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: Policy.java,v 1.9 2010/01/10 01:19:35 veiming Exp $
026 *
027 * Portions Copyrighted 2011-2015 ForgeRock AS.
028 */
029
030package com.sun.identity.policy;
031
032import java.util.Collection;
033import java.util.Collections;
034import java.util.HashMap;
035import java.util.HashSet;
036import java.util.Iterator;
037import java.util.Map;
038import java.util.Set;
039import java.util.StringTokenizer;
040
041import com.iplanet.am.sdk.AMCommonUtils;
042import com.iplanet.am.util.Cache;
043import com.iplanet.sso.SSOException;
044import com.iplanet.sso.SSOToken;
045import com.sun.identity.policy.interfaces.Condition;
046import com.sun.identity.policy.interfaces.Referral;
047import com.sun.identity.policy.interfaces.ResponseProvider;
048import com.sun.identity.policy.interfaces.Subject;
049import com.sun.identity.policy.plugins.OrgReferral;
050import com.sun.identity.shared.debug.Debug;
051import com.sun.identity.shared.xml.XMLUtils;
052import com.sun.identity.sm.AttributeSchema;
053import org.forgerock.openam.ldap.LDAPUtils;
054import org.w3c.dom.Node;
055
056/**
057 * The class <code>Policy</code> represents a policy definition.
058 * A policy contains a set of rules associated with a collection of 
059 * users and conditions. The policy object is saved in the data store
060 * only when the <code>store</code> method of the <code>Policy</code> is 
061 * called, or if the methods <code>addPolicy</code> or <code>replacePolicy
062 * </code> of <code>PolicyManager</code> instance is invoked with this policy.
063 * The <code>Policy</code> object is accessible to policy evaluation and 
064 * enforcement points only after it is saved in data store. 
065 *
066 * @supported.api
067 * @deprecated since 12.0.0
068 */
069@Deprecated
070public class Policy implements Cloneable {
071
072    static final String REFERRAL_POLICY = "referralPolicy";
073    static final String ACTIVE_FLAG = "active";
074
075    private static final int SUBJECTS_CONDITIONS_RULES = 1;
076    private static final int CONDITIONS_SUBJECTS_RULES = 2;
077    private static final int RULES_SUBJECTS_CONDITIONS = 3;
078    private static final int RULES_CONDITIONS_SUBJECTS = 4;
079    private static final int SUBJECTS_RULES_CONDITIONS = 5;
080    private static final int CONDITIONS_RULES_SUBJECTS = 6;
081
082    private static String EVALUATION_WEIGHTS = null;
083    private static String DEFAULT_EVALUATION_WEIGHTS = "10:10:10";
084    private final static String EVALUATION_WEIGHTS_KEY 
085            = "com.sun.identity.policy.Policy.policy_evaluation_weights";
086    private static final Debug DEBUG = PolicyManager.debug;
087
088    private int evaluationOrder = RULES_SUBJECTS_CONDITIONS;
089
090    private static int ruleWeight;
091    private static int conditionWeight;
092    private static int subjectWeight;
093
094    private int prWeight;
095    private int pcWeight;
096    private int psWeight;
097
098    static {
099        initializeStaticEvaluationWeights();
100    }
101
102    private String origPolicyName;
103    private String policyName;
104    private String description = "";
105    private String createdBy;
106    private String lastModifiedBy;
107    private long creationDate;
108    private long lastModifiedDate;
109    private boolean referralPolicy=false;
110    private boolean active = true;
111
112    private int priority;
113    private Map rules = new HashMap();
114    private Subjects users = new Subjects();
115    private Conditions conditions = new Conditions();
116    private ResponseProviders respProviders = new ResponseProviders();
117    private Referrals referrals = new Referrals();
118    private String organizationName;
119    private final static int MATCHED_RULE_RESULTS_CACHE_SIZE = 1000;
120    private final static int MATCHED_REFERRAL_RULES_CACHE_SIZE = 100;
121    private Cache matchRulesResultsCache 
122            = new Cache(MATCHED_RULE_RESULTS_CACHE_SIZE);
123    private String subjectRealm;
124
125    /**
126     * No-arg constructor.
127     */
128    private Policy() {
129        // do nothing
130    }
131
132    /**
133     * Constructs a policy given the policy name.
134     *
135     * @param policyName name of the policy
136     *
137     * @exception InvalidNameException if policy name is not valid
138     *
139     * @supported.api
140     *
141     */
142    public Policy(String policyName) throws InvalidNameException {
143        this(policyName, null);
144    }
145
146    /**
147     * Constructs a policy given the policy name and priority. 
148     *
149     * @param policyName name of the policy
150     * @param priority priority assigned to the policy
151     *
152     * @exception InvalidNameException if policy name is not valid
153     */
154    private Policy(String policyName, int priority) throws InvalidNameException 
155    {
156        validateName(policyName);
157        this.policyName = policyName;
158        // Set the policy priority
159        this.priority = priority;
160    }
161
162    /**
163     * Constructs a policy given  the policy name and description.
164     *
165     * @param policyName name of the policy
166     * @param description description for the policy
167     *
168     * @exception InvalidNameException if policy name is not valid
169     *
170     * @supported.api
171     *
172     */
173    public Policy(String policyName, String description)
174        throws InvalidNameException {
175
176        this(policyName, description, false, true);
177    }
178
179    /**
180     * Constructs a policy given  the policy name,description and a 
181     * referralPolicy flag.
182     *
183     * @param policyName name of the policy
184     * @param description description for the policy
185     * @param referralPolicy indicates whether the policy is a 
186     *        referral policy or a standard policy.
187     * A referral policy is used only to delegate policy definitions to 
188     * sub/peer organizations. A referral policy does not make use of any
189     * action values
190     *
191     *
192     * @exception InvalidNameException if policy name is not valid
193     *
194     * @supported.api
195     *
196     */
197    public Policy(String policyName, String description, 
198        boolean referralPolicy) throws InvalidNameException 
199    {
200        this(policyName, description, referralPolicy, true);
201    }
202
203    /**
204     * Constructs a policy given  the policy name , description,
205     * referralPolicy flag, and active flag
206     *
207     * @param policyName name of the policy
208     * @param description description for the policy
209     * @param referralPolicy indicates whether the policy is a 
210     *        referral policy or a standard policy.
211     * @param active indicates if the policy is active or not.
212     * A referral policy is used only to delegate policy definitions to 
213     * sub/peer organizations. A referral policy does not make use of any
214     * action values
215     *
216     * @exception InvalidNameException if policy name is not valid
217     *
218     * @supported.api
219     *
220     */
221    public Policy(String policyName, String description, 
222        boolean referralPolicy, boolean active) throws InvalidNameException 
223    {
224        validateName(policyName);
225        this.policyName = policyName;
226        if (description != null) {
227            this.description = description;
228        }
229        this.referralPolicy = referralPolicy;
230        this.active = active;
231    }
232
233    /**
234     * Constructs a policy given the Policy Node. 
235     * This is used by PolicyManager
236     * @param pm <code>PolicyManager</code> requesting the operation
237     *
238     * @param policyNode XML node in W3C DOM format representing 
239     * the policy object which needs to be created.
240     * @exception InvalidFormatException, InvalidNameException,
241     * NameNotFoundException, PolicyException
242     */
243    public Policy(PolicyManager pm, Node policyNode)
244        throws InvalidFormatException, InvalidNameException,
245        NameNotFoundException, PolicyException {
246        // Check if the node name is PolicyManager.POLICY_ROOT_NODE
247        if (!policyNode.getNodeName().equalsIgnoreCase(
248            PolicyManager.POLICY_ROOT_NODE)) {
249            if (PolicyManager.debug.warningEnabled()) {
250                PolicyManager.debug.warning(
251                    "invalid policy xml blob given to construct policy");
252            }
253            throw (new InvalidFormatException(ResBundleUtils.rbName,
254                "invalid_xml_policy_root_node", null, "", 
255                PolicyException.POLICY));
256        }
257
258        // Get the policy name
259        policyName = XMLUtils.getNodeAttributeValue(policyNode,
260            PolicyManager.NAME_ATTRIBUTE);
261        validateName(policyName);
262
263        // Get descrition, can be null
264        description = XMLUtils.getNodeAttributeValue(policyNode,
265                PolicyManager.DESCRIPTION_ATTRIBUTE);
266
267        getModificationInfo(policyNode);
268
269        // Get referralPolicy flag
270        String referralPolicy = XMLUtils.getNodeAttributeValue(policyNode,
271                Policy.REFERRAL_POLICY);
272        if ( (referralPolicy != null) &&
273                (referralPolicy.equalsIgnoreCase("true")) ) {
274            this.referralPolicy = true;
275        }
276
277        // Get active flag
278        String active = XMLUtils.getNodeAttributeValue(policyNode,
279                Policy.ACTIVE_FLAG);
280        if ( (active != null) &&
281                (active.equalsIgnoreCase("false")) ) {
282            this.active = false;
283        }
284
285        // Get priority
286        String pri = XMLUtils.getNodeAttributeValue(policyNode,
287            PolicyManager.PRIORITY_ATTRIBUTE);
288        if (pri != null) {
289            try {
290                priority = Integer.parseInt(pri);
291            } catch (NumberFormatException nfe) {
292                // write to debug and continue
293                PolicyManager.debug.error("Number format exception in " +
294                   "determining policy's priority: " + pri, nfe);
295            }
296        }
297
298
299        // Get the rule nodes and instantiate them
300        Set ruleNodes = XMLUtils.getChildNodes(policyNode,
301            PolicyManager.POLICY_RULE_NODE);
302        if ( ruleNodes != null ) {
303            Iterator items = ruleNodes.iterator();
304            while (items.hasNext()) {
305                Node ruleNode = (Node) items.next();
306                Rule rule = new Rule(ruleNode);
307                addRule(rule);
308            }
309        }
310
311        if (!this.referralPolicy) {
312            // Get the users collection and instantiate Subjects
313            Node subjectsNode = XMLUtils.getChildNode(policyNode,
314                    PolicyManager.POLICY_SUBJECTS_NODE);
315            if ( subjectsNode != null ) {
316                users = new Subjects(pm, subjectsNode);
317            }
318        
319            // Get the conditions collection and instantiate Conditions
320            Node conditionsNode = XMLUtils.getChildNode(policyNode,
321                    PolicyManager.POLICY_CONDITIONS_NODE);
322            if ( conditionsNode != null ) {
323                conditions = new Conditions(pm.getConditionTypeManager(), 
324                    conditionsNode);
325            }
326            // Get the respProviders collection and instantiate 
327            // ResponseProviders
328            Node respProvidersNode = XMLUtils.getChildNode(policyNode,
329                    PolicyManager.POLICY_RESP_PROVIDERS_NODE);
330            if ( respProvidersNode != null ) {
331                respProviders = new ResponseProviders(
332                    pm.getResponseProviderTypeManager(), 
333                    respProvidersNode);
334            }
335        } else {
336            // Get the referrals collection and instantiate Referrals
337            Node referralsNode = XMLUtils.getChildNode(policyNode,
338                    PolicyManager.POLICY_REFERRALS_NODE);
339            if ( referralsNode != null ) {
340                referrals = new Referrals(pm, referralsNode);
341            }
342        }
343    }
344
345    private void getModificationInfo(Node policyNode) {
346        String strCreationDate = XMLUtils.getNodeAttributeValue(policyNode,
347                PolicyManager.CREATION_DATE_ATTRIBUTE);
348        if ((strCreationDate != null) && (strCreationDate.length() > 0)) {
349            try {
350                creationDate = Long.parseLong(strCreationDate);
351            } catch (NumberFormatException e) {
352                //ignore
353            }
354        }
355        String strLastModifiediDate = XMLUtils.getNodeAttributeValue(
356            policyNode, PolicyManager.LAST_MODIFIED_DATE_ATTRIBUTE);
357        if ((strLastModifiediDate != null) &&
358            (strLastModifiediDate.length() > 0)
359        ) {
360            try {
361                lastModifiedDate = Long.parseLong(strLastModifiediDate);
362            } catch (NumberFormatException e) {
363                //ignore
364            }
365        }
366
367        createdBy = XMLUtils.getNodeAttributeValue(policyNode,
368            PolicyManager.CREATED_BY_ATTRIBUTE);
369        lastModifiedBy = XMLUtils.getNodeAttributeValue(policyNode,
370            PolicyManager.LAST_MODIFIED_BY_ATTRIBUTE);
371    }
372
373    /**
374     * Gets the name of the policy.
375     *
376     * @return name of the policy
377     *
378     * @supported.api
379     *
380     */
381    public String getName() {
382        return (policyName);
383    }
384
385    /**
386     * Sets the name of the policy.
387     *
388     * @param policyName name of the policy.
389     * @exception InvalidNameException if <code>policyName</code> is an invalid
390     * name.
391     *
392     * @supported.api
393     *
394     */
395    public void setName(String policyName) throws InvalidNameException {
396        validateName(policyName);
397        if (this.policyName.equals(policyName)) {
398            return;
399        }
400        if (origPolicyName == null) {
401            origPolicyName = this.policyName;
402        }
403        this.policyName = policyName;
404    }
405
406    /**
407     * Gets the original policy name. 
408     * This is used to track policies called via
409     * <code>PolicyManager::replacePolicy()</code>
410     * with the changed policy name.
411     *
412     * @return the policy name that was present when
413     *          the object was instantiated
414     */
415    protected String getOriginalName() {
416        return (origPolicyName);
417    }
418
419    /**
420     * Sets the organization name under which the policy is created
421     * This would be set only for policies that have been read from data store.
422     * Otherwise this would be <code>null</code>
423     *
424     * @param  organizationName name of the organization name in which the 
425     * policy is created.
426     */
427    void setOrganizationName(String organizationName) {
428        this.organizationName = organizationName;
429    }
430
431    /**
432     * Gets the organization name under which the policy is created
433     * This would be set only for policies that have been read from data store.
434     * Otherwise this would be <code>null</code>
435     *
436     * @return the organization name under which the policy is created
437     *
438     * @supported.api
439     *
440     */
441    public String getOrganizationName() {
442        return organizationName;
443    }
444
445    /**
446     * Resets the original policy name
447     */
448    protected void resetOriginalName() {
449        origPolicyName = null;
450    }
451
452    /**
453     * Gets the description for the policy.
454     * If the description for the policy has not been set
455     * the method will return an empty string; not <code>
456     * null</code>.
457     *
458     * @return description of the policy
459     *
460     * @supported.api
461     *
462     */
463    public String getDescription() {
464        return description;
465    }
466
467    /**
468     * Sets the description for the policy.
469     *
470     * @param description description for the policy
471     * @exception InvalidNameException if the description is invalid
472     *
473     * @supported.api
474     *
475     */
476    public void setDescription(String description)
477        throws InvalidNameException {
478        if (description != null) {
479            this.description = description;
480        }
481    }
482
483    /**
484     * Checks whether the policy is a referral policy.
485     * A referral policy is used only to delegate policy definitions to 
486     * sub/peer organizations. A referral policy does not make use of any
487     * action values
488     *
489     * @return <code>true</code> if this is a referral policy.
490     *         Otherwise returns <code>false</code>
491     *
492     * @supported.api
493     *
494     */
495    public boolean isReferralPolicy() {
496        return referralPolicy;
497    }
498
499    /**
500     * Checks whether the policy is active or inactive
501     * An inactive policy is not used to make policy evaluations.
502     *
503     * @return <code>true</code> if this is an active policy.
504     *         Otherwise returns <code>false</code>
505     *
506     * @supported.api
507     *
508     */
509    public boolean isActive() {
510        return active;
511    }
512
513    /**
514     * Set the active flag for policy.
515     * An inactive policy is not used to make policy evaluations.
516     * @param active <code>boolean</code> representing active or inactive.
517     *
518     * @supported.api
519     *
520     */
521    public void setActive(boolean active) {
522        this.active = active;
523    }
524
525    /**
526     * Gets the priority of the policy.
527     *
528     * @return priority of the policy
529     */
530    public int getPriority() {
531        return (priority);
532    }
533
534    /**
535     * Sets a priority of the policy.
536     *
537     * @param priority priority of the policy
538     */
539    public void setPriority(int priority) {
540        this.priority = priority;
541    }
542
543    /**
544     * Gets the set of rule names associated with the policy.
545     *
546     * @return <code>Set</code> of rule names
547     *
548     * @supported.api
549     *
550     */
551    public Set getRuleNames() {
552        return (new HashSet(rules.keySet()));
553    }
554
555    /**
556     * Gets the rule object identified by name.
557     *
558     * @param ruleName name of rule.
559     *
560     * @return <code>Rule</code> object.
561     *
562     * @exception NameNotFoundException if a <code>Rule</code> with the given 
563     *            name does not exist
564     * @supported.api
565     *
566     */
567    public Rule getRule(String ruleName) throws NameNotFoundException {
568        Rule rule = (Rule) rules.get(ruleName);
569        if (rule == null) {
570            throw (new NameNotFoundException(ResBundleUtils.rbName,
571                "rule_not_found", null, ruleName, PolicyException.RULE));
572        }
573        return (rule);
574    }
575
576    /**
577     * Adds a new policy rule.
578     *
579     * @param rule rule object to be added to the policy
580     * @exception NameAlreadyExistsException a rule with the given name
581     *            already exists
582     * @exception InvalidNameException if the rule name is invalid
583     *            same service name as the policy
584     * @supported.api
585     *
586     */
587    public void addRule(Rule rule) throws NameAlreadyExistsException ,
588            InvalidNameException {
589        // Since 5.0 does not support rule name, it can be null
590        if (rule.getName() == null) {
591            // Assign a name dynamically
592            rule.setName("rule" + ServiceTypeManager.generateRandomName());
593        }
594
595        // Check if the rule name or rule itself already exists
596        if (rules.containsKey(rule.getName())) {
597            throw (new NameAlreadyExistsException(ResBundleUtils.rbName,
598                "rule_name_already_present", null, rule.getName(),
599                PolicyException.RULE));
600        } else if (rules.containsValue(rule)) {
601            throw (new NameAlreadyExistsException(ResBundleUtils.rbName,
602                "rule_already_present", null, rule.getName(), 
603                PolicyException.RULE));
604        }
605
606        rules.put(rule.getName(), rule);
607    }
608
609    /**
610     * Replaces an existing rule with the same name by the
611     * current one. If a <code>Rule</code> with the same name does not exist,
612     * it will be added.
613     *
614     * @param rule <code>Rule</code> that will replace an existing rule
615     *        with the same name
616     *
617     * @exception InvalidNameException if <code>Rule</code> name is invalid
618     *
619     * @supported.api
620     *
621     */
622    public void replaceRule(Rule rule) throws InvalidNameException {
623        // Since 5.0 does not support rule name, it can be null
624        if (rule.getName() == null) {
625            // Assign a name dynamically
626            rule.setName("rule" + ServiceTypeManager.generateRandomName());
627        }
628
629        rules.put(rule.getName(), rule);
630    }
631
632    /**
633     * Removes the <code>Rule</code> with the given name. 
634     *
635     * @param ruleName name of the rule
636     *
637     * @return returns the <code>Rule</code> object being removed;
638     *         if not present returns <code>null</code>
639     *
640     * @supported.api
641     *
642     */
643    public Rule removeRule(String ruleName) {
644        return ((Rule) rules.remove(ruleName));
645    }
646
647    /**
648     * Returns a <code>Subjects</code> object that contains
649     * a set of <code>Subject</code> instances for which the
650     * policy is applied.
651     *
652     * @return Subjects object of the policy
653     */
654    Subjects getSubjects() {
655        return (users);
656    }
657
658    /**
659     * Get the <code>Set</code> of subject names associated with the policy.
660     *
661     * @return <code>Set</code> of String objects representing subject names
662     *
663     * @supported.api
664     *
665     */
666    public Set getSubjectNames() {
667        return users.getSubjectNames();
668    }
669
670    /**
671     * Gets the Subject object identified by name.
672     *
673     * @param subjectName name of subject.
674     *
675     * @return <code>Subject</code> object
676     *
677     * @exception NameNotFoundException if a Subject with the given name
678     * does not exist
679     *
680     * @supported.api
681     *
682     */
683    public Subject getSubject(String subjectName) throws NameNotFoundException {
684        return users.getSubject(subjectName);
685    }
686
687    /**
688     * Adds a new policy subject.
689     * The subject is added as a normal (non exclusive) subject.
690     * So, policy will apply to members of the subject.
691     * The policy will apply to a user if he is a member of 
692     * any normal (non exclusive) subject in the policy
693     * or not a member of any exclusive subject in the policy.
694     *
695     * @param name name of the Subject instance 
696     * @param subject Subject object to be added to the policy
697     *
698     * @exception NameAlreadyExistsException if a Subject with the given name
699     *          already exists
700     * @exception InvalidNameException if the subject name is invalid
701     *
702     * @supported.api
703     *
704     */
705    public void addSubject(String name, Subject subject) 
706            throws NameAlreadyExistsException, InvalidNameException {
707        users.addSubject(name, subject, false);
708    }
709
710    /**
711     * Adds a reference in the policy to a Subject defined at the realm.
712     *
713     *
714     * @param token SSOToken of the user adding the subject
715     * @param subjectName name of the Subject as defined at the realm
716     * @param realmName name of the realm in which the subject is defined
717     *
718     * @exception NameAlreadyExistsException if a Subject with the given name
719     *          already exists in the policy
720     * @exception InvalidNameException if the subject name is invalid 
721     *         or the subject is not found at the realm
722     * @exception SSOException if the SSO token is invalid
723     * @exception PolicyException if the subject could not be added 
724     *               for any other reason
725     *
726     * @supported.api
727     *
728     */
729    public void addRealmSubject(SSOToken token, String subjectName, 
730            String realmName, boolean exclusive) 
731            throws NameAlreadyExistsException, InvalidNameException,
732            PolicyException, SSOException {
733        PolicyManager pm = new PolicyManager(token, realmName);
734        SubjectTypeManager stm = pm.getSubjectTypeManager();
735        addRealmSubject(subjectName, stm, exclusive);
736    }
737
738    /**
739     * Adds a reference in the policy to a Subject defined at the realm.
740     *
741     *
742     * @param subjectName name of the Subject as defined at the realm
743     * @param stm <code>SubjectTypeManager<code> of the realm.
744     *       You have to pass the SubjectTypeManager of realm in which 
745     *       you would save the policy. Trying to save the policy at 
746     *       a different realm would throw PolicyException.
747     *
748     * @exception NameAlreadyExistsException if a Subject with the given name
749     *          already exists in the policy
750     * @exception InvalidNameException if the subject name is invalid 
751     *         or the subject is not found at the realm
752     * @exception SSOException if the SSO token is invalid
753     * @exception PolicyException if the subject could not be added 
754     *               for any other reason
755     *
756     * @supported.api
757     *
758     */
759    public void addRealmSubject(String subjectName, SubjectTypeManager stm,
760            boolean exclusive) 
761            throws NameAlreadyExistsException, InvalidNameException,
762            PolicyException, SSOException {
763        String realmName = stm.getPolicyManager().getOrganizationDN();
764        realmName = LDAPUtils.formatToRFC(realmName);
765        if ((subjectRealm != null) && !subjectRealm.equals(realmName)) {
766            String[] objs = {realmName, subjectRealm};
767            if (DEBUG.messageEnabled()) {
768                DEBUG.message("Policy.addRealmSubject():can not add"
769                        + " realm subject " + subjectName
770                        + " , from realm : " + realmName
771                        + " , policy already has subject from different realm:"
772                        + subjectRealm);
773            }
774
775            throw (new InvalidNameException(ResBundleUtils.rbName,
776                "policy_realms_do_not_match", objs, null, realmName, 
777                PolicyException.POLICY));
778        }
779        if (subjectRealm == null) {
780            subjectRealm = realmName;
781        }
782        /**
783         *  would result in NameNotFoundException if the subject does not exist
784         *  we would propogate the exception without catching
785         */
786        stm.getSubjectByName(subjectName); 
787
788        users.addSubject(subjectName, stm.getSharedSubject(subjectName),
789                exclusive);
790
791        if (DEBUG.messageEnabled()) {
792            DEBUG.message("Policy.addRealmSubject():added "
793                    + " realm subject " + subjectName
794                    + " , from realm : " + realmName);
795        }
796    }
797
798    /**
799     * Adds a new policy subject.
800     * The policy will apply to a user if he is a member of 
801     * any normal (non exclusive) subject  in the policy
802     * or not a member of any exclusive subject in the policy.
803     *
804     * @param name name of the Subject instance 
805     * @param subject Subject object to be added to the policy
806     *
807     * @param exclusive boolean flag indicating whether the subject 
808     *        is to be exclusive subject. If subject is exclusive, 
809     *        policy applies to users who are not members of the 
810     *        subject. Otherwise, policy applies to members of the subject.
811     *
812     * @exception NameAlreadyExistsException if a Subject with the given name
813     *          already exists
814     * @exception InvalidNameException if the subject name is invalid
815     *
816     * @supported.api
817     *
818     */
819    public void addSubject(String name, Subject subject, boolean exclusive) 
820            throws NameAlreadyExistsException, InvalidNameException {
821        users.addSubject(name, subject, exclusive);
822    }
823
824    /**
825     * Replaces an existing subject with the same name by the
826     * current one. If a subject with the same name does not exist,
827     * it will be added.
828     * The subject is replaced as a normal (non exclusive) subject.
829     * So, policy will apply to members of the subject.
830     * The policy will apply to a user if he is a member of 
831     * any normal (non exclusive) subject subject in the policy 
832     * or not a member of any exclusive subject subject in the policy.
833     *
834     * @param name name of the Subject instance 
835     * @param subject Subject that will replace an existing Subject
836     *        with the same name
837     *
838     * @exception NameNotFoundException if a Subject instance
839     *        with the given name is not present
840     *
841     * @supported.api
842     *
843     */
844    public void replaceSubject(String name, Subject subject) 
845            throws NameNotFoundException {
846        users.replaceSubject(name, subject, false);
847    }
848
849    /**
850     * Replaces an existing subject with the same name by the
851     * current one. If a subject with the same name does not exist,
852     * it will be added.
853     * The policy will apply to a user if he is a member of 
854     * any normal (non exclusive) subject in the policy 
855     * or not a member of any exclusive subject in the policy.
856     *
857     * @param name name of the Subject instance 
858     * @param subject Subject that will replace an existing Subject
859     * with the same name
860     *
861     * @param exclusive boolean flag indicating whether the subject 
862     *        is to be exclusive subject. If subject is exclusive, 
863     *        policy applies to users who are not members of the 
864     *        subject. Otherwise, policy applies to members of the subject.
865     *
866     * @exception NameNotFoundException if a Subject instance
867     *        with the given name is not present
868     *
869     * @supported.api
870     *
871     */
872    public void replaceSubject(String name, Subject subject, boolean exclusive) 
873            throws NameNotFoundException {
874        users.replaceSubject(name, subject, exclusive);
875    }
876
877    /**
878     * Removes the subject with the given name. 
879     *
880     * @param subjectName name of the Subject
881     *
882     * @return returns the Subject object being removed.
883     *         if not present returns <code>null</code>
884     *
885     * @supported.api
886     *
887     */
888    public Subject removeSubject(String subjectName) {
889        return users.removeSubject(subjectName);
890    }
891
892    /**
893     * Removes the <code>Subject</code> object identified by
894     * object's <code>equals</code> method. If a Subject instance
895     * does not exist, the method will return silently.
896     *
897     * @param subject Subject object that
898     *        will be removed from the user collection
899     *
900     * @supported.api
901     *
902     */
903    public void removeSubject(Subject subject) {
904        String subjectName = users.getSubjectName(subject);
905        if (subjectName != null) {
906            removeSubject(subjectName);
907        }
908    }
909
910
911    /**
912     * Checks if the subject is exclusive. 
913     * If subject is exclusive, policy applies to users who are not members of
914     * the subject. Otherwise, policy applies to members of the subject.
915     * The policy will apply to a user if he is a member of 
916     * any normal (non exclusive) subject in the policy
917     * or not a member of any exclusive subject in the policy.
918     *
919     * @param subjectName name of the subject 
920     * @return <code>true</code> if the subject is exclusive, <code>false</code>
921     *         otherwise.
922     * @exception NameNotFoundException if the subject with the given
923     *         <code>subjectName</code> does not exist in the policy.
924     *
925     * @supported.api
926     *
927     */
928    public boolean isSubjectExclusive(String subjectName) 
929            throws NameNotFoundException {
930        return users.isSubjectExclusive(subjectName);
931    }
932
933    /**
934     * Checks if the subjectName is a reference to a Subject 
935     * defined at the realm
936     *
937     * @param subjectName name of the subject 
938     * @return <code>true</code> if the subject is a reference to a 
939     *         Subject defined at the realm, <code>false</code>
940     *        otherwise.
941     * @exception NameNotFoundException if the subject with the given
942     *         <code>subjectName</code> does not exist in the policy.
943     *
944     * @supported.api
945     *
946     */
947    public boolean isRealmSubject(String subjectName) 
948            throws NameNotFoundException {
949        return users.isRealmSubject(subjectName);
950    }
951
952    /**
953     * Returns a <code>Referrals</code> object that contains
954     * a set of <code>Referral</code> instances for whom the
955     * policy is applied.
956     *
957     * @return Referrals object of the policy
958     */
959    Referrals getReferrals() {
960        return (referrals);
961    }
962
963    /**
964     * Get the <code>Set</code> of referral names associated with the policy.
965     *
966     * @return <code>Set</code> of referral names
967     *
968     * @supported.api
969     *
970     */
971    public Set getReferralNames() {
972        return referrals.getReferralNames();
973    }
974
975    /**
976     * Gets the Referral object identified by name.
977     *
978     * @param referralName name of referral.
979     *
980     * @return <code>Referral</code> object
981     *
982     * @exception NameNotFoundException if a Referral with the given name
983     * does not exist
984     *
985     * @supported.api
986     *
987     */
988    public Referral getReferral(String referralName) throws 
989        NameNotFoundException 
990    {
991        return referrals.getReferral(referralName);
992    }
993
994    /**
995     * Adds a new policy referral.
996     *
997     * @param name name of the <code>Referral</code> instance 
998     * @param referral <code>Referral</code> object to be added to the policy
999     *
1000     * @exception NameAlreadyExistsException if a Referral with the given name
1001     *            already exists
1002     * @exception InvalidNameException if the referral name is invalid
1003     *
1004     * @supported.api
1005     *
1006     */
1007    public void addReferral(String name, Referral referral) 
1008            throws NameAlreadyExistsException, InvalidNameException {
1009        referrals.addReferral(name, referral);
1010    }
1011
1012    /**
1013     * Replaces an existing referral with the same name by the
1014     * current one. If a referral with the same name does not exist,
1015     * it will be added.
1016     *
1017     * @param name name of the <code>Referral</code> instance 
1018     * @param     referral <code>Referral</code> that will replace an existing 
1019     *            Referral with the same name
1020     *
1021     * @exception NameNotFoundException if a Referral instance
1022     *            with the given name is not present
1023     *
1024     * @supported.api
1025     *
1026     */
1027    public void replaceReferral(String name, Referral referral) 
1028            throws NameNotFoundException {
1029        referrals.replaceReferral(name, referral);
1030    }
1031
1032    /**
1033     * Removes the referral with the given name. 
1034     *
1035     * @param referralName name of the <code>Referral</code>
1036     *
1037     * @return returns the <code>Referral</code> object being removed;
1038     *         if not present returns <code>null</code>
1039     *
1040     * @supported.api
1041     *
1042     */
1043    public Referral removeReferral(String referralName) {
1044        return referrals.removeReferral(referralName);
1045    }
1046    /**
1047     * Removes the <code>Referral</code> object identified by
1048     * object's <code>equals</code> method. If a Referral instance
1049     * does not exist, the method will return silently.
1050     *
1051     * @param referral Referral object that will be removed 
1052     *
1053     * @supported.api
1054     *
1055     */
1056    public void removeReferral(Referral referral) {
1057        String referralName = referrals.getReferralName(referral);
1058        if (referralName != null) {
1059            removeReferral(referralName);
1060        }
1061    }
1062
1063
1064    /**
1065     * Returns a <code>Conditions</code> object that contains
1066     * a set of <code>Condition</code> objects that apply
1067     * to the policy
1068     *
1069     * @return <code>Conditions</code> object of the policy
1070     */
1071    Conditions getConditions() {
1072        return (conditions);
1073    }
1074
1075    /**
1076     * Get the set of condition names associated with the policy.
1077     *
1078     * @return <code>Set</code> of condition names
1079     *
1080     * @supported.api
1081     *
1082     */
1083    public Set getConditionNames() {
1084        return conditions.getConditionNames();
1085    }
1086
1087    /**
1088     * Gets the condition object identified by name.
1089     *
1090     * @param condition name of condition.
1091     *
1092     * @return <code>Condition</code> object.
1093     *
1094     * @exception NameNotFoundException if a Condition with the given name
1095     * does not exist.
1096     *
1097     * @supported.api
1098     *
1099     */
1100    public Condition getCondition(String condition) throws 
1101        NameNotFoundException 
1102    {
1103        return conditions.getCondition(condition);
1104    }
1105
1106    /**
1107     * Adds a new policy condition.
1108     *
1109     * @param name name of the Condition instance 
1110     * @param condition Condition object to be added to the policy
1111     *
1112     * @exception NameAlreadyExistsException if a Condition with the given name
1113     *            already exists
1114     * @exception InvalidNameException if the condition name is invalid
1115     *
1116     * @supported.api
1117     *
1118     */
1119    public void addCondition(String name, Condition condition) 
1120            throws NameAlreadyExistsException, InvalidNameException {
1121        conditions.addCondition(name, condition);
1122    }
1123
1124    /**
1125     * Replaces an existing condition with the same name by the
1126     * current one. If a condition with the same name does not exist,
1127     * it will be added.
1128     *
1129     * @param name name of the <code>Condition</code> instance 
1130     * @param     condition <code>Condition</code> that will replace an 
1131     *            existing Condition with the same name
1132     *
1133     * @exception NameNotFoundException if a Condition instance
1134     *            with the given name is not present
1135     *
1136     * @supported.api
1137     *
1138     */
1139    public void replaceCondition(String name, Condition condition) 
1140            throws NameNotFoundException {
1141        conditions.replaceCondition(name, condition);
1142    }
1143
1144    /**
1145     * Removes the condition with the given name. 
1146     *
1147     * @param condition name of the <code>Condition</code>
1148     *
1149     * @return returns the Condition object being removed;
1150     *         if not present returns <code>null</code>
1151     *
1152     * @supported.api
1153     *
1154     */
1155    public Condition removeCondition(String condition) {
1156        return conditions.removeCondition(condition);
1157    }
1158
1159    /**
1160     * Removes the <code>Condition</code> object identified by
1161     * object's <code>equals</code> method. If a condition instance
1162     * does not exist, the method will return silently.
1163     *
1164     * @param condition Condition object that will be removed 
1165     *
1166     * @supported.api
1167     *
1168     */
1169    public void removeCondition(Condition condition) {
1170        String conditionName = conditions.getConditionName(condition);
1171        if (conditionName != null) {
1172            removeCondition(conditionName);
1173        }
1174    }
1175
1176
1177    /**
1178     * Returns a <code>ResponseProviders</code> object that contains
1179     * a set of <code>ResponseProvider</code> objects that apply
1180     * to the policy
1181     *
1182     * @return <code>ResponseProviders</code> object found in the policy
1183     */
1184    ResponseProviders getResponseProviders() {
1185        return (respProviders);
1186    }
1187
1188    /**
1189     * Get a <code>Set</code> of <code>String</code> objects representing
1190     * the responseProvider names associated with the policy.
1191     *
1192     * @return <code>Set</code> of responseProvider names
1193     *
1194     *
1195     */
1196    public Set getResponseProviderNames() {
1197        return respProviders.getResponseProviderNames();
1198    }
1199
1200    /**
1201     * Gets the <code>ResponseProvider</code> object identified by name.
1202     *
1203     * @param respProvider name of <code>ResponseProvider</code>.
1204     *
1205     * @return <code>ResponseProvider</code> object.
1206     *
1207     * @exception NameNotFoundException if a ResponseProvider with the given 
1208     *            name does not exist.
1209     *
1210     *
1211     */
1212    public ResponseProvider getResponseProvider(String respProvider) 
1213        throws NameNotFoundException {
1214        return respProviders.getResponseProvider(respProvider);
1215    }
1216
1217    /**
1218     * Adds a new <code>ResponseProvider</code> to the policy.
1219     *
1220     * @param name name of the <code>ResponseProvider</code> instance 
1221     * @param respProvider <code>ResponseProvider</code> object to be added to 
1222     *            the policy
1223     *
1224     * @exception NameAlreadyExistsException if a ResponseProvider with the 
1225     *            given name already exists
1226     * @exception InvalidNameException if the <code>respProvider</code>
1227     *             name is invalid
1228     *
1229     *
1230     */
1231    public void addResponseProvider(String name, ResponseProvider respProvider) 
1232            throws NameAlreadyExistsException {
1233        respProviders.addResponseProvider(name, respProvider);
1234    }
1235
1236    /**
1237     * Replaces an existing <code>ResponseProvider</code> with the same name 
1238     * by the current one. If a respProvider with the same name does not exist,
1239     * it will be added.
1240     *
1241     * @param name name of the ResponseProvider instance 
1242     * @param respProvider ResponseProvider that will replace an existing 
1243     *            ResponseProvider with the same name
1244     *
1245     * @exception NameNotFoundException if a ResponseProvider instance
1246     *            with the given name is not present.
1247     *
1248     *
1249     */
1250    public void replaceResponseProvider(String name, 
1251        ResponseProvider respProvider) throws NameNotFoundException {
1252        respProviders.replaceResponseProvider(name, respProvider);
1253    }
1254
1255    /**
1256     * Removes the <code>ResponseProvider</code> with the given name. 
1257     *
1258     * @param respProvider name of the ResponseProvider
1259     *
1260     * @return returns the ResponseProvider object being removed;
1261     * if not present returns null.
1262     *
1263     *
1264     */
1265    public ResponseProvider removeResponseProvider(String respProvider) {
1266        return respProviders.removeResponseProvider(respProvider);
1267    }
1268
1269    /**
1270     * Removes the <code>ResponseProvider</code> object.
1271     * If a respProvider instance does not exist, the method will 
1272     * return silently.
1273     *
1274     * @param respProvider ResponseProvider object that
1275     * will be removed 
1276     *
1277     *
1278     */
1279    public void removeResponseProvider(ResponseProvider respProvider) {
1280        String respProviderName = respProviders.getResponseProviderName(
1281            respProvider);
1282        if (respProviderName != null) {
1283            removeResponseProvider(respProviderName);
1284        }
1285    }
1286
1287    /**
1288     * Stores the policy object in a persistent data store
1289     * under the organization, sub-organization or a container
1290     * object, specified as a parameter. The organization,
1291     * sub-organization, or the container can be either
1292     * a LDAP distinguished name (<code>dn</code>) or slash "/" separated
1293     * as per SMS. This method
1294     * uses the <code>SSOToken</code> provided to perform the store
1295     * operation, and hence if the single sign token has expired
1296     * <code>SSOException</code> will be thrown, and if the
1297     * user does not have the required privileges
1298     * <code>NoPermissionException</code> exception will be thrown.
1299     * <p>
1300     * If a policy with the same name exists for the organization
1301     * the method will throw <code>NameAlreadyExistsException</code>.
1302     * And if the organization name does not exist, the method
1303     * will throw <code>NameNotFoundException</code>.
1304     *
1305     * @param token  SSO token of the user managing policy
1306     * @param name name of the organization, sub-organization or
1307     * a container in which the policy will be stored.
1308     *
1309     * @exception SSOException invalid or expired single-sign-on token
1310     * @exception NoPermissionException user does not have sufficient
1311     * privileges to add policy
1312     *
1313     * @exception NameAlreadyExistsException a policy with the same
1314     * name already exists
1315     *
1316     * @exception NameNotFoundException the given organization name
1317     * does not exist
1318     *
1319     * @exception PolicyException for any other abnormal condition
1320     *
1321     * @supported.api
1322     *
1323     */
1324    public void store(SSOToken token, String name) throws SSOException,
1325        NoPermissionException, NameAlreadyExistsException,
1326        NameNotFoundException, PolicyException {
1327        PolicyManager pm = new PolicyManager(token, name);
1328        pm.addPolicy(this);
1329    }
1330
1331    /**
1332     * Checks if two policy objects are equal.
1333     * This method does not check the policy name and description 
1334     * for equality.
1335     *
1336     * @param obj object againt which the policy object
1337     * will be checked for equality
1338     *
1339     * @return <code>true</code> if policies are equal,
1340     * <code>false</code> otherwise.
1341     */
1342    public boolean equals(Object obj) {
1343        if (obj instanceof Policy) {
1344            Policy p = (Policy) obj;
1345            if (rules.equals(p.rules) && users.equals(p.users)
1346                        && referrals.equals(p.referrals)
1347                        && respProviders.equals(p.respProviders)
1348                        && conditions.equals(p.conditions) ) {
1349                return (true);
1350            }
1351        }
1352        return (false);
1353    }
1354
1355    /**
1356     * Creates and returns a copy of this object. The returned
1357     * <code>Policy</code> object will have the same policy
1358     * name, rules, subjects, referrals and conditions
1359     * such that <code>x.clone().equals(x)</code> will be
1360     * <code>true</code>. However <code>x.clone()</code>
1361     * will not be the same as <code>x</code>, i.e.,
1362     * <code>x.clone() != x</code>.
1363     *
1364     * @return a copy of this object
1365     */
1366    public Object clone() {
1367        Policy answer = null;
1368        try {
1369            answer = (Policy) super.clone();
1370        } catch (CloneNotSupportedException se) {
1371            answer = new Policy();
1372        }
1373        // Copy state variables
1374        answer.origPolicyName = origPolicyName;
1375        answer.policyName = policyName;
1376        answer.description = description;
1377        answer.active = active;
1378
1379        // Copy rules
1380        answer.rules = new HashMap();
1381        Iterator items = rules.keySet().iterator();
1382        while (items.hasNext()) {
1383            Object o = items.next();
1384            Rule rule = (Rule) rules.get(o);
1385            answer.rules.put(o, rule.clone());
1386        }
1387
1388        // Copy subjects
1389        answer.users = (Subjects) users.clone();
1390
1391        // Copy referrals
1392        answer.referrals = (Referrals) referrals.clone();
1393
1394        // Copy responseProviders
1395        answer.respProviders = (ResponseProviders) respProviders.clone();
1396
1397        // Copy conditions
1398        answer.conditions = (Conditions) conditions.clone();
1399
1400        return (answer);
1401    }
1402
1403    /**
1404     * Returns the serialized policy in XML 
1405     * @return serialized policy in XML
1406     *
1407     * @supported.api
1408     *
1409     */
1410    public String toXML() {
1411        return toXML(true);
1412    }
1413
1414    public String toXML(boolean withHeader) {
1415        StringBuilder answer = new StringBuilder(200);
1416
1417        if (withHeader) {
1418            answer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1419        }
1420
1421        answer.append("<Policy name=\"");
1422        answer.append(XMLUtils.escapeSpecialCharacters(policyName));
1423        if ((description != null) && (description.length() > 0)) {
1424            answer.append("\" description=\"");
1425            answer.append(XMLUtils.escapeSpecialCharacters(description));
1426        }
1427
1428        if ((createdBy != null) && (createdBy.length() > 0)) {
1429            answer.append("\" ")
1430                .append(PolicyManager.CREATED_BY_ATTRIBUTE)
1431                .append("=\"")
1432                .append(XMLUtils.escapeSpecialCharacters(createdBy));
1433        }
1434        if ((lastModifiedBy != null) && (lastModifiedBy.length() > 0)) {
1435            answer.append("\" ")
1436                .append(PolicyManager.LAST_MODIFIED_BY_ATTRIBUTE)
1437                .append("=\"")
1438                .append(XMLUtils.escapeSpecialCharacters(lastModifiedBy));
1439        }
1440        if (creationDate > 0) {
1441            answer.append("\" ")
1442                .append(PolicyManager.CREATION_DATE_ATTRIBUTE)
1443                .append("=\"")
1444                .append(XMLUtils.escapeSpecialCharacters(
1445                    Long.toString(creationDate)));
1446        }
1447        if (lastModifiedDate > 0) {
1448            answer.append("\" ")
1449                .append(PolicyManager.LAST_MODIFIED_DATE_ATTRIBUTE)
1450                .append("=\"")
1451                .append(XMLUtils.escapeSpecialCharacters(
1452                    Long.toString(lastModifiedDate)));
1453        }
1454
1455        answer.append("\" referralPolicy=\"").append(referralPolicy);
1456        answer.append("\" active=\"").append(active);
1457        answer.append("\" >");
1458        for (Iterator i = getRuleNames().iterator(); i.hasNext(); ) {
1459            String ruleName = (String)i.next();
1460            try {
1461                Rule rule = getRule(ruleName);
1462                answer.append(rule.toXML());
1463            } catch (Exception e) {
1464                // Ignore the exception
1465                DEBUG.error("Error in policy.toXML():" + e.getMessage());
1466            }
1467        }
1468
1469        if (!this.referralPolicy) {
1470            // Add the users
1471            if ( !(users.getSubjectNames().isEmpty()) ) {
1472                answer.append(users.toXML());
1473            }
1474
1475            // Add the conditions
1476            if ( !(conditions.getConditionNames().isEmpty()) ) {
1477                answer.append(conditions.toXML());
1478            }
1479            // Add the responseProviders
1480            if ( !(respProviders.getResponseProviderNames().isEmpty()) ) {
1481                answer.append(respProviders.toXML());
1482            }
1483        } else {
1484            // Add the referrals
1485            if ( !(referrals.getReferralNames().isEmpty()) ) {
1486                answer.append(referrals.toXML());
1487            }
1488        }
1489
1490        answer.append("\n").append("</Policy>");
1491        return (answer.toString());
1492    }
1493
1494    /**
1495     * Gets string representation of the policy object.
1496     *
1497     * @return XML string representation of the policy object
1498     *
1499     * @supported.api
1500     */
1501    public String toString() {
1502        return (toXML());
1503    }
1504
1505    /**
1506     * Checks for the char <code>c</code> in the String
1507     * @param name String in which the character needs to be checked for.
1508     * @param c <code>char</code> which needs to be checked.
1509     * @exception InvalidNameException if <code>c</code> does not occur
1510     *            anywhere in <code>name</code>.
1511     */
1512    static void checkForCharacter(String name, char c)
1513        throws InvalidNameException {
1514        if (name.indexOf(c) != -1) {
1515            Character objs[] =  { new Character(c) };
1516            throw (new InvalidNameException(ResBundleUtils.rbName,
1517                "invalid_char_in_name", objs, name,
1518                PolicyException.POLICY));
1519        }
1520    }
1521
1522    /** 
1523     * Gets policy decision 
1524     * @param token sso token identifying the user for who the policy has to 
1525     *        be evaluated.
1526     * @param resourceTypeName resourceType name
1527     * @param resourceName resourceName
1528     * @param actionNames a set of action names for which policy results
1529     *        are to be evaluated. Each element of the set should be a
1530     *        String
1531     * @param envParameters a  <code>Map</code> of environment parameters
1532     *        Each key of the <code>Map</code> is a String valued parameter name
1533     *        Each value of the map is a <code>Set</code> of String values
1534     * @return a <code>PolicyDecision</code>
1535     * @exception NameNotFoundException if the action name or resource name
1536     *         is not found
1537     * @exception SSOException if token is invalid
1538     * @exception PolicyException for any other exception condition
1539     */
1540   public PolicyDecision getPolicyDecision(SSOToken token, 
1541            String resourceTypeName,String resourceName, Set actionNames, 
1542            Map envParameters) throws SSOException, NameNotFoundException, 
1543            PolicyException 
1544   {
1545
1546        PolicyDecision policyDecision = new PolicyDecision();
1547
1548        ServiceTypeManager stm = ServiceTypeManager.getServiceTypeManager();
1549        ServiceType resourceType 
1550                = stm.getServiceType(resourceTypeName);
1551
1552        /**
1553         * get the evaluation order that is likely to be least expensive 
1554         * in terms of cpu.
1555         */
1556        if (token != null) {
1557            evaluationOrder = getEvaluationOrder(token);
1558        } else {
1559            evaluationOrder = SUBJECTS_RULES_CONDITIONS;
1560        }
1561        if (DEBUG.messageEnabled()) {
1562            DEBUG.message("Policy " + getName() 
1563                + " is Using Policy evaluation order :" + evaluationOrder);
1564        }
1565        if (isReferralPolicy() && !referrals.isEmpty()) {
1566
1567            //process referrals irrespective subjects and conditions
1568            PolicyDecision referralDecision 
1569                    = referrals.getPolicyDecision(token, 
1570                    resourceTypeName, resourceName, actionNames, 
1571                    envParameters);
1572            if (referralDecision != null) {
1573                PolicyEvaluator.mergePolicyDecisions(
1574                        resourceType, referralDecision, policyDecision);
1575            } 
1576            if (DEBUG.messageEnabled()) {
1577                String tokenPrincipal = 
1578                        (token != null) ? token.getPrincipal().getName()
1579                        : PolicyUtils.EMPTY_STRING;
1580                DEBUG.message(
1581                    new StringBuffer("at Policy.getPolicyDecision()")
1582                    .append(" after processing referrals only:")
1583                    .append(" principal, resource name, action names,")
1584                    .append(" policyName, referralResults = ")
1585                    .append(tokenPrincipal) .append(",  ")
1586                    .append(resourceName) .append(",  ")
1587                    .append(actionNames) .append(",  ")
1588                    .append(this.getName()).append(",  ")
1589                    .append(referralDecision).toString());
1590            }
1591        } else if (evaluationOrder == SUBJECTS_CONDITIONS_RULES) {
1592            if (DEBUG.messageEnabled()) {
1593                DEBUG.message("Using policy evaluation order:" 
1594                        + "SUBJECTS_CONDITIONS_RULES");
1595            }
1596            getPolicyDecisionSCR(token, resourceType, resourceName, 
1597                    actionNames, envParameters, policyDecision);
1598        } else if (evaluationOrder == CONDITIONS_SUBJECTS_RULES) {
1599            if (DEBUG.messageEnabled()) {
1600                DEBUG.message("Using policy evaluation order:" 
1601                        + "CONDITIONS_SUBJECTS_RULES");
1602            }
1603            getPolicyDecisionCSR(token, resourceType, resourceName, 
1604                    actionNames, envParameters, policyDecision);
1605        }  else if (evaluationOrder == RULES_SUBJECTS_CONDITIONS) {
1606            if (DEBUG.messageEnabled()) {
1607                DEBUG.message("Using policy evaluation order:" 
1608                        + "RULES_SUBJECTS_CONDITIONS");
1609            }
1610            getPolicyDecisionRSC(token, resourceType, resourceName, 
1611                    actionNames, envParameters, policyDecision);
1612        }  else if (evaluationOrder == RULES_CONDITIONS_SUBJECTS) {
1613            if (DEBUG.messageEnabled()) {
1614                DEBUG.message("Using policy evaluation order:" 
1615                        + "RULES_CONDITIONS_SUBJECTS");
1616            }
1617            getPolicyDecisionRCS(token, resourceType, resourceName, 
1618                    actionNames, envParameters, policyDecision);
1619        }  else if (evaluationOrder == SUBJECTS_RULES_CONDITIONS) {
1620            if (DEBUG.messageEnabled()) {
1621                DEBUG.message("Using policy evaluation order:" 
1622                        + "SUBJECTS_RULES_CONDITIONS");
1623            }
1624            getPolicyDecisionSRC(token, resourceType, resourceName, 
1625                    actionNames, envParameters, policyDecision);
1626        }  else if (evaluationOrder == CONDITIONS_RULES_SUBJECTS) {
1627            if (DEBUG.messageEnabled()) {
1628                DEBUG.message("Using policy evaluation order:" 
1629                        + "CONDITIONS_RULES_SUBJECTS");
1630            }
1631            getPolicyDecisionCRS(token, resourceType, resourceName, 
1632                    actionNames, envParameters, policyDecision);
1633        }  else { //default:RULES_CONDITIONS_SUBJECTS
1634            if (DEBUG.messageEnabled()) {
1635                DEBUG.message("Using default policy evaluation order:" 
1636                        + "RULES_CONDITIONS_SUBJECTS");
1637            }
1638            getPolicyDecisionRCS(token, resourceType, resourceName, 
1639                    actionNames, envParameters, policyDecision);
1640        }
1641
1642        if (DEBUG.messageEnabled()) {
1643            String tokenPrincipal = 
1644                    (token != null) ? token.getPrincipal().getName()
1645                    : PolicyUtils.EMPTY_STRING;
1646            DEBUG.message(
1647                new StringBuffer("at Policy.getPolicyDecision()")
1648                .append(" principal, resource name, action names,")
1649                .append(" policyName, policyDecision = ")
1650                .append(tokenPrincipal) .append(",  ")
1651                .append(resourceName) .append(",  ")
1652                .append(actionNames) .append(",  ")
1653                .append(this.getName()).append(",  ")
1654                .append(policyDecision).toString());
1655        }
1656        Map actionDecisionMap = policyDecision.getActionDecisions();
1657        if (actionDecisionMap != null && !actionDecisionMap.isEmpty())
1658        {
1659            Collection actionDecisions = null;
1660            if ((actionDecisions = actionDecisionMap.values()) != null &&
1661                !actionDecisions.isEmpty()) {
1662                Iterator it = actionDecisions.iterator();
1663                while (it.hasNext()) {
1664                    Set actionValues = ((ActionDecision)it.next()).getValues();
1665                    if (actionValues != null && !actionValues.isEmpty())
1666                        { // put the response Attrs in the PolicyDecision
1667                        Map responseAttributes = 
1668                           respProviders.getResponseProviderDecision(token, 
1669                                envParameters);
1670                            policyDecision.setResponseAttributes(
1671                                responseAttributes);
1672                        break;/**
1673                               * even if one action Value found, set the 
1674                               * resp attributes
1675                               */
1676                    }
1677                }
1678            }
1679        }
1680        return policyDecision;
1681    }
1682
1683    /** Gets matched rule results given resource type, resource name and 
1684     *  action names
1685     *  @param resourceType resource type(<code>ServiceType</code> of resource
1686     *  @param resourceName resource name for which to get action values
1687     *  @param actionNames action names for which to get values
1688     *  @return <code>Map</code> of action values keyed by action names
1689     *  @exception NameNotFoundException
1690     */
1691    private Map getMatchedRuleResults(ServiceType resourceType,
1692            String resourceName, Set actionNames) throws NameNotFoundException {
1693        String resourceTypeName = resourceType.getName();
1694        Map answer = null;
1695        StringBuilder cacheKeyBuffer = new StringBuilder(100);
1696        String cacheKey = cacheKeyBuffer.append(resourceTypeName)
1697                .append(resourceName).append(actionNames).toString();
1698        answer = (Map) matchRulesResultsCache.get(cacheKey);
1699        if ( answer == null ) {
1700            answer = new HashMap();
1701
1702            //Process rules
1703            Iterator ruleIterator = rules.values().iterator();
1704            while (ruleIterator.hasNext()) {
1705                Rule rule = (Rule) ruleIterator.next();
1706                Map actionResults = rule.getActionValues(resourceTypeName, 
1707                        resourceName, actionNames);
1708                PolicyUtils.appendMapToMap(actionResults, answer);
1709            }
1710
1711            Iterator actions = answer.keySet().iterator();
1712            while ( actions.hasNext() ) {
1713                String action = (String) actions.next();
1714                Set actionValues = (Set) answer.get(action);
1715                if ( actionValues.size() == 2 ) {
1716                    ActionSchema actionSchema = null;
1717                    AttributeSchema.Syntax actionSyntax = null;
1718                    try {
1719                        actionSchema = resourceType.getActionSchema(action);
1720                        actionSyntax = actionSchema.getSyntax();
1721                    } catch(InvalidNameException e) {
1722                        PolicyManager.debug.error(
1723                            "can not find action schmea for action = " 
1724                            + action, e );
1725                    }
1726                    if (AttributeSchema.Syntax.BOOLEAN.equals(
1727                            actionSyntax)) {
1728                        String trueValue = actionSchema.getTrueValue();
1729                        actionValues.remove(trueValue);
1730                    }
1731                }
1732            }
1733
1734            // Add to cache
1735            matchRulesResultsCache.put(cacheKey, answer);
1736        }
1737        return cloneRuleResults(answer);
1738    }
1739
1740    /**Gets resource names that are exact matches, sub resources or 
1741     * wild card matches of argument resource name.
1742     * To determine whether to include a
1743     * resource name of a resource,  we compare argument resource name and 
1744     * policy resource name, treating wild characters in the policy 
1745     * resource name as wild. If the comparsion resulted in EXACT_MATCH,
1746     * WILD_CARD_MATCH or SUB_RESOURCE_MATCH, the resource result would be
1747     * included.
1748     *
1749     * @param token sso token
1750     * @param serviceTypeName service type name
1751     * @param resourceName resource name
1752     * @param followReferrals indicates whether to follow the referrals to
1753     *                        compute the resources
1754     * @return resource names that match to be exact match, sub 
1755     *         resource match or wild card match of the argument
1756     *         resourceName
1757     *
1758     * @exception PolicyException
1759     * @exception SSOException
1760     *
1761     * @see ResourceMatch#EXACT_MATCH
1762     * @see ResourceMatch#SUB_RESOURCE_MATCH
1763     * @see ResourceMatch#WILDCARD_MATCH
1764     *
1765     */
1766    Set getResourceNames(SSOToken token, String serviceTypeName,
1767            String resourceName, boolean followReferrals) 
1768            throws PolicyException, SSOException {
1769        Set resourceNames = new HashSet();
1770        ServiceType st = ServiceTypeManager.getServiceTypeManager()
1771                .getServiceType( serviceTypeName);
1772        Iterator ruleIterator = rules.values().iterator();
1773        while (ruleIterator.hasNext()) {
1774            Rule rule = (Rule) ruleIterator.next();
1775            if (rule.getServiceType().getName().equals(serviceTypeName)) {
1776                String ruleResource = rule.getResourceName();
1777                ResourceMatch resourceMatch = st.compare(resourceName,
1778                        ruleResource, true); // interpret wild char
1779                if (resourceMatch.equals(ResourceMatch.SUB_RESOURCE_MATCH)
1780                      || resourceMatch.equals(ResourceMatch.EXACT_MATCH)
1781                      || resourceMatch.equals(ResourceMatch.WILDCARD_MATCH)) {
1782                    resourceNames.add(ruleResource);
1783                } 
1784            if ( DEBUG.messageEnabled() ) {
1785                StringBuilder sb = new StringBuilder(200);
1786                sb.append("at Policy.getResourceNames : ");
1787                sb.append(" for policyName, serviceType, resourceName, ");
1788                sb.append(" ruleResource, resourceMatch :");
1789                sb.append(getName()).append( ",").append( serviceTypeName);
1790                sb.append(",").append(resourceName).append(",");
1791                sb.append(ruleResource).append(",").append(resourceMatch);
1792                DEBUG.message(sb.toString());
1793            }
1794            }
1795        }
1796        if (!resourceNames.isEmpty() && followReferrals) {
1797            Set rResourceNames = referrals.getResourceNames(token, 
1798                    serviceTypeName, resourceName);
1799            resourceNames.addAll(rResourceNames);
1800        }
1801        if ( DEBUG.messageEnabled() ) {
1802            StringBuilder sb = new StringBuilder(200);
1803            sb.append("at Policy.getResourceNames : ");
1804            sb.append(" for policyName, serviceType, resourceName, ");
1805            sb.append(" followReferral, resourceNames :");
1806            sb.append(getName()).append( ",").append( serviceTypeName);
1807            sb.append(",").append(resourceName).append(",");
1808            sb.append(followReferrals).append(",").append(resourceNames);
1809            DEBUG.message(sb.toString());
1810        }
1811        return resourceNames;
1812    }
1813
1814    /** Gets the resource names of a given serviceType managed by this
1815     *  policy.
1816     *  @param  serviceTypeName name of service type for which to 
1817     *          find resource names
1818     *  @return a set of resource names of serviceTypeName managed
1819     *          by this policy
1820     *  @exception SSOException
1821     *  @exception NameNotFoundException
1822     */
1823    Set getResourceNames(String serviceTypeName) throws SSOException,
1824            NameNotFoundException {
1825        Set resourceNames = new HashSet();
1826        Iterator ruleIterator = rules.values().iterator();
1827        while (ruleIterator.hasNext()) {
1828            Rule rule = (Rule) ruleIterator.next();
1829            String rSvcTypeName = (rule.getServiceType() == null) ?
1830                rule.getServiceTypeName() : rule.getServiceType().getName();
1831            if (rSvcTypeName.equals(serviceTypeName)) {
1832                String ruleResource = rule.getResourceName();
1833                resourceNames.add(ruleResource);
1834            }
1835        }
1836        return resourceNames;
1837    }
1838
1839//    public String getServiceTypeName() {
1840        /* com.iplanet.am.admin.cli uses this method. 
1841         * Need to clean up cli not to use this 
1842         * method. Without this method build breaks - 03/05/02 */
1843 //       return null;
1844  //  }
1845
1846    /**
1847     *  Gets organizations referred to in this policy by OrgReferral(s)
1848     *  defined in this policy.
1849     *  
1850     *  @return names of organization (DNs) of organizations referred
1851     *          to in this policy via <code>OrgReferral</code>(s) defined in 
1852     *          this policy.
1853     *          Please note that <code>PeerOrgReferral</code> and 
1854     *          <code>SubOrgReferral</code> extend <code>OrgReferral</code> 
1855     *          and hence qualify as OrgReferral.
1856     *  @exception PolicyException
1857     */
1858    Set getReferredToOrganizations() throws PolicyException {
1859        Set referredToOrgs = new HashSet();
1860        Iterator referralNames = referrals.getReferralNames().iterator();
1861        while ( referralNames.hasNext() ) {
1862            String referralName = (String) referralNames.next();
1863            Referral referral = (Referral) referrals.getReferral(referralName);
1864            if ( referral instanceof OrgReferral ) {
1865                Set values = referral.getValues();
1866                if ( (values != null) && (!values.isEmpty()) ) {
1867                    String orgName = (String) values.iterator().next();
1868                    referredToOrgs.add(orgName.toLowerCase());
1869                }
1870            }
1871        }
1872        return referredToOrgs;
1873    }
1874
1875    /** Sets time to live for Subjects result. 
1876     *  @param ttl time to live for Subjects result
1877     */
1878    void setSubjectsResultTtl(long ttl) {
1879        users.setResultTtl(ttl);
1880    }
1881
1882
1883    /**
1884     * validates the String <code>name</code>.
1885     * @param name String to be validated.
1886     * @exception throws InvalidNameException is name is null or
1887     *            does contain invalid character "/".
1888     */
1889
1890    private void validateName(String name) throws InvalidNameException {
1891        if ( (name == null) || (name.length() == 0) )  {
1892            DEBUG.message("Invalid policy name:" + name);
1893            throw (new InvalidNameException(ResBundleUtils.rbName,
1894                "null_name", null, "", PolicyException.POLICY));
1895        }
1896    }
1897
1898    /** Gets policy decision  computing Subjects, Conditions and Rules
1899     *  in this order. Referrals in the policy are ignored.
1900     *
1901     * @param token sso token identifying the user for who the policy has to 
1902     *        be evaluated.
1903     * @param resourceType service type
1904     * @param resourceName resource name
1905     * @param actionNames a set of action names for which policy results
1906     *        are to be evaluated. Each element of the set should be a
1907     *        String
1908     * @param envParameters a map of environment parameters
1909     *        Each key of the map is a String valued parameter name
1910     *        Each value of the map is a set of String values
1911     * @param policyDecision a collecting argument. Computed policy decisions
1912     *        in this method are merged to this policy decision
1913     * @return computed and merged policy decision
1914     * @exception NameNotFoundException if the action name or resource name
1915     *         is not found
1916     * @exception SSOException if token is invalid
1917     * @exception PolicyException for any other exception condition
1918     */
1919    private PolicyDecision getPolicyDecisionSCR(SSOToken token, 
1920            ServiceType resourceType,
1921            String resourceName, Set actionNames, Map envParameters,
1922            PolicyDecision policyDecision) 
1923            throws SSOException, NameNotFoundException, PolicyException {
1924        boolean resourceMatched = false;
1925        ConditionDecision conditionDecision = null;
1926        boolean allowedByConditions = false;
1927        boolean allowedBySubjects = false;
1928        Map advicesFromConditions = null;
1929        long conditionsTtl = Long.MIN_VALUE;
1930        long timeToLive = Long.MIN_VALUE;
1931        Map actionResults = null;
1932
1933        if (token != null) {
1934            allowedBySubjects = users.isMember(token);
1935            timeToLive = users.getResultTtl(token);
1936        } else {
1937            allowedBySubjects = true;
1938            timeToLive = Long.MAX_VALUE;
1939        }
1940
1941        if (allowedBySubjects) { //subjects+ 
1942            conditionDecision = conditions.getConditionDecision(
1943                    token, envParameters);
1944            allowedByConditions = conditionDecision.isAllowed();
1945            advicesFromConditions = conditionDecision.getAdvices();
1946            conditionsTtl = conditionDecision.getTimeToLive();
1947            if ( conditionsTtl < timeToLive ) {
1948                timeToLive = conditionsTtl;
1949            }
1950            if (allowedByConditions) { //subjects+, conditions+
1951                actionResults = getMatchedRuleResults(resourceType,
1952                        resourceName, actionNames);
1953                resourceMatched = !actionResults.isEmpty();
1954                if (resourceMatched) { //subjects+,conditions+,resourceMatch+
1955                    Iterator resultActionNames 
1956                            = actionResults.keySet().iterator();
1957                    while ( resultActionNames.hasNext() ) {
1958                        String resultActionName 
1959                                = (String) resultActionNames.next();
1960                        Set resultActionValues 
1961                            = (Set)actionResults.get(resultActionName);
1962
1963                        /*  ActionDecision to include values, no advices
1964                         */
1965                        ActionDecision actionDecision 
1966                                = new ActionDecision(resultActionName,
1967                                resultActionValues, 
1968                                advicesFromConditions, timeToLive);
1969                        policyDecision.addActionDecision(
1970                                actionDecision, resourceType);
1971                    }
1972                } else { // subjects+,conditions+,resourceMatch-
1973                    policyDecision.setTimeToLive(Long.MAX_VALUE);
1974                }
1975            } else { //subjects+,conditions-
1976                //ActionDecision to include advices only
1977
1978                if (!advicesFromConditions.isEmpty()) {
1979                    actionResults = getMatchedRuleResults(resourceType,
1980                            resourceName, actionNames);
1981                    Iterator resultActionNames 
1982                            = actionResults.keySet().iterator();
1983                    while ( resultActionNames.hasNext() ) {
1984                        String resultActionName 
1985                                = (String) resultActionNames.next();
1986
1987                        /*  ActionDecision to include advices, no values
1988                         */
1989                        ActionDecision actionDecision 
1990                                = new ActionDecision(resultActionName,
1991                                Collections.EMPTY_SET, 
1992                                advicesFromConditions, timeToLive);
1993                        policyDecision.addActionDecision(
1994                                actionDecision, resourceType);
1995                    }
1996                } else {
1997                    policyDecision.setTimeToLive(timeToLive);
1998                }
1999            }
2000        } else { //subjects-
2001            policyDecision.setTimeToLive(timeToLive);
2002        }
2003        return policyDecision;
2004    }
2005
2006    /** Gets policy decision  computing Subjects, Rules and Conditions
2007     *  in this order. Referrals in the policy are ignored.
2008     *
2009     * @param token sso token identifying the user for who the policy has to 
2010     *        be evaluated.
2011     * @param resourceType service type
2012     * @param resourceName resourceName
2013     * @param actionNames a set of action names for which policy results
2014     *        are to be evaluated. Each element of the set should be a
2015     *        String
2016     * @param envParameters a map of environment parameters
2017     *        Each key of the map is a String valued parameter name
2018     *        Each value of the map is a set of String values
2019     * @param policyDecision a collecting argument. Computed policy decisions
2020     *        in this method are merged to this policy decision
2021     * @return computed and merged policy decision
2022     * @exception NameNotFoundException if the action name or resource name
2023     *         is not found
2024     * @exception SSOException if token is invalid
2025     * @exception PolicyException for any other exception condition
2026     */
2027    private PolicyDecision getPolicyDecisionSRC(SSOToken token, 
2028            ServiceType resourceType,
2029            String resourceName, Set actionNames, Map envParameters,
2030            PolicyDecision policyDecision) 
2031            throws SSOException, NameNotFoundException, PolicyException {
2032        boolean resourceMatched = false;
2033        ConditionDecision conditionDecision = null;
2034        boolean allowedByConditions = false;
2035        boolean allowedBySubjects = false;
2036        Map advicesFromConditions = null;
2037        long conditionsTtl = Long.MIN_VALUE;
2038        long timeToLive = Long.MIN_VALUE;
2039        Map actionResults = null;
2040
2041        if (token != null) {
2042            allowedBySubjects = users.isMember(token);
2043            timeToLive = users.getResultTtl(token);
2044        } else {
2045            allowedBySubjects = true;
2046            timeToLive = Long.MAX_VALUE;
2047        }
2048        if (allowedBySubjects) { //subjects+
2049            actionResults = getMatchedRuleResults(resourceType,
2050                    resourceName, actionNames);
2051            resourceMatched = !actionResults.isEmpty();
2052            if (resourceMatched) { //subjects+, resourceMatch+
2053                conditionDecision = conditions.getConditionDecision(
2054                        token, envParameters);
2055                allowedByConditions = conditionDecision.isAllowed();
2056                advicesFromConditions = conditionDecision.getAdvices();
2057                conditionsTtl = conditionDecision.getTimeToLive();
2058                if ( conditionsTtl < timeToLive ) {
2059                    timeToLive = conditionsTtl;
2060                }
2061                if (allowedByConditions) { 
2062                    //subjects+, resourceMatch+,conditions+
2063                    Iterator resultActionNames 
2064                            = actionResults.keySet().iterator();
2065                    while ( resultActionNames.hasNext() ) {
2066                        String resultActionName 
2067                                = (String) resultActionNames.next();
2068                        Set resultActionValues 
2069                            = (Set)actionResults.get(resultActionName);
2070
2071                        /*  ActionDecision to include values, no advices
2072                         */
2073                        ActionDecision actionDecision 
2074                                = new ActionDecision(resultActionName,
2075                                resultActionValues, 
2076                                advicesFromConditions, timeToLive);
2077                        policyDecision.addActionDecision(
2078                                actionDecision, resourceType);
2079                    }
2080                } else { //subjects+, resourceMatch+,conditions-
2081                    if (!advicesFromConditions.isEmpty()) {
2082                        Iterator resultActionNames 
2083                                = actionResults.keySet().iterator();
2084                        while ( resultActionNames.hasNext() ) {
2085                            String resultActionName 
2086                                    = (String) resultActionNames.next();
2087
2088                            /*  ActionDecision to include advices, no values
2089                             */
2090                            ActionDecision actionDecision 
2091                                    = new ActionDecision(resultActionName,
2092                                    Collections.EMPTY_SET, 
2093                                    advicesFromConditions, timeToLive);
2094                            policyDecision.addActionDecision(
2095                                    actionDecision, resourceType);
2096                        }
2097                    } else {
2098                        policyDecision.setTimeToLive(timeToLive);
2099                    }
2100                }
2101            } else { //subjects+,resourceMatch-
2102                policyDecision.setTimeToLive(Long.MAX_VALUE);
2103            }
2104        } else { //subjects-
2105            policyDecision.setTimeToLive(timeToLive);
2106        }
2107        return policyDecision;
2108    }
2109
2110    /** Gets policy decision  computing Conditions, Subject and Rules
2111     *  in this order. Referrals in the policy are ignored.
2112     *
2113     * @param token sso token identifying the user for who the policy has to 
2114     *        be evaluated.
2115     * @param resourceType service type
2116     * @param resourceName resourceName
2117     * @param actionNames a set of action names for which policy results
2118     *        are to be evaluated. Each element of the set should be a
2119     *        String
2120     * @param envParameters a map of environment parameters
2121     *        Each key of the map is a String valued parameter name
2122     *        Each value of the map is a set of String values
2123     * @param policyDecision a collecting arugment. Computed policy decisions
2124     *        in this method are merged to this policy decision
2125     * @return computed and merged policy decision
2126     * @exception NameNotFoundException if the action name or resource name
2127     *         is not found
2128     * @exception SSOException if token is invalid
2129     * @exception PolicyException for any other exception condition
2130     */
2131    private PolicyDecision getPolicyDecisionCSR(SSOToken token, 
2132            ServiceType resourceType,
2133            String resourceName, Set actionNames, Map envParameters,
2134            PolicyDecision policyDecision) 
2135            throws SSOException, NameNotFoundException, PolicyException {
2136        boolean resourceMatched = false;
2137        ConditionDecision conditionDecision = null;
2138        boolean allowedByConditions = false;
2139        boolean allowedBySubjects = false;
2140        Map advicesFromConditions = null;
2141        long timeToLive = Long.MIN_VALUE;
2142        long subjectsTtl = Long.MIN_VALUE;
2143        Map actionResults = null;
2144
2145        conditionDecision = conditions.getConditionDecision(
2146                token, envParameters);
2147        allowedByConditions = conditionDecision.isAllowed();
2148        advicesFromConditions = conditionDecision.getAdvices();
2149        timeToLive = conditionDecision.getTimeToLive();
2150        if (allowedByConditions) { //conditions+
2151            allowedBySubjects = users.isMember(token);
2152            subjectsTtl = users.getResultTtl(token);
2153            if (subjectsTtl < timeToLive) {
2154                timeToLive = subjectsTtl;
2155            }
2156            if (allowedBySubjects) { //conditions+, subjects+
2157                actionResults = getMatchedRuleResults(resourceType,
2158                        resourceName, actionNames);
2159                resourceMatched = !actionResults.isEmpty();
2160                if (resourceMatched) { 
2161                    //conditions+, subjects+, resourceMatched+
2162                    Iterator resultActionNames 
2163                            = actionResults.keySet().iterator();
2164                    while ( resultActionNames.hasNext() ) {
2165                        String resultActionName 
2166                                = (String) resultActionNames.next();
2167                        Set resultActionValues 
2168                            = (Set)actionResults.get(resultActionName);
2169
2170                        /*  ActionDecision to include values, no advices
2171                         */
2172                        ActionDecision actionDecision 
2173                                = new ActionDecision(resultActionName,
2174                                resultActionValues, 
2175                                advicesFromConditions, timeToLive);
2176                        policyDecision.addActionDecision(
2177                                actionDecision, resourceType);
2178                    }
2179                } else { //conditions+, subjects+, resourceMatched-
2180                    policyDecision.setTimeToLive(Long.MAX_VALUE);
2181                }
2182            } else { //conditions+,subjects-
2183                policyDecision.setTimeToLive(timeToLive);
2184            }
2185        } else { //conditions-
2186            boolean reportAdvices = false;
2187            if (!advicesFromConditions.isEmpty()) {
2188                reportAdvices = users.isMember(token);
2189                subjectsTtl = users.getResultTtl(token);
2190                if (subjectsTtl < timeToLive) {
2191                    timeToLive = subjectsTtl;
2192                }
2193            }
2194            if (reportAdvices) {
2195                actionResults = getMatchedRuleResults(resourceType,
2196                        resourceName, actionNames);
2197                Iterator resultActionNames 
2198                        = actionResults.keySet().iterator();
2199                while ( resultActionNames.hasNext() ) {
2200                    String resultActionName 
2201                            = (String) resultActionNames.next();
2202
2203                    /*  ActionDecision to include advices, no values
2204                     */
2205                    ActionDecision actionDecision 
2206                            = new ActionDecision(resultActionName,
2207                            Collections.EMPTY_SET, 
2208                            advicesFromConditions, timeToLive);
2209                    policyDecision.addActionDecision(
2210                            actionDecision, resourceType);
2211                }
2212            } else { //no advices to report
2213                policyDecision.setTimeToLive(timeToLive);
2214            }
2215        }
2216        return policyDecision;
2217    }
2218
2219    /** Gets policy decision  computing Conditions, Rules and Subjects
2220     *  in this order. Referrals in the policy are ignored.
2221     *
2222     * @param token sso token identifying the user for who the policy has to 
2223     *        be evaluated.
2224     * @param resourceType service type
2225     * @param resourceName resourceName
2226     * @param actionNames a set of action names for which policy results
2227     *        are to be evaluated. Each element of the set should be a
2228     *        String
2229     * @param envParameters a map of environment parameters
2230     *        Each key of the map is a String valued parameter name
2231     *        Each value of the map is a set of String values
2232     * @param policyDecision a collecting arugment. Computed policy decisions
2233     *        in this method are merged to this policy decision
2234     * @return computed and merged policy decision
2235     * @exception NameNotFoundException if the action name or resource name
2236     *         is not found
2237     * @exception SSOException if token is invalid
2238     * @exception PolicyException for any other exception condition
2239     */
2240    private PolicyDecision getPolicyDecisionCRS(SSOToken token, 
2241            ServiceType resourceType,
2242            String resourceName, Set actionNames, Map envParameters,
2243            PolicyDecision policyDecision) 
2244            throws SSOException, NameNotFoundException, PolicyException {
2245        boolean resourceMatched = false;
2246        ConditionDecision conditionDecision = null;
2247        boolean allowedByConditions = false;
2248        boolean allowedBySubjects = false;
2249        Map advicesFromConditions = null;
2250        long subjectsTtl = Long.MIN_VALUE;
2251        long timeToLive = Long.MIN_VALUE;
2252        Map actionResults = null;
2253
2254        conditionDecision = conditions.getConditionDecision(
2255                token, envParameters);
2256        allowedByConditions = conditionDecision.isAllowed();
2257        advicesFromConditions = conditionDecision.getAdvices();
2258        timeToLive = conditionDecision.getTimeToLive();
2259        actionResults = getMatchedRuleResults(resourceType,
2260                resourceName, actionNames);
2261        if (allowedByConditions) { //conditions+
2262            resourceMatched = !actionResults.isEmpty();
2263            if (resourceMatched) { ///conditions+, resourceMatched+
2264                allowedBySubjects = users.isMember(token);
2265                subjectsTtl = users.getResultTtl(token);
2266                if (subjectsTtl < timeToLive) {
2267                    timeToLive = subjectsTtl;
2268                }
2269                if (allowedBySubjects) {
2270
2271                    //conditions+, resourceMatched+, subjects+
2272                    Iterator resultActionNames 
2273                            = actionResults.keySet().iterator();
2274                    while ( resultActionNames.hasNext() ) {
2275                        String resultActionName 
2276                                = (String) resultActionNames.next();
2277                        Set resultActionValues 
2278                            = (Set)actionResults.get(resultActionName);
2279
2280                        /*  ActionDecision to include values, no advices
2281                         */
2282                        ActionDecision actionDecision 
2283                                = new ActionDecision(resultActionName,
2284                                resultActionValues, 
2285                                advicesFromConditions, timeToLive);
2286                        policyDecision.addActionDecision(
2287                                actionDecision, resourceType);
2288                    }
2289                } else { //conditions+, resourceMatched+, subjects-
2290                    policyDecision.setTimeToLive(timeToLive);
2291                }
2292            } else { //conditions+, resourceMatched-
2293                policyDecision.setTimeToLive(Long.MAX_VALUE);
2294            }
2295        } else { //conditions-
2296            boolean reportAdvices = false;
2297            if (!advicesFromConditions.isEmpty()) {
2298                reportAdvices = users.isMember(token);
2299                subjectsTtl = users.getResultTtl(token);
2300                if (subjectsTtl < timeToLive) {
2301                    timeToLive = subjectsTtl;
2302                }
2303            }
2304            if (reportAdvices) {
2305                actionResults = getMatchedRuleResults(resourceType,
2306                        resourceName, actionNames);
2307                Iterator resultActionNames 
2308                        = actionResults.keySet().iterator();
2309                while ( resultActionNames.hasNext() ) {
2310                    String resultActionName 
2311                            = (String) resultActionNames.next();
2312
2313                    /*  ActionDecision to include advices, no values
2314                     */
2315                    ActionDecision actionDecision 
2316                            = new ActionDecision(resultActionName,
2317                            Collections.EMPTY_SET, 
2318                            advicesFromConditions, timeToLive);
2319                    policyDecision.addActionDecision(
2320                            actionDecision, resourceType);
2321                }
2322            } else { //no advices to report
2323                policyDecision.setTimeToLive(timeToLive);
2324            }
2325        }
2326        return policyDecision;
2327    }
2328
2329    /** Gets policy decision  computing Rules, Subjects and Conditions
2330     *  in this order. Referrals in the policy are ignored.
2331     *
2332     * @param token sso token identifying the user for who the policy has to 
2333     *        be evaluated.
2334     * @param resourceType service type
2335     * @param resourceName resourceName
2336     * @param actionNames a set of action names for which policy results
2337     *        are to be evaluated. Each element of the set should be a
2338     *        String
2339     * @param envParameters a map of environment parameters
2340     *        Each key of the map is a String valued parameter name
2341     *        Each value of the map is a set of String values
2342     * @param policyDecision a collecting arugment. Computed policy decisions
2343     *        in this method are merged to this policy decision
2344     * @return computed and merged policy decision
2345     * @exception NameNotFoundException if the action name or resource name
2346     *         is not found
2347     * @exception SSOException if token is invalid
2348     * @exception PolicyException for any other exception condition
2349     */
2350    private PolicyDecision getPolicyDecisionRSC(SSOToken token, 
2351            ServiceType resourceType,
2352            String resourceName, Set actionNames, Map envParameters,
2353            PolicyDecision policyDecision) 
2354            throws SSOException, NameNotFoundException, PolicyException {
2355        boolean resourceMatched = false;
2356        ConditionDecision conditionDecision = null;
2357        boolean allowedByConditions = false;
2358        boolean allowedBySubjects = false;
2359        Map advicesFromConditions = null;
2360        long conditionsTtl = Long.MIN_VALUE;
2361        long timeToLive = Long.MIN_VALUE;
2362
2363        Map actionResults = getMatchedRuleResults(resourceType,
2364                resourceName, actionNames);
2365        resourceMatched = !actionResults.isEmpty();
2366        if (resourceMatched) { //resourceMatched+
2367            allowedBySubjects = users.isMember(token);
2368            timeToLive = users.getResultTtl(token);
2369            if (allowedBySubjects) { //resourceMatched+, subjects+
2370                conditionDecision = conditions.getConditionDecision(
2371                        token, envParameters);
2372                allowedByConditions = conditionDecision.isAllowed();
2373                advicesFromConditions = conditionDecision.getAdvices();
2374                conditionsTtl = conditionDecision.getTimeToLive();
2375                if (conditionsTtl < timeToLive) {
2376                    timeToLive = conditionsTtl;
2377                }
2378                if (allowedByConditions) {
2379
2380                    //resourceMatched+, subjects+, conditions+
2381                    Iterator resultActionNames 
2382                            = actionResults.keySet().iterator();
2383                    while ( resultActionNames.hasNext() ) {
2384                        String resultActionName 
2385                                = (String) resultActionNames.next();
2386                        Set resultActionValues 
2387                            = (Set)actionResults.get(resultActionName);
2388
2389                        /*  ActionDecision to include values, no advices
2390                         */
2391                        ActionDecision actionDecision 
2392                                = new ActionDecision(resultActionName,
2393                                resultActionValues, 
2394                                advicesFromConditions, timeToLive);
2395                        policyDecision.addActionDecision(
2396                                actionDecision, resourceType);
2397                    }
2398                } else { //resourceMatched+, subjects+, conditions-
2399                    Iterator resultActionNames  
2400                            = actionResults.keySet().iterator();
2401                    if (!advicesFromConditions.isEmpty()) {
2402                        while ( resultActionNames.hasNext() ) {
2403                            String resultActionName 
2404                                    = (String) resultActionNames.next();
2405
2406                            /*  ActionDecision to include advices, no values
2407                             */
2408                            ActionDecision actionDecision 
2409                                    = new ActionDecision(resultActionName,
2410                                    Collections.EMPTY_SET, 
2411                                    advicesFromConditions, timeToLive);
2412                            policyDecision.addActionDecision(
2413                                    actionDecision, resourceType);
2414                        }
2415                    } else {
2416                        policyDecision.setTimeToLive(timeToLive);
2417                    }
2418                }
2419            } else { //resourceMatched+, subjects-
2420                policyDecision.setTimeToLive(timeToLive);
2421            }
2422        } else { //resourceMached-
2423            policyDecision.setTimeToLive(Long.MAX_VALUE);
2424        }
2425        return policyDecision;
2426    }
2427
2428    /** Gets policy decision  computing Rules, Conditions and Subjects
2429     *  in this order. Referrals in the policy are ignored.
2430     *
2431     * @param token sso token identifying the user for who the policy has to 
2432     *        be evaluated.
2433     * @param resourceType service type
2434     * @param resourceName resourceName
2435     * @param actionNames a set of action names for which policy results
2436     *        are to be evaluated. Each element of the set should be a
2437     *        String
2438     * @param envParameters a map of environment parameters
2439     *        Each key of the map is a String valued parameter name
2440     *        Each value of the map is a set of String values
2441     * @param policyDecision a collecting argument. Computed policy decisions
2442     *        in this method are merged to this policy decision
2443     * @return computed and merged policy decision
2444     * @exception NameNotFoundException if the action name or resource name
2445     *         is not found
2446     * @exception SSOException if token is invalid
2447     * @exception PolicyException for any other exception condition
2448     */
2449    private PolicyDecision getPolicyDecisionRCS(SSOToken token, 
2450            ServiceType resourceType,
2451            String resourceName, Set actionNames, Map envParameters,
2452            PolicyDecision policyDecision) 
2453            throws SSOException, NameNotFoundException, PolicyException {
2454        boolean resourceMatched = false;
2455        ConditionDecision conditionDecision = null;
2456        boolean allowedByConditions = false;
2457        boolean allowedBySubjects = false;
2458        Map advicesFromConditions = null;
2459        long conditionsTtl = Long.MIN_VALUE;
2460        long subjectsTtl = Long.MIN_VALUE;
2461        long timeToLive = Long.MIN_VALUE;
2462
2463        Map actionResults = getMatchedRuleResults(resourceType,
2464                resourceName, actionNames);
2465        resourceMatched = !actionResults.isEmpty();
2466        if (resourceMatched) { //resourceMatch+
2467            conditionDecision = conditions.getConditionDecision(
2468                    token, envParameters);
2469            allowedByConditions = conditionDecision.isAllowed();
2470            advicesFromConditions = conditionDecision.getAdvices();
2471            conditionsTtl = conditionDecision.getTimeToLive();
2472            timeToLive = conditionsTtl;
2473            if (allowedByConditions) { //resourceMatch+, conditions+
2474                allowedBySubjects = users.isMember(token);
2475                subjectsTtl = users.getResultTtl(token);
2476                if (subjectsTtl < timeToLive) {
2477                    timeToLive = subjectsTtl;
2478                }
2479                if (allowedBySubjects) {
2480                    //resourceMatch+, conditions+, subjects+
2481                    Iterator resultActionNames 
2482                            = actionResults.keySet().iterator();
2483                    while ( resultActionNames.hasNext() ) {
2484                        String resultActionName 
2485                                = (String) resultActionNames.next();
2486                        Set resultActionValues 
2487                            = (Set)actionResults.get(resultActionName);
2488
2489                        /*  ActionDecision to include values, no advices
2490                         */
2491                        ActionDecision actionDecision 
2492                                = new ActionDecision(resultActionName,
2493                                resultActionValues, 
2494                                advicesFromConditions, timeToLive);
2495                        policyDecision.addActionDecision(
2496                                actionDecision, resourceType);
2497                    }
2498                } else { //resourceMatch+, conditions+, subjects-
2499                    policyDecision.setTimeToLive(timeToLive);
2500                }
2501            } else { //resourceMatch+, conditions-
2502                boolean reportAdvices = false;
2503                if (!advicesFromConditions.isEmpty()) {
2504                    reportAdvices = users.isMember(token);
2505                    subjectsTtl = users.getResultTtl(token);
2506                    if (subjectsTtl < timeToLive) {
2507                        timeToLive = subjectsTtl;
2508                    }
2509                }
2510                if (reportAdvices) {
2511                    Iterator resultActionNames 
2512                            = actionResults.keySet().iterator();
2513                    while ( resultActionNames.hasNext() ) {
2514                        String resultActionName 
2515                                = (String) resultActionNames.next();
2516
2517                        /*  ActionDecision to include advices, no values
2518                         */
2519                        ActionDecision actionDecision 
2520                                = new ActionDecision(resultActionName,
2521                                Collections.EMPTY_SET, 
2522                                advicesFromConditions, timeToLive);
2523                        policyDecision.addActionDecision(
2524                                actionDecision, resourceType);
2525                    }
2526                } else { //no advices to report
2527                    policyDecision.setTimeToLive(timeToLive);
2528                }
2529            }
2530        } else { //resourceMatch-
2531            policyDecision.setTimeToLive(Long.MAX_VALUE);
2532        }
2533        return policyDecision;
2534    }
2535
2536
2537    /** Gets evaluation order of Subjects, Rules and Conditions for this policy
2538     *  that is likely to be least expensive in terms of cpu.
2539     *
2540     *  @return int representing preferred evaluation order for this policy
2541     */
2542    private int getEvaluationOrder(SSOToken token) throws SSOException {
2543
2544        int evaluationOrder = RULES_CONDITIONS_SUBJECTS;
2545
2546        //treat subject weight as 0, if sub result is in cache
2547        int mpsWeight = users.isSubjectResultCached(token) ? 0 : psWeight;
2548        if (( mpsWeight <= pcWeight) && (pcWeight <= prWeight)) {
2549            evaluationOrder = SUBJECTS_CONDITIONS_RULES;
2550        }  else if (( pcWeight <= mpsWeight) && (mpsWeight <= prWeight)) {
2551            evaluationOrder = CONDITIONS_SUBJECTS_RULES;
2552        }  else if (( prWeight <= pcWeight) && (pcWeight <= mpsWeight)) {
2553            evaluationOrder = RULES_CONDITIONS_SUBJECTS;
2554        }  else if (( prWeight <= mpsWeight) && (mpsWeight <= pcWeight)) {
2555            evaluationOrder = RULES_SUBJECTS_CONDITIONS;
2556        }  else if (( mpsWeight <= prWeight) && (prWeight <= pcWeight)) {
2557            evaluationOrder = SUBJECTS_RULES_CONDITIONS;
2558        }  else if (( pcWeight <= prWeight) && (prWeight <= mpsWeight)) {
2559            evaluationOrder = CONDITIONS_RULES_SUBJECTS;
2560        } 
2561        return evaluationOrder;
2562    }
2563
2564    /** Initializes global values of evaluation weight 
2565     *  per Subject, per Condition and per Rule element
2566     *  of the policies by reading value of property
2567     * <code>EVALUATION_WEIGHTS_KEY</code> from AMConfig.properties.
2568     * If the value is not defined in AMConfig.properties, the value defaults
2569     * to <code>DEFAULT_EVALUATION_WEIGHTS</code>.
2570     * @see #DEFAULT_EVALUATION_WEIGHTS
2571     */
2572    private static void initializeStaticEvaluationWeights() {
2573        EVALUATION_WEIGHTS = com.iplanet.am.util.SystemProperties.get(
2574                EVALUATION_WEIGHTS_KEY, DEFAULT_EVALUATION_WEIGHTS);
2575        StringTokenizer st = new StringTokenizer(EVALUATION_WEIGHTS, ":");
2576        int tokenCount = st.countTokens();
2577        if ( tokenCount != 3) {
2578            if (PolicyManager.debug.warningEnabled()) {
2579                PolicyManager.debug.warning(
2580                    "Policy.initializeStaticEvaluationWeights:"
2581                    + " invalid evaulationWeights defined, "
2582                    + " defaulting to " + DEFAULT_EVALUATION_WEIGHTS);
2583            }
2584            EVALUATION_WEIGHTS = DEFAULT_EVALUATION_WEIGHTS;
2585        } else {
2586            String weight = st.nextToken();
2587            try {
2588                subjectWeight = Integer.parseInt(weight);
2589            } catch (NumberFormatException nfe) {
2590                if (PolicyManager.debug.warningEnabled()) {
2591                    PolicyManager.debug.warning(
2592                        "Policy.initializeStaticEvaluationWeights:"
2593                        + " invalid subjectWeight defined, defaulting to 0");
2594                }
2595                subjectWeight = 0;
2596            }
2597            weight = st.nextToken();
2598            try {
2599                ruleWeight = Integer.parseInt(weight);
2600            } catch (NumberFormatException nfe) {
2601                if (PolicyManager.debug.warningEnabled()) {
2602                    PolicyManager.debug.warning(
2603                        "Policy.initializeStaticEvaluationWeights:"
2604                        + " invalid ruleWeight defined, defaulting to 0");
2605                }
2606                ruleWeight = 0;
2607            }
2608            weight = st.nextToken();
2609            try {
2610                conditionWeight = Integer.parseInt(weight);
2611            } catch (NumberFormatException nfe) {
2612                if (PolicyManager.debug.warningEnabled()) {
2613                    PolicyManager.debug.warning(
2614                        "Policy.initializeStaticEvaluationWeights:"
2615                        + " invalid conditionWeight defined, defaulting to 0");
2616                }
2617                conditionWeight = 0;
2618            }
2619        }
2620    }
2621
2622
2623    /** Initializes  evaluation weights for 
2624     *  Subjects, Conditions and rules of this policy object.
2625     */
2626    void initializeEvaluationWeights() {
2627        psWeight = users.size() * subjectWeight;
2628        prWeight = rules.size() * ruleWeight;
2629        pcWeight = conditions.size() * conditionWeight;
2630    }
2631
2632    /**
2633     * Checks whether the policy is applicable to user identified by sso token
2634     * @return <code>true</code> if the policy is applicable to the  user 
2635     *          identified by sso token, else <code>false</code>
2636     */
2637    boolean isApplicableToUser(SSOToken token)
2638        throws PolicyException, SSOException 
2639    {
2640        return  users.isMember(token);
2641    }
2642
2643    static  Map cloneRuleResults(Map ruleResults) {
2644        Map clonedResults = new HashMap();
2645        if ( (ruleResults != null) && !ruleResults.isEmpty()) {
2646            Iterator keys = ruleResults.keySet().iterator();
2647            while (keys.hasNext()) {
2648                String key = (String)keys.next();
2649                Set values = (Set)ruleResults.get(key);
2650                Set clonedValues = new HashSet();
2651                clonedValues.addAll(values);
2652                clonedResults.put(key, clonedValues);
2653            }
2654        }
2655        return clonedResults;
2656    }
2657
2658    /*
2659     * We track the subject realm when a realm subject is added to the policy.
2660     * We use this information to enforce that a policy has 
2661     * realm subjects only from one realm. We also use this information
2662     * to enforce that policy is not saved into a different realm.
2663     */
2664    String getSubjectRealm() {
2665        return subjectRealm;
2666    }
2667
2668    /**
2669     * Clears the cached membership evaluation results corresponding
2670     * to the <code>tokenIdString</code>. This is triggered through
2671     * <code>PolicySSOTokenListener</code> and <code>PolicyCache</code>
2672     * when session property
2673     * of a logged in user is changed
2674     *
2675     * @param tokenIdString sessionId of the user whose session property changed
2676     */
2677    void clearSubjectResultCache(String tokenIdString) throws PolicyException {
2678        if (DEBUG.messageEnabled()) {
2679            DEBUG.message("Policy.clearSubjectResultCache(tokenIdString): "
2680                    + " clearing cached subject evaluation result for "
2681                    + " tokenId XXXXX");
2682        }
2683        users.clearSubjectResultCache(tokenIdString);
2684    }
2685
2686    /**
2687     * Returns creation date.
2688     *
2689     * @return creation date.
2690     */
2691    public long getCreationDate() {
2692        return creationDate;
2693    }
2694    
2695    /**
2696     * Sets the creation date.
2697     * 
2698     * @param creationDate creation date.
2699     */
2700    public void setCreationDate(long creationDate) {
2701        this.creationDate = creationDate;
2702    }
2703    
2704    /**
2705     * Returns last modified date.
2706     * 
2707     * @return last modified date.
2708     */
2709    public long getLastModifiedDate() {
2710        return lastModifiedDate;
2711    }
2712
2713    /**
2714     * Sets the last modified date.
2715     *
2716     * @param lastModifiedDate last modified date.
2717     */
2718    public void setLastModifiedDate(long lastModifiedDate) {
2719        this.lastModifiedDate = lastModifiedDate;
2720    }
2721
2722    /**
2723     * Returns the user ID who last modified the policy.
2724     *
2725     * @return user ID who last modified the policy.
2726     */
2727    public String getLastModifiedBy() {
2728        return lastModifiedBy;
2729    }
2730
2731    /**
2732     * Sets the user ID who last modified the policy.
2733     *
2734     * @param lastModifiedBy user ID who last modified the policy.
2735     */
2736    public void setLastModifiedBy(String lastModifiedBy) {
2737        this.lastModifiedBy = lastModifiedBy;
2738    }
2739
2740    /**
2741     * Returns the user ID who created the policy.
2742     *
2743     * @return user ID who created the policy.
2744     */
2745    public String getCreatedBy() {
2746        return createdBy;
2747    }
2748
2749    /**
2750     * Sets the user ID who created the policy.
2751     *
2752     * @param createdBy user ID who created the policy.
2753     */
2754    public void setCreatedBy(String createdBy) {
2755        this.createdBy = createdBy;
2756    }
2757}