/*
* 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
* https://opensso.dev.java.net/public/CDDLv1.0.html or
* opensso/legal/CDDLv1.0.txt
* 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: IdRepoListener.java,v 1.16 2009/01/28 05:34:59 ww203982 Exp $
*
* Portions Copyrighted 2011-2016 ForgeRock AS.
*/
package com.sun.identity.idm;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.forgerock.openam.ldap.LDAPUtils;
import org.forgerock.openam.ldap.PersistentSearchChangeType;
import org.forgerock.openam.utils.StringUtils;
import com.iplanet.sso.SSOException;
import com.iplanet.sso.SSOToken;
import com.sun.identity.security.AdminTokenAction;
import com.sun.identity.shared.debug.Debug;
import com.sun.identity.shared.jaxrpc.SOAPClient;
import com.sun.identity.sm.SMSException;
import com.sun.identity.sm.ServiceConfig;
import com.sun.identity.sm.ServiceConfigManager;
import com.sun.identity.sm.ServiceManager;
/**
* Provides methods that can be called by IdRepo plugins to notify change
* events. Used to update cache and also to send notifications to registered
* listeners. Each IdRepo plugin will be given a unique instance of this object.
*
* Additionally, this class maintains the configuration data for the IdRepo
* plugin and also to store the SMS Service attributes for the organization.
*
* @supported.all.api
*/
public final class IdRepoListener {
// Configuration data for the IdRepo plugin
// Must have "realm" key to correctly send the notifications to clients
private Map configMap = null;
// Listener registed by JAXRPC Impl to send notifications
private static IdEventListener remoteListener = null;
private static Debug debug = Debug.getInstance("idrepoListener");
// To serialize and deserialize configMap
protected static SOAPClient sclient;
// Configured Identity Types
private static IdType[] defaultIdTypes;
// Flags to check if caching is enabled and to clear them
private static boolean cacheChecked;
private static boolean cacheEnabled;
private static IdServices idServices;
/*
* (non-Javadoc)
*
* @see com.iplanet.am.sdk.AMObjectListener#allObjectsChanged()
*/
public void allObjectsChanged() {
if (debug.messageEnabled()) {
debug.message("IdRepoListener: allObjectsChanged Called!");
}
// Check if caching is enabled
if (!cacheChecked) {
idServices = IdServicesFactory.getDataStoreServices();
if (idServices instanceof IdCachedServices) {
// If Caching was enabled - then clear the cache!!
cacheEnabled = true;
}
cacheChecked = true;
}
if (cacheEnabled) {
// If Caching was enabled - then clear the cache!!
((IdCachedServices) idServices).clearCache();
}
// Get the list of listeners setup with idRepo
String org = (String) configMap.get("realm");
ArrayList list = (ArrayList) AMIdentityRepository.listeners.get(org);
// Update any listeners registered with IdRepo
if (list != null) {
int size = list.size();
for (int j = 0; j < size; j++) {
IdEventListener l = (IdEventListener) list.get(j);
l.allIdentitiesChanged();
}
}
if (remoteListener != null) {
remoteListener.allIdentitiesChanged();
}
}
/**
*
* This method has been deprecated as of OpenSSO Enterprise 8.0.
*
* @param name name of the identity that changed
* @param type change type i.e., add, delete, modify, etc.
* @param cMap configuration map that contains realm and plugin-name
*
* @deprecated As of Sun Java System Access Manager 7.1.
*/
public void objectChanged(String name, int type, Map cMap) {
objectChanged(name, null, type, cMap);
}
/**
* Notification mechanism for IdRepo plugins to specify the identiy name
* and identity type that has been changed.
*
* @param name name of the identity that changed
* @param idType IdType i.e., user, group, etc.
* @param changeType change type i.e., add, delete, modify, etc.
* @param cMap configuration map that contains realm and plugin-name
*/
public void objectChanged(String name, IdType idType, int changeType,
Map cMap) {
if (debug.messageEnabled()) {
debug.message("objectChanged called with IdType= name: " + name +
" IdType: " + idType + " ChangeType: " + changeType +
"\nConfigmap = " + cMap);
}
// Get the list of listeners setup with idRepo
String org = (String) configMap.get("realm");
List<IdEventListener> list = (List<IdEventListener>) AMIdentityRepository.listeners.get(org);
list = list == null ? new ArrayList<IdEventListener>() : new ArrayList<>(list);
if (remoteListener != null) {
list.add(remoteListener);
}
// Check if caching is enabled
if (!cacheChecked) {
idServices = IdServicesFactory.getDataStoreServices();
if (idServices instanceof IdCachedServices) {
// If Caching was enabled - then clear the cache!!
cacheEnabled = true;
}
cacheChecked = true;
}
if (StringUtils.isNotEmpty(name)) {
String[] changed = getChangedIds(name, idType, cMap);
for (int i = 0; i < changed.length; i++) {
if (cacheEnabled) {
((IdCachedServices) idServices).dirtyCache(changed[i],
changeType, false, false, Collections.EMPTY_SET);
}
for (IdEventListener l : list) {
// Update any listeners registered with IdRepo
if(changeType == OBJECT_CHANGED || changeType == OBJECT_ADDED) {
l.identityChanged(changed[i]);
} else if (changeType == OBJECT_REMOVED) {
l.identityDeleted(changed[i]);
} else if (changeType == OBJECT_RENAMED) {
l.identityRenamed(changed[i]);
}
}
}
} else if (debug.warningEnabled()) {
debug.warning("objectChanged called with an empty name");
}
}
public static void addRemoteListener(IdEventListener l) {
remoteListener = l;
}
/*
* Returns the configurations for the IdRepo plugins
*/
public Map getConfigMap() {
return configMap;
}
/*
* Maintains the configurations for the IdRepo plugins
*/
public void setConfigMap(Map cMap) {
configMap = cMap;
}
/**
* Stores service's dynamic attributes within the IdRepo plugin
* configuration. In the current implementation changes to dynamic
* attributes to LDAPv3Repo restart the plugin, since it triggers
* a configuration change notification.
*
* @param sName service name for which attributes are being set
* @param attrs service synamic attributes
* @throws com.sun.identity.idm.IdRepoException
*/
public void setServiceAttributes(String sName, Map attrs)
throws IdRepoException {
String realm = (String) configMap.get("realm");
String pluginName = (String) configMap.get("plugin-name");
if (realm == null || pluginName == null) {
AMIdentityRepository.debug.error(
"IdRepoListener.setServiveAttribute: realm or plugin name"
+ " is null");
Object[] args = { sName, IdType.ROLE.getName() };
throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_ALREADY_ASSIGNED, args);
}
try {
SSOToken token = (SSOToken) AccessController
.doPrivileged(AdminTokenAction.getInstance());
ServiceConfigManager scm = new ServiceConfigManager(token,
IdConstants.REPO_SERVICE, "1.0");
ServiceConfig sc = scm.getOrganizationConfig(realm, null);
if (sc == null) {
return;
}
ServiceConfig subConfig = sc.getSubConfig(pluginName);
if (subConfig == null) {
return;
}
Map attributes = subConfig.getAttributes();
Set vals = (Set) attributes.get(IdConstants.SERVICE_ATTRS);
if (vals == null || vals == Collections.EMPTY_SET) {
vals = new HashSet();
}
if (sclient == null) {
sclient = new SOAPClient("dummy");
}
String mapStr = sclient.encodeMap("result", attrs);
vals = new HashSet();
vals.add(mapStr);
attributes.put(IdConstants.SERVICE_ATTRS, vals);
subConfig.setAttributes(attributes);
} catch (SMSException smse) {
AMIdentityRepository.debug.error(
"IdRepoListener: Unable to set service attributes", smse);
Object[] args = { sName, IdType.ROLE.getName() };
throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_ALREADY_ASSIGNED, args);
} catch (SSOException ssoe) {
AMIdentityRepository.debug.error(
"IdRepoListener: Unable to set service attributes", ssoe);
Object[] args = { sName, IdType.ROLE.getName() };
throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_ALREADY_ASSIGNED, args);
}
}
private String[] getChangedIds(String name, IdType type, Map cMap) {
int size = IdUtils.supportedTypes.size();
// If configMap is null, then this is a "remote" cache update
if ((cMap == null) || cMap.isEmpty()) {
String ct[] = new String[1];
if (LDAPUtils.isDN(name)) {
// Name should be the universal id
ct[0] = name;
} else {
if (type == null) {
// Default to user
type = IdType.USER;
}
ct[0] = "id=" + name + ",ou=" + type.getName() + "," +
ServiceManager.getBaseDN();
}
return ct;
}
String changedTypes[] = null;
IdType types[] = null;
if (type == null) {
changedTypes = new String[size];
if (defaultIdTypes == null) {
Set idtypes = IdUtils.supportedTypes;
defaultIdTypes = new IdType[idtypes.size()];
defaultIdTypes = (IdType[]) idtypes.toArray(defaultIdTypes);
}
types = defaultIdTypes;
} else {
changedTypes = new String[1];
types = new IdType[1];
types[0] = type;
}
String realm = (String) cMap.get("realm");
String Amsdk = (String) cMap.get("amsdk");
boolean isAmsdk = Amsdk != null;
for (int i = 0; i < types.length; i++) {
IdType itype = types[i];
String n = LDAPUtils.isDN(name) ? LDAPUtils.rdnValueFromDn(name) : name;
String id = "id=" + n + ",ou=" + itype.getName() + "," + realm;
if (isAmsdk) {
id = id + ",amsdkdn=" + name;
}
changedTypes[i] = id;
}
return changedTypes;
}
// Constants for change type recevied from the IdRepo plugins
/**
* Represents an object addition event type.
*/
public static final int OBJECT_ADDED = PersistentSearchChangeType.ADDED;
/**
* Represents an object change event type.
*/
public static final int OBJECT_CHANGED = PersistentSearchChangeType.MODIFIED;
/**
* Represents an object removal event type.
*/
public static final int OBJECT_REMOVED = PersistentSearchChangeType.REMOVED;
/**
* Represents an object renaming event type.
*/
public static final int OBJECT_RENAMED = PersistentSearchChangeType.RENAMED;
}