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