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-2016 ForgeRock AS.
028 */
029
030package com.sun.identity.policy;
031
032import static org.forgerock.openam.entitlement.PolicyConstants.SUPER_ADMIN_SUBJECT;
033import static org.forgerock.openam.entitlement.utils.EntitlementUtils.getApplicationService;
034
035import java.io.ByteArrayInputStream;
036import java.net.MalformedURLException;
037import java.net.URL;
038import java.security.AccessController;
039import java.util.Collections;
040import java.util.Date;
041import java.util.HashMap;
042import java.util.HashSet;
043import java.util.Iterator;
044import java.util.Map;
045import java.util.Set;
046import java.util.concurrent.locks.Lock;
047
048import org.forgerock.openam.ldap.LDAPUtils;
049import org.forgerock.openam.shared.concurrency.LockFactory;
050import org.forgerock.openam.utils.Time;
051import org.forgerock.opendj.ldap.DN;
052import org.w3c.dom.Document;
053import org.w3c.dom.Node;
054
055import com.iplanet.am.util.SystemProperties;
056import com.iplanet.sso.SSOException;
057import com.iplanet.sso.SSOToken;
058import com.iplanet.sso.SSOTokenManager;
059import com.sun.identity.entitlement.Application;
060import com.sun.identity.entitlement.EntitlementException;
061import com.sun.identity.entitlement.IPrivilege;
062import com.sun.identity.entitlement.PrivilegeIndexStore;
063import com.sun.identity.entitlement.opensso.PrivilegeUtils;
064import com.sun.identity.entitlement.opensso.SubjectUtils;
065import com.sun.identity.idm.IdRepoException;
066import com.sun.identity.idm.IdUtils;
067import com.sun.identity.policy.interfaces.Subject;
068import com.sun.identity.security.AdminTokenAction;
069import com.sun.identity.shared.debug.Debug;
070import com.sun.identity.shared.xml.XMLUtils;
071import com.sun.identity.sm.DNMapper;
072import com.sun.identity.sm.OrganizationConfigManager;
073import com.sun.identity.sm.PluginSchema;
074import com.sun.identity.sm.SMSEntry;
075import com.sun.identity.sm.SMSException;
076import com.sun.identity.sm.ServiceAlreadyExistsException;
077import com.sun.identity.sm.ServiceConfig;
078import com.sun.identity.sm.ServiceConfigManager;
079import com.sun.identity.sm.ServiceListener;
080import com.sun.identity.sm.ServiceManager;
081import com.sun.identity.sm.ServiceNotFoundException;
082import com.sun.identity.sm.ServiceSchemaManager;
083
084/**
085 * The <code>PolicyManager</code> class manages policies
086 * for a specific organization, sub organization or a container.
087 * This class is the
088 * starting point for policy management, and provides methods to
089 * create/modify/delete policies.
090 * <p>It is a final class
091 * and hence cannot be further extended. The methods in this class
092 * works directly with the backend datastore (usually a
093 * directory server) to store and manage policies. Hence, user
094 * of this class must have valid <code>SSOToken</code>
095 * and privileges to the backend datastore.
096 *
097 * @supported.api
098 * @deprecated since 12.0.0
099 */
100@Deprecated
101public final class PolicyManager {
102
103    /**
104     * The service name for Policy component.
105     * @supported.api
106     */
107    public static final String POLICY_SERVICE_NAME = "iPlanetAMPolicyService";
108    public static final String POLICY_DEBUG_NAME = "amPolicy";
109    
110    /**
111     * The key for the plugins to get the organization name.
112     * @supported.api
113     */
114    public static final String ORGANIZATION_NAME = "OrganizationName";
115    public static final String DELEGATION_REALM = 
116                      "/sunamhiddenrealmdelegationservicepermissions";
117
118    public static final String NAMED_POLICY = "Policies";
119    static final String REALM_SUBJECTS = "RealmSubjects";
120    static final String XML_REALM_SUBJECTS = "xmlRealmSubjects";
121    private static final String NAMED_POLICY_ID = "NamedPolicy";
122    static final String RESOURCES_POLICY = "Resources";
123    static final String RESOURCES_POLICY_ID = "ServiceType";
124    private static final String SUBJECTS_POLICY = "Subjects";
125    static final String SUBJECT_POLICY = "Subject";
126    static final String REALM_SUBJECT_POLICY = "RealmSubject";
127    static final String CONDITION_POLICY = "Condition";
128    static final String RESP_PROVIDER_POLICY = "ResponseProvider";
129    static final String REFERRAL_POLICY = "Referral";
130    static final String REFERRALS_POLICY = "Referrals";
131    private static final String POLICY_XML = "xmlpolicy";
132    static final String POLICY_VERSION = "1.0";
133
134    public static final String POLICY_ROOT_NODE = "Policy";
135    static final String POLICY_RULE_NODE = "Rule";
136    static final String POLICY_SUBJECTS_NODE = "Subjects";
137    static final String POLICY_CONDITIONS_NODE = "Conditions";
138    static final String POLICY_RESP_PROVIDERS_NODE = "ResponseProviders";
139    static final String POLICY_REFERRALS_NODE = "Referrals";
140    static final String POLICY_RULE_SERVICE_NODE = "ServiceName";
141    static final String POLICY_RULE_RESOURCE_NODE = "ResourceName";
142    static final String POLICY_RULE_EXCLUDED_RESOURCE_NODE =
143        "ExcludedResourceName";
144    static final String POLICY_RULE_APPLICATION_NAME_NODE = "ApplicationName";
145    static final String ATTR_VALUE_PAIR_NODE = "AttributeValuePair";
146    static final String ATTR_NODE = "Attribute";
147    static final String ATTR_VALUE_NODE = "Value";
148    static final String NAME_ATTRIBUTE = "name";
149    static final String TYPE_ATTRIBUTE = "type";
150    static final String DESCRIPTION_ATTRIBUTE = "description";
151    static final String CREATED_BY_ATTRIBUTE = "createdby";
152    static final String CREATION_DATE_ATTRIBUTE = "creationdate";
153    static final String LAST_MODIFIED_BY_ATTRIBUTE = "lastmodifiedby";
154    static final String LAST_MODIFIED_DATE_ATTRIBUTE = "lastmodifieddate";
155    static final String PRIORITY_ATTRIBUTE = "priority";
156    static final String STATUS_ATTRIBUTE = "priority";
157    static final String STATUS_ACTIVE = "active";
158    static final String STATUS_INACTIVE = "inactive";
159    static final String SERVICE_TYPE_NAME_ATTRIBUTE = "serviceName";
160
161    static final String POLICY_INDEX_ROOT_NODE = "PolicyCrossReferences";
162    static final String POLICY_INDEX_ROOT_NODE_NAME_ATTR = "name";
163    static final String POLICY_INDEX_ROOT_NODE_TYPE_ATTR = "type";
164    static final String
165        POLICY_INDEX_ROOT_NODE_TYPE_ATTR_RESOURCES_VALUE = "Resources";
166    static final String POLICY_INDEX_REFERENCE_NODE = "Reference";
167    static final String POLICY_INDEX_REFERENCE_NODE_NAME_ATTR = "name";
168    static final String POLICY_INDEX_POLICYNAME_NODE = "PolicyName";
169    static final String POLICY_INDEX_POLICYNAME_NODE_NAME_ATTR = "name";
170    static final long DEFAULT_SUBJECTS_RESULT_TTL = 10 * 60 * 1000;
171
172    static final String WEB_AGENT_SERVICE = "iPlanetAMWebAgentService";
173    public static final String ID_REPO_SERVICE = "sunIdentityRepositoryService";
174    public static final String ORG_ALIAS = "sunOrganizationAliases";
175    public static final String ORG_ALIAS_URL_HTTP_PREFIX = "http://";
176    public static final String ORG_ALIAS_URL_HTTPS_PREFIX = "https://";
177    public static final String ORG_ALIAS_URL_SUFFIX = ":*";
178
179    private String org = "/";
180    private String givenOrgName = "";
181    private ServiceConfigManager scm;
182    private OrganizationConfigManager ocm;
183    private ResourceManager rm;
184    private ServiceTypeManager svtm;
185    private SubjectTypeManager stm;
186    private ConditionTypeManager ctm;
187    private ResponseProviderTypeManager rpm;
188    private ReferralTypeManager rtm;
189    private PolicyCache policyCache;
190    private ResourceIndexManager rim;
191    private final LockFactory<String> lockFactory;
192
193    private static ServiceSchemaManager ssm;
194    private static javax.security.auth.Subject adminSubject;
195
196    SSOToken token;
197
198    // Can be shared by classes
199    static Debug debug = Debug.getInstance(POLICY_DEBUG_NAME);
200    static DN delegationRealm = DN.valueOf(DNMapper.orgNameToDN(DELEGATION_REALM));
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        PolicyManager.initAdminSubject();
573
574        //TODO: handle non DNs/
575        realmName = LDAPUtils.formatToRFC(realmName);
576        String subjectRealm = policy.getSubjectRealm();
577        String[] realmNames = {realmName, subjectRealm};
578        if ((subjectRealm != null) && !subjectRealm.equals(realmName)) {
579            if (debug.messageEnabled()) {
580                debug.message("Can not add policy in realm :"
581                        + realmName + ", policy has realm subjects "
582                        + " from realm : " + subjectRealm);
583            }
584
585            //TODO : add logging?
586
587            throw (new InvalidFormatException(ResBundleUtils.rbName,
588                "policy_realm_does_not_match", realmNames, null, realmName, 
589                PolicyException.POLICY));
590        }
591        validateForResourcePrefix(policy);
592        validateReferrals(policy);
593
594        String testCreatedBy = policy.getCreatedBy();
595        //testCreatedBy is set if we are doing policy replaced.
596        if ((testCreatedBy == null) || (testCreatedBy.length() == 0)) {
597            Date creationDate = Time.newDate();
598            policy.setCreatedBy(token.getPrincipal().getName());
599            policy.setCreationDate(creationDate.getTime());
600            policy.setLastModifiedBy(token.getPrincipal().getName());
601            policy.setLastModifiedDate(creationDate.getTime());
602        }
603
604        // Construct the named policy
605        String policyXml = policy.toXML();
606        Map attrs = new HashMap();
607        Set set = new HashSet();
608        set.add(policyXml);
609        attrs.put(POLICY_XML, set);
610
611        // Get(create if necessary) ou=policies entry
612        ServiceConfig namedPolicy = createOrGetPolicyConfig(
613            NAMED_POLICY, NAMED_POLICY, scm, org);
614        try {
615            //create the policy entry
616            namedPolicy.addSubConfig(policy.getName(),
617                NAMED_POLICY_ID, 0, attrs);
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        } catch (EntitlementException e) {
626            String[] objs = { policy.getName(), org };
627            throw (new PolicyException(ResBundleUtils.rbName, 
628                "unable_to_add_policy", objs, e)); 
629        } catch (ServiceAlreadyExistsException e) {
630            String[] objs = { policy.getName(), org };
631            if (PolicyUtils.logStatus) {
632                 PolicyUtils.logErrorMessage(
633                    "POLICY_ALREADY_EXISTS_IN_REALM", objs, token);
634            }
635            throw (new NameAlreadyExistsException(ResBundleUtils.rbName,
636                "policy_already_exists_in_org", objs, policy.getName(), 
637                PolicyException.POLICY));
638        } catch (SMSException se) {
639            String[] objs = { policy.getName(), org };
640            if (PolicyUtils.logStatus) {
641                 PolicyUtils.logErrorMessage("UNABLE_TO_ADD_POLICY", objs, 
642                    token);
643            }
644            debug.error("SMS error in add policy: " +
645                    policy.getName() + " for org: " + org, se);
646
647            // Check for permission exception
648            if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
649                throw (new NoPermissionException(ResBundleUtils.rbName,
650                    "insufficient_access_rights", null));
651            } else {
652                // Throw generic policy exception
653                throw (new PolicyException(ResBundleUtils.rbName, 
654                        "unable_to_add_policy",
655                        objs, se));
656            }
657        }
658        if (PolicyUtils.logStatus) {
659            String[] objs = { policy.getName(), org };
660            PolicyUtils.logAccessMessage("POLICY_CREATE_SUCCESS", objs, token);
661        }
662    }
663
664    /**
665     * Replaces a policy object  in the data store with the same policy name
666     *
667     * @param policy policy object to be added to the organization
668     *
669     * @throws SSOException invalid or expired single-sign-on token
670     * @throws NoPermissionException user does not have sufficient
671     * privileges to replace policy
672     * @throws NameNotFoundException policy with the same name does
673     * not exist.
674     * @throws InvalidFormatException the provide policy from the
675     * data store has been corrupted or does not have a valid format
676     * @throws PolicyException for any other abnormal condition.
677     *
678     * @supported.api
679     */
680    public void replacePolicy(Policy policy) throws SSOException,
681        NameNotFoundException, NoPermissionException,
682        InvalidFormatException, PolicyException {
683
684        PolicyManager.initAdminSubject();
685        String realm = getOrganizationDN();
686        String subjectRealm = policy.getSubjectRealm();
687        String[] realmNames = {realm, subjectRealm};
688        if ((subjectRealm != null) && !subjectRealm.equals(realm)) {
689
690            if (debug.messageEnabled()) {
691                debug.message("Can not replace policy in realm :"
692                        + realm + ", policy has realm subjects "
693                        + " from realm : " + subjectRealm);
694            }
695
696            throw (new InvalidFormatException(ResBundleUtils.rbName,
697                "policy_realm_does_not_match", realmNames, null, realm,
698                PolicyException.POLICY));
699        }
700
701        policy.setLastModifiedBy(token.getPrincipal().getName());
702        Date lastModifiedDate = Time.newDate();
703        policy.setLastModifiedDate(lastModifiedDate.getTime());
704
705        // Construct the named policy
706        String policyXml = policy.toXML();
707        Map attrs = new HashMap();
708        Set set = new HashSet();
709        set.add(policyXml);
710        attrs.put(POLICY_XML, set);
711
712        String name = null;
713        // Get(create if necessary) ou=policies entry
714        ServiceConfig namedPolicy = createOrGetPolicyConfig(
715            NAMED_POLICY, NAMED_POLICY, scm, org);
716        try {
717            String policyName = policy.getName();
718            String oldPolicyName = policy.getOriginalName();
719            ServiceConfig policyEntry = namedPolicy.getSubConfig(policyName);
720            ServiceConfig oldPolicyEntry = null;
721            if ( oldPolicyName != null ) {
722                oldPolicyEntry = namedPolicy.getSubConfig(oldPolicyName);
723                name = oldPolicyName;
724            } else {
725                name = policy.getName();
726            }
727            if ( policyEntry == null ) {
728                if ( oldPolicyEntry != null ) {
729                    removePolicy(oldPolicyName);
730                    addPolicy(policy);
731                    // reset the policy name
732                    // TODO: need to think this through
733                    policy.resetOriginalName();
734                } else {
735                    // neither the new policy nor the old policy is present
736                    String objs[] = { policy.getName(), org };
737                    throw (new NameNotFoundException(ResBundleUtils.rbName,
738                            "policy_not_found_in_organization", objs,
739                         policy.getName(), PolicyException.POLICY));
740                }
741            } else { //newPolicy exisits
742                String[] objs = { policy.getName(), org };
743                if((oldPolicyName != null) && 
744                            !policy.getName().equalsIgnoreCase(oldPolicyName)) {
745                    if (PolicyUtils.logStatus) {
746                        PolicyUtils.logErrorMessage(
747                            "DID_NOT_REPLACE_POLICY", 
748                            objs, token);
749                    }
750                    throw (new NameAlreadyExistsException(ResBundleUtils.rbName,
751                        "policy_already_exists_in_org", objs, policy.getName(), 
752                        PolicyException.POLICY));
753                }
754
755                Policy oldPolicy = getPolicy(policy.getName());
756                validateForResourcePrefix(policy);
757                validateReferrals(policy);
758                policyEntry.setAttributes(attrs);
759                if (oldPolicy != null) {
760                    // Acquire lock to ensure atomicity when updating policy.
761                    Lock lock = lockFactory.acquireLock(policyName);
762
763                    try {
764                        lock.lock();
765                        PrivilegeIndexStore pis = PrivilegeIndexStore.getInstance(
766                                SubjectUtils.createSubject(token), realm);
767                        pis.delete(PrivilegeUtils.policyToPrivileges(oldPolicy));
768                        pis.add(PrivilegeUtils.policyToPrivileges(policy));
769                    } finally {
770                        lock.unlock();
771                    }
772
773                    policyCache.sendPolicyChangeNotification(oldPolicy, policy, ServiceListener.MODIFIED);
774                }
775            }
776        } catch (EntitlementException e) {
777            String[] objs = { name, org };
778            throw (new PolicyException(ResBundleUtils.rbName,
779                "unable_to_replace_policy", objs, e));
780        } catch (SMSException se) {
781            String[] objs = { name, org };
782            if (PolicyUtils.logStatus) {
783                PolicyUtils.logErrorMessage("UNABLE_TO_REPLACE_POLICY", objs, 
784                    token);
785            }
786            debug.error("SMS error in replacing policy: " +
787                    policy.getOriginalName() + " for org: " + org, se);
788            // Check for permission exception
789            if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
790                throw (new NoPermissionException(ResBundleUtils.rbName,
791                    "insufficient_access_rights", null));
792            } else {
793                // Throw generic policy exception
794                throw (new PolicyException(ResBundleUtils.rbName, 
795                    "unable_to_replace_policy", objs, se));
796            }
797        }
798        if (PolicyUtils.logStatus) {
799            String[] objs = { name, org };
800            PolicyUtils.logAccessMessage("POLICY_MODIFY_SUCCESS", objs, token);
801        }
802    }
803
804    /**
805     * Deletes a policy in the organization with the given name.
806     *
807     * @param policyName name of the policy to be deleted
808     *
809     * @throws SSOException invalid or expired single-sign-on token
810     * @throws NoPermissionException user does not have sufficient
811     * privileges to remove policies
812     * @throws PolicyException for any other abnormal condition
813     *
814     * @supported.api
815     */
816    public void removePolicy(String policyName) throws
817        SSOException, NoPermissionException, PolicyException {
818        // Check if name is valid
819        if (policyName == null) {
820            if (debug.warningEnabled()) {
821                debug.warning("In PolicyManager::removePolicy(), name is null");
822            }
823            throw (new InvalidNameException(ResBundleUtils.rbName,
824                "null_name", null, "null", PolicyException.POLICY));
825        }
826
827        try {
828            PolicyManager.initAdminSubject();
829            // Get service config for named policy node
830            ServiceConfig oConfig = scm.getOrganizationConfig(org, null);
831            ServiceConfig namedPolicy = (oConfig == null) ? null :
832                oConfig.getSubConfig(NAMED_POLICY);
833            if (namedPolicy != null) {
834                /* Remove the named policy
835                 * before removing the named policy
836                 * prepare for changes in resources tree
837                 */
838                Policy policy = getPolicy(policyName);
839
840                // do the removal of policy 
841                namedPolicy.removeSubConfig(policyName);
842
843                if (policy != null) {
844                    // should use super admin token to remove the index store
845                    // entry
846                    PrivilegeIndexStore pis = PrivilegeIndexStore.
847                        getInstance(
848                        SubjectUtils.createSuperAdminSubject(),
849                        getOrganizationDN());
850                    if (policy.isReferralPolicy()) {
851                        pis.deleteReferral((policyName));
852                    } else {
853                        pis.delete(
854                            PrivilegeUtils.policyToPrivileges(policy));
855                    }
856                    policyCache.sendPolicyChangeNotification(null, policy,
857                        ServiceListener.REMOVED);
858                }
859            }
860        } catch (EntitlementException e) {
861            debug.error("Error while removing policy : " + e.getMessage());
862        } catch (ServiceNotFoundException snfe) {
863            debug.error("Error while removing policy : " +
864                    snfe.getMessage() );
865        } catch (SMSException smse) {
866            String objs[] = { policyName, org };
867            if (PolicyUtils.logStatus) {
868                PolicyUtils.logErrorMessage("UNABLE_TO_REMOVE_POLICY", objs, 
869                    token);
870            }
871            debug.error("SMS error in deleting policy: " +
872                    policyName + " for org: " + org, smse);
873            // Check for permission exception
874            if (smse.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
875                throw (new NoPermissionException(ResBundleUtils.rbName,
876                    "insufficient_access_rights", null));
877            } else {
878                // Throw generic policy exception
879                throw (new PolicyException(ResBundleUtils.rbName, 
880                    "unable_to_remove_policy", objs, smse));
881            }
882        }
883        String objs[] = { policyName, org };
884        if (PolicyUtils.logStatus) {
885            PolicyUtils.logAccessMessage("POLICY_REMOVE_SUCCESS", objs, token);
886        }
887    }
888
889    /**
890     * Gets the <code>ResourceManager</code> object instance associated
891     * with this <code>PolicyManager</code> object instance
892     *
893     * @return <code>ResourceManager</code> object
894     *
895     * @supported.api
896     */    
897    public ResourceManager getResourceManager() {
898        return rm;
899    }
900    
901    /**
902     * Gets the <code>SubjectTypeManager</code> object instance associated
903     * with this <code>PolicyManager</code> object instance
904     *
905     * @return <code>SubjectTypeManager</code> object
906     *
907     * @supported.api
908     */    
909    public SubjectTypeManager getSubjectTypeManager() {
910        if (stm == null) {
911            stm = new SubjectTypeManager(this);
912        }
913        return (stm);
914    }
915    
916    /**
917     * Gets the <code>ConditionTypeManager</code> object instance associated
918     * with this <code>PolicyManager</code> object instance
919     *
920     * @return <code>ConditionTypeManager</code> object
921     *
922     * @supported.api
923     */    
924    public ConditionTypeManager getConditionTypeManager() {
925        if (ctm == null) {
926            ctm = new ConditionTypeManager(this);
927        }
928        return (ctm);
929    }
930
931     /**
932      * Gets the <code>ResponseProviderTypeManager</code> object instance 
933      * associated with this <code>PolicyManager</code> object instance
934      *
935      * @return <code>ResponseProviderTypeManager</code> object
936      *
937      */    
938     public ResponseProviderTypeManager getResponseProviderTypeManager() {
939         if (rpm == null) {
940             rpm = new ResponseProviderTypeManager(this);
941         }
942         return (rpm);
943     }
944     
945    /** Creates or gets a node (namedPolicy, resources, or userCollection)
946     *  under ou=policies
947     */
948    static ServiceConfig createOrGetPolicyConfig(String configName,
949        String configId, ServiceConfigManager scm, String org)
950        throws NoPermissionException, PolicyException, SSOException {
951        // Get service config that represents named policy node
952        ServiceConfig sConfig = null;
953        try {
954            ServiceConfig oConfig = scm.getOrganizationConfig(org, null);
955            sConfig = (oConfig == null) ? null :
956                oConfig.getSubConfig(configName);
957            if (sConfig == null) {
958                if (debug.messageEnabled()) {
959                    debug.message("Creating the " + configName +
960                        " tree for org: " + org);
961                }
962                // create the named policy node
963                createPolicyTree(configName, configId, scm, org);
964
965                // Check if policy tree is created
966                if (oConfig == null) {
967                    oConfig = scm.getOrganizationConfig(org, null);
968                }
969                if ((oConfig == null) || ((sConfig = oConfig.getSubConfig(
970                    configName)) == null)) {
971                    // Throw generic policy exception
972                    String objs[] = { configName };
973                    throw (new PolicyException(ResBundleUtils.rbName,
974                        "unable_to_get_policy_node", objs, null));
975                }
976            }
977        } catch (SMSException smse) {
978            // Debug messages
979            debug.error("SMS error in creating " + configName +
980                            " node for org: " + org, smse);
981
982            // Check for permission exception
983            if (smse.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
984                String objs[] = { configName };
985                throw (new NoPermissionException(ResBundleUtils.rbName,
986                    "insufficient_access_rights", objs));
987            } else {
988                // Throw generic policy exception
989                String objs[] = { configName };
990                throw (new PolicyException(ResBundleUtils.rbName,
991                    "unable_to_get_policy_node", objs, smse));
992            }
993        }
994        return (sConfig);
995    }
996
997    /**
998     *  Creates the policy tree, ou=policy, ou=services, ... 
999     */
1000    static void createPolicyTree(String configName, String configId,
1001        ServiceConfigManager scm, String org) throws NoPermissionException,
1002        PolicyException, SSOException {
1003        try {
1004            // Get the iPlanetPolicyService node            
1005            ServiceConfig pConfig = scm.getOrganizationConfig(org, null);
1006            if (pConfig == null) {
1007                // Since not present, create organization services node
1008                // i.e, ou=services, <org dn> and ou=iPlanetPolicyService,
1009                //  ou=services, ...
1010                scm.createOrganizationConfig(org, null);
1011                // Since it is created above, get it
1012                pConfig = scm.getOrganizationConfig(org, null);
1013            }
1014            // Create requested policy sub node
1015            // i.e., ou=<configName>, ou=iPlanetPolicyService, ou=services, ...
1016            pConfig.addSubConfig(configName, configId, 0, null);
1017        } catch (ServiceAlreadyExistsException se) {
1018            // do nothing
1019            if (debug.messageEnabled()) {
1020                debug.message("PolicyManager->createPolicyTree: Name: " +
1021                    configName + " ID: " + configId + 
1022                    " Policy service already exists under org->" + org);
1023            }
1024        } catch (SMSException e) {
1025            // Check for permission exception
1026            String[] objs = { org };
1027            if (e.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
1028                throw (new NoPermissionException(ResBundleUtils.rbName,
1029                    "insufficient_access_rights", null));
1030            } else {
1031                throw (new PolicyException(ResBundleUtils.rbName,
1032                    "unable_to_create_policy_for_org", objs, e));
1033            }
1034        }
1035    }
1036
1037    /**
1038     * Verifies if the name, which specifies a organization,
1039     * a suborganization or a container object, is in DN format; If not,
1040     * the name will be converted to a DN. Furthermore, whether the entry
1041     * corresponding to the DN exists is also checked.
1042     *
1043     * @param name name of the organization, suborganization
1044     * or container for which to manage policies.
1045     * The name could be either slash (/) separated
1046     * or the complete DN.
1047     *
1048     * @return the name in DN format (possibly converted from slash format)
1049     *
1050     * @throws SSOException invalid or expired single-sign-on token
1051     * @throws InvalidNameException the name is null
1052     * @throws NameNotFoundException if the given organization,
1053     * sub-organization or container name is not present
1054     */
1055    String verifyOrgName(String name)
1056        throws InvalidNameException, NameNotFoundException, SSOException {
1057        String orgName = null;
1058
1059        // Check for null name
1060        if (name == null) {
1061            throw (new InvalidNameException(ResBundleUtils.rbName, "null_name",
1062                null, "null", PolicyException.ORGANIZATION));
1063        }
1064
1065        /* this mapping call is required if name is not a DN
1066         * or if the name is not DN of a realm
1067         * This call is harmless if the DN is already DN of a realm
1068         */
1069        orgName = DNMapper.orgNameToDN(name);
1070
1071        // Check to see if the organization exists
1072        // if not present throw NameNotFoundException
1073        if (!SMSEntry.checkIfEntryExists(orgName, token)) {
1074            if (debug.warningEnabled()) {
1075                debug.warning("Checking for organization name: " +
1076                    orgName + " failed since entry does not exist");
1077            }
1078            String[] objs = { name };
1079            throw (new NameNotFoundException(ResBundleUtils.rbName,
1080                "org_not_found", objs, orgName,
1081                PolicyException.ORGANIZATION));
1082        }
1083        return (orgName);
1084    }
1085    
1086    /**
1087     * Gets a list of subordinate organizations or containers. If
1088     * there are no subordinate organizations or containers, returns
1089     * an empty set (not null).
1090     *
1091     * @return set of valid subordinate organizations or containers
1092     *
1093     * @throws SSOException invalid or expired single-sign-on token
1094     * @throws NoPermissionException user does not have sufficient
1095     * privileges to replace policy
1096     */
1097    Set getSubOrganizationNames() throws SSOException,
1098        NoPermissionException, PolicyException {
1099        throw (new UnsupportedOperationException());
1100    }
1101
1102    /**
1103     * Gets sub-organizations, given a filter. The filter
1104     * accepts "*" as the wild card for searching sub-organization names.
1105     * For example if the filter is "co*", it returns sub-organizations
1106     * starting with "co". Similarly, if the filter is "*net", it returns
1107     * sub-organizations ending with "net".
1108     *
1109     * @param filter the search filter that be used to 
1110     *               identify sub-organizations
1111     *
1112     * @return a set of sub-organizations
1113     */
1114    Set getSubOrganizationNames(String filter)
1115        throws SSOException, PolicyException {
1116        throw (new UnsupportedOperationException());
1117    }
1118
1119    /**
1120     * Gets sub-organization's policy manager.
1121     *
1122     * @param subOrgName name of the sub-organization organization. This
1123     * should be relative to the current organization.
1124     *
1125     * @return returns the policy manager for the organization;
1126     * else returns <code>null</code>.
1127     */
1128    PolicyManager getSubOrganizationPolicyManager(String subOrgName)
1129        throws SSOException, PolicyException {
1130        // the assumption is that orgnames are / separated
1131        return (new PolicyManager(token, org + "/" + subOrgName));
1132    }
1133
1134    /**
1135     * Gets <code>ServiceTypeManager</code> associated with this 
1136     * policy manager
1137     */
1138    ServiceTypeManager getServiceTypeManager() {
1139        return svtm;
1140    }
1141    
1142    /**
1143     * Returns <code>ReferralTypeManager</code> associated with this 
1144     * policy manager.
1145     *
1146     * @return <code>ReferralTypeManager</code> associated with this 
1147     * policy manager.
1148     * @supported.api
1149     */
1150    public ReferralTypeManager getReferralTypeManager() {
1151        if ( rtm == null ) {
1152            rtm = new ReferralTypeManager(this);
1153        }
1154        return rtm;
1155    }
1156
1157
1158    /**
1159     * Gets plugins schemas for a given interface name
1160     */
1161    static Set getPluginSchemaNames(String interfaceName) {
1162        if (ssm == null || !ssm.isSSOTokenValid()) {
1163            try {
1164                ssm = new ServiceSchemaManager(
1165                    PolicyManager.POLICY_SERVICE_NAME,
1166                    ServiceTypeManager.getSSOToken());
1167            } catch (Exception se) {
1168                PolicyManager.debug.error(
1169                        "Cannot create service schema " +
1170                        "manager for policy", se);
1171                return (Collections.EMPTY_SET);
1172            }
1173        }
1174
1175        Set answer = null;
1176        try {
1177           /* Get the plugin schema names for the root
1178            * In the future might want to customize it for org
1179            */
1180            answer = ssm.getPluginSchemaNames(interfaceName, null);
1181        } catch (Exception e) {
1182            PolicyManager.debug.error(
1183                    "Cannot get plugin schemas: " +
1184                    interfaceName + " for policy", e);
1185            return (Collections.EMPTY_SET);
1186        }
1187        return ((answer == null) ? Collections.EMPTY_SET : answer);
1188    }
1189
1190
1191    /**
1192     * Gets PluginSchema object for the given plugin interface name
1193     * and plugin name. Returns <code>null</code> if not present.
1194     */
1195    static PluginSchema getPluginSchema(String interfaceName,
1196        String pluginName) {
1197        Set plugins = getPluginSchemaNames(interfaceName);
1198        if (plugins.contains(pluginName)) {
1199            try {
1200                return (ssm.getPluginSchema(pluginName, interfaceName, null));
1201            } catch (Exception e) {
1202                PolicyManager.debug.error(
1203                        "Cannot get plugin schemas: " +
1204                        interfaceName + " for policy", e);
1205            }
1206        }
1207        return (null);
1208    }
1209
1210    /**
1211     * Gets the view bean URL given the plugin type 
1212     * and the plugin java class name
1213     *
1214     * @param pluginType  type of plugin such as Subject, Referral, Condition
1215     * @param pluginClassName name of java class name implementing the plugin
1216     *                        type
1217     *
1218     * @return view bean URL defined for pluginType with name pluginName
1219     */
1220    static String getViewBeanURL(String pluginType, String pluginClassName) {
1221        String viewBeanURL = null;
1222        if (pluginType != null) {
1223            Iterator items = PolicyManager.getPluginSchemaNames(
1224                    pluginType).iterator();
1225            while (items.hasNext()) {
1226                String pluginName = (String) items.next();
1227                PluginSchema ps = PolicyManager.getPluginSchema(pluginType, 
1228                        pluginName);
1229                if (pluginClassName.equals(ps.getClassName())) {
1230                    viewBeanURL = ps.getPropertiesViewBeanURL();
1231                    break;
1232                }
1233            }
1234        }
1235        return viewBeanURL;
1236    }
1237
1238    /** Gets a policy using policy cache. 
1239     * @param policyName policy name
1240     * @param useCache flag to indicate whether to use cache or not
1241     * @return the policy with the given policy name
1242     * @throws SSOException
1243     * @throws NoPermissionException
1244     * @throws InvalidFormatException
1245     * @throws PolicyException
1246     */
1247    Policy getPolicy(String policyName, boolean useCache) throws SSOException,
1248            NoPermissionException, InvalidFormatException, 
1249            NameNotFoundException,
1250            InvalidFormatException, PolicyException {
1251        Policy policy = null;
1252        if ( useCache ) {
1253            policy = policyCache.getPolicy(org, policyName);
1254        } else {
1255            policy = getPolicy(policyName);
1256        }
1257        return policy;
1258    }
1259
1260    ResourceIndexManager getResourceIndexManager() {
1261        return rim;
1262    }
1263
1264    private boolean validateResourceForPrefix(ServiceType resourceType, 
1265        String resourceName) throws PolicyException {
1266        Set<String> resourcePrefixes = Collections.emptySet();
1267        return validateResourceForPrefix(resourceType,
1268            resourcePrefixes, resourceName);
1269    }
1270
1271    private boolean validateResourceForPrefixE(
1272        String realm,
1273        String serviceName,
1274        Set<String> resourcePrefixes,
1275        String resourceName) throws PolicyException, EntitlementException {
1276
1277        String realmName = LDAPUtils.isDN(realm) ?
1278            DNMapper.orgNameToRealmName(realm) :realm;
1279
1280        Application appl = getApplicationService(SUPER_ADMIN_SUBJECT, realmName).getApplication(serviceName);
1281        com.sun.identity.entitlement.interfaces.ResourceName resComp = appl.
1282            getResourceComparator();
1283        resourceName = resComp.canonicalize(resourceName);
1284
1285        for (String prefix : resourcePrefixes) {
1286            boolean interpretWildCard = true;
1287            com.sun.identity.entitlement.ResourceMatch resMatch =
1288                resComp.compare(resourceName,
1289                resComp.canonicalize(prefix), interpretWildCard);
1290            if ( resMatch.equals(
1291                com.sun.identity.entitlement.ResourceMatch.SUPER_RESOURCE_MATCH)
1292                || resMatch.equals(
1293                    com.sun.identity.entitlement.ResourceMatch.WILDCARD_MATCH)
1294                || resMatch.equals(
1295                    com.sun.identity.entitlement.ResourceMatch.EXACT_MATCH) ) {
1296                return true;
1297            }
1298
1299        }
1300        return false;
1301    }
1302
1303    private boolean validateResourceForPrefix(
1304        ServiceType resourceType,
1305        Set<String> resourcePrefixes,
1306        String resourceName) throws PolicyException {
1307
1308        for (String prefix : resourcePrefixes) {
1309            boolean interpretWildCard = true;
1310            ResourceMatch resMatch = resourceType.compare(resourceName, prefix,
1311                    interpretWildCard);
1312            if ( resMatch.equals(ResourceMatch.SUPER_RESOURCE_MATCH)
1313                        || resMatch.equals(ResourceMatch.WILDCARD_MATCH)
1314                        || resMatch.equals(ResourceMatch.EXACT_MATCH) ) {
1315                return true;
1316            }
1317
1318        }
1319        return false;
1320    }
1321
1322    private void validateForResourcePrefix(Policy policy)
1323                throws SSOException, PolicyException {
1324        DN orgDN = DN.valueOf(org);
1325        DN baseDN = DN.valueOf(ServiceManager.getBaseDN());
1326        PolicyManager.initAdminSubject();
1327
1328        if (!orgDN.equals(baseDN) && !orgDN.equals(delegationRealm)) {
1329            String realm = DNMapper.orgNameToRealmName(getOrganizationDN());
1330            Iterator ruleNames = policy.getRuleNames().iterator();
1331            while (ruleNames.hasNext()) {
1332                try {
1333                    String ruleName = (String) ruleNames.next();
1334                    Rule rule = (Rule) policy.getRule(ruleName);
1335                    String serviceTypeName = rule.getServiceTypeName();
1336                    String ruleResource = rule.getResourceName();
1337                    // Make sure adminSubject has been set before using
1338                    if (adminSubject == null) {
1339                       initialise();
1340                    }
1341                    Set<String> referredResources = getApplicationService(adminSubject, realm)
1342                            .getReferredResources(serviceTypeName);
1343                    if ((referredResources == null) || referredResources.
1344                        isEmpty()) {
1345                        String[] objs = {org};
1346                        throw new PolicyException(ResBundleUtils.rbName,
1347                            "no_referral_can_not_create_policy", objs, null);
1348                    }
1349                    ServiceType resourceType = getServiceTypeManager().
1350                        getServiceType(serviceTypeName);
1351
1352                    if (!validateResourceForPrefixE(realm, serviceTypeName,
1353                        referredResources, ruleResource)) {
1354                        String[] objs = {ruleResource, resourceType.getName()};
1355                        throw new PolicyException(ResBundleUtils.rbName,
1356                            "resource_name_not_permitted_by_prefix_names", objs,
1357                            null);
1358                    }
1359                } catch (EntitlementException ex) {
1360                    String[] objs = {org};
1361                    throw new PolicyException(ResBundleUtils.rbName,
1362                        "no_referral_can_not_create_policy", objs, null);
1363                }
1364            }
1365        }
1366    }
1367
1368    private void validateForResourcePrefixO(Policy policy)
1369            throws SSOException, PolicyException {
1370        DN orgDN = DN.valueOf(org);
1371        DN baseDN = DN.valueOf(ServiceManager.getBaseDN());
1372        Set prefixes = getManagedResourceNames();
1373        if (!orgDN.equals(baseDN) && !orgDN.equals(delegationRealm)
1374             && ((prefixes == null ) || prefixes.isEmpty()) ) {
1375                String[] objs = {org};
1376                throw new PolicyException(
1377                        ResBundleUtils.rbName,
1378                        "no_referral_can_not_create_policy", objs, null);
1379        }
1380        Iterator ruleNames = policy.getRuleNames().iterator();
1381        while ( ruleNames.hasNext() ) {
1382            String ruleName = (String) ruleNames.next();
1383            Rule rule = (Rule) policy.getRule(ruleName);
1384            String serviceTypeName = rule.getServiceTypeName();
1385            ServiceType resourceType = getServiceTypeManager()
1386                    .getServiceType(serviceTypeName);
1387            String ruleResource = rule.getResourceName();
1388            boolean validResource = true;
1389            if (!orgDN.equals(baseDN) && !orgDN.equals(delegationRealm)) {
1390                validResource = validateResourceForPrefix(resourceType, 
1391                        ruleResource);
1392            }
1393            if (!validResource) {
1394                String[] objs = { ruleResource, resourceType.getName() };
1395                throw new PolicyException(
1396                        ResBundleUtils.rbName,
1397                        "resource_name_not_permitted_by_prefix_names",
1398                        objs, null);
1399            }
1400        }
1401
1402    }
1403
1404    private void validateReferrals(Policy policy) 
1405            throws SSOException, PolicyException {
1406        Set candidateOrgs = policy.getReferredToOrganizations();
1407        if ( candidateOrgs.contains(org.toLowerCase()) ) {
1408            String[] objs = { org };
1409            throw new PolicyException(
1410                    ResBundleUtils.rbName,
1411                    "invalid_referral_pointing_to_self",
1412                    objs, null);
1413        }
1414        Iterator iter = candidateOrgs.iterator();
1415        while ( iter.hasNext() ) {
1416            String candidateOrg = (String) iter.next();
1417
1418            /* 
1419             * check org orgName exisits - would result in
1420             * PolicyException if the orgName does not exist 
1421             */
1422            verifyOrgName(candidateOrg);
1423        }
1424
1425    }
1426
1427    void saveRealmSubjects(Subjects subjects) 
1428            throws PolicyException, SSOException {
1429        ServiceConfig realmSubjects = createOrGetPolicyConfig(
1430            REALM_SUBJECTS, REALM_SUBJECTS, scm, org);
1431        Map attributes = new HashMap(1);
1432        Set values = new HashSet(1);
1433        String subjectsXML = subjects.toXML();
1434        values.add(subjectsXML);
1435        attributes.put(XML_REALM_SUBJECTS, values);
1436        try {
1437            realmSubjects.setAttributes(attributes);
1438        } catch (SMSException se) {
1439            debug.error("SMS error in saving realm subjects " 
1440                    + " in organization: " + org);
1441            // Check for permission exception
1442            String objs[] = { org };
1443            if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
1444                throw new PolicyException(ResBundleUtils.rbName,
1445                    "insufficient_access_rights", null, se);
1446            } else {
1447                // Throw generic policy exception
1448                throw new PolicyException(ResBundleUtils.rbName,
1449                    "unable_to_save_realm_subjects", objs, se);
1450            }
1451        }
1452        if (debug.messageEnabled()) {
1453            debug.message("saved realm subjects:" + subjectsXML);
1454        }
1455    }
1456
1457    Subjects readRealmSubjects() throws PolicyException, SSOException {
1458        Subjects subjects = null;
1459        ServiceConfig realmSubjects = createOrGetPolicyConfig(
1460                REALM_SUBJECTS, REALM_SUBJECTS, scm, org);
1461        Set values = null;
1462        values = (Set)realmSubjects.getAttributes().get(XML_REALM_SUBJECTS);
1463        if ((values != null) && !values.isEmpty()) {
1464            String xmlSubjects = (String)values.iterator().next();
1465            Document doc = null;
1466            try {
1467                doc = XMLUtils.getXMLDocument(
1468                    new ByteArrayInputStream(xmlSubjects.getBytes("UTF8")));
1469            } catch (Exception xmle) {
1470                debug.error("XML parsing error for realmSubjects: " 
1471                        + " in organization: " + org);
1472                // throw generic policy exception
1473                throw (new PolicyException(xmle));
1474            }
1475            Node subjectsNode = XMLUtils.getRootNode(doc, SUBJECTS_POLICY);
1476            if (subjectsNode == null) {
1477                debug.error("invalid xmlRealmSubjects blob " 
1478                        +    " in organization: " + org);
1479                throw (new InvalidFormatException(ResBundleUtils.rbName,
1480                    "invalid_xml_realmsubjects_root_node", null, 
1481                    org, PolicyException.POLICY));
1482            }
1483            subjects = new Subjects(this, subjectsNode);
1484        } else {
1485            subjects = new Subjects();
1486        }
1487        if (debug.messageEnabled()) {
1488            debug.message("read realm subjects:" + subjects.toXML());
1489        }
1490        subjects.setPolicyConfig(getPolicyConfig());
1491        return subjects;
1492    }
1493
1494    /**
1495     * Gets the set of policies that use the realm subject
1496     * @param subjectName name of the realm subject to check for
1497     * @return a <code>Set</code> of <code>Policy</code> objects 
1498     *        that use the  realm subject
1499     */
1500    public Set getPoliciesUsingRealmSubject(String subjectName) 
1501            throws PolicyException, SSOException {
1502        Set policies = new HashSet();
1503        Set policyNames = getPolicyNames();
1504        for (Iterator policyIter = policyNames.iterator(); 
1505                policyIter.hasNext();) {
1506            String policyName = (String)policyIter.next();
1507            Policy policy = getPolicy(policyName);
1508            Set subjectNames = policy.getSubjectNames();
1509            if (subjectNames.contains(subjectName)) {
1510                Subject subject = policy.getSubject(subjectName);
1511                if (subject instanceof SharedSubject) {
1512                    policies.add(policy);
1513                }
1514            }
1515        }
1516        return policies;
1517    }
1518
1519    Policy getPolicyUsingRealmSubject(String subjectName) 
1520            throws PolicyException, SSOException {
1521        Policy policy = null;
1522        Set policyNames = getPolicyNames();
1523        for (Iterator policyIter = policyNames.iterator(); 
1524                policyIter.hasNext();) {
1525            String policyName = (String)policyIter.next();
1526            Policy p = getPolicy(policyName);
1527            Set subjectNames = p.getSubjectNames();
1528            if (subjectNames.contains(subjectName)) {
1529                Subject subject = p.getSubject(subjectName);
1530                if (subject instanceof SharedSubject) {
1531                    policy = p;
1532                    break;
1533                }
1534            }
1535        }
1536        return policy;
1537    }
1538
1539    private Set getOrgAliasMappedResourceNames() 
1540            throws PolicyException {
1541        if (debug.messageEnabled()) {
1542            debug.message("PolicyManager.getOrgAliasMappedResourceNames(): "
1543                    + " entering:orgName = " + org);
1544        }
1545        Set managedResourceNames = new HashSet(3);
1546        if (ocm == null) {
1547            try {
1548                ocm = new OrganizationConfigManager(token, givenOrgName);
1549            } catch (SMSException sme) {
1550                String[] objs = { org };
1551                throw (new PolicyException(ResBundleUtils.rbName,
1552                        "unable_to_get_org_config_manager_for_org", 
1553                        objs, sme));
1554            }
1555        }
1556
1557        Set orgAliases = null;
1558        try {
1559            Map orgAttributes = ocm.getAttributes(ID_REPO_SERVICE);
1560            orgAliases 
1561                    = (Set)orgAttributes.get(ORG_ALIAS);
1562            if (debug.messageEnabled()) {
1563                debug.message("PolicyManager.getOrgAliasMappedResourceNames(): "
1564                        + " orgName = " + org
1565                        + ":orgAliases=" + orgAliases);
1566            }
1567        } catch (SMSException sme) {
1568            String[] objs = { org };
1569            throw (new PolicyException(ResBundleUtils.rbName,
1570                    "unable_to_get_org_alias_for_org", objs, sme));
1571        }
1572        if (orgAliases != null) {
1573            Iterator iter = orgAliases.iterator();
1574            while (iter.hasNext()) {
1575                String orgAlias = (String)iter.next();
1576                managedResourceNames.add(ORG_ALIAS_URL_HTTP_PREFIX 
1577                        + orgAlias.trim() 
1578                        + ORG_ALIAS_URL_SUFFIX);
1579                managedResourceNames.add(ORG_ALIAS_URL_HTTPS_PREFIX 
1580                        + orgAlias.trim() 
1581                        + ORG_ALIAS_URL_SUFFIX);
1582            }
1583        }
1584        if (debug.messageEnabled()) {
1585            debug.message("PolicyManager.getOrgAliasMappedResourceNames(): "
1586                    + " returning: orgName = " + org
1587                    + ":orgAliases=" + orgAliases
1588                    + ":managedResourceNames=" + managedResourceNames);
1589        }
1590        return managedResourceNames;
1591    }
1592
1593    public Set getManagedResourceNames() 
1594            throws PolicyException {
1595        PolicyManager.initAdminSubject();
1596        Set managedResourceNames = rm.getManagedResourceNames();
1597        if ((managedResourceNames == null) 
1598                || (managedResourceNames == Collections.EMPTY_SET)) {
1599                    managedResourceNames = new HashSet();
1600        }
1601        managedResourceNames.addAll(getOrgAliasMappedResourceNames());
1602        if (debug.messageEnabled()) {
1603            debug.message("PolicyManager.getManagedResourceNames(): "
1604                    + " returning: orgName = " + org
1605                    + ":managedResourceNames=" + managedResourceNames);
1606        }
1607        return managedResourceNames;
1608    }
1609
1610    String getOrgAliasWithResource(String resourceName) 
1611            throws PolicyException, SSOException {
1612        if (debug.messageEnabled()) {
1613            debug.message("PolicyManager.getOrgAliasWithResource(): "
1614                    + " orgName = " + org
1615                    + ", resourceName = " + resourceName);
1616        }
1617        if (resourceName == null) {
1618            return null;
1619        }
1620        String orgAlias = null;
1621        try {
1622            URL url = new URL(resourceName);
1623            orgAlias = url.getHost();
1624        } catch (MalformedURLException mfe) {
1625            String[] objs = { resourceName };
1626            if (debug.messageEnabled()) {
1627                debug.message("PolicyManager.getOrgAliasWithResource(): "
1628                        + " orgName = " + org
1629                        + ", resourceName = " + resourceName
1630                        + " is invalid URL, no org alias mapping can be found");
1631            }
1632        }
1633        return orgAlias;
1634    }
1635
1636    String getOrgNameWithAlias(String orgAlias) 
1637            throws PolicyException, SSOException {
1638        String aliasMappedOrg = null;
1639        try {
1640            aliasMappedOrg = IdUtils.getOrganization(token, orgAlias);
1641        } catch (IdRepoException re) {
1642            //idRepo throws exception if there is no mapping
1643            if (debug.messageEnabled()) {
1644                debug.message("PolicyManager.getOrgNameWithAlias(): "
1645                        + " can not get orgName for orgAlias = " + orgAlias);
1646            }
1647        }
1648        if (debug.messageEnabled()) {
1649            debug.message("PolicyManager.getOrgNameWithAlias(): "
1650                    + " orgAlias = " + orgAlias
1651                    + ", mapped org = " + aliasMappedOrg);
1652        }
1653        return aliasMappedOrg;
1654    }
1655
1656    public boolean canCreatePolicies(Set<String> services) 
1657        throws EntitlementException {
1658        PolicyManager.initAdminSubject();
1659        String realm = DNMapper.orgNameToRealmName(getOrganizationDN());
1660        if (realm.equals("/")) {
1661            return true;
1662        }
1663
1664        for (String s : services) {
1665            Set<String> res = getApplicationService(adminSubject, realm).getReferredResources(s);
1666            if ((res != null) && !res.isEmpty()) {
1667                return true;
1668            }
1669        }
1670        return false;
1671    }
1672
1673    private static void initialise() {
1674
1675        // Do this outside of a static block to avoid issues on container shutdown/restart
1676        adminSubject = SubjectUtils.createSubject(
1677                (SSOToken)AccessController.doPrivileged(AdminTokenAction.getInstance()));
1678    }
1679
1680    public boolean canCreateNewResource(String svcTypeName) {
1681        boolean can = false;
1682        ResourceManager resMgr = getResourceManager();
1683        PolicyManager.initAdminSubject();
1684        if (resMgr != null) {
1685            try {
1686                can = resMgr.canCreateNewResource(svcTypeName);
1687            } catch (PolicyException e) {
1688                debug.warning("PolicyManager.canCreateNewResource",e);
1689            }
1690        }
1691        return can;
1692    }
1693
1694    /**
1695     * To initialise the adminSubject if it was null.
1696     * This must be non-null for the migratedToEntitlementService to have been
1697     * calculated correctly
1698     */
1699    public static void initAdminSubject(){
1700        if (adminSubject == null){
1701            initialise();
1702        }
1703    }
1704}