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: AMIdentityRepository.java,v 1.21 2010/01/06 01:58:26 veiming Exp $ 026 * 027 * Portions Copyrighted 2011-2016 ForgeRock AS. 028 */ 029package com.sun.identity.idm; 030 031import java.util.ArrayList; 032import java.util.Collections; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.Iterator; 036import java.util.Map; 037import java.util.Set; 038 039import javax.inject.Inject; 040import javax.security.auth.callback.Callback; 041 042import org.forgerock.openam.ldap.LDAPUtils; 043 044import com.google.inject.assistedinject.Assisted; 045import com.iplanet.am.sdk.AMHashMap; 046import com.iplanet.sso.SSOException; 047import com.iplanet.sso.SSOToken; 048import com.sun.identity.common.CaseInsensitiveHashMap; 049import com.sun.identity.common.DNUtils; 050import com.sun.identity.shared.debug.Debug; 051import com.sun.identity.sm.DNMapper; 052import com.sun.identity.sm.OrganizationConfigManager; 053import com.sun.identity.sm.SMSException; 054import org.forgerock.openam.utils.CrestQuery; 055 056/** 057 * The class <code> AMIdentityRepository </code> represents an object to access 058 * the repositories in which user/role/group and other identity data is 059 * configured. This class provides access to methods which will search, create 060 * and delete identities. An instance of this class can be obtained in the 061 * following manner: 062 * <p> 063 * 064 * <PRE> 065 * 066 * AMIdentityRepository idRepo = new AMIdentityRepository(ssoToken, realmName); 067 * 068 * </PRE> 069 * 070 * @supported.api 071 */ 072public class AMIdentityRepository { 073 private SSOToken token; 074 private String organizationDN; 075 private String idRealmName; 076 077 public static Debug debug = Debug.getInstance("amIdm"); 078 public static Map listeners = new CaseInsensitiveHashMap(); 079 080 private static Set<IdRepoCreationListener> creationListeners = new HashSet<IdRepoCreationListener>(); 081 082 /** 083 * @supported.api 084 * 085 * Constructor for the <code>AMIdentityRepository</code> object. If a null 086 * is passed for the organization identifier <code>realmName</code>, then 087 * the "root" realm is assumed. 088 * 089 * @param ssotoken 090 * Single sign on token of the user 091 * @param realmName 092 * Name of the realm (can be a Fully qualified DN) 093 * @throws IdRepoException Never thrown, required by legacy code. 094 * @throws SSOException Never thrown, required by legacy code. 095 * @deprecated in 13.0.0, use {@link #AMIdentityRepository(String, com.iplanet.sso.SSOToken)} instead 096 */ 097 @Deprecated 098 public AMIdentityRepository(SSOToken ssotoken, String realmName) 099 throws IdRepoException, SSOException { 100 this(realmName, ssotoken); 101 } 102 103 /** 104 * @supported.api 105 * 106 * Constructor for the {@code AMIdentityRepository} object. If a {@code null} is passed for 107 * the organization identifier {@code realmName}, then the "root" realm is assumed. 108 * 109 * @param ssoToken Single sign on token of the user. 110 * @param realmName Name of the realm (can be a Fully qualified DN). 111 */ 112 @Inject 113 public AMIdentityRepository(@Assisted String realmName, @Assisted SSOToken ssoToken) { 114 token = ssoToken; 115 idRealmName = realmName; 116 organizationDN = DNMapper.orgNameToDN(realmName); 117 notifyCreationListeners(); 118 } 119 120 /** 121 * Adds a creation listener that will be notified each time a {@code AMIdentityRepository} is created . 122 * 123 * @param listener The listener. 124 */ 125 public static void addCreationListener(IdRepoCreationListener listener) { 126 creationListeners.add(listener); 127 } 128 129 /** 130 * Removes a creation listener so that it will no longer be notified when a 131 * {@code AMIdentityRepository} is created. 132 * 133 * @param listener The listener. 134 * @return {@code true} if the listener was removed. 135 */ 136 public static boolean removeCreationListener(IdRepoCreationListener listener) { 137 return creationListeners.remove(listener); 138 } 139 140 private void notifyCreationListeners() { 141 for (IdRepoCreationListener listener : creationListeners) { 142 listener.notify(this, idRealmName); 143 } 144 } 145 146 /** 147 * @supported.api 148 * 149 * Returns the set of supported object types <code>IdType</code> for this 150 * deployment. This is not realm specific. 151 * 152 * @return Set of supported <code> IdType </code> objects. 153 * @throws IdRepoException 154 * if there are repository related error conditions. 155 * @throws SSOException 156 * if user's single sign on token is invalid. 157 */ 158 public Set getSupportedIdTypes() throws IdRepoException, SSOException { 159 IdServices idServices = IdServicesFactory.getDataStoreServices(); 160 Set res = idServices.getSupportedTypes(token, organizationDN); 161 res.remove(IdType.REALM); 162 return res; 163 } 164 165 /** 166 * @supported.api 167 * 168 * Returns the set of Operations for a given <code>IdType</code>, 169 * <code>IdOperations</code> that can be performed on an Identity. This 170 * varies for each organization (and each plugin?). 171 * 172 * @param type 173 * Type of identity 174 * @return Set of <code>IdOperation</code> objects. 175 * @throws IdRepoException 176 * if there are repository related error conditions. 177 * @throws SSOException 178 * if user's single sign on token is invalid. 179 */ 180 public Set getAllowedIdOperations(IdType type) throws IdRepoException, 181 SSOException { 182 IdServices idServices = IdServicesFactory.getDataStoreServices(); 183 return idServices.getSupportedOperations(token, type, organizationDN); 184 } 185 186 /** 187 * 188 * Return the special identities for this realm for a given type. These 189 * identities cannot be deleted and hence have to be shown in the admin 190 * console as non-deletable. 191 * 192 * @param type 193 * Type of the identity 194 * @return IdSearchResult 195 * @throws IdRepoException 196 * if there is a datastore exception 197 * @throws SSOException 198 * if the user's single sign on token is not valid. 199 */ 200 public IdSearchResults getSpecialIdentities(IdType type) 201 throws IdRepoException, SSOException { 202 203 IdSearchResults results = getSpecialIdentities(token, type, 204 organizationDN); 205 206 if (type.equals(IdType.USER)) { 207 // Iterating through to get out the names and remove only amadmin 208 // anonymous as per AM console requirement. 209 210 IdSearchResults newResults = new IdSearchResults(type, 211 organizationDN); 212 Set identities = results.getSearchResults(); 213 if ((identities != null) && !identities.isEmpty()) { 214 for (Iterator i = identities.iterator(); i.hasNext();) { 215 AMIdentity amid = ((AMIdentity) i.next()); 216 String remUser = amid.getName().toLowerCase(); 217 if (!remUser.equalsIgnoreCase(IdConstants.AMADMIN_USER) 218 && !remUser.equalsIgnoreCase( 219 IdConstants.ANONYMOUS_USER)) 220 { 221 newResults.addResult(amid, Collections.EMPTY_MAP); 222 } 223 } 224 results = newResults; 225 } 226 } 227 return results; 228 } 229 230 /** 231 * Searches for identities of a certain type. The iterator returns 232 * AMIdentity objects for use by the application. 233 * 234 * @deprecated This method is deprecated. Use 235 * {@link #searchIdentities(IdType type,String pattern, 236 * IdSearchControl ctrl)} 237 * @param type 238 * Type of identity being searched for. 239 * @param pattern 240 * Search pattern, like "a*" or "*". 241 * @param avPairs 242 * Map of attribute-values which can further help qualify the 243 * search pattern. 244 * @param recursive 245 * If true, then the search is performed on the entire subtree 246 * (if applicable) 247 * @param maxResults 248 * Maximum number of results to be returned. A -1 means no limit 249 * on the result set. 250 * @param maxTime 251 * Maximum amount of time after which the search should return 252 * with partial results. 253 * @param returnAttributes 254 * Set of attributes to be read when performing the search. 255 * @param returnAllAttributes 256 * If true, then read all the attributes of the entries. 257 * @return results containing <code>AMIdentity</code> objects. 258 * @throws IdRepoException 259 * if there are repository related error conditions. 260 * @throws SSOException 261 * if user's single sign on token is invalid. 262 */ 263 public IdSearchResults searchIdentities(IdType type, String pattern, 264 Map avPairs, boolean recursive, int maxResults, int maxTime, 265 Set returnAttributes, boolean returnAllAttributes) 266 throws IdRepoException, SSOException { 267 268 IdSearchControl crtl = new IdSearchControl(); 269 crtl.setSearchModifiers(IdSearchOpModifier.OR, avPairs); 270 crtl.setRecursive(recursive); 271 crtl.setMaxResults(maxResults); 272 crtl.setTimeOut(maxTime); 273 crtl.setReturnAttributes(returnAttributes); 274 crtl.setAllReturnAttributes(returnAllAttributes); 275 276 // Call search method that takes IdSearchControl 277 CrestQuery crestQuery = new CrestQuery(pattern); 278 return searchIdentities(type, crestQuery, crtl); 279 } 280 281 /** 282 * @supported.api 283 * 284 * Searches for identities of certain types from each plugin and returns a 285 * combined result. 286 * 287 * <b>Note:</b> The AMIdentity objects representing IdType.REALM can be 288 * used for services related operations only. The realm <code>AMIdentity 289 * </code> object can be used to assign and unassign services containing 290 * dynamic attributes to this realm. 291 * 292 * @param type 293 * Type of identity being searched for. 294 * @param pattern 295 * Pattern to be used when searching. 296 * @param ctrl 297 * IdSearchControl which can be used to set up various search 298 * controls on the search to be performed. 299 * @return Returns the combined results in an object IdSearchResults. 300 * @see com.sun.identity.idm.IdSearchControl 301 * @see com.sun.identity.idm.IdSearchResults 302 * @throws IdRepoException 303 * if there are repository related error conditions. 304 * @throws SSOException 305 * if user's single sign on token is invalid. 306 */ 307 public IdSearchResults searchIdentities(IdType type, String pattern, IdSearchControl ctrl) 308 throws IdRepoException, SSOException { 309 310 CrestQuery crestQuery = new CrestQuery(pattern); 311 return searchIdentities(type, crestQuery, ctrl); 312 } 313 314 /** 315 * Searches for identities of certain types from each plugin and returns a 316 * combined result 317 * 318 * <b>Note:</b> The AMIdentity objects representing IdType.REALM can be 319 * used for services related operations only. The realm <code>AMIdentity 320 * </code> object can be used to assign and unassign services containing 321 * dynamic attributes to this realm. 322 * 323 * @param type 324 * Type of identity being searched for. 325 * @param crestQuery 326 * Basically just an object which supports both _queryId and _queryFilter 327 * @param ctrl 328 * IdSearchControl which can be used to set up various search 329 * controls on the search to be performed. 330 * @return Returns the combined results in an object IdSearchResults. 331 * @see com.sun.identity.idm.IdSearchControl 332 * @see com.sun.identity.idm.IdSearchResults 333 * @throws IdRepoException 334 * if there are repository related error conditions. 335 * @throws SSOException 336 * if user's single sign on token is invalid. 337 */ 338 public IdSearchResults searchIdentities(IdType type, CrestQuery crestQuery, IdSearchControl ctrl) 339 throws IdRepoException, SSOException { 340 341 IdSearchResults idSearchResults = null; 342 343 if (type.equals(IdType.REALM)) { 344 345 if (crestQuery.hasQueryFilter()) { 346 throw new IdRepoException("realm searchIdentities does not support query filters"); 347 } 348 349 try { 350 idSearchResults = new IdSearchResults(type, idRealmName); 351 OrganizationConfigManager orgMgr = 352 new OrganizationConfigManager(token, idRealmName); 353 354 // Realm searches only support _queryId 355 String pattern = crestQuery.getQueryId(); 356 357 Set realmNames = orgMgr.getSubOrganizationNames(pattern, false); 358 if (realmNames != null) { 359 Iterator iterator = realmNames.iterator(); 360 while (iterator.hasNext()) { 361 String realmName = (String) iterator.next(); 362 363 AMIdentity realmIdentity = getSubRealmIdentity(realmName); 364 Map attributes = new HashMap(); 365 366 idSearchResults.addResult(realmIdentity, attributes); 367 idSearchResults.setErrorCode(IdSearchResults.SUCCESS); 368 } 369 } 370 } catch (SMSException sme) { 371 debug.error("AMIdentityRepository.searchIdentities() - " 372 + "Error occurred while searching " + type.getName() 373 + ":", sme); 374 throw new IdRepoException(sme.getMessage()); 375 } 376 } else { 377 IdServices idServices = IdServicesFactory.getDataStoreServices(); 378 379 idSearchResults = idServices.search(token, type, ctrl, organizationDN, crestQuery); 380 } 381 return idSearchResults; 382 } 383 384 /** 385 * @supported.api 386 * 387 * Returns a handle of the Identity object representing this 388 * realm for services related operations only. This <code> AMIdentity 389 * </code> object can be used to assign and unassign services containing 390 * dynamic attributes to this realm 391 * 392 * @return a handle of the Identity object. 393 * @throws IdRepoException 394 * if there are repository related error conditions. 395 * @throws SSOException 396 * if user's single sign on token is invalid. 397 */ 398 public AMIdentity getRealmIdentity() throws IdRepoException, SSOException { 399 return getRealmIdentity(token, organizationDN); 400 } 401 402 private AMIdentity getRealmIdentity(SSOToken token, String orgDN) 403 throws IdRepoException { 404 String universalId = "id=ContainerDefaultTemplateRole,ou=realm," + 405 orgDN; 406 return IdUtils.getIdentity(token, universalId); 407 } 408 409 private AMIdentity getSubRealmIdentity(String subRealmName) throws 410 IdRepoException, SSOException { 411 String realmName = idRealmName; 412 if (LDAPUtils.isDN(idRealmName)) { // Wouldn't be a DN if it starts with "/" 413 realmName = DNMapper.orgNameToRealmName(idRealmName); 414 } 415 416 String fullRealmName = realmName + IdConstants.SLASH_SEPARATOR + 417 subRealmName; 418 String subOrganizationDN = DNMapper.orgNameToDN(fullRealmName); 419 420 return getRealmIdentity(token, subOrganizationDN); 421 } 422 423 /** 424 * @supported.api 425 * 426 * Creates a single object of a type. The object is 427 * created in all the plugins that support creation of this type of object. 428 * 429 * This method is only valid for: 430 * 431 * <ol> 432 * <li> {@link IdType#AGENT IdType.AGENT} </li> 433 * <li> {@link IdType#USER IdType.USER} </li> 434 * <li> {@link IdType#REALM IdType.REALM} </li> 435 * </ol> 436 * 437 * <br> 438 * <b>Note:</b> For creating {@link IdType#REALM IdType.REALM} identities, 439 * a map of <code>sunIdentityRepositoryService</code> attributes need to 440 * be passed. Also, AMIdentity object representing this realm can be 441 * used for services related operations only. This <code> AMIdentity 442 * </code> object can be used to assign and unassign services containing 443 * dynamic attributes to this realm 444 * 445 * 446 * @param type 447 * <code>IdType</code> of object to be created. 448 * @param idName 449 * Name of object. If the type is <code>IdType.REALM</code> 450 * then enter a valid realm name. 451 * @param attrMap 452 * Map of attribute-values to be set when creating the entry. 453 * @return Identity object representing the newly created entry. 454 * @throws IdRepoException 455 * if there are repository related error conditions. 456 * @throws SSOException 457 * if user's single sign on token is invalid. 458 */ 459 public AMIdentity createIdentity(IdType type, String idName, Map attrMap) 460 throws IdRepoException, SSOException { 461 IdServices idServices = IdServicesFactory.getDataStoreServices(); 462 return idServices.create(token, type, idName, attrMap, organizationDN); 463 } 464 465 /** 466 * @supported.api 467 * 468 * Creates multiple objects of the same type. The objects are created in all 469 * the <code>IdRepo</code> plugins that support creation of these objects. 470 * 471 * This method is only valid for: 472 * 473 * <ol> 474 * <li> {@link IdType#AGENT IdType.AGENT} </li> 475 * <li> (@link IdType#USER IdType.USER} </li> 476 * <li> {@link IdType#REALM IdType.REALM} </li> 477 * </ol> 478 * 479 * <br> 480 * <b>Note:</b> For creating {@link IdType#REALM IdType.REALM} identities, 481 * a map of <code>sunIdentityRepositoryService</code> attributes need to 482 * be passed. Also, AMIdentity object representing this realm can be 483 * used for services related operations only. This <code> AMIdentity 484 * </code> object can be used to assign and unassign services containing 485 * dynamic attributes to this realm. 486 * 487 * @param type 488 * Type of object to be created 489 * @param identityNamesAndAttrs 490 * Names of the identities and their 491 * @return Set of created Identities. 492 * @throws IdRepoException 493 * if there are repository related error conditions. 494 * @throws SSOException 495 * if user's single sign on token is invalid. 496 */ 497 public Set createIdentities(IdType type, Map identityNamesAndAttrs) 498 throws IdRepoException, SSOException { 499 Set results = new HashSet(); 500 501 if (identityNamesAndAttrs == null || identityNamesAndAttrs.isEmpty()) { 502 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.ILLEGAL_ARGUMENTS, null); 503 } 504 505 Iterator it = identityNamesAndAttrs.keySet().iterator(); 506 507 while (it.hasNext()) { 508 String name = (String) it.next(); 509 Map attrMap = (Map) identityNamesAndAttrs.get(name); 510 AMIdentity id = createIdentity(type, name, attrMap); 511 results.add(id); 512 } 513 514 return results; 515 } 516 517 /** 518 * @supported.api 519 * 520 * Deletes identities. The Set passed is a set of <code>AMIdentity</code> 521 * objects. 522 * 523 * This method is only valid for: 524 * <ol> 525 * <li> {@link IdType#AGENT IdType.AGENT} </li> 526 * <li> {@link IdType#REALM IdType.REALM} </li> 527 * <li> (@link IdType#USER IdType.USER} </li> 528 * </ol> 529 * 530 * @param type Type of Identity to be deleted. 531 * @param identities Set of <code>AMIdentity</code> objects to be deleted. 532 * @throws IdRepoException if there are repository related error conditions. 533 * @throws SSOException if user's single sign on token is invalid. 534 * @deprecated As of release AM 7.1, replaced by 535 * {@link #deleteIdentities(Set)} 536 */ 537 public void deleteIdentities(IdType type, Set identities) 538 throws IdRepoException, SSOException { 539 deleteIdentities(identities); 540 } 541 542 /** 543 * @supported.api 544 * 545 * Deletes identities. The Set passed is a set of <code>AMIdentity</code> 546 * objects. 547 * 548 * This method is only valid for: 549 * <ol> 550 * <li> {@link IdType#AGENT IdType.AGENT} </li> 551 * <li> {@link IdType#REALM IdType.REALM} </li> 552 * <li> (@link IdType#USER IdType.USER} </li> 553 * </ol> 554 * 555 * @param identities Set of <code>AMIdentity</code> objects to be deleted 556 * @throws IdRepoException if there are repository related error conditions. 557 * @throws SSOException if user's single sign on token is invalid. 558 */ 559 public void deleteIdentities(Set identities) throws IdRepoException, 560 SSOException { 561 if (identities == null || identities.isEmpty()) { 562 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.ILLEGAL_ARGUMENTS, null); 563 } 564 565 Iterator it = identities.iterator(); 566 while (it.hasNext()) { 567 AMIdentity id = (AMIdentity) it.next(); 568 IdServices idServices = IdServicesFactory.getDataStoreServices(); 569 idServices.delete(token, id.getType(), id.getName(), organizationDN, 570 id.getDN()); 571 } 572 } 573 574 /** 575 * Non-javadoc, non-public methods Returns <code>true</code> if the data 576 * store has successfully authenticated the identity with the provided 577 * credentials. In case the data store requires additional credentials, the 578 * list would be returned via the <code>IdRepoException</code> exception. 579 * 580 * @param credentials 581 * Array of callback objects containing information such as 582 * username and password. 583 * 584 * @return <code>true</code> if data store authenticates the identity; 585 * else <code>false</code> 586 */ 587 public boolean authenticate(Callback[] credentials) throws IdRepoException, 588 com.sun.identity.authentication.spi.AuthLoginException { 589 IdServices idServices = IdServicesFactory.getDataStoreServices(); 590 return (idServices.authenticate(organizationDN, credentials)); 591 } 592 593 /** 594 * Non-javadoc, non-public methods Returns <code>true</code> if the data 595 * store has successfully authenticated the identity with the provided 596 * credentials. In case the data store requires additional credentials, the 597 * list would be returned via the <code>IdRepoException</code> exception. 598 * 599 * @param credentials 600 * Array of callback objects containing information such as 601 * username and password. 602 * @param idType 603 * The type of identity to authenticate as, or null for any. 604 * 605 * @return <code>true</code> if data store authenticates the identity; 606 * else <code>false</code> 607 */ 608 public boolean authenticate(IdType idType, Callback[] credentials) throws IdRepoException, 609 com.sun.identity.authentication.spi.AuthLoginException { 610 IdServices idServices = IdServicesFactory.getDataStoreServices(); 611 return idServices.authenticate(organizationDN, credentials, idType); 612 } 613 614 /** 615 * @supported.api 616 * 617 * Adds a listener, which should receive notifications for all changes that 618 * occurred in this organization. 619 * 620 * This method is only valid for IdType User and Agent. 621 * 622 * @param listener 623 * The callback which implements <code>AMEventListener</code>. 624 * @return Integer identifier for this listener. 625 */ 626 public int addEventListener(IdEventListener listener) { 627 ArrayList listOfListeners = (ArrayList) listeners.get(organizationDN); 628 if (listOfListeners == null) { 629 listOfListeners = new ArrayList(); 630 } 631 synchronized (listeners) { 632 listOfListeners.add(listener); 633 listeners.put(organizationDN, listOfListeners); 634 } 635 return (listOfListeners.size() - 1); 636 } 637 638 /** 639 * @supported.api 640 * 641 * Removes listener as the application is no longer interested in receiving 642 * notifications. 643 * 644 * @param identifier 645 * Integer identifying the listener. 646 */ 647 public void removeEventListener(int identifier) { 648 ArrayList listOfListeners = (ArrayList) listeners.get(organizationDN); 649 if (listOfListeners != null) { 650 synchronized (listeners) { 651 listOfListeners.remove(identifier); 652 } 653 } 654 } 655 656 /** 657 * @supported.api 658 * 659 * Clears the cache. 660 */ 661 public static void clearCache() { 662 IdServices idServices = IdServicesFactory.getDataStoreServices(); 663 idServices.reinitialize(); 664 IdUtils.initialize(); 665 } 666 667 668 public IdSearchResults getSpecialIdentities(SSOToken token, IdType type, 669 String orgName) throws IdRepoException, SSOException { 670 IdServices idServices = IdServicesFactory.getDataStoreServices(); 671 return idServices.getSpecialIdentities(token, type, orgName); 672 } 673 674 /** 675 * Return String representation of the <code>AMIdentityRepository 676 * </code> object. It returns realm name. 677 * 678 * @return String representation of <code>AMIdentityRepository</code> 679 * object. 680 */ 681 public String toString() { 682 StringBuilder sb = new StringBuilder(100); 683 sb.append("AMIdentityRepository object: ") 684 .append(organizationDN); 685 return (sb.toString()); 686 } 687 688 // TODO: 689 // FIXME: Move these utilities to a util class 690 private Map reverseMapAttributeNames(Map attrMap, Map configMap) { 691 if (attrMap == null || attrMap.isEmpty()) { 692 return attrMap; 693 } 694 Map resultMap; 695 Map[] mapArray = getAttributeNameMap(configMap); 696 if (mapArray == null) { 697 resultMap = attrMap; 698 } else { 699 resultMap = new CaseInsensitiveHashMap(); 700 Map reverseMap = mapArray[1]; 701 Iterator it = attrMap.keySet().iterator(); 702 while (it.hasNext()) { 703 String curr = (String) it.next(); 704 if (reverseMap.containsKey(curr)) { 705 resultMap.put((String) reverseMap.get(curr), (Set) attrMap 706 .get(curr)); 707 } else { 708 resultMap.put(curr, (Set) attrMap.get(curr)); 709 } 710 } 711 } 712 return resultMap; 713 } 714 715 private IdSearchResults combineSearchResults(SSOToken token, 716 Object[][] arrayOfResult, int sizeOfArray, IdType type, 717 String orgName, boolean amsdkIncluded, Object[][] amsdkResults) { 718 Map amsdkDNs = new CaseInsensitiveHashMap(); 719 Map resultsMap = new CaseInsensitiveHashMap(); 720 int errorCode = IdSearchResults.SUCCESS; 721 if (amsdkIncluded) { 722 RepoSearchResults amsdkRepoRes = (RepoSearchResults) 723 amsdkResults[0][0]; 724 Set results = amsdkRepoRes.getSearchResults(); 725 Map attrResults = amsdkRepoRes.getResultAttributes(); 726 for (String dn : (Set<String>) results) { 727 String name = LDAPUtils.rdnValueFromDn(dn); 728 amsdkDNs.put(name, dn); 729 Set attrMaps = new HashSet(); 730 attrMaps.add((Map) attrResults.get(dn)); 731 resultsMap.put(name, attrMaps); 732 } 733 errorCode = amsdkRepoRes.getErrorCode(); 734 } 735 for (int i = 0; i < sizeOfArray; i++) { 736 RepoSearchResults current = (RepoSearchResults) arrayOfResult[i][0]; 737 Map configMap = (Map) arrayOfResult[i][1]; 738 Map allAttrMaps = current.getResultAttributes(); 739 for (String m : (Set<String>) current.getSearchResults()) { 740 String mname = DNUtils.DNtoName(m); 741 Map attrMap = (Map) allAttrMaps.get(m); 742 attrMap = reverseMapAttributeNames(attrMap, configMap); 743 Set attrMaps = (Set) resultsMap.get(mname); 744 if (attrMaps == null) { 745 attrMaps = new HashSet(); 746 } 747 attrMaps.add(attrMap); 748 resultsMap.put(mname, attrMaps); 749 } 750 } 751 IdSearchResults results = new IdSearchResults(type, orgName); 752 for (String mname : (Set<String>) resultsMap.keySet()) { 753 Map combinedMap = combineAttrMaps((Set) resultsMap.get(mname), 754 true); 755 AMIdentity id = new AMIdentity(token, mname, type, orgName, 756 (String) amsdkDNs.get(mname)); 757 results.addResult(id, combinedMap); 758 } 759 results.setErrorCode(errorCode); 760 return results; 761 } 762 763 private Map[] getAttributeNameMap(Map configMap) { 764 Set attributeMap = (Set) configMap.get(IdConstants.ATTR_MAP); 765 766 if (attributeMap == null || attributeMap.isEmpty()) { 767 return null; 768 } else { 769 Map returnArray[] = new Map[2]; 770 int size = attributeMap.size(); 771 returnArray[0] = new CaseInsensitiveHashMap(size); 772 returnArray[1] = new CaseInsensitiveHashMap(size); 773 Iterator it = attributeMap.iterator(); 774 while (it.hasNext()) { 775 String mapString = (String) it.next(); 776 int eqIndex = mapString.indexOf('='); 777 if (eqIndex > -1) { 778 String first = mapString.substring(0, eqIndex); 779 String second = mapString.substring(eqIndex + 1); 780 returnArray[0].put(first, second); 781 returnArray[1].put(second, first); 782 } else { 783 returnArray[0].put(mapString, mapString); 784 returnArray[1].put(mapString, mapString); 785 } 786 } 787 return returnArray; 788 } 789 } 790 791 private Map combineAttrMaps(Set setOfMaps, boolean isString) { 792 // Map resultMap = new CaseInsensitiveHashMap(); 793 Map resultMap = new AMHashMap(); 794 Iterator it = setOfMaps.iterator(); 795 while (it.hasNext()) { 796 Map currMap = (Map) it.next(); 797 if (currMap != null) { 798 Iterator keyset = currMap.keySet().iterator(); 799 while (keyset.hasNext()) { 800 String thisAttr = (String) keyset.next(); 801 if (isString) { 802 Set resultSet = (Set) resultMap.get(thisAttr); 803 Set thisSet = (Set) currMap.get(thisAttr); 804 if (resultSet != null) { 805 resultSet.addAll(thisSet); 806 } else { 807 /* 808 * create a new Set so that we do not alter the set 809 * that is referenced in setOfMaps 810 */ 811 resultSet = new HashSet((Set) 812 currMap.get(thisAttr)); 813 resultMap.put(thisAttr, resultSet); 814 } 815 } else { // binary attributes 816 817 byte[][] resultSet = (byte[][]) resultMap.get(thisAttr); 818 byte[][] thisSet = (byte[][]) currMap.get(thisAttr); 819 int combinedSize = thisSet.length; 820 if (resultSet != null) { 821 combinedSize = resultSet.length + thisSet.length; 822 byte[][] tmpSet = new byte[combinedSize][]; 823 for (int i = 0; i < resultSet.length; i++) { 824 tmpSet[i] = (byte[]) resultSet[i]; 825 } 826 for (int i = 0; i < thisSet.length; i++) { 827 tmpSet[i] = (byte[]) thisSet[i]; 828 } 829 resultSet = tmpSet; 830 } else { 831 resultSet = (byte[][]) thisSet.clone(); 832 } 833 resultMap.put(thisAttr, resultSet); 834 835 } 836 837 } 838 } 839 } 840 return resultMap; 841 } 842}