craigmcc    01/07/30 19:00:02

  Modified:    catalina/src/share/org/apache/catalina Session.java
               catalina/src/share/org/apache/catalina/authenticator
                        AuthenticatorBase.java Constants.java
                        FormAuthenticator.java
               catalina/src/share/org/apache/catalina/session
                        StandardSession.java
  Log:
  Session/StandardSession:  Implement a new "notes" API that is functionally
  equivalent to session attributes, but available only to internal Catalina
  components (not applications).  This can be used by event listeners to
  decorate sessions with arbitrary sets of objects.
  
  StandardSession:  Implement property change notification on the "authType"
  and "principal" properties, so that event listeners can track changes to
  these properties (used to cache authentication information and avoid hving
  to call Realm.authenticate() on every request).
  
  FormAuthenticator:  Use the new "notes" mechanism, rather than session
  attributes, to store the objects related to form-based login processing.
  Also, store additional information so that form based login continues to
  work even if the "cache" property is set to false (which will cause a call
  to Realm.authenticate() on every request).
  
  This is the third of three patches necessary to fix BugTraq #4485977.
  
  Revision  Changes    Path
  1.5       +40 -4     
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Session.java
  
  Index: Session.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Session.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Session.java      2001/07/29 03:43:54     1.4
  +++ Session.java      2001/07/31 02:00:02     1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Session.java,v 1.4 
2001/07/29 03:43:54 craigmcc Exp $
  - * $Revision: 1.4 $
  - * $Date: 2001/07/29 03:43:54 $
  + * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Session.java,v 1.5 
