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




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.