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