markt       2004/11/27 10:29:44

  Modified:    catalina/src/share/org/apache/catalina/realm
                        DataSourceRealm.java JAASRealm.java JDBCRealm.java
                        LocalStrings.properties MemoryRealm.java
                        RealmBase.java UserDatabaseRealm.java
               webapps/tomcat-docs realm-howto.xml
  Log:
  Fix bug 19767.  Port support for digested passwords with DIGEST
    authentication for JDBC and DataSource realms from TC5.
  
  Remove unused imports in o.a.c.realm package
  
  Revision  Changes    Path
  1.4       +135 -73   
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java
  
  Index: DataSourceRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- DataSourceRealm.java      26 Aug 2004 21:37:21 -0000      1.3
  +++ DataSourceRealm.java      27 Nov 2004 18:29:44 -0000      1.4
  @@ -18,36 +18,20 @@
   package org.apache.catalina.realm;
   
   
  -import java.io.File;
  -import java.security.MessageDigest;
   import java.security.Principal;
   import java.sql.Connection;
  -import java.sql.Driver;
   import java.sql.PreparedStatement;
   import java.sql.ResultSet;
   import java.sql.SQLException;
   import java.util.ArrayList;
  -import java.util.Properties;
   
  -import javax.naming.InitialContext;
   import javax.naming.Context;
  -import javax.naming.NamingException;
   import javax.sql.DataSource;
   
  -import org.apache.catalina.Container;
  -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;
  -import org.apache.catalina.Realm;
  -import org.apache.catalina.Server;
   import org.apache.catalina.ServerFactory;
   import org.apache.catalina.core.StandardServer;
  -import org.apache.catalina.util.HexUtils;
  -import org.apache.catalina.util.LifecycleSupport;
   import org.apache.catalina.util.StringManager;
  -import org.apache.catalina.util.Base64;
   
   /**
   *
  @@ -323,64 +307,37 @@
        */
       private Principal authenticate(Connection dbConnection,
                                                  String username,
  -                                               String credentials)
  -        throws SQLException {
  +                                               String credentials) {
   
  -        ResultSet rs = null;
  -        PreparedStatement stmt = null;
  -        ArrayList list = null;
   
  -        try {
  -            // Look up the user's credentials
  -            String dbCredentials = null;
  -            stmt = credentials(dbConnection, username);
  -            rs = stmt.executeQuery();
  -            while (rs.next()) {
  -                dbCredentials = rs.getString(1).trim();
  -            }
  -            rs.close();
  -            rs = null;
  -            stmt.close();
  -            stmt = null;
  -            if (dbCredentials == null) {
  -                return (null);
  -            }
  -    
  -            // Validate the user's credentials
  -            boolean validated = false;
  -            if (hasMessageDigest()) {
  -                // Hex hashes should be compared case-insensitive
  -                validated = 
(digest(credentials).equalsIgnoreCase(dbCredentials));
  -            } else
  -                validated = (digest(credentials).equals(dbCredentials));
  -    
  -            if (validated) {
  -                if (debug >= 2)
  -                    log(sm.getString("dataSourceRealm.authenticateSuccess",
  -                                     username));
  -            } else {
  -                if (debug >= 2)
  -                    log(sm.getString("dataSourceRealm.authenticateFailure",
  -                                     username));
  -                return (null);
  -            }
  -    
  -            // Accumulate the user's roles
  -            list = new ArrayList();
  -            stmt = roles(dbConnection, username);
  -            rs = stmt.executeQuery();
  -            while (rs.next()) {
  -                list.add(rs.getString(1).trim());
  -            }
  -        } finally {
  -            if (rs != null) {
  -                rs.close();
  -            }
  -            if (stmt != null) {
  -                stmt.close();
  -            }
  +        // No user - can't possibly authenticate
  +        if (username == null) {
  +            return (null);
           }
   
  +        String dbCredentials = getPassword(username);
  +
  +        // Validate the user's credentials
  +        boolean validated = false;
  +        if (hasMessageDigest()) {
  +            // Hex hashes should be compared case-insensitive
  +            validated = 
(digest(credentials).equalsIgnoreCase(dbCredentials));
  +        } else
  +            validated = (digest(credentials).equals(dbCredentials));
  +
  +        if (validated) {
  +            if (debug >=2)
  +                log(sm.getString("dataSourceRealm.authenticateSuccess",
  +                                 username));
  +        } else {
  +            if (debug >=2)
  +                log(sm.getString("dataSourceRealm.authenticateFailure",
  +                                 username));
  +            return (null);
  +        }
  +
  +        ArrayList list = getRoles(username);
  +
           // Create and return a suitable Principal for this user
           return (new GenericPrincipal(this, username, credentials, list));
   
  @@ -455,7 +412,7 @@
        */
       protected String getName() {
   
  -        return (this.name);
  +        return (DataSourceRealm.name);
   
       }
   
  @@ -465,6 +422,60 @@
        */
       protected String getPassword(String username) {
   
  +        ResultSet rs = null;
  +        PreparedStatement stmt = null;
  +        ArrayList list = null;
  +        Connection dbConnection = null;
  +
  +        // Ensure that we have an open database connection
  +        dbConnection = open();
  +        if (dbConnection == null) {
  +            return null;
  +        }
  +
  +        try {
  +            // Look up the user's credentials
  +            String dbCredentials = null;
  +            stmt = credentials(dbConnection, username);
  +            rs = stmt.executeQuery();
  +            if (rs.next()) {
  +                dbCredentials = rs.getString(1);
  +            }
  +            rs.close();
  +            rs = null;
  +            stmt.close();
  +            stmt = null;
  +            if (dbCredentials == null) {
  +                return (null);
  +            }
  +            dbCredentials = dbCredentials.trim();
  +
  +            return (dbCredentials);
  +            
  +        } catch(SQLException e) {
  +             log(sm.getString("datasourceRealm.getPassword.exception",
  +                    username));
  +        } finally {
  +             try {
  +                 if (rs != null) {
  +                     rs.close();
  +                 }
  +                 if (stmt != null) {
  +                     stmt.close();
  +                 }
  +                 if( !dbConnection.getAutoCommit() ) {
  +                     dbConnection.commit();             
  +                 }
  +             } catch (SQLException e) {
  +             log(sm.getString("datasourceRealm.getPassword.exception",
  +                        username));
  +                     
  +             }
  +            // Release the database connection we just used
  +            close(dbConnection);
  +            dbConnection = null;
  +
  +        }
           return (null);
   
       }
  @@ -475,10 +486,61 @@
        */
       protected Principal getPrincipal(String username) {
   
  -        return (null);
  +        return (new GenericPrincipal(this,
  +                username,
  +                getPassword(username),
  +                getRoles(username)));
   
       }
   
  +
  +
  +    /**
  +     * Return the roles associated with the gven user name.
  +     */
  +    protected ArrayList getRoles(String username) {
  +
  +        ResultSet rs = null;
  +        PreparedStatement stmt = null;
  +        Connection dbConnection = null;
  +
  +        // Ensure that we have an open database connection
  +        dbConnection = open();
  +        if (dbConnection == null) {
  +            return null;
  +        }
  +
  +        try {
  +            // Accumulate the user's roles
  +            ArrayList list = new ArrayList();
  +            stmt = roles(dbConnection, username);
  +            rs = stmt.executeQuery();
  +            while (rs.next()) {
  +                String role = rs.getString(1);
  +                if (role != null) {
  +                    list.add(role.trim());
  +                }
  +            }
  +            
  +            return (list);
  +        } catch(SQLException e) {
  +            log(sm.getString("datasourceRealm.getRoles.exception", 
username));
  +        } finally {
  +             try {
  +                 if (rs != null) {
  +                     rs.close();
  +                 }
  +                 if (stmt != null) {
  +                     stmt.close();
  +                 }
  +            } catch(SQLException e) {
  +             log(sm.getString("datasourceRealm.getRoles.exception",
  +                        username));
  +             }
  +        }
  +
  +        return (null);
  +    }
   
   
       /**
  
  
  
  1.6       +2 -4      
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASRealm.java
  
  Index: JAASRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASRealm.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- JAASRealm.java    26 Aug 2004 21:37:21 -0000      1.5
  +++ JAASRealm.java    27 Nov 2004 18:29:44 -0000      1.6
  @@ -21,14 +21,12 @@
   import java.security.Principal;
   import java.util.ArrayList;
   import java.util.Iterator;
  -import java.util.Set;
   import javax.security.auth.Subject;
   import javax.security.auth.login.AccountExpiredException;
   import javax.security.auth.login.CredentialExpiredException;
   import javax.security.auth.login.FailedLoginException;
   import javax.security.auth.login.LoginContext;
   import javax.security.auth.login.LoginException;
  -import org.apache.catalina.Lifecycle;
   import org.apache.catalina.LifecycleException;
   import org.apache.catalina.util.StringManager;
   
  @@ -296,7 +294,7 @@
        */
       protected String getName() {
   
  -        return (this.name);
  +        return (JAASRealm.name);
   
       }
   
  
  
  
  1.25      +117 -68   
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JDBCRealm.java
  
  Index: JDBCRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JDBCRealm.java,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- JDBCRealm.java    26 Aug 2004 21:37:21 -0000      1.24
  +++ JDBCRealm.java    27 Nov 2004 18:29:44 -0000      1.25
  @@ -44,7 +44,8 @@
   * @author Craig R. McClanahan
   * @author Carson McDonald
   * @author Ignacio Ortega
  -* @version $Revision$ $Date$*/
  +* @version $Revision$ $Date$
  +*/
   
   public class JDBCRealm
       extends RealmBase {
  @@ -384,81 +385,42 @@
        * @param username Username of the Principal to look up
        * @param credentials Password or other credentials to use in
        *  authenticating this username
  -     *
  -     * @exception SQLException if a database error occurs
        */
       public synchronized Principal authenticate(Connection dbConnection,
                                                  String username,
  -                                               String credentials)
  -        throws SQLException {
  -
  -        // Look up the user's credentials
  -        String dbCredentials = null;
  -        PreparedStatement stmt = null;
  -        ResultSet rs = null;
  -
  -        try {
  -            stmt = credentials(dbConnection, username);
  -            rs = stmt.executeQuery();
  -
  -            if (rs.next()) {
  -                dbCredentials = rs.getString(1);
  -            }
  -            rs.close();
  -            rs = null;
  -            if (dbCredentials == null) {
  -                return (null);
  -            }
  -
  -            dbCredentials = dbCredentials.trim();
  +                                               String credentials) {
   
   
  -            // Validate the user's credentials
  -            boolean validated = false;
  -            if (hasMessageDigest()) {
  -                // Hex hashes should be compared case-insensitive
  -                validated = 
(digest(credentials).equalsIgnoreCase(dbCredentials));
  -            } else {
  -                validated = (digest(credentials).equals(dbCredentials));
  -            }
  +        // No user - can't possibly authenticate
  +        if (username == null) {
  +            return (null);
  +        }
   
  -            if (validated) {
  -                if (debug >= 2)
  -                    log(sm.getString("jdbcRealm.authenticateSuccess",
  -                                     username));
  -            } else {
  -                if (debug >= 2)
  -                    log(sm.getString("jdbcRealm.authenticateFailure",
  -                                     username));
  -                return (null);
  -            }
  +        // Look up the user's credentials
  +        String dbCredentials = getPassword(username);
   
  -            // Accumulate the user's roles
  -            ArrayList roleList = new ArrayList();
  -            stmt = roles(dbConnection, username);
  -            rs = stmt.executeQuery();
  -            while (rs.next()) {
  -                String role = rs.getString(1);
  -                if (null!=role) {
  -                    roleList.add(role.trim());
  -                }
  -            }
  -            rs.close();
  -            rs = null;
  +        // Validate the user's credentials
  +        boolean validated = false;
  +        if (hasMessageDigest()) {
  +            // Hex hashes should be compared case-insensitive
  +            validated = 
(digest(credentials).equalsIgnoreCase(dbCredentials));
  +        } else {
  +            validated = (digest(credentials).equals(dbCredentials));
  +        }
   
  -            // Create and return a suitable Principal for this user
  -            return (new GenericPrincipal(this, username, credentials, 
roleList));
  -        } finally {
  -            if (rs!=null) {
  -                try {
  -                    rs.close();
  -                } catch(SQLException e) {
  -                    log(sm.getString("jdbcRealm.abnormalCloseResultSet"));
  -                }
  -            }
  -            dbConnection.commit();
  +        if (validated) {
  +            if (debug >= 2)
  +                log(sm.getString("jdbcRealm.authenticateSuccess", username));
  +        } else {
  +            if (debug >=2)
  +                log(sm.getString("jdbcRealm.authenticateFailure",
 username));
  +            return (null);
           }
   
  +        ArrayList roles = getRoles(username);
  +        
  +        // Create and return a suitable Principal for this user
  +        return (new GenericPrincipal(this, username, credentials, roles));
       }
   
   
  @@ -542,7 +504,7 @@
        */
       protected String getName() {
   
  -        return (this.name);
  +        return (JDBCRealm.name);
   
       }
   
  @@ -552,6 +514,44 @@
        */
       protected String getPassword(String username) {
   
  +        // Look up the user's credentials
  +        String dbCredentials = null;
  +        PreparedStatement stmt = null;
  +        ResultSet rs = null;
  +
  +        try {
  +            stmt = credentials(dbConnection, username);
  +            rs = stmt.executeQuery();
  +
  +            if (rs.next()) {
  +                dbCredentials = rs.getString(1);
  +            }
  +            rs.close();
  +            rs = null;
  +            if (dbCredentials == null) {
  +                return (null);
  +            }
  +
  +            dbCredentials = dbCredentials.trim();
  +            return dbCredentials;
  +            
  +        } catch(SQLException e){
  +            log(sm.getString("jdbcRealm.getPassword.exception", username));
  +        } finally {
  +            if (rs!=null) {
  +                try {
  +                    rs.close();
  +                } catch(SQLException e) {
  +                    log(sm.getString("jdbcRealm.abnormalCloseResultSet"));
  +                }
  +            }
  +            try {
  +                dbConnection.commit();
  +            } catch (SQLException e) {
  +                log(sm.getString("jdbcRealm.getPassword.exception", 
username));
  +            }
  +        }
  +        
           return (null);
   
       }
  @@ -562,11 +562,60 @@
        */
       protected Principal getPrincipal(String username) {
   
  -        return (null);
  +        return (new GenericPrincipal(this,
  +                                     username,
  +                                     getPassword(username),
  +                                     getRoles(username)));
   
       }
   
   
  +    /**
  +     * Return the roles associated with the gven user name.
  +     */
  +    protected ArrayList getRoles(String username) {
  +        
  +        PreparedStatement stmt = null;
  +        ResultSet rs = null;
  +
  +        try {
  +            // Accumulate the user's roles
  +            ArrayList roleList = new ArrayList();
  +            stmt = roles(dbConnection, username);
  +            rs = stmt.executeQuery();
  +            while (rs.next()) {
  +                String role = rs.getString(1);
  +                if (null!=role) {
  +                    roleList.add(role.trim());
  +                }
  +            }
  +            rs.close();
  +            rs = null;
  +            
  +            return (roleList);
  +            
  +        } catch(SQLException e){
  +            log(sm.getString("jdbcRealm.getRoles.exception", username));
  +        } finally {
  +            if (rs!=null) {
  +                try {
  +                    rs.close();
  +                } catch(SQLException e) {
  +                    log(sm.getString("jdbcRealm.abnormalCloseResultSet"));
  +                }
  +            }
  +            try {
  +                dbConnection.commit();
  +            } catch (SQLException e) {
  +                log(sm.getString("jdbcRealm.getRoles.exception", username));
  +            }
  +        }
  +
  +        return (null);
  +        
  +    }
  +    
  +    
       /**
        * Open (if necessary) and return a database connection for use by
        * this Realm.
  
  
  
  1.10      +5 -1      
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- LocalStrings.properties   12 Dec 2003 22:39:22 -0000      1.9
  +++ LocalStrings.properties   27 Nov 2004 18:29:44 -0000      1.10
  @@ -13,6 +13,8 @@
   jdbcRealm.authenticateSuccess=Username {0} successfully authenticated
   jdbcRealm.close=Exception closing database connection
   jdbcRealm.exception=Exception performing authentication
  +jdbcRealm.getPassword.exception=Exception retrieving password for "{0}"
  +jdbcRealm.getRoles.exception=Exception retrieving roles for "{0}"
   jdbcRealm.open=Exception opening database connection
   jndiRealm.authenticateFailure=Username {0} NOT successfully authenticated
   jndiRealm.authenticateSuccess=Username {0} successfully authenticated
  @@ -41,4 +43,6 @@
   dataSourceRealm.authenticateSuccess=Username {0} successfully authenticated
   dataSourceRealm.close=Exception closing database connection
   dataSourceRealm.exception=Exception performing authentication
  +datasourceRealm.getPassword.exception=Exception retrieving password for "{0}"
  +datasourceRealm.getRoles.exception=Exception retrieving roles for "{0}"
   dataSourceRealm.open=Exception opening database connection
  
  
  
  1.15      +2 -8      
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/MemoryRealm.java
  
  Index: MemoryRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/MemoryRealm.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- MemoryRealm.java  26 Aug 2004 21:37:21 -0000      1.14
  +++ MemoryRealm.java  27 Nov 2004 18:29:44 -0000      1.15
  @@ -23,13 +23,7 @@
   import java.util.ArrayList;
   import java.util.HashMap;
   import org.apache.catalina.Container;
  -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;
  -import org.apache.catalina.Realm;
  -import org.apache.catalina.util.LifecycleSupport;
   import org.apache.catalina.util.StringManager;
   import org.apache.commons.digester.Digester;
   
  @@ -243,7 +237,7 @@
        */
       protected String getName() {
   
  -        return (this.name);
  +        return (MemoryRealm.name);
   
       }
   
  
  
  
  1.15      +99 -15    
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.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- RealmBase.java    26 Aug 2004 21:37:21 -0000      1.14
  +++ RealmBase.java    27 Nov 2004 18:29:44 -0000      1.15
  @@ -24,10 +24,10 @@
   import java.security.MessageDigest;
   import java.security.NoSuchAlgorithmException;
   import java.security.cert.X509Certificate;
  -import java.io.File;
  +import java.io.UnsupportedEncodingException;
  +
   import org.apache.catalina.Container;
   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;
  @@ -74,6 +74,11 @@
        */
       protected String digest = null;
   
  +    /**
  +     * The encoding charset for the digest.
  +     */
  +    protected String digestEncoding = null;
  +
   
       /**
        * Descriptive information about this Realm implementation.
  @@ -202,6 +207,24 @@
   
   
       /**
  +     * Returns the digest encoding charset.
  +     *
  +     * @return The charset (may be null) for platform default
  +     */
  +    public String getDigestEncoding() {
  +        return digestEncoding;
  +    }
  +
  +    /**
  +     * Sets the digest encoding charset.
  +     *
  +     * @param charset The charset (null for platform default)
  +     */
  +    public void setDigestEncoding(String charset) {
  +        digestEncoding = charset;
  +    }
  +
  +    /**
        * Return descriptive information about this Realm implementation and
        * the corresponding version number, in the format
        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  @@ -262,9 +285,18 @@
   
           String serverCredentials = getPassword(username);
   
  -        if ( (serverCredentials == null)
  -             || (!serverCredentials.equals(credentials)) )
  +        boolean validated;
  +        if ( serverCredentials == null ) {
  +            validated = false;
  +        } else if(hasMessageDigest()) {
  +            validated = 
serverCredentials.equalsIgnoreCase(digest(credentials));
  +        } else {
  +            validated = serverCredentials.equals(credentials);
  +        }
  +
  +        if(! validated ) {
               return null;
  +        }
   
           return getPrincipal(username);
   
  @@ -322,14 +354,24 @@
           String md5a1 = getDigest(username, realm);
           if (md5a1 == null)
               return null;
  -        String serverDigestValue;
  -        if (!"auth".equals(qop))
  -          serverDigestValue = md5a1 + ":" + nOnce + ":" + md5a2;
  -        else
  -          serverDigestValue = md5a1 + ":" + nOnce + ":" + nc + ":"
  +        String serverDigestValue = md5a1 + ":" + nOnce + ":" + nc + ":"
               + cnonce + ":" + qop + ":" + md5a2;
  +
  +        byte[] valueBytes = null;
  +        if(getDigestEncoding() == null) {
  +            valueBytes = serverDigestValue.getBytes();
  +        } else {
  +            try {
  +                valueBytes = serverDigestValue.getBytes(getDigestEncoding());
  +            } catch (UnsupportedEncodingException uee) {
  +                log("Illegal digestEncoding: " + getDigestEncoding(), uee);
  +                throw new IllegalArgumentException(uee.getMessage());
  +            }
  +        }
  +
           String serverDigest =
  -            
md5Encoder.encode(md5Helper.digest(serverDigestValue.getBytes()));
  +            md5Encoder.encode(md5Helper.digest(valueBytes));
  +
           //System.out.println("Server digest : " + serverDigest);
   
           if (serverDigest.equals(clientDigest))
  @@ -389,12 +431,18 @@
        */
       public boolean hasRole(Principal principal, String role) {
   
  +        // Should be overriten in JAASRealm - to avoid pretty inefficient 
conversions
           if ((principal == null) || (role == null) ||
               !(principal instanceof GenericPrincipal))
               return (false);
  +
           GenericPrincipal gp = (GenericPrincipal) principal;
  -        if (!(gp.getRealm() == this))
  -            return (false);
  +        if (!(gp.getRealm() == this)) {
  +            if (debug >= 2) {
  +                log("Different realm " + this + " " + gp.getRealm());
  +            }
  +        }
  +
           boolean result = gp.hasRole(role);
           if (debug >= 2) {
               String name = principal.getName();
  @@ -539,7 +587,20 @@
           synchronized (this) {
               try {
                   md.reset();
  -                md.update(credentials.getBytes());
  +    
  +                byte[] bytes = null;
  +                if(getDigestEncoding() == null) {
  +                    bytes = credentials.getBytes();
  +                } else {
  +                    try {
  +                        bytes = credentials.getBytes(getDigestEncoding());
  +                    } catch (UnsupportedEncodingException uee) {
  +                        log("Illegal digestEncoding: " + 
getDigestEncoding(), uee);
  +                        throw new IllegalArgumentException(uee.getMessage());
  +                    }
  +                }
  +                md.update(bytes);
  +
                   return (HexUtils.convert(md.digest()));
               } catch (Exception e) {
                   log(sm.getString("realmBase.digest"), e);
  @@ -565,10 +626,30 @@
                   throw new IllegalStateException();
               }
           }
  +
  +     if (hasMessageDigest()) {
  +             // Use pre-generated digest
  +             return getPassword(username);
  +     }
  +     
           String digestValue = username + ":" + realmName + ":"
               + getPassword(username);
  +
  +        byte[] valueBytes = null;
  +        if(getDigestEncoding() == null) {
  +            valueBytes = digestValue.getBytes();
  +        } else {
  +            try {
  +                valueBytes = digestValue.getBytes(getDigestEncoding());
  +            } catch (UnsupportedEncodingException uee) {
  +                log("Illegal digestEncoding: " + getDigestEncoding(), uee);
  +                throw new IllegalArgumentException(uee.getMessage());
  +            }
  +        }
  +
           byte[] digest =
  -            md5Helper.digest(digestValue.getBytes());
  +            md5Helper.digest(valueBytes);
  +
           return md5Encoder.encode(digest);
       }
   
  @@ -657,8 +738,11 @@
               // Obtain a new message digest with "digest" encryption
               MessageDigest md =
                   (MessageDigest) MessageDigest.getInstance(algorithm).clone();
  + 
               // encode the credentials
  +            // Should use the digestEncoding, but that's not a static field
               md.update(credentials.getBytes());
  +
               // Digest the credentials and return as hexadecimal
               return (HexUtils.convert(md.digest()));
           } catch(Exception ex) {
  
  
  
  1.11      +31 -62    
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java
  
  Index: UserDatabaseRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- UserDatabaseRealm.java    26 Aug 2004 21:37:21 -0000      1.10
  +++ UserDatabaseRealm.java    27 Nov 2004 18:29:44 -0000      1.11
  @@ -19,7 +19,6 @@
   
   
   import java.security.Principal;
  -import java.util.ArrayList;
   import java.util.Iterator;
   import javax.naming.Context;
   import org.apache.catalina.LifecycleException;
  @@ -126,74 +125,44 @@
   
       // --------------------------------------------------------- Public 
Methods
   
  -
       /**
  -     * Return the Principal associated with the specified username and
  -     * credentials, if there is one; otherwise return <code>null</code>.
  +     * Return <code>true</code> if the specified Principal has the specified
  +     * security role, within the context of this Realm; otherwise return
  +     * <code>false</code>. This implementation returns <code>true</code>
  +     * if the <code>User</code> has the role, or if any <code>Group</code>
  +     * that the <code>User</code> is a member of has the role. 
        *
  -     * @param username Username of the Principal to look up
  -     * @param credentials Password or other credentials to use in
  -     *  authenticating this username
  -     */
  -    public Principal authenticate(String username, String credentials) {
  -
  -        // Does a user with this username exist?
  -        User user = database.findUser(username);
  -        if (user == null) {
  -            return (null);
  -        }
  -
  -        // Do the credentials specified by the user match?
  -        // FIXME - Update all realms to support encoded passwords
  -        boolean validated = false;
  -        if (hasMessageDigest()) {
  -            // Hex hashes should be compared case-insensitive
  -            validated = (digest(credentials)
  -                         .equalsIgnoreCase(user.getPassword()));
  -        } else {
  -            validated =
  -                (digest(credentials).equals(user.getPassword()));
  -        }
  -        if (!validated) {
  -            if (debug >= 2) {
  -                log(sm.getString("userDatabaseRealm.authenticateFailure",
  -                                 username));
  -            }
  -            return (null);
  -        }
  -
  -        // Construct a GenericPrincipal that represents this user
  -        if (debug >= 2) {
  -            log(sm.getString("userDatabaseRealm.authenticateSuccess",
  -                             username));
  +     * @param principal Principal for whom the role is to be checked
  +     * @param role Security role to be checked
  +     */
  +    public boolean hasRole(Principal principal, String role) {
  +        if(! (principal instanceof User) ) {
  +            //Play nice with SSO and mixed Realms
  +            return super.hasRole(principal, role);
  +        }
  +        if("*".equals(role)) {
  +            return true;
  +        } else if(role == null) {
  +            return false;
  +        }
  +        User user = (User)principal;
  +        Role dbrole = database.findRole(role);
  +        if(dbrole == null) {
  +            return false; 
           }
  -        ArrayList combined = new ArrayList();
  -        Iterator roles = user.getRoles();
  -        while (roles.hasNext()) {
  -            Role role = (Role) roles.next();
  -            String rolename = role.getRolename();
  -            if (!combined.contains(rolename)) {
  -                combined.add(rolename);
  -            }
  +        if(user.isInRole(dbrole)) {
  +            return true;
           }
           Iterator groups = user.getGroups();
  -        while (groups.hasNext()) {
  -            Group group = (Group) groups.next();
  -            roles = group.getRoles();
  -            while (roles.hasNext()) {
  -                Role role = (Role) roles.next();
  -                String rolename = role.getRolename();
  -                if (!combined.contains(rolename)) {
  -                    combined.add(rolename);
  -                }
  +        while(groups.hasNext()) {
  +            Group group = (Group)groups.next();
  +            if(group.isInRole(dbrole)) {
  +                return true;
               }
           }
  -        return (new GenericPrincipal(this, user.getUsername(),
  -                                     user.getPassword(), combined));
  -
  +        return false;
       }
   
  -
       // ------------------------------------------------------ Protected 
Methods
   
   
  @@ -202,7 +171,7 @@
        */
       protected String getName() {
   
  -        return (this.name);
  +        return (UserDatabaseRealm.name);
   
       }
   
  
  
  
  1.15      +7 -0      jakarta-tomcat-4.0/webapps/tomcat-docs/realm-howto.xml
  
  Index: realm-howto.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/webapps/tomcat-docs/realm-howto.xml,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- realm-howto.xml   21 Aug 2004 12:37:56 -0000      1.14
  +++ realm-howto.xml   27 Nov 2004 18:29:44 -0000      1.15
  @@ -1271,6 +1271,13 @@
       standard output.</li>
   </ul>
   
  +<p>If using digested passwords with DIGEST authentication, the cleartext used
  +   to generate the digest is different. In the examples above
  +   <code>{cleartext-password}</code> must be replaced with 
  +   <code>{username}:{realm}:{cleartext-password}</code>. For example, in a
  +   development environment this might take the form
  +   <code>testUser:localhost:8080:testPassword</code>.</p>
  +
   <p>To use either of the above techniques, the
   <code>$CATALINA_HOME/server/lib/catalina.jar</code> file will need to be
   on your class path to make the <code>RealmBase</code> class available.</p>
  
  
  

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

Reply via email to