craigmcc    01/07/30 13:04:05

  Modified:    catalina/src/share/org/apache/catalina Realm.java
               catalina/src/share/org/apache/catalina/authenticator
                        LocalStrings.properties SSLAuthenticator.java
               catalina/src/share/org/apache/catalina/realm RealmBase.java
  Log:
  Realm:  Add a new authenticate() method signature that takes a client
  certificate chain (presumably provided when the CLIENT-CERT login method
  is selected.
  
  RealmBase:  Provide a default implementation of the new authenticate()
  signature that does the following:
  * (Optionally, but default=true) Ask the certificate chain to check
    validity on each included certificate.
  * Call the getPrincipal() method of the actual implementation class
    to return a Principal based on the username of the first certificate
    in the chain (i.e. the client itself).  As a side effect of this change,
    role lookups for CLIENT-CERT authenticated principals will now work
    the same as for BASIC, DIGEST, and FORM based authentications.
  
  SSLAuthenticator:  Use the new Realm.authenticate() signature in a manner
  similar to that used by the other Authenticator implementations.
  
  This is a partial solution to BugTraq #4485977.
  
  Revision  Changes    Path
  1.4       +15 -4     
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Realm.java
  
  Index: Realm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Realm.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Realm.java        2001/07/22 20:13:30     1.3
  +++ Realm.java        2001/07/30 20:04:04     1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Realm.java,v 1.3 
2001/07/22 20:13:30 pier Exp $
  - * $Revision: 1.3 $
  - * $Date: 2001/07/22 20:13:30 $
  + * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Realm.java,v 1.4 
2001/07/30 20:04:04 craigmcc Exp $
  + * $Revision: 1.4 $
  + * $Date: 2001/07/30 20:04:04 $
    *
    * ====================================================================
    *
  @@ -67,6 +67,7 @@
   
   import java.beans.PropertyChangeListener;
   import java.security.Principal;
  +import java.security.cert.X509Certificate;
   
   
   /**
  @@ -77,7 +78,7 @@
    * Container.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.3 $ $Date: 2001/07/22 20:13:30 $
  + * @version $Revision: 1.4 $ $Date: 2001/07/30 20:04:04 $
    */
   
   public interface Realm {
  @@ -158,6 +159,16 @@
                                     String nonce, String nc, String cnonce,
                                     String qop, String realm,
                                     String md5a2);
  +
  +
  +    /**
  +     * Return the Principal associated with the specified chain of X509
  +     * client certificates.  If there is none, return <code>null</code>.
  +     *
  +     * @param certs Array of client certificates, with the first one in
  +     *  the array being the certificate of the client itself.
  +     */
  +    public Principal authenticate(X509Certificate certs[]);
   
   
       /**
  
  
  
  1.3       +1 -0      
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/LocalStrings.properties,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- LocalStrings.properties   2000/09/12 00:10:09     1.2
  +++ LocalStrings.properties   2001/07/30 20:04:04     1.3
  @@ -7,4 +7,5 @@
   authenticator.notAuthenticated=Configuration error:  Cannot perform access control 
without an authenticated principal
   authenticator.notContext=Configuration error:  Must be attached to a Context
   authenticator.notStarted=Security Interceptor has not yet been started
  +authenticator.unauthorized=Cannot authenticate with the provided credentials
   authenticator.userDataConstraint=This request violates a User Data constraint for 
this application
  
  
  
  1.8       +19 -23    
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.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- SSLAuthenticator.java     2001/07/22 20:09:19     1.7
  +++ SSLAuthenticator.java     2001/07/30 20:04:04     1.8
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java,v
 1.7 2001/07/22 20:09:19 pier Exp $
  - * $Revision: 1.7 $
  - * $Date: 2001/07/22 20:09:19 $
  + * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java,v
 1.8 2001/07/30 20:04:04 craigmcc Exp $
  + * $Revision: 1.8 $
  + * $Date: 2001/07/30 20:04:04 $
    *
    * ====================================================================
    *
  @@ -86,7 +86,7 @@
    * that utilizes SSL certificates to identify client users.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.7 $ $Date: 2001/07/22 20:09:19 $
  + * @version $Revision: 1.8 $ $Date: 2001/07/30 20:04:04 $
    */
   
   public final class SSLAuthenticator
  @@ -137,10 +137,15 @@
           // Have we already authenticated someone?
           Principal principal =
               ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  -        if (principal != null)
  +        if (principal != null) {
  +            if (debug >= 1)
  +                log("Already authenticated '" + principal.getName() + "'");
               return (true);
  +        }
   
           // Retrieve the certificate chain for this client
  +        HttpServletResponse hres =
  +            (HttpServletResponse) response.getResponse();
           if (debug >= 1)
               log(" Looking up certificates");
           X509Certificate certs[] = (X509Certificate[])
  @@ -148,28 +153,19 @@
           if ((certs == null) || (certs.length < 1)) {
               if (debug >= 1)
                   log("  No certificates included with this request");
  -            ((HttpServletResponse) response.getResponse()).
  -                sendError(HttpServletResponse.SC_BAD_REQUEST,
  -                          sm.getString("authenticator.certificates"));
  +            hres.sendError(HttpServletResponse.SC_BAD_REQUEST,
  +                           sm.getString("authenticator.certificates"));
               return (false);
           }
  -        principal = certs[0].getSubjectDN();
   
  -        // Check the validity of each certificate in the chain
  -        for (int i = 0; i < certs.length; i++) {
  +        // Authenticate the specified certificate chain
  +        principal = context.getRealm().authenticate(certs);
  +        if (principal == null) {
               if (debug >= 1)
  -                log(" Checking validity for '" +
  -                    certs[i].getSubjectDN().getName() + "'");
  -            try {
  -                certs[i].checkValidity();
  -            } catch (Exception e) {
  -                if (debug >= 1)
  -                    log("  Validity exception", e);
  -                ((HttpServletResponse) response.getResponse()).
  -                    sendError(HttpServletResponse.SC_FORBIDDEN,
  -                              sm.getString("authenticator.invalid"));
  -                return (false);
  -            }
  +                log("  Realm.authenticate() returned false");
  +            hres.sendError(HttpServletResponse.SC_UNAUTHORIZED,
  +                           sm.getString("authenticator.unauthorized"));
  +            return (false);
           }
   
           // Cache the principal (if requested) and record this authentication
  
  
  
  1.5       +69 -4     
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/RealmBase.java
  
  Index: RealmBase.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/RealmBase.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- RealmBase.java    2001/07/22 20:25:11     1.4
  +++ RealmBase.java    2001/07/30 20:04:04     1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/RealmBase.java,v
 1.4 2001/07/22 20:25:11 pier Exp $
  - * $Revision: 1.4 $
  - * $Date: 2001/07/22 20:25:11 $
  + * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/RealmBase.java,v
 1.5 2001/07/30 20:04:04 craigmcc Exp $
  + * $Revision: 1.5 $
  + * $Date: 2001/07/30 20:04:04 $
    *
    * ====================================================================
    *
  @@ -70,6 +70,7 @@
   import java.security.Principal;
   import java.security.MessageDigest;
   import java.security.NoSuchAlgorithmException;
  +import java.security.cert.X509Certificate;
   import java.io.File;
   import org.apache.catalina.Container;
   import org.apache.catalina.Lifecycle;
  @@ -94,7 +95,7 @@
    * location) are identical to those currently supported by Tomcat 3.X.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.4 $ $Date: 2001/07/22 20:25:11 $
  + * @version $Revision: 1.5 $ $Date: 2001/07/30 20:04:04 $
    */
   
   public abstract class RealmBase
  @@ -175,6 +176,12 @@
       protected PropertyChangeSupport support = new PropertyChangeSupport(this);
   
   
  +    /**
  +     * Should we validate client certificate chains when they are presented?
  +     */
  +    protected boolean validate = true;
  +
  +
       // ------------------------------------------------------------- Properties
   
   
  @@ -257,6 +264,28 @@
       }
   
   
  +    /**
  +     * Return the "validate certificate chains" flag.
  +     */
  +    public boolean getValidate() {
  +
  +        return (this.validate);
  +
  +    }
  +
  +
  +    /**
  +     * Set the "validate certificate chains" flag.
  +     *
  +     * @param validate The new validate certificate chains flag
  +     */
  +    public void setValidate(boolean validate) {
  +
  +        this.validate = validate;
  +
  +    }
  +
  +
       // --------------------------------------------------------- Public Methods
   
   
  @@ -356,6 +385,42 @@
               return null;
       }
   
  +
  +
  +    /**
  +     * Return the Principal associated with the specified chain of X509
  +     * client certificates.  If there is none, return <code>null</code>.
  +     *
  +     * @param certs Array of client certificates, with the first one in
  +     *  the array being the certificate of the client itself.
  +     */
  +    public Principal authenticate(X509Certificate certs[]) {
  +
  +        if ((certs == null) || (certs.length < 1))
  +            return (null);
  +
  +        // Check the validity of each certificate in the chain
  +        if (debug >= 1)
  +            log("Authenticating client certificate chain");
  +        if (validate) {
  +            for (int i = 0; i < certs.length; i++) {
  +                if (debug >= 2)
  +                    log(" Checking validity for '" +
  +                        certs[i].getSubjectDN().getName() + "'");
  +                try {
  +                    certs[i].checkValidity();
  +                } catch (Exception e) {
  +                    if (debug >= 2)
  +                        log("  Validity exception", e);
  +                    return (null);
  +                }
  +            }
  +        }
  +
  +        // Check the existence of the client Principal in our database
  +        return (getPrincipal(certs[0].getSubjectDN().getName()));
  +
  +    }
   
   
       /**
  
  
  

Reply via email to