CTSPersistentStore.java revision 9f70e00b4c0aea24675f90732e58a16d17d67635
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2012 ForgeRock US Inc. All Rights Reserved
*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information:
*
* "Portions copyright [year] [name of copyright owner]".
*
*/
/**
* Configuration Directory as OpenAM's Session and Token Store.
* <p>
* Having a replicated Directory
* will provide the underlying Session High Availability and Failover
* for OpenAM Session Data.
* </p>
* <p/>
*
* @author steve
* @author jeff.schenk@forgerock.com
* @author jason.lemay@forgerock.com
*
*/
public class CTSPersistentStore extends GeneralTaskRunnable
/**
* Globals Constants, so not to pollute entire product.
*/
private static final String ANY_OBJECTCLASS_FILTER = "(" + OBJECTCLASS + Constants.EQUALS + Constants.ASTERISK + ")";
/**
* Search Constructs
*/
/**
* Singleton Instance
*/
/**
* Shared SM Data Layer Accessor.
*/
private static volatile CTSDataLayer CTSDataLayer;
/**
* Debug Logging
*/
/**
* Service Globals
*/
private static volatile boolean shutdown = false;
private static Thread storeThread;
/**
* Grace Period
*/
/**
* Configuration Definitions
*/
private static boolean caseSensitiveUUID =
/**
* Define Global DN and Container Constants
*/
// Our default for SM_CONFIG_ROOT_SUFFIX = dc=openam,dc=forgerock,dc=org
private static final String SM_CONFIG_ROOT_SUFFIX =
// Our default for TOKEN_ROOT_SUFFIX = ou=tokens
private static final String TOKEN_ROOT_SUFFIX =
// Our default for TOKEN_ROOT = ou=tokens,dc=openam,dc=forgerock,dc=org
// Our default for TOKEN_SESSION_HA_ROOT_SUFFIX = ou=openam-session
private static final String TOKEN_SESSION_HA_ROOT_SUFFIX =
// Our default for TOKEN_SAML2_HA_ROOT_SUFFIX = ou=openam-saml2
private static final String TOKEN_SAML2_HA_ROOT_SUFFIX =
// Our default for TOKEN_OAUTH2_HA_ROOT_SUFFIX = ou-openam-oauth2
private static final String TOKEN_OAUTH2_HA_ROOT_SUFFIX =
/**
* Define Session DN Constants
*/
private static final String SESSION_FAILOVER_HA_BASE_DN =
private static final String SESSION_FAILOVER_HA_ELEMENT_DN_TEMPLATE =
/**
* Session Expiration Filter.
*/
private final static String TOKEN_EXPIRATION_FILTER_TEMPLATE =
/**
* Define SAML2 DN Constants
*/
private static final String SAML2_HA_BASE_DN =
private static final String TOKEN_SAML2_HA_ELEMENT_DN_TEMPLATE =
/**
* Define OAUTH2 DN Constants
*/
private static final String OAUTH2_HA_BASE_DN =
private static final String TOKEN_OAUTH2_HA_ELEMENT_DN_TEMPLATE =
OAuth2Constants.Params.ID + Constants.EQUALS + "{"+OAUTH2_KEY_NAME+"}" + Constants.COMMA + OAUTH2_HA_BASE_DN;
/**
* Define all our Top Level DN for Validation.
* This DIT hierarchy must exist for this component to operate.
*
* The Squence of these should be in DIT order.
*/
private static final String[] containersToBeValidated = {
};
/**
* Return Attribute Constructs
*/
private static String[] returnAttrs_ARRAY;
private static String[] returnAttrs_OAuth2_ARRAY;
private static String[] returnAttrs_PKEY_ONLY_ARRAY;
private static String[] returnAttrs_DN_ONLY_ARRAY;
private static String[] returnAttrs_ID_ONLY_ARRAY;
/**
* Expired Session Search Limit and Date & Time Formatter.
*/
private static final int DEFAULT_EXPIRED_SESSION_SEARCH_LIMIT = 250;
private static int EXPIRED_SESSION_SEARCH_LIMIT;
/**
* Deferred Operation Queue.
*/
private static ConcurrentLinkedQueue<AMSessionRepositoryDeferredOperation>
/**
* Time period between two successive runs of repository cleanup thread
* which checks and removes expired records
*/
private static long cleanUpValue = 0;
public static final String CLEANUP_RUN_PERIOD =
"com.sun.identity.session.repository.cleanupRunPeriod";
/**
* Time period between two successive runs of DBHealthChecker thread which
* checks for Database availability.
*/
public static final String HEALTH_CHECK_RUN_PERIOD =
"com.sun.identity.session.repository.healthCheckRunPeriod";
/**
* This period is actual one that is used by the thread. The value is set to
* the smallest value of cleanUPPeriod and healthCheckPeriod.
*/
/**
* Static Initialization Stanza
* - Set all Timing Periods.
*/
static {
try {
} catch (Exception e) {
+ ", using default");
}
try {
} catch (Exception e) {
+ ", using default");
}
try {
} catch (Exception e) {
+ ", using default");
}
// Create and Initialize all Necessary Attribute Linked Sets.
returnAttrs_PKEY_ONLY_ARRAY = returnAttrs_PKEY_ONLY.toArray(new String[returnAttrs_PKEY_ONLY.size()]);
//create OAuth2 attribute Lined Sets
// Set Up Our Expired Search Limit
try {
Integer.getInteger(SystemPropertiesManager.get(SYS_PROPERTY_EXPIRED_SEARCH_LIMIT, Integer.toString(DEFAULT_EXPIRED_SESSION_SEARCH_LIMIT)));
} catch (Exception e) {
}
// Set Our Simple Date Formatter, per our data Store.
// Proceed With Initialization of Service.
try {
// Initialize the Initial Singleton Service Instance.
initialize();
} catch (StoreException se) {
}
} // End of Static Initialization Stanza.
/**
* Private restricted to preserve Singleton Instantiation.
*/
private CTSPersistentStore() {
}
/**
* Provide Service Instance Access to our Singleton
*
* @return CTSPersistentStore Singleton Instance.
* @throws StoreException
*/
return instance;
}
/**
* Perform Initialization
*/
private synchronized static void initialize()
throws StoreException {
// Initialize this Service
if (DEBUG.messageEnabled()) {
DEBUG.message("Initializing Configuration for the OpenAM Session Repository using Implementation Class: " +
CTSPersistentStore.class.getSimpleName());
}
// *******************************
// Set up Shutdown Thread Hook.
public void run() {
}
});
// **********************************************************************************************
// Obtain our Directory Connection and ensure we can access our
// Internal Directory Connection or use an External Source as
// per configuration.
//
// ******************************************
// Start our AM Repository Store Thread.
storeThread.start();
// Finish Initialization
if (DEBUG.messageEnabled()) {
DEBUG.message("Successful Configuration Initialization for the OpenAM Session Repository using Implementation Class: " +
CTSPersistentStore.class.getSimpleName());
}
}
/**
* Perform Service Shutdown.
*/
public void shutdown() {
}
/**
* Internal Service Shutdown Process.
*/
protected static void internalShutdown() {
shutdown = true;
}
/**
* Service Thread Run Process Loop.
*/
@SuppressWarnings("SleepWhileInLoop")
public void run() {
synchronized (LOCK) {
while (!shutdown) {
try {
// Delete any expired Sessions up to now.
// Delete any expired SAML2 Artifacts
// Delete expired OAuth2 tokens
// Process any Deferred Operations
// Wait for next tick or interrupt.
} catch (InterruptedException ie) {
} catch (StoreException se) {
} catch (JsonResourceException e){
}
}
}
}
/**
* Default Service Method, used to satisfy GeneralTaskRunnable extending.
*
* @param obj
* @return
*/
return false;
}
/**
* Default Service Method, used to satisfy GeneralTaskRunnable extending.
*
* @param obj
* @return
*/
return false;
}
/**
* Default Service Method, used to satisfy GeneralTaskRunnable extending.
*
* @return
*/
public boolean isEmpty() {
return true;
}
/**
* Saves session state to the repository If it is a new session (version ==
* 0) it inserts new record(s) to the repository. For an existing session it
* updates repository record instead while checking that versions in the
* InternalSession and in the record match In case of version mismatch or
* missing record IllegalArgumentException will be thrown
*
* @param is reference to <code>InternalSession</code> object being saved.
* @throws Exception if anything goes wrong.
*/
return;
}
}
/**
* Private Helper Method to perform the InternalSession Save Immediately,
* without any queueing of request.
*
* @throws Exception
*/
try {
+ " is null, Unable to persist Session.");
return;
}
// Create a FAMRecord Object to wrap our Serialized Internal Session
// Construct the Entry's DN and Persist Record
writeImmediate(famRec, getFormattedString(SESSION_FAILOVER_HA_ELEMENT_DN_TEMPLATE, PKEY_NAMING_ATTR, famRec.getPrimaryKey()));
} catch (Exception e) {
}
}
/**
* Takes an AMRecord and writes this to the store
*
* @param amRootEntity The record object to store
* @throws com.iplanet.dpro.session.exceptions.StoreException
*
*/
if (amRootEntity == null) {
return;
}
// Construct our Entity's DN and Write this AM Root Entity Object now.
}
/**
* Takes an AMRecord and writes this to the store
*
* @param amRootEntity The record object to store
* @throws com.iplanet.dpro.session.exceptions.StoreException
*
*/
throws StoreException {
try {
// Assume we are Adding the Entry.
// Log Action
logAMRootEntity(amRootEntity, "CTSPersistenceStore.storeImmediate: \nBaseDN:[" + baseDN.toString() + "] ");
// Update / Modify existing Entry.
// Log Action
logAMRootEntity(amRootEntity, "CTSPersistenceStore.updateImmediate: \nBaseDN:[" + baseDN.toString() + "] ");
}
}
/**
* Perform a Store Immediate to the Directory, since our record does not
* exist per our up-stream caller.
*
* @param record
* @throws StoreException
*/
throws StoreException, EntryAlreadyExistsException {
return;
}
// Prepare to Marshal our AMRootEntity Object.
// Ensure our ObjectClass Attributes have been set per our Entity instance Type.
// Initialize the Attribute Set
// Obtain a Connection.
try {
// Iterate over and convert RawAttribute List to actual LDAPAttributes.
}
}
// Add the new Directory Entry.
if (DEBUG.messageEnabled()) {
}
} catch (LDAPException ldapException) {
// This usually indicates schema has not been applied to the Directory Information Base (DIB) Instance.
} else {
final LocalizableMessage message = DB_SVR_CRE_FAIL2.get(baseDN, Integer.toString(ldapException.getLDAPResultCode()));
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Perform an Update Immediate to the Directory, since our record does already
* exist per our up-stream caller.
*
* @param record
* @throws StoreException
*/
throws StoreException {
// Initialize.
try {
// Obtain a Connection.
// Convert our RawModification List to a LDAPModificationRequest.
} // End of Inner For Each Attribute ValuesIteration.
} // End of Inner For Each Attribute Iteration.
} // End of Inner For Each Modification Iteration.
// Now Perform the Modification of the Object.
if (DEBUG.messageEnabled()) {
}
} catch (LDAPException ldapException) {
// Not Found No Such Object
// This usually indicates schema has not been applied to the Directory Information Base (DIB) Instance.
} else {
// Other Issue Detected.
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Prepare the RAW LDAP Modifications List for Directory
* consumption.
*
* @param record
* @return List<RawModification>
* @throws StoreException
*/
throws StoreException {
}
return mods;
}
/**
* Deletes a record from the store.
*
* @param id The id of the record to delete from the store
* @throws com.iplanet.dpro.session.exceptions.StoreException
*
* @throws com.iplanet.dpro.session.exceptions.NotFoundException
*
*/
}
/**
* Deletes session record from the repository.
*
* @param sid session ID.
* @throws Exception if anything goes wrong.
*/
}
/**
* Private Helper method for Delete Immediately by Session ID.
*
* @param sid
* @throws Exception
*/
}
/**
* Private Helper method for Delete Immediately by Session ID.
*
* @param id
* @throws StoreException
*/
throws StoreException {
return;
}
// Initialize.
try {
// Obtain a Connection.
// Delete the Entry, our Entries are flat,
// so we have no children to contend with, if this
// changes however, this deletion will need to
// specify a control to delete child entries.
} catch (LDAPException ldapException) {
// Not Found No Such Object, simple Ignore a Not Found,
// as another OpenAM instance could have purged already and replicated
// the change across the OpenDJ Bus.
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Delete all Expired Sessions, within Default Limits.
*
* @throws Exception
*/
public void deleteExpired() throws Exception {
}
/**
* Delete all records in the store
* that have an expiry date older than the one specified.
*
* @param expirationDate The Calendar Entry depicting the time in which all existing Session
* objects should be deleted if less than this time.
* @throws StoreException
*/
/**
* Set up our Duration Object, should be performed
* using AspectJ and a Pointcut.
*/
// Check and formulate the Date String for Query.
if (expirationDate == null) {
}
// Formulate the Date String.
// Initialize.
int objectsDeleted = 0;
try {
// Initialize Filter.
if (DEBUG.messageEnabled()) {
+ formattedExpirationDate + "]");
}
// Obtain a Connection.
// Create our Search Constraints to limit number of expired sessions returned during this tick,
// otherwise we could stall this Service Background thread.
// Perform Search
// Anything Found?
return;
}
// Iterate over results and delete each entry.
while (searchResults.hasMoreElements()) {
continue;
}
// Process the Entry to perform a delete Against it.
continue;
}
// Obtain the primary Key and perform the Deletion.
} // End of while loop.
} catch (LDAPException ldapException) {
// Determine specific actions per LDAP Return Code.
// Not Found No Such Object, Nothing to Delete?
// Possibly the Expired Session has been already deleted
// by a peer OpenAM Instance.
return;
// Our Size Limit was Exceed, so there are more results, but we have consumed
// our established limit. @see LDAPSearchConstraints setting above.
// Let our Next Pass obtain another chuck to delete.
return;
} else {
// Some other type of Error has occurred...
final LocalizableMessage message = DB_ENT_ACC_FAIL.get(SESSION_FAILOVER_HA_BASE_DN, ldapException.errorCodeToString());
}
// Are we in Shutdown Mode?
if (!shutdown) {
} else {
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
timeDuration.stop();
if (objectsDeleted > 0) {
DEBUG.error(messageTag + "Number of Expired Sessions Deleted:[" + objectsDeleted + "], Duration:[" + timeDuration.getDurationToString() + "]");
}
}
}
/**
* Retrieve a persisted Internal Session.
*
* @param sid session ID
* @return InternalSession
* @throws Exception
*/
try {
// Read the Session Information from the Store.
// if we have a not found, simply return null,
// this can occur the first time a new session
// is created and we try to obtain the ID from the
// store.
if ((amRootEntity != null) &&
// Log Action
}
// Return unMarshaled Internal Session or null.
return is;
} catch (NotFoundException nfe) {
// Not performing any message generation here will limit the verbosity
// as during session recovery, multiple attempts
// are made to check for session existence and during high session creation,
// logs can easily spill and cause a performance degradation.
// Simply return null as upstream will handle that condition.
return null;
} catch (Exception e) {
// Issue other than a Not Found Condition.
return null;
}
}
/**
* Returns the expiration information of all sessions belonging to a user.
* The returned value will be a Map (sid->expiration_time).
*
* @param uuid User's universal unique ID.
* @return Map of all Session for the user
* @throws Exception if there is any problem with accessing the session
* repository.
*/
try {
return amRecord.getExtraStringAttributes();
}
return null;
} catch (Exception e) {
throw new SessionException(e);
}
}
/**
* Read the Persisted Session Record from the Store.
*
* @param id The primary key of the record to find
* @return
* @throws NotFoundException
* @throws StoreException
*/
throws NotFoundException, StoreException {
return null;
}
// Establish our DN
// Initialize LDAP Objects
try {
// Obtain a Connection.
// Anything Found?
return null;
}
// UnMarshal LDAP Entry to a Map.
// UnMarshal
// Log Action
// Return UnMarshaled Object
return dataEntry.getAMRecord();
} catch (LDAPException ldapException) {
// Not Found, No Such Object
// This can be due to the session has expired and removed from the store.
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Read with Security Key.
*
* @param id The secondary key on which to search the store
* @return
* @throws StoreException
* @throws NotFoundException
*/
throws StoreException, NotFoundException {
return null;
}
if (DEBUG.messageEnabled()) {
}
// Initialize LDAP Objects
try {
// Obtain a Connection.
// Create our Search Constraints with no return limits.
// Perform the Search.
// Anything Found?
return null;
}
// UnMarshal LDAP Entry to a Map, only pull in a Single Entry.
// UnMarshal
// Log Action
// Return UnMarshaled Object(s)
}
}
// Show Success
if (DEBUG.messageEnabled()) {
}
// return result
return result;
} catch (LDAPException ldapException) {
// Not Found No Such Object
// This can be due to the session has expired and removed from the store.
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Get the number of Session Objects per our secondary key which is the
* DN Owner of the Session Objects.
*
* @param id
* @return Map<String, Long>
* @throws StoreException
*/
throws StoreException {
return null;
}
// Initialize LDAP Objects
try {
// Create Search Filter for our Secondary Key.
// Obtain a Connection.
// Create our Search Constraints with no return limits.
// Perform the Search.
// Anything Found?
return null;
}
// Process our Results.
while (searchResults.hasMoreElements()) {
continue;
}
// Process the Entries Attribute Set.
// Convert LDAP attributes to a simple Map.
// Get the AuxData.
key = v;
}
}
// Get our Expiration Date.
}
}
}
// Return our Results.
if (DEBUG.messageEnabled()) {
}
return result;
} catch (LDAPException ldapException) {
return null;
} else {
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Get DB Statistics
*
* @return
*/
public DBStatistics getDBStatistics() {
// TODO Build out proper Statistics.
return stats;
}
/**
* Return Service Run Period.
*
* @return long current run period.
*/
public long getRunPeriod() {
return runPeriod;
}
// ***************************************************************************************************
//
// AMTokenSAML2Repository Implementation Methods.
// These methods are called directly from the CTSPersistentSAML2Store, if that is the configured and
// desired implementation.
//
// ***************************************************************************************************
/**
* Retrieves existing SAML2 object from persistent Repository.
*
* @param samlKey primary key
* @return SAML2 object, if failed, return null.
*/
// Initialize.
// Arguments Valid?
DEBUG.error(messageTag + "Unable to Retrieve SAML2 Token Object, as Primary SAML2 Key was not provided!");
return null;
}
// Establish our DN
// Initialize LDAP Objects
try {
// Obtain a Connection.
// Anything Found?
return null;
}
// UnMarshal LDAP Entry to a Map.
// UnMarshal
// Log Action
// Return UnMarshaled Object
return dataEntry.getAMRecord();
} catch (LDAPException ldapException) {
// Not Found, No Such Object
// This can be due to the session has expired and removed from the store.
return null;
}
return null;
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Retrives a list of existing SAML2 object from persistent Repository with Secondary Key.
*
* @param secKey Secondary Key
* @return SAML2 object, if failed, return null.
*/
// Initialize.
// Arguments Valid?
DEBUG.error(messageTag + "Unable to Retrieve SAML2 Token Object, as Secondary SAML2 Key was not provided!");
return null;
}
if (DEBUG.messageEnabled()) {
}
// Initialize LDAP Objects
try {
// Obtain a Connection.
// Create our Search Constraints with no return limits.
// Perform the Search.
// Anything Found?
return null;
}
// UnMarshal LDAP Entry to a Map, only pull in a Single Entry.
// UnMarshal
AMRecordDataEntry dataEntry = new AMRecordDataEntry(filter.toString(), AMRecord.READ, attributeMapResults);
// Log Action
// return result
return results;
} catch (LDAPException ldapException) {
// Not Found No Such Object
// This can be due to the session has expired and removed from the store.
return null;
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Saves SAML2 Token and Marshals SAML2 Object into the SAML2 Repository, for subsequent use by the owner.
*
* @param samlKey primary key
* @param samlObj saml object such as Response, IDPSession
* @param expirationTime expiration time
* @param secKey Secondary Key
*/
// Initialize.
// Arguments Valid?
DEBUG.error(messageTag + "Unable to Persist SAML2 Token Object, as Primary SAML2 Key was not provided!");
return;
DEBUG.error(messageTag + "Unable to Persist SAML2 Token Object, as Secondary SAML2 Key was not provided!");
return;
return;
}
// Marshal our Object and establish a FAMRecord for this Token Instance.
try {
// Create a FAMRecord Object to wrap our SAML2 Object.
// Construct the Entry's DN and Persist Record
writeImmediate(famRec, getFormattedString(TOKEN_SAML2_HA_ELEMENT_DN_TEMPLATE, PKEY_NAMING_ATTR, famRec.getPrimaryKey()));
} catch (Exception e) {
}
}
/**
* Deletes the SAML2 object by given primary key from the repository
*
* @param samlKey primary key
*/
// Arguments Valid?
DEBUG.error(messageTag + "Unable to Delete SAML2 Token Object, as Primary SAML2 Key was not provided!");
return;
}
// Initialize.
try {
// Obtain a Connection.
// Delete the Entry, our Entries are flat,
// so we have no children to contend with, if this
// changes however, this deletion will need to
// specify a control to delete child entries.
} catch (LDAPException ldapException) {
// Not Found No Such Object, simple Ignore a Not Found,
// as another OpenAM instance could have purged already and replicated
// the change across the OpenDJ Bus.
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Deletes expired SAML2 object from the repository
*/
public void deleteExpiredSAML2Tokens() throws StoreException {
// Initialize.
/**
* Set up our Duration Object, should be performed
* using AspectJ and a Pointcut.
*/
// Formulate the Date String.
// Initialize.
int objectsDeleted = 0;
try {
// Initialize Filter.
String filter = getFormattedString(TOKEN_EXPIRATION_FILTER_TEMPLATE, FORMATTED_EXPIRATION_DATE_NAME, formattedExpirationDate);
if (DEBUG.messageEnabled()) {
+ formattedExpirationDate + "]");
}
// Obtain a Connection.
// Create our Search Constraints to limit number of expired sessions returned during this tick,
// otherwise we could stall this Service Background thread.
// Perform Search
// Anything Found?
return;
}
// Iterate over results and delete each entry.
while (searchResults.hasMoreElements()) {
continue;
}
// Process the Entry to perform a delete Against it.
continue;
}
// Obtain the primary Key and perform the Deletion.
} // End of while loop.
} catch (LDAPException ldapException) {
// Determine specific actions per LDAP Return Code.
// Not Found No Such Object, Nothing to Delete?
// Possibly the Expired Session has been already deleted
// by a peer OpenAM Instance.
return;
// Our Size Limit was Exceed, so there are more results, but we have consumed
// our established limit. @see LDAPSearchConstraints setting above.
// Let our Next Pass obtain another chuck to delete.
return;
} else {
// Some other type of Error has occurred...
final LocalizableMessage message = DB_ENT_ACC_FAIL.get(SAML2_HA_BASE_DN, ldapException.errorCodeToString());
}
// Are we in Shutdown Mode?
if (!shutdown) {
} else {
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
timeDuration.stop();
if (objectsDeleted > 0) {
DEBUG.error(messageTag + "Number of Expired SAML2 Artifacts Deleted:[" + objectsDeleted + "], Duration:[" + timeDuration.getDurationToString() + "]");
}
}
}
// ***************************************************************************************************
//
// Private Helper Methods.
//
// ***************************************************************************************************
/**
* Process any and all deferred AM Session Repository Operations.
*/
private synchronized void processDeferredAMSessionRepositoryOperations() {
int count = 0;
count++;
// TODO -- Build out Implementation to invoke Session Repository Events.
// TODO -- Add Statistics Gathering for Post to Admin Statistics View.
// Place Entry in Collection to be removed from Queue.
}
// Remove all entries processed in the Queue.
if (count > 0) {
}
}
/**
* Logging Helper Method.
*
* @param amRootEntity
* @param message
*/
// Set to Message to Error to see messages.
if (DEBUG.messageEnabled()) {
"\n IS:[" + (
"\n Data:[" + (
"\nAuxData:[" + (
);
}
}
/**
* Return current Time in Seconds.
*
* @return long Time in Seconds.
*/
private static long nowInSeconds() {
}
/**
* Return specified Milliseconds in a Date Object.
*
* @param milliseconds
* @return Date
*/
}
/**
* Prepare our BackEnd Persistence Store.
*
* @throws StoreException - Exception thrown if Error condition exists.
*/
private synchronized static void prepareCTSPersistenceStore() throws StoreException {
DEBUG.message(messageTag + "Attempting to Prepare BackEnd Persistence Store for Session Services.");
try {
if (CTSDataLayer == null) {
throw new StoreException("Unable to obtain BackEnd Persistence Store for Session Services.");
}
} catch (Exception e) {
throw new StoreException(e);
}
// Now Exercise and Validate the
// LDAP Connection from the Pool and perform a Read of our DIT Container to verify setup.
if (!validateCTSPersistenceStore()) {
"Please Verify DIT Structure in OpenAM Configuration Directory.";
}
// Show Informational Message.
if (DEBUG.messageEnabled()) {
DEBUG.message(messageTag + "Successfully Prepared BackEnd Persistence Store for Session Services.");
}
}
/**
* Private Common Helper Method to Obtain an LDAP Connection
* from the SMDataLayer Pool.
*
* @return LDAPConnection - Obtained Directory Connection from Pool.
* @throws StoreException
*/
if (ldapConnection == null) {
throw new StoreException("CTSPersistenceStore.prepareCTSPersistenceStore: Unable to Obtain Directory Connection!");
}
// Return Obtain Connection from Pool.
return ldapConnection;
}
/**
* Private Helper Method to perform Validation of our LDAP Connection and
* the existence of our DIT hierarchy which this component requires.
*
* @return boolean - indicates if validation was successful or not.
* @throws StoreException - Exception thrown if Error condition exists.
*/
private static boolean validateCTSPersistenceStore() throws StoreException {
// Iterate over our Token DIT Structure to Verify.
Map<String, Boolean> validationResultMap = new HashMap<String, Boolean>(containersToBeValidated.length);
}
// Now Iterate over the Validation Result Map to supply information, especially if we have
// detected something missing...
int validatedSuccessfully=0;
} else {
}
} // End of KeySet for each loop...
// Determine if we are good to go or not....
}
/**
* Private Helper method, Does DN Exist?
*
* @param dn - To be Check for Existence.
* @return boolean - indicator, "True" if DN has been Found, otherwise "False".
*/
try {
// Obtain a Connection.
// Perform the Search.
LDAPv2.SCOPE_BASE, ANY_OBJECTCLASS_FILTER, returnAttrs_DN_ONLY_ARRAY, false, new LDAPSearchConstraints());
return false;
}
return true;
} catch (LDAPException ldapException) {
return false;
}
return false;
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* Private helper method to properly format the Expiration Date
* for a proper LDAP Date Attribute Query.
*
* @param expirationDate
* @return String - representing the Formatted Date String for Query.
*/
}
/**
* Simple Helper Method to convert a Time represented as a Long in
* Milliseconds to a Calendar object.
*
* @param expirationDate
* @return Calendar Object set to Expiration Date.
*/
return expirationDateOnCalendar;
}
/**
* Helper method to correctly format a String with a name,value pair.
* This uses the include Open Source @see MapFormat Source.
*
* @param template
* @param name
* @param value
* @return String of Formatted Template
*/
}
// ***************************************************************************************************
//
// OAuth2TokenRepository Implementation Methods.
//
// ***************************************************************************************************
/**
* {@inheritDoc}
*/
return null;
}
String dn = getFormattedString(TOKEN_OAUTH2_HA_ELEMENT_DN_TEMPLATE, OAUTH2_KEY_NAME, token.getDN());
// Obtain a Connection.
try {
// Iterate over and convert RawAttribute List to actual LDAPAttributes.
}
}
// Add the new Directory Entry.
if (DEBUG.messageEnabled()) {
}
} catch (LDAPException ldapException) {
// This usually indicates schema has not been applied to the Directory Information Base (DIB) Instance.
} else {
final LocalizableMessage message = DB_SVR_CRE_FAIL2.get(dn, Integer.toString(ldapException.getLDAPResultCode()));
throw new JsonResourceException(JsonResourceException.INTERNAL_ERROR, messageTag + message.toString(), ldapException);
}
} catch(StoreException e){
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
return null;
}
/**
* {@inheritDoc}
*/
return null;
}
// Establish our DN
// Initialize LDAP Objects
try {
// Obtain a Connection.
LDAPv2.SCOPE_BASE, ANY_OBJECTCLASS_FILTER, returnAttrs_OAuth2_ARRAY, false, new LDAPSearchConstraints());
// Anything Found?
return null;
}
// UnMarshal LDAP Entry to a Map.
// UnMarshal
// Log Action
// Return UnMarshaled Object
} catch (LDAPException ldapException) {
// Not Found, No Such Object
// This can be due to the session has expired and removed from the store.
}
throw new JsonResourceException(JsonResourceException.INTERNAL_ERROR, messageTag + message.toString(), ldapException);
} catch(StoreException e){
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* {@inheritDoc}
*/
return oauth2Create(request);
}
/**
* {@inheritDoc}
*/
return null;
}
try {
// Obtain a Connection.
// Delete the Entry, our Entries are flat,
// so we have no children to contend with, if this
// changes however, this deletion will need to
// specify a control to delete child entries.
} catch (LDAPException ldapException) {
// Not Found No Such Object, simple Ignore a Not Found,
// as another OpenAM instance could have purged already and replicated
// the change across the OpenDJ Bus.
}
} catch(StoreException e){
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
/**
* {@inheritDoc}
*/
return null;
}
Map<String, Object> filters = (Map<String, Object>)request.get("params").required().asMap().get("filter");
} else {
filter = new StringBuilder();
}
}
int objectsDeleted = 0;
try {
// Obtain a Connection.
// Create our Search Constraints to limit number of expired sessions returned during this tick,
// otherwise we could stall this Service Background thread.
// Perform Search
// Anything Found?
}
// Iterate over results and delete each entry.
while (searchResults.hasMoreElements()) {
continue;
}
} // End of while loop.
} catch (LDAPException ldapException) {
// Determine specific actions per LDAP Return Code.
// Not Found No Such Object, Nothing to Delete?
// Possibly the Expired Session has been already deleted
// by a peer OpenAM Instance.
// Our Size Limit was Exceed, so there are more results, but we have consumed
// our established limit. @see LDAPSearchConstraints setting above.
// Let our Next Pass obtain another chuck to delete.
} else {
// Some other type of Error has occurred...
final LocalizableMessage message = DB_ENT_ACC_FAIL.get(OAUTH2_HA_BASE_DN, ldapException.errorCodeToString());
throw new JsonResourceException(JsonResourceException.INTERNAL_ERROR, messageTag + message.toString(), ldapException);
}
// Are we in Shutdown Mode?
if (!shutdown) {
} else {
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
}
public void oauth2DeleteExpired() throws JsonResourceException{
filter.append(EXPDATE_FILTER_PRE_OAUTH).append(System.currentTimeMillis()).append(EXPDATE_FILTER_POST_OAUTH);
int objectsDeleted = 0;
try {
// Obtain a Connection.
// Create our Search Constraints to limit number of expired sessions returned during this tick,
// otherwise we could stall this Service Background thread.
// Perform Search
// Anything Found?
return;
}
// Iterate over results and delete each entry.
while (searchResults.hasMoreElements()) {
continue;
}
// Process the Entry to perform a delete Against it.
continue;
}
// Obtain the primary Key and perform the Deletion.
} // End of while loop.
} catch (LDAPException ldapException) {
// Determine specific actions per LDAP Return Code.
// Not Found No Such Object, Nothing to Delete?
// Possibly the Expired Session has been already deleted
// by a peer OpenAM Instance.
return;
// Our Size Limit was Exceed, so there are more results, but we have consumed
// our established limit. @see LDAPSearchConstraints setting above.
// Let our Next Pass obtain another chuck to delete.
return;
} else {
// Some other type of Error has occurred...
final LocalizableMessage message = DB_ENT_ACC_FAIL.get(OAUTH2_HA_BASE_DN, ldapException.errorCodeToString());
throw new JsonResourceException(JsonResourceException.INTERNAL_ERROR, messageTag + message.toString(), ldapException);
}
// Are we in Shutdown Mode?
if (!shutdown) {
} else {
}
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
if (objectsDeleted > 0) {
//if (DEBUG.messageEnabled()) { // TODO -- Uncomment to limit verbosity.
//}
}
}
return;
}
/**
* {@inheritDoc}
*/
return;
}
// Initialize.
try {
// Obtain a Connection.
// Delete the Entry, our Entries are flat,
// so we have no children to contend with, if this
// changes however, this deletion will need to
// specify a control to delete child entries.
} catch (LDAPException ldapException) {
// Not Found No Such Object, simple Ignore a Not Found,
// as another OpenAM instance could have purged already and replicated
// the change across the OpenDJ Bus.
}
} catch(StoreException e){
} finally {
if (ldapConnection != null) {
// Release the Connection.
}
}
return;
}
/**
* Private helper method to Add Underscores to named elements whose name have spaces.
*
* @param results<String, Set<String>>
*/
//need to add the _ back into expiry_time, client_id, redirect_uri
//and remove objectClass(by product of LDAP)
}
}
}
}