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




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.