2001/07/31 02:00:02 craigmcc Exp $
  + * $Revision: 1.5 $
  + * $Date: 2001/07/31 02:00:02 $
    *
    * ====================================================================
    *
  @@ -67,6 +67,7 @@
   
   import java.io.IOException;
   import java.security.Principal;
  +import java.util.Iterator;
   import javax.servlet.ServletException;
   import javax.servlet.http.HttpSession;
   
  @@ -77,7 +78,7 @@
    * between requests for a particular user of a web application.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.4 $ $Date: 2001/07/29 03:43:54 $
  + * @version $Revision: 1.5 $ $Date: 2001/07/31 02:00:02 $
    */
   
   public interface Session {
  @@ -270,6 +271,22 @@
   
   
       /**
  +     * Return the object bound with the specified name to the internal notes
  +     * for this session, or <code>null</code> if no such binding exists.
  +     *
  +     * @param name Name of the note to be returned
  +     */
  +    public Object getNote(String name);
  +
  +
  +    /**
  +     * Return an Iterator containing the String names of all notes bindings
  +     * that exist for this session.
  +     */
  +    public Iterator getNoteNames();
  +
  +
  +    /**
        * Release all object references, and initialize instance variables, in
        * preparation for reuse of this object.
        */
  @@ -277,9 +294,28 @@
   
   
       /**
  +     * Remove any object bound to the specified name in the internal notes
  +     * for this session.
  +     *
  +     * @param name Name of the note to be removed
  +     */
  +    public void removeNote(String name);
  +
  +
  +    /**
        * Remove a session event listener from this component.
        */
       public void removeSessionListener(SessionListener listener);
  +
  +
  +    /**
  +     * Bind an object to a specified name in the internal notes associated
  +     * with this session, replacing any existing binding for this name.
  +     *
  +     * @param name Name to which the object should be bound
  +     * @param value Object to be bound to the specified name
  +     */
  +    public void setNote(String name, Object value);
   
   
   }
  
  
  
  1.21      +5 -4      
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java
  
  Index: AuthenticatorBase.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- AuthenticatorBase.java    2001/07/29 03:43:54     1.20
  +++ AuthenticatorBase.java    2001/07/31 02:00:02     1.21
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java,v
 1.20 2001/07/29 03:43:54 craigmcc Exp $
  - * $Revision: 1.20 $
  - * $Date: 2001/07/29 03:43:54 $
  + * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java,v
 1.21 2001/07/31 02:00:02 craigmcc Exp $
  + * $Revision: 1.21 $
  + * $Date: 2001/07/31 02:00:02 $
    *
    * ====================================================================
    *
  @@ -121,7 +121,7 @@
    * requests.  Requests of any other type will simply be passed through.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.20 $ $Date: 2001/07/29 03:43:54 $
  + * @version $Revision: 1.21 $ $Date: 2001/07/31 02:00:02 $
    */
   
   
  @@ -543,6 +543,7 @@
               return (true);
   
           // Specifically allow access to the form login and form error pages
  +        // and the "j_security_check" action
           LoginConfig config = context.getLoginConfig();
           if ((config != null) &&
               (Constants.FORM_METHOD.equals(config.getAuthMethod()))) {
  
  
  
  1.6       +11 -7     
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/Constants.java
  
  Index: Constants.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/Constants.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- Constants.java    2001/07/22 20:09:19     1.5
  +++ Constants.java    2001/07/31 02:00:02     1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/Constants.java,v
 1.5 2001/07/22 20:09:19 pier Exp $
  - * $Revision: 1.5 $
  - * $Date: 2001/07/22 20:09:19 $
  + * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/Constants.java,v
 1.6 2001/07/31 02:00:02 craigmcc Exp $
  + * $Revision: 1.6 $
  + * $Date: 2001/07/31 02:00:02 $
    *
    * ====================================================================
    *
  @@ -82,12 +82,16 @@
   
       // Form based authentication constants
       public static final String FORM_ACTION = "/j_security_check";
  -    public static final String FORM_KEY =
  -        "org.apache.catalina.security.REQUEST";
       public static final String FORM_PASSWORD = "j_password";
  -    public static final String FORM_PRINCIPAL =
  -        "org.apache.catalina.security.PRINCIPAL";
  +    public static final String FORM_PASSWORD_NOTE =
  +        "org.apache.catalina.authenticator.PASSWORD";
  +    public static final String FORM_PRINCIPAL_NOTE =
  +        "org.apache.catalina.authenticator.PRINCIPAL";
  +    public static final String FORM_REQUEST_NOTE =
  +        "org.apache.catalina.authenticator.REQUEST";
       public static final String FORM_USERNAME = "j_username";
  +    public static final String FORM_USERNAME_NOTE =
  +        "org.apache.catailna.authenticator.USERNAME";
   
       // Cookie name for single sign on support
       public static final String SINGLE_SIGN_ON_COOKIE = "JSESSIONIDSSO";
  
  
  
  1.15      +51 -16    
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java
  
  Index: FormAuthenticator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- FormAuthenticator.java    2001/07/29 03:43:54     1.14
  +++ FormAuthenticator.java    2001/07/31 02:00:02     1.15
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java,v
 1.14 2001/07/29 03:43:54 craigmcc Exp $
  - * $Revision: 1.14 $
  - * $Date: 2001/07/29 03:43:54 $
  + * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java,v
 1.15 2001/07/31 02:00:02 craigmcc Exp $
  + * $Revision: 1.15 $
  + * $Date: 2001/07/31 02:00:02 $
    *
    * ====================================================================
    *
  @@ -88,7 +88,7 @@
    * Authentication, as described in the Servlet API Specification, Version 2.2.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.14 $ $Date: 2001/07/29 03:43:54 $
  + * @version $Revision: 1.15 $ $Date: 2001/07/31 02:00:02 $
    */
   
   public final class FormAuthenticator
  @@ -158,14 +158,39 @@
               return (true);
           }
   
  +        // Have we authenticated this user before but have caching disabled?
  +        if (!cache) {
  +            session = getSession(request, true);
  +            if (debug >= 1)
  +                log("Checking for reauthenticate in session " + session);
  +            String username =
  +                (String) session.getNote(Constants.FORM_USERNAME_NOTE);
  +            String password =
  +                (String) session.getNote(Constants.FORM_PASSWORD_NOTE);
  +            if ((username != null) && (password != null)) {
  +                if (debug >= 1)
  +                    log("Reauthenticating username '" + username + "'");
  +                principal =
  +                    context.getRealm().authenticate(username, password);
  +                if (principal != null) {
  +                    session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
  +                    register(request, response, principal,
  +                             Constants.FORM_METHOD);
  +                    return (true);
  +                }
  +                if (debug >= 1)
  +                    log("Reauthentication failed, proceed normally");
  +            }
  +        }
  +
           // Is this the re-submit of the original request URI after successful
           // authentication?  If so, forward the *original* request instead.
           if (matchRequest(request)) {
  -            session = getSession(request);
  +            session = getSession(request, true);
               if (debug >= 1)
                   log("Restore request from session '" + session.getId() + "'");
               principal = (Principal)
  -              session.getSession().getAttribute(Constants.FORM_PRINCIPAL);
  +                session.getNote(Constants.FORM_PRINCIPAL_NOTE);
               register(request, response, principal, Constants.FORM_METHOD);
               String ssoId = request.getSsoId();
               if (ssoId != null)
  @@ -230,6 +255,8 @@
           Realm realm = context.getRealm();
           String username = hreq.getParameter(Constants.FORM_USERNAME);
           String password = hreq.getParameter(Constants.FORM_PASSWORD);
  +        if (debug >= 1)
  +            log("Authenticating username '" + username + "'");
           principal = realm.authenticate(username, password);
           if (principal == null) {
               if (debug >= 1)
  @@ -239,15 +266,23 @@
           }
   
           // Save the authenticated Principal in our session
  +        if (debug >= 1)
  +            log("Authentication of '" + username + "' was successful");
           if (session == null)
  -            session = getSession(request);
  -        session.getSession().setAttribute(Constants.FORM_PRINCIPAL, principal);
  +            session = getSession(request, true);
  +        session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
  +
  +        // If we are not caching, save the username and password as well
  +        if (!cache) {
  +            session.setNote(Constants.FORM_USERNAME_NOTE, username);
  +            session.setNote(Constants.FORM_PASSWORD_NOTE, password);
  +        }
   
           // Redirect the user to the original request URI (which will cause
           // the original request to be restored)
           requestURI = savedRequestURL(session);
           if (debug >= 1)
  -            log("Redirecting to '" + requestURI + "'");
  +            log("Redirecting to original '" + requestURI + "'");
           hres.sendRedirect(hres.encodeRedirectURL(requestURI));
           return (false);
   
  @@ -272,12 +307,12 @@
   
         // Is there a saved request?
         SavedRequest sreq = (SavedRequest)
  -        session.getSession().getAttribute(Constants.FORM_KEY);
  +          session.getNote(Constants.FORM_REQUEST_NOTE);
         if (sreq == null)
             return (false);
   
         // Is there a saved principal?
  -      if (session.getSession().getAttribute(Constants.FORM_PRINCIPAL) == null)
  +      if (session.getNote(Constants.FORM_PRINCIPAL_NOTE) == null)
             return (false);
   
         // Does the request URI match?
  @@ -303,9 +338,9 @@
   
           // Retrieve and remove the SavedRequest object from our session
           SavedRequest saved = (SavedRequest)
  -            session.getSession().getAttribute(Constants.FORM_KEY);
  -        session.getSession().removeAttribute(Constants.FORM_KEY);
  -        session.getSession().removeAttribute(Constants.FORM_PRINCIPAL);
  +            session.getNote(Constants.FORM_REQUEST_NOTE);
  +        session.removeNote(Constants.FORM_REQUEST_NOTE);
  +        session.removeNote(Constants.FORM_PRINCIPAL_NOTE);
           if (saved == null)
               return (false);
   
  @@ -387,7 +422,7 @@
           saved.setRequestURI(hreq.getRequestURI());
   
           // Stash the SavedRequest in our session for later use
  -        session.getSession().setAttribute(Constants.FORM_KEY, saved);
  +        session.setNote(Constants.FORM_REQUEST_NOTE, saved);
   
       }
   
  @@ -401,7 +436,7 @@
       private String savedRequestURL(Session session) {
   
           SavedRequest saved =
  -          (SavedRequest) session.getSession().getAttribute(Constants.FORM_KEY);
  +            (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
           if (saved == null)
               return (null);
           StringBuffer sb = new StringBuffer(saved.getRequestURI());
  
  
  
  1.25      +88 -6     
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/StandardSession.java
  
  Index: StandardSession.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/StandardSession.java,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- StandardSession.java      2001/07/29 03:43:54     1.24
  +++ StandardSession.java      2001/07/31 02:00:02     1.25
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/StandardSession.java,v
 1.24 2001/07/29 03:43:54 craigmcc Exp $
  - * $Revision: 1.24 $
  - * $Date: 2001/07/29 03:43:54 $
  + * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/StandardSession.java,v
 1.25 2001/07/31 02:00:02 craigmcc Exp $
  + * $Revision: 1.25 $
  + * $Date: 2001/07/31 02:00:02 $
    *
    * ====================================================================
    *
  @@ -65,6 +65,8 @@
   package org.apache.catalina.session;
   
   
  +import java.beans.PropertyChangeListener;
  +import java.beans.PropertyChangeSupport;
   import java.io.IOException;
   import java.io.NotSerializableException;
   import java.io.ObjectInputStream;
  @@ -113,7 +115,7 @@
    * @author Craig R. McClanahan
    * @author Sean Legassick
    * @author <a href="mailto:[EMAIL PROTECTED]";>Jon S. Stevens</a>
  - * @version $Revision: 1.24 $ $Date: 2001/07/29 03:43:54 $
  + * @version $Revision: 1.25 $ $Date: 2001/07/31 02:00:02 $
    */
   
   class StandardSession
  @@ -243,6 +245,14 @@
   
   
       /**
  +     * Internal notes associated with this session by Catalina components
  +     * and event listeners.  <b>IMPLEMENTATION NOTE:</b> This object is
  +     * <em>not</em> saved and restored across session serializations!
  +     */
  +    private transient HashMap notes = new HashMap();
  +
  +
  +    /**
        * The authenticated Principal associated with this session, if any.
        * <b>IMPLEMENTATION NOTE:</b>  This object is <i>not</i> saved and
        * restored across session serializations!
  @@ -264,6 +274,14 @@
   
   
       /**
  +     * The property change support for this component.  NOTE:  This value
  +     * is not included in the serialized version of this object.
  +     */
  +    private transient PropertyChangeSupport support =
  +        new PropertyChangeSupport(this);
  +
  +
  +    /**
        * The current accessed time for this session.
        */
       private long thisAccessedTime = creationTime;
  @@ -291,7 +309,9 @@
        */
       public void setAuthType(String authType) {
   
  +        String oldAuthType = this.authType;
           this.authType = authType;
  +        support.firePropertyChange("authType", oldAuthType, this.authType);
   
       }
   
  @@ -484,7 +504,9 @@
        */
       public void setPrincipal(Principal principal) {
   
  +        Principal oldPrincipal = this.principal;
           this.principal = principal;
  +        support.firePropertyChange("principal", oldPrincipal, this.principal);
   
       }
   
  @@ -658,6 +680,34 @@
   
   
       /**
  +     * Return the object bound with the specified name to the internal notes
  +     * for this session, or <code>null</code> if no such binding exists.
  +     *
  +     * @param name Name of the note to be returned
  +     */
  +    public Object getNote(String name) {
  +
  +        synchronized (notes) {
  +            return (notes.get(name));
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * Return an Iterator containing the String names of all notes bindings
  +     * that exist for this session.
  +     */
  +    public Iterator getNoteNames() {
  +
  +        synchronized (notes) {
  +            return (notes.keySet().iterator());
  +        }
  +
  +    }
  +
  +
  +    /**
        * Release all object references, and initialize instance variables, in
        * preparation for reuse of this object.
        */
  @@ -665,14 +715,15 @@
   
           // Reset the instance variables associated with this Session
           attributes.clear();
  -        authType = null;
  +        setAuthType(null);
           creationTime = 0L;
           expiring = false;
           id = null;
           lastAccessedTime = 0L;
           manager = null;
           maxInactiveInterval = -1;
  -        principal = null;
  +        notes.clear();
  +        setPrincipal(null);
           isNew = false;
           isValid = false;
   
  @@ -684,12 +735,43 @@
   
   
       /**
  +     * Remove any object bound to the specified name in the internal notes
  +     * for this session.
  +     *
  +     * @param name Name of the note to be removed
  +     */
  +    public void removeNote(String name) {
  +
  +        synchronized (notes) {
  +            notes.remove(name);
  +        }
  +
  +    }
  +
  +
  +    /**
        * Remove a session event listener from this component.
        */
       public void removeSessionListener(SessionListener listener) {
   
           synchronized (listeners) {
               listeners.remove(listener);
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * Bind an object to a specified name in the internal notes associated
  +     * with this session, replacing any existing binding for this name.
  +     *
  +     * @param name Name to which the object should be bound
  +     * @param value Object to be bound to the specified name
  +     */
  +    public void setNote(String name, Object value) {
  +
  +        synchronized (notes) {
  +            notes.put(name, value);
           }
   
       }
  
  
  

Reply via email to