You're not yet using Java 1.2? Access password-protected URLs with Java 1.1 In the last tip, we introduced the following scenario: You’re using your favorite browser to surf the ‘Net, and you encounter a URL that requires authentication from a proxy or HTTP server. What you see on the screen is the standard box in which you must enter your username and password so as to gain access to the site. To refresh your memory, here’s what that screen looks like: From a Java program, you’ll find yourself in trouble: When you try to read from an InputStream associated with the URL, a FileNotFoundException is thrown. Starting with Java 1.2, you can take advantage of the Authenticator class, which, as mentioned above, you learned about in Java Tip 46. However, with versions prior to Java 1.2, you need to know if the URL you want to access is password-protected before you try to read from it. If the URL is protected, you have to manually configure the username-password response for each URL, so you can properly access the contents. The response is in the form of what’s called an authorization request property. The property gets associated with the URLConnection for the URL. Once the authorization setting is installed, when you get the URL’s contents, the information will be accessible. The authorization string is of the form “ Authorization: Basic username:password,” where the basic authentication fields are encoded in Base64. (A description of the encoding scheme is found in RFC 1113. An RFC is a “request for comments” document that, basically, describes some kind of Internet standard. In this case, #1113 describes Message Encipherment and Authentication Procedures. See Resources below.) To do the encoding, you can use the BASE64Encoder class in the sun.misc package, or you can create your own class. To set up this access, you simply have to configure the URL ‘s URLConnection to have the proper “Authorization” request property. The following steps describe everything: Step 1: Create URL URL url = new URL (urlString); Step 2: Get username and password for specificURLStep 3: Place in String separated by colon (“:”) String userPassword = theUsername + ":" + thePassword; Step 4: Encode the bytes of the string String encoding = new sun.misc.BASE64Encoder().encode (userPassword.getBytes()); Step 5: Create a URLConnection from the URL URLConnection uc = url.openConnection(); Step 6: Set the “Authorization” request property for the URLConnection uc.setRequestProperty ("Authorization", "Basic " + encoding); And now, the solutionAccessing a password-protected URL in Java 1.1 is demonstrated in its entirety below, with its own authentication prompt dialog. The code is as similar as can be to the Java 1.2 Authenticator example provided in Java Tip 46. If you choose to avoid sun.misc classes, or if this happens to be unavailable on your platform, the source for a converter is included below. import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; public class Auth11 extends Frame implements ActionListener { private TextField tf = new TextField(); private TextArea ta = new TextArea(); public void actionPerformed (ActionEvent e) { String s = tf.getText(); if (s.length() != 0) ta.setText (fetchURL (s)); } public Auth11() { super ("URL11 Password"); // Setup screen add (tf, BorderLayout.NORTH); ta.setEditable(false); add (ta, BorderLayout.CENTER); tf.addActionListener (this); addWindowListener (new WindowAdapter() { public void windowClosing (WindowEvent e) { dispose(); System.exit(0); } }); } private String fetchURL (String urlString) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); try { URL url = new URL (urlString); // Popup Window to request username/password password MyAuthenticator ma = new MyAuthenticator(); String userPassword = ma.getPasswordAuthentication(this, url.getHost()); // Encode String String encoding = new sun.misc.BASE64Encoder().encode (userPassword.getBytes()); // or // String encoding = Base64Converter.encode (userPassword.getBytes()); // Need to work with URLConnection to set request property URLConnection uc = url.openConnection(); uc.setRequestProperty ("Authorization", "Basic " + encoding); InputStream content = (InputStream)uc.getInputStream(); BufferedReader in = new BufferedReader (new InputStreamReader (content)); String line; while ((line = in.readLine()) != null) { pw.println (line); } } catch (MalformedURLException e) { pw.println ("Invalid URL"); } catch (IOException e) { pw.println ("Error reading URL"); } return sw.toString(); } public static void main (String args[]) { Frame f = new Auth11(); f.setSize(300, 300); f.setVisible (true); } class MyAuthenticator { String getPasswordAuthentication(Frame f, String prompt) { final Dialog jd = new Dialog (f, "Enter password", true); jd.setLayout (new GridLayout (0, 1)); Label jl = new Label (prompt); jd.add (jl); TextField username = new TextField(); username.setBackground (Color.lightGray); jd.add (username); TextField password = new TextField(); password.setEchoChar ('*'); password.setBackground (Color.lightGray); jd.add (password); Button jb = new Button ("OK"); jd.add (jb); jb.addActionListener (new ActionListener() { public void actionPerformed (ActionEvent e) { jd.dispose(); } }); jd.pack(); jd.setVisible(true); return username.getText() + ":" + password.getText(); } } } /********************************************************************* * BASE 64 encoding of a String or an array of bytes. * * See also RFC 1421. * * @author * Unknown * @author * David W. Croft * @version * 1998-06-08 *********************************************************************/ public class Base64Converter ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// { public static final char [ ] alphabet = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47 'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55 '4', '5', '6', '7', '8', '9', '+', '/' }; // 56 to 63 ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// public static String encode ( String s ) ////////////////////////////////////////////////////////////////////// { return encode ( s.getBytes ( ) ); } public static String encode ( byte [ ] octetString ) ////////////////////////////////////////////////////////////////////// { int bits24; int bits6; char [ ] out = new char [ ( ( octetString.length - 1 ) / 3 + 1 ) * 4 ]; int outIndex = 0; int i = 0; while ( ( i + 3 ) > 18; out [ outIndex++ ] = alphabet [ bits6 ]; bits6 = ( bits24 & 0x0003F000 ) >> 12; out [ outIndex++ ] = alphabet [ bits6 ]; bits6 = ( bits24 & 0x00000FC0 ) >> 6; out [ outIndex++ ] = alphabet [ bits6 ]; bits6 = ( bits24 & 0x0000003F ); out [ outIndex++ ] = alphabet [ bits6 ]; } if ( octetString.length - i == 2 ) { // store the octets bits24 = ( octetString [ i ] & 0xFF ) > 18; out [ outIndex++ ] = alphabet [ bits6 ]; bits6 = ( bits24 & 0x0003F000 ) >> 12; out [ outIndex++ ] = alphabet [ bits6 ]; bits6 = ( bits24 & 0x00000FC0 ) >> 6; out [ outIndex++ ] = alphabet [ bits6 ]; // padding out [ outIndex++ ] = '='; } else if ( octetString.length - i == 1 ) { // store the octets bits24 = ( octetString [ i ] & 0xFF ) > 18; out [ outIndex++ ] = alphabet [ bits6 ]; bits6 = ( bits24 & 0x0003F000 ) >> 12; out [ outIndex++ ] = alphabet [ bits6 ]; // padding out [ outIndex++ ] = '='; out [ outIndex++ ] = '='; } return new String ( out ); } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// } Remember that using this program will require you to find a URL with a username and password that you know. If you happen to have acquired a free account from Discover Brokerage Direct for the Authenticator tip, you can use it again here. Otherwise, you can get a free password at the registration desk. Then, as with the last tip, you can try the program with a URL of https://www.lombard.com/cgi-bin/Quotes/quote. John Zukowski is a software mage with MageLang Institute, author of Java AWT Reference from O’Reilly & Associates and Borland’s JBuilder: No experience required from Sybex, as well as the Focus on Java guide at the Mining Company. Access ControlAuthentication