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: IdUtils.java,v 1.34 2009/11/20 23:52:54 ww203982 Exp $ 026 * 027 * Portions Copyrighted 2011-2015 ForgeRock AS. 028 * Portions Copyrighted 2014 Nomura Research Institute, Ltd 029 */ 030 031package com.sun.identity.idm; 032 033import java.security.AccessController; 034import java.util.Collections; 035import java.util.HashSet; 036import java.util.Iterator; 037import java.util.Map; 038import java.util.Set; 039import java.util.StringTokenizer; 040 041import com.iplanet.am.sdk.AMConstants; 042import com.iplanet.am.sdk.AMDirectoryAccessFactory; 043import com.iplanet.am.sdk.AMException; 044import com.iplanet.am.sdk.AMObject; 045import com.iplanet.am.sdk.AMOrganization; 046import com.iplanet.am.sdk.AMStoreConnection; 047import com.iplanet.am.sdk.common.IDirectoryServices; 048import com.iplanet.am.util.SystemProperties; 049import com.iplanet.sso.SSOException; 050import com.iplanet.sso.SSOToken; 051import com.sun.identity.authentication.service.AuthD; 052import com.sun.identity.common.CaseInsensitiveHashMap; 053import com.sun.identity.common.DNUtils; 054import com.sun.identity.security.AdminTokenAction; 055import com.sun.identity.shared.Constants; 056import com.sun.identity.shared.debug.Debug; 057import com.sun.identity.sm.DNMapper; 058import com.sun.identity.sm.OrgConfigViaAMSDK; 059import com.sun.identity.sm.OrganizationConfigManager; 060import com.sun.identity.sm.SMSEntry; 061import com.sun.identity.sm.SMSException; 062import com.sun.identity.sm.ServiceConfig; 063import com.sun.identity.sm.ServiceConfigManager; 064import com.sun.identity.sm.ServiceManager; 065import org.forgerock.openam.ldap.LDAPUtils; 066import org.forgerock.opendj.ldap.DN; 067 068/** 069 * The class defines some static utilities used by other components like policy 070 * and auth 071 * 072 * @supported.api 073 */ 074public final class IdUtils { 075 private static Debug debug = AMIdentityRepository.debug; 076 077 private static Map mapSupportedTypes = new CaseInsensitiveHashMap(10); 078 079 public static Set supportedTypes = new HashSet(); 080 081 private static Map mapTypesToServiceNames = new CaseInsensitiveHashMap(); 082 083 protected static Map typesCanBeMemberOf = new CaseInsensitiveHashMap(); 084 085 protected static Map typesCanHaveMembers = new CaseInsensitiveHashMap(); 086 087 protected static Map typesCanAddMembers = new CaseInsensitiveHashMap(); 088 089 // Static map to cache "orgIdentifier" and organization DN 090 private static Map orgIdentifierToOrgName = Collections.synchronizedMap( 091 new CaseInsensitiveHashMap()); 092 private static Map orgStatusCache = Collections.synchronizedMap( 093 new CaseInsensitiveHashMap()); 094 095 // ServiceConfigManager for sunidentityrepository service 096 private static String notificationId; 097 098 private static ServiceConfigManager serviceConfigManager; 099 100 // User naming attribute for AMSDK 101 private static String USER_NAMING_ATTR; 102 103 // Organization naming attribute for AMSDK 104 private static String ORG_NAMING_ATTR; 105 106 // SMS Root Suffix 107 private static String ROOT_SUFFIX; 108 109 // DN pointing to the services node 110 private static String SERVICES_SUFFIX; 111 112 // Special Users 113 private static Set specialUsers = new HashSet(); 114 115 static { 116 initialize(); 117 } 118 119 protected static void initialize() { 120 if (ServiceManager.isConfigMigratedTo70()) { 121 // IdRepo service schema exists. Read the supported 122 // entities from there 123 try { 124 SSOToken adminToken = (SSOToken) AccessController 125 .doPrivileged(AdminTokenAction.getInstance()); 126 serviceConfigManager = new ServiceConfigManager(adminToken, 127 IdConstants.REPO_SERVICE, "1.0"); 128 ServiceConfig ss = serviceConfigManager.getGlobalConfig(null); 129 Set typeSchemaNames = ss.getSubConfigNames("*", 130 IdConstants.SUPPORTED_TYPES); 131 if (typeSchemaNames == null || typeSchemaNames.isEmpty()) { 132 loadDefaultTypes(); 133 } else { 134 Iterator it = typeSchemaNames.iterator(); 135 while (it.hasNext()) { 136 String typeSchema = (String) it.next(); 137 IdType idType = new IdType(typeSchema); 138 supportedTypes.add(idType); 139 mapSupportedTypes.put(idType.getName(), idType); 140 ServiceConfig tsc = ss.getSubConfig(typeSchema); 141 Map attributes = tsc.getAttributes(); 142 Set serviceNameSet = (Set) attributes 143 .get(IdConstants.SERVICE_NAME); 144 Set canBeMembersOf = (Set) attributes 145 .get(IdConstants.ATTR_MEMBER_OF); 146 Set canHaveMembers = (Set) attributes 147 .get(IdConstants.ATTR_HAVE_MEMBERS); 148 Set canAddMembers = (Set) attributes 149 .get(IdConstants.ATTR_ADD_MEMBERS); 150 if (serviceNameSet != null && 151 !serviceNameSet.isEmpty()) { 152 mapTypesToServiceNames.put(typeSchema, 153 (String) serviceNameSet.iterator().next()); 154 } 155 if (canBeMembersOf != null && 156 !canBeMembersOf.isEmpty()) { 157 Set memberOfSet = getMemberSet(canBeMembersOf); 158 typesCanBeMemberOf.put(typeSchema, memberOfSet); 159 } 160 if (canHaveMembers != null && 161 !canHaveMembers.isEmpty()) { 162 Set memberSet = getMemberSet(canHaveMembers); 163 typesCanHaveMembers.put(typeSchema, memberSet); 164 } 165 if (canAddMembers != null && 166 !canAddMembers.isEmpty()) 167 { 168 Set memberSet = getMemberSet(canAddMembers); 169 typesCanAddMembers.put(typeSchema, memberSet); 170 } 171 } 172 } 173 } catch (SMSException e) { 174 String installTime = SystemProperties.get( 175 Constants.SYS_PROPERTY_INSTALL_TIME, "false"); 176 if (!installTime.equals("true")) { 177 debug.error( 178 "IdUtils.initialize: Loading default types.", e); 179 } 180 loadDefaultTypes(); 181 } catch (SSOException ssoe) { 182 debug.error("dUtils.initialize: Loading default types", ssoe); 183 loadDefaultTypes(); 184 } 185 } else { 186 loadDefaultTypes(); 187 } 188 189 // Register for SMS notifications to root realm 190 if (notificationId == null) { 191 try { 192 SSOToken adminToken = (SSOToken) AccessController 193 .doPrivileged(AdminTokenAction.getInstance()); 194 if (serviceConfigManager == null) { 195 serviceConfigManager = new ServiceConfigManager(adminToken, 196 IdConstants.REPO_SERVICE, "1.0"); 197 } 198 notificationId = serviceConfigManager.addListener( 199 new IdUtilsListener()); 200 } catch (SMSException e) { 201 String installTime = SystemProperties.get( 202 Constants.SYS_PROPERTY_INSTALL_TIME, "false"); 203 if (!installTime.equals("true")) { 204 debug.error( 205 "IdUtils.initialize: Register notification", e); 206 } 207 } catch (SSOException ssoe) { 208 String installTime = SystemProperties.get( 209 Constants.SYS_PROPERTY_INSTALL_TIME, "false"); 210 if (!installTime.equals("true")) { 211 debug.error( 212 "IdUtils.initialize: Register notification", ssoe); 213 } 214 } 215 } 216 } 217 218 /** 219 * @supported.api 220 * Returns a handle of the Identity object based on 221 * the SSO Token passed in (<code>AMIdentity</code> object of the user 222 * who is authenticated). 223 * 224 * @param token Single sign on token of user. 225 * @return Identity object. 226 * @throws IdRepoException if there are repository related error conditions. 227 * @throws SSOException if user's single sign on token is invalid. 228 */ 229 public static AMIdentity getIdentity(SSOToken token) 230 throws IdRepoException, SSOException { 231 String principal = token.getProperty(Constants.UNIVERSAL_IDENTIFIER); 232 if (principal == null) { 233 // This could happen during co-existence with AM 6.x 234 // and SSOToken created by AM 6.x server. In this case 235 // the principal name would be the DN 236 principal = token.getPrincipal().getName(); 237 } 238 return (getIdentity(token, principal)); 239 } 240 241 /** 242 * @supported.api 243 * 244 * Returns a string which uniquely represents this identity object. 245 * 246 * @param id 247 * <code>AMIdentity</code> object whose string represenation is 248 * needed. 249 * @return universal identifier of <code>id</code>. 250 */ 251 public static String getUniversalId(AMIdentity id) { 252 return id.getUniversalId(); 253 } 254 255 /** 256 * @supported.api 257 * 258 * Returns an <code>AMIdentity</code> object, if provided with a string 259 * identifier for the object. 260 * 261 * @param token SSOToken of the administrator 262 * @param univId String represenation of the identity. 263 * @return Identity object 264 * @throws IdRepoException if the identifier provided is wrong. 265 */ 266 public static AMIdentity getIdentity(SSOToken token, String univId) 267 throws IdRepoException { 268 return (getIdentity(token, univId, null)); 269 } 270 271 /** 272 * Returns an <code>AMIdentity</code> object, given the 273 * DN of an authenticated identity, realm name and identity type. 274 * This interface is mainly for authentication component to get 275 * back the identity of the user. 276 * 277 * @param token SSOToken of the administrator 278 * @param amsdkdn DN of the authenticated user 279 * @param realm realm name where the user was authenticated 280 * @return Identity object or <code>null</code> 281 * @throws IdRepoException if the underly components throws 282 * exception while obtaining the identity object 283 */ 284 public static AMIdentity getIdentity(SSOToken token, String amsdkdn, 285 String realm) throws IdRepoException { 286 if (amsdkdn == null || !LDAPUtils.isDN(amsdkdn)) { 287 Object[] args = { amsdkdn }; 288 throw (new IdRepoException(IdRepoBundle.BUNDLE_NAME, 289 IdRepoErrorCode.ILLEGAL_UNIVERSAL_IDENTIFIER, args)); 290 } 291 DN amsdkdnObject = LDAPUtils.newDN(amsdkdn); 292 293 // Try constructing the identity object 294 if (amsdkdn.toLowerCase().startsWith("id=")) { 295 try { 296 return (new AMIdentity(amsdkdnObject, token)); 297 } catch (IdRepoException ide) { 298 // this could be a AMSDK DN. Follow the AMSDK rules 299 if (debug.messageEnabled()) { 300 debug.message("IdUtils:getIdentity(token, " + 301 amsdkdn + ") got exception: " + ide.getMessage() + 302 "\n\tContinuing with AMSDK DN check"); 303 } 304 } 305 } 306 307 // Check for Special Users 308 initializeSpecialUsers(); 309 if (specialUsers.contains(DNUtils.normalizeDN(amsdkdn))) { 310 return new AMIdentity(amsdkdnObject, token, LDAPUtils.rdnValueFromDn( 311 amsdkdnObject), IdType.USER, ROOT_SUFFIX); 312 } 313 314 // Since "amsdkdn" is not a UUID, check if realm has AMSDK configured 315 // This change is to avoid the issue of IdUtils always checking the 316 // users in AMSDK as IdUtils does not check if AMSDK is configured in 317 // any of the realms. 318 try { 319 if (!ServiceManager.isAMSDKEnabled() || ((realm != null) && 320 !OrgConfigViaAMSDK.isAMSDKConfigured(realm)) || 321 (!ServiceManager.isAMSDKConfigured())) { 322 // Not configured for AMSDK, return 323 return (null); 324 } 325 } catch (SMSException smse) { 326 // Ignore the exception and continue 327 } 328 329 // Initialize root realm suffix, org and user naming attributes 330 initializeForGetIdentity(); 331 332 // Determine if the amsdkdn is valid. Obtain name & type 333 String name = null; 334 IdType type = null; 335 try { 336 // Since we would using AMSDK, get AMDirectoryManager preload 337 // all the attributes and check if it exists 338 IDirectoryServices dsServices = 339 AMDirectoryAccessFactory.getDirectoryServices(); 340 // Preload/cache all the attributes assuming it is a user 341 // Mainly for performance reasons, since getObjectType would 342 // force multiple another directory lookup 343 try { 344 if (amsdkdn.startsWith(USER_NAMING_ATTR)) { 345 dsServices.getAttributes(token, amsdkdn, AMObject.USER); 346 } 347 } catch (Exception e) { 348 // Ignore the exception and continue since this for cache 349 } 350 351 // Getting object type would use the cached attributes 352 int sdkType = dsServices.getObjectType(token, amsdkdn); 353 354 // Convert the sdkType to IdRepo type 355 type = getType(AMStoreConnection.getObjectName(sdkType)); 356 name = AMConstants.CONTAINER_DEFAULT_TEMPLATE_ROLE; 357 if (!type.equals(IdType.REALM)) { 358 name = LDAPUtils.rdnValueFromDn(amsdkdnObject); 359 } 360 } catch (AMException ame) { 361 // Debug the message and return null 362 if (debug.messageEnabled()) { 363 debug.message("IdUtils.getIdentity: Unable to resolve " + 364 "AMSDK DN: " + amsdkdn, ame); 365 } 366 return (null); 367 } catch (SSOException ssoe) { 368 // Debug the message and return null 369 if (debug.messageEnabled()) { 370 debug.message("IdUtils.getIdentity: Unable to resolve " + 371 "AMSDK DN. Got SSOException", ssoe); 372 } 373 return (null); 374 } 375 376 // Need to determine realm for amsdkdn 377 String srealm = ROOT_SUFFIX; 378 if (!amsdkdn.equals(ROOT_SUFFIX) && 379 !amsdkdn.equals(SERVICES_SUFFIX)) { 380 // Need to get the object type and walk up the tree 381 int index = amsdkdn.indexOf(ORG_NAMING_ATTR); 382 if (index == 0) { 383 srealm = OrgConfigViaAMSDK.getRealmForAMSDK(amsdkdn, realm); 384 } else if (index > 0) { 385 srealm = OrgConfigViaAMSDK.getRealmForAMSDK( 386 amsdkdn.substring(index), realm); 387 } 388 if (debug.messageEnabled()) { 389 debug.message("IdUtils.getIdentity:: amsdkdn=" + 390 amsdkdn + " maps to realm=" + srealm); 391 } 392 } else if (amsdkdn.equals(SERVICES_SUFFIX)) { 393 // Since amsdkdn points to services node, 394 // it should be reset to root suffix 395 amsdkdn = ROOT_SUFFIX; 396 } 397 398 return (new AMIdentity(amsdkdnObject, token, name, type, srealm)); 399 } 400 401 /** 402 * Returns the name of service which defines the profile information for 403 * this type. Returns null, if nothing is defined. 404 * 405 * @param type IdType whose service name is needed. 406 * @return Name of the service. 407 */ 408 public static String getServiceName(IdType type) { 409 return (String) mapTypesToServiceNames.get(type.getName()); 410 } 411 412 /** 413 * Returns corresponding <code>IdType</code> object given a type. 414 * 415 * @param type of object to return. 416 * @return Idtype of type. 417 * @throws IdRepoException if there are no corresponding types. 418 */ 419 public static IdType getType(String type) throws IdRepoException { 420 if (type.equalsIgnoreCase("managedrole")) { 421 type = "role"; 422 } else if (type.equalsIgnoreCase("organization") 423 || type.equalsIgnoreCase("organizationalunit")) { 424 type = "realm"; 425 } 426 427 IdType returnType = (IdType) mapSupportedTypes.get(type); 428 if (returnType == null) { 429 Object args[] = { type }; 430 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, 431 IdRepoErrorCode.NOT_SUPPORTED_TYPE, args); 432 } 433 return returnType; 434 } 435 436 /** 437 * Returns the matching DN from the AM SDK for this entry. This utility is 438 * required by auth. 439 * 440 * @param id <code>AMIdentity</code> object. 441 * @return <code>DN</code> of the object, as represented in the datastore. 442 */ 443 public static String getDN(AMIdentity id) { 444 if (id.getDN() != null) { 445 return id.getDN(); 446 } else { 447 return id.getUniversalId(); 448 } 449 } 450 451 /** 452 * Returns an organization which maps to the identifier used by application 453 * 454 * @param orgIdentifier Organization identifier 455 * @return Organization mapping to that identifier. 456 */ 457 public static String getOrganization(SSOToken token, String orgIdentifier) 458 throws IdRepoException, SSOException { 459 // Check in cache first 460 String id = null; 461 if ((id = (String) orgIdentifierToOrgName.get(orgIdentifier)) != null) { 462 return (id); 463 } 464 465 // Compute the organization name 466 if (debug.messageEnabled()) { 467 debug.message("IdUtils:getOrganization Input orgname: " 468 + orgIdentifier); 469 } 470 if (orgIdentifier == null || orgIdentifier.length() == 0 471 || orgIdentifier.equals("/")) { 472 // Return base DN 473 id = DNMapper.orgNameToDN("/"); 474 } else if (orgIdentifier.startsWith("/")) { 475 // If orgIdentifier is in "/" format covert to DN and return 476 id = DNMapper.orgNameToDN(orgIdentifier); 477 try { 478 new OrganizationConfigManager(token, orgIdentifier); 479 } catch (SMSException e) { 480 debug.message("IdUtils.getOrganization Exception in getting org name from SMS", e); 481 Object[] args = { orgIdentifier }; 482 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.NO_MAPPING_FOUND, args); 483 } 484 } else if (LDAPUtils.isDN(orgIdentifier)) { 485 id = orgIdentifier; 486 try { 487 // Search for realms with orgIdentifier name 488 OrganizationConfigManager ocm = 489 new OrganizationConfigManager(token, orgIdentifier); 490 } catch (SMSException smse) { 491 // debug message here. 492 if (debug.messageEnabled()) { 493 debug.message("IdUtils.getOrganization Exception in " 494 + "getting org name from SMS", smse); 495 } 496 Object[] args = { orgIdentifier }; 497 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.NO_MAPPING_FOUND, args); 498 } 499 } else if (ServiceManager.isCoexistenceMode()) { 500 // Return the org DN as determined by AMStoreConnection 501 if (debug.messageEnabled()) { 502 debug.message("IdUtils.getOrganization: getting from AMSDK"); 503 } 504 try { 505 AMStoreConnection amsc = new AMStoreConnection(token); 506 id = amsc.getOrganizationDN(orgIdentifier, null); 507 } catch (AMException ame) { 508 if (debug.messageEnabled()) { 509 debug.message("IdUtils.getOrganization Exception in " 510 + "getting org name from AMSDK", ame); 511 } 512 throw convertAMException(ame); 513 } 514 } else { 515 // Get the realm name from SMS 516 if (debug.messageEnabled()) { 517 debug.message("IdUtils.getOrganization: getting from " + 518 "SMS realms"); 519 } 520 try { 521 boolean foundOrg = false; 522 ServiceManager sm = new ServiceManager(token); 523 // First search for realms with orgIdentifier name 524 OrganizationConfigManager ocm = sm 525 .getOrganizationConfigManager("/"); 526 Set subOrgNames = ocm.getSubOrganizationNames(orgIdentifier, 527 true); 528 if (subOrgNames != null && !subOrgNames.isEmpty()) { 529 if (subOrgNames.size() == 1) { 530 id = DNMapper.orgNameToDN((String) subOrgNames 531 .iterator().next()); 532 foundOrg = true; 533 } else { 534 for (Iterator items = subOrgNames.iterator(); 535 items.hasNext();) { 536 // check for orgIdentifier 537 String subRealmName = (String) items.next(); 538 StringTokenizer st = new StringTokenizer( 539 subRealmName, "/"); 540 // Need to handle the scenario where multiple 541 // sub-realm with the same name should not be 542 // allowed 543 while (st.hasMoreTokens()) { 544 if (st.nextToken().equalsIgnoreCase( 545 orgIdentifier)) { 546 if (!foundOrg) { 547 id = DNMapper.orgNameToDN(subRealmName); 548 foundOrg = true; 549 } else { 550 Object[] args = {orgIdentifier}; 551 throw new IdRepoException(IdRepoBundle 552 .BUNDLE_NAME, IdRepoErrorCode.MULTIPLE_MAPPINGS_FOUND, args); 553 } 554 } 555 } 556 } 557 } 558 } 559 560 // Check if organization name has been determined 561 if (debug.messageEnabled()) { 562 debug.message("IdUtils.getOrganization: getting from " + 563 "SMS realms aliases"); 564 } 565 // perform organization alias search 566 Set vals = new HashSet(); 567 vals.add(orgIdentifier); 568 Set orgAliases = sm.searchOrganizationNames( 569 IdConstants.REPO_SERVICE, 570 IdConstants.ORGANIZATION_ALIAS_ATTR, vals); 571 if (!foundOrg && 572 ((orgAliases == null) || orgAliases.isEmpty())) { 573 if (debug.warningEnabled()) { 574 debug.warning("IdUtils.getOrganization Unable" + 575 " to find Org name for: " + orgIdentifier); 576 } 577 Object[] args = {orgIdentifier}; 578 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, 579 IdRepoErrorCode.NO_MAPPING_FOUND, args); 580 } else if ((orgAliases != null) && (orgAliases.size() > 0) && 581 (foundOrg || orgAliases.size() > 1)) { 582 // Multiple realms should not have the same alias 583 if (debug.warningEnabled()) { 584 debug.warning("IdUtils.getOrganization Multiple " + 585 " matching Orgs found for: " + orgIdentifier); 586 } 587 Object[] args = {orgIdentifier}; 588 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, 589 IdRepoErrorCode.MULTIPLE_MAPPINGS_FOUND, args); 590 } 591 if (!foundOrg) { 592 String tmpS = (String) orgAliases.iterator().next(); 593 id = DNMapper.orgNameToDN(tmpS); 594 } 595 } catch (SMSException smse) { 596 // debug message here. 597 if (debug.messageEnabled()) { 598 debug.message("IdUtils.getOrganization Exception in " 599 + "getting org name from SMS", smse); 600 } 601 Object[] args = { orgIdentifier }; 602 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.NO_MAPPING_FOUND, args); 603 } 604 } 605 606 if (debug.messageEnabled()) { 607 debug.message("IdUtils:getOrganization Search for OrgIdentifier:" + 608 orgIdentifier + " returning realm DN: " + id); 609 } 610 611 // Add to cache and return id 612 orgIdentifierToOrgName.put(orgIdentifier, id); 613 return id; 614 } 615 616 /** 617 * Clears the cache containing orgIdentifiers to organization names 618 */ 619 protected static void clearOrganizationNamesCache() { 620 orgIdentifierToOrgName.clear(); 621 orgStatusCache.clear(); 622 if (debug.messageEnabled()) { 623 debug.message("IdUtils.clearOrganizationNamesCache called"); 624 } 625 } 626 627 /** 628 * Returs true or false, depending on if this organization is enabled or 629 * not. The organization string passed to this method should be an 630 * identifier returned from the method 631 * <code> IdUtils.getOrganization </code>. In the default mode, where 632 * relams are enabled but backward comaptibility is required, this checks 633 * for organization status in the AM enabled Sun DS. Otherwise, it checks 634 * for organization status from the realms tree. 635 * 636 * @param token token SSOToken a valid SSOToken. 637 * @param org name of the organization of interest. 638 * @return <code>true</code> if org is active; 639 * otherwise <code>false</code> 640 * @throws IdRepoException if there are repository related error conditions. 641 * @throws SSOException If user's single sign on token is invalid. 642 */ 643 public static boolean isOrganizationActive(SSOToken token, String org) 644 throws IdRepoException, SSOException { 645 // Check the cache 646 if (orgStatusCache.containsKey(org)) { 647 return (((Boolean) orgStatusCache.get(org)).booleanValue()); 648 } 649 boolean isActive = true; 650 // Need to initialize ServiceManager by creating the constructor 651 if (!ServiceManager.isCoexistenceMode()) { 652 // Pick it up from the realms tree. 653 try { 654 OrganizationConfigManager ocm = new OrganizationConfigManager( 655 token, org); 656 if (ocm == null) { 657 Object[] args = { org }; 658 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.NO_MAPPING_FOUND, args); 659 } 660 Map attributes = ocm.getAttributes(IdConstants.REPO_SERVICE); 661 Set vals = (Set) attributes 662 .get(IdConstants.ORGANIZATION_STATUS_ATTR); 663 if (vals == null || vals.isEmpty()) { 664 isActive = true; 665 } else { 666 String stringActive = (String) vals.iterator().next(); 667 isActive = stringActive.equalsIgnoreCase("Active"); 668 } 669 } catch (SMSException smse) { 670 Object args[] = { org }; 671 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.NO_MAPPING_FOUND, args); 672 } 673 } else if (ServiceManager.isAMSDKEnabled()) { 674 // Return the org DN as determined by AMStoreConnection. 675 try { 676 AMStoreConnection amsc = new AMStoreConnection(token); 677 AMOrganization orgObj = amsc.getOrganization(org); 678 isActive = orgObj.isActivated(); 679 } catch (AMException ame) { 680 throw convertAMException(ame); 681 } 682 } 683 // Add to cache 684 orgStatusCache.put(org, isActive); 685 return isActive; 686 } 687 688 private static void initializeForGetIdentity() { 689 // Initialize root realm, if not already initalized 690 if (ROOT_SUFFIX == null) { 691 ROOT_SUFFIX = SMSEntry.getRootSuffix(); 692 StringBuilder sb = new StringBuilder(100); 693 sb.append(SMSEntry.SERVICES_RDN) 694 .append(SMSEntry.COMMA).append(ROOT_SUFFIX); 695 SERVICES_SUFFIX = DNUtils.normalizeDN(sb.toString()); 696 } 697 698 // Initialize organization and user naming attributes 699 if ((ORG_NAMING_ATTR == null) || (USER_NAMING_ATTR == null)) { 700 try { 701 ORG_NAMING_ATTR = AMStoreConnection.getNamingAttribute( 702 AMObject.ORGANIZATION).toLowerCase() + "="; 703 USER_NAMING_ATTR = AMStoreConnection.getNamingAttribute( 704 AMObject.USER).toLowerCase() + "="; 705 } catch (AMException ame) { 706 if (debug.warningEnabled()) { 707 debug.warning("IdUtils: unable to get naming " + 708 "attribute for org/user. Using \"o\"/\"uid\""); 709 } 710 ORG_NAMING_ATTR = "o="; 711 USER_NAMING_ATTR = "uid="; 712 } 713 } 714 } 715 716 private static void initializeSpecialUsers() { 717 // Populate special users 718 if (specialUsers.isEmpty()) { 719 String susers = SystemProperties.get( 720 Constants.AUTHENTICATION_SPECIAL_USERS, ""); 721 StringTokenizer st = new StringTokenizer( 722 susers, "|"); 723 while (st.hasMoreTokens()) { 724 specialUsers.add(DNUtils.normalizeDN(st.nextToken())); 725 } 726 susers = SystemProperties.get( 727 "com.sun.identity.authentication.super.user", ""); 728 specialUsers.add(DNUtils.normalizeDN(susers)); 729 } 730 } 731 732 /** 733 * Returns an IdRepoException based on an <code>AMException</code> 734 * 735 * @param ame 736 * @return IdRepoException based on ame. 737 */ 738 public static IdRepoException convertAMException(AMException ame) { 739 Object[] args = ame.getMessageArgs(); 740 String eCode = ame.getErrorCode(); 741 IdRepoException ide = null; 742 if (args == null) { 743 ide = new IdRepoException("amProfile", eCode, null); 744 } else { 745 ide = new IdRepoException("amProfile", ame.getErrorCode(), args); 746 } 747 ide.setLDAPErrorCode(ame.getLDAPErrorCode()); 748 return ide; 749 } 750 751 private static void loadDefaultTypes() { 752 supportedTypes.add(IdType.REALM); 753 supportedTypes.add(IdType.AGENT); 754 supportedTypes.add(IdType.USER); 755 supportedTypes.add(IdType.ROLE); 756 supportedTypes.add(IdType.GROUP); 757 supportedTypes.add(IdType.FILTEREDROLE); 758 mapSupportedTypes.put(IdType.REALM.getName(), IdType.REALM); 759 mapSupportedTypes.put(IdType.USER.getName(), IdType.USER); 760 mapSupportedTypes.put(IdType.ROLE.getName(), IdType.ROLE); 761 mapSupportedTypes.put(IdType.FILTEREDROLE.getName(), 762 IdType.FILTEREDROLE); 763 mapSupportedTypes.put(IdType.AGENT.getName(), IdType.AGENT); 764 mapSupportedTypes.put(IdType.GROUP.getName(), IdType.GROUP); 765 Set memberSet = new HashSet(); 766 memberSet.add(IdType.ROLE); 767 memberSet.add(IdType.GROUP); 768 memberSet.add(IdType.FILTEREDROLE); 769 typesCanBeMemberOf.put(IdType.USER.getName(), memberSet); 770 Set memberShipSet = new HashSet(); 771 memberShipSet.add(IdType.USER); 772 typesCanHaveMembers.put(IdType.ROLE.getName(), memberShipSet); 773 typesCanHaveMembers.put(IdType.GROUP.getName(), memberShipSet); 774 typesCanHaveMembers.put(IdType.FILTEREDROLE.getName(), memberShipSet); 775 typesCanAddMembers.put(IdType.GROUP.getName(), memberShipSet); 776 typesCanAddMembers.put(IdType.ROLE.getName(), memberShipSet); 777 } 778 779 private static Set getMemberSet(Set members) { 780 Set memberSet = new HashSet(members.size() * 2); 781 for (Iterator iter = members.iterator(); iter.hasNext();) { 782 String currType = (String) iter.next(); 783 memberSet.add(new IdType(currType)); 784 } 785 return memberSet; 786 } 787 788 /** 789 * Returns the user name extracted from the uuid 790 * if the orgName supplied in the parameter is 791 * not same realm name in uuid then <code>IdRepoException</code> 792 * is thrown 793 * 794 * @param uuid uuid of the user 795 * @param orgName the org user is trying to login to 796 * @return user name 797 * @throws IdRepoException 798 */ 799 public static String getIdentityName(String uuid, String orgName) 800 throws IdRepoException { 801 String username = uuid; 802 // Check uuid 803 if ((uuid != null) && uuid.toLowerCase().startsWith("id=")) { 804 // Could be universal id, get the identity object 805 AMIdentity id = new AMIdentity(null, uuid); 806 username = id.getName(); 807 // Check the realm names 808 String realm = DNUtils.normalizeDN(id.getRealm()); 809 if (!DNUtils.normalizeDN(orgName).equals(realm)) { 810 Object[] args = {uuid, orgName}; 811 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.REALM_NAME_NOT_MATCH_AUTHENTICATION_REALM, 812 args); 813 } 814 } 815 return (username); 816 } 817 818 /** 819 * Gets the AMIdentity of a user with username equal to uName that exists in realm 820 * 821 * @param uName username of the user to get. 822 * @param realm realm the user belongs to. 823 * @return The AMIdentity of user with username equal to uName. 824 */ 825 public static AMIdentity getIdentity(String uName, String realm) { 826 AMIdentity theID = null; 827 828 AMIdentityRepository amIdRepo = getAMIdentityRepository(DNMapper.orgNameToDN(realm)); 829 830 IdSearchControl idsc = new IdSearchControl(); 831 idsc.setRecursive(true); 832 idsc.setAllReturnAttributes(true); 833 // search for the identity 834 Set<AMIdentity> results = Collections.EMPTY_SET; 835 try { 836 idsc.setMaxResults(0); 837 IdSearchResults searchResults = amIdRepo.searchIdentities(IdType.USER, uName, idsc); 838 if (searchResults != null) { 839 results = searchResults.getSearchResults(); 840 } 841 842 if (results == null || results.size() != 1) { 843 throw new IdRepoException("IdUtils" + 844 ".getIdentity : " + 845 "More than one user found"); 846 } 847 theID = results.iterator().next(); 848 } catch (IdRepoException e) { 849 debug.warning("Error searching for user identity"); 850 } catch (SSOException e) { 851 debug.warning("User's ssoToken has expired"); 852 } 853 return theID; 854 } 855 856 /** 857 * Returns <code>AMIdentityRepostiory</code> handle for an organization. 858 * 859 * @param orgDN the organization name. 860 * @return <code>AMIdentityRepostiory</code> object 861 */ 862 public static AMIdentityRepository getAMIdentityRepository(String orgDN) { 863 return AuthD.getAuth().getAMIdentityRepository(orgDN); 864 } 865 866 // SMS service listener to reinitialize if IdRepo service changes 867 static class IdUtilsListener implements com.sun.identity.sm.ServiceListener 868 { 869 public void schemaChanged(String serviceName, String version) { 870 initialize(); 871 } 872 873 public void globalConfigChanged(String serviceName, String version, 874 String groupName, String serviceComponent, int type) { 875 initialize(); 876 clearOrganizationNamesCache(); 877 } 878 879 public void organizationConfigChanged(String serviceName, 880 String version, String orgName, String groupName, 881 String serviceComponent, int type) { 882 clearOrganizationNamesCache(); 883 } 884 } 885 886}