You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2003/12/24 21:40:50 UTC

cvs commit: jakarta-tomcat-4.0/webapps/tomcat-docs/config valve.xml

markt       2003/12/24 12:40:50

  Modified:    catalina/src/share/org/apache/catalina/authenticator
                        AuthenticatorBase.java BasicAuthenticator.java
                        DigestAuthenticator.java FormAuthenticator.java
                        NonLoginAuthenticator.java SSLAuthenticator.java
                        SingleSignOn.java
               webapps/tomcat-docs/config valve.xml
  Log:
  - Port of patch from TC5.
  - Fix bugs 4350, 9077, 10040 and 23881.
  - SSO in embedded Tomcat.
  - Patch provided by Brian Stansberry.
  
  Revision  Changes    Path
  1.39      +87 -24    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.38
  retrieving revision 1.39
  diff -u -r1.38 -r1.39
  --- AuthenticatorBase.java	18 Jul 2003 04:39:31 -0000	1.38
  +++ AuthenticatorBase.java	24 Dec 2003 20:40:50 -0000	1.39
  @@ -84,7 +84,6 @@
   import org.apache.catalina.HttpRequest;
   import org.apache.catalina.HttpResponse;
   import org.apache.catalina.Lifecycle;
  -import org.apache.catalina.LifecycleEvent;
   import org.apache.catalina.LifecycleException;
   import org.apache.catalina.LifecycleListener;
   import org.apache.catalina.Logger;
  @@ -99,7 +98,6 @@
   import org.apache.catalina.deploy.LoginConfig;
   import org.apache.catalina.deploy.SecurityConstraint;
   import org.apache.catalina.util.LifecycleSupport;
  -import org.apache.catalina.util.RequestUtil;
   import org.apache.catalina.util.StringManager;
   import org.apache.catalina.valves.ValveBase;
   
  @@ -666,7 +664,7 @@
        *
        * @param request Request we are processing
        * @param response Response we are creating
  -     * @param login Login configuration describing how authentication
  +     * @param config    Login configuration describing how authentication
        *              should be performed
        *
        * @exception IOException if an input/output error occurs
  @@ -817,7 +815,6 @@
       protected synchronized String generateSessionId() {
   
           // Generate a byte array containing a session identifier
  -        Random random = getRandom();
           byte bytes[] = new byte[SESSION_ID_BYTES];
           getRandom().nextBytes(bytes);
           bytes = getDigest().digest(bytes);
  @@ -975,6 +972,52 @@
   
   
       /**
  +     * Attempts reauthentication to the <code>Realm</code> using
  +     * the credentials included in argument <code>entry</code>.
  +     *
  +     * @param ssoId identifier of SingleSignOn session with which the
  +     *              caller is associated
  +     * @param request   the request that needs to be authenticated
  +     */
  +    protected boolean reauthenticateFromSSO(String ssoId, HttpRequest request) {
  +
  +        if (sso == null || ssoId == null)
  +            return false;
  +
  +        boolean reauthenticated = false;
  +
  +        SingleSignOnEntry entry = sso.lookup(ssoId);
  +        if (entry != null && entry.getCanReauthenticate()) {
  +            Principal reauthPrincipal = null;
  +            Container parent = getContainer();
  +            if (parent != null) {
  +                Realm realm = getContainer().getRealm();
  +                String username = entry.getUsername();
  +                if (realm != null && username != null) {
  +                    reauthPrincipal =
  +                        realm.authenticate(username, entry.getPassword());
  +                }
  +            }
  +
  +            if (reauthPrincipal != null) {
  +                associate(ssoId, getSession(request, true));
  +                request.setAuthType(entry.getAuthType());
  +                request.setUserPrincipal(reauthPrincipal);
  +
  +                reauthenticated = true;
  +                if (debug >= 1) {
  +                    log(" Reauthenticated cached principal '" +
  +                        entry.getPrincipal().getName() + "' with auth type '" +
  +                        entry.getAuthType() + "'");
  +                }
  +            }
  +        }
  +
  +        return reauthenticated;
  +    }
  +
  +
  +    /**
        * Register an authenticated Principal and authentication type in our
        * request, in the current session (if there is one), and with our
        * SingleSignOn valve, if there is one.  Set the appropriate cookie
  @@ -998,10 +1041,10 @@
           // Cache the authentication information in our request
           request.setAuthType(authType);
           request.setUserPrincipal(principal);
  -
  +        
  +        Session session = getSession(request, false);
           // Cache the authentication information in our session, if any
  -        if (cache) {
  -            Session session = getSession(request, false);
  +        if (cache) {            
               if (session != null) {
                   session.setAuthType(authType);
                   session.setPrincipal(principal);
  @@ -1019,19 +1062,39 @@
           // Construct a cookie to be returned to the client
           if (sso == null)
               return;
  -        HttpServletRequest hreq =
  -            (HttpServletRequest) request.getRequest();
  -        HttpServletResponse hres =
  -            (HttpServletResponse) response.getResponse();
  -        String value = generateSessionId();
  -        Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, value);
  -        cookie.setMaxAge(-1);
  -        cookie.setPath("/");
  -        hres.addCookie(cookie);
  -
  -        // Register this principal with our SSO valve
  -        sso.register(value, principal, authType, username, password);
  -        request.setNote(Constants.REQ_SSOID_NOTE, value);
  +
  +        // Only create a new SSO entry if the SSO did not already set a note
  +        // for an existing entry (as it would do with subsequent requests
  +        // for DIGEST and SSL authenticated contexts)
  +        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
  +        if (ssoId == null) {
  +            // Construct a cookie to be returned to the client
  +            HttpServletResponse hres =
  +                (HttpServletResponse) response.getResponse();
  +            ssoId = generateSessionId();
  +            Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId);
  +            cookie.setMaxAge(-1);
  +            cookie.setPath("/");
  +            hres.addCookie(cookie);
  +
  +            // Register this principal with our SSO valve
  +            sso.register(ssoId, principal, authType, username, password);
  +            request.setNote(Constants.REQ_SSOID_NOTE, ssoId);
  +
  +        } else {
  +            // Update the SSO session with the latest authentication data
  +            sso.update(ssoId, principal, authType, username, password);
  +        }
  +
  +        // Fix for Bug 10040
  +        // Always associate a session with a new SSO reqistration.
  +        // SSO entries are only removed from the SSO registry map when
  +        // associated sessions are destroyed; if a new SSO entry is created
  +        // above for this request and the user never revisits the context, the
  +        // SSO entry will never be cleared if we don't associate the session
  +        if (session == null)
  +            session = getSession(request, true);
  +        sso.associate(ssoId, session);
   
       }
   
  
  
  
  1.13      +23 -5     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java
  
  Index: BasicAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- BasicAuthenticator.java	23 Mar 2002 17:52:16 -0000	1.12
  +++ BasicAuthenticator.java	24 Dec 2003 20:40:50 -0000	1.13
  @@ -131,7 +131,7 @@
        *
        * @param request Request we are processing
        * @param response Response we are creating
  -     * @param login Login configuration describing how authentication
  +     * @param config    Login configuration describing how authentication
        *              should be performed
        *
        * @exception IOException if an input/output error occurs
  @@ -144,10 +144,28 @@
           // Have we already authenticated someone?
           Principal principal =
               ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  +        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
           if (principal != null) {
               if (debug >= 1)
                   log("Already authenticated '" + principal.getName() + "'");
  +            // Associate the session with any existing SSO session
  +            if (ssoId != null)
  +                associate(ssoId, getSession(request, true));
               return (true);
  +        }
  +
  +        // Is there an SSO session against which we can try to reauthenticate?
  +        if (ssoId != null) {
  +            if (debug >= 1)
  +                log("SSO Id " + ssoId + " set; attempting reauthentication");
  +            /* Try to reauthenticate using data cached by SSO.  If this fails,
  +               either the original SSO logon was of DIGEST or SSL (which
  +               we can't reauthenticate ourselves because there is no
  +               cached username and password), or the realm denied
  +               the user's reauthentication for some reason.
  +               In either case we have to prompt the user for a logon */
  +            if (reauthenticateFromSSO(ssoId, request))
  +                return true;
           }
   
           // Validate any credentials already included with this request
  
  
  
  1.12      +41 -12    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java
  
  Index: DigestAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- DigestAuthenticator.java	24 Mar 2003 23:19:19 -0000	1.11
  +++ DigestAuthenticator.java	24 Dec 2003 20:40:50 -0000	1.12
  @@ -76,7 +76,6 @@
   import org.apache.catalina.HttpRequest;
   import org.apache.catalina.HttpResponse;
   import org.apache.catalina.Realm;
  -import org.apache.catalina.Session;
   import org.apache.catalina.deploy.LoginConfig;
   import org.apache.catalina.util.MD5Encoder;
   
  @@ -205,7 +204,7 @@
        *
        * @param request Request we are processing
        * @param response Response we are creating
  -     * @param login Login configuration describing how authentication
  +     * @param config    Login configuration describing how authentication
        *              should be performed
        *
        * @exception IOException if an input/output error occurs
  @@ -218,8 +217,41 @@
           // Have we already authenticated someone?
           Principal principal =
               ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  -        if (principal != null)
  +        //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
  +        if (principal != null) {
  +            if (debug >= 1)
  +                log("Already authenticated '" + principal.getName() + "'");
  +            // Associate the session with any existing SSO session in order
  +            // to get coordinated session invalidation at logout
  +            String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
  +            if (ssoId != null)
  +                associate(ssoId, getSession(request, true));
               return (true);
  +        }
  +
  +        // NOTE: We don't try to reauthenticate using any existing SSO session,
  +        // because that will only work if the original authentication was
  +        // BASIC or FORM, which are less secure than the DIGEST auth-type
  +        // specified for this webapp
  +        //
  +        // Uncomment below to allow previous FORM or BASIC authentications
  +        // to authenticate users for this webapp
  +        // TODO make this a configurable attribute (in SingleSignOn??)
  +        /*
  +        // Is there an SSO session against which we can try to reauthenticate?
  +        if (ssoId != null) {
  +            if (debug >= 1)
  +                log("SSO Id " + ssoId + " set; attempting reauthentication");
  +            // Try to reauthenticate using data cached by SSO.  If this fails,
  +            // either the original SSO logon was of DIGEST or SSL (which
  +            // we can't reauthenticate ourselves because there is no
  +            // cached username and password), or the realm denied
  +            // the user's reauthentication for some reason.
  +            // In either case we get logon credentials from the user.
  +            if (reauthenticateFromSSO(ssoId, request))
  +                return true;
  +        }
  +        */
   
           // Validate any credentials already included with this request
           HttpServletRequest hreq =
  @@ -263,8 +295,6 @@
        *
        * @param request HTTP servlet request
        * @param authorization Authorization credentials from this request
  -     * @param login Login configuration describing how authentication
  -     *              should be performed
        * @param realm Realm used to authenticate Principals
        */
       protected static Principal findPrincipal(HttpServletRequest request,
  @@ -291,7 +321,6 @@
           String qop = null;
           String uri = null;
           String response = null;
  -        String opaque = null;
           String method = request.getMethod();
   
           while (commaTokenizer.hasMoreTokens()) {
  @@ -442,8 +471,8 @@
        * </pre>
        *
        * @param request HTTP Servlet request
  -     * @param resonse HTTP Servlet response
  -     * @param login Login configuration describing how authentication
  +     * @param response HTTP Servlet response
  +     * @param config    Login configuration describing how authentication
        *              should be performed
        * @param nOnce nonce token
        */
  
  
  
  1.21      +22 -11    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.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- FormAuthenticator.java	14 Mar 2002 20:58:24 -0000	1.20
  +++ FormAuthenticator.java	24 Dec 2003 20:40:50 -0000	1.21
  @@ -74,7 +74,6 @@
   import javax.servlet.http.Cookie;
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
  -import javax.servlet.http.HttpSession;
   import org.apache.catalina.HttpRequest;
   import org.apache.catalina.HttpResponse;
   import org.apache.catalina.Realm;
  @@ -129,7 +128,7 @@
        *
        * @param request Request we are processing
        * @param response Response we are creating
  -     * @param login Login configuration describing how authentication
  +     * @param config    Login configuration describing how authentication
        *              should be performed
        *
        * @exception IOException if an input/output error occurs
  @@ -148,16 +147,31 @@
   
           // Have we already authenticated someone?
           Principal principal = hreq.getUserPrincipal();
  +        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
           if (principal != null) {
               if (debug >= 1)
                   log("Already authenticated '" +
                       principal.getName() + "'");
  -            String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
  +            // Associate the session with any existing SSO session
               if (ssoId != null)
                   associate(ssoId, getSession(request, true));
               return (true);
           }
   
  +        // Is there an SSO session against which we can try to reauthenticate?
  +        if (ssoId != null) {
  +            if (debug >= 1)
  +                log("SSO Id " + ssoId + " set; attempting reauthentication");
  +            // Try to reauthenticate using data cached by SSO.  If this fails,
  +            // either the original SSO logon was of DIGEST or SSL (which
  +            // we can't reauthenticate ourselves because there is no
  +            // cached username and password), or the realm denied
  +            // the user's reauthentication for some reason.
  +            // In either case we have to prompt the user for a logon */
  +            if (reauthenticateFromSSO(ssoId, request))
  +                return true;
  +        }
  +
           // Have we authenticated this user before but have caching disabled?
           if (!cache) {
               session = getSession(request, true);
  @@ -195,9 +209,6 @@
               register(request, response, principal, Constants.FORM_METHOD,
                        (String) session.getNote(Constants.SESS_USERNAME_NOTE),
                        (String) session.getNote(Constants.SESS_PASSWORD_NOTE));
  -            String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
  -            if (ssoId != null)
  -                associate(ssoId, session);
               if (restoreRequest(request, session)) {
                   if (debug >= 1)
                       log("Proceed to restored request");
  @@ -377,7 +388,7 @@
               while (paramNames.hasNext()) {
                   String paramName = (String) paramNames.next();
                   String paramValues[] =
  -                    (String[]) saved.getParameterValues(paramName);
  +                    saved.getParameterValues(paramName);
                   request.addParameter(paramName, paramValues);
               }
           }
  
  
  
  1.4       +15 -10    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/NonLoginAuthenticator.java
  
  Index: NonLoginAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/NonLoginAuthenticator.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- NonLoginAuthenticator.java	22 Jul 2001 20:09:19 -0000	1.3
  +++ NonLoginAuthenticator.java	24 Dec 2003 20:40:50 -0000	1.4
  @@ -66,13 +66,9 @@
   
   
   import java.io.IOException;
  -import java.security.Principal;
  -import javax.servlet.http.HttpServletRequest;
  -import javax.servlet.http.HttpServletResponse;
  +
   import org.apache.catalina.HttpRequest;
   import org.apache.catalina.HttpResponse;
  -import org.apache.catalina.Realm;
  -import org.apache.catalina.Session;
   import org.apache.catalina.deploy.LoginConfig;
   
   
  @@ -123,7 +119,7 @@
        *
        * @param request Request we are processing
        * @param response Response we are creating
  -     * @param login Login configuration describing how authentication
  +     * @param config    Login configuration describing how authentication
        *              should be performed
        *
        * @exception IOException if an input/output error occurs
  @@ -132,6 +128,15 @@
                                   HttpResponse response,
                                   LoginConfig config)
           throws IOException {
  +
  +        /*  Associating this request's session with an SSO would allow
  +            coordinated session invalidation, but should the session for
  +            a webapp that the user didn't log into be invalidated when
  +            another session is logged out?
  +        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
  +        if (ssoId != null)
  +            associate(ssoId, getSession(request, true));
  +        */
   
           if (debug >= 1)
               log("User authentication is not required");
  
  
  
  1.14      +35 -8     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java
  
  Index: SSLAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- SSLAuthenticator.java	23 Sep 2002 00:25:10 -0000	1.13
  +++ SSLAuthenticator.java	24 Dec 2003 20:40:50 -0000	1.14
  @@ -73,10 +73,7 @@
   import org.apache.catalina.Globals;
   import org.apache.catalina.HttpRequest;
   import org.apache.catalina.HttpResponse;
  -import org.apache.catalina.Lifecycle;
   import org.apache.catalina.LifecycleException;
  -import org.apache.catalina.Realm;
  -import org.apache.catalina.Session;
   import org.apache.catalina.deploy.LoginConfig;
   
   
  @@ -124,7 +121,7 @@
        *
        * @param request Request we are processing
        * @param response Response we are creating
  -     * @param login Login configuration describing how authentication
  +     * @param config    Login configuration describing how authentication
        *              should be performed
        *
        * @exception IOException if an input/output error occurs
  @@ -137,11 +134,41 @@
           // Have we already authenticated someone?
           Principal principal =
               ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  +        //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
           if (principal != null) {
               if (debug >= 1)
                   log("Already authenticated '" + principal.getName() + "'");
  +            // Associate the session with any existing SSO session in order
  +            // to get coordinated session invalidation at logout
  +            String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
  +            if (ssoId != null)
  +                associate(ssoId, getSession(request, true));
               return (true);
           }
  +
  +        // NOTE: We don't try to reauthenticate using any existing SSO session,
  +        // because that will only work if the original authentication was
  +        // BASIC or FORM, which are less secure than the CLIENT-CERT auth-type
  +        // specified for this webapp
  +        //
  +        // Uncomment below to allow previous FORM or BASIC authentications
  +        // to authenticate users for this webapp
  +        // TODO make this a configurable attribute (in SingleSignOn??)
  +        /*
  +        // Is there an SSO session against which we can try to reauthenticate?
  +        if (ssoId != null) {
  +            if (debug >= 1)
  +                log("SSO Id " + ssoId + " set; attempting reauthentication");
  +            // Try to reauthenticate using data cached by SSO.  If this fails,
  +            // either the original SSO logon was of DIGEST or SSL (which
  +            // we can't reauthenticate ourselves because there is no
  +            // cached username and password), or the realm denied
  +            // the user's reauthentication for some reason.
  +            // In either case we have to prompt the user for a logon
  +            if (reauthenticateFromSSO(ssoId, request))
  +                return true;
  +        }
  +        */
   
           // Retrieve the certificate chain for this client
           HttpServletResponse hres =
  
  
  
  1.13      +179 -57   jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java
  
  Index: SingleSignOn.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- SingleSignOn.java	23 Dec 2003 17:55:39 -0000	1.12
  +++ SingleSignOn.java	24 Dec 2003 20:40:50 -0000	1.13
  @@ -145,6 +145,14 @@
        */
       protected LifecycleSupport lifecycle = new LifecycleSupport(this);
   
  +    
  +    /**
  +     * Indicates whether this valve should require a downstream Authenticator to
  +     * reauthenticate each request, or if it itself can bind a UserPrincipal
  +     * and AuthType object to the request.
  +     */
  +    private boolean requireReauthentication = false;
  +
   
       /**
        * The cache of single sign on identifiers, keyed by the Session that is
  @@ -191,6 +199,75 @@
       }
   
   
  +    /**
  +     * Gets whether each request needs to be reauthenticated (by an
  +     * Authenticator downstream in the pipeline) to the security
  +     * <code>Realm</code>, or if this Valve can itself bind security info
  +     * to the request based on the presence of a valid SSO entry without
  +     * rechecking with the <code>Realm</code..
  +     *
  +     * @return  <code>true</code> if it is required that a downstream
  +     *          Authenticator reauthenticate each request before calls to
  +     *          <code>HttpServletRequest.setUserPrincipal()</code>
  +     *          and <code>HttpServletRequest.setAuthType()</code> are made;
  +     *          <code>false</code> if the <code>Valve</code> can itself make
  +     *          those calls relying on the presence of a valid SingleSignOn
  +     *          entry associated with the request.
  +     *
  +     * @see #setRequireReauthentication
  +     */
  +    public boolean getRequireReauthentication()
  +    {
  +        return requireReauthentication;
  +    }
  +
  +
  +    /**
  +     * Sets whether each request needs to be reauthenticated (by an
  +     * Authenticator downstream in the pipeline) to the security
  +     * <code>Realm</code>, or if this Valve can itself bind security info
  +     * to the request, based on the presence of a valid SSO entry, without
  +     * rechecking with the <code>Realm</code.
  +     * <p>
  +     * If this property is <code>false</code> (the default), this
  +     * <code>Valve</code> will bind a UserPrincipal and AuthType to the request
  +     * if a valid SSO entry is associated with the request.  It will not notify
  +     * the security <code>Realm</code> of the incoming request.
  +     * <p>
  +     * This property should be set to <code>true</code> if the overall server
  +     * configuration requires that the <code>Realm</code> reauthenticate each
  +     * request thread.  An example of such a configuration would be one where
  +     * the <code>Realm</code> implementation provides security for both a
  +     * web tier and an associated EJB tier, and needs to set security
  +     * credentials on each request thread in order to support EJB access.
  +     * <p>
  +     * If this property is set to <code>true</code>, this Valve will set flags
  +     * on the request notifying the downstream Authenticator that the request
  +     * is associated with an SSO session.  The Authenticator will then call its
  +     * {@link AuthenticatorBase#reauthenticateFromSSO reauthenticateFromSSO}
  +     * method to attempt to reauthenticate the request to the
  +     * <code>Realm</code>, using any credentials that were cached with this
  +     * Valve.
  +     * <p>
  +     * The default value of this property is <code>false</code>, in order
  +     * to maintain backward compatibility with previous versions of Tomcat.
  +     *
  +     * @param required  <code>true</code> if it is required that a downstream
  +     *                  Authenticator reauthenticate each request before calls
  +     *                  to  <code>HttpServletRequest.setUserPrincipal()</code>
  +     *                  and <code>HttpServletRequest.setAuthType()</code> are
  +     *                  made; <code>false</code> if the <code>Valve</code> can
  +     *                  itself make those calls relying on the presence of a
  +     *                  valid SingleSignOn entry associated with the request.
  +     *
  +     * @see AuthenticatorBase#reauthenticateFromSSO
  +     */
  +    public void setRequireReauthentication(boolean required)
  +    {
  +        this.requireReauthentication = required;
  +    }
  +
  +
       // ------------------------------------------------------ Lifecycle Methods
   
   
  @@ -299,9 +376,23 @@
           }
           if (ssoId == null)
               return;
  +        
   
  -        // Deregister this single session id, invalidating associated sessions
  -        deregister(ssoId);
  +        /*
  +         *  Was the session destroyed as the result of a timeout?
  +         *  If so, we'll just remove the expired session from the
  +         *  SSO.  If the session was logged out, we'll log out
  +         *  of all session associated with the SSO.
  +         */
  +        if (System.currentTimeMillis() - session.getLastAccessedTime() >=
  +                session.getMaxInactiveInterval() * 1000) {            
  +            removeSession(ssoId, session);
  +        }
  +        else {
  +            // The session was logged out.
  +            // Deregister this single session id, invalidating associated sessions
  +            deregister(ssoId);
  +        }
   
       }
   
  @@ -384,11 +475,14 @@
           if (entry != null) {
               if (debug >= 1)
                   log(" Found cached principal '" +
  -                    entry.principal.getName() + "' with auth type '" +
  -                    entry.authType + "'");
  +                    entry.getPrincipal().getName() + "' with auth type '" +
  +                    entry.getAuthType() + "'");
               request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
  -            ((HttpRequest) request).setAuthType(entry.authType);
  -            ((HttpRequest) request).setUserPrincipal(entry.principal);
  +            // Only set security elements if reauthentication is not required
  +            if (!getRequireReauthentication()) {
  +                ((HttpRequest) request).setAuthType(entry.getAuthType());
  +                ((HttpRequest) request).setUserPrincipal(entry.getPrincipal());
  +            }
           } else {
               if (debug >= 1)
                   log(" No cached principal found, erasing SSO cookie");
  @@ -510,6 +604,81 @@
   
       }
   
  +    
  +    /**
  +     * Remove a single Session from a SingleSignOn.  Called when
  +     * a session is timed out and no longer active.
  +     *
  +     * @param ssoId Single sign on identifier from which to remove the session.
  +     * @param session the session to be removed.
  +     */
  +    void removeSession(String ssoId, Session session) {
  +        
  +        if (debug >= 1)
  +            log("Removing session " + session.toString() + " from sso id " + 
  +                ssoId );
  +        
  +        // Get a reference to the SingleSignOn
  +        SingleSignOnEntry entry = lookup(ssoId);
  +        if (entry == null)
  +            return;
  +       
  +        // Remove the inactive session from SingleSignOnEntry
  +        entry.removeSession(session);
  +    
  +        // Remove the inactive session from the 'reverse' Map.
  +        synchronized(reverse) {
  +            reverse.remove(session);
  +        }
  +    
  +        // If there are not sessions left in the SingleSignOnEntry,
  +        // deregister the entry.
  +        if (entry.findSessions().length == 0) {
  +            deregister(ssoId);
  +        }
  +    }
  +
  +    
  +    /**
  +     * Updates any <code>SingleSignOnEntry</code> found under key
  +     * <code>ssoId</code> with the given authentication data.
  +     * <p>
  +     * The purpose of this method is to allow an SSO entry that was
  +     * established without a username/password combination (i.e. established
  +     * following DIGEST or CLIENT-CERT authentication) to be updated with
  +     * a username and password if one becomes available through a subsequent
  +     * BASIC or FORM authentication.  The SSO entry will then be usable for
  +     * reauthentication.
  +     * <p>
  +     * <b>NOTE:</b> Only updates the SSO entry if a call to
  +     * <code>SingleSignOnEntry.getCanReauthenticate()</code> returns
  +     * <code>false</code>; otherwise, it is assumed that the SSO entry already
  +     * has sufficient information to allow reauthentication and that no update
  +     * is needed.
  +     *
  +     * @param ssoId identifier of Single sign to be updated
  +     * @param principal the <code>Principal</code> returned by the latest
  +     *                  call to <code>Realm.authenticate</code>.
  +     * @param authType  the type of authenticator used (BASIC, CLIENT-CERT,
  +     *                  DIGEST or FORM)
  +     * @param username  the username (if any) used for the authentication
  +     * @param password  the password (if any) used for the authentication
  +     */
  +    void update(String ssoId, Principal principal, String authType,
  +                  String username, String password) {
  +
  +        SingleSignOnEntry sso = lookup(ssoId);
  +        if (sso != null && !sso.getCanReauthenticate()) {
  +            if (debug >= 1)
  +                log("Update sso id " + ssoId + " to auth type " + authType);
  +
  +            synchronized(sso) {
  +                sso.updateCredentials(principal, authType, username, password);
  +            }
  +
  +        }
  +    }
  +
   
       // ------------------------------------------------------ Protected Methods
   
  @@ -561,53 +730,6 @@
               return ((SingleSignOnEntry) cache.get(ssoId));
           }
   
  -    }
  -
  -
  -}
  -
  -
  -// ------------------------------------------------------------ Private Classes
  -
  -
  -/**
  - * A private class representing entries in the cache of authenticated users.
  - */
  -class SingleSignOnEntry {
  -
  -    public String authType = null;
  -
  -    public String password = null;
  -
  -    public Principal principal = null;
  -
  -    public Session sessions[] = new Session[0];
  -
  -    public String username = null;
  -
  -    public SingleSignOnEntry(Principal principal, String authType,
  -                             String username, String password) {
  -        super();
  -        this.principal = principal;
  -        this.authType = authType;
  -        this.username = username;
  -        this.password = password;
  -    }
  -
  -    public synchronized void addSession(SingleSignOn sso, Session session) {
  -        for (int i = 0; i < sessions.length; i++) {
  -            if (session == sessions[i])
  -                return;
  -        }
  -        Session results[] = new Session[sessions.length + 1];
  -        System.arraycopy(sessions, 0, results, 0, sessions.length);
  -        results[sessions.length] = session;
  -        sessions = results;
  -        session.addSessionListener(sso);
  -    }
  -
  -    public synchronized Session[] findSessions() {
  -        return (this.sessions);
       }
   
   }
  
  
  
  1.9       +10 -0     jakarta-tomcat-4.0/webapps/tomcat-docs/config/valve.xml
  
  Index: valve.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/webapps/tomcat-docs/config/valve.xml,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- valve.xml	12 Jan 2003 17:26:48 -0000	1.8
  +++ valve.xml	24 Dec 2003 20:40:50 -0000	1.9
  @@ -309,6 +309,16 @@
           <p>Detail level of debugging messages created by this component.  By
           default, this is set to zero (0), which means no debug output.</p>
         </attribute>
  +        
  +      <attribute name="requireReauthentication" required="false">
  +        <p>Default false. Flag to determine whether each request needs to be 
  +        reauthenticated to the security <strong>Realm</strong>. If "true", this
  +        Valve uses cached security credentials (username and password) to
  +        reauthenticate to the <strong>Realm</strong> each request associated 
  +        with an SSO session.  If "false", the Valve can itself authenticate 
  +        requests based on the presence of a valid SSO cookie, without 
  +        rechecking with the <strong>Realm</strong>.</p>
  +      </attribute>
   
       </attributes>
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org