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: OrganizationConfigManager.java,v 1.31 2010/01/20 17:01:36 veiming Exp $
026 *
027 * Portions Copyrighted 2011-2014 ForgeRock AS.
028 */
029package com.sun.identity.sm;
030
031import com.iplanet.am.util.SystemProperties;
032import java.util.Collections;
033import java.util.HashMap;
034import java.util.HashSet;
035import java.util.Iterator;
036import java.util.Map;
037import java.util.regex.Pattern;
038import java.util.Set;
039import java.util.StringTokenizer;
040
041import com.sun.identity.shared.ldap.util.DN;
042
043import com.iplanet.sso.SSOException;
044import com.iplanet.sso.SSOToken;
045import com.iplanet.ums.IUMSConstants;
046import com.sun.identity.authentication.util.ISAuthConstants;
047import com.sun.identity.common.CaseInsensitiveHashSet;
048import com.sun.identity.delegation.DelegationException;
049import com.sun.identity.delegation.DelegationUtils;
050import com.sun.identity.idm.IdConstants;
051import com.sun.identity.idm.IdRepoException;
052import com.sun.identity.idm.plugins.internal.AgentsRepo;
053import com.sun.identity.shared.Constants;
054
055/**
056 * The class <code>OrganizationConfigManager</code> provides interfaces to
057 * manage an organization's configuration data. It provides interfaces to create
058 * and delete organizations, service attributes for organizations and service
059 * configuration parameters.
060 * <p>
061 * The organization configuration can be managed in a hierarchical manner, and a
062 * forward slash "/" will be used to separate the name hierarchy. Hence the root
063 * of the organization hierarchy will be represented by a single forward slash
064 * "/", and sub-organizations will be separated by "/". For example "/a/b/c"
065 * would represent a "c" sub-organization within "b" which would be a
066 * sub-organization of "a".
067 *
068 * @supported.all.api
069 */
070public class OrganizationConfigManager {
071    // Instance variables
072    private SSOToken token;
073
074    private String orgName;
075
076    private String orgDN;
077
078    private OrgConfigViaAMSDK amsdk;
079
080    private OrganizationConfigManagerImpl orgConfigImpl;
081
082    static String orgNamingAttrInLegacyMode;
083
084    static Pattern baseDNpattern = Pattern.compile(SMSEntry.getRootSuffix());
085
086    protected static final String SERVICES_NODE = SMSEntry.SERVICES_RDN
087            + SMSEntry.COMMA + SMSEntry.getRootSuffix();
088
089    // set the special characters which are not in realm names.
090    static String specialCharsString = "*|(|)|!|/|=";
091
092    private static String SEPERATOR = "|";
093
094    private String CONF_ENABLED =
095        "sun-idrepo-amSDK-config-copyconfig-enabled";
096
097    private boolean copyOrgInitialized;
098
099    private boolean copyOrgEnabled;
100
101    private String amSDKOrgDN;
102
103    // sunOrganizationAlias in org DIT.
104    public static final String SUNORG_ALIAS = "sunOrganizationAliases";
105
106    // associatedDomain in org DIT.
107    private String SUNDNS_ALIAS = "sunDNSAliases";
108
109    // sunPreferredDomain in org DIT.
110    private String SUNPREF_DOMAIN = "sunPreferredDomain";
111
112    // inetDomainStatus in org DIT.
113    private String SUNORG_STATUS = "sunOrganizationStatus";
114
115    static {
116        initializeFlags();
117    }
118
119    /**
120     * Constructor to obtain an instance of
121     * <code>OrganizationConfigManager
122     * </code> for an organization by providing
123     * an authenticated identity of the user. The organization name would be "/"
124     * seperated to represent organization hierarchy.
125     * 
126     * @param token
127     *            single sign on token of authenticated user identity.
128     * @param orgName
129     *            name of the organization. The value of <code>null
130     * </code> or
131     *            "/" would represent the root organization.
132     * 
133     * @throws SMSException
134     *             if an error has occurred while getting the instance of
135     *             <code>OrganizationConfigManager
136     *                      </code>.
137     */
138    public OrganizationConfigManager(SSOToken token, String orgName)
139            throws SMSException {
140        // Copy instance variables
141        this.token = token;
142        this.orgName = orgName;
143
144        // Instantiate and validate
145        validateConfigImpl();
146        orgDN = orgConfigImpl.getOrgDN();
147        try {
148            if (migratedTo70 && !registeredForConfigNotifications) {
149                ServiceConfigManager scmr = new ServiceConfigManager(
150                        ServiceManager.REALM_SERVICE, token);
151                scmr.addListener(new OrganizationConfigManagerListener());
152                registeredForConfigNotifications = true;
153            }
154        } catch (SMSException s) {
155            String installTime = SystemProperties.get(
156                Constants.SYS_PROPERTY_INSTALL_TIME, "false");
157            if (!installTime.equals("true")) {
158                SMSEntry.debug.warning("OrganizationConfigManager: "
159                    + "constructor. Unable to "
160                    + "construct ServiceConfigManager for idRepoService ", s);
161            }
162            throw s;
163        } catch (SSOException ssoe) {
164            SMSEntry.debug.error("OrganizationConfigManager:Constructor", ssoe);
165            throw (new SMSException(SMSEntry.bundle
166                    .getString("sms-INVALID_SSO_TOKEN"),
167                    "sms-INVALID_SSO_TOKEN"));
168        }
169
170        if (coexistMode) {
171            amsdk = new OrgConfigViaAMSDK(token, DNMapper
172                    .realmNameToAMSDKName(orgDN), orgDN);
173            if (orgNamingAttrInLegacyMode == null) {
174                orgNamingAttrInLegacyMode = getNamingAttrForOrg();
175            }
176        }
177    }
178
179    /**
180     * Returns the fully qualified name of the
181     * organization from the root
182     * 
183     * @return the name of the organization
184     */
185    public String getOrganizationName() {
186        return (orgName);
187    }
188
189    /**
190     * Returns the services configured for the organization.
191     * 
192     * @return service names configured for the organization.
193     * @throws SMSException
194     *             if there is an error accessing the data store to read the
195     *             configured services.
196     * 
197     * @deprecated This method has been deprecated, use <code>
198     * getAssignedServices()</code>
199     *             instead.
200     */
201    public Set getConfiguredServices() throws SMSException {
202        return (getAssignedServices());
203    }
204
205    /**
206     * Returns a set of service schemas to be used for
207     * creation of an organization. The service schemas contain a list of
208     * attributes and their schema, and will be provided as
209     * <code>ServiceSchema</code>.
210     * 
211     * @return Set of <code>ServiceSchema</code> to be used for creation of an
212     *         organization.
213     * @throws SMSException
214     *             if there is an error accessing the data store to read the
215     *             service schemas.
216     */
217    public Set getServiceSchemas() throws SMSException {
218        // Loop through the services and determine the
219        // organization creation schemas
220        Set serviceSchemaSet = null;
221        try {
222            Set serviceNames = getServiceNames(token);
223            serviceSchemaSet = new HashSet(serviceNames.size() * 2);
224            for (Iterator names = serviceNames.iterator(); names.hasNext();) {
225                ServiceSchemaManager ssm = new ServiceSchemaManager(
226                    (String) names.next(), token);
227                ServiceSchema ss = ssm.getOrganizationCreationSchema();
228                if (ss != null) {
229                    serviceSchemaSet.add(ss);
230                }
231            }
232        } catch (SSOException ssoe) {
233            SMSEntry.debug.error("OrganizationConfigManager:getServiceSchemas"
234                    + " unable to get service schema", ssoe);
235            throw (new SMSException(SMSEntry.bundle
236                    .getString("sms-INVALID_SSO_TOKEN"), ssoe,
237                    "sms-INVALID_SSO_TOKEN"));
238        }
239        return (serviceSchemaSet);
240    }
241
242    /**
243     * Creates a sub-organization under the current
244     * organization and sets the specified attributes. The sub-organization
245     * created can be only one level below the current organization. For
246     * multiple levels this method must be called recursively with the
247     * corresponding <code>OrganizationConfigManager
248     * </code>. The organization
249     * name must not have forward slash ("/"). For eg., the actual organization
250     * name 'iplanet' cannot be 'iplan/et' because we are using '/' as the
251     * seperator here. The attributes for the organization can be <code>
252     * null</code>;
253     * else would contain service name as the key and another <code>Map</code>
254     * as the value that would contain the key-values pair for the services.
255     * 
256     * @param subOrgName
257     *            the name of the sub-organization.
258     * @param attributes
259     *            Map of attributes for the organization per service. The
260     *            parameter Map attributes contains another Map as its value,
261     *            which then has attribute names and values. The way it is
262     *            arranged is: Map::attributes --> Key: String::ServiceName
263     *            Value: Map::svcAttributes Map::svcAttributes --> Key:
264     *            String::AttributeName Value: Set::AttributeValues
265     * 
266     * @return organization config manager of the newly created
267     *         sub-organization.
268     * @throws SMSException
269     *             if creation of sub-organization failed, or if creation of
270     *             sub-organization is attempted when configuration is not
271     *             migrated to realms.
272     */
273    public OrganizationConfigManager createSubOrganization(String subOrgName,
274            Map attributes) throws SMSException {
275        validateConfigImpl();
276        /*
277         * Since the "Map attributes" can contain more than one service name,
278         * creation of the sub organization is be achieved in 2 steps. i) create
279         * the sub-organization without the attributes ii) for the service names
280         * in the Map call setAttributes(...)
281         */
282        boolean orgExists = false;
283        String subOrgDN = normalizeDN(subOrgName, orgDN);
284        try {
285            // Check if realm exists, this throws SMSException
286            // if realm does not exist
287            // This is to avoid duplicate creation of realms.
288            new OrganizationConfigManager(token, subOrgDN);
289            SMSEntry.debug.error("OrganizationConfigManager::"
290                    + "createSubOrganization() " + "Realm Already Exists.. "
291                    + subOrgDN);
292            orgExists = true;
293        } catch (SMSException smse) {
294            // Realm does not exist, create it
295            if (SMSEntry.debug.messageEnabled()) {
296                SMSEntry.debug.message("OrganizationConfigManager::"
297                        + "createSubOrganization() "
298                        + "New Realm, creating realm: " + subOrgName + "-"
299                        + smse);
300            }
301        }
302        Object args[] = { subOrgName };
303        if (orgExists) {
304            throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
305                "sms-organization_already_exists1",
306                    args));
307        }
308        StringTokenizer st =
309            new StringTokenizer(specialCharsString, SEPERATOR);
310        while (st.hasMoreTokens()) {
311            String obj = (String) st.nextToken();
312            if (subOrgName.indexOf(obj) > -1) {
313                SMSEntry.debug.error("OrganizationConfigManager::"+
314                    "createSubOrganization() : Invalid realm name: "+
315                        subOrgName);
316                SMSEntry.debug.error("OrganizationConfigManager::"+
317                    "createSubOrganization() : Detected invalid chars: "+obj);
318                Object args1[] = {subOrgName};
319                throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
320                    SMSEntry.bundle.getString("sms-invalid-org-name"),args1));
321            }
322        }
323
324        // If in legacy mode or (realm mode and copy org enabled)
325        // Create the AMSDK organization first
326        if ((coexistMode) || (realmEnabled && isCopyOrgEnabled())) {
327            amsdk.createSubOrganization(subOrgName);
328        }
329        if ((realmEnabled || subOrgDN.toLowerCase().startsWith(
330                SMSEntry.SUN_INTERNAL_REALM_PREFIX))
331                && getSubOrganizationNames(subOrgName, false).isEmpty()) {
332            CreateServiceConfig.createOrganization(token, subOrgDN);
333        }
334        // Update the attributes
335        // If in coexistMode and serviceName is idRepoService
336        // the following call sets the attributes to AMSDK organization also.
337        OrganizationConfigManager ocm = getSubOrgConfigManager(subOrgName);
338        if ((attributes != null) && (!attributes.isEmpty())) {
339            for (Iterator svcNames = attributes.keySet().iterator(); svcNames
340                    .hasNext();) {
341                String serviceName = (String) svcNames.next();
342                Map svcAttributes = (Map) attributes.get(serviceName);
343                if ((svcAttributes != null) && (!svcAttributes.isEmpty())) {
344                    ocm.setAttributes(serviceName, svcAttributes);
345                }
346            }
347        }
348
349        if (realmEnabled) {
350            AgentsRepo agentsRepo = new AgentsRepo();
351            HashMap config = new HashMap(1);
352            HashSet realmName = new HashSet(1);
353            realmName.add(subOrgDN);
354            config.put("agentsRepoRealmName", realmName);
355            try {
356                agentsRepo.initialize(config);
357                agentsRepo.createAgentGroupConfig(token);
358            } catch (IdRepoException ide) {
359                SMSEntry.debug.error("OrganizationConfigManager::"+
360                        "createSubOrganization:", ide);
361            }
362        }
363                        
364        // If in realm mode and not in legacy mode, default services needs
365        // to be added.
366        if (realmEnabled && !coexistMode) {
367            loadDefaultServices(token, ocm);
368        }
369
370        // If in realm mode and copy org enabled, default services needs
371        // to be registered for the newly created org/suborg and the
372        // amSDKOrgName/OpenSSO Organization is updated with the
373        // new suborg dn.
374        if (realmEnabled && isCopyOrgEnabled()) {
375            registerSvcsForOrg(subOrgName, subOrgDN);
376            OrganizationConfigManager subOrg =
377                getSubOrgConfigManager(subOrgName);
378            ServiceConfig s =
379                subOrg.getServiceConfig(ServiceManager.REALM_SERVICE);
380            if (s != null) {
381                try {
382                    Iterator items = s.getSubConfigNames().iterator();
383                    while (items.hasNext()) {
384                        ServiceConfig subConfig =
385                            s.getSubConfig((String) items.next());
386                        if (subConfig.getSchemaID().equalsIgnoreCase(
387                            IdConstants.AMSDK_PLUGIN_NAME)) {
388                            Map amsdkConfig = new HashMap();
389                            Set vals = new HashSet();
390                            vals.add(orgNamingAttrInLegacyMode +
391                                SMSEntry.EQUALS +
392                                subOrgName + SMSEntry.COMMA + amSDKOrgDN);
393                            amsdkConfig.put("amSDKOrgName", vals);
394                            subConfig.setAttributes(amsdkConfig);
395                        }
396                        break;
397                    }
398                } catch (SSOException ssoe) {
399                    SMSEntry.debug.error("OrganizationConfigManager::"+
400                        "createSubOrganization:", ssoe);
401                    throw (new SMSException(SMSEntry.bundle.getString(
402                        "sms-INVALID_SSO_TOKEN"), "sms-INVALID_SSO_TOKEN"));
403                }
404            }
405        }
406
407        if (realmEnabled) {
408            try {
409                if (coexistMode) {
410                    DelegationUtils.createRealmPrivileges(token, orgName);
411                } else {
412                    OrganizationConfigManager parentOrg =
413                        getParentOrgConfigManager();
414                    DelegationUtils.copyRealmPrivilegesFromParent(
415                        token, parentOrg, ocm);
416                }
417            } catch (SSOException ssoe) {
418                if (SMSEntry.debug.messageEnabled()) {
419                        SMSEntry.debug.message("Creating delegation permissions for: " +
420                        orgName + " failed", ssoe);
421                }
422            } catch (SMSException smse) {
423                if (SMSEntry.debug.messageEnabled()) {
424                        SMSEntry.debug.message("Creating delegation permissions for: " +
425                        orgName + " failed", smse);
426                }
427            } catch (DelegationException de) {
428                if (SMSEntry.debug.messageEnabled()) {
429                        SMSEntry.debug.message("Creating delegation permissions for: " +
430                        orgName + " failed", de);
431                }
432            }
433        } 
434
435        // Return the newly created organization config manager
436        return (ocm);
437    }
438
439    /**
440     * Returns the names of all sub-organizations.
441     * 
442     * @return set of names of all sub-organizations.
443     * @throws SMSException
444     *             if there is an error accessing the data store to read the
445     *             sub-organization names.
446     */
447
448    public Set getSubOrganizationNames() throws SMSException {
449        try {
450            return (getSubOrganizationNames("*", false));
451        } catch (SMSException s) {
452            SMSEntry.debug.error("OrganizationConfigManager: "
453                    + "getSubOrganizationNames() Unable to "
454                    + "get sub organization names ", s);
455            throw s;
456        }
457    }
458
459    /**
460     * Returns the names of all peer-organizations.
461     * 
462     * @return set of names of all peer-organizations.
463     * @throws SMSException
464     *             if there is an error accessing the data store to read the
465     *             peer-organization names.
466     */
467
468    public Set getPeerOrganizationNames() throws SMSException {
469        Set getPeerSet = Collections.EMPTY_SET;
470        if (realmEnabled) {
471            try {
472                OrganizationConfigManager ocmParent = 
473                    getParentOrgConfigManager();
474                getPeerSet = ocmParent.getSubOrganizationNames();
475            } catch (SMSException s) {
476                if (SMSEntry.debug.warningEnabled()) {
477                    SMSEntry.debug.warning("OrganizationConfigManager: "
478                            + "getPeerOrganizationNames() Unable to "
479                            + "get Peer organization names ", s);
480                }
481                throw s;
482            }
483        }
484        return (getPeerSet);
485    }
486
487    /**
488     * Returns names of sub-organizations matching the
489     * given pattern. If the parameter <code>recursive</code> is set to
490     * <code>true</code>, search will be performed for the entire sub-tree.
491     * The pattern can contain "*" as the wildcard to represent zero or more
492     * characters.
493     * 
494     * @param pattern
495     *            pattern that will be used for searching, where "*" will be the
496     *            wildcard.
497     * @param recursive
498     *            if set to <code>true</code> the entire sub-tree will be
499     *            searched for the organization names.
500     * @return names of sub-organizations matching the pattern.
501     * @throws SMSException
502     *             if there is an error accessing the data store to read the
503     *             sub-organization names.
504     */
505    public Set getSubOrganizationNames(String pattern, boolean recursive)
506            throws SMSException {
507        validateConfigImpl();
508        try {
509            if (realmEnabled) {
510                return (orgConfigImpl.getSubOrganizationNames(token, pattern,
511                        recursive));
512            } else {
513                // Must be in coexistence mode
514                return (amsdk.getSubOrganizationNames(pattern, recursive));
515            }
516        } catch (SMSException s) {
517            SMSEntry.debug.error("OrganizationConfigManager: "
518                    + "getSubOrganizationNames(String pattern, "
519                    + "boolean recursive) Unable to get sub organization "
520                    + "names for filter: " + pattern, s);
521            throw s;
522        }
523    }
524
525    /**
526     * Deletes the given sub-organization. If the
527     * parameter <code>recursive</code> is set to <code>true</code>, then
528     * the suborganization and the sub-tree will be deleted.
529     * 
530     * If the parameter <code>recursive</code> is set to <code>false</code>
531     * then the sub-organization shall be deleted provided it is the leaf node.
532     * If there are entries beneath the sub-organization and if the parameter
533     * <code>recursive</code> is set to <code>false</code>, then an
534     * exception is thrown that this sub-organization cannot be deleted.
535     * 
536     * @param subOrgName
537     *            sub-organization name to be deleted.
538     * @param recursive
539     *            if set to <code>true</code> the entire sub-tree will be
540     *            deleted.
541     * @throws SMSException
542     *             if the sub-organization name cannot be found, or if there are
543     *             entries beneath the sub-organization and if the parameter
544     *             <code>recursive</code> is set to <code>false</code>.
545     */
546    public void deleteSubOrganization(String subOrgName, boolean recursive)
547            throws SMSException {
548        validateConfigImpl();
549        // Should not delete the root realm, should throw exception if
550        // attempted.
551        String subOrgDN = normalizeDN(subOrgName, orgDN);
552        if (subOrgDN.equals(SMSEntry.SLASH_STR) ||
553            subOrgDN.equalsIgnoreCase(SMSEntry.getRootSuffix()) ||
554            subOrgDN.equalsIgnoreCase(SERVICES_NODE)) {
555            
556            Object parms[] = { orgName };
557            SMSEntry.debug.error(
558                    "OrganizationConfigManager: deleteSubOrganization(" +
559                    "Root realm "+orgName + " cannot be deleted. ");
560            throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
561                "sms-cannot_delete_rootsuffix",parms));
562                    
563        }
564        // Delete the sub-organization
565        OrganizationConfigManager subRlmConfigMgr =
566            getSubOrgConfigManager(subOrgName);
567        //set the filter "*" to be passed for the search.
568        Set subRlmSet =
569            subRlmConfigMgr.getSubOrganizationNames("*", true);
570
571        if (realmEnabled) {
572            try {
573                CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token,
574                        subOrgDN);
575                if (cEntry.isDirty()) {
576                    cEntry.refresh();
577                }
578                SMSEntry entry = cEntry.getClonedSMSEntry();
579                if (!recursive) {
580                    // Check if there are sub organization entries
581                    // and if exist
582                    // throw exception that this sub organization cannot be
583                    // deleted.
584                    if ((subRlmSet !=null) && (!subRlmSet.isEmpty())) {
585                        throw (new SMSException(SMSEntry.bundle
586                                .getString("sms-entries-exists"),
587                                "sms-entries-exists"));
588                    }
589                }
590                // Obtain the SMSEntry for the suborg and
591                // sub tree and delete it.
592                entry.delete(token);
593                cEntry.refresh(entry);
594            } catch (SSOException ssoe) {
595                SMSEntry.debug.error(
596                        "OrganizationConfigManager: deleteSubOrganization(" +
597                        "String subOrgName, boolean recursive) Unable to " +
598                        "delete sub organization ", ssoe);
599                throw (new SMSException(SMSEntry.bundle
600                        .getString("sms-INVALID_SSO_TOKEN"),
601                        "sms-INVALID_SSO_TOKEN"));
602            }
603        }
604
605        // If in legacy mode or (realm mode and copy org enabled)
606        // delete the corresponding organization.
607        if ((coexistMode) || (realmEnabled && isCopyOrgEnabled())) {
608            String amsdkName = DNMapper.realmNameToAMSDKName(subOrgDN);
609            if (!SMSEntry.getRootSuffix().equalsIgnoreCase(
610                SMSEntry.getAMSdkBaseDN())) {
611                String convOrg = subOrgName;
612                if (subOrgName.startsWith("/")) {
613                    convOrg = DNMapper.convertToDN(subOrgName).toString();
614                }
615                amsdkName = convOrg + SMSEntry.COMMA + amSDKOrgDN;
616            }
617            amsdk.deleteSubOrganization(amsdkName);
618        }
619    }
620
621    /**
622     * Returns the <code>OrganizationConfigManager</code>
623     * for the given organization name.
624     * 
625     * @param subOrgName
626     *            the name of the organization.
627     * @return the configuration manager for the given organization.
628     * 
629     * @throws SMSException
630     *             if the organization name cannot be found or user doesn't have
631     *             access to that organization.
632     */
633    public OrganizationConfigManager getSubOrgConfigManager(String subOrgName)
634            throws SMSException {
635        validateConfigImpl();
636        // Normalize sub organization name
637        return (new OrganizationConfigManager(token, normalizeDN(subOrgName,
638                orgDN)));
639    }
640
641    /**
642     * Returns the organization creation attributes for
643     * the service.
644     * 
645     * @param serviceName
646     *            name of the service.
647     * @return map of organization creation attribute values for service
648     * @throws SMSException
649     *             if there is an error accessing the data store to read the
650     *             attributes of the service.
651     */
652    public Map getAttributes(String serviceName) throws SMSException {
653        validateConfigImpl();
654        if (serviceName == null) {
655            return (Collections.EMPTY_MAP);
656        }
657        Map attrValues = null;
658        // Attributes can be obtained only if DIT is migrated to AM 7.0
659        if (migratedTo70) {
660            // Lowercase the service name
661            serviceName = serviceName.toLowerCase();
662            try {
663                CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token,
664                        orgDN);
665                if (cEntry.isDirty() || (coexistMode) ||
666                    (realmEnabled && isCopyOrgEnabled())) {
667                    // Since AMSDK org notifications will not be
668                    // obtained, the entry must be read again
669                    cEntry.refresh();
670                }
671                SMSEntry entry = cEntry.getSMSEntry();
672                Map map = SMSUtils.getAttrsFromEntry(entry);
673                if ((map != null) && (!map.isEmpty())) {
674                    Iterator itr = map.keySet().iterator();
675                    while (itr.hasNext()) {
676                        String name = (String) itr.next();
677                        if ((name.toLowerCase()).startsWith(serviceName)) {
678                            Set values = (Set) map.get(name);
679                            // Remove the serviceName and '-' and return only
680                            // the attribute name,value.
681                            String key = name
682                                    .substring(serviceName.length() + 1);
683                            if (attrValues == null) {
684                                attrValues = new HashMap();
685                            }
686                            attrValues.put(key, values);
687                        }
688                    }
689                }
690            } catch (SSOException ssoe) {
691                SMSEntry.debug.error("OrganizationConfigManager: "
692                        + "getAttributes(String serviceName) Unable to "
693                        + "get Attributes", ssoe);
694                throw (new SMSException(SMSEntry.bundle
695                        .getString("sms-INVALID_SSO_TOKEN"),
696                        "sms-INVALID_SSO_TOKEN"));
697            }
698        }
699
700        // If in coexistMode and serviceName is idRepoService
701        // get attributes from AMSDK organization
702        if ((coexistMode || (realmEnabled && isCopyOrgEnabled()))
703                && serviceName
704                    .equalsIgnoreCase(OrgConfigViaAMSDK.IDREPO_SERVICE)) {
705            Map amsdkMap = amsdk.getAttributes();
706            Map mergesdkMap = new HashMap(2);
707            if (amsdkMap != null && !amsdkMap.isEmpty()) {
708                Set mergeValues = new HashSet(2);
709                Iterator itr = amsdkMap.keySet().iterator();
710                while (itr.hasNext()) {
711                    String key = (String) itr.next();
712                    if (key.equalsIgnoreCase(SUNDNS_ALIAS) || 
713                        key.equalsIgnoreCase(SUNPREF_DOMAIN) ||
714                            key.equalsIgnoreCase(SUNORG_ALIAS)) {
715                        buildSet(key, amsdkMap, mergeValues);
716                    }
717                }
718                mergesdkMap.put(SUNORG_ALIAS, mergeValues);
719                mergesdkMap.put(SUNORG_STATUS,
720                    (Set) amsdkMap.get(SUNORG_STATUS));
721            }
722            if (attrValues == null) {
723                attrValues = mergesdkMap;
724            } else {
725                attrValues.putAll(mergesdkMap);
726            }
727        }
728        return ((attrValues == null) ? Collections.EMPTY_MAP : attrValues);
729    }
730
731    /**
732     * Builds and returns the appropriate Set for the attributes to be
733     * merged from org and realm if the system is
734     * in intrusive mode (Both org DIT and realm DIT are present).
735     * This happens when the Copy Config flag is enabled.
736     */
737    private Set buildSet(String attrName, Map attributes, Set resultSet) {
738        Set vals = (Set) attributes.get(attrName);
739        if ((vals != null) && !vals.isEmpty()) {
740            resultSet.addAll(vals);
741        }
742        return (resultSet);
743    }
744
745    /**
746     * Adds organization attributes for the service. If
747     * the attribute already exists, the values will be appended to it, provided
748     * it is a multi-valued attribute. It will throw exception if we try to add
749     * a value to an attribute which has the same value already.
750     * 
751     * @param serviceName
752     *            name of the service.
753     * @param attrName
754     *            name of the attribute.
755     * @param values
756     *            values for the attribute.
757     * @throws SMSException
758     *             if we try to add a value to an attribute which has the same
759     *             value already.
760     */
761    public void addAttributeValues(String serviceName, String attrName,
762            Set values) throws SMSException {
763        validateConfigImpl();
764        if (serviceName == null || attrName == null) {
765            return;
766        }
767
768        if (migratedTo70) {
769            // Lowercase the servicename
770            serviceName = serviceName.toLowerCase();
771            try {
772                CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token,
773                        orgDN);
774                if (cEntry.isDirty()) {
775                    cEntry.refresh();
776                }
777                SMSEntry e = cEntry.getClonedSMSEntry();
778                ServiceSchemaManager ssm = new ServiceSchemaManager(
779                        serviceName, token);
780                ServiceSchema ss = ssm.getOrganizationCreationSchema();
781                if (ss == null) {
782                    throw (new SMSException(SMSEntry.bundle
783                            .getString("sms-SMSSchema_service_notfound"),
784                            "sms-SMSSchema_service_notfound"));
785                }
786
787                Map map = new HashMap(2);
788                Set newValues = new HashSet(values);
789                Map allAttributes = ss.getAttributeDefaults();
790                Set existingValues = (Set)allAttributes.get(attrName);
791                if ((existingValues != null) && !existingValues.isEmpty()) {
792                    newValues.addAll(existingValues);
793                }
794                map.put(attrName, newValues);
795                ss.validateAttributes(map);
796                SMSUtils.addAttribute(e, serviceName + "-" + attrName,
797                    values, ss.getSearchableAttributeNames());
798                e.save(token);
799                cEntry.refresh(e);
800            } catch (SSOException ssoe) {
801                SMSEntry.debug.error("OrganizationConfigManager: Unable "
802                        + "to add Attribute Values", ssoe);
803                throw (new SMSException(SMSEntry.bundle
804                        .getString("sms-INVALID_SSO_TOKEN"),
805                        "sms-INVALID_SSO_TOKEN"));
806            }
807        }
808
809        // If in coexistMode and serviceName is idRepoService
810        // add the attributes to AMSDK organization
811        if (coexistMode
812                && serviceName
813                        .equalsIgnoreCase(OrgConfigViaAMSDK.IDREPO_SERVICE)) {
814            amsdk.addAttributeValues(attrName, values);
815        }
816    }
817
818    /**
819     * Sets/Creates organization attributes for the
820     * service. If the attributes already exists, the given attribute values
821     * will replace them.
822     * 
823     * @param serviceName
824     *            name of the service.
825     * @param attributes
826     *            attribute-values pairs.
827     * @throws SMSException
828     *             if the serviceName cannot be found.
829     */
830    public void setAttributes(String serviceName, Map attributes)
831            throws SMSException {
832        validateConfigImpl();
833        if (serviceName == null) {
834            return;
835        }
836
837        if (migratedTo70) {
838            // Lowercase the serviceName
839            serviceName = serviceName.toLowerCase();
840            try {
841                CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token,
842                        orgDN);
843                if (cEntry.isDirty()) {
844                    cEntry.refresh();
845                }
846                SMSEntry e = cEntry.getClonedSMSEntry();
847                if ((attributes != null) && (!attributes.isEmpty())) {
848                    // Validate the attributes
849                    ServiceSchemaManager ssm = new ServiceSchemaManager(
850                            serviceName, token);
851                    ServiceSchema ss = ssm.getOrganizationCreationSchema();
852                    ss.validateAttributes(attributes);
853
854                    // Normalize the attributes with service name
855                    Map attrsMap = new HashMap();
856                    Iterator itr = attributes.keySet().iterator();
857                    while (itr.hasNext()) {
858                        String name = (String) itr.next();
859                        Set values = (Set) attributes.get(name);
860                        /*
861                         * To make the attributes qualified by service name we
862                         * prefix the attribute names with the service name.
863                         */
864                        attrsMap.put(serviceName + "-" + name, values);
865                    }
866
867                    // Look for old attrs. in the storage and add them too.
868                    Map oldAttrs = getAttributes(serviceName);
869                    Iterator it = oldAttrs.keySet().iterator();
870                    while (it.hasNext()) {
871                        String skey = (String) it.next();
872                        if (!attributes.containsKey(skey))
873                            attrsMap.put(serviceName + "-" + skey, oldAttrs
874                                    .get(skey));
875                    }
876
877                    // Set the attributes in SMSEntry
878                    SMSUtils.setAttributeValuePairs(e, attrsMap, ss
879                            .getSearchableAttributeNames());
880
881                    String dataStore = SMSEntry.getDataStore(token);
882                    // Add these OCs only for SunOne DS. Do not add the 
883                    // OCs for Active Directory.
884                    // Will get WILL_NOT_PERFORM in AD.
885                    if ((dataStore != null) && !dataStore.equals(
886                        SMSEntry.DATASTORE_ACTIVE_DIR)
887                    ) {
888                        // This is for storing organization attributes
889                        // in top/default realm node. eg.,ou=services,o=isp
890                        if (e.getDN().equalsIgnoreCase(SERVICES_NODE)) {
891                            String[] ocVals = e
892                                .getAttributeValues(SMSEntry.ATTR_OBJECTCLASS);
893                            boolean exists = false;
894                            for (int ic = 0; ocVals != null 
895                                && ic < ocVals.length; ic++) 
896                            {
897                                if (ocVals[ic].startsWith(
898                                    SMSEntry.OC_SERVICE_COMP)) {
899                                    // OC needs to be added outside the for loop
900                                    // else will throw concurrent mod exception
901                                    exists = true;
902                                    break;
903                                }
904                            }
905                            if (!exists) {
906                                e.addAttribute(SMSEntry.ATTR_OBJECTCLASS,
907                                    SMSEntry.OC_SERVICE_COMP);
908                            }
909                        } else if (e.getDN().startsWith(
910                            SMSEntry.ORGANIZATION_RDN + SMSEntry.EQUALS)) {
911                            // This is for storing organization attributes in
912                            // organizations created via sdk through realm 
913                            // console.
914                            String[] vals = e
915                                .getAttributeValues(SMSEntry.ATTR_OBJECTCLASS);
916                            boolean rsvcExists = false;
917                            for (int n = 0; vals != null && n < vals.length; 
918                                n++) {
919                                if (vals[n].equalsIgnoreCase(
920                                    SMSEntry.OC_REALM_SERVICE)) 
921                                {
922                                    // OC needs to be added outside the for loop
923                                    // else will throw concurrent mod exception
924                                    rsvcExists = true;
925                                    break;
926                                }
927                            }
928                            if (!rsvcExists) {
929                                e.addAttribute(SMSEntry.ATTR_OBJECTCLASS,
930                                    SMSEntry.OC_REALM_SERVICE);
931                            }
932                        }
933                    }
934
935                    // Save in backend data store and refresh the cache
936                    e.save(token);
937                    cEntry.refresh(e);
938                }
939
940            } catch (SSOException ssoe) {
941                SMSEntry.debug.error("OrganizationConfigManager: Unable "
942                        + "to set Attributes", ssoe);
943                throw (new SMSException(SMSEntry.bundle
944                        .getString("sms-INVALID_SSO_TOKEN"),
945                        "sms-INVALID_SSO_TOKEN"));
946            }
947        }
948
949        // If in coexistMode and serviceName is idRepoService
950        // set the attributes to AMSDK organization
951        if ((coexistMode || (realmEnabled && isCopyOrgEnabled()))
952                && serviceName
953                        .equalsIgnoreCase(OrgConfigViaAMSDK.IDREPO_SERVICE)) {
954            amsdk.setAttributes(attributes);
955        }
956    }
957
958    /**
959     * Removes the given organization creation attribute
960     * for the service.
961     * 
962     * @param serviceName
963     *            name of service.
964     * @param attrName
965     *            name of attribute.
966     * @throws SMSException
967     *             if the organization attribute for the service to be removed
968     *             cannot be found, or if the service name cannot be found.
969     */
970    public void removeAttribute(String serviceName, String attrName)
971            throws SMSException {
972        validateConfigImpl();
973        if (serviceName == null || attrName == null) {
974            return;
975        }
976
977        if (migratedTo70) {
978            try {
979                CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token,
980                        orgDN);
981                if (cEntry.isDirty()) {
982                    cEntry.refresh();
983                }
984                SMSEntry e = cEntry.getClonedSMSEntry();
985                SMSUtils.removeAttribute(e, serviceName.toLowerCase() + "-"
986                        + attrName);
987                e.save(token);
988                cEntry.refresh(e);
989            } catch (SSOException ssoe) {
990                SMSEntry.debug.error("OrganizationConfigManager: Unable "
991                        + "to remove Attribute", ssoe);
992                throw (new SMSException(SMSEntry.bundle
993                        .getString("sms-INVALID_SSO_TOKEN"),
994                        "sms-INVALID_SSO_TOKEN"));
995            }
996        }
997
998        // If in coexistMode and serviceName is idRepoService
999        // remove the attributes to AMSDK organization
1000        if (coexistMode
1001                && serviceName
1002                        .equalsIgnoreCase(OrgConfigViaAMSDK.IDREPO_SERVICE)) {
1003            amsdk.removeAttribute(attrName);
1004        }
1005    }
1006
1007    /**
1008     * Removes the given organization creation attribute
1009     * values for the service.
1010     * 
1011     * @param serviceName
1012     *            name of service.
1013     * @param attrName
1014     *            name of attribute.
1015     * @param values
1016     *            attribute values to be removed.
1017     * @throws SMSException
1018     *             if the organization attribute for the service to be removed
1019     *             cannot be found, or if the service name cannot be found, or
1020     *             if the value cannot be removed.
1021     */
1022    public void removeAttributeValues(String serviceName, String attrName,
1023            Set values) throws SMSException {
1024        validateConfigImpl();
1025        if (serviceName == null || attrName == null) {
1026            return;
1027        }
1028        if (migratedTo70) {
1029            try {
1030                CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token,
1031                        orgDN);
1032                if (cEntry.isDirty()) {
1033                    cEntry.refresh();
1034                }
1035                SMSEntry e = cEntry.getClonedSMSEntry();
1036                ServiceSchemaManager ssm = new ServiceSchemaManager(
1037                        serviceName, token);
1038                ServiceSchema ss = ssm.getOrganizationCreationSchema();
1039                Map map = new HashMap(2);
1040                map.put(attrName, values);
1041                ss.validateAttributes(map);
1042                SMSUtils.removeAttributeValues(e, serviceName.toLowerCase()
1043                        + "-" + attrName, values, ss
1044                        .getSearchableAttributeNames());
1045                e.save(token);
1046                cEntry.refresh(e);
1047
1048            } catch (SSOException ssoe) {
1049                SMSEntry.debug.error("OrganizationConfigManager: Unable "
1050                        + "to remove Attribute Values", ssoe);
1051                throw (new SMSException(SMSEntry.bundle
1052                        .getString("sms-INVALID_SSO_TOKEN"),
1053                        "sms-INVALID_SSO_TOKEN"));
1054            }
1055        }
1056
1057        // If in coexistMode and serviceName is idRepoService
1058        // remove the attributes to AMSDK organization
1059        if (coexistMode
1060                && serviceName
1061                        .equalsIgnoreCase(OrgConfigViaAMSDK.IDREPO_SERVICE)) {
1062            amsdk.removeAttributeValues(attrName, values);
1063        }
1064    }
1065
1066    /**
1067     * Returns the service configuration object for the
1068     * given service name.
1069     * 
1070     * @param serviceName
1071     *            name of a service.
1072     * @return service configuration object for the service.
1073     * @throws SMSException
1074     *             if there is an error accessing the data store to read the
1075     *             service configuration, or if the service name cannot be
1076     *             found.
1077     */
1078    public ServiceConfig getServiceConfig(String serviceName)
1079            throws SMSException {
1080        try {
1081            ServiceConfigManager scmgr = new ServiceConfigManager(serviceName,
1082                    token);
1083            ServiceConfig scg = scmgr.getOrganizationConfig(orgName, null);
1084            return (scg);
1085        } catch (SSOException ssoe) {
1086            SMSEntry.debug.error("OrganizationConfigManager: Unable to "
1087                    + "get Service Config", ssoe);
1088            throw (new SMSException(SMSEntry.bundle
1089                    .getString("sms-INVALID_SSO_TOKEN"),
1090                    "sms-INVALID_SSO_TOKEN"));
1091        }
1092    }
1093
1094    /**
1095     * Adds a service configuration object for the given
1096     * service name for this organization. If the service has been already added
1097     * a <code>SMSException</code> will be thrown.
1098     * 
1099     * @param serviceName
1100     *            name of the service.
1101     * @param attributes
1102     *            service configuration attributes.
1103     * @return service configuration object.
1104     * @throws SMSException
1105     *             if the service configuration has been added already.
1106     */
1107    public ServiceConfig addServiceConfig(String serviceName, Map attributes)
1108            throws SMSException {
1109        try {
1110            ServiceConfigManagerImpl scmi = ServiceConfigManagerImpl
1111                    .getInstance(token, serviceName, 
1112                    ServiceManager.getVersion(serviceName));
1113            ServiceConfigImpl sci = scmi.getOrganizationConfig(token, orgName,
1114                    null);
1115            if (sci == null || sci.isNewEntry()) {
1116                ServiceConfigManager scm = new ServiceConfigManager(
1117                        serviceName, token);
1118                return (scm.createOrganizationConfig(orgName, attributes));
1119            } else {
1120                SMSEntry.debug.error("OrganizationConfigManager: "
1121                        + "ServiceConfig already exists: " + sci.getDN());
1122                throw (new SMSException(SMSEntry.bundle
1123                        .getString("sms-service_already_exists1")));
1124            }
1125        } catch (SSOException ssoe) {
1126            SMSEntry.debug.error("OrganizationConfigManager: Unable to "
1127                    + "add Service Config", ssoe);
1128            throw (new SMSException(SMSEntry.bundle
1129                    .getString("sms-INVALID_SSO_TOKEN"),
1130                    "sms-INVALID_SSO_TOKEN"));
1131        }
1132    }
1133
1134    /**
1135     * Removes the service configuration object for the
1136     * given service name for this organization.
1137     * 
1138     * @param serviceName
1139     *            name of the service.
1140     * @throws SMSException
1141     *             if the service name cannot be found, or not added to the
1142     *             organization.
1143     */
1144    public void removeServiceConfig(String serviceName) throws SMSException {
1145        try {
1146            ServiceConfigManager scm = new ServiceConfigManager(serviceName,
1147                    token);
1148            scm.deleteOrganizationConfig(orgName);
1149        } catch (SSOException ssoe) {
1150            SMSEntry.debug.error("OrganizationConfigManager: Unable to "
1151                    + "delete Service Config", ssoe);
1152            throw (new SMSException(SMSEntry.bundle
1153                    .getString("sms-INVALID_SSO_TOKEN"),
1154                    "sms-INVALID_SSO_TOKEN"));
1155        }
1156    }
1157
1158    /**
1159     * Registers for changes to organization's
1160     * configuration. The object will be called when configuration for this
1161     * organization is changed.
1162     * 
1163     * @param listener
1164     *            callback object that will be invoked when organization
1165     *            configuration has changed
1166     * @return an ID of the registered listener.
1167     */
1168    public String addListener(ServiceListener listener) {
1169        return (orgConfigImpl.addListener(listener));
1170    }
1171
1172    /**
1173     * Removes the listener from the organization for the
1174     * given listener ID. The ID was issued when the listener was registered.
1175     * 
1176     * @param listenerID
1177     *            the listener ID issued when the listener was registered
1178     */
1179    public void removeListener(String listenerID) {
1180        orgConfigImpl.removeListener(listenerID);
1181    }
1182
1183    /**
1184     * Returns normalized DN for realm model
1185     */
1186    private static String normalizeDN(String subOrgName, String orgDN) {
1187        // Return orgDN if subOrgName is either null or empty
1188        if (subOrgName == null || subOrgName.length() == 0) {
1189            return (orgDN);
1190        }
1191        if (SMSEntry.debug.messageEnabled()) {
1192            SMSEntry.debug.message("OrganizationConfigManager."
1193                    + "normalizeDN()-subOrgName " + subOrgName);
1194        }
1195        String subOrgDN = null;
1196        if (DN.isDN(subOrgName) && (!subOrgName.startsWith("///"))) {
1197            int ndx = subOrgName.lastIndexOf(DNMapper.serviceDN);
1198            if (ndx == -1) {
1199                // Check for baseDN
1200                ndx = subOrgName.lastIndexOf(SMSEntry.getRootSuffix());
1201            }
1202            if (ndx > 0) {
1203                subOrgName = subOrgName.substring(0, ndx - 1);
1204            }
1205            subOrgDN = DNMapper.normalizeDN(subOrgName) + orgDN;
1206        } else if (subOrgName.indexOf('/') != -1) {
1207            String tmp = DNMapper.convertToDN(subOrgName).toString();
1208            if (SMSEntry.debug.messageEnabled()) {
1209                SMSEntry.debug.message("OrganizationConfigManager."
1210                        + "normalizeDN()-slashConvertedString: " + tmp);
1211            }
1212            if (tmp != null && tmp.length() > 0) {
1213                if (tmp.charAt(tmp.length() - 1) == ',') {
1214                    subOrgDN = tmp + DNMapper.serviceDN;
1215                } else {
1216                    int dx = tmp.indexOf(SMSEntry.COMMA);
1217                    if (dx >= 0) {
1218                        subOrgDN = tmp + SMSEntry.COMMA + DNMapper.serviceDN;
1219                    } else {
1220                        subOrgDN = tmp + SMSEntry.COMMA + orgDN;
1221                    }
1222                }
1223            } else {
1224                subOrgDN = orgDN;
1225            }
1226        } else if (subOrgName.startsWith(SMSEntry.SUN_INTERNAL_REALM_NAME)) {
1227            subOrgDN = SMSEntry.ORG_PLACEHOLDER_RDN + subOrgName
1228                    + SMSEntry.COMMA + DNMapper.serviceDN;
1229        } else {
1230            if (coexistMode) {
1231                subOrgDN = orgNamingAttrInLegacyMode + SMSEntry.EQUALS
1232                        + subOrgName + SMSEntry.COMMA
1233                        + DNMapper.realmNameToAMSDKName(orgDN);
1234            } else {
1235                subOrgDN = SMSEntry.ORG_PLACEHOLDER_RDN + subOrgName
1236                        + SMSEntry.COMMA + orgDN;
1237            }
1238        }
1239        if (SMSEntry.debug.messageEnabled()) {
1240            SMSEntry.debug.message("OrganizationConfigManager::"
1241                    + "normalizeDN() suborgdn " + subOrgDN);
1242        }
1243        return (subOrgDN);
1244    }
1245
1246    /**
1247     * Returns all service names configured for AM
1248     */
1249    static Set getServiceNames(SSOToken token) throws SMSException,
1250            SSOException {
1251        // Get the service names from ServiceManager
1252        CachedSubEntries cse = CachedSubEntries.getInstance(token,
1253                DNMapper.serviceDN);
1254        return (cse.getSubEntries(token));
1255    }
1256
1257    /**
1258     * Returns a set of service names that can be assigned
1259     * to a realm. This set excludes name of services that are already assigned
1260     * to the realm and services that are required for the existence of a realm.
1261     * 
1262     * @return a set of service names that can be assigned to a realm.
1263     * @throws SMSException
1264     *             if there is an error accessing the data store to read the
1265     *             service configuration
1266     */
1267    public Set getAssignableServices() throws SMSException {
1268        // Get all service names, and remove the assigned services
1269        // Set containing service names that has organization schema
1270        Set orgSchemaServiceNames = new HashSet();
1271        try {
1272            for (Iterator names = getServiceNames(token).iterator(); names
1273                    .hasNext();) {
1274                String serviceName = (String) names.next();
1275                ServiceSchemaManagerImpl ssmi = ServiceSchemaManagerImpl
1276                        .getInstance(token, serviceName, 
1277                        ServiceManager.getVersion(serviceName));
1278                if (ssmi.getSchema(SchemaType.ORGANIZATION) != null) {
1279                    // Need to check if the user has permission
1280                    // to add/assign the service
1281                    StringBuilder d = new StringBuilder(100);
1282                    // Need to construct
1283                    // "ou=default,ou=organizationconfig,ou=1.0,ou="
1284                    d.append(SMSEntry.PLACEHOLDER_RDN).append(SMSEntry.EQUALS)
1285                            .append(SMSUtils.DEFAULT).append(SMSEntry.COMMA)
1286                            .append(CreateServiceConfig.ORG_CONFIG_NODE)
1287                            .append(SMSEntry.PLACEHOLDER_RDN).append(
1288                                    SMSEntry.EQUALS).append("1.0").append(
1289                                    SMSEntry.COMMA).append(
1290                                    SMSEntry.PLACEHOLDER_RDN).append(
1291                                    SMSEntry.EQUALS);
1292                    // Append service name, and org name
1293                    d.append(serviceName);
1294                    if (!orgDN.equalsIgnoreCase(DNMapper.serviceDN)) {
1295                        d.append(SMSEntry.COMMA).append(SMSEntry.SERVICES_NODE);
1296                    }
1297                    d.append(SMSEntry.COMMA).append(orgDN);
1298                    try {
1299                        // The function will throw exception if
1300                        // user does not have permissions
1301                        SMSEntry.getDelegationPermission(token, d.toString(),
1302                                SMSEntry.modifyActionSet);
1303                        orgSchemaServiceNames.add(serviceName);
1304                    } catch (SMSException smse) {
1305                        if (smse.getExceptionCode() != 
1306                            SMSException.STATUS_NO_PERMISSION) 
1307                        {
1308                            throw (smse);
1309                        }
1310                    }
1311                }
1312            }
1313            // Need to remove mandatory services
1314            // %%% TODO. Need to have SMS Service with this information
1315            // orgSchemaServiceNames.removeAll(getMandatoryServices());
1316        } catch (SSOException ssoe) {
1317            SMSEntry.debug.error("OrganizationConfigManager."
1318                    + "getAssignableServices(): SSOException", ssoe);
1319            throw (new SMSException(SMSEntry.bundle
1320                    .getString("sms-INVALID_SSO_TOKEN"),
1321                    "sms-INVALID_SSO_TOKEN"));
1322        }
1323        // Remove assigned services
1324        HashSet answer = new HashSet(orgSchemaServiceNames);
1325        answer.removeAll(getAssignedServices());
1326        return (answer);
1327    }
1328
1329    /**
1330     * Returns a set of service names that are assigned to
1331     * a realm.
1332     * 
1333     * @return a set of service names that are assigned to a realm.
1334     * @throws SMSException
1335     *             if there is an error accessing the data store to read the
1336     *             service configuration
1337     */
1338    public Set<String> getAssignedServices() throws SMSException {
1339        return (getAssignedServices(true));
1340    }
1341
1342    /**
1343     * Returns a set of service names that are assigned to a realm.
1344     * 
1345     * @param includeMandatory
1346     *            <code>true</code> to include mandatory service names.
1347     * @return a set of service names that are assigned to a realm.
1348     * @throws SMSException
1349     *             if there is an error accessing the data store to read the
1350     *             service configuration
1351     */
1352    public Set<String> getAssignedServices(boolean includeMandatory)
1353            throws SMSException {
1354        validateConfigImpl();
1355        Set<String> assignedServices = Collections.EMPTY_SET;
1356        if (coexistMode) {
1357            // Get assigned services from OrgConfigViaAMSDK
1358            assignedServices = amsdk.getAssignedServices();
1359        } else {
1360            // Get assigned service names from OrganizationConfigManagerImpl
1361            assignedServices = orgConfigImpl.getAssignedServices(token);
1362        }
1363        if (!includeMandatory) {
1364            // Get services assigned by default
1365            Set ds = ServiceManager.requiredServices();
1366            assignedServices.removeAll(ds);
1367        }
1368        return (assignedServices);
1369    }
1370
1371    /**
1372     * Assigns the given service to the orgnization with
1373     * the respective attributes. If the service has been already added a <code>
1374     * SMSException</code>
1375     * will be thrown.
1376     * 
1377     * @param serviceName
1378     *            name of the service
1379     * @param attributes
1380     *            service configuration attributes
1381     * @throws SMSException
1382     *             if the service configuration has been added already.
1383     */
1384    public void assignService(String serviceName, Map attributes)
1385            throws SMSException {
1386        addServiceConfig(serviceName, attributes);
1387    }
1388
1389    /**
1390     * Returns attributes configured for the service.
1391     * 
1392     * @param serviceName
1393     *            name of the service
1394     * @return a map of attributes for the service
1395     * @throws SMSException
1396     *             if there is an error accessing the data store to read the
1397     *             service configuration, or if the service name cannot be
1398     *             found.
1399     */
1400    public Map getServiceAttributes(String serviceName) throws SMSException {
1401        ServiceConfig scg = getServiceConfig(serviceName);
1402        if (scg == null) {
1403            Object args[] = { serviceName };
1404            SMSEntry.debug.error(
1405                    "OrganizationConfigManager.getServiceAttributes() Unable " +
1406                    "to get service attributes. ");
1407            throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
1408                    "sms-no-organization-schema",
1409                    args));
1410
1411        }
1412        return (scg.getAttributes());
1413    }
1414
1415    /**
1416     * Unassigns the service from the organization.
1417     * 
1418     * @param serviceName
1419     *            name of the service
1420     * @throws SMSException
1421     *             if the service name cannot be found or assigned, or if the
1422     *             service is a mandatory service.
1423     */
1424    public void unassignService(String serviceName) throws SMSException {
1425        // if (coexistMode) {
1426        // amsdk.unassignService(serviceName);
1427        // } else {
1428        removeServiceConfig(serviceName);
1429        // }
1430    }
1431
1432    /**
1433     * Sets the attributes related to provided service.
1434     * The assumption is that the service is already assigned to the
1435     * organization. The attributes for the service are validated against the
1436     * service schema.
1437     * 
1438     * @param serviceName
1439     *            name of the service
1440     * @param attributes
1441     *            attributes of the service
1442     * @throws SMSException
1443     *             if the service name cannot be found or not assigned to the
1444     *             organization.
1445     */
1446    public void modifyService(String serviceName, Map attributes)
1447            throws SMSException {
1448        try {
1449            getServiceConfig(serviceName).setAttributes(attributes);
1450        } catch (SSOException ssoe) {
1451            SMSEntry.debug.error("OrganizationConfigManager.modifyService "
1452                    + "SSOException in modify service ", ssoe);
1453            throw (new SMSException(SMSEntry.bundle
1454                    .getString("sms-INVALID_SSO_TOKEN"),
1455                    "sms-INVALID_SSO_TOKEN"));
1456        }
1457    }
1458
1459    public String getNamingAttrForOrg() {
1460        return OrgConfigViaAMSDK.getNamingAttrForOrg();
1461    }
1462
1463    /**
1464     * Returns the <code>OrganizationConfigManager</code>
1465     * of the parent for the given organization name.
1466     * 
1467     * @return the configuration manager of the parent for the given
1468     *         organization.
1469     * @throws SMSException
1470     *             if user doesn't have access to that organization.
1471     */
1472    public OrganizationConfigManager getParentOrgConfigManager()
1473            throws SMSException {
1474        OrganizationConfigManager ocm = null;
1475        String parentDN = null;
1476        if (DN.isDN(orgDN)) {
1477            if (orgDN.equalsIgnoreCase(DNMapper.serviceDN)) {
1478                return (this);
1479            }
1480            parentDN = (new DN(orgDN)).getParent().toString();
1481            if (SMSEntry.debug.messageEnabled()) {
1482                SMSEntry.debug.message("OrganizationConfigManager."
1483                        + "getParentOrgConfigManager() parentDN : " + parentDN);
1484            }
1485            if (parentDN != null && parentDN.length() > 0) {
1486                ocm = new OrganizationConfigManager(token, parentDN);
1487            }
1488        }
1489        return ocm;
1490    }
1491
1492    /**
1493     * Loads default services to a newly created realm
1494     */
1495    public static void loadDefaultServices(SSOToken token,
1496            OrganizationConfigManager ocm) throws SMSException {
1497        // Check if DIT has been migrated to 7.0
1498        if (!migratedTo70) {
1499            return;
1500        }
1501        Set defaultServices = ServiceManager.servicesAssignedByDefault();
1502        // Load the default services automatically
1503        OrganizationConfigManager parentOrg = ocm.getParentOrgConfigManager();
1504        if (defaultServices == null) {
1505            // There are no services to be loaded
1506            return;
1507        }
1508
1509        Set assignedServices = new CaseInsensitiveHashSet(
1510            parentOrg.getAssignedServices());
1511        if (SMSEntry.debug.messageEnabled()) {
1512            SMSEntry.debug.message("OrganizationConfigManager"
1513                    + "::loadDefaultServices " + "assignedServices : "
1514                    + assignedServices);
1515        }
1516        boolean doAuthServiceLater = false;
1517        boolean doAuthHttpBasicLater = false;
1518        String serviceName = null;
1519
1520        // Copy service configuration
1521        Iterator items = defaultServices.iterator();
1522        while (items.hasNext() || doAuthHttpBasicLater || doAuthServiceLater) {
1523            if (items.hasNext()) {
1524                serviceName = (String) items.next();
1525                if (serviceName.equals(ISAuthConstants.AUTH_SERVICE_NAME)) {
1526                    doAuthServiceLater = true;
1527                    continue;
1528                } else if (serviceName.equals(
1529                    ISAuthConstants.AUTH_HTTP_BASIC_SERVICE_NAME)) {
1530
1531                    doAuthHttpBasicLater = true;
1532                    continue;
1533                }
1534            } else if (doAuthHttpBasicLater) {
1535                serviceName = ISAuthConstants.AUTH_HTTP_BASIC_SERVICE_NAME;
1536                doAuthHttpBasicLater = false;
1537            } else if (doAuthServiceLater) {
1538                serviceName = ISAuthConstants.AUTH_SERVICE_NAME;
1539                doAuthServiceLater = false;
1540            }
1541            if (SMSEntry.debug.messageEnabled()) {
1542                SMSEntry.debug.message("OrganizationConfigManager" +
1543                    "::loadDefaultServices:ServiceName " + serviceName);
1544            }
1545            try {
1546                ServiceConfig sc = parentOrg.getServiceConfig(serviceName);
1547                Map attrs = null;
1548                if (sc != null && assignedServices.contains(serviceName)) {
1549                    attrs = sc.getAttributesWithoutDefaults();
1550                    if (SMSEntry.debug.messageEnabled()) {
1551                        SMSEntry.debug
1552                                .message("OrganizationConfigManager"
1553                                        + "::loadDefaultServices "
1554                                        + "Copying service from parent: "
1555                                        + serviceName);
1556                    }
1557                    ServiceConfig scn = ocm
1558                            .addServiceConfig(serviceName, attrs);
1559                    // Copy sub-configurations, if any
1560                    copySubConfig(sc, scn);
1561                }
1562            } catch (SSOException ssoe) {
1563                if (SMSEntry.debug.messageEnabled()) {
1564                    SMSEntry.debug.message(
1565                            "OrganizationConfigManager.loadDefaultServices " +
1566                            "SSOException in loading default services ",
1567                                    ssoe);
1568                }
1569                throw (new SMSException(SMSEntry.bundle
1570                        .getString("sms-INVALID_SSO_TOKEN"),
1571                        "sms-INVALID_SSO_TOKEN"));
1572            }
1573        }
1574    }
1575
1576
1577    /**
1578     * Registers default services to newly created suborganizations.
1579     */
1580    private void registerSvcsForOrg(String subOrgName, String subOrgDN)
1581    {
1582        try {
1583            Set defaultServices =
1584                ServiceManager.servicesAssignedByDefault();
1585            if (SMSEntry.debug.messageEnabled()) {
1586                SMSEntry.debug.message("OrganizationConfigManager::"+
1587                    "registerSvcsForOrg. "+
1588                    "defaultServices : " + defaultServices);
1589            }
1590
1591            // Register the default services to the newly created orgs,so
1592            // they will be marked with the OC sunRegisteredServiceName.
1593            if (defaultServices != null) {
1594                Set assignedServices = amsdk.getAssignedServices();
1595                if (SMSEntry.debug.messageEnabled()) {
1596                    SMSEntry.debug.message("OrganizationConfigManager::" +
1597                        "registerSvcsForOrg:assignedServices: " +
1598                            assignedServices);
1599                }
1600                Iterator items = defaultServices.iterator();
1601                String serviceName = null;
1602                if (SMSEntry.getRootSuffix().equalsIgnoreCase(
1603                    SMSEntry.getAMSdkBaseDN())) {
1604                    amsdk = new OrgConfigViaAMSDK(token,
1605                      orgNamingAttrInLegacyMode + SMSEntry.EQUALS +
1606                        subOrgName + SMSEntry.COMMA +
1607                        DNMapper.realmNameToAMSDKName(orgDN), subOrgDN);
1608                } else {
1609                    amsdk = new OrgConfigViaAMSDK(token,
1610                      orgNamingAttrInLegacyMode + SMSEntry.EQUALS +
1611                        subOrgName + SMSEntry.COMMA + amSDKOrgDN, subOrgDN);
1612                }
1613                while (items.hasNext()) {
1614                    serviceName = (String) items.next();
1615                    if (assignedServices.contains(serviceName)) {
1616                        if (SMSEntry.debug.messageEnabled()) {
1617                            SMSEntry.debug.message(
1618                                "OrganizationConfigManager::"+
1619                                "registerSvcsForOrg:ServiceName : " +
1620                                serviceName);
1621                        }
1622                        amsdk.assignService(serviceName);
1623                    }
1624                }
1625            }
1626        } catch (SMSException smse) {
1627            // Unable to load default services
1628            if (SMSEntry.debug.warningEnabled()) {
1629                SMSEntry.debug.warning("OrganizationConfigManager::" +
1630                    "registerSvcsForOrg. " +
1631                    "SMSException in registering services: ", smse);
1632            }
1633        }
1634    }
1635
1636    /**
1637     * Copies service configurations recursively from source to destination
1638     */
1639    static void copySubConfig(ServiceConfig from, ServiceConfig to)
1640            throws SMSException, SSOException {
1641        Set subConfigNames = from.getSubConfigNames();
1642        for (Iterator items = subConfigNames.iterator(); items.hasNext();) {
1643            String subConfigName = (String) items.next();
1644            ServiceConfig scf = from.getSubConfig(subConfigName);
1645            to.addSubConfig(subConfigName, scf.getSchemaID(),
1646                    scf.getPriority(), scf.getAttributesWithoutDefaults());
1647            ServiceConfig sct = to.getSubConfig(subConfigName);
1648            copySubConfig(scf, sct);
1649        }
1650    }
1651
1652
1653    /**
1654     * Determines whether an organization ought to be created for each
1655     * realm in realm only mode of installation based on the boolean flag
1656     * in amSDK plugin.
1657     * This requirement is for portal customers.
1658     */
1659    protected boolean isCopyOrgEnabled() {
1660        if (copyOrgInitialized) {
1661            return (copyOrgEnabled);
1662        }
1663        if (SMSEntry.debug.messageEnabled()) {
1664            SMSEntry.debug.message("OrganizationConfigManager: "+
1665                "in isCopyOrgEnabled() ");
1666        }
1667        // Check if AMSDK is configured for the realm
1668        try {
1669            ServiceConfig s = getServiceConfig(ServiceManager.REALM_SERVICE);
1670            if (s != null) {
1671                Iterator items = s.getSubConfigNames().iterator();
1672                while (items.hasNext()) {
1673                    String name = items.next().toString();
1674                    ServiceConfig subConfig = s.getSubConfig(name);
1675                    if (subConfig == null) {
1676                        SMSEntry.debug.error("OrganizationConfigManager.is" +
1677                            "CopyOrgEnabled. SubConfig is NULL: " +
1678                            "SC Name: " + name + " For org: " + orgDN);
1679                        return (false);
1680                    }
1681                    if (subConfig.getSchemaID().equalsIgnoreCase(
1682                        IdConstants.AMSDK_PLUGIN_NAME)) {
1683                        Map configMap = subConfig.getAttributes();
1684                        if ((configMap != null) && !configMap.isEmpty()) {
1685                            // Get the amsdkOrgName from the amSDKRepo to build
1686                            // OrgConfigViaSDK instance.
1687                            Set orgs = (Set) configMap.get("amSDKOrgName");
1688                            if (orgs != null && !orgs.isEmpty()) {
1689                                amSDKOrgDN = (String) orgs.iterator().next();
1690                                Set cfgs = (Set) configMap.get(CONF_ENABLED);
1691                                if ( (cfgs != null) && (!cfgs.isEmpty()) &&
1692                                    (cfgs.contains("true")) &&
1693                                        (amSDKOrgDN !=null) ) {
1694                                    amsdk = new OrgConfigViaAMSDK(token,
1695                                        amSDKOrgDN, orgDN);
1696                                    if (orgNamingAttrInLegacyMode == null) {
1697                                        orgNamingAttrInLegacyMode =
1698                                        getNamingAttrForOrg();
1699                                    }
1700                                    copyOrgEnabled = true;
1701                                }
1702                                break;
1703                            }
1704                        }
1705                    }
1706                }
1707            }
1708        } catch (SSOException sse) {
1709            // Use default values i.e., false
1710            if (SMSEntry.debug.messageEnabled()) {
1711                SMSEntry.debug.message("OrganizationConfigManager:" +
1712                    "isCopyOrgEnabled() Unable to get service: " +
1713                    ServiceManager.REALM_SERVICE, sse);
1714            }
1715        } catch (SMSException e) {
1716            // Use default values i.e., false
1717            if (SMSEntry.debug.messageEnabled()) {
1718                SMSEntry.debug.message("OrganizationConfigManager:" +
1719                    "isCopyOrgEnabled() Unable to get service: " +
1720                    ServiceManager.REALM_SERVICE, e);
1721            }
1722        }
1723        copyOrgInitialized = true;
1724        if (SMSEntry.debug.messageEnabled()) {
1725            SMSEntry.debug.message("OrganizationConfigManager: "+
1726                "copyOrgEnabled == " + copyOrgEnabled);
1727        }
1728        return (copyOrgEnabled);
1729    }
1730
1731    static void initializeFlags() {
1732        realmEnabled = ServiceManager.isRealmEnabled();
1733        coexistMode = ServiceManager.isCoexistenceMode();
1734        migratedTo70 = ServiceManager.isConfigMigratedTo70();
1735    }
1736    
1737    void validateConfigImpl() throws SMSException {
1738        // Instantiate the OrgConfigImpl and cache it
1739        if ((orgConfigImpl == null) || !orgConfigImpl.isValid()) {
1740            try {
1741                orgConfigImpl = OrganizationConfigManagerImpl.getInstance(
1742                    token, orgName);
1743            } catch (SSOException ssoe) {
1744                throw (new SMSException(ssoe, "sms-INVALID_SSO_TOKEN"));
1745            }
1746        }
1747    }
1748
1749    class OrganizationConfigManagerListener implements ServiceListener {
1750        public void schemaChanged(String serviceName, String version) {
1751            // Call ServiceManager to notify
1752            ServiceManager.schemaChanged();
1753            // If naming service has changed, reload the AM Servers
1754            if (serviceName.equalsIgnoreCase(ServiceManager.PLATFORM_SERVICE)) {
1755                ServiceManager.accessManagerServers = null;
1756            }
1757        }
1758
1759        public void globalConfigChanged(String serviceName, String version,
1760                String groupName, String serviceComponent, int type) {
1761            if (serviceName.equalsIgnoreCase(ServiceManager.REALM_SERVICE)) {
1762                try {
1763                    ServiceManager.checkFlags(token);
1764                } catch (SSOException ssoe) {
1765                    SMSEntry.debug.error("OrganizationConfigManager: "
1766                            + "globalConfigChanged ", ssoe);
1767                } catch (SMSException smse) {
1768                    SMSEntry.debug.error("OrganizationConfigManager: "
1769                            + "globalConfigChanged ", smse);
1770                }
1771                realmEnabled = ServiceManager.isRealmEnabled();
1772                coexistMode = ServiceManager.isCoexistenceMode();
1773                migratedTo70 = ServiceManager.isConfigMigratedTo70();
1774            }
1775        }
1776
1777        public void organizationConfigChanged(String serviceName,
1778                String version, String orgName, String groupName,
1779                String serviceComponent, int type) {
1780            // Reset the cached configuration in OrgConfigViaAMSDK
1781            if (serviceName.equalsIgnoreCase(OrgConfigViaAMSDK.IDREPO_SERVICE))
1782            {
1783                OrgConfigViaAMSDK.attributeMappings = new HashMap();
1784                OrgConfigViaAMSDK.reverseAttributeMappings = new HashMap();
1785            }
1786        }
1787    }
1788
1789    // ******* Static Variables ************
1790    // To determine if notification object has been registered for config
1791    // changes
1792    private static boolean registeredForConfigNotifications;
1793
1794    // Realm & Co-existence modes
1795    private static boolean realmEnabled;
1796
1797    private static boolean coexistMode;
1798
1799    private static boolean migratedTo70;
1800}




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.