SMSLdapObject.java revision 907b0bec113a7d4590896a40a0ce930096b8791e
/**
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2005 Sun Microsystems 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
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/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 Copyrighted [year] [name of copyright owner]"
*
* $Id: SMSLdapObject.java,v 1.27 2009/11/20 23:52:56 ww203982 Exp $
*
*/
/*
* Portions Copyrighted [2011-2013] [ForgeRock AS]
*/
/**
* This object represents an LDAP entry in the directory server. The UMS have an
* equivalent class called PersistentObject. The SMS could not integrate with
* PersistentObject, because of the its dependecy on the Session object. This
* would mean that, to instantiate an PersistentObject inside SMS, we need to
* create an UMS instance, which would be having directory parameters of SMS.
* <p>
* This class is used both to read and write information into the directory
* server. The appropriate constructors discusses it is done.
* <p>
* There can be only three types of SMS entries in the directory (i) entry with
* organizationUnit object class (attribute: ou) (ii) entry with sunService
* object class (attributes: ou, labeledURI, sunServiceSchema, sunPluginSchema,
* and sunKeyValue (sunXMLKeyValue, in the future) (iii) entry with
* sunServiceComponent object class (attributes: ou, sunServiceID,
* sunSMSPriority, sunKeyValue. All the schema, configuration and plugin entries
* will be stored using the above entries.
*/
// LDAP specific & retry paramters
static SMDataLayer smdlayer;
static int connNumRetry = 3;
static int connRetryInterval = 1000;
static int entriesPresentCacheSize = 1000;
static boolean initializedNotification;
new LinkedHashSet());
new LinkedHashSet());
// Other parameters
static ResourceBundle bundle;
boolean initialized;
static boolean enableProxy;
// Admin SSOToken
static Principal adminPrincipal;
/**
* Public constructor for SMSLdapObject
*/
public SMSLdapObject() throws SMSException {
// Initialized (should be called only once by SMSEntry)
initialize();
}
/**
* Synchronized initialized method
*/
private synchronized void initialize() throws SMSException {
if (initialized) {
return;
}
// Obtain the I18N resource bundle & Debug
if (debug.messageEnabled()) {
}
try {
if (enableProxy) {
// Initialize the principal, used only with AMSDK
// for proxy connections
// Get UMS datalayer
if (debug.messageEnabled()) {
+ "obtained.");
}
} else {
// Get SM datalayer
if (debug.messageEnabled()) {
+ "obtained.");
}
}
}
// Get connection retry parameters
// Need to check if the root nodes exists. If not, create them
if (!entryExists(serviceDN)) {
}
} catch (Exception e) {
// Unable to initialize (trouble!!)
}
initialized = true;
}
private void initializeNotification() {
if (!initializedNotification) {
// If cache is enabled, register for notification to maintian
// internal cache of entriesPresent
if (SMSNotificationManager.isCacheEnabled()) {
.registerCallbackHandler(this);
}
initializedNotification = true;
}
}
/**
* Reads in the object from persistent store, assuming that the guid and the
* SSOToken are valid
*/
// This must not be possible return an exception.
}
"sms-INVALID_DN", args);
}
// Check if entry does not exist
if (SMSNotificationManager.isCacheEnabled() &&
if (debug.messageEnabled()) {
+ " (checked in cached)");
}
return (null);
}
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
int errorCode = 0;
try {
break;
} catch (LDAPException e) {
errorCode = e.getLDAPResultCode();
(retry == connNumRetry)
) {
// Add to not present Set
if (debug.messageEnabled()) {
"SMSLdapObject.read: entry not present:" + dn);
}
break;
} else {
if (debug.warningEnabled()) {
"Error in accessing entry DN: " + dn, e);
}
throw new SMSException(e, "sms-entry-cannot-access");
}
}
retry++;
try {
} catch (InterruptedException ex) {
// ignored
}
} finally {
}
}
}
if (debug.messageEnabled()) {
}
} else {
return null;
}
}
/**
* Create an entry in the directory
*/
throws SMSException, SSOException {
// Call the private method that takes the principal name
attrs);
// Update entryPresent cache
}
/**
* Create an entry in the directory using the principal name
*/
throws SMSException, SSOException {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
int errorCode = 0;
try {
conn = getConnection(p);
if (debug.messageEnabled()) {
"SMSLdapObject.create Successfully created entry: " +
dn);
}
break;
} catch (LDAPException e) {
errorCode = e.getLDAPResultCode();
(retry > 0)) {
// During install time and other times,
// this error gets throws due to unknown issue. Issue:
// Hence mask it.
"Already Exists Error for DN" + dn);
break;
}
(retry >= connNumRetry)
) {
"SMSLdapObject.create() Error in creating entry: " +
throw new SMSException(e, "sms-entry-cannot-create");
}
retry++;
try {
} catch (InterruptedException ex) {
//ignored
}
} finally {
}
}
}
}
/**
* Save the entry using the token provided. The principal provided will be
* used to get the proxy connection.
*/
throws SMSException, SSOException {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
int errorCode = 0;
try {
if (debug.messageEnabled()) {
"SMSLdapObject.modify(): Successfully modified entry: "
+ dn);
}
break;
} catch (LDAPException e) {
errorCode = e.getLDAPResultCode();
(retry == connNumRetry)
) {
"SMSLdapObject.modify(): Error in modifying entry: " +
dn + "\nBy Principal: " +
throw new SMSException(e, "sms-entry-cannot-modify");
}
retry++;
try {
} catch (InterruptedException ex) {
// ignored
}
} finally {
}
}
}
}
/**
* Delete the entry in the directory. This will delete sub-entries also!
*/
// Check if there are sub-entries, delete if present
if (debug.messageEnabled()) {
}
}
// Check if there are suborganizations, delete if present
// The recursive 'false' here has the scope SCOPE_ONE
// while searching for the suborgs.
// Loop through the suborg at the first level and if there
// is no next suborg, delete that.
if (debug.messageEnabled()) {
+ subOrg);
}
}
// Get LDAP connection
// Update entriesPresent cache
}
throws SMSException {
// Delete the entry
try {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
try {
conn = getConnection(p);
break;
} catch (LDAPException e) {
int errorCode = e.getLDAPResultCode();
|| retry == connNumRetry) {
throw e;
}
retry++;
try {
} catch (InterruptedException ex) {
}
}
}
} catch (LDAPException le) {
if (debug.warningEnabled()) {
}
} finally {
}
}
}
/**
* Returns the sub-entry names. Returns a set of RDNs that are sub-entries.
* The paramter <code>numOfEntries</code> identifies the number of entries
* to return, if <code>0</code> returns all the entries.
*/
throws SMSException, SSOException {
filter = "*";
}
if (debug.messageEnabled()) {
}
// Construct the filter
// This is a workaround for Issue 3823, where DS returns an
// empty set if restarted during OpenSSO operation
}
return (answer);
}
throws SMSException, SSOException {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
int errorCode = 0;
try {
// Get the sub entries
break;
} catch (LDAPException e) {
errorCode = e.getLDAPResultCode();
if (debug.messageEnabled()) {
"SMSLdapObject.subEntries(): entry not present:" +
dn);
}
break;
}
(retry >= connNumRetry)
) {
if (debug.warningEnabled()) {
"SMSLdapObject.subEntries: Unable to search for " +
"sub-entries: " + dn, e);
}
throw new SMSException(e, "sms-entry-cannot-search");
}
retry++;
try {
} catch (InterruptedException ex) {
// ignored
}
} finally {
}
}
}
// Construct the results and return
// Check if the results have to sorted
if (sortResults) {
}
while (results.hasMoreElements()) {
try {
// Check if the attribute starts with "ou="
// Workaround for 3823, where (objectClass=*) is used
continue;
}
} catch (LDAPException e) {
if (debug.warningEnabled()) {
"SMSLdapObject.subEntries: Error in obtaining " +
"sub-entries: " + dn, e);
}
throw new SMSException(e, "sms-entry-cannot-obtain");
}
}
if (debug.messageEnabled()) {
"SMSLdapObject.subEntries: Successfully obtained " +
"sub-entries for : " + dn);
}
}
return (answer);
}
/**
* Returns the sub-entry names. Returns a set of RDNs that are sub-entries.
* The paramter <code>numOfEntries</code> identifies the number of entries
* to return, if <code>0</code> returns all the entries.
*/
if (debug.messageEnabled()) {
}
// Construct the filter
return (answer);
}
return ("SMSLdapObject");
}
/**
* Releases a LDAPConnection.
*/
if (enableProxy) {
} else {
}
}
}
/**
* Releases a LDAPConnection.
*/
if (enableProxy) {
} else {
}
}
}
/**
* Returns a LDAPConnection for the given principal
*/
throws SMSException {
if (enableProxy) {
} else {
}
+ "server for the principal: " + p);
"sms-SERVER_DOWN"));
}
return (conn);
}
/**
* Returns LDAP entries that match the filter, using the start DN provided
* in method
*/
throws SSOException, SMSException {
}
boolean sortResults, boolean ascendingOrder
) throws SSOException, SMSException {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
int errorCode = 0;
try {
break;
} catch (LDAPException e) {
errorCode = e.getLDAPResultCode();
if (debug.warningEnabled()) {
numOfEntries + " exceeded");
}
break;
}
(retry >= connNumRetry)
) {
if (debug.warningEnabled()) {
"SMSLdapObject.search(): LDAP exception in search "
+ "for filter match: " + filter, e);
}
throw new SMSException(e, "sms-error-in-searching");
}
retry++;
try {
} catch (InterruptedException ex) {
//ignored
}
} finally {
}
}
}
return results;
}
/**
* Returns LDAP entries that match the filter, using the start DN provided
* in method
*/
if (debug.messageEnabled()) {
}
// Convert LDAP results to DNs
try {
} catch (LDAPException ldape) {
if (debug.warningEnabled()) {
numOfEntries + " exceeded");
}
break;
} else {
if (debug.warningEnabled()) {
"SMSLdapObject.search(): Error in searching for " +
}
}
}
}
if (debug.messageEnabled()) {
}
return answer;
}
private LDAPSearchResults searchObjects(
int numOfEntries,
int timeLimit,
boolean sortResults,
boolean ascendingOrder
) throws SSOException, SMSException {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
int errorCode = 0;
try {
break;
} catch (LDAPException e) {
errorCode = e.getLDAPResultCode();
(retry >= connNumRetry)
) {
if (debug.warningEnabled()) {
"SMSLdapObject.search(): LDAP exception in search "
+ "for filter match: " + filter, e);
}
throw new SMSException(e, "sms-error-in-searching");
}
retry++;
try {
} catch (InterruptedException ex) {
//ignored
}
} finally {
}
}
}
return results;
}
/**
* Checks if the provided DN exists. Used by PolicyManager.
*/
/**
* Checks if the provided DN exists. Used by PolicyManager.
*/
if (debug.messageEnabled()) {
}
// Check the caches
if (SMSNotificationManager.isCacheEnabled() &&
if (debug.messageEnabled()) {
}
return (true);
} else if (SMSNotificationManager.isCacheEnabled() &&
if (debug.messageEnabled()) {
+ "not-present-cache: " + dn);
}
return (false);
}
// Check if entry exisits
// Update the cache
synchronized (entriesPresent) {
}
}
}
} else if (SMSNotificationManager.isCacheEnabled()) {
synchronized (entriesNotPresent) {
}
}
}
}
return (entryExists);
}
/**
* Checks if the provided DN exists.
*/
boolean entryExists = false;
try {
// Use the Admin Principal to check if entry exists
OU_ATTR);
entryExists = true;
} catch (LDAPException e) {
if (debug.warningEnabled()) {
+ "does not exist");
}
} catch (SMSException ssoe) {
if (debug.warningEnabled()) {
}
} finally {
}
}
return (entryExists);
}
/**
* Registration of Notification Callbacks
*/
throws SMSException {
}
}
// Method to convert Map to LDAPAttributeSet
}
return (new LDAPAttributeSet(ldapAttrs));
}
// Method to covert JNDI ModificationItems to LDAPModificationSet
private static LDAPModificationSet copyModItemsToLDAPModSet(
try {
}
switch (mods[i].getModificationOp()) {
case DirContext.ADD_ATTRIBUTE:
break;
case DirContext.REPLACE_ATTRIBUTE:
break;
case DirContext.REMOVE_ATTRIBUTE:
break;
}
}
} catch (NamingException nne) {
throw (new SMSException(nne,
"sms-cannot-copy-fromModItemToModSet"));
}
return (modSet);
}
// Remove from entriesPresent Set
// Remove from entriesNotPresent set
}
}
public void allObjectsChanged() {
// Not clear why this class is implemeting the SMSObjectListener
// interface.
"SMSLDAPObject: got notifications, all objects changed");
}
}
/**
* Returns the suborganization names. Returns a set of RDNs that are
* suborganization name. The paramter <code>numOfEntries</code> identifies
* the number of entries to return, if <code>0</code> returns all the
* entries.
*/
if (debug.messageEnabled()) {
}
/*
* Instead of constructing the filter in the framework(SMSEntry.java),
* Construct the filter here in SMSLdapObject or the plugin
* implementation to support JDBC or other data store.
*/
+ "={0}))";
return (answer);
}
private Set searchSubOrganizationNames(
int numOfEntries,
boolean sortResults,
boolean ascendingOrder,
boolean recursive
) throws SMSException, SSOException {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
"SMSLdapObject.searchSubOrganizationNames() retry: " +
retry);
}
int errorCode = 0;
try {
// Get the suborganization names
break;
} catch (LDAPException e) {
errorCode = e.getLDAPResultCode();
(retry >= connNumRetry)
) {
if (debug.messageEnabled()) {
"SMSLdapObject.searchSubOrganizationNames(): " +
"suborg not present:" + dn);
}
break;
} else {
if (debug.warningEnabled()) {
"SMSLdapObject.searchSubOrganizationName(): " +
"Unable to search for suborganization names: "
+ dn, e);
}
throw new SMSException(e, "sms-suborg-cannot-search");
}
}
retry++;
try {
} catch (InterruptedException ex) {
// ignored
}
} finally {
}
}
}
// Check if the results have to be sorted
}
// Construct the results and return
try {
} catch (LDAPException e) {
if (debug.warningEnabled()) {
"SMSLdapObject.searchSubOrganizationName: " +
"Error in obtaining suborganization names: " + dn, e);
}
throw new SMSException(e, "sms-suborg-cannot-obtain");
}
}
if (debug.messageEnabled()) {
"Successfully obtained suborganization names for : " + dn);
"Successfully obtained suborganization names : " +
}
return (answer);
}
/**
* Returns the organization names. Returns a set of RDNs that are
* organization name. The paramter <code>numOfEntries</code> identifies
* the number of entries to return, if <code>0</code> returns all the
* entries.
*/
throws SMSException, SSOException {
if (debug.messageEnabled()) {
+ dn);
}
/*
* Instead of constructing the filter in the framework(SMSEntry.java),
* Construct the filter here in SMSLdapObject or the plugin
* implementation to support JDBC or other data store. To return
* organization names that match the given attribute name and values,
* only exact matching is supported, and if more than one value is
* provided the organization must have all these values for the
* attribute. Basically an AND is performed for attribute values for
* searching. The attributes can be under the service config as well
* under the Realm/Organization directly. For eg.,
* (|(&(objectclass=sunRealmService)(&
* (|(sunxmlkeyvalue=SERVICE_NAME-ATTR_NAME=VALUE1)
* (sunxmlkeyvalue=ATTR_NAME=VALUE1))
* (|(sunxmlkeyvalue=SERVICE_NAME-ATTR_NAME=VALUE2)
* (sunxmlkeyvalue=ATTR_NAME=VALUE2))(...))
* (&(objectclass=sunServiceComponent)(&
* (|(sunxmlkeyvalue=SERVICE_NAME-ATTR_NAME=VALUE1)
* (sunxmlkeyvalue=ATTR_NAME=VALUE1))
* (|(sunxmlkeyvalue=SERVICE_NAME-ATTR_NAME=VALUE2)
* (sunxmlkeyvalue=ATTR_NAME=VALUE2))(...))
*
*/
}
) {
// Include the OCs only for sunDS, not Active Directory.
//String FILTER_PATTERN_SEARCH_ORG = "(|(&(objectclass="
FILTER_PATTERN_SEARCH_ORG = "(|(&(objectclass="
}
if (debug.messageEnabled()) {
}
return (answer);
}
public void shutdown() {
}
// dlayer (from AMSDK) has dependecy on AMSDK
// and cannot be shutdown by SMS.
// Should be initialized by AMSDK
}
throws SMSException, SSOException {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
int errorCode = 0;
try {
// Get the organization names
break;
} catch (LDAPException e) {
errorCode = e.getLDAPResultCode();
(retry == connNumRetry)
) {
if (debug.messageEnabled()) {
"SMSLdapObject.getOrgNames(): org not present:"
+ dn);
}
break;
} else {
if (debug.warningEnabled()) {
"SMSLdapObject.getOrgNames: " +
"Unable to search for organization names: " +
dn, e);
}
throw new SMSException(e, "sms-org-cannot-search");
}
}
retry++;
try {
} catch (InterruptedException ex) {
// ignored
}
} finally {
}
}
}
// Check if the results have to be sorted
}
// Construct the results and return
try {
} catch (LDAPException e) {
if (debug.warningEnabled()) {
"Error in obtaining organization names: " + dn, e);
}
throw new SMSException(e, "sms-org-cannot-obtain");
}
}
if (debug.messageEnabled()) {
"Successfully obtained organization names for : " + dn);
"Successfully obtained organization names : " +
}
return (answer);
}
) {
}
}
return name;
}
/*
* If the datastore is Active Directory, convert
* ou=dc=samples^dc=com^^AgentLogging to
* ou=dc_samples^dc_com^^AgentLogging.
* Otherwise BAD_NAME error LDAPException code 34 will occur.
**/
) {
s = dns[i];
}
}
}
return dn;
}
}