Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4755765

HttpURLConnection Fails on 401 Response

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P3 P3
    • None
    • 1.4.1
    • core-libs
    • x86
    • windows_2000



      Name: nt126004 Date: 09/30/2002


      FULL PRODUCT VERSION :
      C:\ems\spawar\ems\svc\gui\client>java -version
      java version "1.4.1"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
      Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

      FULL OPERATING SYSTEM VERSION : Windows 2000 sp2


      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Web server is Netscape Enterprise Server 6.1 running on
      same machine.

      A DESCRIPTION OF THE PROBLEM :
      A GET request is submitted to a servlet running Netscape
      Enterprise Server 6.1 (HTTP/1.1) for a realm which has
      already been successfully authenticated. A servlet running
      within that realm intentionally responds with a 401/WWW-
      Authentication response to force a reauthentication. If
      the user enters an incorrect login during the
      reauthentication, the connection fails and cannot be
      reinitialized without restarting the client.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Start the servlet in a restricted realm
      2. Start the client and login to the restricted realm
      3. Initiate a GET request to the servlet to force
      reauthentication in the restricted realm - a login dialog
      appears
      4. Login incorrectly when prompted - error occurs


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      Beginning from step 4, the login prompt should appear until
      the user successfully reauthenticates or the connection
      expires in which case the user should be notified.

      Instead, an uncaught exception occurs resulting in a
      connection that can no longer be reinitialized without
      restarting the client.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
              at java.util.LinkedList.entry(LinkedList.java:356)
              at java.util.LinkedList.get(LinkedList.java:299)
              at sun.net.www.protocol.http.PathMap.get(AuthenticationInfo.java:355)
              at sun.net.www.protocol.http.AuthenticationInfo.getAuth
      (AuthenticationInfo.java:176)
              at sun.net.www.protocol.http.AuthenticationInfo.getServerAuth
      (AuthenticationInfo.java:166)
              at sun.net.www.protocol.http.HttpURLConnection.getServerAuthentication
      (HttpURLConnection.java:920)
              at sun.net.www.protocol.http.HttpURLConnection.getInputStream
      (HttpURLConnection.java:600)
              at sun.net.www.protocol.http.HttpURLConnection.getHeaderFields
      (HttpURLConnection.java:1133)
              at TestClient.reauthenticate(TestClient.java:30)
              at TestClient.main(TestClient.java:57)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------

      ************************** Client code: **************************************
      public class TestClient {
          
          /**
          allows reauthentication. Used to update an expired user
          token.
          */
          public static void reauthenticate(String url)
          {
              java.net.HttpURLConnection urlConnection = null;

              try
              {
                  java.net.URL u = new java.net.URL(url + "?html=authenticate&id=1");
                  urlConnection = (java.net.HttpURLConnection)u.openConnection();
                  //prevent login/password from being sent
                  urlConnection.setRequestProperty("Authorization", "");
                  urlConnection.setRequestProperty("Cache-Control", "no-cache");
                  urlConnection.setRequestProperty("Pragma", "no-cache");
                  urlConnection.connect();
                  java.util.Map m = urlConnection.getHeaderFields();
                  java.util.Set s = m.keySet();
                  java.util.Iterator i = s.iterator();
                  while(i.hasNext())
                  {
                      String key = (String)i.next();
                      Object value = m.get(key);
                      System.out.println(key + ": " + value);
                  }
              }
              catch(Exception e){e.printStackTrace();}
              finally{urlConnection.disconnect();}
          }
          
          /**
           * @param args the command line arguments
           */
          public static void main(String[] args) {
              //args[0] must be a reference to a simple html page in a restricted
      realm (e.g. /client/index.html)
              //args[1] must be a reference to the TestServlet deeper in the
      restricted realm (e.g. /client/control/TestServlet)
              java.net.URLConnection.setDefaultAllowUserInteraction(true);
              java.net.Authenticator.setDefault(new BasicAuthenticator());
       
              javax.swing.JTextPane pane = new javax.swing.JTextPane();
              //authenticate in realm first
              try{pane.setPage(args[0]);}
              catch(java.io.IOException e){}
              TestClient t = new TestClient();
              //attempt to reauthenticate in the same realm
              t.reauthenticate(args[1]);
          }
          
      }

      ************************** Servlet code: **************************************

      import java.text.*;
      import java.net.*;
      import java.awt.*;
      import java.io.*;
      import java.util.*;
      import javax.servlet.*;
      import javax.servlet.http.*;

      public class TestServlet extends javax.servlet.http.HttpServlet
      {
          private Hashtable hotswapHash = new Hashtable();

          public synchronized void doGet (HttpServletRequest req, HttpServletResponse
      res) throws ServletException, IOException
          {
              short posit = 0;
              String targetUrl = null;
              String id = null;
              res.setContentType("text/html");

              StringTokenizer qryParams = new StringTokenizer(req.getQueryString
      (), "&");
              while(qryParams.hasMoreTokens())
              {
                  String qryHash = qryParams.nextToken();
                  if ( (posit = (short)qryHash.indexOf("html=")) != -1)
                      targetUrl = qryHash.substring(posit+5);
                  else if ( (posit = (short)qryHash.indexOf("id=")) != -1)
                      id = qryHash.substring(posit+3);
              }

              if(targetUrl.equals("authenticate"))
              {
                  /*java.io.File f = new File("c:\\temp\\output.txt");
                  java.io.FileOutputStream o = new FileOutputStream(f);
                  StringBuffer b = new StringBuffer();
                  b.append(
                      "\n\nRequest Method: " + req.getMethod() +
                      "\nRequest URI: " + req.getRequestURI() +
                      "\nRequest Protocol:"+ req.getProtocol());
                      java.util.Enumeration headerNames = req.getHeaderNames();
                  while(headerNames.hasMoreElements()) {
                    String headerName = (String)headerNames.nextElement();
                    b.append("\n" + headerName + ": " + req.getHeader(headerName));
                  }
                  
                  byte output[] = b.toString().getBytes();
                  o.write(output, (int)f.length(), output.length);
                  o.close();
                  */

                  //if in reauthenticate hash already, reauthenticate
                  //with new login
                  if(hotswapHash.containsKey(id))
                  {
                      //remove flag from hash
                      hotswapHash.remove(id);
                      //reset id on Access Service by changing the user
                      //RTS - no only will this reset token but will
                      //pick up any data changes in the LDAP server
                      try
                      {
                          res.setStatus(res.SC_NO_CONTENT);
                          System.out.println("succeeded.");
                      }
                      catch(Exception e)
                      {
                          //return error which will prompt for reauthentication
                          askForPassword(res);
                          System.out.println("failed");
                      }
                      finally
                      {
                          return;
                      }
                  }
                  //else store in reauthenticate hash and prompt for login
                  else
                  {
                      //store flag in hash
                      hotswapHash.put(id, id);
                      //return error which will prompt for reauthentication
                      askForPassword(res);
                      System.out.print("reauthenticating " + id + "...");
                      return;
                  }
              }
         }
          
          private void askForPassword(HttpServletResponse response)
          {
              response.setStatus(response.SC_UNAUTHORIZED); // Ie 401
              response.setHeader("WWW-Authenticate",
                                 "BASIC realm=\"Client Login\"");
          }
      }

      *************************** Authenticator Code: *******************************

      /*
       * BasicAuthenticator.java
       *
       * Created on June 24, 2002, 6:24 PM
       */

      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import java.net.PasswordAuthentication;

      /**
       * Extends Authenticator to allow for user login
       * @author R. Smudz
       */
      public class BasicAuthenticator extends java.net.Authenticator {
          private LoginDialog dialog;
          
          /** Creates a new instance of BasicAuthenticator */
          public BasicAuthenticator() {
          }
          
          protected java.net.PasswordAuthentication getPasswordAuthentication() {
              PasswordAuthentication authentication = createLoginDialog();
              return authentication;
          }

          private PasswordAuthentication createLoginDialog() {
              if (dialog == null)
                  dialog = new LoginDialog();

              dialog.show();
              PasswordAuthentication p = dialog.getAuth();
              return p;
          }
      }

      class LoginDialog extends JDialog implements KeyListener, ActionListener
      {
          private JPanel north, south;
          private JLabel nameLabel, passwordLabel, infoLabel;
          private JTextField nameTextField;
          private JPasswordField passwordField;
          private JButton loginButton, cancelButton;
          private String username;
          private char password[];
          private PasswordAuthentication privateAuth;

          public LoginDialog()
          {
              setModal(true);
              setTitle("Login Required");
              north = new JPanel();
              north.setLayout(null);
              north.setPreferredSize(new Dimension(277, 110));
              nameLabel = new JLabel("Username:", JLabel.LEFT);
              nameLabel.setBounds(10, 60, 90, 20);
              north.add(nameLabel);
              passwordLabel = new JLabel("Password:", JLabel.LEFT);
              passwordLabel.setBounds(10, 90, 90, 20);
              north.add(passwordLabel);
              nameTextField = new JTextField();
              nameTextField.setBounds(100, 60, 157, 20);
              north.add(nameTextField);
              passwordField = new JPasswordField();
              passwordField.setBounds(100, 90, 157, 20);
              north.add(passwordField);

              getContentPane().add(north,BorderLayout.CENTER);
              south = new JPanel();
              south.setLayout(new FlowLayout(FlowLayout.RIGHT, 10, 10));
              loginButton = new JButton("Login");
              loginButton.addActionListener(this);
              south.add(loginButton);
      cancelButton = new JButton("Cancel");
              cancelButton.addActionListener(new ActionListener()
              {
                  public void actionPerformed(ActionEvent ae)
                  {
                      privateAuth = null;
                      hide();
                  }
              });

              south.add(cancelButton);
              getContentPane().add(south, BorderLayout.SOUTH);
      loginButton.addKeyListener(this);
              setDefaultCloseOperation(HIDE_ON_CLOSE);
              pack();
              //parent frame may not be up so use center of screen
              Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
              setLocation((int)d.getWidth()/2 - getWidth()/2, (int)d.getHeight()/2 -
      getHeight()/2 );
          }

          public void actionPerformed(ActionEvent ae)
          {
              char[] authArray;

              username = nameTextField.getText();
              nameTextField.setText("");
              password = passwordField.getPassword();
              passwordField.setText("");
              privateAuth = new PasswordAuthentication(username, password);
              // Delete attributes for userID and password
              username = "";
              password = new String("").toCharArray();
              nameTextField.requestFocus();
              hide();
          }

          /**
           * Returns the actual PasswordAuthentication,
           * which was generated from the login dialog.
           *
           * @return PasswordAuthentication - actual PasswordAuthentication.
           */
          public PasswordAuthentication getAuth()
          {
                  return privateAuth;
          }
          
          public void keyPressed(java.awt.event.KeyEvent keyEvent) {
          }
          
          public void keyReleased(java.awt.event.KeyEvent keyEvent) {
          }
          
          public void keyTyped(java.awt.event.KeyEvent keyEvent) {
              if(keyEvent.getKeyCode() == KeyEvent.VK_UNDEFINED || keyEvent.getKeyCode
      () == KeyEvent.VK_ENTER)
                  actionPerformed(null);
          }
      }
      ---------- END SOURCE ----------
      (Review ID: 164925)
      ======================================================================

            michaelm Michael McMahon
            nthompsosunw Nathanael Thompson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: