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: AMIdentity.java,v 1.37 2009/11/20 23:52:54 ww203982 Exp $ 026 * 027 * Portions Copyrighted 2011-2015 ForgeRock AS. 028 */ 029package com.sun.identity.idm; 030 031import java.util.Collections; 032import java.util.HashMap; 033import java.util.HashSet; 034import java.util.Iterator; 035import java.util.Map; 036import java.util.Set; 037 038import com.iplanet.am.sdk.AMCommonUtils; 039import com.iplanet.am.sdk.AMCrypt; 040import com.iplanet.am.sdk.AMHashMap; 041import com.iplanet.sso.SSOException; 042import com.iplanet.sso.SSOToken; 043import com.sun.identity.common.CaseInsensitiveHashMap; 044import com.sun.identity.common.CaseInsensitiveHashSet; 045import com.sun.identity.idm.common.IdRepoUtils; 046import com.sun.identity.shared.Constants; 047import com.sun.identity.shared.debug.Debug; 048import com.sun.identity.sm.DNMapper; 049import com.sun.identity.sm.SMSException; 050import com.sun.identity.sm.SchemaType; 051import com.sun.identity.sm.ServiceManager; 052import com.sun.identity.sm.ServiceNotFoundException; 053import com.sun.identity.sm.ServiceSchema; 054import com.sun.identity.sm.ServiceSchemaManager; 055import org.forgerock.i18n.LocalizedIllegalArgumentException; 056import org.forgerock.openam.ldap.LDAPUtils; 057import org.forgerock.opendj.ldap.DN; 058import org.forgerock.opendj.ldap.RDN; 059 060/** 061 * This class represents an Identity which needs to be managed by Access 062 * Manager. This identity could exist in multiple repositories, which are 063 * configured for a given realm or organization. When any operation is performed 064 * from this class, it executes all plugins that are configured for performing 065 * that operation. For eg: getAttributes. The application gets access to 066 * constructing <code> AMIdentity </code> objects by using 067 * <code> AMIdentityRepository 068 * </code> interfaces. For example: 069 * <p> 070 * 071 * <PRE> 072 * 073 * AMIdentityRepository idrepo = new AMIdentityRepository(token, org); 074 * AMIdentity id = idrepo.getRealmIdentity(); 075 * 076 * </PRE> 077 * 078 * The <code>id</code> returned above is the AMIdentity object of the user's 079 * single sign-on token passed above. The results obtained from search performed 080 * using AMIdentityRepository also return AMIdentity objects. The type of an 081 * object can be determined by doing the following: 082 * <p> 083 * 084 * <PRE> 085 * 086 * IdType type = identity.getType(); 087 * 088 * </PRE> 089 * 090 * The name of an object can be determined by: 091 * <p> 092 * 093 * <PRE> 094 * 095 * String name = identity.getName(); 096 * 097 * </PRE> 098 * 099 * @supported.api 100 */ 101 102public class AMIdentity { 103 104 private String univIdWithoutDN; 105 106 private final SSOToken token; 107 108 private final String name; 109 110 private final IdType type; 111 112 private final String orgName; 113 114 private Set fullyQualifiedNames; 115 116 private final AMHashMap modMap = new AMHashMap(false); 117 118 private final AMHashMap binaryModMap = new AMHashMap(true); 119 120 protected String univDN = null; 121 122 /** 123 * @supported.api 124 * 125 * Constructor for the <code>AMIdentity</code> object. 126 * 127 * @param ssotoken 128 * Single sign on token of the user 129 * @throws SSOException 130 * if user's single sign on token is invalid. 131 * @throws IdRepoException 132 * if the single sign on token does not have a 133 * a valid universal identifier 134 */ 135 public AMIdentity(SSOToken ssotoken) throws SSOException, IdRepoException { 136 this(ssotoken, ssotoken.getProperty(Constants.UNIVERSAL_IDENTIFIER)); 137 } 138 139 /** 140 * @supported.api 141 * 142 * Constructor for the <code>AMIdentity</code> object. 143 * 144 * @param ssotoken 145 * Single sign on token to construct the identity 146 * object. Access permission to Identity object 147 * would be based on this user 148 * @param universalId 149 * Universal Identifier of the identity. 150 * 151 * @throws IdRepoException 152 * if the universal identifier is invalid 153 * 154 */ 155 public AMIdentity(SSOToken ssotoken, String universalId) 156 throws IdRepoException { 157 this(universalId == null ? null : LDAPUtils.newDN(universalId), ssotoken); 158 } 159 160 public AMIdentity(DN universalId, SSOToken ssotoken) throws IdRepoException { 161 this.token = ssotoken; 162 // Validate Universal ID 163 if (universalId == null || universalId.size() < 3 || !"id".equalsIgnoreCase(LDAPUtils.rdnTypeFromDn(universalId))) { 164 // Not a valid UUID since it should have the 165 // name, type and realm components 166 Object args[] = { universalId }; 167 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.ILLEGAL_UNIVERSAL_IDENTIFIER, args); 168 } 169 170 // Valid UUID, construct rest of the parameters 171 univIdWithoutDN = universalId.toString(); 172 173 // Check for AMSDK DN 174 int index; 175 if ((index = univIdWithoutDN.toLowerCase().indexOf(",amsdkdn=")) != -1) { 176 // obtain DN and univIdWithoutDN 177 univDN = univIdWithoutDN.substring(index + 9); 178 univIdWithoutDN = univIdWithoutDN.substring(0, index); 179 universalId = DN.valueOf(univIdWithoutDN); 180 } 181 name = LDAPUtils.rdnValue(universalId.rdn()); 182 type = new IdType(LDAPUtils.rdnValue(universalId.parent().rdn())); 183 orgName = universalId.parent().parent().toString(); 184 } 185 186 /** 187 * Constructor for the <code>AMIdentity</code> object. 188 * 189 * @param token 190 * Single sign on token to construct the identity 191 * object. Access permission to Identity object 192 * would be based on this user 193 * @param name 194 * the name associated with this identity. 195 * @param type 196 * the <code>IdType</code> of this identity. 197 * @param orgName 198 * the organizaton name this identity belongs to. 199 * @param amsdkdn 200 * the amsdk name assoicated with this identity if any. 201 */ 202 public AMIdentity(SSOToken token, String name, IdType type, String orgName, String amsdkdn) { 203 this(amsdkdn == null ? null : DN.valueOf(amsdkdn), token, name, type, orgName); 204 } 205 206 public AMIdentity(DN amsdkdn, SSOToken token, String name, IdType type, String orgName) { 207 this.name = name; 208 this.type = type; 209 this.orgName = DNMapper.orgNameToDN(orgName); 210 this.token = token; 211 if (amsdkdn != null && amsdkdn.size() > 0) { 212 this.univDN = amsdkdn.toString(); 213 } 214 215 if (LDAPUtils.isDN(name)) { 216 name = LDAPUtils.rdnValueFromDn(name); 217 } 218 219 try { 220 univIdWithoutDN = LDAPUtils.newDN(this.orgName) 221 .child(new RDN("ou", type.getName())) 222 .child(new RDN("id", name)) 223 .toString(); 224 } catch (LocalizedIllegalArgumentException e) { 225 throw new IllegalArgumentException("Cannot parse orgName: " + orgName, e); 226 } 227 } 228 229 // General APIs 230 /** 231 * 232 * Returns the name of the identity. 233 * 234 * @return Name of the identity 235 * @supported.api 236 */ 237 public String getName() { 238 String sname = name; 239 if (type.equals(IdType.REALM)) { 240 // Since '0'th location currently has ContainerDefaultTemplate 241 // the 2nd location would have the realm name 242 sname = LDAPUtils.rdnValue(DN.valueOf(univIdWithoutDN).parent().parent().rdn()); 243 } 244 return sname; 245 } 246 247 /** 248 * Returns the Type of the Identity. 249 * 250 * @return <code>IdType</code> representing the type of this object. 251 * @supported.api 252 */ 253 public IdType getType() { 254 return type; 255 } 256 257 /** 258 * Returns the realm for this identity. 259 * 260 * @return String representing realm name. 261 * @supported.api 262 */ 263 public String getRealm() { 264 return orgName; 265 } 266 267 /** 268 * If there is a status attribute configured, then verifies if the identity 269 * is active and returns true. This method is only valid for AMIdentity 270 * objects of type User and Agent. 271 * 272 * @return true if the identity is active or if it is not configured for a 273 * status attribute, false otherwise. 274 * @throws IdRepoException 275 * If there are repository related error conditions. 276 * @throws SSOException 277 * If user's single sign on token is invalid. 278 * @supported.api 279 */ 280 public boolean isActive() throws IdRepoException, SSOException { 281 IdServices idServices = IdServicesFactory.getDataStoreServices(); 282 return idServices.isActive(token, type, name, orgName, univDN); 283 } 284 285 /** 286 * If there is a status attribute configured, then set its status to 287 * true or activated state if the parameter active is true. 288 * This method is only valid for AMIdentity objects of type User and Agent. 289 * 290 * @param active The state value to assign to status attribute. The actual 291 * value assigned to the status attribute will depend on what is configured 292 * for that particular plugin. If active is true, the status will be 293 * assigned the value corresponding to activated. 294 * @throws IdRepoException If there are repository related error conditions. 295 * @throws SSOException If user's single sign on token is invalid. 296 * @supported.api 297 */ 298 public void setActiveStatus(boolean active) 299 throws IdRepoException, SSOException { 300 IdServices idServices = 301 IdServicesFactory.getDataStoreServices(); 302 idServices.setActiveStatus(token, type, name, orgName, univDN, active); 303 } 304 305 /** 306 * Returns all attributes and values of this identity. This method is only 307 * valid for AMIdentity objects of type User, Agent, Group, and Role. 308 * 309 * @return Map of attribute-values 310 * @throws IdRepoException 311 * If there are repository related error conditions. 312 * @throws SSOException 313 * If user's single sign on token is invalid. 314 * @supported.api 315 */ 316 public Map getAttributes() throws IdRepoException, SSOException { 317 318 IdServices idServices = IdServicesFactory.getDataStoreServices(); 319 Map attrs = idServices 320 .getAttributes(token, type, name, orgName, univDN); 321 if (debug.messageEnabled()) { 322 debug.message("AMIdentity.getAttributes all: attrs=" + 323 IdRepoUtils.getAttrMapWithoutPasswordAttrs(attrs, null)); 324 } 325 return attrs; 326 } 327 328 /** 329 * Returns requested attributes and values of this object. 330 * 331 * This method is only valid for AMIdentity object of type User, Agent, 332 * Group, and Role. 333 * 334 * @param attrNames 335 * Set of attribute names to be read 336 * @return Map of attribute-values. 337 * @throws IdRepoException 338 * If there are repository related error conditions. 339 * @throws SSOException 340 * If user's single sign on token is invalid. 341 * @supported.api 342 */ 343 public Map getAttributes(Set attrNames) throws IdRepoException, 344 SSOException { 345 346 IdServices idServices = IdServicesFactory.getDataStoreServices(); 347 Map attrs = idServices.getAttributes(token, type, name, attrNames, 348 orgName, univDN, true); 349 CaseInsensitiveHashMap caseAttrs = new CaseInsensitiveHashMap(attrs); 350 CaseInsensitiveHashMap resultMap = new CaseInsensitiveHashMap(); 351 Iterator it = attrNames.iterator(); 352 while (it.hasNext()) { 353 String attrName = (String) it.next(); 354 if (caseAttrs.containsKey(attrName)) { 355 resultMap.put(attrName, caseAttrs.get(attrName)); 356 } 357 } 358 359 if (debug.messageEnabled()) { 360 debug.message("AMIdentity.getAttributes 6: attrNames=" + attrNames 361 + "; resultMap=" + resultMap + "; attrs=" + attrs); 362 } 363 return resultMap; 364 } 365 366 /** 367 * Returns requested attributes and values of this object. 368 * 369 * This method is only valid for AMIdentity objects of type User, Agent, 370 * Group, and Role. 371 * 372 * @param attrNames 373 * Set of attribute names to be read 374 * @return Map of attribute-values. 375 * @throws IdRepoException 376 * If there are repository related error conditions. 377 * @throws SSOException 378 * If user's single sign on token is invalid. 379 * @supported.api 380 */ 381 public Map getBinaryAttributes(Set attrNames) throws IdRepoException, 382 SSOException { 383 384 IdServices idServices = IdServicesFactory.getDataStoreServices(); 385 return idServices.getAttributes(token, type, name, attrNames, orgName, 386 univDN, false); 387 } 388 389 /** 390 * Returns the values of the requested attribute. Returns an empty set, if 391 * the attribute is not set in the object. 392 * 393 * This method is only valid for AMIdentity objects of type User, Agent, 394 * Group, and Role. 395 * 396 * @param attrName 397 * Name of attribute 398 * @return Set of attribute values. 399 * @throws IdRepoException 400 * if there are repository related error conditions. 401 * @throws SSOException 402 * If user's single sign on token is invalid. 403 * @supported.api 404 */ 405 public Set getAttribute(String attrName) throws IdRepoException, 406 SSOException { 407 408 Set attrNames = new HashSet(); 409 attrNames.add(attrName); 410 IdServices idServices = IdServicesFactory.getDataStoreServices(); 411 Map valMap = idServices.getAttributes(token, type, name, attrNames, 412 orgName, univDN, true); 413 return ((Set) valMap.get(attrName)); 414 } 415 416 /** 417 * Sets the values of attributes. This method should be followed by the 418 * method "store" to commit the changes to the Repository. 419 * This method is only valid for <code>AMIdentity</code> objects of 420 * type User and Agent. 421 * 422 * @param attrMap is a map of attribute name 423 * <code>(String)</code> 424 * to a <code>Set</code> of attribute values <code>(String)</code>. 425 * It is arranged as: 426 * Map::attrMap --> 427 * Key: String::AttributeName 428 * Value: Set::AttributeValues (Set of String) 429 * @throws IdRepoException 430 * If there are repository related error conditions. 431 * @throws SSOException 432 * If user's single sign on token is invalid. 433 * @supported.api 434 */ 435 public void setAttributes(Map attrMap) throws IdRepoException, SSOException 436 { 437 modMap.copy(attrMap); 438 } 439 440 /** 441 * Changes password for the identity. 442 * 443 * @param oldPassword old password 444 * @param newPassword new password 445 * @throws IdRepoException If there are repository related error conditions. 446 * @throws SSOException If user's single sign on token is invalid. 447 * @supported.api 448 */ 449 public void changePassword(String oldPassword, String newPassword) 450 throws IdRepoException, SSOException { 451 452 IdServices idServices = IdServicesFactory.getDataStoreServices(); 453 idServices.changePassword(token, type, name, oldPassword, 454 newPassword, orgName, getDN()); 455 } 456 457 /** 458 * Set the values of binary attributes. This method should be followed by 459 * the method "store" to commit the changes to the Repository 460 * 461 * This method is only valid for AMIdentity objects of type User and Agent. 462 * 463 * @param attrMap 464 * Map of attribute-values to be set in the repository or 465 * repositories (if multiple plugins are configured for "edit"). 466 * @throws IdRepoException 467 * If there are repository related error conditions. 468 * @throws SSOException 469 * If user's single sign on token is invalid. 470 * @supported.api 471 */ 472 public void setBinaryAttributes(Map attrMap) throws IdRepoException, 473 SSOException { 474 binaryModMap.copy(attrMap); 475 } 476 477 /** 478 * Removes the attributes from the identity entry. This method should be 479 * followed by a "store" to commit the changes to the Repository. 480 * 481 * This method is only valid for AMIdentity objects of type User and Agent. 482 * 483 * @param attrNames 484 * Set of attribute names to be removed 485 * @throws IdRepoException 486 * If there are repository related error conditions. 487 * @throws SSOException 488 * If the user's single sign on token is invalid 489 * @supported.api 490 */ 491 public void removeAttributes(Set attrNames) throws IdRepoException, 492 SSOException { 493 if (attrNames == null || attrNames.isEmpty()) { 494 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.ILLEGAL_ARGUMENTS, null); 495 } 496 497 boolean agentflg = getType().equals(IdType.AGENTONLY); 498 if (agentflg) { 499 IdServices idServices = IdServicesFactory.getDataStoreServices(); 500 idServices.removeAttributes(token, type, name, attrNames, 501 orgName, null); 502 Iterator it = attrNames.iterator(); 503 while (it.hasNext()) { 504 String attr = (String) it.next(); 505 modMap.remove(attr); 506 } 507 } else { 508 Iterator it = attrNames.iterator(); 509 while (it.hasNext()) { 510 String attr = (String) it.next(); 511 modMap.put(attr, Collections.EMPTY_SET); 512 } 513 } 514 } 515 516 /** 517 * Stores the attributes of the object. 518 * 519 * This method is only valid for AMIdentity objects of type User and Agent. 520 * 521 * @throws IdRepoException 522 * If there are repository related error conditions. 523 * @throws SSOException 524 * If user's single sign on token is invalid. 525 * @supported.api 526 */ 527 public void store() throws IdRepoException, SSOException { 528 IdServices idServices = IdServicesFactory.getDataStoreServices(); 529 if (modMap != null && !modMap.isEmpty()) { 530 idServices.setAttributes(token, type, name, modMap, false, orgName, 531 univDN, true); 532 modMap.clear(); 533 } 534 if (binaryModMap != null && !binaryModMap.isEmpty()) { 535 idServices.setAttributes(token, type, name, binaryModMap, false, 536 orgName, univDN, false); 537 binaryModMap.clear(); 538 } 539 } 540 541 // SERVICE RELATED APIS 542 543 /** 544 * Returns the set of services already assigned to this identity. 545 * 546 * This method is only valid for AMIdentity object of type User. 547 * 548 * @return Set of serviceNames 549 * @throws IdRepoException 550 * If there are repository related error conditions. 551 * @throws SSOException 552 * If user's single sign on token is invalid. 553 * @supported.api 554 */ 555 public Set getAssignedServices() throws IdRepoException, SSOException { 556 // Get all service names for the type from SMS 557 ServiceManager sm; 558 try { 559 sm = new ServiceManager(token); 560 } catch (SMSException smse) { 561 debug.error("Error while creating Service manager:", smse); 562 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode 563 .SERVICE_MANAGER_INITIALIZATION_FAILED, null); 564 } 565 Map sMap = sm.getServiceNamesAndOCs(type.getName()); 566 567 // Get the list of assigned services 568 IdServices idServices = IdServicesFactory.getDataStoreServices(); 569 Set assigned = Collections.EMPTY_SET; 570 try { 571 assigned = idServices.getAssignedServices(token, type, name, sMap, 572 orgName, univDN); 573 } catch (IdRepoException ide) { 574 // Check if this is permission denied exception 575 if (!ide.getErrorCode().equals(IdRepoErrorCode.ACCESS_DENIED)) { 576 throw (ide); 577 } 578 } 579 return (assigned); 580 } 581 582 /** 583 * Returns all services which can be assigned to this entity. 584 * 585 * This method is only valid for AMIdentity object of type User. 586 * 587 * @return Set of service names 588 * @throws IdRepoException 589 * if there are repository related error conditions. 590 * @throws SSOException 591 * If user's single sign on token is invalid. 592 * @supported.api 593 */ 594 public Set getAssignableServices() throws IdRepoException, SSOException { 595 // Get all service names for the type from SMS 596 ServiceManager sm; 597 try { 598 sm = new ServiceManager(token); 599 } catch (SMSException smse) { 600 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode 601 .SERVICE_MANAGER_INITIALIZATION_FAILED, null); 602 } 603 Map sMap = sm.getServiceNamesAndOCs(type.getName()); 604 605 // Get the list of assigned services 606 IdServices idServices = IdServicesFactory.getDataStoreServices(); 607 Set assigned = Collections.EMPTY_SET; 608 try { 609 assigned = idServices.getAssignedServices(token, type, name, sMap, 610 orgName, univDN); 611 } catch (IdRepoException ide) { 612 // Check if this is permission denied exception 613 if (!ide.getErrorCode().equals(IdRepoErrorCode.ACCESS_DENIED)) { 614 throw (ide); 615 } else { 616 // Return the empty set 617 return (assigned); 618 } 619 } 620 621 // Return the difference 622 Set keys = sMap.keySet(); 623 keys.removeAll(assigned); 624 return (keys); 625 626 } 627 628 /** 629 * Assigns the service and service related attributes to the identity. 630 * 631 * This method is only valid for AMIdentity object of type User. 632 * 633 * @param serviceName 634 * Name of service to be assigned. 635 * @param attributes 636 * Map of attribute-values 637 * @throws IdRepoException 638 * If there are repository related error conditions. 639 * @throws SSOException 640 * If user's single sign on token is invalid. 641 * @supported.api 642 */ 643 public void assignService(String serviceName, Map attributes) 644 throws IdRepoException, SSOException { 645 646 IdServices idServices = IdServicesFactory.getDataStoreServices(); 647 Set OCs = getServiceOCs(token, serviceName); 648 SchemaType stype; 649 Map tMap = new HashMap(); 650 tMap.put(serviceName, OCs); 651 Set assignedServices = idServices.getAssignedServices(token, type, 652 name, tMap, orgName, univDN); 653 654 if (assignedServices.contains(serviceName)) { 655 Object args[] = { serviceName, type.getName() }; 656 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_ALREADY_ASSIGNED, args); 657 } 658 659 // Validate the service attributes 660 try { 661 ServiceSchemaManager ssm = new ServiceSchemaManager(serviceName, 662 token); 663 ServiceSchema ss = ssm.getSchema(type.getName()); 664 665 if (ss != null) { 666 // Check if attrMap has cos priority attribute 667 // If present, remove it for validating the attributes 668 Set cosPriority = (attributes != null) ? 669 (Set)attributes.remove(COS_PRIORITY) : null; 670 attributes = ss.validateAndInheritDefaults(attributes, orgName, 671 true); 672 if (cosPriority != null) { 673 attributes.put(COS_PRIORITY, cosPriority); 674 } 675 attributes = AMCommonUtils.removeEmptyValues(attributes); 676 stype = ss.getServiceType(); 677 } else { 678 ss = ssm.getSchema(SchemaType.DYNAMIC); 679 if (ss == null) { 680 Object args[] = { serviceName }; 681 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.UNABLE_GET_SERVICE_SCHEMA, 682 args); 683 } 684 if (attributes == null) { 685 try { 686 attributes = getServiceConfig(token, serviceName, 687 SchemaType.DYNAMIC); 688 } catch (SMSException smsex) { 689 Object args[] = { serviceName, type.getName() }; 690 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, 691 "451", args); 692 } 693 } else { 694 attributes = ss.validateAndInheritDefaults(attributes, 695 orgName, true); 696 } 697 attributes = AMCommonUtils.removeEmptyValues(attributes); 698 stype = SchemaType.DYNAMIC; 699 } 700 701 // TODO: Remove this dependency of AMCrypt 702 attributes = AMCrypt.encryptPasswords(attributes, ss); 703 } catch (SMSException smse) { 704 // debug.error here 705 Object[] args = { serviceName }; 706 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_NOT_ASSIGNED, args); 707 } 708 709 attributes.put("objectclass", OCs); 710 // The protocol for params is to pass the 711 // name of the service, and attribute Map containing the 712 // OCs to be set and validated attribute map 713 idServices.assignService(token, type, name, serviceName, stype, 714 attributes, orgName, univDN); 715 } 716 717 /** 718 * Removes a service from the identity. 719 * 720 * This method is only valid for AMIdentity object of type User. 721 * 722 * @param serviceName 723 * Name of service to be removed. 724 * @throws IdRepoException 725 * If there are repository related error conditions. 726 * @throws SSOException 727 * If user's single sign on token is invalid. 728 * @supported.api 729 */ 730 public void unassignService(String serviceName) throws IdRepoException, 731 SSOException { 732 IdServices idServices = IdServicesFactory.getDataStoreServices(); 733 Set OCs = getServiceOCs(token, serviceName); 734 735 Map tMap = new HashMap(); 736 tMap.put(serviceName, OCs); 737 Set assignedServices = idServices.getAssignedServices(token, type, 738 name, tMap, orgName, univDN); 739 740 if (!assignedServices.contains(serviceName)) { 741 Object args[] = { serviceName }; 742 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_NOT_ASSIGNED, args); 743 } 744 745 Map attrMap = new HashMap(); 746 Set objectclasses = getAttribute("objectclass"); 747 if (objectclasses != null && !objectclasses.isEmpty()) { 748 Set removeOCs = AMCommonUtils.updateAndGetRemovableOCs( 749 objectclasses, OCs); 750 751 try { 752 // Get attribute names for USER type only, so plugin knows 753 // what attributes to remove. 754 Set attrNames = new HashSet(); 755 ServiceSchemaManager ssm = new ServiceSchemaManager( 756 serviceName, token); 757 ServiceSchema uss = ssm.getSchema(type.getName()); 758 759 if (uss != null) { 760 attrNames = uss.getAttributeSchemaNames(); 761 } 762 763 Iterator it = attrNames.iterator(); 764 while (it.hasNext()) { 765 String a = (String) it.next(); 766 attrMap.put(a, Collections.EMPTY_SET); 767 } 768 } catch (SMSException smse) { 769 /* 770 * debug.error( "AMIdentity.unassignService: Caught SM 771 * exception", smse); do nothing 772 */ 773 } 774 775 attrMap.put("objectclass", removeOCs); 776 // The protocol is to pass service Name and Map of objectclasses 777 // to be removed from entry. 778 } 779 780 idServices.unassignService(token, type, name, serviceName, attrMap, 781 orgName, univDN); 782 } 783 784 /** 785 * Returns attributes related to a service, if the service is assigned to 786 * the identity. 787 * 788 * This method is only valid for AMIdentity object of type User. 789 * 790 * @param serviceName 791 * Name of the service. 792 * @return Map of attribute-values. 793 * @throws IdRepoException 794 * if there are repository related error conditions. 795 * @throws SSOException 796 * If user's single sign on token is invalid. 797 * @supported.api 798 */ 799 public Map getServiceAttributes(String serviceName) 800 throws IdRepoException, SSOException { 801 Set attrNames = getServiceAttributesName(serviceName); 802 803 IdServices idServices = 804 IdServicesFactory.getDataStoreServices(); 805 if (debug.messageEnabled()) { 806 debug.message("AMIdentity.getServiceAttributes: attrNames=" 807 + attrNames + "; orgName=" + orgName + "; univDN=" + univDN); 808 } 809 return idServices.getServiceAttributes(token, type, name, serviceName, 810 attrNames, orgName, univDN); 811 } 812 813 814 /** 815 * Returns attributes related to a service, if the service is assigned 816 * to the identity. 817 * 818 * This method is only valid for AMIdentity object of type User. 819 * 820 * @param serviceName Name of the service. 821 * @return Map of attribute-values in array of byte. 822 * @throws IdRepoException if there are repository related error conditions. 823 * @throws SSOException If user's single sign on token is invalid. 824 * iPlanet-PUBLIC-METHOD 825 */ 826 public Map getBinaryServiceAttributes(String serviceName) 827 throws IdRepoException, SSOException { 828 Set attrNames = getServiceAttributesName(serviceName); 829 830 IdServices idServices = 831 IdServicesFactory.getDataStoreServices(); 832 if (debug.messageEnabled()) { 833 debug.message("AMIdentity.getBinaryServiceAttributes: attrNames=" 834 + attrNames + "; orgName=" + orgName + "; univDN=" + univDN); 835 } 836 return idServices.getBinaryServiceAttributes(token, type, name, 837 serviceName, attrNames, orgName, univDN); 838 } 839 840 841 /** 842 * Returns attributes related to a service, if the service is assigned 843 * to the identity. 844 * 845 * This method is only valid for AMIdentity object of type User. 846 * 847 * @param serviceName Name of the service. 848 * @return Map of attribute-values. 849 * @throws IdRepoException if there are repository related error conditions. 850 * @throws SSOException If user's single sign on token is invalid. 851 * @supported.api 852 */ 853 public Map getServiceAttributesAscending(String serviceName) 854 throws IdRepoException, SSOException { 855 Set attrNames = getServiceAttributesName(serviceName); 856 857 IdServices idServices = 858 IdServicesFactory.getDataStoreServices(); 859 if (debug.messageEnabled()) { 860 debug.message("AMIdentity.getServiceAttributesAscending: " 861 + "attrNames=" + attrNames + "; orgName=" + orgName 862 + "; univDN=" + univDN); 863 } 864 return idServices.getServiceAttributesAscending(token, type, name, 865 serviceName, attrNames, orgName, univDN); 866 } 867 868 869 /** 870 * Set attributes related to a specific service. The assumption is that the 871 * service is already assigned to the identity. The attributes for the 872 * service are validated against the service schema. 873 * 874 * This method is only valid for AMIdentity object of type User. 875 * 876 * @param serviceName 877 * Name of the service. 878 * @param attrMap 879 * Map of attribute-values. 880 * @throws IdRepoException 881 * If there are repository related error conditions. 882 * @throws SSOException 883 * If user's single sign on token is invalid. 884 * @supported.api 885 */ 886 public void modifyService(String serviceName, Map attrMap) 887 throws IdRepoException, SSOException { 888 IdServices idServices = IdServicesFactory.getDataStoreServices(); 889 Set OCs = getServiceOCs(token, serviceName); 890 SchemaType stype; 891 Map tMap = new HashMap(); 892 tMap.put(serviceName, OCs); 893 Set assignedServices = idServices.getAssignedServices(token, type, 894 name, tMap, orgName, univDN); 895 if (!assignedServices.contains(serviceName)) { 896 Object args[] = { serviceName }; 897 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.SERVICE_NOT_ASSIGNED, args); 898 } 899 900 // Check if attrMap has cos priority attribute 901 // If present, remove it for validating the attributes 902 boolean hasCosPriority = (new CaseInsensitiveHashSet( 903 attrMap.keySet()).contains(COS_PRIORITY)); 904 Object values = null; 905 if (hasCosPriority) { 906 attrMap = new CaseInsensitiveHashMap(attrMap); 907 values = attrMap.remove(COS_PRIORITY); 908 } 909 910 // Validate the attributes 911 try { 912 ServiceSchemaManager ssm = new ServiceSchemaManager(serviceName, 913 token); 914 ServiceSchema ss = ssm.getSchema(type.getName()); 915 if (ss != null) { 916 attrMap = ss.validateAndInheritDefaults(attrMap, false); 917 stype = ss.getServiceType(); 918 } else if ((ss = ssm.getSchema(SchemaType.DYNAMIC)) != null) { 919 attrMap = ss.validateAndInheritDefaults(attrMap, false); 920 stype = SchemaType.DYNAMIC; 921 } else { 922 Object args[] = { serviceName }; 923 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, 924 IdRepoErrorCode.UNABLE_GET_SERVICE_SCHEMA, args); 925 } 926 } catch (SMSException smse) { 927 // debug.error 928 Object args[] = { serviceName }; 929 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.DATA_INVALID_FOR_SERVICE, args); 930 } 931 932 // Add COS priority if present 933 if (hasCosPriority) { 934 attrMap.put(COS_PRIORITY, values); 935 } 936 937 // modify service attrs 938 if (debug.messageEnabled()) { 939 debug.message("AMIdentity.modifyService befre idService " + 940 "serviceName=" + serviceName + "; attrMap=" + attrMap); 941 } 942 idServices.modifyService(token, type, name, serviceName, stype, 943 attrMap, orgName, univDN); 944 } 945 946 947 /** 948 949 * Removes attributes value related to a specific service by 950 * setting it to empty. 951 * The assumption is that the service is already assigned to 952 * the identity. The attributes for the service are validated 953 * against the service schema. 954 * 955 * This method is only valid for <AMIdentity> object of type User. 956 * 957 * @param serviceName Name of the service. 958 * @param attrNames Set of attributes name. 959 * @throws IdRepoException If there are repository related error conditions. 960 * @throws SSOException If user's single sign on token is invalid. 961 * @supported.api 962 */ 963 public void removeServiceAttributes(String serviceName, Set attrNames) 964 throws IdRepoException, SSOException { 965 Map attrMap = new HashMap(attrNames.size() *2); 966 Iterator it = attrNames.iterator(); 967 while (it.hasNext()) { 968 String attrName = (String) it.next(); 969 attrMap.put(attrName, Collections.EMPTY_SET); 970 } 971 modifyService(serviceName, attrMap); 972 } 973 974 975 // MEMBERSHIP RELATED APIS 976 /** 977 * Verifies if this identity is a member of the identity being passed. 978 * 979 * This method is only valid for AMIdentity objects of type Role, Group and 980 * User. 981 * 982 * @param identity 983 * <code>AMIdentity</code> to check membership with 984 * @return true if this Identity is a member of the given Identity 985 * @throws IdRepoException 986 * if there are repository related error conditions. 987 * @throws SSOException 988 * if user's single sign on token is invalid. 989 * @supported.api 990 */ 991 public boolean isMember(AMIdentity identity) throws IdRepoException, 992 SSOException { 993 boolean ismember = false; 994 IdRepoException idException = null; 995 IdServices idServices = IdServicesFactory.getDataStoreServices(); 996 try { 997 //This method should always retrieve all the membership information a user could possibly have (either 998 //through the user when memberOf attribute is defined, or through the group using uniquemember attribute), 999 //hence there is no need to try to look up the group and query its members to see if this given identity 1000 //is in that list. 1001 //Generally speaking, this should be the case for every IdRepo implementation -> when we ask for the user 1002 //memberships, we should always get all of them for the sake of consistency. 1003 Set members = idServices.getMemberships(token, getType(), 1004 getName(), identity.getType(), orgName, getDN()); 1005 if (members != null && members.contains(identity)) { 1006 ismember = true; 1007 } else if (members != null) { 1008 // Check for fully qualified names or 1009 // if AM SDK DNs for these identities match 1010 String dn = identity.getDN(); 1011 Iterator it = members.iterator(); 1012 while (it.hasNext()) { 1013 AMIdentity id = (AMIdentity) it.next(); 1014 if (identity.equals(id)) { 1015 ismember = true; 1016 break; 1017 } else if (dn != null) { 1018 String mdn = id.getDN(); 1019 if ((mdn != null) && mdn.equalsIgnoreCase(dn)) { 1020 ismember = true; 1021 break; 1022 } 1023 } 1024 } 1025 } 1026 1027 // If membership is still false, check only the UUID 1028 // without the amsdkdn 1029 if (!ismember && members != null && !members.isEmpty()) { 1030 // Get UUID without amsdkdn for "membership" identity 1031 String identityDN = identity.getUniversalId(); 1032 String amsdkdn = identity.getDN(); 1033 if ((amsdkdn != null) && 1034 (identityDN.toLowerCase().indexOf(",amsdkdn=") != -1)) { 1035 identityDN = identityDN.substring(0, identityDN 1036 .indexOf(amsdkdn) - 9); 1037 } 1038 // Get UUID without amsdkdn for users memberships 1039 Iterator it = members.iterator(); 1040 while (it.hasNext()) { 1041 AMIdentity id = (AMIdentity) it.next(); 1042 String idDN = id.getUniversalId(); 1043 String mdn = id.getDN(); 1044 if (mdn != null) { 1045 int endIdx = idDN.indexOf(mdn) - 9; 1046 if (endIdx >= 0) { 1047 idDN = idDN.substring(0, endIdx); 1048 } 1049 } 1050 if (idDN.equalsIgnoreCase(identityDN)) { 1051 ismember = true; 1052 break; 1053 } 1054 } 1055 } 1056 1057 } catch (IdRepoException ide) { 1058 // Save the exception to be used later 1059 idException = ide; 1060 } 1061 1062 if (idException != null) { 1063 throw (idException); 1064 } 1065 return ismember; 1066 } 1067 1068 /** 1069 * @supported.api 1070 * 1071 * If membership is supported then add the new identity as a member. 1072 * 1073 * @param identity 1074 * AMIdentity to be added 1075 * @throws IdRepoException 1076 * if there are repository related error conditions. 1077 * @throws SSOException 1078 * if user's single sign on token is invalid. non-public methods 1079 */ 1080 public void addMember(AMIdentity identity) throws IdRepoException, 1081 SSOException { 1082 IdServices idServices = IdServicesFactory.getDataStoreServices(); 1083 Set members = new HashSet(); 1084 members.add(identity.getName()); 1085 idServices.modifyMemberShip(token, type, name, members, identity 1086 .getType(), IdRepo.ADDMEMBER, orgName); 1087 } 1088 1089 /** 1090 * @supported.api 1091 * 1092 * Removes the identity from this identity's membership. 1093 * 1094 * @param identity 1095 * AMIdentity to be removed from membership. 1096 * @throws IdRepoException 1097 * if there are repository related error conditions. 1098 * @throws SSOException 1099 * if user's single sign on token is invalid. non-public methods 1100 */ 1101 public void removeMember(AMIdentity identity) throws IdRepoException, 1102 SSOException { 1103 IdServices idServices = IdServicesFactory.getDataStoreServices(); 1104 Set members = new HashSet(); 1105 members.add(identity.getName()); 1106 idServices.modifyMemberShip(token, type, name, members, identity 1107 .getType(), IdRepo.REMOVEMEMBER, orgName); 1108 } 1109 1110 /** 1111 * @supported.api 1112 * 1113 * Removes the identities from this identity's membership. 1114 * 1115 * @param identityObjects 1116 * Set of AMIdentity objects 1117 * @throws IdRepoException 1118 * if there are repository related error conditions. 1119 * @throws SSOException 1120 * if user's single sign on token is invalid. non-public methods 1121 */ 1122 public void removeMembers(Set identityObjects) throws IdRepoException, 1123 SSOException { 1124 IdServices idServices = IdServicesFactory.getDataStoreServices(); 1125 Set members = new HashSet(); 1126 Iterator it = identityObjects.iterator(); 1127 1128 while (it.hasNext()) { 1129 AMIdentity identity = (AMIdentity) it.next(); 1130 members.add(identity.getName()); 1131 idServices.modifyMemberShip(token, type, name, members, identity 1132 .getType(), IdRepo.REMOVEMEMBER, orgName); 1133 members = new HashSet(); 1134 } 1135 } 1136 1137 /** 1138 * Return all members of a given identity type of this identity as a Set of 1139 * AMIdentity objects. 1140 * 1141 * This method is only valid for AMIdentity objects of type Group and User. 1142 * 1143 * @param mtype 1144 * Type of identity objects 1145 * @return Set of AMIdentity objects that are members of this object. 1146 * @throws IdRepoException 1147 * if there are repository related error conditions. 1148 * @throws SSOException 1149 * if user's single sign on token is invalid. 1150 * @supported.api 1151 */ 1152 public Set getMembers(IdType mtype) throws IdRepoException, SSOException { 1153 IdServices idServices = IdServicesFactory.getDataStoreServices(); 1154 return idServices 1155 .getMembers(token, type, name, orgName, mtype, getDN()); 1156 } 1157 1158 /** 1159 * Returns the set of identities that this identity belongs to. 1160 * 1161 * This method is only valid for AMIdentity objects of type User and Role. 1162 * 1163 * @param mtype 1164 * Type of member identity. 1165 * @return Set of AMIdentity objects of the given type that this identity 1166 * belongs to. 1167 * @throws IdRepoException 1168 * if there are repository related error conditions. 1169 * @throws SSOException 1170 * if user's single sign on token is invalid. 1171 * @supported.api 1172 */ 1173 public Set getMemberships(IdType mtype) throws IdRepoException, 1174 SSOException { 1175 IdServices idServices = IdServicesFactory.getDataStoreServices(); 1176 return idServices.getMemberships(token, type, name, mtype, orgName, 1177 getDN()); 1178 } 1179 1180 /** 1181 * This method determines if the identity exists and returns true or false. 1182 * 1183 * This method is only valid for AMIdentity objects of type User and Agent. 1184 * 1185 * @return true if the identity exists or false otherwise. 1186 * @throws IdRepoException 1187 * If there are repository related error conditions. 1188 * @throws SSOException 1189 * If user's single sign on token is invalid. 1190 * @supported.api 1191 */ 1192 public boolean isExists() throws IdRepoException, SSOException { 1193 IdServices idServices = IdServicesFactory.getDataStoreServices(); 1194 return idServices.isExists(token, type, name, orgName); 1195 } 1196 1197 /** 1198 * Returns <code>true</code> if the given object is equal to this object. 1199 * 1200 * @param o Object for comparison. 1201 * @return <code>true</code> if the given object is equal to this object. 1202 * @supported.api 1203 */ 1204 @Override 1205 public boolean equals(Object o) { 1206 boolean isEqual = false; 1207 if (o instanceof AMIdentity) { 1208 AMIdentity compareTo = (AMIdentity) o; 1209 if (univIdWithoutDN.equalsIgnoreCase( 1210 compareTo.univIdWithoutDN)) { 1211 isEqual = true; 1212 } else if (univDN != null) { 1213 // check if the amsdkdn match 1214 String dn = compareTo.getDN(); 1215 if (dn != null && dn.equalsIgnoreCase(univDN)) { 1216 isEqual = true; 1217 } 1218 } 1219 1220 if (!isEqual && !type.equals(IdType.REALM) && 1221 type.equals(compareTo.getType())) { 1222 // Check fully qualified names 1223 Set sfqn = getFullyQualifiedNames(); 1224 Set cfqn = compareTo.getFullyQualifiedNames(); 1225 if ((sfqn != null) && (cfqn != null) && 1226 !sfqn.isEmpty() && !cfqn.isEmpty()) { 1227 for (Iterator items = sfqn.iterator(); 1228 items.hasNext();) { 1229 String next = (String)items.next(); 1230 if (next != null && cfqn.contains(next)) { 1231 isEqual = true; 1232 break; 1233 } 1234 } 1235 } 1236 } 1237 } 1238 return (isEqual); 1239 } 1240 1241 /** 1242 * Non-javadoc, non-public methods 1243 */ 1244 @Override 1245 public int hashCode() { 1246 return (univIdWithoutDN.toLowerCase().hashCode()); 1247 } 1248 1249 /** 1250 * Nonjavadoc, non-public methods 1251 * 1252 */ 1253 public void setDN(String dn) { 1254 univDN = dn; 1255 } 1256 1257 /** 1258 * Returns universal distinguished name of this object. 1259 * 1260 * @return universal distinguished name of this object. 1261 */ 1262 public String getDN() { 1263 return univDN; 1264 } 1265 1266 /** 1267 * Returns the universal identifier of this object. 1268 * 1269 * @return String representing the universal identifier of this object. 1270 * @supported.api 1271 */ 1272 public String getUniversalId() { 1273 return univIdWithoutDN; 1274 } 1275 1276 /** 1277 * Returns String representation of the <code>AMIdentity</code> 1278 * object. It returns universal identifier, orgname, type, etc. 1279 * 1280 * @return String representation of the <code>ServiceConfig</code> object. 1281 */ 1282 @Override 1283 public String toString() { 1284 StringBuilder sb = new StringBuilder(100); 1285 sb.append("AMIdentity object: ").append(univIdWithoutDN); 1286 if (univDN != null) { 1287 sb.append("AMSDKDN=").append(univDN); 1288 } 1289 return (sb.toString()); 1290 } 1291 1292 // Returns a set of fully qulified names, as returned by DataStores 1293 protected Set getFullyQualifiedNames() { 1294 if (fullyQualifiedNames == null) { 1295 try { 1296 IdServices idServices = 1297 IdServicesFactory.getDataStoreServices(); 1298 fullyQualifiedNames = idServices.getFullyQualifiedNames( 1299 token, type, name, orgName); 1300 } catch (IdRepoException ire) { 1301 if (debug.messageEnabled()) { 1302 debug.message("AMIdentity:getFullyQualifiedNames: " + 1303 "got exception: ", ire); 1304 } 1305 } catch (SSOException ssoe) { 1306 if (debug.messageEnabled()) { 1307 debug.message("AMIdentity:getFullyQualifiedNames: " + 1308 "got exception: ", ssoe); 1309 } 1310 } 1311 } 1312 return (fullyQualifiedNames); 1313 } 1314 1315 private Set getServiceOCs(SSOToken token, String serviceName) 1316 throws SSOException { 1317 Set result = new HashSet(); 1318 try { 1319 if (serviceHasSubSchema(token, serviceName, SchemaType.GLOBAL)) { 1320 Map attrs = getServiceConfig(token, serviceName, 1321 SchemaType.GLOBAL); 1322 Set vals = (Set) attrs.get("serviceObjectClasses"); 1323 1324 if (vals != null) { 1325 result.addAll(vals); 1326 } 1327 } 1328 } catch (SMSException smsex) { 1329 } 1330 1331 return result; 1332 } 1333 1334 /** 1335 * Get service default config from SMS 1336 * 1337 * @param token 1338 * SSOToken a valid SSOToken 1339 * @param serviceName 1340 * the service name 1341 * @param type 1342 * service schema type (Dynamic, Policy etc) 1343 * @return returns a Map of Default Configuration values for the specified 1344 * service. 1345 */ 1346 private Map getServiceConfig(SSOToken token, String serviceName, 1347 SchemaType type) throws SMSException, SSOException { 1348 Map attrMap = null; // Map of attribute/value pairs 1349 if (type != SchemaType.POLICY) { 1350 ServiceSchemaManager scm = new ServiceSchemaManager(serviceName, 1351 token); 1352 ServiceSchema gsc = scm.getSchema(type); 1353 attrMap = gsc.getAttributeDefaults(); 1354 } 1355 return attrMap; 1356 } 1357 1358 /** 1359 * Returns true if the service has the subSchema. False otherwise. 1360 * 1361 * @param token 1362 * SSOToken a valid SSOToken 1363 * @param serviceName 1364 * the service name 1365 * @param schemaType 1366 * service schema type (Dynamic, Policy etc) 1367 * @return true if the service has the subSchema. 1368 */ 1369 private boolean serviceHasSubSchema(SSOToken token, String serviceName, 1370 SchemaType schemaType) throws SMSException, SSOException { 1371 boolean schemaTypeFlg = false; 1372 try { 1373 ServiceSchemaManager ssm = new ServiceSchemaManager(serviceName, 1374 token); 1375 Set types = ssm.getSchemaTypes(); 1376 if (debug.messageEnabled()) { 1377 debug.message("AMServiceUtils.serviceHasSubSchema() " 1378 + "SchemaTypes types for " + serviceName + " are: " 1379 + types); 1380 } 1381 schemaTypeFlg = types.contains(schemaType); 1382 } catch (ServiceNotFoundException ex) { 1383 if (debug.warningEnabled()) { 1384 debug.warning("AMServiceUtils.serviceHasSubSchema() " 1385 + "Service does not exist : " + serviceName); 1386 } 1387 } 1388 return (schemaTypeFlg); 1389 } 1390 1391 private Set getServiceAttributesName(String serviceName) 1392 throws IdRepoException, SSOException { 1393 Set attrNames = Collections.EMPTY_SET; 1394 1395 try { 1396 // Get attribute names for USER type only, so plugin knows 1397 // what attributes to remove. 1398 attrNames = new HashSet(); 1399 ServiceSchemaManager ssm = new ServiceSchemaManager( 1400 serviceName, token); 1401 ServiceSchema uss = ssm.getSchema(type.getName()); 1402 1403 if (uss != null) { 1404 attrNames = uss.getAttributeSchemaNames(); 1405 } 1406 // If the identity type is not of role, filteredrole or 1407 // realm, need to add dynamic attributes also 1408 if (!(type.equals(IdType.ROLE) || type.equals(IdType.REALM) || 1409 type.equals(IdType.FILTEREDROLE))) { 1410 uss = ssm.getDynamicSchema(); 1411 if (uss != null) { 1412 if (attrNames == Collections.EMPTY_SET) { 1413 attrNames = uss.getAttributeSchemaNames(); 1414 } else { 1415 attrNames.addAll(uss.getAttributeSchemaNames()); 1416 } 1417 } 1418 } else { 1419 // Add COS priority attribute 1420 attrNames.add(COS_PRIORITY); 1421 } 1422 } catch (SMSException smse) { 1423 if (debug.messageEnabled()) { 1424 debug.message( 1425 "AMIdentity.getServiceAttributes: Caught SM exception", 1426 smse); 1427 } 1428 // just returned whatever we find or empty set 1429 // if services is not found. 1430 } 1431 1432 return attrNames; 1433 } 1434 1435 private static Debug debug = Debug.getInstance("amIdm"); 1436 1437 public static String COS_PRIORITY = "cospriority"; 1438}