ASF Bugzilla – Attachment 14168 Details for
Bug 33357
DataSourceRealm leaks connections
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
o.a.c.realm.DataSourceRealm
DataSourceRealm.java (text/plain), 18.62 KB, created by
Dominik Drzewiecki
on 2005-02-03 10:56:24 UTC
(
hide
)
Description:
o.a.c.realm.DataSourceRealm
Filename:
MIME Type:
Creator:
Dominik Drzewiecki
Created:
2005-02-03 10:56:24 UTC
Size:
18.62 KB
patch
obsolete
>/* > * Copyright 1999,2004 The Apache Software Foundation. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > * You may obtain a copy of the License at > * > * http://www.apache.org/licenses/LICENSE-2.0 > * > * Unless required by applicable law or agreed to in writing, software > * distributed under the License is distributed on an "AS IS" BASIS, > * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > * See the License for the specific language governing permissions and > * limitations under the License. > */ > > >package org.apache.catalina.realm; > > >import java.security.Principal; >import java.sql.Connection; >import java.sql.PreparedStatement; >import java.sql.ResultSet; >import java.sql.SQLException; >import java.util.ArrayList; > >import javax.naming.Context; >import javax.sql.DataSource; > >import org.apache.naming.ContextBindings; >import org.apache.catalina.LifecycleException; >import org.apache.catalina.ServerFactory; >import org.apache.catalina.core.StandardServer; >import org.apache.catalina.util.StringManager; > >/** >* >* Implmentation of <b>Realm</b> that works with any JDBC JNDI DataSource. >* See the JDBCRealm.howto for more details on how to set up the database and >* for configuration options. >* >* @author Glenn L. Nielsen >* @author Craig R. McClanahan >* @author Carson McDonald >* @author Ignacio Ortega >* @version $Revision: 1.11 $ >*/ > >public class DataSourceRealm > extends RealmBase { > > > // ----------------------------------------------------- Instance Variables > > > /** > * The generated string for the roles PreparedStatement > */ > private StringBuffer preparedRoles = null; > > > /** > * The generated string for the credentials PreparedStatement > */ > private StringBuffer preparedCredentials = null; > > > /** > * The name of the JNDI JDBC DataSource > */ > protected String dataSourceName = null; > > > /** > * Descriptive information about this Realm implementation. > */ > protected static final String info = > "org.apache.catalina.realm.DataSourceRealm/1.0"; > > > /** > * Context local datasource. > */ > protected boolean localDataSource = false; > > > /** > * Descriptive information about this Realm implementation. > */ > protected static final String name = "DataSourceRealm"; > > > /** > * The column in the user role table that names a role > */ > protected String roleNameCol = null; > > > /** > * The string manager for this package. > */ > protected static final StringManager sm = > StringManager.getManager(Constants.Package); > > > /** > * The column in the user table that holds the user's credintials > */ > protected String userCredCol = null; > > > /** > * The column in the user table that holds the user's name > */ > protected String userNameCol = null; > > > /** > * The table that holds the relation between user's and roles > */ > protected String userRoleTable = null; > > > /** > * The table that holds user data. > */ > protected String userTable = null; > > > // ------------------------------------------------------------- Properties > > > /** > * Return the name of the JNDI JDBC DataSource. > * > */ > public String getDataSourceName() { > return dataSourceName; > } > > /** > * Set the name of the JNDI JDBC DataSource. > * > * @param dataSourceName the name of the JNDI JDBC DataSource > */ > public void setDataSourceName( String dataSourceName) { > this.dataSourceName = dataSourceName; > } > > /** > * Return if the datasource will be looked up in the webapp JNDI Context. > */ > public boolean getLocalDataSource() { > return localDataSource; > } > > /** > * Set to true to cause the datasource to be looked up in the webapp JNDI > * Context. > * > * @param localDataSource the new flag value > */ > public void setLocalDataSource(boolean localDataSource) { > this.localDataSource = localDataSource; > } > > /** > * Return the column in the user role table that names a role. > * > */ > public String getRoleNameCol() { > return roleNameCol; > } > > /** > * Set the column in the user role table that names a role. > * > * @param roleNameCol The column name > */ > public void setRoleNameCol( String roleNameCol ) { > this.roleNameCol = roleNameCol; > } > > /** > * Return the column in the user table that holds the user's credentials. > * > */ > public String getUserCredCol() { > return userCredCol; > } > > /** > * Set the column in the user table that holds the user's credentials. > * > * @param userCredCol The column name > */ > public void setUserCredCol( String userCredCol ) { > this.userCredCol = userCredCol; > } > > /** > * Return the column in the user table that holds the user's name. > * > */ > public String getUserNameCol() { > return userNameCol; > } > > /** > * Set the column in the user table that holds the user's name. > * > * @param userNameCol The column name > */ > public void setUserNameCol( String userNameCol ) { > this.userNameCol = userNameCol; > } > > /** > * Return the table that holds the relation between user's and roles. > * > */ > public String getUserRoleTable() { > return userRoleTable; > } > > /** > * Set the table that holds the relation between user's and roles. > * > * @param userRoleTable The table name > */ > public void setUserRoleTable( String userRoleTable ) { > this.userRoleTable = userRoleTable; > } > > /** > * Return the table that holds user data.. > * > */ > public String getUserTable() { > return userTable; > } > > /** > * Set the table that holds user data. > * > * @param userTable The table name > */ > public void setUserTable( String userTable ) { > this.userTable = userTable; > } > > > // --------------------------------------------------------- Public Methods > > > /** > * Return the Principal associated with the specified username and > * credentials, if there is one; otherwise return <code>null</code>. > * > * If there are any errors with the JDBC connection, executing > * the query or anything we return null (don't authenticate). This > * 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) { > > // No user - can't possibly authenticate, don't bother the database then > if (username == null) { > return null; > } > > Connection dbConnection = null; > > try { > > // Ensure that we have an open database connection > dbConnection = open(); > if (dbConnection == null) { > // If the db connection open fails, return "not authenticated" > return null; > } > > // Acquire a Principal object for this user > return authenticate(dbConnection, username, credentials); > > } catch (SQLException e) { > // Log the problem for posterity > container.getLogger().error(sm.getString("dataSourceRealm.exception"), e); > > // Return "not authenticated" for this request > return (null); > > } finally { > close(dbConnection); > } > > } > > > // -------------------------------------------------------- Package Methods > > > // ------------------------------------------------------ Protected Methods > > > /** > * Return the Principal associated with the specified username and > * credentials, if there is one; otherwise return <code>null</code>. > * > * @param dbConnection The database connection to be used > * @param username Username of the Principal to look up > * @param credentials Password or other credentials to use in > * authenticating this username > */ > protected Principal authenticate(Connection dbConnection, > String username, > String credentials) throws SQLException{ > > String dbCredentials = getPassword(dbConnection, 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 (container.getLogger().isTraceEnabled()) > container.getLogger().trace(sm.getString("dataSourceRealm.authenticateSuccess", > username)); > } else { > if (container.getLogger().isTraceEnabled()) > container.getLogger().trace(sm.getString("dataSourceRealm.authenticateFailure", > username)); > return (null); > } > > ArrayList list = getRoles(dbConnection, username); > > // Create and return a suitable Principal for this user > return (new GenericPrincipal(this, username, credentials, list)); > > } > > > /** > * Close the specified database connection. > * > * @param dbConnection The connection to be closed > */ > protected void close(Connection dbConnection) { > > // Do nothing if the database connection is already closed > if (dbConnection == null) > return; > > // Close this database connection, and log any errors > try { > if (!dbConnection.getAutoCommit()) { > dbConnection.commit(); > } > dbConnection.close(); > } catch (SQLException e) { > container.getLogger().error(sm.getString("dataSourceRealm.close"), e); // Just log it here > } > > } > > /** > * Open the specified database connection. > * > * @return Connection to the database > */ > protected Connection open() { > > try { > Context context = null; > if (localDataSource) { > context = ContextBindings.getClassLoader(); > context = (Context) context.lookup("comp/env"); > } else { > StandardServer server = > (StandardServer) ServerFactory.getServer(); > context = server.getGlobalNamingContext(); > } > DataSource dataSource = (DataSource)context.lookup(dataSourceName); > return dataSource.getConnection(); > } catch (Exception e) { > // Log the problem for posterity > container.getLogger().error(sm.getString("dataSourceRealm.exception"), e); > } > return null; > } > > /** > * Return a short name for this Realm implementation. > */ > protected String getName() { > > return (name); > > } > > /** > * Return the password associated with the given principal's user name. > */ > protected String getPassword(String username) { > > Connection dbConnection = null; > > // Ensure that we have an open database connection > dbConnection = open(); > if (dbConnection == null) { > return null; > } > > try { > return getPassword(dbConnection, username); > } finally { > close(dbConnection); > } > } > > /** > * Return the password associated with the given principal's user name. > * @param dbConnection The database connection to be used > * @param username Username for which password should be retrieved > */ > protected String getPassword(Connection dbConnection, > String username) { > > ResultSet rs = null; > PreparedStatement stmt = null; > String dbCredentials = null; > > try { > stmt = credentials(dbConnection, username); > rs = stmt.executeQuery(); > if (rs.next()) { > dbCredentials = rs.getString(1); > } > > return (dbCredentials != null) ? dbCredentials.trim() : null; > > } catch(SQLException e) { > container.getLogger().error(sm > .getString("dataSourceRealm.getPassword.exception", > username)); > } finally { > try { > if (rs != null) { > rs.close(); > } > if (stmt != null) { > stmt.close(); > } > } catch (SQLException e) { > container.getLogger().error(sm > .getString("dataSourceRealm.getPassword.exception", > username)); > > } > } > > return null; > } > > > /** > * Return the Principal associated with the given user name. > */ > protected Principal getPrincipal(String username) { > Connection dbConnection = open(); > if (dbConnection == null) { > return new GenericPrincipal(this,username, null, null); > } > try { > return (new GenericPrincipal(this, > username, > getPassword(dbConnection, username), > getRoles(dbConnection, username))); > } finally { > close(dbConnection); > } > > } > > /** > * Return the roles associated with the given user name. > * @param username Username for which roles should be retrieved > */ > protected ArrayList getRoles(String username) { > > Connection dbConnection = null; > > // Ensure that we have an open database connection > dbConnection = open(); > if (dbConnection == null) { > return null; > } > > try { > return getRoles(dbConnection, username); > } finally { > close(dbConnection); > } > } > > /** > * Return the roles associated with the given user name > * @param dbConnection The database connection to be used > * @param username Username for which roles should be retrieved > */ > protected ArrayList getRoles(Connection dbConnection, > String username) { > > ResultSet rs = null; > PreparedStatement stmt = null; > ArrayList list = null; > > try { > stmt = roles(dbConnection, username); > rs = stmt.executeQuery(); > list = new ArrayList(); > > while (rs.next()) { > String role = rs.getString(1); > if (role != null) { > list.add(role.trim()); > } > } > return list; > } catch(SQLException e) { > container.getLogger().error(sm > .getString("dataSourceRealm.getRoles.exception", > username)); > } > finally { > try { > if (rs != null) { > rs.close(); > } > if (stmt != null) { > stmt.close(); > } > } catch (SQLException e) { > container.getLogger().error(sm > .getString("dataSourceRealm.getRoles.exception", > username)); > > } > } > > return null; > } > > /** > * Return a PreparedStatement configured to perform the SELECT required > * to retrieve user credentials for the specified username. > * > * @param dbConnection The database connection to be used > * @param username Username for which credentials should be retrieved > * > * @exception SQLException if a database error occurs > */ > private PreparedStatement credentials(Connection dbConnection, > String username) > throws SQLException { > > PreparedStatement credentials = > dbConnection.prepareStatement(preparedCredentials.toString()); > > credentials.setString(1, username); > return (credentials); > > } > > /** > * Return a PreparedStatement configured to perform the SELECT required > * to retrieve user roles for the specified username. > * > * @param dbConnection The database connection to be used > * @param username Username for which roles should be retrieved > * > * @exception SQLException if a database error occurs > */ > private PreparedStatement roles(Connection dbConnection, String username) > throws SQLException { > > PreparedStatement roles = > dbConnection.prepareStatement(preparedRoles.toString()); > > roles.setString(1, username); > return (roles); > > } > > // ------------------------------------------------------ Lifecycle Methods > > > /** > * > * Prepare for active use of the public methods of this Component. > * > * @exception LifecycleException if this component detects a fatal error > * that prevents it from being started > */ > public void start() throws LifecycleException { > > // Create the roles PreparedStatement string > preparedRoles = new StringBuffer("SELECT "); > preparedRoles.append(roleNameCol); > preparedRoles.append(" FROM "); > preparedRoles.append(userRoleTable); > preparedRoles.append(" WHERE "); > preparedRoles.append(userNameCol); > preparedRoles.append(" = ?"); > > // Create the credentials PreparedStatement string > preparedCredentials = new StringBuffer("SELECT "); > preparedCredentials.append(userCredCol); > preparedCredentials.append(" FROM "); > preparedCredentials.append(userTable); > preparedCredentials.append(" WHERE "); > preparedCredentials.append(userNameCol); > preparedCredentials.append(" = ?"); > > // Perform normal superclass initialization > super.start(); > > } > > > /** > * Gracefully shut down active use of the public methods of this Component. > * > * @exception LifecycleException if this component detects a fatal error > * that needs to be reported > */ > public void stop() throws LifecycleException { > > // Perform normal superclass finalization > super.stop(); > > } > > >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 33357
:
14165
|
14166
| 14168