funkman     2003/11/21 11:09:22

  Modified:    catalina/src/share/org/apache/catalina/realm JDBCRealm.java
  Log:
  Backport JDBCRealm from 5 which had the following fixes:
  7116 - JDBC realm doesn't handle NULL passwords
  10623 - JDBCRealm lacks one DB commit, preventing sucessfull authentication under 
certain circunstances
  11929 - In case db connection is bad (stale due to firewall ...) - retry 
authenticating (2 tries total)
          And many dups
  8091 - Allow tomcat to startup even if the database isn't available
  (and some other dup bz items)
  
  Import cleanup
  
  Revision  Changes    Path
  1.22      +109 -83   
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.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- JDBCRealm.java    9 Jun 2002 02:19:43 -0000       1.21
  +++ JDBCRealm.java    21 Nov 2003 19:09:22 -0000      1.22
  @@ -64,8 +64,6 @@
   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;
  @@ -74,17 +72,9 @@
   import java.sql.SQLException;
   import java.util.ArrayList;
   import java.util.Properties;
  -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.HexUtils;
  -import org.apache.catalina.util.LifecycleSupport;
   import org.apache.catalina.util.StringManager;
  -import org.apache.catalina.util.Base64;
   
   
   /**
  @@ -95,13 +85,12 @@
   *
   * <p><strong>TODO</strong> - Support connection pooling (including message
   * format objects) so that <code>authenticate()</code> does not have to be
  -* synchronized.</p>
  +* synchronized and would fix the ugly connection logic. </p>
   *
   * @author Craig R. McClanahan
   * @author Carson McDonald
   * @author Ignacio Ortega
  -* @version $Revision$ $Date$
  -*/
  +* @version $Revision$ $Date$*/
   
   public class JDBCRealm
       extends RealmBase {
  @@ -377,43 +366,53 @@
        * event is also logged, and the connection will be closed so that
        * a subsequent request will automatically re-open it.
        *
  +     *
        * @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) {
  +    public synchronized Principal authenticate(String username, String credentials) 
{
   
  -        Connection dbConnection = null;
  +        // Number of tries is the numebr of attempts to connect to the database
  +        // during this login attempt (if we need to open the database)
  +        // This needs rewritten wuth better pooling support, the existing code
  +        // needs signature changes since the Prepared statements needs cached
  +        // with the connections.
  +        // The code below will try twice if there is a SQLException so the
  +        // connection may try to be opened again. On normal conditions (including
  +        // invalid login - the above is only used once.
  +        int numberOfTries = 2;
  +        while (numberOfTries>0) {
  +            try {
   
  -        try {
  +                // Ensure that we have an open database connection
  +                open();
   
  -            // Ensure that we have an open database connection
  -            dbConnection = open();
  +                // Acquire a Principal object for this user
  +                Principal principal = authenticate(dbConnection,
  +                                                   username, credentials);
   
  -            // Acquire a Principal object for this user
  -            Principal principal = authenticate(dbConnection,
  -                                               username, credentials);
   
  -            // Release the database connection we just used
  -            release(dbConnection);
  +                // Return the Principal (if any)
  +                return (principal);
   
  -            // Return the Principal (if any)
  -            return (principal);
  +            } catch (SQLException e) {
   
  -        } catch (SQLException e) {
  +                // Log the problem for posterity
  +                log(sm.getString("jdbcRealm.exception"), e);
   
  -            // Log the problem for posterity
  -            log(sm.getString("jdbcRealm.exception"), e);
  +                // Close the connection so that it gets reopened next time
  +                if (dbConnection != null)
  +                    close(dbConnection);
   
  -            // Close the connection so that it gets reopened next time
  -            if (dbConnection != null)
  -                close(dbConnection);
  -
  -            // Return "not authenticated" for this request
  -            return (null);
  +            }
   
  +            numberOfTries--;
           }
   
  +        // Worst case scenario
  +        return null;
  +
       }
   
   
  @@ -441,47 +440,70 @@
   
           // Look up the user's credentials
           String dbCredentials = null;
  -        PreparedStatement stmt = credentials(dbConnection, username);
  -        ResultSet rs = stmt.executeQuery();
  -        while (rs.next()) {
  -            dbCredentials = rs.getString(1).trim();
  -        }
  -        rs.close();
  -        if (dbCredentials == null) {
  -            return (null);
  -        }
  +        PreparedStatement stmt = null;
  +        ResultSet 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));
  -
  -        if (validated) {
  -            if (debug >= 2)
  -                log(sm.getString("jdbcRealm.authenticateSuccess",
  -                                 username));
  -        } else {
  -            if (debug >= 2)
  -                log(sm.getString("jdbcRealm.authenticateFailure",
  -                                 username));
  -            return (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();
   
  -        // Accumulate the user's roles
  -        ArrayList list = new ArrayList();
  -        stmt = roles(dbConnection, username);
  -        rs = stmt.executeQuery();
  -        while (rs.next()) {
  -            list.add(rs.getString(1).trim());
  -        }
  -        rs.close();
  -        dbConnection.commit();
   
  -        // Create and return a suitable Principal for this user
  -        return (new GenericPrincipal(this, username, credentials, list));
  +            // 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("jdbcRealm.authenticateSuccess",
  +                                     username));
  +            } else {
  +                if (debug >= 2)
  +                    log(sm.getString("jdbcRealm.authenticateFailure",
  +                                     username));
  +                return (null);
  +            }
  +
  +            // 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;
  +
  +            // 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();
  +        }
   
       }
   
  @@ -503,24 +525,26 @@
           } catch (Throwable f) {
               ;
           }
  +        this.preparedCredentials = null;
  +
  +
           try {
               preparedRoles.close();
           } catch (Throwable f) {
               ;
           }
  +        this.preparedRoles = null;
  +
   
           // Close this database connection, and log any errors
           try {
               dbConnection.close();
           } catch (SQLException e) {
               log(sm.getString("jdbcRealm.close"), e); // Just log it here
  +        } finally {
  +           this.dbConnection = null;
           }
   
  -        // Release resources associated with the closed connection
  -        this.dbConnection = null;
  -        this.preparedCredentials = null;
  -        this.preparedRoles = null;
  -
       }
   
   
  @@ -674,11 +698,12 @@
        */
       public void start() throws LifecycleException {
   
  -        // Validate that we can open our connection
  +        // Validate that we can open our connection - but let tomcat
  +        // startup in case the database is temporarily unavailable
           try {
               open();
           } catch (SQLException e) {
  -            throw new LifecycleException(sm.getString("jdbcRealm.open"), e);
  +            log(sm.getString("jdbcRealm.open"), e);
           }
   
           // Perform normal superclass initialization
  @@ -705,3 +730,4 @@
   
   
   }
  +
  
  
  

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

Reply via email to