001/* 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: IdRepoListener.java,v 1.16 2009/01/28 05:34:59 ww203982 Exp $ 026 * 027 * Portions Copyrighted 2011-2016 ForgeRock AS. 028 */ 029package com.sun.identity.idm; 030 031import java.security.AccessController; 032import java.util.ArrayList; 033import java.util.Collections; 034import java.util.HashSet; 035import java.util.List; 036import java.util.Map; 037import java.util.Set; 038 039import org.forgerock.openam.ldap.LDAPUtils; 040import org.forgerock.openam.ldap.PersistentSearchChangeType; 041import org.forgerock.openam.utils.StringUtils; 042 043import com.iplanet.sso.SSOException; 044import com.iplanet.sso.SSOToken; 045import com.sun.identity.security.AdminTokenAction; 046import com.sun.identity.shared.debug.Debug; 047import com.sun.identity.shared.jaxrpc.SOAPClient; 048import com.sun.identity.sm.SMSException; 049import com.sun.identity.sm.ServiceConfig; 050import com.sun.identity.sm.ServiceConfigManager; 051import com.sun.identity.sm.ServiceManager; 052 053/** 054 * Provides methods that can be called by IdRepo plugins to notify change 055 * events. Used to update cache and also to send notifications to registered 056 * listeners. Each IdRepo plugin will be given a unique instance of this object. 057 * 058 * Additionally, this class maintains the configuration data for the IdRepo 059 * plugin and also to store the SMS Service attributes for the organization. 060 * 061 * @supported.all.api 062 */ 063public final class IdRepoListener { 064 065 // Configuration data for the IdRepo plugin 066 // Must have "realm" key to correctly send the notifications to clients 067 private Map configMap = null; 068 069 // Listener registed by JAXRPC Impl to send notifications 070 private static IdEventListener remoteListener = null; 071 072 private static Debug debug = Debug.getInstance("idrepoListener"); 073 074 // To serialize and deserialize configMap 075 protected static SOAPClient sclient; 076 077 // Configured Identity Types 078 private static IdType[] defaultIdTypes; 079 080 // Flags to check if caching is enabled and to clear them 081 private static boolean cacheChecked; 082 private static boolean cacheEnabled; 083 private static IdServices idServices; 084 085 /* 086 * (non-Javadoc) 087 * 088 * @see com.iplanet.am.sdk.AMObjectListener#allObjectsChanged() 089 */ 090 public void allObjectsChanged() { 091 if (debug.messageEnabled()) { 092 debug.message("IdRepoListener: allObjectsChanged Called!"); 093 } 094 095 // Check if caching is enabled 096 if (!cacheChecked) { 097 idServices = IdServicesFactory.getDataStoreServices(); 098 if (idServices instanceof IdCachedServices) { 099 // If Caching was enabled - then clear the cache!! 100 cacheEnabled = true; 101 } 102 cacheChecked = true; 103 } 104 if (cacheEnabled) { 105 // If Caching was enabled - then clear the cache!! 106 ((IdCachedServices) idServices).clearCache(); 107 } 108 109 // Get the list of listeners setup with idRepo 110 String org = (String) configMap.get("realm"); 111 ArrayList list = (ArrayList) AMIdentityRepository.listeners.get(org); 112 // Update any listeners registered with IdRepo 113 if (list != null) { 114 int size = list.size(); 115 for (int j = 0; j < size; j++) { 116 IdEventListener l = (IdEventListener) list.get(j); 117 l.allIdentitiesChanged(); 118 } 119 } 120 if (remoteListener != null) { 121 remoteListener.allIdentitiesChanged(); 122 } 123 } 124 125 /** 126 * 127 * This method has been deprecated as of OpenSSO Enterprise 8.0. 128 * 129 * @param name name of the identity that changed 130 * @param type change type i.e., add, delete, modify, etc. 131 * @param cMap configuration map that contains realm and plugin-name 132 * 133 * @deprecated As of Sun Java System Access Manager 7.1. 134 */ 135 public void objectChanged(String name, int type, Map cMap) { 136 objectChanged(name, null, type, cMap); 137 } 138 139 /** 140 * Notification mechanism for IdRepo plugins to specify the identiy name 141 * and identity type that has been changed. 142 * 143 * @param name name of the identity that changed 144 * @param idType IdType i.e., user, group, etc. 145 * @param changeType change type i.e., add, delete, modify, etc. 146 * @param cMap configuration map that contains realm and plugin-name 147 */ 148 public void objectChanged(String name, IdType idType, int changeType, 149 Map cMap) { 150 if (debug.messageEnabled()) { 151 debug.message("objectChanged called with IdType= name: " + name + 152 " IdType: " + idType + " ChangeType: " + changeType + 153 "\nConfigmap = " + cMap); 154 } 155 // Get the list of listeners setup with idRepo 156 String org = (String) configMap.get("realm"); 157 List<IdEventListener> list = (List<IdEventListener>) AMIdentityRepository.listeners.get(org); 158 list = list == null ? new ArrayList<IdEventListener>() : new ArrayList<>(list); 159 if (remoteListener != null) { 160 list.add(remoteListener); 161 } 162 163 // Check if caching is enabled 164 if (!cacheChecked) { 165 idServices = IdServicesFactory.getDataStoreServices(); 166 if (idServices instanceof IdCachedServices) { 167 // If Caching was enabled - then clear the cache!! 168 cacheEnabled = true; 169 } 170 cacheChecked = true; 171 } 172 173 if (StringUtils.isNotEmpty(name)) { 174 String[] changed = getChangedIds(name, idType, cMap); 175 for (int i = 0; i < changed.length; i++) { 176 177 if (cacheEnabled) { 178 ((IdCachedServices) idServices).dirtyCache(changed[i], 179 changeType, false, false, Collections.EMPTY_SET); 180 } 181 182 for (IdEventListener l : list) { 183 // Update any listeners registered with IdRepo 184 if(changeType == OBJECT_CHANGED || changeType == OBJECT_ADDED) { 185 l.identityChanged(changed[i]); 186 } else if (changeType == OBJECT_REMOVED) { 187 l.identityDeleted(changed[i]); 188 } else if (changeType == OBJECT_RENAMED) { 189 l.identityRenamed(changed[i]); 190 } 191 } 192 } 193 } else if (debug.warningEnabled()) { 194 debug.warning("objectChanged called with an empty name"); 195 } 196 } 197 198 public static void addRemoteListener(IdEventListener l) { 199 remoteListener = l; 200 } 201 202 /* 203 * Returns the configurations for the IdRepo plugins 204 */ 205 public Map getConfigMap() { 206 return configMap; 207 } 208 209 /* 210 * Maintains the configurations for the IdRepo plugins 211 */ 212 public void setConfigMap(Map cMap) { 213 configMap = cMap; 214 } 215 216 /** 217 * Stores service's dynamic attributes within the IdRepo plugin 218 * configuration. In the current implementation changes to dynamic 219 * attributes to LDAPv3Repo restart the plugin, since it triggers 220 * a configuration change notification. 221 * 222 * @param sName service name for which attributes are being set 223 * @param attrs service synamic attributes 224 * @throws com.sun.identity.idm.IdRepoException 225 */ 226 public void setServiceAttributes(String sName, Map attrs) 227 throws IdRepoException { 228 String realm = (String) configMap.get("realm"); 229 String pluginName = (String) configMap.get("plugin-name"); 230 if (realm == null || pluginName == null) { 231 AMIdentityRepository.debug.error( 232 "IdRepoListener.setServiveAttribute: realm or plugin name" 233 + " is null"); 234 Object[] args = { sName, IdType.ROLE.getName() }; 235 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_ALREADY_ASSIGNED, args); 236 } 237 try { 238 SSOToken token = (SSOToken) AccessController 239 .doPrivileged(AdminTokenAction.getInstance()); 240 ServiceConfigManager scm = new ServiceConfigManager(token, 241 IdConstants.REPO_SERVICE, "1.0"); 242 ServiceConfig sc = scm.getOrganizationConfig(realm, null); 243 if (sc == null) { 244 return; 245 } 246 247 ServiceConfig subConfig = sc.getSubConfig(pluginName); 248 if (subConfig == null) { 249 return; 250 } 251 Map attributes = subConfig.getAttributes(); 252 Set vals = (Set) attributes.get(IdConstants.SERVICE_ATTRS); 253 if (vals == null || vals == Collections.EMPTY_SET) { 254 vals = new HashSet(); 255 } 256 if (sclient == null) { 257 sclient = new SOAPClient("dummy"); 258 } 259 String mapStr = sclient.encodeMap("result", attrs); 260 vals = new HashSet(); 261 vals.add(mapStr); 262 attributes.put(IdConstants.SERVICE_ATTRS, vals); 263 subConfig.setAttributes(attributes); 264 } catch (SMSException smse) { 265 AMIdentityRepository.debug.error( 266 "IdRepoListener: Unable to set service attributes", smse); 267 Object[] args = { sName, IdType.ROLE.getName() }; 268 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_ALREADY_ASSIGNED, args); 269 } catch (SSOException ssoe) { 270 AMIdentityRepository.debug.error( 271 "IdRepoListener: Unable to set service attributes", ssoe); 272 Object[] args = { sName, IdType.ROLE.getName() }; 273 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_ALREADY_ASSIGNED, args); 274 } 275 } 276 277 private String[] getChangedIds(String name, IdType type, Map cMap) { 278 int size = IdUtils.supportedTypes.size(); 279 // If configMap is null, then this is a "remote" cache update 280 if ((cMap == null) || cMap.isEmpty()) { 281 String ct[] = new String[1]; 282 if (LDAPUtils.isDN(name)) { 283 // Name should be the universal id 284 ct[0] = name; 285 } else { 286 if (type == null) { 287 // Default to user 288 type = IdType.USER; 289 } 290 ct[0] = "id=" + name + ",ou=" + type.getName() + "," + 291 ServiceManager.getBaseDN(); 292 } 293 return ct; 294 } 295 String changedTypes[] = null; 296 IdType types[] = null; 297 if (type == null) { 298 changedTypes = new String[size]; 299 if (defaultIdTypes == null) { 300 Set idtypes = IdUtils.supportedTypes; 301 defaultIdTypes = new IdType[idtypes.size()]; 302 defaultIdTypes = (IdType[]) idtypes.toArray(defaultIdTypes); 303 } 304 types = defaultIdTypes; 305 } else { 306 changedTypes = new String[1]; 307 types = new IdType[1]; 308 types[0] = type; 309 } 310 String realm = (String) cMap.get("realm"); 311 String Amsdk = (String) cMap.get("amsdk"); 312 boolean isAmsdk = Amsdk != null; 313 314 for (int i = 0; i < types.length; i++) { 315 IdType itype = types[i]; 316 String n = LDAPUtils.isDN(name) ? LDAPUtils.rdnValueFromDn(name) : name; 317 String id = "id=" + LDAPUtils.escapeValue(n) + ",ou=" + itype.getName() + "," + realm; 318 if (isAmsdk) { 319 id = id + ",amsdkdn=" + name; 320 } 321 changedTypes[i] = id; 322 } 323 return changedTypes; 324 } 325 326 // Constants for change type recevied from the IdRepo plugins 327 328 /** 329 * Represents an object addition event type. 330 */ 331 public static final int OBJECT_ADDED = PersistentSearchChangeType.ADDED; 332 333 /** 334 * Represents an object change event type. 335 */ 336 public static final int OBJECT_CHANGED = PersistentSearchChangeType.MODIFIED; 337 338 /** 339 * Represents an object removal event type. 340 */ 341 public static final int OBJECT_REMOVED = PersistentSearchChangeType.REMOVED; 342 343 /** 344 * Represents an object renaming event type. 345 */ 346 public static final int OBJECT_RENAMED = PersistentSearchChangeType.RENAMED; 347}