0001: /*
0002: * The contents of this file are subject to the Sapient Public License
0003: * Version 1.0 (the "License"); you may not use this file except in compliance
0004: * with the License. You may obtain a copy of the License at
0005: * http://carbon.sf.net/License.html.
0006: *
0007: * Software distributed under the License is distributed on an "AS IS" basis,
0008: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
0009: * the specific language governing rights and limitations under the License.
0010: *
0011: * The Original Code is The Carbon Component Framework.
0012: *
0013: * The Initial Developer of the Original Code is Sapient Corporation
0014: *
0015: * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
0016: */
0017:
0018: package org.sape.carbon.services.security.management.rdbms;
0019:
0020: import java.security.Principal;
0021: import java.security.acl.Group;
0022: import java.sql.Connection;
0023: import java.sql.PreparedStatement;
0024: import java.sql.ResultSet;
0025: import java.sql.SQLException;
0026: import java.util.HashMap;
0027: import java.util.HashSet;
0028: import java.util.Iterator;
0029: import java.util.Map;
0030: import java.util.Set;
0031:
0032: import org.sape.carbon.core.component.ComponentConfiguration;
0033: import org.sape.carbon.core.component.lifecycle.Configurable;
0034: import org.sape.carbon.core.config.InvalidConfigurationException;
0035: import org.sape.carbon.core.exception.ExceptionUtility;
0036: import org.sape.carbon.services.security.management.DefaultGroupImpl;
0037: import org.sape.carbon.services.security.management.DefaultUserImpl;
0038: import org.sape.carbon.services.security.management.DuplicateGroupException;
0039: import org.sape.carbon.services.security.management.DuplicatePrincipalException;
0040: import org.sape.carbon.services.security.management.LazyLoadGroup;
0041: import org.sape.carbon.services.security.management.RuntimeSecurityManagementException;
0042: import org.sape.carbon.services.security.management.UnknownGroupException;
0043: import org.sape.carbon.services.security.management.UnknownPrincipalException;
0044: import org.sape.carbon.services.security.management.UserManager;
0045: import org.sape.carbon.services.sql.StatementFactoryException;
0046:
0047: import org.apache.commons.logging.Log;
0048: import org.apache.commons.logging.LogFactory;
0049:
0050: /**
0051: * Implementation of the UserManager against a RDBMS backing store. This
0052: * implementation executes queries against the datastore as specified in
0053: * the configuration file as well as the statement factory. Copyright
0054: * 2002 Sapient
0055: *
0056: * @author Jordan Reed, September 2002
0057: * @version $Revision: 1.14 $($Author: dvoet $ / $Date: 2003/10/28 19:02:01 $)
0058: *
0059: * @since carbon 1.2
0060: */
0061: public class RdbmsUserManagerImpl implements UserManager, Configurable {
0062:
0063: /**
0064: * Provides a handle to Apache-commons logger
0065: */
0066: private Log log = LogFactory.getLog(this .getClass());
0067:
0068: /** Holds a reference to the configuration. */
0069: protected RdbmsUserManagerConfiguration config;
0070:
0071: /**
0072: * Creates a new user object in the database and returns it.
0073: *
0074: * @param username the name of the user to create
0075: * @param credential the credential for the user to authenticate
0076: *
0077: * @return the new instance of a principal generated
0078: *
0079: * @throws DuplicatePrincipalException indicates the a principal with
0080: * the same name already exists in the database
0081: * @throws RuntimeSecurityManagementException indicates an error
0082: * communicating with the database
0083: */
0084: public Principal createUser(String username, Map userInfo)
0085: throws DuplicatePrincipalException {
0086:
0087: Principal resultUser = null;
0088: Connection connection = null;
0089:
0090: try {
0091: connection = config.getConnectionFactory().getConnection();
0092: } catch (SQLException sqle) {
0093: log.trace("Caught exception: " + sqle
0094: + ExceptionUtility.captureStackTrace(sqle));
0095:
0096: throw new RuntimeSecurityManagementException(this
0097: .getClass(),
0098: "Caught SQLException while opening connection",
0099: sqle);
0100: }
0101:
0102: try {
0103: resultUser = createUser(connection, username, userInfo);
0104: } finally {
0105: try {
0106: if (connection != null) {
0107: connection.close();
0108: }
0109: } catch (SQLException sqle) {
0110: log.info("Caught exception closing Connection: " + sqle
0111: + ExceptionUtility.captureStackTrace(sqle));
0112: }
0113: }
0114:
0115: return resultUser;
0116: }
0117:
0118: /**
0119: * Creates a new user object in the database and returns it using the
0120: * given connection.
0121: *
0122: * <p>
0123: * This method makes calls to two helper methods to delegate the two
0124: * bits of functionality. <code>createUserEntry</code> to create the
0125: * database entry for the user and <code>createCredentialEntry</code>
0126: * to create the credential entry for the user.
0127: * </p>
0128: *
0129: * @param connection connection to execute database calls against
0130: * @param username the name of the user to create
0131: * @param credential the credential for the user to authenticate
0132: *
0133: * @return the new instance of a principal generated
0134: *
0135: * @throws DuplicatePrincipalException indicates the a principal with
0136: * the same name already exists in the database
0137: * @throws RuntimeSecurityManagementException indicates an error
0138: * communicating with the database
0139: */
0140: protected Principal createUser(Connection connection,
0141: String username, Map userInfo)
0142: throws DuplicatePrincipalException {
0143:
0144: if (log.isTraceEnabled()) {
0145: log.trace("Adding user with name [" + username
0146: + "] and additional info [" + userInfo + "]");
0147: }
0148:
0149: Principal currentUser = retreiveUser(connection, username);
0150:
0151: if (currentUser != null) {
0152: throw new DuplicatePrincipalException(this .getClass(),
0153: currentUser);
0154: }
0155:
0156: try {
0157: connection.setAutoCommit(false);
0158: createUserEntry(connection, username);
0159: currentUser = retreiveUser(connection, username);
0160: createCredentialEntry(connection, currentUser, userInfo);
0161: connection.commit();
0162: connection.setAutoCommit(true);
0163: } catch (RuntimeSecurityManagementException rsme) {
0164: try {
0165: if (connection != null) {
0166: connection.rollback();
0167: connection.setAutoCommit(true);
0168: }
0169: } catch (SQLException se) {
0170: // Ignore exception.
0171: }
0172:
0173: throw rsme;
0174: } catch (SQLException se) {
0175: try {
0176: if (connection != null) {
0177: connection.rollback();
0178: connection.setAutoCommit(true);
0179: }
0180: } catch (SQLException se2) {
0181: // Ignore exception.
0182: }
0183:
0184: throw new RuntimeSecurityManagementException(this
0185: .getClass(), "Caught SQLException while adding "
0186: + "new user named [" + username + "]", se);
0187: }
0188:
0189: return currentUser;
0190: }
0191:
0192: /**
0193: * Creates the user row in the database. If the credential is created
0194: * at the same time, the <code>createCredentialEntry</code> method
0195: * should be overriden and set to empty.
0196: *
0197: * @param connection connection to execute database calls against
0198: * @param username the name of the user to create
0199: * @param credential the credential for the user to authenticate
0200: *
0201: * @throws RuntimeSecurityManagementException indicates an error
0202: * communicating with the database or inconsistent state.
0203: */
0204: protected void createUserEntry(Connection connection,
0205: String username) {
0206: PreparedStatement createUserStatement = null;
0207:
0208: try {
0209: createUserStatement = config
0210: .getStatementFactory()
0211: .createPreparedStatement(
0212: config.getCreateUserQueryName(), connection);
0213: createUserStatement.setString(1, username);
0214:
0215: int resultCount = createUserStatement.executeUpdate();
0216:
0217: if (log.isInfoEnabled()) {
0218: log.info("Added user with name [" + username + "]");
0219: }
0220: } catch (StatementFactoryException sfe) {
0221: log.trace("Caught exception: " + sfe
0222: + ExceptionUtility.captureStackTrace(sfe));
0223:
0224: throw new RuntimeSecurityManagementException(this
0225: .getClass(),
0226: "Caught StatementFactoryException while adding "
0227: + "new user.", sfe);
0228: } catch (SQLException sqle) {
0229: log.trace("Caught exception: " + sqle
0230: + ExceptionUtility.captureStackTrace(sqle));
0231:
0232: throw new RuntimeSecurityManagementException(this
0233: .getClass(), "Caught SQLException while adding "
0234: + "new user.", sqle);
0235: } finally {
0236: try {
0237: if (createUserStatement != null) {
0238: createUserStatement.close();
0239: }
0240: } catch (SQLException sqle) {
0241: // Ignore exception.
0242: }
0243: }
0244: }
0245:
0246: /**
0247: * Creates the credential row in the database. If the credential is
0248: * created with the user this method should be overriden and set to
0249: * empty.
0250: *
0251: * @param connection connection to execute database calls against
0252: * @param currentUser the user to create a credential for
0253: * @param credential the credential for the user to authenticate
0254: *
0255: * @throws RuntimeSecurityManagementException indicates an error
0256: * communicating with the database or inconsistent state.
0257: */
0258: protected void createCredentialEntry(Connection connection,
0259: Principal currentUser, Map userInfo) {
0260: PreparedStatement createCredentialStatement = null;
0261: Object userPrimaryKey = null;
0262:
0263: try {
0264: userPrimaryKey = retreivePrincipalPrimaryKey(connection,
0265: currentUser);
0266: } catch (UnknownPrincipalException upe) {
0267: throw new RuntimeSecurityManagementException(this
0268: .getClass(),
0269: "Caught UnknownPrincipalException while getting "
0270: + "primary key for ["
0271: + currentUser.getName() + "]", upe);
0272: }
0273:
0274: try {
0275: Object credential = userInfo.get(this .config
0276: .getCreateUserBindParameters()[0]);
0277:
0278: createCredentialStatement = config.getStatementFactory()
0279: .createPreparedStatement(
0280: config.getCreateCredentialQueryName(),
0281: connection);
0282:
0283: createCredentialStatement.setObject(1, userPrimaryKey);
0284: createCredentialStatement.setObject(2, credential);
0285:
0286: int resultCount = createCredentialStatement.executeUpdate();
0287:
0288: if (log.isInfoEnabled()) {
0289: log.info("Added credential to user with name ["
0290: + currentUser.getName()
0291: + "] and credential of type ["
0292: + credential.getClass().getName() + "]");
0293: }
0294: } catch (StatementFactoryException sfe) {
0295: log.trace("Caught exception: " + sfe
0296: + ExceptionUtility.captureStackTrace(sfe));
0297:
0298: throw new RuntimeSecurityManagementException(this
0299: .getClass(),
0300: "Caught StatementFactoryException while adding "
0301: + "new user.", sfe);
0302: } catch (SQLException sqle) {
0303: log.trace("Caught exception: " + sqle
0304: + ExceptionUtility.captureStackTrace(sqle));
0305:
0306: throw new RuntimeSecurityManagementException(this
0307: .getClass(), "Caught SQLException while adding "
0308: + "new user.", sqle);
0309: } finally {
0310: try {
0311: if (createCredentialStatement != null) {
0312: createCredentialStatement.close();
0313: }
0314: } catch (SQLException sqle) {
0315: // Ignore exception.
0316: }
0317: }
0318: }
0319:
0320: /**
0321: * Removes the credential row from the database.
0322: *
0323: * @param connection connection to execute database calls against
0324: * @param userPrimaryKey the primary key of the user.
0325: *
0326: * @throws RuntimeSecurityManagementException indicates an error
0327: * communicating with the database or inconsistent state.
0328: */
0329: protected void removeCredential(Connection connection,
0330: Object userPrimaryKey) {
0331: PreparedStatement removeCredentialStatement = null;
0332:
0333: try {
0334: removeCredentialStatement = config.getStatementFactory()
0335: .createPreparedStatement(
0336: config.getRemoveCredentialQueryName(),
0337: connection);
0338:
0339: removeCredentialStatement.setObject(1, userPrimaryKey);
0340:
0341: int resultCount = removeCredentialStatement.executeUpdate();
0342:
0343: if (log.isInfoEnabled()) {
0344: log.info("Deleted credential to user with name ["
0345: + userPrimaryKey + "]");
0346: }
0347: } catch (StatementFactoryException sfe) {
0348: log.trace("Caught exception: " + sfe
0349: + ExceptionUtility.captureStackTrace(sfe));
0350:
0351: throw new RuntimeSecurityManagementException(this
0352: .getClass(),
0353: "Caught StatementFactoryException while deleting "
0354: + "credential.", sfe);
0355: } catch (SQLException sqle) {
0356: log.trace("Caught exception: " + sqle
0357: + ExceptionUtility.captureStackTrace(sqle));
0358:
0359: throw new RuntimeSecurityManagementException(this
0360: .getClass(), "Caught SQLException while deleting "
0361: + "credential.", sqle);
0362: } finally {
0363: try {
0364: if (removeCredentialStatement != null) {
0365: removeCredentialStatement.close();
0366: }
0367: } catch (SQLException sqle) {
0368: // Ignore exception.
0369: }
0370: }
0371: }
0372:
0373: /**
0374: * Authenticates a user against a given credential.
0375: *
0376: * <p>
0377: * This method will check the validity of a credential for a given
0378: * user and return if the user is valid to log in of if some other
0379: * status prevents them.
0380: * </p>
0381: *
0382: * <p>
0383: * This method does not provide business specific reasons why a user
0384: * may be unable to log in (user does not exist, incorrect password,
0385: * locked out, etc.). Projects must write project specific checks for
0386: * business conditions preventing a user from logging in.
0387: * </p>
0388: *
0389: * @param username The username identifying the user inside the user
0390: * store.
0391: * @param credential The credential object a user needs to prove they
0392: * can be referenced by the principal.
0393: *
0394: * @return if this is the valid credential for the given user
0395: *
0396: * @throws RuntimeSecurityManagementException indicates an error
0397: * communicating with the database or inconsistent state.
0398: */
0399: public boolean authenticate(String username, Object credential) {
0400: Connection connection = null;
0401: boolean authenticated = false;
0402:
0403: try {
0404: connection = config.getConnectionFactory().getConnection();
0405: } catch (SQLException sqle) {
0406: log.trace("Caught exception: " + sqle
0407: + ExceptionUtility.captureStackTrace(sqle));
0408:
0409: throw new RuntimeSecurityManagementException(this
0410: .getClass(), "Caught SQLException while opening "
0411: + "connection", sqle);
0412: }
0413:
0414: try {
0415: authenticated = authenticate(connection, username,
0416: credential);
0417: } finally {
0418: try {
0419: if (connection != null) {
0420: connection.close();
0421: }
0422: } catch (SQLException sqle) {
0423: log.info("Caught exception closing Connection: " + sqle
0424: + ExceptionUtility.captureStackTrace(sqle));
0425: }
0426: }
0427:
0428: return authenticated;
0429: }
0430:
0431: /**
0432: * Authenticates a user against a given credential.
0433: *
0434: * <p>
0435: * This method will check the validity of a credential for a given
0436: * user and return if the user is valid to log in of if some other
0437: * status prevents them.
0438: * </p>
0439: *
0440: * <p>
0441: * This method does not provide business specific reasons why a user
0442: * may be unable to log in (user does not exist, incorrect password,
0443: * locked out, etc.). Projects must write project specific checks for
0444: * business conditions preventing a user from logging in.
0445: * </p>
0446: *
0447: * @param connection connection to execute database calls against
0448: * @param username The username identifying the user inside the user
0449: * store.
0450: * @param credential The credential object a user needs to prove they
0451: * can be referenced by the principal.
0452: *
0453: * @return if this is the valid credential for the given user
0454: *
0455: * @throws RuntimeSecurityManagementException indicates an error
0456: * communicating with the database or inconsistent state.
0457: */
0458: public boolean authenticate(Connection connection, String username,
0459: Object credential) {
0460: PreparedStatement authenticateUserStatement = null;
0461: ResultSet authenticateUserResultSet = null;
0462: boolean authenticated = false;
0463:
0464: if (log.isTraceEnabled()) {
0465: log.trace("Searching for user with principal name ["
0466: + username + "]");
0467: }
0468:
0469: try {
0470: authenticateUserStatement = config.getStatementFactory()
0471: .createPreparedStatement(
0472: config.getAuthenticateUserQueryName(),
0473: connection);
0474: authenticateUserStatement.setString(1, username);
0475: authenticateUserStatement.setObject(2, credential);
0476: authenticateUserResultSet = authenticateUserStatement
0477: .executeQuery();
0478:
0479: if (authenticateUserResultSet.next()) {
0480: authenticated = true;
0481:
0482: if (log.isTraceEnabled()) {
0483: log.trace("User with principal name [" + username
0484: + "] was successfully authenticated");
0485: }
0486: } else {
0487: authenticated = false;
0488:
0489: if (log.isTraceEnabled()) {
0490: log.trace("User with principal name [" + username
0491: + "] failed authentication");
0492: }
0493: }
0494: } catch (StatementFactoryException sfe) {
0495: log.trace("Caught exception: " + sfe
0496: + ExceptionUtility.captureStackTrace(sfe));
0497:
0498: throw new RuntimeSecurityManagementException(this
0499: .getClass(),
0500: "Caught StatementFactoryException while adding "
0501: + "new user.", sfe);
0502: } catch (SQLException sqle) {
0503: log.trace("Caught exception: " + sqle
0504: + ExceptionUtility.captureStackTrace(sqle));
0505:
0506: throw new RuntimeSecurityManagementException(this
0507: .getClass(),
0508: "Caught SQLException while authenticating "
0509: + "user.", sqle);
0510: } finally {
0511: try {
0512: if (authenticateUserResultSet != null) {
0513: authenticateUserResultSet.close();
0514: }
0515: } catch (SQLException sqle) {
0516: log.info("Caught exception closing ResultSet: " + sqle
0517: + ExceptionUtility.captureStackTrace(sqle));
0518: }
0519:
0520: try {
0521: if (authenticateUserStatement != null) {
0522: authenticateUserStatement.close();
0523: }
0524: } catch (SQLException sqle) {
0525: log.info("Caught exception closing Statement: " + sqle
0526: + ExceptionUtility.captureStackTrace(sqle));
0527: }
0528: }
0529:
0530: return authenticated;
0531: }
0532:
0533: /**
0534: * Removes a principal from all groups it is in.
0535: *
0536: * <p>
0537: * This is used when removing a user or group from the system to
0538: * validate that no extraneous rows are leftover.
0539: * </p>
0540: *
0541: * @param connection connection to execute database calls against
0542: * @param principalPrimaryKey the principal (either user or group) to
0543: * remove from all groups it is in
0544: *
0545: * @throws UnknownPrincipalException indicates the principal does not
0546: * currently exists in the system
0547: * @throws RuntimeSecurityManagementException indicates an error
0548: * communicating with the database
0549: */
0550: protected void removeAllRelationships(Connection connection,
0551: Object principalPrimaryKey)
0552: throws UnknownPrincipalException {
0553: PreparedStatement removeAllRelationshipsStatement = null;
0554:
0555: if (log.isTraceEnabled()) {
0556: log.trace("Removing principal [" + principalPrimaryKey
0557: + "] from all relationships");
0558: }
0559:
0560: try {
0561: removeAllRelationshipsStatement = config
0562: .getStatementFactory()
0563: .createPreparedStatement(
0564: config.getRemoveAllRelationshipsQueryName(),
0565: connection);
0566: removeAllRelationshipsStatement.setObject(1,
0567: principalPrimaryKey);
0568: removeAllRelationshipsStatement.setObject(2,
0569: principalPrimaryKey);
0570:
0571: int resultCount = removeAllRelationshipsStatement
0572: .executeUpdate();
0573:
0574: if (log.isInfoEnabled()) {
0575: log.info("Removed principal with name ["
0576: + principalPrimaryKey + "] from ["
0577: + resultCount + "] relationships");
0578: }
0579: } catch (StatementFactoryException sfe) {
0580: log.trace("Caught exception: " + sfe
0581: + ExceptionUtility.captureStackTrace(sfe));
0582:
0583: throw new RuntimeSecurityManagementException(this
0584: .getClass(),
0585: "Caught StatementFactoryException while removing "
0586: + "user.", sfe);
0587: } catch (SQLException sqle) {
0588: log.trace("Caught exception: " + sqle
0589: + ExceptionUtility.captureStackTrace(sqle));
0590:
0591: throw new RuntimeSecurityManagementException(this
0592: .getClass(), "Caught SQLException while removing "
0593: + "user.", sqle);
0594: } finally {
0595: try {
0596: if (removeAllRelationshipsStatement != null) {
0597: removeAllRelationshipsStatement.close();
0598: }
0599: } catch (SQLException sqle) {
0600: log.info("Caught exception closing Statement: " + sqle
0601: + ExceptionUtility.captureStackTrace(sqle));
0602: }
0603: }
0604: }
0605:
0606: /**
0607: * Removes a user from the database.
0608: *
0609: * <p>
0610: * This will first remove the user from any groups it may be in, and
0611: * then proceed to delete the user. These two steps are done in a
0612: * transaction against the database that will rollback if there is an
0613: * error on either step.
0614: * </p>
0615: *
0616: * @param user The user to remove from the database
0617: *
0618: * @throws UnknownPrincipalException indicates the principal does not
0619: * currently exists in the system
0620: * @throws RuntimeSecurityManagementException indicates an error
0621: * communicating with the database
0622: */
0623: public void removeUser(Principal user)
0624: throws UnknownPrincipalException {
0625:
0626: Connection connection = null;
0627:
0628: try {
0629: connection = config.getConnectionFactory().getConnection();
0630: } catch (SQLException sqle) {
0631: log.trace("Caught exception: " + sqle
0632: + ExceptionUtility.captureStackTrace(sqle));
0633:
0634: throw new RuntimeSecurityManagementException(this
0635: .getClass(), "Caught SQLException while opening "
0636: + "connection", sqle);
0637: }
0638:
0639: try {
0640: removeUser(connection, user);
0641: } finally {
0642: try {
0643: if (connection != null) {
0644: connection.close();
0645: }
0646: } catch (SQLException sqle) {
0647: log.info("Caught exception closing Connection: " + sqle
0648: + ExceptionUtility.captureStackTrace(sqle));
0649: }
0650: }
0651: }
0652:
0653: /**
0654: * Removes a user from the database.
0655: *
0656: * <p>
0657: * This will first remove the user from any groups it may be in, and
0658: * then proceed to delete the user. These two steps are done in a
0659: * transaction against the database that will rollback if there is an
0660: * error on either step.
0661: * </p>
0662: *
0663: * @param connection connection to execute database calls against
0664: * @param user The user to remove from the database
0665: *
0666: * @throws UnknownPrincipalException indicates the principal does not
0667: * currently exists in the system
0668: * @throws RuntimeSecurityManagementException indicates an error
0669: * communicating with the database
0670: */
0671: protected void removeUser(Connection connection, Principal user)
0672: throws UnknownPrincipalException {
0673:
0674: Principal currentUser = retreiveUser(connection, user.getName());
0675:
0676: if (currentUser == null) {
0677: throw new UnknownPrincipalException(this .getClass(), user
0678: .getName());
0679: }
0680:
0681: Object userPrimaryKey = retreivePrincipalPrimaryKey(connection,
0682: user);
0683:
0684: if (log.isTraceEnabled()) {
0685: log.trace("Removing user with principal [" + user.getName()
0686: + "]");
0687: }
0688:
0689: try {
0690: connection.setAutoCommit(false);
0691:
0692: removeAllRelationships(connection, userPrimaryKey);
0693: removeCredential(connection, userPrimaryKey);
0694: removeUserEntry(connection, userPrimaryKey);
0695:
0696: connection.commit();
0697: connection.setAutoCommit(true);
0698:
0699: if (log.isInfoEnabled()) {
0700: log.info("Removed user with name [" + user.getName()
0701: + "]");
0702: }
0703: } catch (RuntimeSecurityManagementException rsme) {
0704: try {
0705: if (connection != null) {
0706: connection.rollback();
0707: connection.setAutoCommit(true);
0708: }
0709: } catch (SQLException se) {
0710: // Ignore exception.
0711: }
0712:
0713: throw rsme;
0714: } catch (SQLException se) {
0715: try {
0716: if (connection != null) {
0717: connection.rollback();
0718: connection.setAutoCommit(true);
0719: }
0720: } catch (SQLException se2) {
0721: // Ignore exception.
0722: }
0723:
0724: throw new RuntimeSecurityManagementException(this
0725: .getClass(), "Caught SQLException while deleting "
0726: + "user named [" + user.getName() + "]", se);
0727: }
0728: }
0729:
0730: /**
0731: * Removes the user row from the database.
0732: *
0733: * <p>
0734: * This method should not normally be called until all other values
0735: * relating to the user have been removed from the database unless
0736: * this is an Oracle database with cascading contraints.
0737: * </p>
0738: *
0739: * @param connection connection to execute database calls against
0740: * @param userPrimaryKey the primary key of the user.
0741: *
0742: * @throws RuntimeSecurityManagementException indicates an error
0743: * communicating with the database or inconsistent state.
0744: */
0745: protected void removeUserEntry(Connection connection,
0746: Object userPrimaryKey) {
0747: PreparedStatement removeUserStatement = null;
0748:
0749: try {
0750: removeUserStatement = config
0751: .getStatementFactory()
0752: .createPreparedStatement(
0753: config.getRemoveUserQueryName(), connection);
0754: removeUserStatement.setObject(1, userPrimaryKey);
0755:
0756: int resultCount = removeUserStatement.executeUpdate();
0757: } catch (StatementFactoryException sfe) {
0758: log.trace("Caught exception and rolled back transaction: "
0759: + sfe + ExceptionUtility.captureStackTrace(sfe));
0760:
0761: throw new RuntimeSecurityManagementException(this
0762: .getClass(),
0763: "Caught StatementFactoryException while removing "
0764: + "user.", sfe);
0765: } catch (SQLException sqle) {
0766: log.trace("Caught exception and rolled back transaction: "
0767: + sqle + ExceptionUtility.captureStackTrace(sqle));
0768:
0769: throw new RuntimeSecurityManagementException(this
0770: .getClass(), "Caught SQLException while removing "
0771: + "user.", sqle);
0772: } finally {
0773: try {
0774: if (removeUserStatement != null) {
0775: removeUserStatement.close();
0776: }
0777: } catch (SQLException sqle) {
0778: log.info("Caught exception closing Statement: " + sqle
0779: + ExceptionUtility.captureStackTrace(sqle));
0780: }
0781: }
0782: }
0783:
0784: /**
0785: * Updates the credential for the user in the database.
0786: *
0787: * @param user the user to update in the database
0788: * @param credential the new credential to assign to the user
0789: *
0790: * @throws UnknownPrincipalException indicates the principal does not
0791: * currently exists in the system
0792: * @throws RuntimeSecurityManagementException indicates an error
0793: * communicating with the database
0794: */
0795: public void updateCredential(Principal user, Object credential)
0796: throws UnknownPrincipalException {
0797: Connection connection = null;
0798:
0799: try {
0800: connection = config.getConnectionFactory().getConnection();
0801: } catch (SQLException sqle) {
0802: log.trace("Caught exception: " + sqle
0803: + ExceptionUtility.captureStackTrace(sqle));
0804:
0805: throw new RuntimeSecurityManagementException(this
0806: .getClass(), "Caught SQLException while opening "
0807: + "connection", sqle);
0808: }
0809:
0810: try {
0811: updateCredential(connection, user, credential);
0812: } finally {
0813: try {
0814: if (connection != null) {
0815: connection.close();
0816: }
0817: } catch (SQLException sqle) {
0818: log.info("Caught exception closing Connection: " + sqle
0819: + ExceptionUtility.captureStackTrace(sqle));
0820: }
0821: }
0822: }
0823:
0824: /**
0825: * Updates the credential for the user in the database.
0826: *
0827: * @param connection the user to update in the database
0828: * @param user the user to update in the database
0829: * @param credential the new credential to assign to the user
0830: *
0831: * @throws UnknownPrincipalException indicates the principal does not
0832: * currently exists in the system
0833: * @throws RuntimeSecurityManagementException indicates an error
0834: * communicating with the database
0835: */
0836: protected void updateCredential(Connection connection,
0837: Principal user, Object credential)
0838: throws UnknownPrincipalException {
0839: PreparedStatement updateCredentialStatement = null;
0840:
0841: if (log.isTraceEnabled()) {
0842: log.trace("Updating user with principal [" + user
0843: + "] and credential of type ["
0844: + credential.getClass().getName() + "]");
0845: }
0846:
0847: Object userPrimaryKey = retreivePrincipalPrimaryKey(connection,
0848: user);
0849:
0850: try {
0851: updateCredentialStatement = config.getStatementFactory()
0852: .createPreparedStatement(
0853: config.getUpdateCredentialQueryName(),
0854: connection);
0855: updateCredentialStatement.setObject(1, credential);
0856: updateCredentialStatement.setObject(2, userPrimaryKey);
0857:
0858: int resultCount = updateCredentialStatement.executeUpdate();
0859:
0860: if (log.isDebugEnabled()) {
0861: log.debug("Updated credential for user with name ["
0862: + user.getName() + "]");
0863: }
0864: } catch (StatementFactoryException sfe) {
0865: log.trace("Caught exception: " + sfe
0866: + ExceptionUtility.captureStackTrace(sfe));
0867:
0868: throw new RuntimeSecurityManagementException(this
0869: .getClass(),
0870: "Caught StatementFactoryException while updating "
0871: + "user.", sfe);
0872: } catch (SQLException sqle) {
0873: log.trace("Caught exception: " + sqle
0874: + ExceptionUtility.captureStackTrace(sqle));
0875:
0876: throw new RuntimeSecurityManagementException(this
0877: .getClass(), "Caught SQLException while updating "
0878: + "user.", sqle);
0879: } finally {
0880: try {
0881: updateCredentialStatement.close();
0882: } catch (SQLException sqle) {
0883: log.info("Caught exception closing Statement: " + sqle
0884: + ExceptionUtility.captureStackTrace(sqle));
0885: }
0886: }
0887: }
0888:
0889: /**
0890: * Creates a new entry for Group in the database.
0891: *
0892: * @param groupName name of the group add to the database
0893: *
0894: * @return a new group object in the database
0895: *
0896: * @throws DuplicateGroupException indicates that a group with the
0897: * same name already exists in the database
0898: * @throws RuntimeSecurityManagementException indicates an error
0899: * communicating with the database
0900: */
0901: public Group createGroup(String groupName)
0902: throws DuplicateGroupException {
0903: Group result = null;
0904: Connection connection = null;
0905:
0906: try {
0907: connection = config.getConnectionFactory().getConnection();
0908: } catch (SQLException sqle) {
0909: log.trace("Caught exception: " + sqle
0910: + ExceptionUtility.captureStackTrace(sqle));
0911:
0912: throw new RuntimeSecurityManagementException(this
0913: .getClass(), "Caught SQLException while opening "
0914: + "connection", sqle);
0915: }
0916:
0917: try {
0918: result = createGroup(connection, groupName);
0919: } finally {
0920: try {
0921: if (connection != null) {
0922: connection.close();
0923: }
0924: } catch (SQLException sqle) {
0925: log.info("Caught exception closing Connection: " + sqle
0926: + ExceptionUtility.captureStackTrace(sqle));
0927: }
0928: }
0929:
0930: return result;
0931: }
0932:
0933: /**
0934: * Creates a new entry for Group in the database.
0935: *
0936: * @param connection connection to execute database calls against
0937: * @param groupName name of the group add to the database
0938: *
0939: * @return a new group object in the database
0940: *
0941: * @throws DuplicateGroupException indicates that a group with the
0942: * same name already exists in the database
0943: * @throws RuntimeSecurityManagementException indicates an error
0944: * communicating with the database
0945: */
0946: protected Group createGroup(Connection connection, String groupName)
0947: throws DuplicateGroupException {
0948: PreparedStatement createGroupStatement = null;
0949:
0950: if (log.isTraceEnabled()) {
0951: log.trace("Adding group [" + groupName + "]");
0952: }
0953:
0954: Group currentGroup = retreiveGroup(connection, groupName);
0955:
0956: if (currentGroup != null) {
0957: throw new DuplicateGroupException(this .getClass(),
0958: currentGroup);
0959: }
0960:
0961: try {
0962: createGroupStatement = config.getStatementFactory()
0963: .createPreparedStatement(
0964: config.getCreateGroupQueryName(),
0965: connection);
0966: createGroupStatement.setString(1, groupName);
0967:
0968: int resultCount = createGroupStatement.executeUpdate();
0969:
0970: if (log.isInfoEnabled()) {
0971: log.info("Added group with name [" + groupName + "]");
0972: }
0973: } catch (StatementFactoryException sfe) {
0974: log.trace("Caught exception: " + sfe
0975: + ExceptionUtility.captureStackTrace(sfe));
0976:
0977: throw new RuntimeSecurityManagementException(this
0978: .getClass(),
0979: "Caught StatementFactoryException while adding "
0980: + "new group.", sfe);
0981: } catch (SQLException sqle) {
0982: log.trace("Caught exception: " + sqle
0983: + ExceptionUtility.captureStackTrace(sqle));
0984:
0985: throw new RuntimeSecurityManagementException(this
0986: .getClass(), "Caught SQLException while adding "
0987: + "new group.", sqle);
0988: } finally {
0989: try {
0990: createGroupStatement.close();
0991: } catch (SQLException sqle) {
0992: log.info("Caught exception closing Statement: " + sqle
0993: + ExceptionUtility.captureStackTrace(sqle));
0994: }
0995: }
0996:
0997: Group newGroup = retreiveGroup(connection, groupName);
0998:
0999: return newGroup;
1000: }
1001:
1002: /**
1003: * Removes a group from the database.
1004: *
1005: * @param group group to remove from the database
1006: *
1007: * @throws UnknownGroupException indicates the group does not
1008: * currently exists in the system
1009: * @throws RuntimeSecurityManagementException indicates an error
1010: * communicating with the database
1011: */
1012: public void removeGroup(Group group) throws UnknownGroupException {
1013: Connection connection = null;
1014:
1015: try {
1016: connection = config.getConnectionFactory().getConnection();
1017: } catch (SQLException sqle) {
1018: log.trace("Caught exception: " + sqle
1019: + ExceptionUtility.captureStackTrace(sqle));
1020:
1021: throw new RuntimeSecurityManagementException(this
1022: .getClass(), "Caught SQLException while opening "
1023: + "connection", sqle);
1024: }
1025:
1026: try {
1027: removeGroup(connection, group);
1028: } finally {
1029: try {
1030: if (connection != null) {
1031: connection.close();
1032: }
1033: } catch (SQLException sqle) {
1034: log.info("Caught exception closing Connection: " + sqle
1035: + ExceptionUtility.captureStackTrace(sqle));
1036: }
1037: }
1038: }
1039:
1040: /**
1041: * Removes a group from the database.
1042: *
1043: * @param connection connection to execute database calls against
1044: * @param group group to remove from the database
1045: *
1046: * @throws UnknownGroupException indicates the group does not
1047: * currently exists in the system
1048: * @throws RuntimeSecurityManagementException indicates an error
1049: * communicating with the database
1050: */
1051: protected void removeGroup(Connection connection, Group group)
1052: throws UnknownGroupException {
1053: PreparedStatement removeGroupStatement = null;
1054: Object groupPrimaryKey;
1055:
1056: Group currentGroup = retreiveGroup(connection, group.getName());
1057:
1058: if (currentGroup == null) {
1059: throw new UnknownGroupException(this .getClass(), group
1060: .getName());
1061: }
1062:
1063: try {
1064: groupPrimaryKey = retreivePrincipalPrimaryKey(connection,
1065: group);
1066: } catch (UnknownPrincipalException upe) {
1067: throw new UnknownGroupException(this .getClass(), group
1068: .getName(), upe);
1069: }
1070:
1071: if (log.isTraceEnabled()) {
1072: log.trace("Removing group [" + group.getName() + "]");
1073: }
1074:
1075: try {
1076: connection.setAutoCommit(false);
1077:
1078: removeAllRelationships(connection, groupPrimaryKey);
1079:
1080: removeGroupStatement = config.getStatementFactory()
1081: .createPreparedStatement(
1082: config.getRemoveGroupQueryName(),
1083: connection);
1084: removeGroupStatement.setObject(1, groupPrimaryKey);
1085:
1086: int resultCount = removeGroupStatement.executeUpdate();
1087:
1088: connection.commit();
1089: connection.setAutoCommit(true);
1090:
1091: if (log.isInfoEnabled()) {
1092: log.info("Removed group with name [" + group.getName()
1093: + "]");
1094: }
1095: } catch (UnknownPrincipalException upe) {
1096: try {
1097: if (connection != null) {
1098: connection.rollback();
1099: connection.setAutoCommit(true);
1100: }
1101: } catch (SQLException sqle) {
1102: log.info("Caught exception rolling back transaction: "
1103: + sqle
1104: + ExceptionUtility.captureStackTrace(sqle));
1105: }
1106:
1107: // This can be thrown from the removeAllRelationships
1108: // statement. Repackage here.
1109: throw new UnknownGroupException(this .getClass(), group
1110: .getName(), upe);
1111: } catch (StatementFactoryException sfe) {
1112: log.trace("Caught exception: " + sfe
1113: + ExceptionUtility.captureStackTrace(sfe));
1114:
1115: try {
1116: if (connection != null) {
1117: connection.rollback();
1118: connection.setAutoCommit(true);
1119: }
1120: } catch (SQLException sqle) {
1121: log.info("Caught exception rolling back transaction: "
1122: + sqle
1123: + ExceptionUtility.captureStackTrace(sqle));
1124: }
1125:
1126: throw new RuntimeSecurityManagementException(this
1127: .getClass(),
1128: "Caught StatementFactoryException while removing "
1129: + "group.", sfe);
1130: } catch (SQLException sqle) {
1131: log.trace("Caught exception: " + sqle
1132: + ExceptionUtility.captureStackTrace(sqle));
1133:
1134: try {
1135: if (connection != null) {
1136: connection.rollback();
1137: connection.setAutoCommit(true);
1138: }
1139: } catch (SQLException sqle2) {
1140: log.info("Caught exception rolling back transaction: "
1141: + sqle2
1142: + ExceptionUtility.captureStackTrace(sqle));
1143: }
1144:
1145: throw new RuntimeSecurityManagementException(this
1146: .getClass(), "Caught SQLException while removing "
1147: + "group.", sqle);
1148: } finally {
1149: try {
1150: if (removeGroupStatement != null) {
1151: removeGroupStatement.close();
1152: }
1153: } catch (SQLException sqle) {
1154: log.info("Caught exception closing Statement: " + sqle
1155: + ExceptionUtility.captureStackTrace(sqle));
1156: }
1157: }
1158: }
1159:
1160: /**
1161: * Finds a user with the given name in the database.
1162: *
1163: * @param username the user in the database
1164: *
1165: * @return the principal associated with the username or null if there
1166: * is no user
1167: *
1168: * @throws RuntimeSecurityManagementException indicates an error
1169: * communicating with the database
1170: */
1171: public Principal retreiveUser(String username) {
1172:
1173: Principal result = null;
1174: Connection connection = null;
1175:
1176: try {
1177: connection = config.getConnectionFactory().getConnection();
1178: } catch (SQLException sqle) {
1179: log.trace("Caught exception: " + sqle
1180: + ExceptionUtility.captureStackTrace(sqle));
1181:
1182: throw new RuntimeSecurityManagementException(this
1183: .getClass(), "Caught SQLException while opening "
1184: + "connection", sqle);
1185: }
1186:
1187: try {
1188: result = retreiveUser(connection, username);
1189: } finally {
1190: try {
1191: if (connection != null) {
1192: connection.close();
1193: }
1194: } catch (SQLException sqle) {
1195: log.debug("Caught exception closing Connection: "
1196: + sqle
1197: + ExceptionUtility.captureStackTrace(sqle));
1198: }
1199: }
1200:
1201: return result;
1202: }
1203:
1204: /**
1205: * Finds a user with the given name in the database.
1206: *
1207: * @param connection connection to execute database calls against
1208: * @param username the user in the database
1209: *
1210: * @return the principal associated with the username or null if there
1211: * is no user
1212: *
1213: * @throws RuntimeSecurityManagementException indicates an error
1214: * communicating with the database
1215: */
1216: protected Principal retreiveUser(Connection connection,
1217: String username) {
1218: PreparedStatement retreiveUserStatement = null;
1219: ResultSet retreiveUserResultSet = null;
1220: Principal resultPrincipal;
1221:
1222: if (log.isTraceEnabled()) {
1223: log.trace("Searching for user with principal name ["
1224: + username + "]");
1225: }
1226:
1227: try {
1228: retreiveUserStatement = config.getStatementFactory()
1229: .createPreparedStatement(
1230: config.getRetreiveUserQueryName(),
1231: connection);
1232: retreiveUserStatement.setString(1, username);
1233: retreiveUserResultSet = retreiveUserStatement
1234: .executeQuery();
1235:
1236: if (retreiveUserResultSet.next()) {
1237: resultPrincipal = createUserObject(retreiveUserResultSet
1238: .getString(1));
1239: } else {
1240: resultPrincipal = null;
1241: }
1242: } catch (StatementFactoryException sfe) {
1243: log.trace("Caught exception: " + sfe
1244: + ExceptionUtility.captureStackTrace(sfe));
1245:
1246: throw new RuntimeSecurityManagementException(this
1247: .getClass(),
1248: "Caught StatementFactoryException while adding "
1249: + "new user.", sfe);
1250: } catch (SQLException sqle) {
1251: log.trace("Caught exception: " + sqle
1252: + ExceptionUtility.captureStackTrace(sqle));
1253:
1254: throw new RuntimeSecurityManagementException(this
1255: .getClass(), "Caught SQLException while adding "
1256: + "new user.", sqle);
1257: } finally {
1258: try {
1259: if (retreiveUserResultSet != null) {
1260: retreiveUserResultSet.close();
1261: }
1262: } catch (SQLException sqle) {
1263: log.info("Caught exception closing ResultSet: " + sqle
1264: + ExceptionUtility.captureStackTrace(sqle));
1265: }
1266:
1267: try {
1268: if (retreiveUserStatement != null) {
1269: retreiveUserStatement.close();
1270: }
1271: } catch (SQLException sqle) {
1272: log.info("Caught exception closing Statement: " + sqle
1273: + ExceptionUtility.captureStackTrace(sqle));
1274: }
1275: }
1276:
1277: return resultPrincipal;
1278: }
1279:
1280: /**
1281: * Finds the group with the given name in the database.
1282: *
1283: * @param groupName the name of the group to get from the database
1284: *
1285: * @return the group with the given name or null if the group was not
1286: * in the database
1287: *
1288: * @throws RuntimeSecurityManagementException indicates an error
1289: * communicating with the database
1290: */
1291: public Group retreiveGroup(String groupName) {
1292:
1293: Group result = null;
1294: Connection connection = null;
1295:
1296: try {
1297: connection = config.getConnectionFactory().getConnection();
1298: } catch (SQLException sqle) {
1299: log.trace("Caught exception: " + sqle
1300: + ExceptionUtility.captureStackTrace(sqle));
1301:
1302: throw new RuntimeSecurityManagementException(this
1303: .getClass(), "Caught SQLException while opening "
1304: + "connection", sqle);
1305: }
1306:
1307: try {
1308: result = retreiveGroup(connection, groupName);
1309: } finally {
1310: try {
1311: if (connection != null) {
1312: connection.close();
1313: }
1314: } catch (SQLException sqle) {
1315: log.info("Caught exception closing Connection: " + sqle
1316: + ExceptionUtility.captureStackTrace(sqle));
1317: }
1318: }
1319:
1320: return result;
1321: }
1322:
1323: /**
1324: * Finds the group with the given name in the database.
1325: *
1326: * @param connection connection to execute database calls against
1327: * @param groupName the name of the group to get from the database
1328: *
1329: * @return the group with the given name or null if the group was not
1330: * in the database
1331: *
1332: * @throws RuntimeSecurityManagementException indicates an error
1333: * communicating with the database
1334: */
1335: protected Group retreiveGroup(Connection connection,
1336: String groupName) {
1337:
1338: PreparedStatement retreiveGroupStatement = null;
1339: ResultSet retreiveGroupResultSet = null;
1340: Group resultGroup;
1341:
1342: if (log.isTraceEnabled()) {
1343: log.trace("Searching for group with name [" + groupName
1344: + "]");
1345: }
1346:
1347: try {
1348: retreiveGroupStatement = config.getStatementFactory()
1349: .createPreparedStatement(
1350: config.getRetreiveGroupQueryName(),
1351: connection);
1352: retreiveGroupStatement.setString(1, groupName);
1353: retreiveGroupResultSet = retreiveGroupStatement
1354: .executeQuery();
1355:
1356: if (retreiveGroupResultSet.next()) {
1357: String resultGroupName = retreiveGroupResultSet
1358: .getString(1);
1359: resultGroup = createGroupObject(resultGroupName, null);
1360:
1361: if (resultGroup instanceof LazyLoadGroup) {
1362: retreiveMembers(connection,
1363: (LazyLoadGroup) resultGroup, null);
1364: } else {
1365: // TODO: Create a more basic loading of 1-level deep
1366: if (log.isDebugEnabled()) {
1367: log
1368: .debug("Group returned is not expected class ["
1369: + LazyLoadGroup.class.getName()
1370: + "] but is actually "
1371: + "instance of ["
1372: + resultGroup.getClass()
1373: .getName()
1374: + "] and therefore members will not be loaded.");
1375: }
1376: }
1377:
1378: if (log.isTraceEnabled()) {
1379: log.trace("Found group with name [" + groupName
1380: + "]");
1381: }
1382: } else {
1383: resultGroup = null;
1384:
1385: if (log.isTraceEnabled()) {
1386: log.trace("Did not find group with name ["
1387: + groupName + "]");
1388: }
1389: }
1390: } catch (StatementFactoryException sfe) {
1391: log.trace("Caught exception: " + sfe
1392: + ExceptionUtility.captureStackTrace(sfe));
1393:
1394: throw new RuntimeSecurityManagementException(this
1395: .getClass(),
1396: "Caught StatementFactoryException while finding "
1397: + "group.", sfe);
1398: } catch (SQLException sqle) {
1399: log.trace("Caught exception: " + sqle
1400: + ExceptionUtility.captureStackTrace(sqle));
1401:
1402: throw new RuntimeSecurityManagementException(this
1403: .getClass(), "Caught SQLException while finding "
1404: + "group.", sqle);
1405: } finally {
1406: try {
1407: if (retreiveGroupResultSet != null) {
1408: retreiveGroupResultSet.close();
1409: }
1410: } catch (SQLException sqle) {
1411: log.info("Caught exception closing ResultSet: " + sqle
1412: + ExceptionUtility.captureStackTrace(sqle));
1413: }
1414:
1415: try {
1416: if (retreiveGroupStatement != null) {
1417: retreiveGroupStatement.close();
1418: }
1419: } catch (SQLException sqle) {
1420: log.info("Caught exception closing Statement: " + sqle
1421: + ExceptionUtility.captureStackTrace(sqle));
1422: }
1423: }
1424:
1425: return resultGroup;
1426: }
1427:
1428: /**
1429: * Retreives the groups contain this particular principal.
1430: *
1431: * <p>
1432: * Only the first level into the group heirachy is queried.
1433: * </p>
1434: *
1435: * @param principal principal to retrieve the groups for
1436: *
1437: * @return groups which the principals is a direct member of
1438: *
1439: * @throws UnknownPrincipalException indicates the user does not exist
1440: * in the datastore
1441: * @throws RuntimeSecurityManagementException indicates an error
1442: * communicating with the database or inconsistent state.
1443: */
1444: public Set retreiveGroups(Principal principal)
1445: throws UnknownPrincipalException {
1446:
1447: Set result = null;
1448: Connection connection = null;
1449:
1450: try {
1451: connection = config.getConnectionFactory().getConnection();
1452: } catch (SQLException sqle) {
1453: log.trace("Caught exception: " + sqle
1454: + ExceptionUtility.captureStackTrace(sqle));
1455:
1456: throw new RuntimeSecurityManagementException(this
1457: .getClass(), "Caught SQLException while opening "
1458: + "connection", sqle);
1459: }
1460:
1461: try {
1462: result = retreiveGroups(connection, principal);
1463: } finally {
1464: try {
1465: if (connection != null) {
1466: connection.close();
1467: }
1468: } catch (SQLException sqle) {
1469: log.info("Caught exception closing Connection: " + sqle
1470: + ExceptionUtility.captureStackTrace(sqle));
1471: }
1472: }
1473:
1474: return result;
1475: }
1476:
1477: /**
1478: * Retreives the groups contain this particular principal.
1479: *
1480: * <p>
1481: * Only the first level into the group heirachy is queried.
1482: * </p>
1483: *
1484: * @param connection connection to execute database calls against
1485: * @param principal principal to retrieve the groups for
1486: *
1487: * @return groups which the principals is a direct member of
1488: *
1489: * @throws UnknownPrincipalException indicates the user does not exist
1490: * in the datastore
1491: * @throws RuntimeSecurityManagementException indicates an error
1492: * communicating with the database or inconsistent state.
1493: */
1494: protected Set retreiveGroups(Connection connection,
1495: Principal principal) throws UnknownPrincipalException {
1496:
1497: String queryname;
1498: Set membershipSet = new HashSet();
1499: PreparedStatement retreiveMembershipStatement = null;
1500: ResultSet retreiveMembershipResultSet = null;
1501:
1502: if (principal instanceof Group) {
1503: Principal currentGroup = retreiveGroup(connection,
1504: principal.getName());
1505:
1506: if (currentGroup == null) {
1507: throw new UnknownPrincipalException(this .getClass(),
1508: principal);
1509: }
1510:
1511: if (log.isTraceEnabled()) {
1512: log.trace("Get membership of group with name ["
1513: + principal.getName() + "]");
1514: }
1515:
1516: queryname = config.getRetreiveGroupsForGroupsQueryName();
1517: } else {
1518: Principal currentUser = retreiveUser(connection, principal
1519: .getName());
1520:
1521: if (currentUser == null) {
1522: throw new UnknownPrincipalException(this .getClass(),
1523: principal);
1524: }
1525:
1526: if (log.isTraceEnabled()) {
1527: log.trace("Get membership of user with name ["
1528: + principal.getName() + "]");
1529: }
1530:
1531: queryname = config.getRetreiveGroupsForUserQueryName();
1532: }
1533:
1534: try {
1535: retreiveMembershipStatement = config.getStatementFactory()
1536: .createPreparedStatement(queryname, connection);
1537: retreiveMembershipStatement.setString(1, principal
1538: .getName());
1539: retreiveMembershipResultSet = retreiveMembershipStatement
1540: .executeQuery();
1541:
1542: while (retreiveMembershipResultSet.next()) {
1543: Group containingGroup = retreiveGroup(connection,
1544: retreiveMembershipResultSet.getString(1));
1545:
1546: if (log.isTraceEnabled()) {
1547: log.trace("Adding membership group with name ["
1548: + containingGroup.getName()
1549: + "] to principals with name ["
1550: + principal.getName() + "]");
1551: }
1552:
1553: membershipSet.add(containingGroup);
1554: }
1555: } catch (StatementFactoryException sfe) {
1556: log.trace("Caught exception: " + sfe
1557: + ExceptionUtility.captureStackTrace(sfe));
1558:
1559: throw new RuntimeSecurityManagementException(this
1560: .getClass(),
1561: "Caught StatementFactoryException while getting groups "
1562: + "for principal [" + principal.getName()
1563: + "]", sfe);
1564: } catch (SQLException sqle) {
1565: log.trace("Caught exception: " + sqle
1566: + ExceptionUtility.captureStackTrace(sqle));
1567:
1568: throw new RuntimeSecurityManagementException(this
1569: .getClass(),
1570: "Caught SQLException while getting roups "
1571: + "for principal [" + principal.getName()
1572: + "]", sqle);
1573: } finally {
1574: try {
1575: if (retreiveMembershipResultSet != null) {
1576: retreiveMembershipResultSet.close();
1577: }
1578: } catch (SQLException sqle) {
1579: log.info("Caught exception closing ResultSet: " + sqle
1580: + ExceptionUtility.captureStackTrace(sqle));
1581: }
1582:
1583: try {
1584: if (retreiveMembershipStatement != null) {
1585: retreiveMembershipStatement.close();
1586: }
1587: } catch (SQLException sqle) {
1588: log.info("Caught exception closing Statement: " + sqle
1589: + ExceptionUtility.captureStackTrace(sqle));
1590: }
1591: }
1592:
1593: return membershipSet;
1594: }
1595:
1596: /**
1597: * Retrieves all the members of the given group.
1598: *
1599: * <p>
1600: * This will recursively load all members of the given group loading
1601: * all groups under it.
1602: * </p>
1603: *
1604: * @param connection connection to execute database calls against
1605: * @param group group to get all members of
1606: * @param loadedGroups map of groups that are already loaded
1607: *
1608: * @throws RuntimeSecurityManagementException indicates an error
1609: * communicating with the database
1610: */
1611: protected void retreiveMembers(Connection connection,
1612: LazyLoadGroup group, Map loadedGroups) {
1613:
1614: if (loadedGroups == null) {
1615: loadedGroups = new HashMap();
1616:
1617: if (log.isTraceEnabled()) {
1618: log
1619: .trace("Retreiving members for top-level group named ["
1620: + group.getName() + "]");
1621: }
1622: }
1623:
1624: Set members = new HashSet();
1625:
1626: PreparedStatement retreiveMembersStatement = null;
1627: ResultSet retreiveMembersResultSet = null;
1628:
1629: try {
1630: retreiveMembersStatement = config.getStatementFactory()
1631: .createPreparedStatement(
1632: config.getRetreiveMemebersQueryName(),
1633: connection);
1634:
1635: retreiveMembersStatement.setString(1, group.getName());
1636: retreiveMembersResultSet = retreiveMembersStatement
1637: .executeQuery();
1638:
1639: while (retreiveMembersResultSet.next()) {
1640: members.add(retreiveMember(retreiveMembersResultSet,
1641: loadedGroups));
1642: }
1643:
1644: group.setMembers(members);
1645:
1646: if (log.isTraceEnabled()) {
1647: log.trace("Added members to group named ["
1648: + group.getName() + "] with total of ["
1649: + members.size() + "] principals");
1650: }
1651: } catch (StatementFactoryException sfe) {
1652: log.trace("Caught exception: " + sfe
1653: + ExceptionUtility.captureStackTrace(sfe));
1654:
1655: throw new RuntimeSecurityManagementException(this
1656: .getClass(),
1657: "Caught StatementFactoryException while adding "
1658: + "new user.", sfe);
1659: } catch (SQLException sqle) {
1660: log.trace("Caught exception: " + sqle
1661: + ExceptionUtility.captureStackTrace(sqle));
1662:
1663: throw new RuntimeSecurityManagementException(this
1664: .getClass(), "Caught SQLException while adding "
1665: + "new user.", sqle);
1666: } finally {
1667: try {
1668: retreiveMembersResultSet.close();
1669: } catch (SQLException sqle) {
1670: log.info("Caught exception closing ResultSet: " + sqle
1671: + ExceptionUtility.captureStackTrace(sqle));
1672: }
1673:
1674: try {
1675: retreiveMembersStatement.close();
1676: } catch (SQLException sqle) {
1677: log.info("Caught exception closing Statement: " + sqle
1678: + ExceptionUtility.captureStackTrace(sqle));
1679: }
1680: }
1681:
1682: // If the group object was constructed using the
1683: // LazyLoadGroup it is possible to load all
1684: // of the subgroups without errors.
1685: Iterator membersIterator = members.iterator();
1686:
1687: while (membersIterator.hasNext()) {
1688: Object currentMember = membersIterator.next();
1689:
1690: if (currentMember instanceof LazyLoadGroup) {
1691: LazyLoadGroup currentGroup = (LazyLoadGroup) currentMember;
1692:
1693: if (currentGroup.isLoaded()) {
1694: if (log.isTraceEnabled()) {
1695: log.trace("In group named [" + group.getName()
1696: + "] found loaded sub-group named ["
1697: + currentGroup.getName() + "]");
1698: }
1699: } else {
1700: if (log.isTraceEnabled()) {
1701: log.trace("In group named [" + group.getName()
1702: + "] found UNLOADED sub-group named ["
1703: + currentGroup.getName() + "]");
1704: }
1705:
1706: retreiveMembers(connection, currentGroup,
1707: loadedGroups);
1708: }
1709: }
1710: }
1711: }
1712:
1713: /**
1714: * Method to create a new User object implementing the principal
1715: * interface. This method is meant to be overridden by a subclass
1716: * that needs to implement its own version.
1717: *
1718: * @param username name of the user to create an object for
1719: *
1720: * @return a new user object
1721: */
1722: protected Principal createUserObject(String username) {
1723: return new DefaultUserImpl(username);
1724: }
1725:
1726: /**
1727: * Method to create a new Group object implementing the Group
1728: * interface. This method is meant to be overridden by a subclass
1729: * that needs to implement its own version.
1730: *
1731: * @param groupName name of the group to create an object for
1732: * @param members a set of members for this group
1733: *
1734: * @return a new group object
1735: */
1736: protected Group createGroupObject(String groupName, Set members) {
1737: return new DefaultGroupImpl(groupName, members, config
1738: .getConfigurationName());
1739: }
1740:
1741: /**
1742: * Retreives a member from a given result.
1743: *
1744: * <p>
1745: * A map of groupname to already loaded groups is passed in as well.
1746: * This allows the method to either return a currently loaded group
1747: * if it exists. Otherwise it will create a new group with a call to
1748: * <code>createGroupObject</code>. It is possible to change the
1749: * group object returned by subclassing this implementation and
1750: * overriding that method.
1751: * </p>
1752: *
1753: * @param memberResultSet ResultSet to get the next user from. This
1754: * method expects the first column to be the name of the user.
1755: * The second column is the type of user identified by the
1756: * <code>PrincipalTypeEnum</code> object.
1757: * @param loadedGroups Map of already loaded groups. The key is the
1758: * name of the group. If the current row of the ResultSet
1759: * returns a group in this map, the already loaded group will
1760: * be returned instead of constructing a new one.
1761: *
1762: * @return a principal contained in the current row of the ResultSet
1763: *
1764: * @throws RuntimeSecurityManagementException indicates an error
1765: * communicating with the database
1766: */
1767: protected Principal retreiveMember(ResultSet memberResultSet,
1768: Map loadedGroups) {
1769:
1770: Principal resultPrincipal = null;
1771:
1772: try {
1773: String principalName = memberResultSet.getString(1);
1774: PrincipalTypeEnum principalTypeEnum = PrincipalTypeEnum
1775: .getByOrdinal(memberResultSet.getInt(2));
1776:
1777: if (log.isTraceEnabled()) {
1778: log.trace("Instantiating new principal named ["
1779: + principalName + "] of enumeration type ["
1780: + principalTypeEnum + "]");
1781: }
1782:
1783: if (principalTypeEnum.equals(PrincipalTypeEnum.USER)) {
1784: resultPrincipal = createUserObject(principalName);
1785: } else if (principalTypeEnum
1786: .equals(PrincipalTypeEnum.GROUP)) {
1787: if (loadedGroups.containsKey(principalName)) {
1788: resultPrincipal = (Principal) loadedGroups
1789: .get(principalName);
1790: } else {
1791: resultPrincipal = createGroupObject(principalName,
1792: null);
1793:
1794: loadedGroups.put(principalName, resultPrincipal);
1795: }
1796: }
1797: } catch (PrincipalTypeEnum.PrincipalTypeEnumNotFoundException ptenfe) {
1798: log.trace("Caught exception: " + ptenfe
1799: + ExceptionUtility.captureStackTrace(ptenfe));
1800:
1801: throw new RuntimeSecurityManagementException(this
1802: .getClass(), "Invalid principal type encountered.",
1803: ptenfe);
1804: } catch (SQLException sqle) {
1805: log.trace("Caught exception: " + sqle
1806: + ExceptionUtility.captureStackTrace(sqle));
1807:
1808: throw new RuntimeSecurityManagementException(this
1809: .getClass(), "Caught SQLException while adding "
1810: + "new user.", sqle);
1811: }
1812:
1813: return resultPrincipal;
1814: }
1815:
1816: /**
1817: * Adds a principal (user or group) into the given group.
1818: *
1819: * @param principal the principal to add into the group
1820: * @param group the group to add a principal to
1821: *
1822: * @return if the database was altered by this call
1823: *
1824: * @throws UnknownPrincipalException indicates the principal does not
1825: * currently exists in the system
1826: * @throws UnknownGroupException indicates the group does not
1827: * currently exists in the system
1828: * @throws RuntimeSecurityManagementException indicates an error
1829: * communicating with the database
1830: */
1831: public boolean addPrincipalToGroup(Principal principal, Group group)
1832: throws UnknownPrincipalException, UnknownGroupException {
1833:
1834: boolean isPrincipalAdded = false;
1835: Connection connection = null;
1836:
1837: try {
1838: connection = config.getConnectionFactory().getConnection();
1839: } catch (SQLException sqle) {
1840: log.trace("Caught exception: " + sqle
1841: + ExceptionUtility.captureStackTrace(sqle));
1842:
1843: throw new RuntimeSecurityManagementException(this
1844: .getClass(),
1845: "Caught SQLException while opening connection",
1846: sqle);
1847: }
1848:
1849: try {
1850: isPrincipalAdded = addPrincipalToGroup(connection,
1851: principal, group);
1852: } finally {
1853: try {
1854: if (connection != null) {
1855: connection.close();
1856: }
1857: } catch (SQLException sqle) {
1858: log.info("Caught exception closing Connection: " + sqle
1859: + ExceptionUtility.captureStackTrace(sqle));
1860: }
1861: }
1862:
1863: return isPrincipalAdded;
1864: }
1865:
1866: /**
1867: * Adds a principal (user or group) into the given group.
1868: *
1869: * @param connection connection to execute database calls against
1870: * @param principal the principal to add into the group
1871: * @param group the group to add a principal to
1872: *
1873: * @return if the database was altered by this call
1874: *
1875: * @throws UnknownPrincipalException indicates the principal does not
1876: * currently exists in the system
1877: * @throws UnknownGroupException indicates the group does not
1878: * currently exists in the system
1879: * @throws RuntimeSecurityManagementException indicates an error
1880: * communicating with the database
1881: */
1882: protected boolean addPrincipalToGroup(Connection connection,
1883: Principal principal, Group group)
1884: throws UnknownPrincipalException, UnknownGroupException {
1885: PreparedStatement addPrincipalToGroupStatement = null;
1886: boolean result = false;
1887:
1888: if (log.isTraceEnabled()) {
1889: log.trace("Adding principal [" + principal.getName()
1890: + "] to group [" + group.getName() + "]");
1891: }
1892:
1893: Object principalPrimaryKey = retreivePrincipalPrimaryKey(
1894: connection, principal);
1895: Object groupPrimaryKey = retreivePrincipalPrimaryKey(
1896: connection, group);
1897:
1898: if (group.isMember(principal)) {
1899: if (log.isTraceEnabled()) {
1900: log.trace("User [" + principal
1901: + "] is already a member of group [" + group
1902: + "]");
1903: }
1904:
1905: result = false;
1906: } else {
1907: try {
1908: addPrincipalToGroupStatement = config
1909: .getStatementFactory()
1910: .createPreparedStatement(
1911: config
1912: .getAddPrincipalToGroupQueryName(),
1913: connection);
1914:
1915: addPrincipalToGroupStatement.setObject(1,
1916: principalPrimaryKey);
1917: addPrincipalToGroupStatement.setObject(2,
1918: groupPrimaryKey);
1919:
1920: int resultCount = addPrincipalToGroupStatement
1921: .executeUpdate();
1922:
1923: if (resultCount > 0) {
1924: result = true;
1925:
1926: if (log.isDebugEnabled()) {
1927: log.debug("Added principal ["
1928: + principal.getName() + "] to group ["
1929: + group.getName() + "]");
1930: }
1931: }
1932: } catch (StatementFactoryException sfe) {
1933: log.trace("Caught exception: " + sfe
1934: + ExceptionUtility.captureStackTrace(sfe));
1935:
1936: throw new RuntimeSecurityManagementException(this
1937: .getClass(),
1938: "Caught StatementFactoryException while adding "
1939: + "new user.", sfe);
1940: } catch (SQLException sqle) {
1941: log.trace("Caught exception: " + sqle
1942: + ExceptionUtility.captureStackTrace(sqle));
1943:
1944: throw new RuntimeSecurityManagementException(this
1945: .getClass(),
1946: "Caught SQLException while adding "
1947: + "new user.", sqle);
1948: } finally {
1949: try {
1950: if (addPrincipalToGroupStatement != null) {
1951: addPrincipalToGroupStatement.close();
1952: }
1953: } catch (SQLException sqle) {
1954: log.info("Caught exception closing Statement: "
1955: + sqle
1956: + ExceptionUtility.captureStackTrace(sqle));
1957: }
1958: }
1959: }
1960:
1961: return result;
1962: }
1963:
1964: /**
1965: * Removes the principal (user or group) from the given group.
1966: *
1967: * @param principal the principal (user or group) to remove from the
1968: * given group
1969: * @param group the group to remove the principal from
1970: *
1971: * @return if the database changed as a result of the call
1972: *
1973: * @throws UnknownPrincipalException indicates the principal does not
1974: * currently exists in the system
1975: * @throws UnknownGroupException indicates the group does not
1976: * currently exists in the system
1977: * @throws RuntimeSecurityManagementException indicates an error
1978: * communicating with the database
1979: */
1980: public boolean removePrincipalFromGroup(Principal principal,
1981: Group group) throws UnknownPrincipalException,
1982: UnknownGroupException {
1983: Connection connection = null;
1984: boolean isRemoved = false;
1985:
1986: try {
1987: connection = config.getConnectionFactory().getConnection();
1988: } catch (SQLException sqle) {
1989: log.trace("Caught exception: " + sqle
1990: + ExceptionUtility.captureStackTrace(sqle));
1991:
1992: throw new RuntimeSecurityManagementException(this
1993: .getClass(),
1994: "Caught SQLException while opening connection",
1995: sqle);
1996: }
1997:
1998: try {
1999: isRemoved = removePrincipalFromGroup(connection, principal,
2000: group);
2001: } finally {
2002: try {
2003: if (connection != null) {
2004: connection.close();
2005: }
2006: } catch (SQLException sqle) {
2007: log.info("Caught exception closing Connection: " + sqle
2008: + ExceptionUtility.captureStackTrace(sqle));
2009: }
2010: }
2011:
2012: return isRemoved;
2013: }
2014:
2015: /**
2016: * Removes the principal (user or group) from the given group.
2017: *
2018: * @param connection connection to execute database calls against
2019: * @param principal the principal (user or group) to remove from the
2020: * given group
2021: * @param group the group to remove the principal from
2022: *
2023: * @return if the database changed as a result of the call
2024: *
2025: * @throws UnknownPrincipalException indicates the principal does not
2026: * currently exists in the system
2027: * @throws UnknownGroupException indicates the group does not
2028: * currently exists in the system
2029: * @throws RuntimeSecurityManagementException indicates an error
2030: * communicating with the database
2031: */
2032: protected boolean removePrincipalFromGroup(Connection connection,
2033: Principal principal, Group group)
2034: throws UnknownPrincipalException, UnknownGroupException {
2035: PreparedStatement removePrincipalFromGroupStatement = null;
2036: boolean result = false;
2037:
2038: if (log.isTraceEnabled()) {
2039: log.trace("Removing principal [" + principal.getName()
2040: + "] from group [" + group.getName() + "]");
2041: }
2042:
2043: Object principalPrimaryKey = retreivePrincipalPrimaryKey(
2044: connection, principal);
2045: Object groupPrimaryKey = retreivePrincipalPrimaryKey(
2046: connection, group);
2047:
2048: if (!group.isMember(principal)) {
2049: result = false;
2050:
2051: if (log.isTraceEnabled()) {
2052: log.trace("User [" + principal
2053: + "] is already not a member of group ["
2054: + group + "]");
2055: }
2056: } else {
2057: try {
2058: removePrincipalFromGroupStatement = config
2059: .getStatementFactory()
2060: .createPreparedStatement(
2061: config
2062: .getRemovePrincipalFromGroupQueryName(),
2063: connection);
2064:
2065: removePrincipalFromGroupStatement.setObject(1,
2066: principalPrimaryKey);
2067: removePrincipalFromGroupStatement.setObject(2,
2068: groupPrimaryKey);
2069:
2070: int resultCount = removePrincipalFromGroupStatement
2071: .executeUpdate();
2072:
2073: if (resultCount > 0) {
2074: result = true;
2075:
2076: if (log.isDebugEnabled()) {
2077: log.debug("Removed principal ["
2078: + principal.getName()
2079: + "] from group [" + group.getName()
2080: + "]");
2081: }
2082: }
2083: } catch (StatementFactoryException sfe) {
2084: log.trace("Caught exception: " + sfe
2085: + ExceptionUtility.captureStackTrace(sfe));
2086:
2087: throw new RuntimeSecurityManagementException(this
2088: .getClass(),
2089: "Caught StatementFactoryException while removing "
2090: + "user.", sfe);
2091: } catch (SQLException sqle) {
2092: log.trace("Caught exception: " + sqle
2093: + ExceptionUtility.captureStackTrace(sqle));
2094:
2095: throw new RuntimeSecurityManagementException(
2096: this .getClass(),
2097: "Caught SQLException while removing " + "user.",
2098: sqle);
2099: } finally {
2100: try {
2101: removePrincipalFromGroupStatement.close();
2102: } catch (SQLException sqle) {
2103: log.info("Caught exception closing Statement: "
2104: + sqle
2105: + ExceptionUtility.captureStackTrace(sqle));
2106: }
2107: }
2108: }
2109:
2110: return result;
2111: }
2112:
2113: /**
2114: * Retreives all unique names of users from the store as a Set of
2115: * Strings.
2116: *
2117: * @return All unique user names as a Set of Strings. If there are no
2118: * users in the system and empty Set will be returned.
2119: *
2120: * @throws RuntimeSecurityManagementException indicates an error
2121: * communicating with the database or inconsistent state.
2122: */
2123: public Set retreiveAllUserNames() {
2124:
2125: Connection connection = null;
2126: Set allUsers = null;
2127:
2128: try {
2129: connection = config.getConnectionFactory().getConnection();
2130: } catch (SQLException sqle) {
2131: log.trace("Caught exception: " + sqle
2132: + ExceptionUtility.captureStackTrace(sqle));
2133:
2134: throw new RuntimeSecurityManagementException(this
2135: .getClass(),
2136: "Caught SQLException while opening connection",
2137: sqle);
2138: }
2139:
2140: try {
2141: allUsers = retreiveAllusernames(connection);
2142: } finally {
2143: try {
2144: if (connection != null) {
2145: connection.close();
2146: }
2147: } catch (SQLException sqle) {
2148: log.info("Caught exception closing Connection: " + sqle
2149: + ExceptionUtility.captureStackTrace(sqle));
2150: }
2151: }
2152:
2153: return allUsers;
2154: }
2155:
2156: /**
2157: * Retreives all unique names of users from the store as a Set of
2158: * Strings.
2159: *
2160: * @param connection connection to execute database calls against
2161: *
2162: * @return All unique user names as a Set of Strings. If there are no
2163: * users in the system and empty Set will be returned.
2164: *
2165: * @throws RuntimeSecurityManagementException indicates an error
2166: * communicating with the database or inconsistent state.
2167: */
2168: protected Set retreiveAllusernames(Connection connection) {
2169: Set allUsers = new HashSet();
2170: PreparedStatement retreiveAllUsersStatement = null;
2171: ResultSet retreiveAllUsersResultSet = null;
2172:
2173: if (log.isTraceEnabled()) {
2174: log.trace("Searching for all users.");
2175: }
2176:
2177: try {
2178: retreiveAllUsersStatement = config.getStatementFactory()
2179: .createPreparedStatement(
2180: config.getRetreiveAllUsersQuery(),
2181: connection);
2182:
2183: retreiveAllUsersResultSet = retreiveAllUsersStatement
2184: .executeQuery();
2185:
2186: while (retreiveAllUsersResultSet.next()) {
2187: allUsers.add(retreiveAllUsersResultSet.getString(1));
2188: }
2189: } catch (StatementFactoryException sfe) {
2190: log.trace("Caught exception: " + sfe
2191: + ExceptionUtility.captureStackTrace(sfe));
2192:
2193: throw new RuntimeSecurityManagementException(this
2194: .getClass(),
2195: "Caught StatementFactoryException while retreiving "
2196: + "users.", sfe);
2197: } catch (SQLException sqle) {
2198: log.trace("Caught exception: " + sqle
2199: + ExceptionUtility.captureStackTrace(sqle));
2200:
2201: throw new RuntimeSecurityManagementException(this
2202: .getClass(),
2203: "Caught SQLException while retreiving users.", sqle);
2204: } finally {
2205: try {
2206: if (retreiveAllUsersResultSet != null) {
2207: retreiveAllUsersResultSet.close();
2208: }
2209: } catch (SQLException sqle) {
2210: log.info("Caught exception closing ResultSet: " + sqle
2211: + ExceptionUtility.captureStackTrace(sqle));
2212: }
2213:
2214: try {
2215: if (retreiveAllUsersStatement != null) {
2216: retreiveAllUsersStatement.close();
2217: }
2218: } catch (SQLException sqle) {
2219: log.info("Caught exception closing Statement: " + sqle
2220: + ExceptionUtility.captureStackTrace(sqle));
2221: }
2222: }
2223:
2224: return allUsers;
2225: }
2226:
2227: /**
2228: * Retreives all unique names of groups from the store as a Set of
2229: * Strings.
2230: *
2231: * @return All unique group names as a Set of Strings. If there are
2232: * no group in the system and empty Set will be returned.
2233: *
2234: * @throws RuntimeSecurityManagementException indicates an error
2235: * communicating with the database or inconsistent state.
2236: */
2237: public Set retreiveAllGroupNames() {
2238:
2239: Connection connection = null;
2240: Set allGroups = null;
2241:
2242: try {
2243: connection = config.getConnectionFactory().getConnection();
2244: } catch (SQLException sqle) {
2245: log.trace("Caught exception: " + sqle
2246: + ExceptionUtility.captureStackTrace(sqle));
2247:
2248: throw new RuntimeSecurityManagementException(this
2249: .getClass(),
2250: "Caught SQLException while opening connection",
2251: sqle);
2252: }
2253:
2254: try {
2255: allGroups = retreiveAllGroupNames(connection);
2256: } finally {
2257: try {
2258: if (connection != null) {
2259: connection.close();
2260: }
2261: } catch (SQLException sqle) {
2262: log.info("Caught exception closing Connection: " + sqle
2263: + ExceptionUtility.captureStackTrace(sqle));
2264: }
2265: }
2266:
2267: return allGroups;
2268: }
2269:
2270: /**
2271: * Retreives all unique names of groups from the store as a Set of
2272: * Strings.
2273: *
2274: * @param connection connection to execute database calls against
2275: *
2276: * @return All unique group names as a Set of Strings. If there are
2277: * no group in the system and empty Set will be returned.
2278: *
2279: * @throws RuntimeSecurityManagementException indicates an error
2280: * communicating with the database or inconsistent state.
2281: */
2282: protected Set retreiveAllGroupNames(Connection connection) {
2283: Set allGroups = new HashSet();
2284: PreparedStatement retreiveAllGroupsStatement = null;
2285: ResultSet retreiveAllGroupsResultSet = null;
2286:
2287: if (log.isTraceEnabled()) {
2288: log.trace("Searching for all users.");
2289: }
2290:
2291: try {
2292: retreiveAllGroupsStatement = config.getStatementFactory()
2293: .createPreparedStatement(
2294: config.getRetreiveAllGroupsQuery(),
2295: connection);
2296:
2297: retreiveAllGroupsResultSet = retreiveAllGroupsStatement
2298: .executeQuery();
2299:
2300: while (retreiveAllGroupsResultSet.next()) {
2301: allGroups.add(retreiveAllGroupsResultSet.getString(1));
2302: }
2303: } catch (StatementFactoryException sfe) {
2304: log.trace("Caught exception: " + sfe
2305: + ExceptionUtility.captureStackTrace(sfe));
2306:
2307: throw new RuntimeSecurityManagementException(this
2308: .getClass(),
2309: "Caught StatementFactoryException while retreiving "
2310: + "groups.", sfe);
2311: } catch (SQLException sqle) {
2312: log.trace("Caught exception: " + sqle
2313: + ExceptionUtility.captureStackTrace(sqle));
2314:
2315: throw new RuntimeSecurityManagementException(this
2316: .getClass(),
2317: "Caught SQLException while retreiving groups.",
2318: sqle);
2319: } finally {
2320: try {
2321: if (retreiveAllGroupsResultSet != null) {
2322: retreiveAllGroupsResultSet.close();
2323: }
2324: } catch (SQLException sqle) {
2325: log.info("Caught exception closing ResultSet: " + sqle
2326: + ExceptionUtility.captureStackTrace(sqle));
2327: }
2328:
2329: try {
2330: if (retreiveAllGroupsStatement != null) {
2331: retreiveAllGroupsStatement.close();
2332: }
2333: } catch (SQLException sqle) {
2334: log.info("Caught exception closing Statement: " + sqle
2335: + ExceptionUtility.captureStackTrace(sqle));
2336: }
2337: }
2338:
2339: return allGroups;
2340: }
2341:
2342: /**
2343: * Gets back the primary key in the database for a given principal.
2344: *
2345: * <p>
2346: * This may execute a query to retreive it, or if the information is
2347: * contained within the Principal object it may return it from there.
2348: * </p>
2349: *
2350: * @param connection connection to execute database calls against
2351: * @param principal the principal to get the primary key for.
2352: *
2353: * @return primary key for the user. This may be a String, Integer,
2354: * etc.
2355: *
2356: * @throws UnknownPrincipalException indicates the principal does not
2357: * currently exists in the system
2358: * @throws UnknownGroupException indicates the group does not
2359: * currently exists in the system
2360: *
2361: * @see #retreiveUserPrimaryKey
2362: * @see #retreiveGroupPrimaryKey
2363: */
2364: protected Object retreivePrincipalPrimaryKey(Connection connection,
2365: Principal principal) throws UnknownPrincipalException,
2366: UnknownGroupException {
2367: Object primaryKey;
2368:
2369: if (principal instanceof Group) {
2370: primaryKey = retreiveGroupPrimaryKey(connection,
2371: (Group) principal);
2372: } else {
2373: primaryKey = retreiveUserPrimaryKey(connection, principal);
2374: }
2375:
2376: return primaryKey;
2377: }
2378:
2379: /**
2380: * Gets back the primary key in the database for a given user.
2381: *
2382: * <p>
2383: * This may execute a query to retreive it, or if the information is
2384: * contained within the Principal object it may return it from there.
2385: * </p>
2386: *
2387: * @param connection connection to execute database calls against
2388: * @param principal the principal to get the primary key for.
2389: *
2390: * @return primary key for the user. This may be a String, Integer,
2391: * etc.
2392: *
2393: * @throws UnknownPrincipalException indicates the principal does not
2394: * currently exists in the system
2395: * @throws RuntimeSecurityManagementException indicates an error
2396: * communicating with the database or inconsistent state.
2397: */
2398: protected Object retreiveUserPrimaryKey(Connection connection,
2399: Principal principal) throws UnknownPrincipalException {
2400: PreparedStatement retreiveUserPrimaryKeyStatement = null;
2401: ResultSet retreiveUserPrimaryKeyResultSet = null;
2402: Object userPrimaryKey = null;
2403:
2404: try {
2405: retreiveUserPrimaryKeyStatement = config
2406: .getStatementFactory()
2407: .createPreparedStatement(
2408: config.getRetreiveUserPrimaryKeyQueryName(),
2409: connection);
2410:
2411: retreiveUserPrimaryKeyStatement.setObject(1, principal
2412: .getName());
2413:
2414: retreiveUserPrimaryKeyResultSet = retreiveUserPrimaryKeyStatement
2415: .executeQuery();
2416:
2417: if (retreiveUserPrimaryKeyResultSet.next()) {
2418: userPrimaryKey = retreiveUserPrimaryKeyResultSet
2419: .getObject(1);
2420: } else {
2421: throw new UnknownPrincipalException(this .getClass(),
2422: principal.getName());
2423: }
2424:
2425: if (log.isTraceEnabled()) {
2426: log.trace("Retreived primary key for user with name ["
2427: + principal.getName() + "] of value ["
2428: + userPrimaryKey + "]");
2429: }
2430: } catch (StatementFactoryException sfe) {
2431: log.trace("Caught exception: " + sfe
2432: + ExceptionUtility.captureStackTrace(sfe));
2433:
2434: throw new RuntimeSecurityManagementException(this
2435: .getClass(),
2436: "Caught StatementFactoryException while getting primary key "
2437: + "for user [" + principal.getName() + "]",
2438: sfe);
2439: } catch (SQLException sqle) {
2440: log.trace("Caught exception: " + sqle
2441: + ExceptionUtility.captureStackTrace(sqle));
2442:
2443: throw new RuntimeSecurityManagementException(this
2444: .getClass(),
2445: "Caught SQLException while getting primary key "
2446: + "for user [" + principal.getName() + "]",
2447: sqle);
2448: } finally {
2449: try {
2450: if (retreiveUserPrimaryKeyResultSet != null) {
2451: retreiveUserPrimaryKeyResultSet.close();
2452: }
2453: } catch (SQLException sqle) {
2454: // Ignore exception.
2455: }
2456:
2457: try {
2458: if (retreiveUserPrimaryKeyStatement != null) {
2459: retreiveUserPrimaryKeyStatement.close();
2460: }
2461: } catch (SQLException sqle) {
2462: // Ignore exception.
2463: }
2464: }
2465:
2466: return userPrimaryKey;
2467: }
2468:
2469: /**
2470: * Gets back the primary key in the database for a given group.
2471: *
2472: * <p>
2473: * This may execute a query to retreive it, or if the information is
2474: * contained within the Principal object it may return it from there.
2475: * </p>
2476: *
2477: * @param connection connection to execute database calls against
2478: * @param group the principal to get the primary key for.
2479: *
2480: * @return primary key for the user. This may be a String, Integer,
2481: * etc.
2482: *
2483: * @throws UnknownGroupException indicates the principal does not
2484: * currently exists in the system
2485: * @throws RuntimeSecurityManagementException indicates an error
2486: * communicating with the database or inconsistent state.
2487: */
2488: protected Object retreiveGroupPrimaryKey(Connection connection,
2489: Group group) throws UnknownGroupException {
2490: PreparedStatement retreiveGroupPrimaryKeyStatement = null;
2491: ResultSet retreiveGroupPrimaryKeyResultSet = null;
2492: Object groupPrimaryKey = null;
2493:
2494: try {
2495: retreiveGroupPrimaryKeyStatement = config
2496: .getStatementFactory()
2497: .createPreparedStatement(
2498: config
2499: .getRetreiveGroupPrimaryKeyQueryName(),
2500: connection);
2501:
2502: retreiveGroupPrimaryKeyStatement.setObject(1, group
2503: .getName());
2504:
2505: retreiveGroupPrimaryKeyResultSet = retreiveGroupPrimaryKeyStatement
2506: .executeQuery();
2507:
2508: if (retreiveGroupPrimaryKeyResultSet.next()) {
2509: groupPrimaryKey = retreiveGroupPrimaryKeyResultSet
2510: .getObject(1);
2511: } else {
2512: throw new UnknownGroupException(this .getClass(), group
2513: .getName());
2514: }
2515:
2516: if (log.isTraceEnabled()) {
2517: log.trace("Retreived primary key for group with name ["
2518: + group.getName() + "] of value ["
2519: + groupPrimaryKey + "]");
2520: }
2521: } catch (StatementFactoryException sfe) {
2522: log.trace("Caught exception: " + sfe
2523: + ExceptionUtility.captureStackTrace(sfe));
2524:
2525: throw new RuntimeSecurityManagementException(this
2526: .getClass(),
2527: "Caught StatementFactoryException while getting primary key "
2528: + "for group [" + group.getName() + "]",
2529: sfe);
2530: } catch (SQLException sqle) {
2531: log.trace("Caught exception: " + sqle
2532: + ExceptionUtility.captureStackTrace(sqle));
2533:
2534: throw new RuntimeSecurityManagementException(this
2535: .getClass(),
2536: "Caught SQLException while getting primary key "
2537: + "for group [" + group.getName() + "]",
2538: sqle);
2539: } finally {
2540: try {
2541: if (retreiveGroupPrimaryKeyResultSet != null) {
2542: retreiveGroupPrimaryKeyResultSet.close();
2543: }
2544: } catch (SQLException sqle) {
2545: // Ignore exception.
2546: }
2547:
2548: try {
2549: if (retreiveGroupPrimaryKeyStatement != null) {
2550: retreiveGroupPrimaryKeyStatement.close();
2551: }
2552: } catch (SQLException sqle) {
2553: // Ignore exception.
2554: }
2555: }
2556:
2557: return groupPrimaryKey;
2558: }
2559:
2560: /**
2561: * Configures the service.
2562: *
2563: * @param configuration <code>RdbmsUserManagerConfiguration</code>
2564: * configuration object for the service
2565: *
2566: * @throws InvalidConfigurationException indicates an error loading
2567: * the configuration
2568: */
2569: public void configure(ComponentConfiguration configuration) {
2570:
2571: try {
2572: this .config = (RdbmsUserManagerConfiguration) configuration;
2573: } catch (ClassCastException cce) {
2574: throw new InvalidConfigurationException(this .getClass(),
2575: configuration.getConfigurationName(),
2576: "ComponentConfiguration",
2577: "Specifed RdbmsUserManagerConfiguration does not implement "
2578: + "correct interface.", cce);
2579: }
2580: }
2581: }
|