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