nacho       01/07/13 20:20:37

  Modified:    src/share/org/apache/tomcat/modules/aaa SimpleRealm.java
                        JDBCRealm.java
  Added:       src/share/org/apache/tomcat/modules/aaa RealmBase.java
  Log:
  * Added RealmBase to simplify a bit Realms writing
  * Used RealmBase in Simple Realm to allow use of  digested passwords. there.
  * Used RealmBase in JDBCRealm.
  
  and ported this fix to JDBCRealm from Tomcat 3.2. branch
  
  Bug# 2149 , 727 ( possibly others )
  
  JDBCRealm did not close all the prepared staments opened,
  when trying to reconnect when found a broken DBConnection,
  I'ts a problem specillay surfaced when using MySQL..
  
  Reported By :
  mark.shotton at micromass.co.uk
  andre.gommlich at netkom.de
  edwin at finalist.com
  kaneda at dedaletechnology.com
  
  Revision  Changes    Path
  1.3       +44 -57    
jakarta-tomcat/src/share/org/apache/tomcat/modules/aaa/SimpleRealm.java
  
  Index: SimpleRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/aaa/SimpleRealm.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- SimpleRealm.java  2001/02/27 19:10:17     1.2
  +++ SimpleRealm.java  2001/07/14 03:20:37     1.3
  @@ -85,17 +85,12 @@
    *  specialized in extracting the information from the request.
    *
    */
  -public class SimpleRealm extends  BaseInterceptor {
  +public class SimpleRealm extends  RealmBase {
   
       MemoryRealm memoryRealm;
  -
  -    int reqRolesNote=-1;
  -    int userNote=-1;
  -    int passwordNote=-1;
  -
       String filename="/conf/users/tomcat-users.xml";
  +
   
  -    
       public SimpleRealm() {
       }
   
  @@ -109,17 +104,7 @@
       }
   
       // -------------------- Hooks --------------------
  -    public void engineInit( ContextManager cm )
  -     throws TomcatException
  -    {
  -     reqRolesNote = cm.getNoteId( ContextManager.REQUEST_NOTE,
  -                                  "required.roles");
  -     userNote=cm.getNoteId( ContextManager.REQUEST_NOTE,
  -                            "credentials.user");
  -     passwordNote=cm.getNoteId( ContextManager.REQUEST_NOTE,
  -                                "credentials.password");
  -    }
  -    
  +
       public void contextInit(Context ctx)
        throws TomcatException
       {
  @@ -137,37 +122,6 @@
        }
       }
   
  -    public int authenticate( Request req, Response response )
  -    {
  -     // This realm will use only username and password callbacks
  -     String user=(String)req.getNote( userNote );
  -     String password=(String)req.getNote( passwordNote );
  -     if( user==null) return DECLINED; // we don't know about this 
  -     
  -     if( debug > 0 ) log( "Verify user=" + user + " pass=" + password );
  -     SimpleRealmPrincipal srp=memoryRealm.getPrincipal( user );
  -     if( srp == null ) return DECLINED;
  -     
  -     if( srp.checkPassword( password ) ) {
  -         if( debug > 0 ) log( "Auth ok, user=" + user );
  -            Context ctx = req.getContext();
  -         req.setAuthType(ctx.getAuthMethod());
  -         req.setRemoteUser( user );
  -         req.setUserPrincipal( srp );
  -         
  -         if( user!=null ) {
  -             String userRoles[] = srp.getUserRoles( user );
  -             req.setUserRoles( userRoles );
  -         }
  -         return OK; // the user is ok, - no need for more work
  -     }
  -     return DECLINED; // the user is not known to me - it may
  -     // be in a different realm.
  -
  -     // XXX maybe we should add "realm-name" - the current behavior
  -     // is to treat them as "global users"
  -    }
  -
       class MemoryRealm {
           // String user -> password
        //        Hashtable passwords=new Hashtable();
  @@ -192,7 +146,7 @@
        public void addPrincipal( String name, Principal p ) {
            principals.put( name, p );
        }
  -     
  +
           public void addUser(String name, String pass, String groups ) {
               if( getDebug() > 0 )  log( "Add user " + name + " " +
                                       pass + " " + groups );
  @@ -225,7 +179,7 @@
                                      String user=attributes.getValue("name");
                                      String pass=attributes.getValue("password");
                                      String group=attributes.getValue("roles");
  -                                
  +
                                      mr.addUser( user, pass, group );
                                  }
                              }
  @@ -249,11 +203,9 @@
        private void addRole(String role ) {
            roles.addElement( role );
        }
  -     
  -     boolean checkPassword( String s ) {
  -         if( s == pass ) return true; // interned or nulls?
  -         if( s==null ) return false; // if pass == null already true
  -         return s.equals( pass );
  +
  +     String getCredentials() {
  +         return pass;
        }
   
        // backward compat - bad XML format !!!
  @@ -268,7 +220,7 @@
               }
        }
   
  -     String[] getUserRoles( String user ) {
  +     String[] getUserRoles( ) {
               String rolesA[]=new String[roles.size()];
               for( int i=0; i<roles.size(); i++ ) {
                   rolesA[i]=(String)roles.elementAt( i );
  @@ -280,6 +232,41 @@
        //             return roles.indexOf( role ) >=0 ;
        //         }
   
  +    }
  +
  +    /**
  +     * getPrincipal
  +     * @param username
  +     * @return java.security.Principal
  +     */
  +    protected Principal getPrincipal(String username) {
  +        return memoryRealm.getPrincipal( username );
  +    }
  +
  +    /**
  +     * getCredentials
  +     * @param username
  +     * @return java.lang.String
  +     */
  +    protected String getCredentials(String username) {
  +        SimpleRealmPrincipal sp=memoryRealm.getPrincipal( username );
  +        if( sp!=null ) {
  +            return sp.getCredentials();
  +        }
  +        return null;
  +    }
  +
  +    /**
  +     * getUserRoles
  +     * @param username
  +     * @return java.lang.String
  +     */
  +    protected String[] getUserRoles(String username) {
  +        SimpleRealmPrincipal sp=memoryRealm.getPrincipal( username );
  +        if( sp!=null ) {
  +            return sp.getUserRoles();
  +        }
  +        return null;
       }
   
   
  
  
  
  1.7       +85 -224   
jakarta-tomcat/src/share/org/apache/tomcat/modules/aaa/JDBCRealm.java
  
  Index: JDBCRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/aaa/JDBCRealm.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- JDBCRealm.java    2001/04/10 09:00:59     1.6
  +++ JDBCRealm.java    2001/07/14 03:20:37     1.7
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/aaa/JDBCRealm.java,v 1.6 
2001/04/10 09:00:59 nacho Exp $
  - * $Revision: 1.6 $
  - * $Date: 2001/04/10 09:00:59 $
  + * $Header: 
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/aaa/JDBCRealm.java,v 1.7 
2001/07/14 03:20:37 nacho Exp $
  + * $Revision: 1.7 $
  + * $Date: 2001/07/14 03:20:37 $
    *
    * The Apache Software License, Version 1.1
    *
  @@ -62,11 +62,10 @@
   package org.apache.tomcat.modules.aaa;
   
   import org.apache.tomcat.core.*;
  -import org.apache.tomcat.util.res.StringManager;
  -import org.apache.tomcat.util.buf.HexUtils;
   import org.apache.tomcat.util.aaa.*;
   import java.security.*;
   import java.security.Principal;
  +
   import java.util.Vector;
   import java.io.*;
   import java.net.*;
  @@ -78,21 +77,15 @@
    * See the JDBCRealm.howto for more details on how to set up the database and
    * for configuration options.
    *
  - *
  - * TODO: - Work on authentication with non-plaintext passwords
  - *
  - *
    * @author Craig R. McClanahan
    * @author Carson McDonald
    * @author Ignacio J. Ortega
    * @author Bip Thelin
    */
  -public final class JDBCRealm extends BaseInterceptor {
  -    int reqRolesNote;
  -    int userNote;
  -    int passwordNote;
  +public class JDBCRealm extends RealmBase {
       // ----------------------------------------------------- Instance Variables
   
  +    private boolean started=false;
       /** The connection to the database. */
       private Connection dbConnection = null;
   
  @@ -103,47 +96,34 @@
       private PreparedStatement preparedRoles = null;
   
       /** The connection URL to use when trying to connect to the databse */
  -    private String connectionURL = null;
  +    protected String connectionURL = null;
   
       /** The connection URL to use when trying to connect to the databse */
  -    private String connectionName = null;
  +    protected String connectionName = null;
   
       /** The connection URL to use when trying to connect to the databse */
  -    private String connectionPassword = null;
  +    protected String connectionPassword = null;
   
       /** The table that holds user data. */
  -    private String userTable = null;
  +    protected String userTable = null;
   
       /** The column in the user table that holds the user's name */
  -    private String userNameCol = null;
  +    protected String userNameCol = null;
   
       /** The column in the user table that holds the user's credintials */
  -    private String userCredCol = null;
  +    protected String userCredCol = null;
   
       /** The table that holds the relation between user's and roles */
  -    private String userRoleTable = null;
  +    protected String userRoleTable = null;
   
       /** The column in the user role table that names a role */
  -    private String roleNameCol = null;
  +    protected String roleNameCol = null;
   
       /** The JDBC driver to use. */
  -    private String driverName = null;
  +    protected String driverName = null;
   
  -    /** The string manager for this package. */
  -    private static StringManager sm = 
StringManager.getManager("org.apache.tomcat.resources");
  -
  -    /** Has this component been started? */
  -    private boolean started = false;
  -
       /** Has the JDBC connection been started? */
  -    private boolean JDBCstarted = false;
  -
  -    /**
  -     * Digest algorithm used in passwords thit is same values accepted by 
MessageDigest  for algorithm
  -     * plus "No" ( no encode ) that is the default
  -     */
  -    private String digest = "No";
  -
  +    protected boolean JDBCStarted = false;
       boolean connectOnInit = false;
       // ------------------------------------------------------------- Properties
   
  @@ -220,26 +200,6 @@
       }
   
       /**
  -     * Gets the digest algorithm  used for credentials in the database
  -     * could be the same that MessageDigest accepts vor algorithm and "No" that
  -     * is the Default
  -     * @return
  -     */
  -    public String getDigest() {
  -        return digest;
  -    }
  -
  -    /**
  -     * Sets the digest algorithm  used for credentials in the database
  -     * could be the same that MessageDigest accepts vor algorithm and "No"
  -     * that is the Default
  -     * @param algorithm the Encode type
  -     */
  -    public void setDigest(String algorithm) {
  -        digest = algorithm;
  -    }
  -
  -    /**
        * When connectOnInit is true the JDBC connection is started at tomcat init
        * if false the connection is started the first times it is needed.
        * @param b
  @@ -260,72 +220,55 @@
        * @param username Username of the Principal to look up
        * @param credentials Password or other credentials to use in authenticating 
this username
        */
  -    private synchronized boolean checkPassword(String username,String credentials) {
  +    public synchronized String getCredentials(String username){
           try {
               if (!checkConnection())
  -                return false;
  +                return null;
               // Create the authentication search prepared statement if necessary
               if (preparedAuthenticate == null) {
  -                String sql = "SELECT " + userCredCol
  -                    + " FROM " + userTable
  -                    + " WHERE " + userNameCol + " = ?";
  -                if (debug >= 1)
  -                    log("JDBCRealm.authenticate: " + sql);
  -                preparedAuthenticate = dbConnection.prepareStatement(sql);
  +                preparedAuthenticate=getPreparedAuthenticate(dbConnection);
               }
               // Perform the authentication search
               preparedAuthenticate.setString(1, username);
               ResultSet rs1 = preparedAuthenticate.executeQuery();
               if (rs1.next()) {
  -                String dbCredentials=rs1.getString(1).trim();
  -                if( digest.equals("") || digest.equalsIgnoreCase("No")){
  -                    if (credentials.equals(dbCredentials)) {
  -                        if (debug >= 2)
  -                            log(sm.getString("jdbcRealm.authenticateSuccess", 
username));
  -                        return true;
  -                    }
  -                } else {
  -                    if (digest(credentials,digest).equals(dbCredentials)) {
  -                        if (debug >= 2)
  -                            log(sm.getString("jdbcRealm.authenticateSuccess", 
username));
  -                        return true;
  -                    }
  -                }
  +                return rs1.getString(1).trim();
               }
               rs1.close();
  -            if (debug >= 2)
  -                log(sm.getString("jdbcRealm.authenticateFailure", username));
  -            return false;
  +            return null;
           } catch (SQLException ex) {
               // Log the problem for posterity
  -            log(sm.getString("jdbcRealm.checkPasswordSQLException", username), ex);
  +            log(sm.getString("jdbcRealm.getCredentialsSQLException", username), ex);
               // Clean up the JDBC objects so that they get recreated next time
  -            if (preparedAuthenticate != null) {
  -                try {
  -                    preparedAuthenticate.close();
  -                } catch (Throwable t) {
  -                    ;
  -                }
  -                preparedAuthenticate = null;
  -            }
  -            if (dbConnection != null) {
  -                try {
  -                    dbConnection.close();
  -                } catch (Throwable t) {
  -                    ;
  -                }
  -                dbConnection = null;
  -            }
               // Return "not authenticated" for this request
  -            return false;
  +            close();
  +            return null;
           }
       }
   
  +    protected PreparedStatement getPreparedAuthenticate(Connection conn) throws 
SQLException {
  +        String sql = "SELECT " + userCredCol
  +            + " FROM " + userTable
  +            + " WHERE " + userNameCol + " = ?";
  +        if (debug >= 1)
  +            log("JDBCRealm.authenticate: " + sql);
  +        return conn.prepareStatement(sql);
  +    }
  +
  +    protected PreparedStatement getPreparedRoles(Connection conn) throws 
SQLException {
  +        String sql = "SELECT " + roleNameCol + " FROM " + userRoleTable
  +                   + " WHERE " + userNameCol + " = ?";
  +        if (debug >= 1)
  +            log("JDBCRealm.roles: " + sql);
  +        return conn.prepareStatement(sql);
  +    }
  +
  +
       private boolean checkConnection() {
           try {
               if ((dbConnection == null) || dbConnection.isClosed()) {
                   Class.forName(driverName);
  -                if( JDBCstarted )
  +                if( JDBCStarted )
                           log(sm.getString("jdbcRealm.checkConnectionDBClosed"));
                   if ((connectionName == null || connectionName.equals("")) ||
                       (connectionPassword == null || connectionPassword.equals(""))) {
  @@ -334,7 +277,7 @@
                       dbConnection = DriverManager.getConnection(connectionURL,
                           connectionName, connectionPassword);
                   }
  -                JDBCstarted=true;
  +                JDBCStarted=true;
                   if (dbConnection == null || dbConnection.isClosed()) {
                       log(sm.getString("jdbcRealm.checkConnectionDBReOpenFail"));
                       return false;
  @@ -343,6 +286,7 @@
               return true;
           } catch (SQLException ex) {
               log(sm.getString("jdbcRealm.checkConnectionSQLException"), ex);
  +            close();
               return false;
           }
           catch (ClassNotFoundException ex) {
  @@ -361,11 +305,7 @@
               if (!checkConnection())
                   return null;
               if (preparedRoles == null) {
  -                String sql = "SELECT " + roleNameCol + " FROM " + userRoleTable
  -                           + " WHERE " + userNameCol + " = ?";
  -                if (debug >= 1)
  -                    log("JDBCRealm.roles: " + sql);
  -                preparedRoles = dbConnection.prepareStatement(sql);
  +                preparedRoles=getPreparedRoles(dbConnection);
               }
               preparedRoles.clearParameters();
               preparedRoles.setString(1, username);
  @@ -389,148 +329,69 @@
               // Set the connection to null.
               // Next time we will try to get a new connection.
               log(sm.getString("jdbcRealm.getUserRolesSQLException", username));
  -            if (preparedRoles != null) {
  -                try {
  -                    preparedRoles.close();
  -                } catch (Throwable t) {
  -                    ;
  -                }
  -                preparedRoles = null;
  -            }
  -            if (dbConnection != null) {
  -                try {
  -                    dbConnection.close();
  -                } catch (Throwable t) {
  -                    ;
  -                }
  -                dbConnection = null;
  -            }
  +            close();
           }
           return null;
       }
   
  -    // -------------------- Tomcat hooks --------------------
  -    public void contextInit(Context ctx) throws 
org.apache.tomcat.core.TomcatException {
  -        super.contextInit(ctx);
  -        init(ctx.getContextManager());
  -        // Validate and update our current component state
  -    }
  +    // Nothing - except carry on the class name information
  +    public static class JdbcPrincipal extends SimplePrincipal {
  +        private String name;
   
  -    public void contextShutdown(Context ctx) throws 
org.apache.tomcat.core.TomcatException {
  -        shutdown();
  +        JdbcPrincipal(String name) {
  +            super(name);
  +        }
  +              
       }
   
  -    public void shutdown() throws org.apache.tomcat.core.TomcatException {
  -        // Validate and update our current component state
  -        if (started) {
  -            started = false;
  +    private void close() {
  +        if (preparedRoles != null) {
               try {
  -                if (dbConnection != null && !dbConnection.isClosed())
  -                    dbConnection.close();
  -            } catch (SQLException ex) {
  -                log("dbConnection.close Exception!!!", ex);
  +                preparedRoles.close();
  +            } catch (Throwable t) {
  +                ;
               }
  +            preparedRoles = null;
           }
  -    }
  -
  -    /** Authenticate hook implementation  */
  -
  -    public int authenticate(Request req, Response response) {
  -        String user = (String)req.getNote(userNote);
  -        String password = (String)req.getNote(passwordNote);
  -        if (user == null) return DECLINED;
  -        if (checkPassword(user, password)) {
  -            if (debug > 0) log("Auth ok, user=" + user);
  -            Context ctx = req.getContext();
  -            if (ctx != null)
  -                req.setAuthType(ctx.getAuthMethod());
  -            if (user != null) {
  -                req.setRemoteUser(user);
  -             req.setUserPrincipal( new JdbcPrincipal( user ));
  -                String userRoles[] = getUserRoles(user);
  -                req.setUserRoles(userRoles);
  -                return OK;
  +        if (preparedAuthenticate != null) {
  +            try {
  +                preparedAuthenticate.close();
  +            } catch (Throwable t) {
  +                ;
               }
  +            preparedAuthenticate = null;
           }
  -        return DECLINED;
  -    }
  -
  -    /**
  -     * Digest password using the algorithm especificied and
  -     * convert the result to a corresponding hex string.
  -     * If exception, the plain credentials string is returned
  -     * @param credentials Password or other credentials to use in authenticating 
this username
  -     * @param algorithm Algorithm used to do th digest
  -     */
  -    public final static String digest(String credentials, String algorithm) {
  -        try {
  -            // Obtain a new message digest with MD5 encryption
  -            MessageDigest md = 
(MessageDigest)MessageDigest.getInstance(algorithm).clone();
  -            // encode the credentials
  -            md.update(credentials.getBytes());
  -            // obtain the byte array from the digest
  -            byte[] dig = md.digest();
  -            // convert the byte array to hex string
  -            //            Base64 enc=new Base64();
  -            //            return new 
String(enc.encode(HexUtils.convert(dig).getBytes()));
  -            return HexUtils.convert(dig);
  -        } catch (Exception ex) {
  -            ex.printStackTrace();
  -            return credentials;
  -        }
  -    }
  -
  -    /**
  -     * JDBCRealm can be used as a standalone tool for offline password digest
  -     * @param args
  -     */
  -    public static void main(String args[]) {
  -        if (args.length >= 2) {
  -            if (args[0].equalsIgnoreCase("-a")) {
  -                for (int i = 2; i < args.length; i++) {
  -                    System.out.print(args[i] + ":");
  -                    System.out.println(digest(args[i], args[1]));
  -                }
  +        if (dbConnection != null) {
  +            try {
  +                dbConnection.close();
  +            } catch (Throwable t) {
  +                ;
               }
  +            dbConnection = null;
           }
       }
   
  -     /** Called when the ContextManager is started */
  -    public void engineInit(ContextManager cm) throws TomcatException {
  -        super.engineInit(cm);
  -        init(cm);
  +    protected void ContextShutdown(Context ctx) throws TomcatException {
  +        if (started && JDBCStarted) close();
       }
   
  -    void init(ContextManager cm) {
  +    protected void ContextInit(Context ctx) throws TomcatException {
           if (!started) {
  -            started = true;
  -            // set-up a per/container note for maps
  -            try {
  -                // XXX make the name a "global" static - after everything is stable!
  -                reqRolesNote = cm.getNoteId(ContextManager.REQUEST_NOTE, 
"required.roles");
  -                userNote = cm.getNoteId(ContextManager.REQUEST_NOTE, 
"credentials.user");
  -                passwordNote = cm.getNoteId(ContextManager.REQUEST_NOTE, 
"credentials.password");
  -                if (connectOnInit && !checkConnection())
  -                        throw new RuntimeException("JDBCRealm cannot be started");
  -            }
  -            catch (TomcatException ex) {
  -                log("setting up note for " + cm, ex);
  -                throw new RuntimeException("Invalid state ");
  +            if (connectOnInit && !checkConnection()) {
  +                throw new RuntimeException("JDBCRealm cannot be started");
               }
  +            started=true;
           }
       }
   
  -    public void engineShutdown(ContextManager cm) throws TomcatException {
  -        shutdown();
  +    /**
  +     * getPrincipal
  +     * @param username
  +     * @return java.security.Principal
  +     */
  +    protected Principal getPrincipal(String username) {
  +        return new JdbcPrincipal( username );
       }
   
  -    // Nothing - except cary on the class name information 
  -    public static class JdbcPrincipal extends SimplePrincipal {
  -     private String name;
  -
  -     JdbcPrincipal(String name) {
  -         super(name);
  -     }
  -    }
   }
   
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/modules/aaa/RealmBase.java
  
  Index: RealmBase.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/aaa/RealmBase.java,v 1.1 
2001/07/14 03:20:37 nacho Exp $
   * $Revision: 1.1 $
   * $Date: 2001/07/14 03:20:37 $
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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.tomcat.modules.aaa;
  
  import org.apache.tomcat.util.res.StringManager;
  import org.apache.tomcat.core.*;
  
  import java.security.MessageDigest;
  import java.security.Principal;
  
  /*
  *  Abstract Base class for Realms.
  *  This class is intented to be a helper for defining Realms, it contains basic
  *  utils for Digesting passwords, and create associated notes.
  *  There are 3 abstract methods in this class, every Realm that inherits from
  *  RealmBase needs to define them to make a basic working Realm..they are:
  *
  *    protected abstract String getCredentials(String username);
  *    protected abstract String[] getUserRoles(String username);
  *    protected abstract Principal getPrincipal(String username);
  *
  *  Defining this methods and if needed contextInit and contextShutdown from
  *  BaseInterceptor are the only methods a Realm Writer needs
  *  to take into account to construct a functional Realm for Tomcat 3.3
  *
  *  A Complex Realm that need more control over the auth process can already
  *  inherit directly from BaseInterceptor.
  *
  */
  
  public abstract class RealmBase extends BaseInterceptor {
  
      int reqRolesNote=-1;
      int userNote=-1;
      int passwordNote=-1;
  
      /** The string manager for this package. */
      protected static StringManager sm = 
StringManager.getManager("org.apache.tomcat.resources");
  
      /**
       * Digest algorithm used in passwords thit is same values accepted by 
MessageDigest  for algorithm
       * plus "No" ( no encode ) that is the default
       */
      protected String digest = "No";
  
      /**
       * Gets the digest algorithm  used for credentials in the database
       * could be the same that MessageDigest accepts vor algorithm and "No" that
       * is the Default
       * @return
       */
      public String getDigest() {
          return digest;
      }
  
      /**
       * Sets the digest algorithm  used for credentials in the database
       * could be the same that MessageDigest accepts vor algorithm and "No"
       * that is the Default
       * @param algorithm the Encode type
       */
      public void setDigest(String algorithm) {
          digest = algorithm;
      }
  
      /**
       * Digest password using the algorithm especificied and
       * convert the result to a corresponding hex string.
       * If exception, the plain credentials string is returned
       * @param credentials Password or other credentials to use in authenticating 
this username
       * @param algorithm Algorithm used to do th digest
       */
      public static final String digest(String credentials,String algorithm ) {
          try {
              // Obtain a new message digest with MD5 encryption
              MessageDigest md = 
(MessageDigest)MessageDigest.getInstance(algorithm).clone();
              // encode the credentials
              md.update(credentials.getBytes());
              // obtain the byte array from the digest
              byte[] dig = md.digest();
              // convert the byte array to hex string
              //            Base64 enc=new Base64();
              //            return new 
String(enc.encode(HexUtils.convert(dig).getBytes()));
              return org.apache.tomcat.util.buf.HexUtils.convert(dig);
          } catch (Exception ex) {
              ex.printStackTrace();
              return credentials;
          }
      }
  
      /**
       * RealmBase can be used as a standalone tool for offline password digest
       * @param args
       */
      public static void main(String[] args) {
          if (args.length >= 2) {
              if (args[0].equalsIgnoreCase("-a")) {
                  for (int i = 2; i < args.length; i++) {
                      System.out.print(args[i] + ":");
                      System.out.println(digest(args[i], args[1]));
                  }
              }
          }
      }
      protected abstract String getCredentials(String username);
      protected abstract String[] getUserRoles(String username);
      protected abstract Principal getPrincipal(String username);
  
  
      String digest(String credentials) {
          if( digest.equals("") || digest.equalsIgnoreCase("No")){
              return credentials;
          } else {
              return digest(credentials,digest);
          }
      }
  
      public void engineInit( ContextManager cm )
        throws TomcatException
      {
        reqRolesNote = cm.getNoteId( ContextManager.REQUEST_NOTE,
                                     "required.roles");
        userNote=cm.getNoteId( ContextManager.REQUEST_NOTE,
                               "credentials.user");
        passwordNote=cm.getNoteId( ContextManager.REQUEST_NOTE,
                                   "credentials.password");
      }
  
  
      public int authenticate(Request req, Response response) {
          String user = (String)req.getNote(userNote);
          String password = (String)req.getNote(passwordNote);
          if (user == null) return DECLINED;
          if (checkPassword(user, password)) {
              if (debug > 0) log("Auth ok, user=" + user);
              Context ctx = req.getContext();
              if (ctx != null)
                  req.setAuthType(ctx.getAuthMethod());
              if (user != null) {
                  req.setRemoteUser(user);
                  req.setUserPrincipal( getPrincipal( user ));
                  String userRoles[] = getUserRoles(user);
                  req.setUserRoles(userRoles);
                  return OK;
              }
          }
          return DECLINED;
      }
      private boolean checkPassword(String username,String credentials) {
          // Create the authentication search prepared statement if necessary
          // Perform the authentication search
          if (digest(credentials).equals(getCredentials(username))) {
              if (debug >= 2)
                  log(sm.getString("jdbcRealm.authenticateSuccess", username));
              return true;
          }
          if (debug >= 2)
              log(sm.getString("jdbcRealm.authenticateFailure", username));
          return false;
      }
  }
  
  
  

Reply via email to