001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2006 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: PolicyManager.java,v 1.19 2010/01/25 23:48:15 veiming Exp $
026 *
027 */
028
029/**
030 * Portions Copyrighted 2011-2012 ForgeRock Inc
031 */
032package com.sun.identity.policy;
033
034import com.sun.identity.entitlement.opensso.PrivilegeUtils;
035import com.iplanet.am.util.SystemProperties;
036import com.iplanet.sso.SSOToken;
037import com.iplanet.sso.SSOTokenManager;
038import com.iplanet.sso.SSOException;
039import com.sun.identity.entitlement.Application;
040import com.sun.identity.entitlement.ApplicationManager;
041import com.sun.identity.entitlement.EntitlementConfiguration;
042import com.sun.identity.policy.interfaces.Subject;
043import com.sun.identity.idm.IdUtils;
044import com.sun.identity.idm.IdRepoException;
045import com.sun.identity.entitlement.EntitlementException;
046import com.sun.identity.entitlement.IPrivilege;
047import com.sun.identity.entitlement.PrivilegeIndexStore;
048import com.sun.identity.entitlement.PrivilegeManager;
049import com.sun.identity.entitlement.ReferralPrivilege;
050import com.sun.identity.entitlement.ReferralPrivilegeManager;
051import com.sun.identity.entitlement.opensso.SubjectUtils;
052import com.sun.identity.security.AdminTokenAction;
053import com.sun.identity.shared.debug.Debug;
054import com.sun.identity.shared.ldap.util.DN;
055import com.sun.identity.shared.xml.XMLUtils;
056import com.sun.identity.sm.DNMapper;
057import com.sun.identity.sm.OrganizationConfigManager;
058import com.sun.identity.sm.PluginSchema;
059import com.sun.identity.sm.SMSEntry;
060import com.sun.identity.sm.SMSException;
061import com.sun.identity.sm.ServiceAlreadyExistsException;
062import com.sun.identity.sm.ServiceConfig;
063import com.sun.identity.sm.ServiceConfigManager;
064import com.sun.identity.sm.ServiceListener;
065import com.sun.identity.sm.ServiceManager;
066import com.sun.identity.sm.ServiceNotFoundException;
067import com.sun.identity.sm.ServiceSchemaManager;
068import java.io.ByteArrayInputStream;
069import java.net.MalformedURLException;
070import java.net.URL;
071import java.security.AccessController;
072import java.util.Collections;
073import java.util.Date;
074import java.util.HashSet;
075import java.util.HashMap;
076import java.util.Iterator;
077import java.util.Map;
078import java.util.Set;
079import org.w3c.dom.Node;
080import org.w3c.dom.Document;
081
082/**
083 * The <code>PolicyManager</code> class manages policies
084 * for a specific organization, sub organization or a container.
085 * This class is the
086 * starting point for policy management, and provides methods to
087 * create/modify/delete policies.
088 * <p>It is a final class
089 * and hence cannot be further extended. The methods in this class
090 * works directly with the backend datastore (usually a
091 * directory server) to store and manage policies. Hence, user
092 * of this class must have valid <code>SSOToken</code>
093 * and privileges to the backend datastore.
094 *
095 * @supported.api
096 */
097public final class PolicyManager {
098
099    /**
100     * The service name for Policy component.
101     * @supported.api
102     */
103    public static final String POLICY_SERVICE_NAME = "iPlanetAMPolicyService";
104    public static final String POLICY_DEBUG_NAME = "amPolicy";
105    
106    /**
107     * The key for the plugins to get the organization name.
108     * @supported.api
109     */
110    public static final String ORGANIZATION_NAME = "OrganizationName";
111    public static final String DELEGATION_REALM = 
112                      "/sunamhiddenrealmdelegationservicepermissions";
113
114    public static final String NAMED_POLICY = "Policies";
115    static final String REALM_SUBJECTS = "RealmSubjects";
116    static final String XML_REALM_SUBJECTS = "xmlRealmSubjects";
117    private static final String NAMED_POLICY_ID = "NamedPolicy";
118    static final String RESOURCES_POLICY = "Resources";
119    static final String RESOURCES_POLICY_ID = "ServiceType";
120    private static final String SUBJECTS_POLICY = "Subjects";
121    static final String SUBJECT_POLICY = "Subject";
122    static final String REALM_SUBJECT_POLICY = "RealmSubject";
123    static final String CONDITION_POLICY = "Condition";
124    static final String RESP_PROVIDER_POLICY = "ResponseProvider";
125    static final String REFERRAL_POLICY = "Referral";
126    static final String REFERRALS_POLICY = "Referrals";
127    private static final String POLICY_XML = "xmlpolicy";
128    static final String POLICY_VERSION = "1.0";
129
130    public static final String POLICY_ROOT_NODE = "Policy";
131    static final String POLICY_RULE_NODE = "Rule";
132    static final String POLICY_SUBJECTS_NODE = "Subjects";
133    static final String POLICY_CONDITIONS_NODE = "Conditions";
134    static final String POLICY_RESP_PROVIDERS_NODE = "ResponseProviders";
135    static final String POLICY_REFERRALS_NODE = "Referrals";
136    static final String POLICY_RULE_SERVICE_NODE = "ServiceName";
137    static final String POLICY_RULE_RESOURCE_NODE = "ResourceName";
138    static final String POLICY_RULE_EXCLUDED_RESOURCE_NODE =
139        "ExcludedResourceName";
140    static final String POLICY_RULE_APPLICATION_NAME_NODE = "ApplicationName";
141    static final String ATTR_VALUE_PAIR_NODE = "AttributeValuePair";
142    static final String ATTR_NODE = "Attribute";
143    static final String ATTR_VALUE_NODE = "Value";
144    static final String NAME_ATTRIBUTE = "name";
145    static final String TYPE_ATTRIBUTE = "type";
146    static final String DESCRIPTION_ATTRIBUTE = "description";
147    static final String CREATED_BY_ATTRIBUTE = "createdby";
148    static final String CREATION_DATE_ATTRIBUTE = "creationdate";
149    static final String LAST_MODIFIED_BY_ATTRIBUTE = "lastmodifiedby";
150    static final String LAST_MODIFIED_DATE_ATTRIBUTE = "lastmodifieddate";
151    static final String PRIORITY_ATTRIBUTE = "priority";
152    static final String STATUS_ATTRIBUTE = "priority";
153    static final String STATUS_ACTIVE = "active";
154    static final String STATUS_INACTIVE = "inactive";
155    static final String SERVICE_TYPE_NAME_ATTRIBUTE = "serviceName";
156
157    static final String POLICY_INDEX_ROOT_NODE = "PolicyCrossReferences";
158    static final String POLICY_INDEX_ROOT_NODE_NAME_ATTR = "name";
159    static final String POLICY_INDEX_ROOT_NODE_TYPE_ATTR = "type";
160    static final String
161        POLICY_INDEX_ROOT_NODE_TYPE_ATTR_RESOURCES_VALUE = "Resources";
162    static final String POLICY_INDEX_REFERENCE_NODE = "Reference";
163    static final String POLICY_INDEX_REFERENCE_NODE_NAME_ATTR = "name";
164    static final String POLICY_INDEX_POLICYNAME_NODE = "PolicyName";
165    static final String POLICY_INDEX_POLICYNAME_NODE_NAME_ATTR = "name";
166    static final long DEFAULT_SUBJECTS_RESULT_TTL = 10 * 60 * 1000;
167
168    static final String WEB_AGENT_SERVICE = "iPlanetAMWebAgentService";
169    public static final String ID_REPO_SERVICE = "sunIdentityRepositoryService";
170    public static final String ORG_ALIAS = "sunOrganizationAliases";
171    public static final String ORG_ALIAS_URL_HTTP_PREFIX = "http://";
172    public static final String ORG_ALIAS_URL_HTTPS_PREFIX = "https://";
173    public static final String ORG_ALIAS_URL_SUFFIX = ":*";
174
175    private String org = "/";
176    private String givenOrgName = "";
177    private ServiceConfigManager scm;
178    private OrganizationConfigManager ocm;
179    private ResourceManager rm;
180    private ServiceTypeManager svtm;
181    private SubjectTypeManager stm;
182    private ConditionTypeManager ctm;
183    private ResponseProviderTypeManager rpm;
184    private ReferralTypeManager rtm;
185    private PolicyCache policyCache;
186    private ResourceIndexManager rim;
187
188    private static ServiceSchemaManager ssm;
189    private static javax.security.auth.Subject adminSubject;
190
191    SSOToken token;
192
193    // Can be shared by classes
194    static Debug debug = Debug.getInstance(POLICY_DEBUG_NAME);
195    static DN delegationRealm = new DN(DNMapper.orgNameToDN(DELEGATION_REALM));
196    private static boolean migratedToEntitlementService = false;
197
198    /**
199     * Constructor for <code>PolicyManager</code> for the
200     * top (or root) organization. It requires a <code>SSOToken
201     * </code> which will be used to perform all data store
202     * operations. If the user does not have sufficient
203     * privileges <code>NoPermissionException</code> will be thrown.
204     *
205     * @param token <code>SSOToken</code> of the user managing policy
206     *
207     * @throws SSOException invalid or expired single-sign-on token
208     * @throws PolicyException for any other abnormal condition
209     *  
210     * @supported.api
211     */
212    public PolicyManager(SSOToken token) throws SSOException, PolicyException {
213        this(token, "");
214        if (debug.messageEnabled()) {
215            debug.message("Policy Manager constructed using SSO token");
216        }
217    }
218
219    /**
220     * Constructor for <code>PolicyManager</code> for the
221     * specified organization, sub organization or a container object.
222     * The names of the organization, sub organization or the
223     * container object could be either "/" separated (as per SMS)
224     * or could be the complete DN of the object.
225     * For example: <code>/isp/coke<code>, <code>/isp/pepsi/tacobell<code>,
226     * etc., or <code>"ou=tacobell, o=pepsi, o=isp"<code>,
227     * <code>"o=coke, o=isp"</code>, etc.
228     * The constructor also requires a single sign on token.
229     * which will be used to perform all data store
230     * operations. If the user does not have sufficient
231     * privileges <code>NoPermissionException</code> will be thrown.
232     *
233     * @param token single-sign-on token of the user managing policies
234     * @param name name of the organization, sub organization
235     * or container for which to manage policies.
236     * The name could be either slash (/) separated
237     * or the complete DN.
238     *
239     * @throws SSOException invalid or expired single-sign-on token
240     * @throws NameNotFoundException if the given organization,
241     *          sub-organization or container name is not present
242     * @throws PolicyException for any other abnormal condition
243     *
244     * @supported.api
245     */
246    public PolicyManager(SSOToken token, String name)
247        throws SSOException, NameNotFoundException, PolicyException {
248        SSOTokenManager.getInstance().validateToken(token);
249        this.token = token;
250        try {
251            scm = new ServiceConfigManager(POLICY_SERVICE_NAME, token);
252
253            // Check name i.e., org name
254            org = verifyOrgName(name);
255            givenOrgName = name;
256
257            rm = new ResourceManager(org);
258        } catch (SMSException se) {
259            debug.error("In constructor for PolicyManager with orgName" +
260                "Unable to get service config manager", se);
261            throw (new PolicyException(se));
262        }
263            
264        if (debug.messageEnabled()) {
265            debug.message("Policy Manager constructed with SSO token " +
266                " for organization: " + org);
267        }
268        if (SystemProperties.isServerMode()) {
269            policyCache = PolicyCache.getInstance();
270            svtm = ServiceTypeManager.getServiceTypeManager();
271        } else {
272            policyCache = PolicyCache.getInstance(token);
273            svtm = new ServiceTypeManager(token);
274        }
275        rim = new ResourceIndexManager(rm);
276
277    }
278
279    /**
280     * Gets the organization name for which the policy manager
281     * was initialized with. The organization name could either be
282     * slash ("/") separated or could be the distinguished name
283     * depending on the manner in which it was initialized.
284     *
285     * @return organization name for which the policy manager was
286     *           instantiated
287     *
288     * @supported.api
289     */
290    public String getOrganizationName() {
291        return (givenOrgName);
292    }
293
294    /** 
295     * Gets the policy config attribute values defined for this policy manager
296     * @return policy config attributes defined for this policy manager. Also, 
297     *         includes the organization distinguished name. 
298     */
299    public Map getPolicyConfig() {
300        Map policyConfig = null;
301        try {
302            policyConfig = PolicyConfig.getPolicyConfig(org);
303        } catch (PolicyException pe) {
304                    debug.error("PolicyManager:can not get policy config "
305                    + " for org : " + org, pe);
306        }
307        if (policyConfig != null) {
308            Set set = new HashSet();
309            set.add(org);
310            policyConfig.put(ORGANIZATION_NAME, set);
311        } else {
312            debug.error("PolicyManager: policy config is null for org:" 
313                  + org + ". Most likely it has been unregistered." 
314                  + " It is not recommended to unregister the policy"
315                  + " configuration serivce. If you do so, the result"
316                  + " is undefined.");
317        }
318        return policyConfig;
319    }
320
321    /**
322     * Gets the organization DN
323     * @return DN of the organization for which this policy manager
324     *          was created
325     */
326    String getOrganizationDN() {
327        return (org);
328    }
329
330    /**
331     * Gets a set of  names of polices defined in the
332     * organization for which the policy manager was instantiated.
333     * If there are no policies defined, this method returns
334     * an empty set (not null).
335     *
336     * @return <code>Set</code> of names of policies defined in the organization
337     * 
338     * @throws SSOException invalid or expired single-sign-on token
339     * @throws NoPermissionException user does not have sufficient
340     *          privileges to get policy names
341     * @throws PolicyException for any other abnormal condition
342     *
343     * @supported.api
344     */
345    public Set getPolicyNames() throws SSOException, NoPermissionException,
346        PolicyException {
347        return (getPolicyNames("*"));
348    }
349
350    /**
351     * Gets a set of selected policy names matching the
352     * pattern in the given organization. The pattern
353     * accepts "*" as the wild card for searching policy names.
354     * For example if the pattern is "co*", it returns policies
355     * starting with "co". Similarly, if the pattern is "*net", it returns
356     * policies ending with "net". The wildcard can be anywhere in the
357     * the string. If there are no policies that match the provided filter,
358     * this method returns an empty set (not null).
359     *
360     * @param pattern search pattern that will be used to select policy names
361     *
362     * @return <code>Set</code> of policy names that satisfy the pattern
363     *
364     * @throws SSOException invalid or expired single-sign-on token
365     * @throws NoPermissionException user does not have sufficient
366     *          privileges to get policy names
367     * @throws PolicyException for any other abnormal condition
368     *
369     * @supported.api
370     */
371    public Set getPolicyNames(String pattern) throws SSOException,
372        NoPermissionException, PolicyException {
373        try {
374            ServiceConfig oConfig = scm.getOrganizationConfig(org, null);
375            ServiceConfig namedPolicy = (oConfig == null) ? null :
376                oConfig.getSubConfig(NAMED_POLICY);
377            if (namedPolicy == null) {
378               return (Collections.EMPTY_SET);
379            } else {
380                if (pattern.equals("*")) {
381                    return (namedPolicy.getSubConfigNames());
382                } else {
383                    return (namedPolicy.getSubConfigNames(pattern));
384                }
385            }
386       } catch (SMSException se) {
387            debug.error("Unable to get named policies for organization: " 
388                    + org);
389            // Check for permission exception
390            String objs[] = { org };
391            if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
392                throw (new NoPermissionException(ResBundleUtils.rbName,
393                    "insufficient_access_rights", null));
394            } else {
395                // Throw generic policy exception
396                throw (new PolicyException(ResBundleUtils.rbName,
397                    "unable_to_get_policies_for_organization", objs,
398                    se));
399            }
400        }
401    }
402
403    /**
404     * Gets the LDAP DN (distinguished name) for the named policy
405     * @param policyName name of the policy
406     * @return DN of the policy 
407     * @throws SSOException if single sign on token associated with the policy
408     *         manager is not valid.
409     * @throws NoPermissionException if not enough permissions
410     * @throws NameNotFoundException if the policy is not found
411     * @throws PolicyException for any other abnormal condition
412     *
413     */
414    public String getPolicyDN(String policyName) throws
415        SSOException, NoPermissionException, NameNotFoundException,
416        PolicyException {
417        // Get the policy. If the policy does not exists it will
418        // throw NameNotFoundException
419        getPolicy(policyName);
420
421        // Policy is present, construct the DN and return
422        StringBuilder answer = new StringBuilder(100);
423        answer.append("ou=");
424        answer.append(policyName);
425        answer.append(",ou=");
426        answer.append(NAMED_POLICY);
427        answer.append(",ou=default,ou=organizationConfig,ou=");
428        answer.append(POLICY_VERSION);
429        answer.append(",ou=");
430        answer.append(POLICY_SERVICE_NAME);
431        answer.append(",ou=services,");
432        answer.append(org);
433        return (answer.toString());
434    }
435
436    /**
437     * Gets the policy object given the name of the policy. 
438     *
439     * @param policyName name of the policy
440     * @return policy with the given policy name
441     * @throws SSOException if single sign on token associated with the policy
442     *         manager is not valid.
443     * @throws NoPermissionException if not enough permissions.
444     * @throws InvalidFormatException if <code>policyName</code> has 
445     *                                invalid format.
446     * @throws NameNotFoundException if the policy is not found.
447     * @throws InvalidNameException if <code>policyName</code> is invalid.
448     * @throws PolicyException for any other abnormal condition.
449     *
450     *
451     * @supported.api
452     */
453    public Policy getPolicy(String policyName) throws SSOException,
454            NoPermissionException, InvalidFormatException, 
455            NameNotFoundException,
456        InvalidNameException, PolicyException {
457        if (policyName == null) {
458            throw (new InvalidNameException(ResBundleUtils.rbName,
459                "null_name", null, "null", PolicyException.POLICY));
460        }
461        if (debug.messageEnabled()) {
462            debug.message("searching for named policy: " + policyName +
463                " in organization: " + org);
464           }
465
466        // Check the cache %%% Need to have notification for policy changes
467        Policy answer = null;
468
469        try {
470            ServiceConfig oConfig = scm.getOrganizationConfig(org, null);
471            ServiceConfig namedPolicy = (oConfig == null) ? null :
472                oConfig.getSubConfig(NAMED_POLICY);
473            ServiceConfig policy = null;
474            Map attrs = null;
475            Set  res = null;
476            if ((namedPolicy == null) ||
477                ((policy = namedPolicy.getSubConfig(policyName)) == null) ||
478                ((attrs = policy.getAttributes()) == null) ||
479                ((res = (Set) attrs.get(POLICY_XML)) == null) ||
480                (res.size() <= 0)) {
481                // Named policy node or policy node does not exist
482                if (debug.warningEnabled()) {
483                    debug.warning("Unable to find named policy: " + policyName +
484                        " in organization: " + org);
485                }
486                String objs[] = { policyName, org };
487                throw (new NameNotFoundException(ResBundleUtils.rbName,
488                    "policy_not_found_in_organization", objs, policyName,
489                    PolicyException.POLICY));
490            }
491
492            // Now create a policy object out of the XML blob
493            Iterator it = res.iterator();
494            String policyXml = (String) it.next();
495            Document doc = null;
496            try {
497                doc = XMLUtils.getXMLDocument(
498                    new ByteArrayInputStream(policyXml.getBytes("UTF8")));
499            } catch (Exception xmle) {
500                debug.error("XML parsing error for policy: " + policyName +
501                    " in organization: " + org);
502                // throw generic policy exception
503                throw (new PolicyException(xmle));
504            }
505            Node rootNode = XMLUtils.getRootNode(doc, POLICY_ROOT_NODE);
506            if (rootNode == null) {
507                debug.error("invalid xml policy blob for named policy: " +
508                        policyName +    " in organization: " + org);
509                throw (new InvalidFormatException(ResBundleUtils.rbName,
510                    "invalid_xml_policy_root_node", null, policyName,
511                    PolicyException.POLICY));
512            }
513
514            if (debug.messageEnabled()) {
515                debug.message("returning named policy: " + policyName +
516                    " for organization: " + org);
517            }
518
519            // Return the policy object
520            answer = new Policy(this, rootNode);
521            Map policyConfig = getPolicyConfig();
522            if (policyConfig != null) {
523                answer.setSubjectsResultTtl(
524                        PolicyConfig.getSubjectsResultTtl(policyConfig));
525            }
526
527            return (answer);
528        } catch (SMSException se) {
529            debug.error("SMS error in finding named policy: " + policyName +
530                    " in organization: " + org);
531            // Check for permission exception
532            String objs[] = { policyName, org };
533            if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
534                throw (new NoPermissionException(ResBundleUtils.rbName,
535                    "insufficient_access_rights", null));
536            } else {
537                // Throw generic policy exception
538                throw (new PolicyException(ResBundleUtils.rbName,
539                    "unable_to_get_policy", objs, se));
540            }
541        }
542
543    }
544
545    /**
546     * Adds a policy to the data store. 
547     *
548     * @param policy policy object to be added to the organization
549     *
550     * @throws SSOException invalid or expired single-sign-on token
551     * @throws NoPermissionException user does not have sufficient
552     * privileges to add policy
553     * @throws InvalidFormatException the data in the policy object
554     * has been corrupted or does not have a valid format
555     * @throws NameAlreadyExistsException a policy with the same
556     * name already exists
557     * @throws PolicyException for any other abnormal condition
558     *
559     * @supported.api
560     */
561    public void addPolicy(Policy policy) throws SSOException,
562            NameAlreadyExistsException, NoPermissionException,
563            InvalidFormatException, PolicyException {
564
565        String realmName = getOrganizationDN();
566
567        //TODO: handle non DNs/
568        realmName = new DN(realmName).toRFCString().toLowerCase();
569        String subjectRealm = policy.getSubjectRealm();
570        String[] realmNames = {realmName, subjectRealm};
571        if ((subjectRealm != null) && !subjectRealm.equals(realmName)) {
572            if (debug.messageEnabled()) {
573                debug.message("Can not add policy in realm :"
574                        + realmName + ", policy has realm subjects "
575                        + " from realm : " + subjectRealm);
576            }
577
578            //TODO : add logging?
579
580            throw (new InvalidFormatException(ResBundleUtils.rbName,
581                "policy_realm_does_not_match", realmNames, null, realmName, 
582                PolicyException.POLICY));
583        }
584        validateForResourcePrefix(policy);
585        validateReferrals(policy);
586
587        String testCreatedBy = policy.getCreatedBy();
588        //testCreatedBy is set if we are doing policy replaced.
589        if ((testCreatedBy == null) || (testCreatedBy.length() == 0)) {
590            Date creationDate = new Date();
591            policy.setCreatedBy(token.getPrincipal().getName());
592            policy.setCreationDate(creationDate.getTime());
593            policy.setLastModifiedBy(token.getPrincipal().getName());
594            policy.setLastModifiedDate(creationDate.getTime());
595        }
596
597        // Construct the named policy
598        String policyXml = policy.toXML();
599        Map attrs = new HashMap();
600        Set set = new HashSet();
601        set.add(policyXml);
602        attrs.put(POLICY_XML, set);
603
604        // Get(create if necessary) ou=policies entry
605        ServiceConfig namedPolicy = createOrGetPolicyConfig(
606            NAMED_POLICY, NAMED_POLICY, scm, org);
607        try {
608            //create the policy entry
609            namedPolicy.addSubConfig(policy.getName(),
610                NAMED_POLICY_ID, 0, attrs);
611            if (isMigratedToEntitlementService()) {
612                PrivilegeIndexStore pis = PrivilegeIndexStore.getInstance(
613                    adminSubject, realmName);
614                Set<IPrivilege> privileges = PrivilegeUtils.policyToPrivileges(
615                    policy);
616                pis.add(privileges);
617                if (policy.isReferralPolicy()) {
618                    ReferralPrivilegeManager refpm =
619                        new ReferralPrivilegeManager(realmName, adminSubject);
620                    refpm.addApplicationToSubRealm(
621                        (ReferralPrivilege)privileges.iterator().next());
622                }
623                policyCache.sendPolicyChangeNotification(null, policy,
624                    ServiceListener.ADDED);
625            } else {
626                // do the addition in resources tree
627                //rm.addPolicyToResourceTree(policy);
628                rim.addPolicyToResourceTree(svtm, token, policy);
629            }
630        } catch (EntitlementException e) {
631            String[] objs = { policy.getName(), org };
632            throw (new PolicyException(ResBundleUtils.rbName, 
633                "unable_to_add_policy", objs, e)); 
634        } catch (ServiceAlreadyExistsException e) {
635            String[] objs = { policy.getName(), org };
636            if (PolicyUtils.logStatus) {
637                 PolicyUtils.logErrorMessage(
638                    "POLICY_ALREADY_EXISTS_IN_REALM", objs, token);
639            }
640            throw (new NameAlreadyExistsException(ResBundleUtils.rbName,
641                "policy_already_exists_in_org", objs, policy.getName(), 
642                PolicyException.POLICY));
643        } catch (SMSException se) {
644            String[] objs = { policy.getName(), org };
645            if (PolicyUtils.logStatus) {
646                 PolicyUtils.logErrorMessage("UNABLE_TO_ADD_POLICY", objs, 
647                    token);
648            }
649            debug.error("SMS error in add policy: " +
650                    policy.getName() + " for org: " + org, se);
651
652            // Check for permission exception
653            if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
654                throw (new NoPermissionException(ResBundleUtils.rbName,
655                    "insufficient_access_rights", null));
656            } else {
657                // Throw generic policy exception
658                throw (new PolicyException(ResBundleUtils.rbName, 
659                        "unable_to_add_policy",
660                        objs, se));
661            }
662        }
663        if (PolicyUtils.logStatus) {
664            String[] objs = { policy.getName(), org };
665            PolicyUtils.logAccessMessage("POLICY_CREATE_SUCCESS", objs, token);
666        }
667    }
668
669    /**
670     * Replaces a policy object  in the data store with the same policy name
671     *
672     * @param policy policy object to be added to the organization
673     *
674     * @throws SSOException invalid or expired single-sign-on token
675     * @throws NoPermissionException user does not have sufficient
676     * privileges to replace policy
677     * @throws NameNotFoundException policy with the same name does
678     * not exist.
679     * @throws InvalidFormatException the provide policy from the
680     * data store has been corrupted or does not have a valid format
681     * @throws PolicyException for any other abnormal condition.
682     *
683     * @supported.api
684     */
685    public void replacePolicy(Policy policy) throws SSOException,
686        NameNotFoundException, NoPermissionException,
687        InvalidFormatException, PolicyException {
688
689        String realm = getOrganizationDN();
690        String subjectRealm = policy.getSubjectRealm();
691        String[] realmNames = {realm, subjectRealm};
692        if ((subjectRealm != null) && !subjectRealm.equals(realm)) {
693
694            if (debug.messageEnabled()) {
695                debug.message("Can not replace policy in realm :"
696                        + realm + ", policy has realm subjects "
697                        + " from realm : " + subjectRealm);
698            }
699
700            throw (new InvalidFormatException(ResBundleUtils.rbName,
701                "policy_realm_does_not_match", realmNames, null, realm,
702                PolicyException.POLICY));
703        }
704
705        policy.setLastModifiedBy(token.getPrincipal().getName());
706        Date lastModifiedDate = new Date();
707        policy.setLastModifiedDate(lastModifiedDate.getTime());
708
709        // Construct the named policy
710        String policyXml = policy.toXML();
711        Map attrs = new HashMap();
712        Set set = new HashSet();
713        set.add(policyXml);
714        attrs.put(POLICY_XML, set);
715
716        String name = null;
717        // Get(create if necessary) ou=policies entry
718        ServiceConfig namedPolicy = createOrGetPolicyConfig(
719            NAMED_POLICY, NAMED_POLICY, scm, org);
720        try {
721            String policyName = policy.getName();
722            String oldPolicyName = policy.getOriginalName();
723            ServiceConfig policyEntry = namedPolicy.getSubConfig(policyName);
724            ServiceConfig oldPolicyEntry = null;
725            if ( oldPolicyName != null ) {
726                oldPolicyEntry = namedPolicy.getSubConfig(oldPolicyName);
727                name = oldPolicyName;
728            } else {
729                name = policy.getName();
730            }
731            if ( policyEntry == null ) {
732                if ( oldPolicyEntry != null ) {
733                    removePolicy(oldPolicyName);
734                    addPolicy(policy);
735                    // reset the policy name
736                    // TODO: need to think this through
737                    policy.resetOriginalName();
738                } else {
739                    // neither the new policy nor the old policy is present
740                    String objs[] = { policy.getName(), org };
741                    throw (new NameNotFoundException(ResBundleUtils.rbName,
742                            "policy_not_found_in_organization", objs,
743                         policy.getName(), PolicyException.POLICY));
744                }
745            } else { //newPolicy exisits
746                String[] objs = { policy.getName(), org };
747                if((oldPolicyName != null) && 
748                            !policy.getName().equalsIgnoreCase(oldPolicyName)) {
749                    if (PolicyUtils.logStatus) {
750                        PolicyUtils.logErrorMessage(
751                            "DID_NOT_REPLACE_POLICY", 
752                            objs, token);
753                    }
754                    throw (new NameAlreadyExistsException(ResBundleUtils.rbName,
755                        "policy_already_exists_in_org", objs, policy.getName(), 
756                        PolicyException.POLICY));
757                }
758
759                Policy oldPolicy = getPolicy(policy.getName());
760                validateForResourcePrefix(policy);
761                validateReferrals(policy);
762                policyEntry.setAttributes(attrs);
763                if (oldPolicy != null) {
764                    if (isMigratedToEntitlementService()) {
765                        PrivilegeIndexStore pis = PrivilegeIndexStore.
766                            getInstance(SubjectUtils.createSubject(token),
767                            realm);
768                        pis.delete(PrivilegeUtils.policyToPrivileges(
769                            oldPolicy));
770                        pis.add(PrivilegeUtils.policyToPrivileges(policy));
771                    } else {
772                        //rm.replacePolicyInResourceTree(oldPolicy, policy);
773                        rim.replacePolicyInResourceTree(svtm, token, oldPolicy,
774                            policy);
775                    }
776
777                    policyCache.sendPolicyChangeNotification(oldPolicy, policy, ServiceListener.MODIFIED);
778                }
779            }
780        } catch (EntitlementException e) {
781            String[] objs = { name, org };
782            throw (new PolicyException(ResBundleUtils.rbName,
783                "unable_to_replace_policy", objs, e));
784        } catch (SMSException se) {
785            String[] objs = { name, org };
786            if (PolicyUtils.logStatus) {
787                PolicyUtils.logErrorMessage("UNABLE_TO_REPLACE_POLICY", objs, 
788                    token);
789            }
790            debug.error("SMS error in replacing policy: " +
791                    policy.getOriginalName() + " for org: " + org, se);
792            // Check for permission exception
793            if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
794                throw (new NoPermissionException(ResBundleUtils.rbName,
795                    "insufficient_access_rights", null));
796            } else {
797                // Throw generic policy exception
798                throw (new PolicyException(ResBundleUtils.rbName, 
799                    "unable_to_replace_policy", objs, se));
800            }
801        }
802        if (PolicyUtils.logStatus) {
803            String[] objs = { name, org };
804            PolicyUtils.logAccessMessage("POLICY_MODIFY_SUCCESS", objs, token);
805        }
806    }
807
808    /**
809     * Deletes a policy in the organization with the given name.
810     *
811     * @param policyName name of the policy to be deleted
812     *
813     * @throws SSOException invalid or expired single-sign-on token
814     * @throws NoPermissionException user does not have sufficient
815     * privileges to remove policies
816     * @throws PolicyException for any other abnormal condition
817     *
818     * @supported.api
819     */
820    public void removePolicy(String policyName) throws
821        SSOException, NoPermissionException, PolicyException {
822        // Check if name is valid
823        if (policyName == null) {
824            if (debug.warningEnabled()) {
825                debug.warning("In PolicyManager::removePolicy(), name is null");
826            }
827            throw (new InvalidNameException(ResBundleUtils.rbName,
828                "null_name", null, "null", PolicyException.POLICY));
829        }
830
831        try {
832            // Get service config for named policy node
833            ServiceConfig oConfig = scm.getOrganizationConfig(org, null);
834            ServiceConfig namedPolicy = (oConfig == null) ? null :
835                oConfig.getSubConfig(NAMED_POLICY);
836            if (namedPolicy != null) {
837                /* Remove the named policy
838                 * before removing the named policy
839                 * prepare for changes in resources tree
840                 */
841                Policy policy = getPolicy(policyName);
842
843                // do the removal of policy 
844                namedPolicy.removeSubConfig(policyName);
845
846                if (policy != null) {
847                    if (isMigratedToEntitlementService()) {
848                        // should use super admin token to remove the index store
849                        // entry
850                        PrivilegeIndexStore pis = PrivilegeIndexStore.
851                            getInstance(
852                            SubjectUtils.createSuperAdminSubject(),
853                            getOrganizationDN());
854                        if (policy.isReferralPolicy()) {
855                            pis.deleteReferral((policyName));
856                        } else {
857                            pis.delete(
858                                PrivilegeUtils.policyToPrivileges(policy));
859                        }
860                        policyCache.sendPolicyChangeNotification(null, policy,
861                            ServiceListener.REMOVED);
862                    } else {
863                        // do the removal in resources tree
864                        rim.removePolicyFromResourceTree(svtm, token, policy);
865
866                    }
867                }
868            }
869        } catch (EntitlementException e) {
870            debug.error("Error while removing policy : " + e.getMessage());
871        } catch (ServiceNotFoundException snfe) {
872            debug.error("Error while removing policy : " +
873                    snfe.getMessage() );
874        } catch (SMSException smse) {
875            String objs[] = { policyName, org };
876            if (PolicyUtils.logStatus) {
877                PolicyUtils.logErrorMessage("UNABLE_TO_REMOVE_POLICY", objs, 
878                    token);
879            }
880            debug.error("SMS error in deleting policy: " +
881                    policyName + " for org: " + org, smse);
882            // Check for permission exception
883            if (smse.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
884                throw (new NoPermissionException(ResBundleUtils.rbName,
885                    "insufficient_access_rights", null));
886            } else {
887                // Throw generic policy exception
888                throw (new PolicyException(ResBundleUtils.rbName, 
889                    "unable_to_remove_policy", objs, smse));
890            }
891        }
892        String objs[] = { policyName, org };
893        if (PolicyUtils.logStatus) {
894            PolicyUtils.logAccessMessage("POLICY_REMOVE_SUCCESS", objs, token);
895        }
896    }
897
898    /**
899     * Gets the <code>ResourceManager</code> object instance associated
900     * with this <code>PolicyManager</code> object instance
901     *
902     * @return <code>ResourceManager</code> object
903     *
904     * @supported.api
905     */    
906    public ResourceManager getResourceManager() {
907        return rm;
908    }
909    
910    /**
911     * Gets the <code>SubjectTypeManager</code> object instance associated
912     * with this <code>PolicyManager</code> object instance
913     *
914     * @return <code>SubjectTypeManager</code> object
915     *
916     * @supported.api
917     */    
918    public SubjectTypeManager getSubjectTypeManager() {
919        if (stm == null) {
920            stm = new SubjectTypeManager(this);
921        }
922        return (stm);
923    }
924    
925    /**
926     * Gets the <code>ConditionTypeManager</code> object instance associated
927     * with this <code>PolicyManager</code> object instance
928     *
929     * @return <code>ConditionTypeManager</code> object
930     *
931     * @supported.api
932     */    
933    public ConditionTypeManager getConditionTypeManager() {
934        if (ctm == null) {
935            ctm = new ConditionTypeManager(this);
936        }
937        return (ctm);
938    }
939
940     /**
941      * Gets the <code>ResponseProviderTypeManager</code> object instance 
942      * associated with this <code>PolicyManager</code> object instance
943      *
944      * @return <code>ResponseProviderTypeManager</code> object
945      *
946      */    
947     public ResponseProviderTypeManager getResponseProviderTypeManager() {
948         if (rpm == null) {
949             rpm = new ResponseProviderTypeManager(this);
950         }
951         return (rpm);
952     }
953     
954    /** Creates or gets a node (namedPolicy, resources, or userCollection)
955     *  under ou=policies
956     */
957    static ServiceConfig createOrGetPolicyConfig(String configName,
958        String configId, ServiceConfigManager scm, String org)
959        throws NoPermissionException, PolicyException, SSOException {
960        // Get service config that represents named policy node
961        ServiceConfig sConfig = null;
962        try {
963            ServiceConfig oConfig = scm.getOrganizationConfig(org, null);
964            sConfig = (oConfig == null) ? null :
965                oConfig.getSubConfig(configName);
966            if (sConfig == null) {
967                if (debug.messageEnabled()) {
968                    debug.message("Creating the " + configName +
969                        " tree for org: " + org);
970                }
971                // create the named policy node
972                createPolicyTree(configName, configId, scm, org);
973
974                // Check if policy tree is created
975                if (oConfig == null) {
976                    oConfig = scm.getOrganizationConfig(org, null);
977                }
978                if ((oConfig == null) || ((sConfig = oConfig.getSubConfig(
979                    configName)) == null)) {
980                    // Throw generic policy exception
981                    String objs[] = { configName };
982                    throw (new PolicyException(ResBundleUtils.rbName,
983                        "unable_to_get_policy_node", objs, null));
984                }
985            }
986        } catch (SMSException smse) {
987            // Debug messages
988            debug.error("SMS error in creating " + configName +
989                            " node for org: " + org, smse);
990
991            // Check for permission exception
992            if (smse.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
993                String objs[] = { configName };
994                throw (new NoPermissionException(ResBundleUtils.rbName,
995                    "insufficient_access_rights", objs));
996            } else {
997                // Throw generic policy exception
998                String objs[] = { configName };
999                throw (new PolicyException(ResBundleUtils.rbName,
1000                    "unable_to_get_policy_node", objs, smse));
1001            }
1002        }
1003        return (sConfig);
1004    }
1005
1006    /**
1007     *  Creates the policy tree, ou=policy, ou=services, ... 
1008     */
1009    static void createPolicyTree(String configName, String configId,
1010        ServiceConfigManager scm, String org) throws NoPermissionException,
1011        PolicyException, SSOException {
1012        try {
1013            // Get the iPlanetPolicyService node            
1014            ServiceConfig pConfig = scm.getOrganizationConfig(org, null);
1015            if (pConfig == null) {
1016                // Since not present, create organization services node
1017                // i.e, ou=services, <org dn> and ou=iPlanetPolicyService,
1018                //  ou=services, ...
1019                scm.createOrganizationConfig(org, null);
1020                // Since it is created above, get it
1021                pConfig = scm.getOrganizationConfig(org, null);
1022            }
1023            // Create requested policy sub node
1024            // i.e., ou=<configName>, ou=iPlanetPolicyService, ou=services, ...
1025            pConfig.addSubConfig(configName, configId, 0, null);
1026        } catch (ServiceAlreadyExistsException se) {
1027            // do nothing
1028            if (debug.messageEnabled()) {
1029                debug.message("PolicyManager->createPolicyTree: Name: " +
1030                    configName + " ID: " + configId + 
1031                    " Policy service already exists under org->" + org);
1032            }
1033        } catch (SMSException e) {
1034            // Check for permission exception
1035            String[] objs = { org };
1036            if (e.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
1037                throw (new NoPermissionException(ResBundleUtils.rbName,
1038                    "insufficient_access_rights", null));
1039            } else {
1040                throw (new PolicyException(ResBundleUtils.rbName,
1041                    "unable_to_create_policy_for_org", objs, e));
1042            }
1043        }
1044    }
1045
1046    /**
1047     * Verifies if the name, which specifies a organization,
1048     * a suborganization or a container object, is in DN format; If not,
1049     * the name will be converted to a DN. Furthermore, whether the entry
1050     * corresponding to the DN exists is also checked.
1051     *
1052     * @param name name of the organization, suborganization
1053     * or container for which to manage policies.
1054     * The name could be either slash (/) separated
1055     * or the complete DN.
1056     *
1057     * @return the name in DN format (possibly converted from slash format)
1058     *
1059     * @throws SSOException invalid or expired single-sign-on token
1060     * @throws InvalidNameException the name is null
1061     * @throws NameNotFoundException if the given organization,
1062     * sub-organization or container name is not present
1063     */
1064    String verifyOrgName(String name)
1065        throws InvalidNameException, NameNotFoundException, SSOException {
1066        String orgName = null;
1067
1068        // Check for null name
1069        if (name == null) {
1070            throw (new InvalidNameException(ResBundleUtils.rbName, "null_name",
1071                null, "null", PolicyException.ORGANIZATION));
1072        }
1073
1074        /* this mapping call is required if name is not a DN
1075         * or if the name is not DN of a realm
1076         * This call is harmless if the DN is already DN of a realm
1077         */
1078        orgName = DNMapper.orgNameToDN(name);
1079
1080        // Check to see if the organization exists
1081        // if not present throw NameNotFoundException
1082        if (!SMSEntry.checkIfEntryExists(orgName, token)) {
1083            if (debug.warningEnabled()) {
1084                debug.warning("Checking for organization name: " +
1085                    orgName + " failed since entry does not exist");
1086            }
1087            String[] objs = { name };
1088            throw (new NameNotFoundException(ResBundleUtils.rbName,
1089                "org_not_found", objs, orgName,
1090                PolicyException.ORGANIZATION));
1091        }
1092        return (orgName);
1093    }
1094    
1095    /**
1096     * Gets a list of subordinate organizations or containers. If
1097     * there are no subordinate organizations or containers, returns
1098     * an empty set (not null).
1099     *
1100     * @return set of valid subordinate organizations or containers
1101     *
1102     * @throws SSOException invalid or expired single-sign-on token
1103     * @throws NoPermissionException user does not have sufficient
1104     * privileges to replace policy
1105     */
1106    Set getSubOrganizationNames() throws SSOException,
1107        NoPermissionException, PolicyException {
1108        throw (new UnsupportedOperationException());
1109    }
1110
1111    /**
1112     * Gets sub-organizations, given a filter. The filter
1113     * accepts "*" as the wild card for searching sub-organization names.
1114     * For example if the filter is "co*", it returns sub-organizations
1115     * starting with "co". Similarly, if the filter is "*net", it returns
1116     * sub-organizations ending with "net".
1117     *
1118     * @param filter the search filter that be used to 
1119     *               identify sub-organizations
1120     *
1121     * @return a set of sub-organizations
1122     */
1123    Set getSubOrganizationNames(String filter)
1124        throws SSOException, PolicyException {
1125        throw (new UnsupportedOperationException());
1126    }
1127
1128    /**
1129     * Gets sub-organization's policy manager.
1130     *
1131     * @param subOrgName name of the sub-organization organization. This
1132     * should be relative to the current organization.
1133     *
1134     * @return returns the policy manager for the organization;
1135     * else returns <code>null</code>.
1136     */
1137    PolicyManager getSubOrganizationPolicyManager(String subOrgName)
1138        throws SSOException, PolicyException {
1139        // the assumption is that orgnames are / separated
1140        return (new PolicyManager(token, org + "/" + subOrgName));
1141    }
1142
1143    /**
1144     * Gets <code>ServiceTypeManager</code> associated with this 
1145     * policy manager
1146     */
1147    ServiceTypeManager getServiceTypeManager() {
1148        return svtm;
1149    }
1150    
1151    /**
1152     * Returns <code>ReferralTypeManager</code> associated with this 
1153     * policy manager.
1154     *
1155     * @return <code>ReferralTypeManager</code> associated with this 
1156     * policy manager.
1157     * @supported.api
1158     */
1159    public ReferralTypeManager getReferralTypeManager() {
1160        if ( rtm == null ) {
1161            rtm = new ReferralTypeManager(this);
1162        }
1163        return rtm;
1164    }
1165
1166
1167    /**
1168     * Gets plugins schemas for a given interface name
1169     */
1170    static Set getPluginSchemaNames(String interfaceName) {
1171        if (ssm == null) {
1172            try {
1173                ssm = new ServiceSchemaManager(
1174                    PolicyManager.POLICY_SERVICE_NAME,
1175                    ServiceTypeManager.getSSOToken());
1176            } catch (Exception se) {
1177                PolicyManager.debug.error(
1178                        "Cannot create service schema " +
1179                        "manager for policy", se);
1180                return (Collections.EMPTY_SET);
1181            }
1182        }
1183
1184        Set answer = null;
1185        try {
1186           /* Get the plugin schema names for the root
1187            * In the future might want to customize it for org
1188            */
1189            answer = ssm.getPluginSchemaNames(interfaceName, null);
1190        } catch (Exception e) {
1191            PolicyManager.debug.error(
1192                    "Cannot get plugin schemas: " +
1193                    interfaceName + " for policy", e);
1194            return (Collections.EMPTY_SET);
1195        }
1196        return ((answer == null) ? Collections.EMPTY_SET : answer);
1197    }
1198
1199
1200    /**
1201     * Gets PluginSchema object for the given plugin interface name
1202     * and plugin name. Returns <code>null</code> if not present.
1203     */
1204    static PluginSchema getPluginSchema(String interfaceName,
1205        String pluginName) {
1206        Set plugins = getPluginSchemaNames(interfaceName);
1207        if (plugins.contains(pluginName)) {
1208            try {
1209                return (ssm.getPluginSchema(pluginName, interfaceName, null));
1210            } catch (Exception e) {
1211                PolicyManager.debug.error(
1212                        "Cannot get plugin schemas: " +
1213                        interfaceName + " for policy", e);
1214            }
1215        }
1216        return (null);
1217    }
1218
1219    /**
1220     * Gets the view bean URL given the plugin type 
1221     * and the plugin java class name
1222     *
1223     * @param pluginType  type of plugin such as Subject, Referral, Condition
1224     * @param pluginClassName name of java class name implementing the plugin
1225     *                        type
1226     *
1227     * @return view bean URL defined for pluginType with name pluginName
1228     */
1229    static String getViewBeanURL(String pluginType, String pluginClassName) {
1230        String viewBeanURL = null;
1231        if (pluginType != null) {
1232            Iterator items = PolicyManager.getPluginSchemaNames(
1233                    pluginType).iterator();
1234            while (items.hasNext()) {
1235                String pluginName = (String) items.next();
1236                PluginSchema ps = PolicyManager.getPluginSchema(pluginType, 
1237                        pluginName);
1238                if (pluginClassName.equals(ps.getClassName())) {
1239                    viewBeanURL = ps.getPropertiesViewBeanURL();
1240                    break;
1241                }
1242            }
1243        }
1244        return viewBeanURL;
1245    }
1246
1247    /** Gets a policy using policy cache. 
1248     * @param policyName policy name
1249     * @param useCache flag to indicate whether to use cache or not
1250     * @return the policy with the given policy name
1251     * @throws SSOException
1252     * @throws NoPermissionException
1253     * @throws InvalidFormatException
1254     * @throws PolicyException
1255     */
1256    Policy getPolicy(String policyName, boolean useCache) throws SSOException,
1257            NoPermissionException, InvalidFormatException, 
1258            NameNotFoundException,
1259            InvalidFormatException, PolicyException {
1260        Policy policy = null;
1261        if ( useCache ) {
1262            policy = policyCache.getPolicy(org, policyName);
1263        } else {
1264            policy = getPolicy(policyName);
1265        }
1266        return policy;
1267    }
1268
1269    ResourceIndexManager getResourceIndexManager() {
1270        return rim;
1271    }
1272
1273    private boolean validateResourceForPrefix(ServiceType resourceType, 
1274        String resourceName) throws PolicyException {
1275        Set<String> resourcePrefixes = getManagedResourceNames(
1276                resourceType.getName());
1277        return validateResourceForPrefix(resourceType,
1278            resourcePrefixes, resourceName);
1279    }
1280
1281    private boolean validateResourceForPrefixE(
1282        String realm,
1283        String serviceName,
1284        Set<String> resourcePrefixes,
1285        String resourceName) throws PolicyException, EntitlementException {
1286
1287        String realmName = (DN.isDN(realm)) ?
1288            DNMapper.orgNameToRealmName(realm) :realm;
1289
1290        Application appl = ApplicationManager.getApplication(
1291            PrivilegeManager.superAdminSubject, realmName, serviceName);
1292        com.sun.identity.entitlement.interfaces.ResourceName resComp = appl.
1293            getResourceComparator();
1294        resourceName = resComp.canonicalize(resourceName);
1295
1296        for (String prefix : resourcePrefixes) {
1297            boolean interpretWildCard = true;
1298            com.sun.identity.entitlement.ResourceMatch resMatch =
1299                resComp.compare(resourceName,
1300                resComp.canonicalize(prefix), interpretWildCard);
1301            if ( resMatch.equals(
1302                com.sun.identity.entitlement.ResourceMatch.SUPER_RESOURCE_MATCH)
1303                || resMatch.equals(
1304                    com.sun.identity.entitlement.ResourceMatch.WILDCARD_MATCH)
1305                || resMatch.equals(
1306                    com.sun.identity.entitlement.ResourceMatch.EXACT_MATCH) ) {
1307                return true;
1308            }
1309
1310        }
1311        return false;
1312    }
1313
1314    private boolean validateResourceForPrefix(
1315        ServiceType resourceType,
1316        Set<String> resourcePrefixes,
1317        String resourceName) throws PolicyException {
1318
1319        for (String prefix : resourcePrefixes) {
1320            boolean interpretWildCard = true;
1321            ResourceMatch resMatch = resourceType.compare(resourceName, prefix,
1322                    interpretWildCard);
1323            if ( resMatch.equals(ResourceMatch.SUPER_RESOURCE_MATCH)
1324                        || resMatch.equals(ResourceMatch.WILDCARD_MATCH)
1325                        || resMatch.equals(ResourceMatch.EXACT_MATCH) ) {
1326                return true;
1327            }
1328
1329        }
1330        return false;
1331    }
1332
1333    private void validateForResourcePrefix(Policy policy)
1334                throws SSOException, PolicyException {
1335        if (isMigratedToEntitlementService()) {
1336            validateForResourcePrefixE(policy);
1337        } else {
1338            validateForResourcePrefixO(policy);
1339        }
1340    }
1341
1342    private void validateForResourcePrefixE(Policy policy)
1343        throws SSOException, PolicyException {
1344        DN orgDN = new DN(org);
1345        DN baseDN = new DN(ServiceManager.getBaseDN());
1346
1347        if (!orgDN.equals(baseDN) && !orgDN.equals(delegationRealm)) {
1348            String realm = DNMapper.orgNameToRealmName(getOrganizationDN());
1349            Iterator ruleNames = policy.getRuleNames().iterator();
1350            while (ruleNames.hasNext()) {
1351                try {
1352                    String ruleName = (String) ruleNames.next();
1353                    Rule rule = (Rule) policy.getRule(ruleName);
1354                    String serviceTypeName = rule.getServiceTypeName();
1355                    String ruleResource = rule.getResourceName();
1356                    // Make sure adminSubject has been set before using
1357                    if (adminSubject == null) {
1358                       initialise();
1359                    }
1360                    Set<String> referredResources = ApplicationManager.
1361                        getReferredResources(adminSubject,
1362                        realm, serviceTypeName);
1363                    if ((referredResources == null) || referredResources.
1364                        isEmpty()) {
1365                        String[] objs = {org};
1366                        throw new PolicyException(ResBundleUtils.rbName,
1367                            "no_referral_can_not_create_policy", objs, null);
1368                    }
1369                    ServiceType resourceType = getServiceTypeManager().
1370                        getServiceType(serviceTypeName);
1371
1372                    if (!validateResourceForPrefixE(realm, serviceTypeName,
1373                        referredResources, ruleResource)) {
1374                        String[] objs = {ruleResource, resourceType.getName()};
1375                        throw new PolicyException(ResBundleUtils.rbName,
1376                            "resource_name_not_permitted_by_prefix_names", objs,
1377                            null);
1378                    }
1379                } catch (EntitlementException ex) {
1380                    String[] objs = {org};
1381                    throw new PolicyException(ResBundleUtils.rbName,
1382                        "no_referral_can_not_create_policy", objs, null);
1383                }
1384            }
1385        }
1386    }
1387
1388    private void validateForResourcePrefixO(Policy policy)
1389            throws SSOException, PolicyException {
1390        DN orgDN = new DN(org);
1391        DN baseDN = new DN(ServiceManager.getBaseDN());
1392        Set prefixes = getManagedResourceNames();
1393        if (!orgDN.equals(baseDN) && !orgDN.equals(delegationRealm)
1394             && ((prefixes == null ) || prefixes.isEmpty()) ) {
1395                String[] objs = {org};
1396                throw new PolicyException(
1397                        ResBundleUtils.rbName,
1398                        "no_referral_can_not_create_policy", objs, null);
1399        }
1400        Iterator ruleNames = policy.getRuleNames().iterator();
1401        while ( ruleNames.hasNext() ) {
1402            String ruleName = (String) ruleNames.next();
1403            Rule rule = (Rule) policy.getRule(ruleName);
1404            String serviceTypeName = rule.getServiceTypeName();
1405            ServiceType resourceType = getServiceTypeManager()
1406                    .getServiceType(serviceTypeName);
1407            String ruleResource = rule.getResourceName();
1408            boolean validResource = true;
1409            if (!orgDN.equals(baseDN) && !orgDN.equals(delegationRealm)) {
1410                validResource = validateResourceForPrefix(resourceType, 
1411                        ruleResource);
1412            }
1413            if (!validResource) {
1414                String[] objs = { ruleResource, resourceType.getName() };
1415                throw new PolicyException(
1416                        ResBundleUtils.rbName,
1417                        "resource_name_not_permitted_by_prefix_names",
1418                        objs, null);
1419            }
1420        }
1421
1422    }
1423
1424    private void validateReferrals(Policy policy) 
1425            throws SSOException, PolicyException {
1426        Set candidateOrgs = policy.getReferredToOrganizations();
1427        if ( candidateOrgs.contains(org.toLowerCase()) ) {
1428            String[] objs = { org };
1429            throw new PolicyException(
1430                    ResBundleUtils.rbName,
1431                    "invalid_referral_pointing_to_self",
1432                    objs, null);
1433        }
1434        Iterator iter = candidateOrgs.iterator();
1435        while ( iter.hasNext() ) {
1436            String candidateOrg = (String) iter.next();
1437
1438            /* 
1439             * check org orgName exisits - would result in
1440             * PolicyException if the orgName does not exist 
1441             */
1442            verifyOrgName(candidateOrg);
1443        }
1444
1445    }
1446
1447    void saveRealmSubjects(Subjects subjects) 
1448            throws PolicyException, SSOException {
1449        ServiceConfig realmSubjects = createOrGetPolicyConfig(
1450            REALM_SUBJECTS, REALM_SUBJECTS, scm, org);
1451        Map attributes = new HashMap(1);
1452        Set values = new HashSet(1);
1453        String subjectsXML = subjects.toXML();
1454        values.add(subjectsXML);
1455        attributes.put(XML_REALM_SUBJECTS, values);
1456        try {
1457            realmSubjects.setAttributes(attributes);
1458        } catch (SMSException se) {
1459            debug.error("SMS error in saving realm subjects " 
1460                    + " in organization: " + org);
1461            // Check for permission exception
1462            String objs[] = { org };
1463            if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
1464                throw new PolicyException(ResBundleUtils.rbName,
1465                    "insufficient_access_rights", null, se);
1466            } else {
1467                // Throw generic policy exception
1468                throw new PolicyException(ResBundleUtils.rbName,
1469                    "unable_to_save_realm_subjects", objs, se);
1470            }
1471        }
1472        if (debug.messageEnabled()) {
1473            debug.message("saved realm subjects:" + subjectsXML);
1474        }
1475    }
1476
1477    Subjects readRealmSubjects() throws PolicyException, SSOException {
1478        Subjects subjects = null;
1479        ServiceConfig realmSubjects = createOrGetPolicyConfig(
1480                REALM_SUBJECTS, REALM_SUBJECTS, scm, org);
1481        Set values = null;
1482        values = (Set)realmSubjects.getAttributes().get(XML_REALM_SUBJECTS);
1483        if ((values != null) && !values.isEmpty()) {
1484            String xmlSubjects = (String)values.iterator().next();
1485            Document doc = null;
1486            try {
1487                doc = XMLUtils.getXMLDocument(
1488                    new ByteArrayInputStream(xmlSubjects.getBytes("UTF8")));
1489            } catch (Exception xmle) {
1490                debug.error("XML parsing error for realmSubjects: " 
1491                        + " in organization: " + org);
1492                // throw generic policy exception
1493                throw (new PolicyException(xmle));
1494            }
1495            Node subjectsNode = XMLUtils.getRootNode(doc, SUBJECTS_POLICY);
1496            if (subjectsNode == null) {
1497                debug.error("invalid xmlRealmSubjects blob " 
1498                        +    " in organization: " + org);
1499                throw (new InvalidFormatException(ResBundleUtils.rbName,
1500                    "invalid_xml_realmsubjects_root_node", null, 
1501                    org, PolicyException.POLICY));
1502            }
1503            subjects = new Subjects(this, subjectsNode);
1504        } else {
1505            subjects = new Subjects();
1506        }
1507        if (debug.messageEnabled()) {
1508            debug.message("read realm subjects:" + subjects.toXML());
1509        }
1510        subjects.setPolicyConfig(getPolicyConfig());
1511        return subjects;
1512    }
1513
1514    /**
1515     * Gets the set of policies that use the realm subject
1516     * @param subjectName name of the realm subject to check for
1517     * @return a <code>Set</code> of <code>Policy</code> objects 
1518     *        that use the  realm subject
1519     */
1520    public Set getPoliciesUsingRealmSubject(String subjectName) 
1521            throws PolicyException, SSOException {
1522        Set policies = new HashSet();
1523        Set policyNames = getPolicyNames();
1524        for (Iterator policyIter = policyNames.iterator(); 
1525                policyIter.hasNext();) {
1526            String policyName = (String)policyIter.next();
1527            Policy policy = getPolicy(policyName);
1528            Set subjectNames = policy.getSubjectNames();
1529            if (subjectNames.contains(subjectName)) {
1530                Subject subject = policy.getSubject(subjectName);
1531                if (subject instanceof SharedSubject) {
1532                    policies.add(policy);
1533                }
1534            }
1535        }
1536        return policies;
1537    }
1538
1539    Policy getPolicyUsingRealmSubject(String subjectName) 
1540            throws PolicyException, SSOException {
1541        Policy policy = null;
1542        Set policyNames = getPolicyNames();
1543        for (Iterator policyIter = policyNames.iterator(); 
1544                policyIter.hasNext();) {
1545            String policyName = (String)policyIter.next();
1546            Policy p = getPolicy(policyName);
1547            Set subjectNames = p.getSubjectNames();
1548            if (subjectNames.contains(subjectName)) {
1549                Subject subject = p.getSubject(subjectName);
1550                if (subject instanceof SharedSubject) {
1551                    policy = p;
1552                    break;
1553                }
1554            }
1555        }
1556        return policy;
1557    }
1558
1559    private Set getOrgAliasMappedResourceNames() 
1560            throws PolicyException {
1561        if (debug.messageEnabled()) {
1562            debug.message("PolicyManager.getOrgAliasMappedResourceNames(): "
1563                    + " entering:orgName = " + org);
1564        }
1565        Set managedResourceNames = new HashSet(3);
1566        if (ocm == null) {
1567            try {
1568                ocm = new OrganizationConfigManager(token, givenOrgName);
1569            } catch (SMSException sme) {
1570                String[] objs = { org };
1571                throw (new PolicyException(ResBundleUtils.rbName,
1572                        "unable_to_get_org_config_manager_for_org", 
1573                        objs, sme));
1574            }
1575        }
1576
1577        Set orgAliases = null;
1578        try {
1579            Map orgAttributes = ocm.getAttributes(ID_REPO_SERVICE);
1580            orgAliases 
1581                    = (Set)orgAttributes.get(ORG_ALIAS);
1582            if (debug.messageEnabled()) {
1583                debug.message("PolicyManager.getOrgAliasMappedResourceNames(): "
1584                        + " orgName = " + org
1585                        + ":orgAliases=" + orgAliases);
1586            }
1587        } catch (SMSException sme) {
1588            String[] objs = { org };
1589            throw (new PolicyException(ResBundleUtils.rbName,
1590                    "unable_to_get_org_alias_for_org", objs, sme));
1591        }
1592        if (orgAliases != null) {
1593            Iterator iter = orgAliases.iterator();
1594            while (iter.hasNext()) {
1595                String orgAlias = (String)iter.next();
1596                managedResourceNames.add(ORG_ALIAS_URL_HTTP_PREFIX 
1597                        + orgAlias.trim() 
1598                        + ORG_ALIAS_URL_SUFFIX);
1599                managedResourceNames.add(ORG_ALIAS_URL_HTTPS_PREFIX 
1600                        + orgAlias.trim() 
1601                        + ORG_ALIAS_URL_SUFFIX);
1602            }
1603        }
1604        if (debug.messageEnabled()) {
1605            debug.message("PolicyManager.getOrgAliasMappedResourceNames(): "
1606                    + " returning: orgName = " + org
1607                    + ":orgAliases=" + orgAliases
1608                    + ":managedResourceNames=" + managedResourceNames);
1609        }
1610        return managedResourceNames;
1611    }
1612
1613    public Set getManagedResourceNames(String serviceName)
1614            throws PolicyException {
1615        return (isMigratedToEntitlementService()) ?
1616            getManagedResourceNamesE(serviceName) :
1617            getManagedResourceNamesO(serviceName);
1618    }
1619
1620    public Set getManagedResourceNamesE(String serviceName) {
1621        try {
1622            Application appl = ApplicationManager.getApplication(
1623                PrivilegeManager.superAdminSubject, org, serviceName);
1624            return (appl == null) ? Collections.EMPTY_SET : appl.getResources();
1625        } catch (EntitlementException ex) {
1626            debug.error("PolicyManager.getManagedResourceNamesE", ex);
1627            return Collections.EMPTY_SET;
1628        }
1629    }
1630
1631
1632    public Set getManagedResourceNamesO(String serviceName)
1633            throws PolicyException {
1634        Set managedResourceNames = new HashSet();
1635        Set delegatedResourceNames = rm.getManagedResourceNames(serviceName);
1636        if (delegatedResourceNames != null) {
1637            managedResourceNames.addAll(delegatedResourceNames);
1638        }
1639        if (WEB_AGENT_SERVICE.equalsIgnoreCase(serviceName) 
1640                && PolicyConfig.orgAliasMappedResourcesEnabled() ) {
1641            managedResourceNames.addAll(getOrgAliasMappedResourceNames());
1642        }
1643        if (debug.messageEnabled()) {
1644            debug.message("PolicyManager.getManagedResourceNames(): "
1645                    + " returning: orgName = " + org
1646                    + ":serviceName=" + serviceName
1647                    + ":managedResourceNames=" + managedResourceNames);
1648        }
1649        return managedResourceNames;
1650    }
1651
1652    public Set getManagedResourceNames() 
1653            throws PolicyException {
1654        Set managedResourceNames = rm.getManagedResourceNames();
1655        if ((managedResourceNames == null) 
1656                || (managedResourceNames == Collections.EMPTY_SET)) {
1657                    managedResourceNames = new HashSet();
1658        }
1659        managedResourceNames.addAll(getOrgAliasMappedResourceNames());
1660        if (debug.messageEnabled()) {
1661            debug.message("PolicyManager.getManagedResourceNames(): "
1662                    + " returning: orgName = " + org
1663                    + ":managedResourceNames=" + managedResourceNames);
1664        }
1665        return managedResourceNames;
1666    }
1667
1668    String getOrgAliasWithResource(String resourceName) 
1669            throws PolicyException, SSOException {
1670        if (debug.messageEnabled()) {
1671            debug.message("PolicyManager.getOrgAliasWithResource(): "
1672                    + " orgName = " + org
1673                    + ", resourceName = " + resourceName);
1674        }
1675        if (resourceName == null) {
1676            return null;
1677        }
1678        String orgAlias = null;
1679        try {
1680            URL url = new URL(resourceName);
1681            orgAlias = url.getHost();
1682        } catch (MalformedURLException mfe) {
1683            String[] objs = { resourceName };
1684            if (debug.messageEnabled()) {
1685                debug.message("PolicyManager.getOrgAliasWithResource(): "
1686                        + " orgName = " + org
1687                        + ", resourceName = " + resourceName
1688                        + " is invalid URL, no org alias mapping can be found");
1689            }
1690        }
1691        return orgAlias;
1692    }
1693
1694    String getOrgNameWithAlias(String orgAlias) 
1695            throws PolicyException, SSOException {
1696        String aliasMappedOrg = null;
1697        try {
1698            aliasMappedOrg = IdUtils.getOrganization(token, orgAlias);
1699        } catch (IdRepoException re) {
1700            //idRepo throws exception if there is no mapping
1701            if (debug.messageEnabled()) {
1702                debug.message("PolicyManager.getOrgNameWithAlias(): "
1703                        + " can not get orgName for orgAlias = " + orgAlias);
1704            }
1705        }
1706        if (debug.messageEnabled()) {
1707            debug.message("PolicyManager.getOrgNameWithAlias(): "
1708                    + " orgAlias = " + orgAlias
1709                    + ", mapped org = " + aliasMappedOrg);
1710        }
1711        return aliasMappedOrg;
1712    }
1713
1714    public boolean canCreatePolicies(Set<String> services) 
1715        throws EntitlementException {
1716        String realm = DNMapper.orgNameToRealmName(getOrganizationDN());
1717        if (realm.equals("/")) {
1718            return true;
1719        }
1720
1721        if (isMigratedToEntitlementService()) {
1722            for (String s : services) {
1723                Set<String> res = ApplicationManager.getReferredResources(
1724                    adminSubject, realm, s);
1725                if ((res != null) && !res.isEmpty()) {
1726                    return true;
1727                }
1728            }
1729            return false;
1730        } else {
1731            return canCreateNewResource(services) ||
1732                hasReferredResources();
1733        }
1734    }
1735    
1736    private boolean canCreateNewResource(Set<String> services) {
1737        boolean can = false;
1738        ResourceManager resMgr = getResourceManager();
1739
1740        if (resMgr != null) {
1741            if ((services != null) && !services.isEmpty()) {
1742                for (Iterator i = services.iterator(); (i.hasNext() && !can);) {
1743                    String svcName = (String)i.next();
1744                    try {
1745                        can = resMgr.canCreateNewResource(svcName);
1746                    } catch (PolicyException  e) {
1747                        debug.warning("PolicyManager.canCreateNewResource",e);
1748                    }
1749                }
1750            }
1751        }
1752
1753        return can;
1754    }
1755
1756    private boolean hasReferredResources() {
1757        boolean hasPrefixes = false;
1758        try {
1759            Set prefixes = getManagedResourceNames();
1760            hasPrefixes = (prefixes != null) && !prefixes.isEmpty();
1761        } catch (PolicyException e) {
1762            debug.warning("PolicyManager.hasReferredResources", e);
1763        }
1764        return hasPrefixes;
1765    }
1766
1767    static boolean isMigratedToEntitlementService() {
1768
1769        // This must be non-null for the migratedToEntitlementService to have been
1770        // calculated correctly
1771        if (adminSubject == null) {
1772            initialise();
1773        }
1774
1775        return migratedToEntitlementService;
1776    }
1777
1778    private static void initialise() {
1779
1780        // Do this outside of a static block to avoid issues on container shutdown/restart
1781        adminSubject = SubjectUtils.createSubject(
1782                (SSOToken)AccessController.doPrivileged(AdminTokenAction.getInstance()));
1783        EntitlementConfiguration ec =
1784                EntitlementConfiguration.getInstance(adminSubject, "/");
1785        migratedToEntitlementService = ec.migratedToEntitlementService();
1786    }
1787
1788    public boolean canCreateNewResource(String svcTypeName) {
1789        boolean can = false;
1790        if (isMigratedToEntitlementService()) {
1791            ResourceManager resMgr = getResourceManager();
1792            if (resMgr != null) {
1793                try {
1794                    can = resMgr.canCreateNewResource(svcTypeName);
1795                } catch (PolicyException e) {
1796                    debug.warning("PolicyManager.canCreateNewResource",e);
1797                }
1798            }
1799        } else {
1800            String realm = DNMapper.orgNameToRealmName(getOrganizationDN());
1801            can = realm.equals("/");
1802        }
1803        return can;
1804    }
1805}