remm        2003/11/24 08:46:56

  Modified:    catalina/src/share/org/apache/catalina/authenticator
                        AuthenticatorBase.java BasicAuthenticator.java
                        DigestAuthenticator.java FormAuthenticator.java
                        NonLoginAuthenticator.java SSLAuthenticator.java
                        SingleSignOn.java mbeans-descriptors.xml
  Added:       catalina/src/share/org/apache/catalina/authenticator
                        SingleSignOnEntry.java
  Log:
  - Bug 23881: SSO in embedded Tomcat.
  - Patch submitted by Brian Stansberry. Thanks :)
  
  Revision  Changes    Path
  1.14      +86 -20    
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java
  
  Index: AuthenticatorBase.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- AuthenticatorBase.java    23 Oct 2003 17:33:10 -0000      1.13
  +++ AuthenticatorBase.java    24 Nov 2003 16:46:56 -0000      1.14
  @@ -625,7 +625,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
  @@ -643,7 +643,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);
  @@ -801,6 +800,53 @@
   
   
       /**
  +     * 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 (log.isDebugEnabled()) {
  +                    log.debug(" 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
  @@ -825,9 +871,9 @@
           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 (session != null) {
                   session.setAuthType(authType);
                   session.setPrincipal(principal);
  @@ -845,19 +891,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.3       +26 -7     
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java
  
  Index: BasicAuthenticator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- BasicAuthenticator.java   12 Mar 2003 06:00:23 -0000      1.2
  +++ BasicAuthenticator.java   24 Nov 2003 16:46:56 -0000      1.3
  @@ -133,7 +133,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
  @@ -146,12 +146,31 @@
           // Have we already authenticated someone?
           Principal principal =
               ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  +        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
           if (principal != null) {
               if (log.isDebugEnabled())
                   log.debug("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 (log.isDebugEnabled())
  +                log.debug("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
           HttpServletRequest hreq =
               (HttpServletRequest) request.getRequest();
  @@ -171,8 +190,8 @@
           String realmName = config.getRealmName();
           if (realmName == null)
               realmName = hreq.getServerName() + ":" + hreq.getServerPort();
  -    //        if (debug >= 1)
  -    //            log("Challenging for realm '" + realmName + "'");
  +    //        if (log.isDebugEnabled())
  +    //            log.debug("Challenging for realm '" + realmName + "'");
           hres.setHeader("WWW-Authenticate",
                          "Basic realm=\"" + realmName + "\"");
           hres.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  
  
  
  1.3       +46 -11    
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java
  
  Index: DigestAuthenticator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- DigestAuthenticator.java  2 Sep 2003 21:22:04 -0000       1.2
  +++ DigestAuthenticator.java  24 Nov 2003 16:46:56 -0000      1.3
  @@ -75,6 +75,9 @@
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
  +
   import org.apache.catalina.HttpRequest;
   import org.apache.catalina.HttpResponse;
   import org.apache.catalina.Realm;
  @@ -94,6 +97,7 @@
   
   public class DigestAuthenticator
       extends AuthenticatorBase {
  +    private static Log log = LogFactory.getLog(DigestAuthenticator.class);
   
   
       // -------------------------------------------------------------- Constants
  @@ -206,7 +210,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
  @@ -219,8 +223,42 @@
           // 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 (log.isDebugEnabled())
  +                log.debug("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 (log.isDebugEnabled())
  +                log.debug("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
           HttpServletRequest hreq =
  @@ -264,8 +302,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,
  @@ -292,7 +328,6 @@
           String qop = null;
           String uri = null;
           String response = null;
  -        String opaque = null;
           String method = request.getMethod();
   
           while (commaTokenizer.hasMoreTokens()) {
  @@ -434,8 +469,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.5       +23 -10    
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java
  
  Index: FormAuthenticator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- FormAuthenticator.java    2 Sep 2003 21:22:04 -0000       1.4
  +++ FormAuthenticator.java    24 Nov 2003 16:46:56 -0000      1.5
  @@ -138,7 +138,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
  @@ -157,16 +157,32 @@
   
           // Have we already authenticated someone?
           Principal principal = hreq.getUserPrincipal();
  +        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
           if (principal != null) {
               if (log.isDebugEnabled())
                   log.debug("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 (log.isDebugEnabled())
  +                log.debug("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);
  @@ -205,9 +221,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 (log.isDebugEnabled())
                       log.debug("Proceed to restored request");
  @@ -380,7 +393,7 @@
               while (paramNames.hasNext()) {
                   String paramName = (String) paramNames.next();
                   String paramValues[] =
  -                    (String[]) saved.getParameterValues(paramName);
  +                    saved.getParameterValues(paramName);
                   request.addParameter(paramName, paramValues);
               }
           }
  
  
  
  1.3       +14 -5     
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/NonLoginAuthenticator.java
  
  Index: NonLoginAuthenticator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/NonLoginAuthenticator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- NonLoginAuthenticator.java        2 Sep 2003 21:22:04 -0000       1.2
  +++ NonLoginAuthenticator.java        24 Nov 2003 16:46:56 -0000      1.3
  @@ -119,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
  @@ -129,6 +129,15 @@
                                   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");
           return (true);
  
  
  
  1.10      +36 -5     
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java
  
  Index: SSLAuthenticator.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- SSLAuthenticator.java     17 Oct 2003 18:47:43 -0000      1.9
  +++ SSLAuthenticator.java     24 Nov 2003 16:46:56 -0000      1.10
  @@ -122,7 +122,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
  @@ -135,11 +135,42 @@
           // 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 (log.isDebugEnabled())
  +                log.debug("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.8       +121 -66   
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java
  
  Index: SingleSignOn.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- SingleSignOn.java 15 Nov 2003 09:42:26 -0000      1.7
  +++ SingleSignOn.java 24 Nov 2003 16:46:56 -0000      1.8
  @@ -145,6 +145,12 @@
        */
       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 +197,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
  +     * [EMAIL PROTECTED] 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
   
   
  @@ -301,10 +376,6 @@
           if (ssoId == null)
               return;
   
  -        deregister(ssoId);
  -        // FIXME: There's no way right now to specify per application or
  -        // global logout
  -        /*
           if ( event.getData() != null 
                && "logout".equals( event.getData().toString() )) {
               // logout of all applications
  @@ -313,7 +384,6 @@
               // invalidate just one session
               deregister(ssoId, session);
           }
  -        */
   
       }
   
  @@ -396,11 +466,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");
  @@ -433,7 +506,7 @@
       }
   
   
  -    // -------------------------------------------------------- Package Methods
  +    // ------------------------------------------------------ Protected Methods
   
   
       /**
  @@ -553,9 +626,6 @@
       }
   
   
  -    // ------------------------------------------------------ Protected Methods
  -
  -
       /**
        * Log a message on the Logger associated with our Container (if any).
        *
  @@ -605,61 +675,46 @@
   
       }
   
  +    //----------------------------------------------  Package-Protected Methods
   
  -}
  -
  -
  -// ------------------------------------------------------------ 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;
  +    /**
  +     * 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) {
   
  -    public SingleSignOnEntry(Principal principal, String authType,
  -                             String username, String password) {
  -        super();
  -        this.principal = principal;
  -        this.authType = authType;
  -        this.username = username;
  -        this.password = password;
  -    }
  +        SingleSignOnEntry sso = lookup(ssoId);
  +        if (sso != null && !sso.getCanReauthenticate()) {
  +            if (debug >= 1)
  +                log("Update sso id " + ssoId + " to auth type " + authType);
   
  -    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);
  -    }
  +            synchronized(sso) {
  +                sso.updateCredentials(principal, authType, username, password);
  +            }
   
  -    public synchronized void removeSession(Session session) {
  -        Session[] nsessions = new Session[sessions.length - 1];
  -        for (int i = 0, j = 0; i < sessions.length; i++) {
  -            if (session == sessions[i])
  -                continue;
  -            nsessions[j++] = sessions[i];
           }
  -        sessions = nsessions;
  -    }
  -
  -    public synchronized Session[] findSessions() {
  -        return (this.sessions);
       }
   
   }
  
  
  
  1.2       +4 -0      
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/mbeans-descriptors.xml
  
  Index: mbeans-descriptors.xml
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/mbeans-descriptors.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- mbeans-descriptors.xml    19 Mar 2003 07:29:20 -0000      1.1
  +++ mbeans-descriptors.xml    24 Nov 2003 16:46:56 -0000      1.2
  @@ -129,6 +129,10 @@
       <attribute name="debug"
                  description="The debugging detail level for this component"
                  type="int"/>
  +
  +    <attribute name="requireReauthentication"
  +               description="Should we attempt to reauthenticate each request 
against the security Realm?"
  +               type="boolean"/>
         
     </mbean>
   
  
  
  
  1.1                  
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/SingleSignOnEntry.java
  
  Index: SingleSignOnEntry.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/authenticator/SingleSignOnEntry.java,v
 1.1 2003/11/24 16:46:56 remm Exp $
   * $Revision: 1.1 $
   * $Date: 2003/11/24 16:46:56 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  package org.apache.catalina.authenticator;
  
  import java.security.Principal;
  
  import org.apache.catalina.Session;
  import org.apache.catalina.authenticator.Constants;
  
  /**
   * A class that represents entries in the cache of authenticated users.
   * This is necessary to make it available to
   * <code>AuthenticatorBase</code> subclasses that need it in order to perform
   * reauthentications when SingleSignOn is in use.
   *
   * @author  B Stansberry, based on work by Craig R. McClanahan
   * @version $Revision: 1.1 $
   *
   * @see SingleSignOn
   * @see AuthenticatorBase#reauthenticateFromSSO
   */
  class SingleSignOnEntry
  {
      // ------------------------------------------------------  Instance Fields
  
      private String authType = null;
  
      private String password = null;
  
      private Principal principal = null;
  
      private Session sessions[] = new Session[0];
  
      private String username = null;
  
      private boolean canReauthenticate = false;
  
      // ---------------------------------------------------------  Constructors
  
      /**
       * Creates a new SingleSignOnEntry
       *
       * @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
       */
      SingleSignOnEntry(Principal principal, String authType,
                          String username, String password) {        
          super();
          updateCredentials(principal, authType, username, password);
      }
  
      // ------------------------------------------------------- Package Methods
  
      /**
       * Adds a <code>Session</code> to the list of those associated with
       * this SSO.
       *
       * @param sso       The <code>SingleSignOn</code> valve that is managing
       *                  the SSO session.
       * @param session   The <code>Session</code> being associated with the SSO.
       */
      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);
      }
  
      /**
       * Removes the given <code>Session</code> from the list of those
       * associated with this SSO.
       *
       * @param session  the <code>Session</code> to remove.
       */
      synchronized void removeSession(Session session) {
          Session[] nsessions = new Session[sessions.length - 1];
          for (int i = 0, j = 0; i < sessions.length; i++) {
              if (session == sessions[i])
                  continue;
              nsessions[j++] = sessions[i];
          }
          sessions = nsessions;
      }
  
      /**
       * Returns the <code>Session</code>s associated with this SSO.
       */
      synchronized Session[] findSessions() {
          return (this.sessions);
      }
  
      /**
       * Gets the name of the authentication type originally used to authenticate
       * the user associated with the SSO.
       *
       * @return "BASIC", "CLIENT-CERT", "DIGEST", "FORM" or "NONE"
       */
      String getAuthType() {
          return (this.authType);
      }
  
      /**
       * Gets whether the authentication type associated with the original
       * authentication supports reauthentication.
       *
       * @return  <code>true</code> if <code>getAuthType</code> returns
       *          "BASIC" or "FORM", <code>false</code> otherwise.
       */
      boolean getCanReauthenticate() {
          return (this.canReauthenticate);
      }
  
      /**
       * Gets the password credential (if any) associated with the SSO.
       *
       * @return  the password credential associated with the SSO, or
       *          <code>null</code> if the original authentication type
       *          does not involve a password.
       */
      String getPassword() {
          return (this.password);
      }
  
      /**
       * Gets the <code>Principal</code> that has been authenticated by
       * the SSO.
       */
      Principal getPrincipal() {
          return (this.principal);
      }
  
      /**
       * Gets the username provided by the user as part of the authentication
       * process.
       */
      String getUsername() {
          return (this.username);
      }
  
  
      /**
       * Updates the SingleSignOnEntry to reflect the latest security
       * information associated with the caller.
       *
       * @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 updateCredentials(Principal principal, String authType,
                  String username, String password) {
  
          this.principal = principal;
          this.authType = authType;
          this.username = username;
          this.password = password;
          this.canReauthenticate =
              (Constants.BASIC_METHOD.equals(authType)
                  || Constants.FORM_METHOD.equals(authType));
      }
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to