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 */
028
029/**
030 * Portions Copyrighted 2011-2012 ForgeRock Inc
031 */
032package com.iplanet.am.sdk;
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.SMSEntry;
039import com.sun.identity.sm.SMSException;
040import com.sun.identity.sm.SchemaType;
041import com.sun.identity.sm.ServiceConfig;
042import com.sun.identity.sm.ServiceManager;
043import com.sun.identity.sm.ServiceSchemaManager;
044import java.text.NumberFormat;
045import java.text.ParseException;
046import java.text.ParsePosition;
047import java.text.SimpleDateFormat;
048import java.util.ArrayList;
049import java.util.Collections;
050import java.util.Date;
051import java.util.HashSet;
052import java.util.Iterator;
053import java.util.List;
054import java.util.Map;
055import java.util.Set;
056import java.util.StringTokenizer;
057import com.sun.identity.shared.ldap.LDAPDN;
058import com.sun.identity.shared.ldap.util.DN;
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,&lt;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 (DN.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 (!com.sun.identity.shared.ldap.util.DN.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 = (new DN(orgDN)).countRDNs();
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 = new DN(thisDN);
1273                    int count = dn.countRDNs();
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.countRDNs() == i) {
1289                            String thisDN = thisdn.toRFCString();
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 (!(new DN(thisDN)).equals(new DN(orgDN)))
1333                                    {
1334                                        thisObj.purge(true, graceperiod);
1335                                    }
1336
1337                                    break;
1338
1339                                default:
1340
1341                                    // should not show up in the searched
1342                                    // objects.
1343                                    // as none of the other objects are
1344                                    // supported
1345                                    // for being marked as soft-deleted/
1346                                    // purging.
1347                                    break;
1348                                } // switch
1349                            } catch (AMPreCallBackException amp) {
1350                                AMCommonUtils.debug.error("AMStoreConnection.purge: "
1351                                        + "Aborting delete of: "
1352                                        + thisDN
1353                                        + " due to pre-callback exception",
1354                                        amp);
1355                            }
1356                        } // if
1357                    } // for
1358                } // for
1359
1360            } // else
1361        } // delIter
1362
1363        return;
1364    }
1365
1366    /**
1367     * This method takes a user ID and a domain name, It uses default search
1368     * templates to search for the organization and uses the deleted objects
1369     * search filter for Users as defined in the Administration Service of
1370     * Access Manager. This filter is used to search for the deleted user under
1371     * the organization. If the user is marked for deletion and the grace period
1372     * is passed then the user is purged. The pre-delete call backs as listed in
1373     * the Administration service, are called before the user is deleted. If any
1374     * of the <code>callbacks</code> throw an exception the delete operation
1375     * is aborted.
1376     * 
1377     * @param uid
1378     *            user ID
1379     * @param domainName
1380     *            domain in which the user belongs.
1381     * @param graceperiod
1382     *            time in days which should have passed before this user can be
1383     *            deleted.
1384     * 
1385     * @throws AMException
1386     *             if there is an error in deleting the user, or if the user
1387     *             <code>callbacks</code> thrown an exception
1388     * @throws SSOException
1389     */
1390    public void purgeUser(String uid, String domainName, int graceperiod)
1391            throws AMException, SSOException {
1392        String orgDN = getOrganizationDN(domainName, null);
1393        String filter = AMCompliance.getDeletedObjectFilter(AMObject.USER);
1394        filter = AMObjectImpl.constructFilter(AMNamingAttrManager
1395                .getNamingAttr(AMObject.USER), filter, uid);
1396
1397        if (AMCommonUtils.debug.messageEnabled()) {
1398            AMCommonUtils.debug.message("AMStoreConnection.purgeGroup: "
1399                    + "Using deleted user filter= " + filter);
1400        }
1401
1402        Set uSet = dsServices.search(token, orgDN, filter, SCOPE_SUB);
1403
1404        if ((uSet == null) || (uSet.size() > 1) || uSet.isEmpty()) {
1405            // throw an exception
1406            Object args[] = { uid };
1407            throw new AMException(AMSDKBundle.getString("971", args, locale),
1408                    "971", args);
1409        }
1410
1411        String uDN = (String) uSet.iterator().next();
1412        AMUser user = getUser(uDN);
1413        user.purge(false, graceperiod);
1414
1415        return;
1416    }
1417
1418    /**
1419     * This method takes a resource ID and a domain name, It uses default search
1420     * templates to search for the organization and uses the deleted objects
1421     * search filter for Resources as defined in the Administration Service of
1422     * Access Manager. This filter is used to search for the deleted resource
1423     * under the organization. If the resource is marked for deletion and the
1424     * grace period is passed then the resource is purged. The pre-delete call
1425     * backs as listed in the Administration service, are called before the user
1426     * is deleted. If any of the <code>callbacks</code> throw an exception the
1427     * delete operation is aborted.
1428     * 
1429     * @param rid
1430     *            resource ID
1431     * @param domainName
1432     *            domain in which the user belongs.
1433     * @param graceperiod
1434     *            time in days which should have passed before this user can be
1435     *            deleted.
1436     * 
1437     * @throws AMException
1438     *             if there is an error in deleting the user, or if the user
1439     *             <code>callbacks</code> thrown an exception
1440     * @throws SSOException
1441     */
1442    public void purgeResource(String rid, String domainName, int graceperiod)
1443            throws AMException, SSOException {
1444        String orgDN = getOrganizationDN(domainName, null);
1445        String filter = AMCompliance.getDeletedObjectFilter(AMObject.RESOURCE);
1446        filter = AMObjectImpl.constructFilter(AMNamingAttrManager
1447                .getNamingAttr(AMObject.RESOURCE), filter, rid);
1448
1449        if (AMCommonUtils.debug.messageEnabled()) {
1450            AMCommonUtils.debug.message("AMStoreConnection.purgeGroup: "
1451                    + "Using deleted user filter= " + filter);
1452        }
1453
1454        Set uSet = dsServices.search(token, orgDN, filter, SCOPE_SUB);
1455
1456        if ((uSet == null) || (uSet.size() > 1) || uSet.isEmpty()) {
1457            // throw an exception
1458            Object args[] = { rid };
1459            throw new AMException(AMSDKBundle.getString("971", args, locale),
1460                    "971", args);
1461        }
1462
1463        String uDN = (String) uSet.iterator().next();
1464        AMResource resource = getResource(uDN);
1465        resource.purge(false, graceperiod);
1466
1467        return;
1468    }
1469
1470    /**
1471     * This method takes a group name and a domain name, It uses default search
1472     * templates to search for the organization and uses the deleted objects
1473     * search filter for Groups as defined in the Administration Service of
1474     * Access Manager. This filter is used to search for the deleted user under
1475     * the organization. If the group is marked for deletion and the grace
1476     * period is passed then the group is purged. The pre-delete call backs as
1477     * listed in the Administration service, are called before the group is
1478     * deleted. If any of the <code>callbacks</code> throw an exception the
1479     * delete operation is aborted.
1480     * 
1481     * @param gid
1482     *            group name
1483     * @param domainName
1484     *            domain in which the group belongs.
1485     * @param graceperiod
1486     *            time in days which should have passed before this user can be
1487     *            deleted. If a -1 is passed, group is deleted right away
1488     *            without check on <code>graceperiod</code>.
1489     * 
1490     * @throws AMException
1491     *             if there is an error in deleting the group, or if the
1492     *             <code>callbacks</code> thrown an exception
1493     * @throws SSOException
1494     */
1495    public void purgeGroup(String gid, String domainName, int graceperiod)
1496            throws AMException, SSOException {
1497        String orgDN = getOrganizationDN(domainName, null);
1498        String filter = AMCompliance.getDeletedObjectFilter(AMObject.GROUP);
1499        filter = AMObjectImpl.constructFilter(AMNamingAttrManager
1500                .getNamingAttr(AMObject.GROUP), filter, gid);
1501
1502        if (AMCommonUtils.debug.messageEnabled()) {
1503            AMCommonUtils.debug.message("AMStoreConnection.purgeGroup: "
1504                    + "Using deleted group filter= " + filter);
1505        }
1506
1507        Set gSet = dsServices.search(token, orgDN, filter, SCOPE_SUB);
1508
1509        if ((gSet == null) || (gSet.size() > 1) || gSet.isEmpty()) {
1510            // throw an exception
1511            Object args[] = { gid };
1512            throw new AMException(AMSDKBundle.getString("971", args, locale),
1513                    "971", args);
1514        }
1515
1516        String uDN = (String) gSet.iterator().next();
1517        AMGroup g = null;
1518        int type = getAMObjectType(uDN);
1519        switch (type) {
1520        case AMObject.GROUP:
1521        case AMObject.STATIC_GROUP:
1522            g = new AMStaticGroupImpl(token, uDN);
1523            break;
1524        case AMObject.ASSIGNABLE_DYNAMIC_GROUP:
1525            g = new AMAssignableDynamicGroupImpl(token, uDN);
1526            break;
1527        case AMObject.DYNAMIC_GROUP:
1528            g = new AMDynamicGroupImpl(token, uDN);
1529            break;
1530        default:
1531        }
1532        if (g != null) {
1533            g.purge(false, graceperiod);
1534        }
1535        return;
1536    }
1537
1538    /**
1539     * Returns a set of <code>com.iplanet.am.sdk.AMEntityType</code> objects,
1540     * which is the set of objects which are supported by the
1541     * <code>com.iplanet.am.sdk.AMEntity</code> APIs.
1542     * 
1543     * @return Set of <code>AMEntityType</code> objects.
1544     */
1545    public Set getEntityTypes() {
1546        return AMCommonUtils.getSupportedEntityTypes();
1547    }
1548
1549    protected String getBaseDN(ServiceConfig sc) {
1550        if (sc != null) {
1551            Map attrMap = sc.getAttributes();
1552            Set vals = (Set) attrMap.get("baseDN");
1553
1554            if ((vals == null) || vals.isEmpty()) {
1555                return null;
1556            } else {
1557                Iterator it = vals.iterator();
1558
1559                return ((String) it.next());
1560            }
1561        } else {
1562            return null;
1563        }
1564    }
1565
1566    protected boolean isRFC2247(ServiceConfig sc) {
1567        // ServiceConfig sc = getSearchTemplateConfig(orgTemplate);
1568        if (sc != null) {
1569            Map attrMap = sc.getAttributes();
1570            Set vals = (Set) attrMap.get("rfc2247flag");
1571
1572            if ((vals == null) || (vals.isEmpty())) {
1573                return (false);
1574            } else {
1575                Iterator it = vals.iterator();
1576
1577                return (((String) it.next()).equalsIgnoreCase("true") ? true
1578                        : false);
1579            }
1580        } else {
1581            return (false);
1582        }
1583    }
1584
1585    /**
1586     * Protected method to update the <code>orgMapCache</code>
1587     * 
1588     */
1589    protected static void addToOrgMapCache(SSOToken stoken, String dn)
1590            throws AMException, SSOException {
1591        if ((dn == null) || !DN.isDN(dn)) {
1592            return;
1593        }
1594
1595        // String rfcDN = (new DN(dn)).toRFCString().toLowerCase();
1596        String rfcDN = dn;
1597        Set attrNames = new HashSet();
1598        attrNames.add("objectclass");
1599        attrNames.add("sunpreferreddomain");
1600        attrNames.add("associateddomain");
1601        attrNames.add("sunorganizationalias");
1602
1603        Map attributes = AMDirectoryAccessFactory.getDirectoryServices()
1604                .getAttributes(stoken, dn, attrNames, AMObject.ORGANIZATION);
1605
1606        // Add to cache
1607        String rdn = LDAPDN.explodeDN(dn, true)[0];
1608        Set prefDomain = (Set) attributes.get("sunpreferreddomain");
1609        Set associatedDomain = (Set) attributes.get("associateddomain");
1610        Set orgAlias = (Set) attributes.get("sunorganizationalias");
1611
1612        synchronized (orgMapCache) {
1613            orgMapCache.put(rdn.toLowerCase(), rfcDN);
1614
1615            if ((prefDomain != null) && (prefDomain.size() == 1)) {
1616                String preferredDomain = (String) prefDomain.iterator().next();
1617
1618                // AMHashMap so no need to lowercase
1619                orgMapCache.put(preferredDomain, rfcDN);
1620            }
1621
1622            if ((associatedDomain != null) && !associatedDomain.isEmpty()) {
1623                Iterator itr = associatedDomain.iterator();
1624
1625                while (itr.hasNext()) {
1626                    String value = (String) itr.next();
1627                    orgMapCache.put(value, rfcDN);
1628                }
1629            }
1630
1631            if ((orgAlias != null) && !orgAlias.isEmpty()) {
1632                Iterator itr = orgAlias.iterator();
1633
1634                while (itr.hasNext()) {
1635                    String value = (String) itr.next();
1636                    orgMapCache.put(value, rfcDN);
1637                }
1638            }
1639        }
1640    }
1641
1642    /**
1643     * Protected method to obtain the number of days since this DN was last
1644     * modified.
1645     */
1646    protected static int daysSinceModified(SSOToken stoken, String entryDN)
1647            throws AMException, SSOException {
1648        NumberFormat nf = NumberFormat.getInstance();
1649        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
1650        ParsePosition pp = new ParsePosition(0);
1651
1652        Set attrNames = new HashSet(1);
1653
1654        // Why are we adding objectclass when it is not being used?
1655        // If a specific reason, then we need to change the method call.
1656        // Same question applicable to other places where we add into orgmap
1657        // cache
1658        // attrNames.add("objectclass");
1659        attrNames.add("modifytimestamp");
1660
1661        Map attributes = AMDirectoryAccessFactory.getDirectoryServices()
1662                .getAttributes(stoken, entryDN, attrNames,
1663                        AMObject.UNDETERMINED_OBJECT_TYPE);
1664        Set values = (Set) attributes.get("modifytimestamp");
1665
1666        if ((values == null) || values.isEmpty()) {
1667            return -1;
1668        }
1669
1670        String value = (String) values.iterator().next();
1671
1672        if ((value == null) || value.length() == 0) {
1673            return -1;
1674        }
1675
1676        Number n;
1677
1678        try {
1679            n = nf.parse(value);
1680        } catch (ParseException pe) {
1681        if (AMCommonUtils.debug.warningEnabled()) {
1682            AMCommonUtils.debug.warning("AMStoreConnection.daysSinceModified: "
1683                        + "unable to parse date: " + value
1684                        + " :Returning default= -1", pe);
1685            }
1686
1687            return (-1);
1688        }
1689
1690        Date modDate = df.parse(n.toString(), pp);
1691        Date nowDate = new Date();
1692
1693        // getTime() fn returns number of milliseconds
1694        // since January 1, 1970, 00:00:00 GMT
1695        long modTimeMSecs = modDate.getTime();
1696        long nowTimeMSecs = nowDate.getTime();
1697
1698        long elapsedTimeMSecs = nowTimeMSecs - modTimeMSecs;
1699        int elapsedDays = (int) (elapsedTimeMSecs / (1000 * 60 * 60 * 24));
1700
1701        if (AMCommonUtils.debug.messageEnabled()) {
1702            AMCommonUtils.debug.message("AMStoreConnection.daysSinceModified() for dn: "
1703                    + entryDN + ", days: " + elapsedDays + " days");
1704        }
1705
1706        return (elapsedDays);
1707    }
1708
1709    /**
1710     * Protected method to update <code>orgMapCache</code>.
1711     */
1712    protected static void updateCache(String dn, int eventType) {
1713        if ((dn == null) || !DN.isDN(dn)) {
1714            return;
1715        }
1716
1717        String rfcDN = AMCommonUtils.formatToRFC(dn);
1718        switch (eventType) {
1719        case AMEvent.OBJECT_ADDED:
1720            // nothing to do
1721            return;
1722
1723        case AMEvent.OBJECT_RENAMED:
1724            synchronized (orgMapCache) {
1725                orgMapCache.clear();
1726            }
1727            return;
1728
1729        case AMEvent.OBJECT_REMOVED:
1730        case AMEvent.OBJECT_CHANGED:
1731            // Go through the entire cache and check and delete
1732            // any entries with values matching this DN
1733            synchronized (orgMapCache) {
1734                Iterator keys = orgMapCache.keySet().iterator();
1735
1736                // String removeKey = null;
1737                Set removeKeys = new HashSet();
1738
1739                while (keys.hasNext()) {
1740                    String key = (String) keys.next();
1741                    String val = (String) orgMapCache.get(key);
1742
1743                    if (val.equalsIgnoreCase(rfcDN)) {
1744                        removeKeys.add(key);
1745                    }
1746                }
1747
1748                if (removeKeys != null) {
1749                    keys = removeKeys.iterator();
1750
1751                    while (keys.hasNext()) {
1752                        String removeKey = (String) keys.next();
1753                        orgMapCache.remove(removeKey);
1754                    }
1755                }
1756                // orgMapCache.clear();
1757            }
1758        }
1759    }
1760
1761    private Set getOrganizations(String domainname, String orgSearchTemplate)
1762            throws AMException, SSOException {
1763        if (domainname == null) {
1764            return Collections.EMPTY_SET;
1765        }
1766
1767        // use the searchfilter to obtain organization DN
1768        // replace %V with domainname.
1769        String searchFilter = AMSearchFilterManager.getSearchFilter(
1770                AMObject.ORGANIZATION, null, orgSearchTemplate, false);
1771
1772        if ((orgSearchTemplate != null) && (searchFilter.indexOf("%V") > -1)) {
1773            searchFilter = AMObjectImpl.constructFilter(AMNamingAttrManager
1774                    .getNamingAttr(AMObject.ORGANIZATION), searchFilter,
1775                    domainname);
1776        } else {
1777            StringBuilder sb = new StringBuilder();
1778            sb.append("(|(&(").append(
1779                    AMNamingAttrManager.getNamingAttr(AMObject.ORGANIZATION))
1780                    .append("=").append(domainname).append(")").append(
1781                            searchFilter).append(")(&(").append(
1782                            "sunPreferredDomain=").append(domainname).append(
1783                            ")").append(searchFilter).append(")(&(").append(
1784                            "associatedDomain=").append(domainname).append(")")
1785                    .append(searchFilter).append(")(&(").append(
1786                            "sunOrganizationAlias=").append(domainname).append(
1787                            ")").append(searchFilter).append("))");
1788            searchFilter = sb.toString();
1789        }
1790
1791        if (AMCommonUtils.debug.messageEnabled()) {
1792            AMCommonUtils.debug.message("AMSC:getOrgDN-> " + "using searchfilter "
1793                    + searchFilter);
1794        }
1795
1796        Set orgSet = dsServices.search(token, rootSuffix, searchFilter,
1797                SCOPE_SUB);
1798        return orgSet;
1799    }
1800
1801    /**
1802     * Converts organization name which is "/" separated to DN.
1803     */
1804    private static String orgNameToDN(String orgName) {
1805        // Check if it is null or empty
1806        if ((orgName == null) || (orgName.length() == 0)) {
1807            return (rootSuffix);
1808        }
1809
1810        // Check if it is org name
1811        if (DN.isDN(orgName)) {
1812            return (orgName);
1813        }
1814
1815        // Construct the DN
1816        StringBuilder buf = new StringBuilder();
1817        ArrayList arr = new ArrayList();
1818        StringTokenizer strtok = new StringTokenizer(orgName, "/");
1819
1820        while (strtok.hasMoreElements()) {
1821            arr.add(strtok.nextToken());
1822        }
1823
1824        int size = arr.size();
1825
1826        for (int i = 0; i < size; i++) {
1827            String theOrg = (String) arr.get(i);
1828            buf
1829                    .append(AMNamingAttrManager
1830                            .getNamingAttr(AMObject.ORGANIZATION));
1831            buf.append('=').append(theOrg).append(',');
1832        }
1833
1834        if (rootSuffix.length() > 0) {
1835            buf.append(rootSuffix);
1836        } else {
1837            buf.deleteCharAt(buf.length() - 1);
1838        }
1839
1840        return (buf.toString());
1841    }
1842}




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.