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]