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: AMStoreConnection.java,v 1.13 2009/01/28 05:34:47 ww203982 Exp $ 026 * 027 * Portions Copyrighted 2011-2016 ForgeRock AS. 028 */ 029 030package com.iplanet.am.sdk; 031 032import static org.forgerock.openam.utils.Time.*; 033 034import com.iplanet.am.sdk.common.IDirectoryServices; 035import com.iplanet.sso.SSOException; 036import com.iplanet.sso.SSOToken; 037import com.iplanet.sso.SSOTokenManager; 038import com.sun.identity.sm.DNMapper; 039import com.sun.identity.sm.SMSEntry; 040import com.sun.identity.sm.SMSException; 041import com.sun.identity.sm.SchemaType; 042import com.sun.identity.sm.ServiceConfig; 043import com.sun.identity.sm.ServiceManager; 044import com.sun.identity.sm.ServiceSchemaManager; 045import org.forgerock.openam.ldap.LDAPUtils; 046import org.forgerock.opendj.ldap.DN; 047 048import java.text.NumberFormat; 049import java.text.ParseException; 050import java.text.ParsePosition; 051import java.text.SimpleDateFormat; 052import java.util.ArrayList; 053import java.util.Collections; 054import java.util.Date; 055import java.util.HashSet; 056import java.util.Iterator; 057import java.util.List; 058import java.util.Map; 059import java.util.Set; 060import java.util.StringTokenizer; 061 062 063/** 064 * The <code>AMStoreConnection</code> class represents a connection to the Sun 065 * Java System Access Manager data store. It provides methods to create, remove 066 * and get different type of Sun Java System Access Manager SDK objects in the 067 * data tore. <code>AMStoreConnection</code> controls and manages access to 068 * the data store. 069 * <p> 070 * An instance of <code>AMStoreConnection</code> object should always be 071 * obtained by anyone using the AM SDK since this object is the entry point to 072 * all other AM SDK managed objects. The constructor takes the SSO token of the 073 * user. Here is some sample code on how to get a user's attributes, using AM 074 * SDK: 075 * 076 * <PRE> 077 * 078 * AMStoreConnection amsc = new AMStoreConnection(ssotoken); AMUser user = 079 * amsc.getUser(ssotoken.getPrincipal()); Map attributes = user.getAttributes(); 080 * 081 * </PRE> 082 * 083 * <p> 084 * <code>AMStoreConnection</code> also has other helper methods which are very 085 * useful. Some examples below: 086 * 087 * <PRE> 088 * 089 * int otype = amsc.getAMObjectType(fullDN); 090 * 091 * </PRE> 092 * 093 * <p> 094 * <code>otype</code> returned is one of the managed <code>AMObject</code> 095 * types, like <code>AMObject.USER</code>, <code>AMObject.ROLE</code>, 096 * <code>AMObject.ORGANIZATION</code>. If the entry being checked in not of 097 * the type managed by AM SDK, then an <code>AMException</code> is thrown. 098 * 099 * <PRE> 100 * 101 * boolean exists = amsc.isValidEntry(fullDN); 102 * 103 * </PRE> 104 * 105 * <p> 106 * If there is a <code>fullDN</code> that you want to know if it exists or not 107 * in the data store, then use the above method. The typical use of this method 108 * is in the case when you know that you need to get a managed object from 109 * <code>amsc</code>, but you want to verify that it exists before you create 110 * the managed object instance: 111 * 112 * <PRE> 113 * 114 * if (amsc.isValidEntry(userDN)) { AMUser user = amsc.getUser(userDN); - More 115 * code here - } 116 * 117 * </PRE> 118 * 119 * <p> 120 * Helper method <code>getOrganizationDN()</code>: Use this method to perform 121 * a subtree scoped search for organization,based on various attribute values. 122 * 123 * <PRE> 124 * 125 * String orgDN = amsc.getOrganizationDN("sun.com", null); 126 * 127 * </PRE> 128 * 129 * <p> 130 * The above method will return the DN of a organization, which matches the 131 * search criterias of having either domain name of <code>sun.com</code>, 132 * Domain alias name of <code>sun.com</code> or it's naming attribute value is 133 * <code>sun.com</code>. More examples of how to use this method are provided 134 * in the Javadocs of the method below. 135 * 136 * @deprecated As of Sun Java System Access Manager 7.1. 137 * @supported.all.api 138 */ 139public final class AMStoreConnection implements AMConstants { 140 // ~ Static fields/initializers 141 // --------------------------------------------- 142 143 public static String rootSuffix; 144 145 protected static String defaultOrg; 146 147 protected static Map orgMapCache = new AMHashMap(); 148 149 // ~ Instance fields 150 // -------------------------------------------------------- 151 152 private IDirectoryServices dsServices; 153 154 private SSOToken token; 155 156 private String locale = "en_US"; 157 158 // ~ Constructors 159 // ----------------------------------------------------------- 160 161 /** 162 * Gets the connection to the Sun Java System Access Manager data store if 163 * the Session is valid. 164 * 165 * @param ssoToken 166 * a valid SSO token object to authenticate before getting the 167 * connection 168 * @throws SSOException 169 * if single sign on token is invalid or expired. 170 */ 171 public AMStoreConnection(SSOToken ssoToken) throws SSOException { 172 // initialize whatever you want to here. 173 SSOTokenManager.getInstance().validateToken(ssoToken); 174 this.token = ssoToken; 175 this.locale = AMCommonUtils.getUserLocale(ssoToken); 176 dsServices = AMDirectoryAccessFactory.getDirectoryServices(); 177 } 178 179 // ~ Methods 180 // ---------------------------------------------------------------- 181 182 /** 183 * Returns the root suffix for user management node. 184 * 185 * @return root suffix for user management node. 186 * 187 */ 188 public static String getAMSdkBaseDN() { 189 defaultOrg = rootSuffix = 190 com.sun.identity.common.DNUtils.normalizeDN( 191 SMSEntry.getAMSdkBaseDN()); 192 // Get an instance as required otherwise it causes issues on container restart. 193 if (AMCommonUtils.debug.messageEnabled()) { 194 AMCommonUtils.debug.message("AMStoreConnection:getAMSdkBaseDN():rootsuffix " + 195 rootSuffix); 196 } 197 if (AMCommonUtils.debug.messageEnabled()) { 198 AMCommonUtils.debug.message("default org: " + defaultOrg); 199 AMCommonUtils.debug.message("AMStoreConnection:getAMSdkBaseDN():default org " + 200 defaultOrg); 201 } 202 return defaultOrg; 203 } 204 205 /** 206 * Returns the filtered role naming attribute. 207 * 208 * @return filtered role naming attribute 209 * @deprecated This method is deprecated. Use 210 * {@link #getNamingAttribute(int) 211 * getNamingAttribute(int objectType)} 212 */ 213 public static String getFilteredRoleNamingAttribute() { 214 return AMNamingAttrManager.getNamingAttr(AMObject.FILTERED_ROLE); 215 } 216 217 /** 218 * Returns the group container naming attribute. 219 * 220 * @return group container naming attribute 221 * @deprecated This method is deprecated. Use 222 * {@link #getNamingAttribute(int) 223 * getNamingAttribute(int objectType)} 224 */ 225 public static String getGroupContainerNamingAttribute() { 226 return AMNamingAttrManager.getNamingAttr(AMObject.GROUP_CONTAINER); 227 } 228 229 /** 230 * Returns the group naming attribute. 231 * 232 * @return group naming attribute 233 * @deprecated This method is deprecated. Use 234 * {@link #getNamingAttribute(int) 235 * getNamingAttribute(int objectType)} 236 */ 237 public static String getGroupNamingAttribute() { 238 return AMNamingAttrManager.getNamingAttr(AMObject.GROUP); 239 } 240 241 /** 242 * Returns the naming attribute of an object type. 243 * 244 * @param objectType 245 * Object type can be one of the following: 246 * <ul> 247 * <li> {@link AMObject#USER AMObject.USER} 248 * <li> {@link AMObject#ROLE AMObject.ROLE} 249 * <li> {@link AMObject#FILTERED_ROLE AMObject.FILTERED_ROLE} 250 * <li> {@link AMObject#ORGANIZATION AMObject.ORGANIZATION} 251 * <li> {@link AMObject#ORGANIZATIONAL_UNIT 252 * AMObject.ORGANIZATIONAL_UNIT} 253 * <li> {@link AMObject#GROUP AMObject.GROUP} 254 * <li> {@link AMObject#DYNAMIC_GROUP AMObject.DYNAMIC_GROUP} 255 * <li> {@link AMObject#ASSIGNABLE_DYNAMIC_GROUP 256 * AMObject.ASSIGNABLE_DYNAMIC_GROUP} 257 * <li> 258 * {@link AMObject#PEOPLE_CONTAINER AMObject.PEOPLE_CONTAINER} 259 * <li> {@link AMObject#GROUP_CONTAINER AMObject.GROUP_CONTAINER} 260 * </ul> 261 * @return the naming attribute corresponding to the <code>objectType</code> 262 * @throws AMException 263 * if an error occurred in obtaining the naming attribute 264 */ 265 public static String getNamingAttribute(int objectType) throws AMException { 266 return AMNamingAttrManager.getNamingAttr(objectType); 267 } 268 269 /** 270 * Returns the organization naming attribute. 271 * 272 * @return organization naming attribute 273 * @deprecated This method is deprecated. Use 274 * {@link #getNamingAttribute(int) 275 * getNamingAttribute(int objectType)} 276 */ 277 public static String getOrganizationNamingAttribute() { 278 return AMNamingAttrManager.getNamingAttr(AMObject.ORGANIZATION); 279 } 280 281 /** 282 * Returns the organizational unit naming attribute. 283 * 284 * @return organizational unit naming attribute 285 * @deprecated This method is deprecated. Use 286 * {@link #getNamingAttribute(int) 287 * getNamingAttribute(int objectType)} 288 */ 289 public static String getOrganizationalUnitNamingAttribute() { 290 return AMNamingAttrManager.getNamingAttr(AMObject.ORGANIZATIONAL_UNIT); 291 } 292 293 /** 294 * Returns the people container naming attribute. 295 * 296 * @return people container naming attribute 297 * @deprecated This method is deprecated. Use 298 * {@link #getNamingAttribute(int) 299 * getNamingAttribute(int objectType)} 300 */ 301 public static String getPeopleContainerNamingAttribute() { 302 return AMNamingAttrManager.getNamingAttr(AMObject.PEOPLE_CONTAINER); 303 } 304 305 /** 306 * Returns the role naming attribute. 307 * 308 * @return role naming attribute 309 * @deprecated This method is deprecated. Use 310 * {@link #getNamingAttribute(int) 311 * getNamingAttribute(int objectType)} 312 */ 313 public static String getRoleNamingAttribute() { 314 return AMNamingAttrManager.getNamingAttr(AMObject.ROLE); 315 } 316 317 /** 318 * Returns the user naming attribute. 319 * 320 * @return user naming attribute 321 * @deprecated This method is deprecated. Use 322 * {@link #getNamingAttribute(int) 323 * getNamingAttribute(int objectType)} 324 */ 325 public static String getUserNamingAttribute() { 326 return AMNamingAttrManager.getNamingAttr(AMObject.USER); 327 } 328 329 /** 330 * Returns the type of the object given its DN. 331 * 332 * @param dn 333 * DN of the object whose type is to be known. 334 * @return the type of the object given its DN. 335 * @throws AMException 336 * if the data store is unavailable or if the object type is 337 * unknown. 338 * @throws SSOException 339 * if single sign on token is invalid or expired. 340 */ 341 public int getAMObjectType(String dn) throws AMException, SSOException { 342 return dsServices.getObjectType(token, dn); 343 } 344 345 /** 346 * Take a supported type, and returns the matching name of the supported 347 * managed type. For example, if <code> AMObject.USER</code> is passed in, 348 * it will return "user" (one of the basic supported types in AM SDK. But 349 * this method (and configuration in the service <code>DAI</code>) can be 350 * used to extend the basic supported types to include customer-specific 351 * entities, like "agents", "printers" etc. 352 * 353 * @param type 354 * Integer type (as returned by <code>getAMObjectType</code>) 355 * @return identifier for the above type. Returns null if type is unknown. 356 */ 357 public String getAMObjectName(int type) { 358 return ((String) AMCommonUtils.supportedNames.get(Integer 359 .toString(type))); 360 } 361 362 /** 363 * Take a supported type, and returns the matching name of the supported 364 * managed type. For example, if <code> AMObject.USER</code> is passed in, 365 * it will return "user" (one of the basic supported types in AM SDK. But 366 * this method (and configuration in the service <code>DAI</code>) can be 367 * used to extend the basic supported types to include customer-specific 368 * entities, like "agents", "printers" etc. 369 * 370 * @param type 371 * Integer type (as returned by <code>getAMObjectType</code>) 372 * @return identifier for the above type. Returns null if type is unknown. 373 */ 374 public static String getObjectName(int type) { 375 return ((String) AMCommonUtils.supportedNames.get(Integer 376 .toString(type))); 377 } 378 379 /** 380 * Returns the handle to the <code>AMAssignableDynamicGroup</code> object 381 * represented by DN. However, the validity of the handle returned by this 382 * method cannot be guaranteed, since the object is created in memory, and 383 * not instantiated from the data store. Using the 384 * <code>AMAssignableDynamicGroup</code> returned from this method may 385 * result in exceptions thrown in the later part of the application, if the 386 * DN is not valid or represents an entry that does not exist. 387 * <p> 388 * 389 * Validity of the DN can be verified is using <code>isValidEntry()</code> 390 * method of the object returned. 391 * 392 * @see #isValidEntry 393 * 394 * @param assignableDynamicGroupDN 395 * assignable dynamic group DN 396 * @return <code>AMAssignableDynamicGroup</code> object represented by DN. 397 * @throws SSOException 398 * if single sign on token is invalid or expired. 399 */ 400 public AMAssignableDynamicGroup getAssignableDynamicGroup( 401 String assignableDynamicGroupDN) throws SSOException { 402 AMAssignableDynamicGroup assignableDynamicGroup = 403 new AMAssignableDynamicGroupImpl(this.token, 404 assignableDynamicGroupDN); 405 406 return assignableDynamicGroup; 407 } 408 409 /** 410 * Returns the service attribute names for a given service name and schema 411 * type. 412 * 413 * @param serviceName 414 * the name of the service 415 * @param schemaType 416 * the type of service schema 417 * @return Set of service attribute names 418 * @throws AMException 419 * if an error is encountered while retrieving information. 420 * @deprecated use <code>com.sun.identity.sm.ServiceSchemaManager. 421 * getServiceAttributeNames(com.sun.identity.sm.SchemaType)</code> 422 */ 423 public Set getAttributeNames(String serviceName, AMSchema.Type schemaType) 424 throws AMException { 425 try { 426 ServiceSchemaManager ssm = new ServiceSchemaManager(serviceName, 427 token); 428 SchemaType st = schemaType.getInternalSchemaType(); 429 430 return ssm.getServiceAttributeNames(st); 431 } catch (SSOException se) { 432 AMCommonUtils.debug.message("AMStoreConnection.getAttributeNames(String, " 433 + "AMSchema.Type)", se); 434 throw new AMException(AMSDKBundle.getString("902", locale), "902"); 435 } catch (SMSException se) { 436 AMCommonUtils.debug.message("AMStoreConnection.getAttributeNames(String, " + 437 "AMSchema.Type)", se); 438 throw new AMException(AMSDKBundle.getString("911", locale), "911"); 439 } 440 } 441 442 /** 443 * Returns the handle to the <code>AMDynamicGroup</code> object 444 * represented by DN. However, the validity of the handle returned by this 445 * method cannot be guaranteed, since the object is created in memory, and 446 * not instantiated from the data store. Using the 447 * <code>AMDynamicGroup</code> returned from this method may result in 448 * exceptions thrown in the later part of the application, if the DN is not 449 * valid or represents an entry that does not exist. 450 * <p> 451 * 452 * Validity of the DN can be verified is using <code>isValidEntry()</code> 453 * method of the object returned. 454 * 455 * @see #isValidEntry 456 * 457 * @param dynamicGroupDN 458 * group DN 459 * @return <code>AMDynamicGroup</code> object represented by DN. 460 * @throws SSOException 461 * if single sign on token is invalid or expired. 462 */ 463 public AMDynamicGroup getDynamicGroup(String dynamicGroupDN) 464 throws SSOException { 465 AMDynamicGroup dynamicGroup = new AMDynamicGroupImpl(this.token, 466 dynamicGroupDN); 467 468 return dynamicGroup; 469 } 470 471 /** 472 * Returns the handle to the <code>AMFilteredRole</code> object 473 * represented by DN. However, the validity of the handle returned by this 474 * method cannot be guaranteed, since the object is created in memory, and 475 * not instantiated from the data store. Using the 476 * <code>AMFilteredRole</code> returned from this method may result in 477 * exceptions thrown in the later part of the application, if the DN is not 478 * valid or represents an entry that does not exist. 479 * <p> 480 * 481 * Validity of the DN can be verified is using <code>isValidEntry()</code> 482 * method of the object returned. 483 * 484 * @see #isValidEntry 485 * 486 * @param roleDN 487 * role DN. 488 * @return <code>AMFilteredRole</code> object represented by DN. 489 * @throws SSOException 490 * if single sign on token is invalid or expired. 491 */ 492 public AMFilteredRole getFilteredRole(String roleDN) throws SSOException { 493 AMFilteredRole role = new AMFilteredRoleImpl(this.token, roleDN); 494 495 return role; 496 } 497 498 /** 499 * Returns the handle to the <code>AMGroupContainer</code> object 500 * represented by DN. However, the validity of the handle returned by this 501 * method cannot be guaranteed, since the object is created in memory, and 502 * not instantiated from the data store. Using the 503 * <code>AMGroupContainer</code> returned from this method may result in 504 * exceptions thrown in the later part of the application, if the DN is not 505 * valid or represents an entry that does not exist. 506 * <p> 507 * 508 * Validity of the DN can be verified is using <code>isValidEntry()</code> 509 * method of the object returned. 510 * 511 * @see #isValidEntry 512 * 513 * @param groupContainerDN 514 * group container DN. 515 * @return <code>AMGroupContainer</code> object represented by DN. 516 * @throws SSOException 517 * if single sign on token is invalid or expired. 518 */ 519 public AMGroupContainer getGroupContainer(String groupContainerDN) 520 throws SSOException { 521 AMGroupContainer groupContainer = new AMGroupContainerImpl(this.token, 522 groupContainerDN); 523 524 return groupContainer; 525 } 526 527 /** 528 * Returns the I18N properties file name that contains the internationalized 529 * messages. 530 * 531 * @param serviceName 532 * the service name 533 * @return String String representing i18N properties file name 534 * @throws AMException 535 * if an error is encountered while retrieving information 536 */ 537 public String getI18NPropertiesFileName(String serviceName) 538 throws AMException { 539 try { 540 ServiceSchemaManager scm = new ServiceSchemaManager(serviceName, 541 token); 542 543 return scm.getI18NFileName(); 544 } catch (SSOException so) { 545 AMCommonUtils.debug.error("AMStoreConnection.getI18NPropertiesFileName(): ", so); 546 throw new AMException(AMSDKBundle.getString("902", locale), "902"); 547 } catch (SMSException se) { 548 AMCommonUtils.debug.error("AMStoreConnection.getServiceNames(): ", se); 549 throw new AMException(AMSDKBundle.getString("909", locale), "909"); 550 } 551 } 552 553 /** 554 * Returns the handle to the <code>AMOrganization</code> object 555 * represented by DN. However, the validity of the handle returned by this 556 * method cannot be guaranteed, since the object is created in memory, and 557 * not instantiated from the data store. Using the 558 * <code>AMOrganization</code> returned from this method may result in 559 * exceptions thrown in the later part of the application, if the DN is not 560 * valid or represents an entry that does not exist. 561 * <p> 562 * 563 * Validity of the DN can be verified is using <code>isValidEntry()</code> 564 * method of the object returned. 565 * 566 * @see #isValidEntry 567 * 568 * @param orgDN 569 * organization DN 570 * @return <code>AMOrganization</code> object represented by DN. 571 * @throws SSOException 572 * if single sign on token is invalid or expired. 573 */ 574 public AMOrganization getOrganization(String orgDN) throws SSOException { 575 AMOrganization organization = new AMOrganizationImpl(this.token, orgDN); 576 577 return organization; 578 } 579 580 /** 581 * Returns the DN of the organization, using the <code>domainname</code> 582 * provided and the <code>searchTemplate</code> (if provided). If 583 * <code>searchTemplate</code> is null, SDK uses the default 584 * <code>searchTemplate</code> to perform the <code>orgDN</code> search. 585 * If the DC tree global flag is enabled, the DC tree is used to obtain the 586 * organization DN, otherwise an LDAP search is conducted using the 587 * <code>searchfilter</code> in the <code>searchtemplate</code>. All 588 * <code>%V</code> in the filter are replaced with <code>domainname</code>. 589 * If the search returns more than one entries, then an Exception is thrown. 590 * Otherwise the DN obtained is returned. 591 * 592 * @param domainname 593 * Organization identifier passed. It can be a domain name 594 * (example: <code>sun.com</code>) or it could be a full DN or 595 * it could be null or <code>* "/"</code>. A full DN is 596 * verified to be an organization and returned as is. A "/" is 597 * assumed to be a request for the root DN and the root DN is 598 * returned. A "/" separated string is assumed to represent an 599 * existing organization DN in the DIT. For example: 600 * <code>/iplanet/sun</code> is converted to a DN 601 * <code>(o=iplanet,o=sun,<base DN>)</code> and the validity 602 * of this DN is checked and returned. Any other string is 603 * assumed to be either a domain or an associated domain or the 604 * organization name. The search filter is created accordingly. 605 * @param orgSearchTemplate 606 * template to use for the search. 607 * @return The full organization DN 608 * @throws AMException 609 * If there is a problem connecting or searching the data store. 610 * @throws SSOException 611 * If the user has an invalid SSO token. 612 */ 613 public String getOrganizationDN(String domainname, String orgSearchTemplate) 614 throws AMException, SSOException { 615 if (domainname == null) { 616 return rootSuffix; 617 } 618 619 // If a DN is passed and is a valid organization DN, then 620 // return it. 621 if (LDAPUtils.isDN(domainname) && isValidEntry(domainname) 622 && (getAMObjectType(domainname) == AMObject.ORGANIZATION)) { 623 return domainname; 624 } 625 626 if (!domainname.startsWith("http://") && (domainname.indexOf("/") > -1)) 627 { 628 String orgdn = orgNameToDN(domainname); 629 630 if (isValidEntry(orgdn) 631 && (getAMObjectType(orgdn) == AMObject.ORGANIZATION)) { 632 return (orgdn); 633 } else { 634 Object[] args = { orgdn }; 635 String locale = AMCommonUtils.getUserLocale(token); 636 throw new AMException(AMSDKBundle 637 .getString("467", args, locale), "467", args); 638 } 639 } 640 641 try { 642 String orgdn; 643 644 if (AMDCTree.isRequired()) { 645 orgdn = AMDCTree.getOrganizationDN(token, domainname); 646 647 if (orgdn != null) { 648 return orgdn; 649 } 650 } 651 } catch (AMException ae) { 652 // do nothing. will try to search the organization 653 // using search template 654 AMCommonUtils.debug.error("AMStoreConnection.getOrganizationDN-> " 655 + "In DC tree mode, unabe to find organization " 656 + " for domain: " + domainname); 657 } 658 659 String orgdn = (String) orgMapCache.get(domainname.toLowerCase()); 660 661 if (orgdn != null) { 662 return (orgdn); 663 } else { 664 // use the searchfilter to obtain org DN 665 // replace %V with domainname. 666 String searchFilter = AMSearchFilterManager.getSearchFilter( 667 AMObject.ORGANIZATION, null, orgSearchTemplate, false); 668 669 if ((orgSearchTemplate != null) 670 && (searchFilter.indexOf("%V") > -1)) { 671 searchFilter = AMObjectImpl.constructFilter(AMNamingAttrManager 672 .getNamingAttr(AMObject.ORGANIZATION), searchFilter, 673 domainname); 674 } else { 675 StringBuilder sb = new StringBuilder(); 676 sb.append("(|(&").append(searchFilter).append("(").append( 677 AMNamingAttrManager 678 .getNamingAttr(AMObject.ORGANIZATION)).append( 679 "=").append(domainname).append(")").append(")(&") 680 .append(searchFilter).append("(").append( 681 "sunPreferredDomain=").append(domainname) 682 .append(")").append(")(&").append(searchFilter).append( 683 "(").append("associatedDomain=").append( 684 domainname).append(")").append(")(&").append( 685 searchFilter).append("(").append( 686 "sunOrganizationAlias=").append(domainname) 687 .append(")").append("))"); 688 searchFilter = sb.toString(); 689 } 690 691 if (AMCommonUtils.debug.messageEnabled()) { 692 AMCommonUtils.debug.message("AMSC:getOrgDN-> " + "using searchfilter " 693 + searchFilter); 694 } 695 696 Set orgSet = dsServices.search(token, rootSuffix, searchFilter, 697 SCOPE_SUB); 698 699 if ((orgSet == null) || (orgSet.size() > 1) || orgSet.isEmpty()) { 700 // throw an exception 701 Object[] args = { domainname }; 702 String locale = AMCommonUtils.getUserLocale(token); 703 throw new AMException(AMSDKBundle 704 .getString("971", args, locale), "971", args); 705 } else { 706 Iterator it = orgSet.iterator(); 707 orgdn = (String) it.next(); 708 addToOrgMapCache(token, orgdn); 709 710 return (orgdn); 711 } 712 } 713 } 714 715 /** 716 * Returns the handle to the <code>AMOrganizationalUnit</code> object 717 * represented by DN. However, the validity of the handle returned by this 718 * method cannot be guaranteed, since the object is created in memory, and 719 * not instantiated from the data store. Using the 720 * <code>AMOrganizationialUnit</code> returned from this method may result 721 * in exceptions thrown in the later part of the application, if the DN is 722 * not valid or represents an entry that does not exist. 723 * <p> 724 * 725 * Validity of the DN can be verified is using <code>isValidEntry()</code> 726 * method of the object returned. 727 * 728 * @see #isValidEntry 729 * 730 * @param orgUnitDN 731 * organizational unit DN 732 * @return <code>AMOrganizationalUnit</code> object represented by DN. 733 * @throws SSOException 734 * if single sign on token is invalid or expired. 735 */ 736 public AMOrganizationalUnit getOrganizationalUnit(String orgUnitDN) 737 throws SSOException { 738 AMOrganizationalUnit organizationalUnit = new AMOrganizationalUnitImpl( 739 this.token, orgUnitDN); 740 741 return organizationalUnit; 742 } 743 744 /** 745 * Returns the handle to the <code>AMPeopleContainer</code> object 746 * represented by DN. However, the validity of the handle returned by this 747 * method cannot be guaranteed, since the object is created in memory, and 748 * not instantiated from the data store. Using the 749 * <code>AMPeopleContainer</code> returned from this method may result in 750 * exceptions thrown in the later part of the application, if the DN is not 751 * valid or represents an entry that does not exist. 752 * <p> 753 * 754 * Validity of the DN can be verified is using <code>isValidEntry()</code> 755 * method of the object returned. 756 * 757 * @see #isValidEntry 758 * 759 * @param peopleContainerDN 760 * people container DN 761 * @return <code>AMPeopleContainer</code> object represented by DN. 762 * @throws SSOException 763 * if single sign on token is invalid or expired. 764 */ 765 public AMPeopleContainer getPeopleContainer(String peopleContainerDN) 766 throws SSOException { 767 AMPeopleContainer peopleContainer = new AMPeopleContainerImpl( 768 this.token, peopleContainerDN); 769 770 return peopleContainer; 771 } 772 773 /** 774 * Returns the handle to the <code>AMTemplate</code> object represented by 775 * DN. However, the validity of the handle returned by this method cannot be 776 * guaranteed, since the object is created in memory, and not instantiated 777 * from the data store. Using the <code>AMTemplate</code> returned from 778 * this method may result in exceptions thrown in the later part of the 779 * application, if the DN is not valid or represents an entry that does not 780 * exist. 781 * <p> 782 * 783 * Validity of the DN can be verified is using <code>isValidEntry()</code> 784 * method of the object returned. 785 * 786 * @deprecated 787 * @see #isValidEntry 788 * 789 * @param templateDN 790 * a policy template DN. 791 * @return <code>AMTemplate</code> object represented by DN. 792 * @throws AMException 793 * if the DN does not represent a Policy template DN 794 * @throws SSOException 795 * if single sign on token is invalid or expired. 796 */ 797 public AMTemplate getPolicyTemplate(String templateDN) throws AMException, 798 SSOException { 799 throw new UnsupportedOperationException(); 800 } 801 802 /** 803 * Returns the URL of the view bean for the service 804 * 805 * @param serviceName 806 * the service name 807 * @return String URL of the view bean for the service 808 * @throws AMException 809 * if an error is encountered while retrieving information 810 */ 811 public String getPropertiesViewBeanURL(String serviceName) 812 throws AMException { 813 try { 814 ServiceSchemaManager scm = new ServiceSchemaManager(serviceName, 815 token); 816 817 return scm.getPropertiesViewBeanURL(); 818 } catch (SSOException so) { 819 AMCommonUtils.debug.error("AMStoreConnection.getPropertiesViewBeanURL(): ", so); 820 throw new AMException(AMSDKBundle.getString("902", locale), "902"); 821 } catch (SMSException se) { 822 AMCommonUtils.debug.error("AMStoreConnection.getServiceNames(): ", se); 823 throw new AMException(AMSDKBundle.getString("910", locale), "910"); 824 } 825 } 826 827 /** 828 * Returns the handle to the <code>AMResource</code> object represented by 829 * DN. However, the validity of the handle returned by this method cannot be 830 * guaranteed, since the object is created in memory, and not instantiated 831 * from the data store. Using the <code>AMResource</code> returned from 832 * this method may result in exceptions thrown in the later part of the 833 * application, if the DN is not valid or represents an entry that does not 834 * exist. 835 * <p> 836 * 837 * Validity of the DN can be verified is using <code>isValidEntry()</code> 838 * method of the object returned. 839 * 840 * @see #isValidEntry 841 * 842 * @param resourceDN 843 * resource DN. 844 * @return <code>AMResource</code> object represented by DN. 845 * @throws SSOException 846 * if single sign on token is invalid or expired. 847 */ 848 public AMResource getResource(String resourceDN) throws SSOException { 849 AMResource res = new AMResourceImpl(this.token, resourceDN); 850 851 return res; 852 } 853 854 /** 855 * Returns the handle to the <code>AMRole</code> object represented by DN. 856 * However, the validity of the handle returned by this method cannot be 857 * guaranteed, since the object is created in memory, and not instantiated 858 * from the data store. Using the <code>AMRole</code> returned from this 859 * method may result in exceptions thrown in the later part of the 860 * application, if the DN is not valid or represents an entry that does not 861 * exist. 862 * <p> 863 * 864 * Validity of the DN can be verified is using <code>isValidEntry()</code> 865 * method of the object returned. 866 * 867 * @see #isValidEntry 868 * 869 * @param roleDN 870 * role DN 871 * @return <code>AMRole</code> object represented by DN. 872 * @throws SSOException 873 * if single sign on token is invalid or expired. 874 */ 875 public AMRole getRole(String roleDN) throws SSOException { 876 AMRole role = new AMRoleImpl(this.token, roleDN); 877 878 return role; 879 } 880 881 /** 882 * Returns the <code>AMSchema</code> for the given service name and 883 * service type. 884 * 885 * @param serviceName 886 * the name of the service 887 * @param schemaType 888 * the type of service schema that needs to be retrieved. 889 * 890 * @return <code>AMSchema</code> corresponding to the given service name 891 * and schema type. 892 * 893 * @throws AMException 894 * if an error is encountered in retrieving the 895 * <code>AMSchema</code>. 896 * 897 * @deprecated This method has been deprecated. Please use 898 * <code>com.sun.identity.sm.ServiceSchemaManager.getSchema() 899 * </code>. 900 */ 901 public AMSchema getSchema(String serviceName, AMSchema.Type schemaType) 902 throws AMException { 903 throw new UnsupportedOperationException(); 904 } 905 906 /** 907 * Returns the schema types available for a particular service. 908 * 909 * @param serviceName 910 * the name of the service whose schema types needs to be 911 * retrieved 912 * @return Set of <code>AMSchema.Type</code> objects 913 * @throws AMException 914 * if an error is encountered in retrieving the 915 * <code>schemaTypes</code>. 916 * 917 * @deprecated This method has been deprecated. Please use 918 * <code> 919 * com.sun.identity.sm.ServiceSchemaManager.getSchemaTypes() 920 * </code>. 921 */ 922 public Set getSchemaTypes(String serviceName) throws AMException { 923 throw new UnsupportedOperationException(); 924 } 925 926 /** 927 * Returns the service hierarchy for all registered services. 928 * 929 * @return the service hierarchy for all registered services. 930 * @throws AMException 931 * if an error is encountered in retrieving the service 932 * hierarchy. The return value is a Set of strings in slash 933 * format. 934 */ 935 public Set getServiceHierarchy() throws AMException { 936 try { 937 Set retSet = new HashSet(); 938 ServiceManager sm = new ServiceManager(token); 939 Set serviceNames = sm.getServiceNames(); 940 Iterator itr = serviceNames.iterator(); 941 942 while (itr.hasNext()) { 943 String st = (String) itr.next(); 944 ServiceSchemaManager scm = new ServiceSchemaManager(st, token); 945 String sh = scm.getServiceHierarchy(); 946 947 if ((sh != null) && (sh.length() != 0)) { 948 retSet.add(sh); 949 } 950 } 951 952 return retSet; 953 } catch (SSOException so) { 954 AMCommonUtils.debug.error("AMStoreConnection.getServiceNames(): ", so); 955 throw new AMException(AMSDKBundle.getString("902", locale), "902"); 956 } catch (SMSException se) { 957 AMCommonUtils.debug.error("AMStoreConnection.getServiceNames(): ", se); 958 throw new AMException(AMSDKBundle.getString("905", locale), "905"); 959 } 960 } 961 962 /** 963 * Returns the set of name of services that have been loaded to the data 964 * store. 965 * 966 * @return set of name of services. 967 * @throws AMException 968 * if an error is encountered in retrieving the names of the 969 * services 970 */ 971 public Set getServiceNames() throws AMException { 972 try { 973 ServiceManager sm = new ServiceManager(token); 974 975 return sm.getServiceNames(); 976 } catch (SSOException so) { 977 AMCommonUtils.debug.error("AMStoreConnection.getServiceNames(): ", so); 978 throw new AMException(AMSDKBundle.getString("902", locale), "902"); 979 } catch (SMSException se) { 980 AMCommonUtils.debug.error("AMStoreConnection.getServiceNames(): ", se); 981 throw new AMException(AMSDKBundle.getString("906", locale), "906"); 982 } 983 } 984 985 /** 986 * Returns the handle to the <code>AMStaticGroup</code> object represented 987 * by DN. However, the validity of the handle returned by this method cannot 988 * be guaranteed, since the object is created in memory, and not 989 * instantiated from the data store. Using the <code>AMStaticGroup</code> 990 * returned from this method may result in exceptions thrown in the later 991 * part of the application, if the DN is not valid or represents an entry 992 * that does not exist. 993 * <p> 994 * 995 * Validity of the DN can be verified is using <code>isValidEntry()</code> 996 * method of the object returned. 997 * 998 * @see #isValidEntry 999 * 1000 * @param groupDN 1001 * group DN 1002 * @return <code>AMStaticGroup</code> object represented by DN. 1003 * @throws SSOException 1004 * if single sign on token is invalid or expired. 1005 */ 1006 public AMStaticGroup getStaticGroup(String groupDN) throws SSOException { 1007 AMStaticGroup group = new AMStaticGroupImpl(this.token, groupDN); 1008 return group; 1009 } 1010 1011 /** 1012 * Returns the top level containers (Organizations, People Containers, 1013 * Roles, etc) for the particular user based on single sign on token as the 1014 * starting point in the tree. 1015 * 1016 * @return set of <code>DBObjects</code> that are top level containers for 1017 * the signed in user. 1018 * @throws AMException 1019 * if an error occurred when retrieving the information from the 1020 * data store. 1021 * @throws SSOException 1022 * if single sign on token is invalid or expired. 1023 */ 1024 public Set getTopLevelContainers() throws AMException, SSOException { 1025 SSOTokenManager.getInstance().validateToken(this.token); 1026 return dsServices.getTopLevelContainers(token); 1027 } 1028 1029 /** 1030 * Returns the "real" or "physical" top level organizations as the starting 1031 * point in the tree. 1032 * 1033 * @return Set Set of DN Strings for top level Organizations 1034 * @throws AMException 1035 * if an error occurred when retrieving the information from the 1036 * data store. 1037 * @throws SSOException 1038 * if single sign on token is invalid or expired. 1039 */ 1040 public Set getTopLevelOrganizations() throws AMException, SSOException { 1041 SSOTokenManager.getInstance().validateToken(this.token); 1042 1043 return dsServices.search(this.token, rootSuffix, AMSearchFilterManager 1044 .getGlobalSearchFilter(AMObject.ORGANIZATION), SCOPE_ONE); 1045 } 1046 1047 /** 1048 * Returns the handle to the <code>AMUser</code> object represented by DN. 1049 * However, the validity of the handle returned by this method cannot be 1050 * guaranteed, since the object is created in memory, and not instantiated 1051 * from the data store. Using the <code>AMUser</code> returned from this 1052 * method may result in exceptions thrown in the later part of the 1053 * application, if the DN is not valid or represents an entry that does not 1054 * exist. 1055 * <p> 1056 * 1057 * Validity of the DN can be verified is using <code>isValidEntry()</code> 1058 * method of the object returned. 1059 * 1060 * @see #isValidEntry 1061 * 1062 * @param userDN 1063 * user DN 1064 * @return <code>AMUser</code> object represented by DN 1065 * @throws SSOException 1066 * if single sign on token is invalid or expired. 1067 */ 1068 public AMUser getUser(String userDN) throws SSOException { 1069 AMUser user = new AMUserImpl(this.token, userDN); 1070 return user; 1071 } 1072 1073 /** 1074 * Returns the handle to the <code>AMEntity</code> object represented by 1075 * DN. However, the validity of the handle returned by this method cannot be 1076 * guaranteed, since the object is created in memory, and not instantiated 1077 * from the data store. Using the <code>AMEntity</code> returned from this 1078 * method may result in exceptions thrown in the later part of the 1079 * application, if the DN is not valid or represents an entry that does not 1080 * exist. 1081 * <p> 1082 * 1083 * Validity of the DN can be verified is using <code>isValidEntry()</code> 1084 * method of the object returned. 1085 * 1086 * @see #isValidEntry 1087 * 1088 * @param eDN 1089 * entity DN. 1090 * @return <code>AMEntity</code> object represented by DN. 1091 * @throws SSOException 1092 * if single sign on token is invalid or expired. 1093 */ 1094 public AMEntity getEntity(String eDN) throws SSOException { 1095 AMEntity entity = null; 1096 try { 1097 entity = new AMEntityImpl(this.token, eDN, getAMObjectType(eDN)); 1098 } catch (AMException ame) { 1099 // Return AMEntity without object type 1100 entity = new AMEntityImpl(this.token, eDN); 1101 } 1102 return entity; 1103 } 1104 1105 /** 1106 * Checks if the entry exists in the directory or not. First a syntax check 1107 * is done on the DN string corresponding to the entry. If the DN syntax is 1108 * valid, a directory call will be made to check for the existence of the 1109 * entry. 1110 * <p> 1111 * 1112 * <b>NOTE:</b> This method internally invokes a call to the directory to 1113 * verify the existence of the entry. There could be a performance overhead. 1114 * Hence, please use your discretion while using this method. 1115 * 1116 * @param dn 1117 * DN of the entry that needs to be validated. 1118 * 1119 * @return false if the entry does not have a valid DN syntax or if the 1120 * entry does not exists in the Directory. True otherwise. 1121 * 1122 * @throws SSOException 1123 * if the single sign on token is no longer valid. 1124 */ 1125 public boolean isValidEntry(String dn) throws SSOException { 1126 // First check if DN syntax is valid. Avoid making iDS call 1127 if (!LDAPUtils.isDN(dn)) { // May be a exception thrown 1128 1129 return false; // would be better here. 1130 } 1131 1132 SSOTokenManager.getInstance().validateToken(token); 1133 1134 if (AMCommonUtils.debug.messageEnabled()) { 1135 AMCommonUtils.debug.message("AMStoreConnection.isValidEntry(): DN=" + dn); 1136 } 1137 1138 return dsServices.doesEntryExists(token, dn); 1139 } 1140 1141 /** 1142 * Bootstraps the Organization tree by creating the Top Organization tree. 1143 * 1144 * @param orgName 1145 * name of the top organization 1146 * @param avPairs 1147 * Attribute-Value pairs for the top organization 1148 * @return Top Organization object. 1149 * @throws AMException 1150 * if an error occurred during the process of creation. 1151 * @throws SSOException 1152 * if single sign on token is invalid or expired. 1153 */ 1154 public AMOrganization createTopOrganization(String orgName, Map avPairs) 1155 throws AMException, SSOException { 1156 StringBuilder orgDNSB = new StringBuilder(); 1157 orgDNSB 1158 .append( 1159 AMNamingAttrManager 1160 .getNamingAttr(AMObject.ORGANIZATION)).append( 1161 "=").append(orgName).append(",").append(rootSuffix); 1162 1163 AMOrganizationImpl orgImpl = new AMOrganizationImpl(this.token, orgDNSB 1164 .toString()); 1165 orgImpl.setAttributes(avPairs); 1166 orgImpl.create(); 1167 1168 return orgImpl; 1169 } 1170 1171 /** 1172 * This method takes an organization DN and purges all objects marked for 1173 * deletion. If the organization itself is marked for deletion, then a 1174 * recursive delete of everything under the organization is called, followed 1175 * by the organization deletion. This method works in the mode where 1176 * soft-delete option in Access Manager is turned on. The Pre/Post 1177 * <code>callbacks</code> for users are executed during this method. 1178 * 1179 * @param domainName 1180 * domain to be purged 1181 * @param graceperiod 1182 * time in days which should have passed since the entry was last 1183 * modified before it can be deleted from the system. 1184 * @throws AMException 1185 * if an error occurred when retrieving the information from the 1186 * data store. 1187 * @throws SSOException 1188 * if single sign on token is invalid or expired. 1189 */ 1190 public void purge(String domainName, int graceperiod) throws AMException, 1191 SSOException { 1192 String orgDN; 1193 Set orgSet; 1194 boolean deleted = false; 1195 if (AMDCTree.isRequired()) { 1196 orgDN = AMDCTree.getOrganizationDN(token, domainName); 1197 orgSet = new HashSet(); 1198 orgSet.add(orgDN); 1199 } else { 1200 // Use special org search filter for searching for deleted 1201 // organizations. 1202 String filter = AMCompliance 1203 .getDeletedObjectFilter(AMObject.ORGANIZATION); 1204 filter = AMObjectImpl.constructFilter(AMNamingAttrManager 1205 .getNamingAttr(AMObject.ORGANIZATION), filter, domainName); 1206 1207 if (AMCommonUtils.debug.messageEnabled()) { 1208 AMCommonUtils.debug.message("AMStoreConnection.purgeOrg: " 1209 + "Using org filter= " + filter); 1210 } 1211 1212 orgSet = dsServices.search(token, rootSuffix, filter, SCOPE_SUB); 1213 1214 if ((orgSet == null) || orgSet.isEmpty()) { 1215 orgSet = getOrganizations(domainName, null); 1216 deleted = false; 1217 } else { 1218 deleted = true; 1219 } 1220 } 1221 1222 if (orgSet == null || orgSet.isEmpty()) { 1223 return; 1224 } 1225 Iterator delIter = orgSet.iterator(); 1226 while (delIter.hasNext()) { 1227 orgDN = (String) delIter.next(); 1228 if (AMCommonUtils.debug.messageEnabled()) { 1229 AMCommonUtils.debug.message("AMStoreConnection.purge: " + "Organization= " 1230 + orgDN); 1231 } 1232 1233 AMOrganization org = getOrganization(orgDN); 1234 1235 // Check to see if grace period has expired. 1236 if (deleted && graceperiod < daysSinceModified(token, orgDN)) { 1237 // Delete all objects using the hardDelete method. 1238 org.purge(true, -1); 1239 } else { 1240 // Search for objects marked as deleted and 1241 // try to purge them, if graceperiod as expired. 1242 String filter = AMCompliance.getDeletedObjectFilter(-1); 1243 1244 if (AMCommonUtils.debug.messageEnabled()) { 1245 AMCommonUtils.debug.message("AMStoreConnection.purge: " 1246 + "Searching deleted objects. Filter: " + filter); 1247 } 1248 1249 Set deletedObjs = dsServices.search(token, orgDN, filter, 1250 SCOPE_SUB); 1251 1252 if (deletedObjs == null) { 1253 // No objecxts to delete 1254 if (AMCommonUtils.debug.messageEnabled()) { 1255 AMCommonUtils.debug.message("AMStoreConnection.purge: " 1256 + "No objects to be deleted found for " 1257 + orgDN); 1258 } 1259 } 1260 1261 Iterator iter = deletedObjs.iterator(); 1262 List list = new ArrayList(); 1263 1264 // get number of RDNs in the entry itself 1265 int entryRDNs = DN.valueOf(orgDN).size(); 1266 1267 // to count maximum level of RDNs in the search return 1268 int maxRDNCount = entryRDNs; 1269 1270 // go through all search results, add DN to the list, and 1271 // set the maximun RDN count, will be used to remove DNs 1272 while (iter.hasNext()) { 1273 String thisDN = (String) iter.next(); 1274 DN dn = DN.valueOf(thisDN); 1275 int count = dn.size(); 1276 1277 if (count > maxRDNCount) { 1278 maxRDNCount = count; 1279 } 1280 1281 list.add(dn); 1282 } 1283 1284 int len = list.size(); 1285 for (int i = maxRDNCount; i >= entryRDNs; i--) { 1286 for (int j = 0; j < len; j++) { 1287 // depending on object type, 1288 DN thisdn = (DN) list.get(j); 1289 1290 if (thisdn.size() == i) { 1291 String thisDN = thisdn.toString(); 1292 int objType = getAMObjectType(thisDN); 1293 AMObject thisObj; 1294 1295 if (AMCommonUtils.debug.messageEnabled()) { 1296 AMCommonUtils.debug.message("AMStoreConnection:purgeOrg: " 1297 + "deleting child " + thisDN); 1298 } 1299 try { // catch PreCallBackException 1300 switch (objType) { 1301 case AMObject.USER: 1302 thisObj = getUser(thisDN); 1303 thisObj.purge(false, graceperiod); 1304 1305 break; 1306 1307 case AMObject.ASSIGNABLE_DYNAMIC_GROUP: 1308 thisObj = getAssignableDynamicGroup(thisDN); 1309 thisObj.purge(false, graceperiod); 1310 1311 break; 1312 1313 case AMObject.DYNAMIC_GROUP: 1314 thisObj = getDynamicGroup(thisDN); 1315 thisObj.purge(false, graceperiod); 1316 1317 break; 1318 1319 case AMObject.STATIC_GROUP: 1320 case AMObject.GROUP: 1321 thisObj = getStaticGroup(thisDN); 1322 thisObj.purge(false, graceperiod); 1323 1324 break; 1325 1326 case AMObject.RESOURCE: 1327 thisObj = getResource(thisDN); 1328 thisObj.purge(false, -1); 1329 break; 1330 1331 case AMObject.ORGANIZATION: 1332 thisObj = getOrganization(thisDN); 1333 1334 if (!DN.valueOf(thisDN).equals(DN.valueOf(orgDN))) { 1335 thisObj.purge(true, graceperiod); 1336 } 1337 1338 break; 1339 1340 default: 1341 1342 // should not show up in the searched 1343 // objects. 1344 // as none of the other objects are 1345 // supported 1346 // for being marked as soft-deleted/ 1347 // purging. 1348 break; 1349 } // switch 1350 } catch (AMPreCallBackException amp) { 1351 AMCommonUtils.debug.error("AMStoreConnection.purge: " 1352 + "Aborting delete of: " 1353 + thisDN 1354 + " due to pre-callback exception", 1355 amp); 1356 } 1357 } // if 1358 } // for 1359 } // for 1360 1361 } // else 1362 } // delIter 1363 1364 return; 1365 } 1366 1367 /** 1368 * This method takes a user ID and a domain name, It uses default search 1369 * templates to search for the organization and uses the deleted objects 1370 * search filter for Users as defined in the Administration Service of 1371 * Access Manager. This filter is used to search for the deleted user under 1372 * the organization. If the user is marked for deletion and the grace period 1373 * is passed then the user is purged. The pre-delete call backs as listed in 1374 * the Administration service, are called before the user is deleted. If any 1375 * of the <code>callbacks</code> throw an exception the delete operation 1376 * is aborted. 1377 * 1378 * @param uid 1379 * user ID 1380 * @param domainName 1381 * domain in which the user belongs. 1382 * @param graceperiod 1383 * time in days which should have passed before this user can be 1384 * deleted. 1385 * 1386 * @throws AMException 1387 * if there is an error in deleting the user, or if the user 1388 * <code>callbacks</code> thrown an exception 1389 * @throws SSOException 1390 */ 1391 public void purgeUser(String uid, String domainName, int graceperiod) 1392 throws AMException, SSOException { 1393 String orgDN = getOrganizationDN(domainName, null); 1394 String filter = AMCompliance.getDeletedObjectFilter(AMObject.USER); 1395 filter = AMObjectImpl.constructFilter(AMNamingAttrManager 1396 .getNamingAttr(AMObject.USER), filter, uid); 1397 1398 if (AMCommonUtils.debug.messageEnabled()) { 1399 AMCommonUtils.debug.message("AMStoreConnection.purgeGroup: " 1400 + "Using deleted user filter= " + filter); 1401 } 1402 1403 Set uSet = dsServices.search(token, orgDN, filter, SCOPE_SUB); 1404 1405 if ((uSet == null) || (uSet.size() > 1) || uSet.isEmpty()) { 1406 // throw an exception 1407 Object args[] = { uid }; 1408 throw new AMException(AMSDKBundle.getString("971", args, locale), 1409 "971", args); 1410 } 1411 1412 String uDN = (String) uSet.iterator().next(); 1413 AMUser user = getUser(uDN); 1414 user.purge(false, graceperiod); 1415 1416 return; 1417 } 1418 1419 /** 1420 * This method takes a resource ID and a domain name, It uses default search 1421 * templates to search for the organization and uses the deleted objects 1422 * search filter for Resources as defined in the Administration Service of 1423 * Access Manager. This filter is used to search for the deleted resource 1424 * under the organization. If the resource is marked for deletion and the 1425 * grace period is passed then the resource is purged. The pre-delete call 1426 * backs as listed in the Administration service, are called before the user 1427 * is deleted. If any of the <code>callbacks</code> throw an exception the 1428 * delete operation is aborted. 1429 * 1430 * @param rid 1431 * resource ID 1432 * @param domainName 1433 * domain in which the user belongs. 1434 * @param graceperiod 1435 * time in days which should have passed before this user can be 1436 * deleted. 1437 * 1438 * @throws AMException 1439 * if there is an error in deleting the user, or if the user 1440 * <code>callbacks</code> thrown an exception 1441 * @throws SSOException 1442 */ 1443 public void purgeResource(String rid, String domainName, int graceperiod) 1444 throws AMException, SSOException { 1445 String orgDN = getOrganizationDN(domainName, null); 1446 String filter = AMCompliance.getDeletedObjectFilter(AMObject.RESOURCE); 1447 filter = AMObjectImpl.constructFilter(AMNamingAttrManager 1448 .getNamingAttr(AMObject.RESOURCE), filter, rid); 1449 1450 if (AMCommonUtils.debug.messageEnabled()) { 1451 AMCommonUtils.debug.message("AMStoreConnection.purgeGroup: " 1452 + "Using deleted user filter= " + filter); 1453 } 1454 1455 Set uSet = dsServices.search(token, orgDN, filter, SCOPE_SUB); 1456 1457 if ((uSet == null) || (uSet.size() > 1) || uSet.isEmpty()) { 1458 // throw an exception 1459 Object args[] = { rid }; 1460 throw new AMException(AMSDKBundle.getString("971", args, locale), 1461 "971", args); 1462 } 1463 1464 String uDN = (String) uSet.iterator().next(); 1465 AMResource resource = getResource(uDN); 1466 resource.purge(false, graceperiod); 1467 1468 return; 1469 } 1470 1471 /** 1472 * This method takes a group name and a domain name, It uses default search 1473 * templates to search for the organization and uses the deleted objects 1474 * search filter for Groups as defined in the Administration Service of 1475 * Access Manager. This filter is used to search for the deleted user under 1476 * the organization. If the group is marked for deletion and the grace 1477 * period is passed then the group is purged. The pre-delete call backs as 1478 * listed in the Administration service, are called before the group is 1479 * deleted. If any of the <code>callbacks</code> throw an exception the 1480 * delete operation is aborted. 1481 * 1482 * @param gid 1483 * group name 1484 * @param domainName 1485 * domain in which the group belongs. 1486 * @param graceperiod 1487 * time in days which should have passed before this user can be 1488 * deleted. If a -1 is passed, group is deleted right away 1489 * without check on <code>graceperiod</code>. 1490 * 1491 * @throws AMException 1492 * if there is an error in deleting the group, or if the 1493 * <code>callbacks</code> thrown an exception 1494 * @throws SSOException 1495 */ 1496 public void purgeGroup(String gid, String domainName, int graceperiod) 1497 throws AMException, SSOException { 1498 String orgDN = getOrganizationDN(domainName, null); 1499 String filter = AMCompliance.getDeletedObjectFilter(AMObject.GROUP); 1500 filter = AMObjectImpl.constructFilter(AMNamingAttrManager 1501 .getNamingAttr(AMObject.GROUP), filter, gid); 1502 1503 if (AMCommonUtils.debug.messageEnabled()) { 1504 AMCommonUtils.debug.message("AMStoreConnection.purgeGroup: " 1505 + "Using deleted group filter= " + filter); 1506 } 1507 1508 Set gSet = dsServices.search(token, orgDN, filter, SCOPE_SUB); 1509 1510 if ((gSet == null) || (gSet.size() > 1) || gSet.isEmpty()) { 1511 // throw an exception 1512 Object args[] = { gid }; 1513 throw new AMException(AMSDKBundle.getString("971", args, locale), 1514 "971", args); 1515 } 1516 1517 String uDN = (String) gSet.iterator().next(); 1518 AMGroup g = null; 1519 int type = getAMObjectType(uDN); 1520 switch (type) { 1521 case AMObject.GROUP: 1522 case AMObject.STATIC_GROUP: 1523 g = new AMStaticGroupImpl(token, uDN); 1524 break; 1525 case AMObject.ASSIGNABLE_DYNAMIC_GROUP: 1526 g = new AMAssignableDynamicGroupImpl(token, uDN); 1527 break; 1528 case AMObject.DYNAMIC_GROUP: 1529 g = new AMDynamicGroupImpl(token, uDN); 1530 break; 1531 default: 1532 } 1533 if (g != null) { 1534 g.purge(false, graceperiod); 1535 } 1536 return; 1537 } 1538 1539 /** 1540 * Returns a set of <code>com.iplanet.am.sdk.AMEntityType</code> objects, 1541 * which is the set of objects which are supported by the 1542 * <code>com.iplanet.am.sdk.AMEntity</code> APIs. 1543 * 1544 * @return Set of <code>AMEntityType</code> objects. 1545 */ 1546 public Set getEntityTypes() { 1547 return AMCommonUtils.getSupportedEntityTypes(); 1548 } 1549 1550 protected String getBaseDN(ServiceConfig sc) { 1551 if (sc != null) { 1552 Map attrMap = sc.getAttributes(); 1553 Set vals = (Set) attrMap.get("baseDN"); 1554 1555 if ((vals == null) || vals.isEmpty()) { 1556 return null; 1557 } else { 1558 Iterator it = vals.iterator(); 1559 1560 return ((String) it.next()); 1561 } 1562 } else { 1563 return null; 1564 } 1565 } 1566 1567 protected boolean isRFC2247(ServiceConfig sc) { 1568 // ServiceConfig sc = getSearchTemplateConfig(orgTemplate); 1569 if (sc != null) { 1570 Map attrMap = sc.getAttributes(); 1571 Set vals = (Set) attrMap.get("rfc2247flag"); 1572 1573 if ((vals == null) || (vals.isEmpty())) { 1574 return (false); 1575 } else { 1576 Iterator it = vals.iterator(); 1577 1578 return (((String) it.next()).equalsIgnoreCase("true") ? true 1579 : false); 1580 } 1581 } else { 1582 return (false); 1583 } 1584 } 1585 1586 /** 1587 * Protected method to update the <code>orgMapCache</code> 1588 * 1589 */ 1590 protected static void addToOrgMapCache(SSOToken stoken, String dn) 1591 throws AMException, SSOException { 1592 if ((dn == null) || !LDAPUtils.isDN(dn)) { 1593 return; 1594 } 1595 1596 // String rfcDN = (new DN(dn)).toRFCString().toLowerCase(); 1597 String rfcDN = dn; 1598 Set attrNames = new HashSet(); 1599 attrNames.add("objectclass"); 1600 attrNames.add("sunpreferreddomain"); 1601 attrNames.add("associateddomain"); 1602 attrNames.add("sunorganizationalias"); 1603 1604 Map attributes = AMDirectoryAccessFactory.getDirectoryServices() 1605 .getAttributes(stoken, dn, attrNames, AMObject.ORGANIZATION); 1606 1607 // Add to cache 1608 String rdn = LDAPUtils.rdnValueFromDn(dn); 1609 Set prefDomain = (Set) attributes.get("sunpreferreddomain"); 1610 Set associatedDomain = (Set) attributes.get("associateddomain"); 1611 Set orgAlias = (Set) attributes.get("sunorganizationalias"); 1612 1613 synchronized (orgMapCache) { 1614 orgMapCache.put(rdn.toLowerCase(), rfcDN); 1615 1616 if ((prefDomain != null) && (prefDomain.size() == 1)) { 1617 String preferredDomain = (String) prefDomain.iterator().next(); 1618 1619 // AMHashMap so no need to lowercase 1620 orgMapCache.put(preferredDomain, rfcDN); 1621 } 1622 1623 if ((associatedDomain != null) && !associatedDomain.isEmpty()) { 1624 Iterator itr = associatedDomain.iterator(); 1625 1626 while (itr.hasNext()) { 1627 String value = (String) itr.next(); 1628 orgMapCache.put(value, rfcDN); 1629 } 1630 } 1631 1632 if ((orgAlias != null) && !orgAlias.isEmpty()) { 1633 Iterator itr = orgAlias.iterator(); 1634 1635 while (itr.hasNext()) { 1636 String value = (String) itr.next(); 1637 orgMapCache.put(value, rfcDN); 1638 } 1639 } 1640 } 1641 } 1642 1643 /** 1644 * Protected method to obtain the number of days since this DN was last 1645 * modified. 1646 */ 1647 protected static int daysSinceModified(SSOToken stoken, String entryDN) 1648 throws AMException, SSOException { 1649 NumberFormat nf = NumberFormat.getInstance(); 1650 SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss"); 1651 ParsePosition pp = new ParsePosition(0); 1652 1653 Set attrNames = new HashSet(1); 1654 1655 // Why are we adding objectclass when it is not being used? 1656 // If a specific reason, then we need to change the method call. 1657 // Same question applicable to other places where we add into orgmap 1658 // cache 1659 // attrNames.add("objectclass"); 1660 attrNames.add("modifytimestamp"); 1661 1662 Map attributes = AMDirectoryAccessFactory.getDirectoryServices() 1663 .getAttributes(stoken, entryDN, attrNames, 1664 AMObject.UNDETERMINED_OBJECT_TYPE); 1665 Set values = (Set) attributes.get("modifytimestamp"); 1666 1667 if ((values == null) || values.isEmpty()) { 1668 return -1; 1669 } 1670 1671 String value = (String) values.iterator().next(); 1672 1673 if ((value == null) || value.length() == 0) { 1674 return -1; 1675 } 1676 1677 Number n; 1678 1679 try { 1680 n = nf.parse(value); 1681 } catch (ParseException pe) { 1682 if (AMCommonUtils.debug.warningEnabled()) { 1683 AMCommonUtils.debug.warning("AMStoreConnection.daysSinceModified: " 1684 + "unable to parse date: " + value 1685 + " :Returning default= -1", pe); 1686 } 1687 1688 return (-1); 1689 } 1690 1691 Date modDate = df.parse(n.toString(), pp); 1692 Date nowDate = newDate(); 1693 1694 // getTime() fn returns number of milliseconds 1695 // since January 1, 1970, 00:00:00 GMT 1696 long modTimeMSecs = modDate.getTime(); 1697 long nowTimeMSecs = nowDate.getTime(); 1698 1699 long elapsedTimeMSecs = nowTimeMSecs - modTimeMSecs; 1700 int elapsedDays = (int) (elapsedTimeMSecs / (1000 * 60 * 60 * 24)); 1701 1702 if (AMCommonUtils.debug.messageEnabled()) { 1703 AMCommonUtils.debug.message("AMStoreConnection.daysSinceModified() for dn: " 1704 + entryDN + ", days: " + elapsedDays + " days"); 1705 } 1706 1707 return (elapsedDays); 1708 } 1709 1710 /** 1711 * Protected method to update <code>orgMapCache</code>. 1712 */ 1713 protected static void updateCache(String dn, int eventType) { 1714 if ((dn == null) || !LDAPUtils.isDN(dn)) { 1715 return; 1716 } 1717 1718 String rfcDN = LDAPUtils.formatToRFC(dn); 1719 switch (eventType) { 1720 case AMEvent.OBJECT_ADDED: 1721 // nothing to do 1722 return; 1723 1724 case AMEvent.OBJECT_RENAMED: 1725 synchronized (orgMapCache) { 1726 orgMapCache.clear(); 1727 } 1728 return; 1729 1730 case AMEvent.OBJECT_REMOVED: 1731 case AMEvent.OBJECT_CHANGED: 1732 // Go through the entire cache and check and delete 1733 // any entries with values matching this DN 1734 synchronized (orgMapCache) { 1735 Iterator keys = orgMapCache.keySet().iterator(); 1736 1737 // String removeKey = null; 1738 Set removeKeys = new HashSet(); 1739 1740 while (keys.hasNext()) { 1741 String key = (String) keys.next(); 1742 String val = (String) orgMapCache.get(key); 1743 1744 if (val.equalsIgnoreCase(rfcDN)) { 1745 removeKeys.add(key); 1746 } 1747 } 1748 1749 if (removeKeys != null) { 1750 keys = removeKeys.iterator(); 1751 1752 while (keys.hasNext()) { 1753 String removeKey = (String) keys.next(); 1754 orgMapCache.remove(removeKey); 1755 } 1756 } 1757 // orgMapCache.clear(); 1758 } 1759 } 1760 } 1761 1762 private Set getOrganizations(String domainname, String orgSearchTemplate) 1763 throws AMException, SSOException { 1764 if (domainname == null) { 1765 return Collections.EMPTY_SET; 1766 } 1767 1768 // use the searchfilter to obtain organization DN 1769 // replace %V with domainname. 1770 String searchFilter = AMSearchFilterManager.getSearchFilter( 1771 AMObject.ORGANIZATION, null, orgSearchTemplate, false); 1772 1773 if ((orgSearchTemplate != null) && (searchFilter.indexOf("%V") > -1)) { 1774 searchFilter = AMObjectImpl.constructFilter(AMNamingAttrManager 1775 .getNamingAttr(AMObject.ORGANIZATION), searchFilter, 1776 domainname); 1777 } else { 1778 StringBuilder sb = new StringBuilder(); 1779 sb.append("(|(&(").append( 1780 AMNamingAttrManager.getNamingAttr(AMObject.ORGANIZATION)) 1781 .append("=").append(domainname).append(")").append( 1782 searchFilter).append(")(&(").append( 1783 "sunPreferredDomain=").append(domainname).append( 1784 ")").append(searchFilter).append(")(&(").append( 1785 "associatedDomain=").append(domainname).append(")") 1786 .append(searchFilter).append(")(&(").append( 1787 "sunOrganizationAlias=").append(domainname).append( 1788 ")").append(searchFilter).append("))"); 1789 searchFilter = sb.toString(); 1790 } 1791 1792 if (AMCommonUtils.debug.messageEnabled()) { 1793 AMCommonUtils.debug.message("AMSC:getOrgDN-> " + "using searchfilter " 1794 + searchFilter); 1795 } 1796 1797 Set orgSet = dsServices.search(token, rootSuffix, searchFilter, 1798 SCOPE_SUB); 1799 return orgSet; 1800 } 1801 1802 /** 1803 * Converts organization name which is "/" separated to DN. 1804 */ 1805 private static String orgNameToDN(String orgName) { 1806 // Check if it is null or empty 1807 if ((orgName == null) || (orgName.length() == 0)) { 1808 return (rootSuffix); 1809 } 1810 1811 // Check if it is org name 1812 if (LDAPUtils.isDN(orgName)) { 1813 return (orgName); 1814 } 1815 1816 // Construct the DN 1817 StringBuilder buf = new StringBuilder(); 1818 ArrayList arr = new ArrayList(); 1819 StringTokenizer strtok = new StringTokenizer(orgName, "/"); 1820 1821 while (strtok.hasMoreElements()) { 1822 arr.add(strtok.nextToken()); 1823 } 1824 1825 int size = arr.size(); 1826 1827 for (int i = 0; i < size; i++) { 1828 String theOrg = (String) arr.get(i); 1829 buf 1830 .append(AMNamingAttrManager 1831 .getNamingAttr(AMObject.ORGANIZATION)); 1832 buf.append('=').append(theOrg).append(','); 1833 } 1834 1835 if (rootSuffix.length() > 0) { 1836 buf.append(rootSuffix); 1837 } else { 1838 buf.deleteCharAt(buf.length() - 1); 1839 } 1840 1841 return (buf.toString()); 1842 } 1843}