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