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: PolicyEvaluator.java,v 1.19 2010/01/14 23:18:35 dillidorai Exp $
026 *
027 * Portions copyright 2011-2013 ForgeRock, Inc.
028 */
029package com.sun.identity.policy;
030
031import java.util.Set;
032import java.util.Enumeration;
033import java.util.HashSet;
034import java.util.Map;
035import java.util.HashMap;
036import java.util.Iterator;
037import java.util.Collections;
038import com.iplanet.am.sdk.AMStoreConnection;
039import com.iplanet.am.sdk.AMUser;
040import com.iplanet.am.sdk.AMException;
041import com.iplanet.am.util.Cache;
042import com.iplanet.am.util.SystemProperties;
043import com.sun.identity.shared.debug.Debug;
044import com.sun.identity.shared.stats.Stats;
045import com.iplanet.sso.SSOToken;
046import com.iplanet.sso.SSOTokenListener;
047import com.iplanet.sso.SSOException;
048import com.sun.identity.monitoring.Agent;
049import com.sun.identity.monitoring.SsoServerPolicySvcImpl;
050import com.sun.identity.entitlement.Application;
051import com.sun.identity.entitlement.ApplicationManager;
052import com.sun.identity.entitlement.Entitlement;
053import com.sun.identity.entitlement.EntitlementException;
054import com.sun.identity.entitlement.Evaluator;
055import com.sun.identity.entitlement.PrivilegeManager;
056import com.sun.identity.entitlement.opensso.SubjectUtils;
057import com.sun.identity.monitoring.MonitoringUtil;
058import com.sun.identity.policy.interfaces.Condition;
059import com.sun.identity.policy.interfaces.PolicyListener;
060import com.sun.identity.security.AdminTokenAction;
061import com.sun.identity.sm.AttributeSchema;
062import com.sun.identity.sm.ServiceManager;
063import com.sun.identity.shared.ldap.util.DN;
064import com.sun.identity.sm.DNMapper;
065import java.security.AccessController;
066import java.security.Principal;
067import java.util.List;
068import javax.security.auth.Subject;
069
070/**
071 * The class <code>PolicyEvaluator</code> evaluates policies
072 * and provides policy decisions.
073 * @supported.api
074 */
075public class PolicyEvaluator {
076
077    /**
078     * Constant used to identity all the resources of a service type. 
079     * The resources include the sub resources of all resource prefixes of 
080     * resource type
081     *
082     * @supported.api
083     */
084    public static final String ALL_RESOURCES 
085            = "---ALL_RESOURCES---";
086
087    public static final String ADVICING_ORGANIZATION 
088            = "AdvicingOrganization";
089
090    /**
091     * Constant used to identity empty resource
092     *
093     * @supported.api
094     */
095    public static final String EMPTY_RESOURCE_NAME = "";
096
097    /**
098     * Constant used for key to pass the requested resource name canonicalized
099     * in the env map, so that Condition(s)/ResponseProvider(s) could use 
100     * the requested resource name, if necessary
101     */
102    public static final String SUN_AM_REQUESTED_RESOURCE 
103            = "sun.am.requestedResource";
104
105    /**
106     * Constant used for key to pass the requested resource name uncanonicalized
107     * in the env map, so that Condition(s)/ResponseProvider(s) could use 
108     * the requested resource name, if necessary
109     */
110    public static final String SUN_AM_ORIGINAL_REQUESTED_RESOURCE 
111            = "sun.am.requestedOriginalResource";
112
113    /**
114     * Constant used for key to pass the requested actions names
115     * in the env map, so that Condition(s)/ResponseProvider(s) could use 
116     *  the requested actions names, if necessary
117     */
118    public static final String SUN_AM_REQUESTED_ACTIONS 
119            = "sun.am.requestedActions";
120
121    /**
122     * Constant used for key to pass the PolicyConfig configuration map 
123     * in the env map, so that Condition(s)  could use 
124     * the <code>PolicyConfig</code> config map, if necessary.
125     * <code>LDAPFilterCondition</code> needs to use PolicyConfig config map
126     *
127     *
128     */
129    public static final String SUN_AM_POLICY_CONFIG = "sun.am.policyConfig";
130
131    public static final String RESULTS_CACHE_SESSION_CAP 
132            = "com.sun.identity.policy.resultsCacheSessionCap";
133
134    public static int DEFAULT_RESULTS_CACHE_SESSION_CAP = 1000;
135
136    public static int resultsCacheSessionCap = DEFAULT_RESULTS_CACHE_SESSION_CAP;
137
138    public static final String RESULTS_CACHE_RESOURCE_CAP 
139            = "com.sun.identity.policy.resultsCacheResourceCap";
140
141    public static int DEFAULT_RESULTS_CACHE_RESOURCE_CAP = 100;
142
143    public static int resultsCacheResourceCap = DEFAULT_RESULTS_CACHE_RESOURCE_CAP;
144
145    private static final Debug DEBUG = PolicyManager.debug;
146    private static final boolean USE_POLICY_CACHE = true;
147    private static final boolean INCLUDE_SUPER_RESOURCE_POLCIES = true;
148    private static final long DEFAULT_USER_NSROLE_CACHE_TTL = 600000;
149
150    private String orgName;
151    private String realm;
152    private String serviceTypeName;
153    private ServiceType serviceType;
154    private PolicyCache policyCache;
155    private PolicyManager policyManager;
156    private ResourceIndexManager resourceIndexManager;
157
158    private HashMap booleanActionNameTrueValues; //cache
159    private HashMap booleanActionNameFalseValues; //cache
160    private Set actionNames; //all action names valid for the serviceType
161    private Set orgNames = new HashSet(); // to pass org name in envParameters
162    // used to pass service type name in envParameters
163    private Set serviceTypeNames = new HashSet(); 
164    // listener for policy decision cache
165    private PolicyDecisionCacheListener listener = null; 
166
167    /*
168     * Cache to keep the policy evaluation results
169     * Cache structure layout:
170     * 
171     * cache ----> Servicename1
172     *       ----> servicename2
173     *        ...  
174     *       ----> servicenameN
175     *
176     * servicenameI ----> Resourcename1
177     *              ----> Resourcename2
178     *              ...
179     *              ----> ResourcenameN
180     *
181     * resourcenameI ----> userssotokenidstring1
182     *               ----> userssotokenidstring2
183     *               ...
184     *               ----> userssotokenidstringN
185     *
186     * userssotokenidstringI ----> requestscope1
187     *                       ----> requestscope2
188     *
189     * requestscope1 ----> resourceresult1
190     * requestscope2 ----> resourceresult2
191     */
192    static Map policyResultsCache = new HashMap();
193
194    /*
195     * The sso token listener registry for policy decision cache. 
196     * To avoid adding multiple sso token listeners for the same 
197     * token, we use this registry to make sure the listener is 
198     * registered only once for each token. It will be unregistered 
199     * if token is expired. 
200     *
201     * Key is tokenId and value is policySSOTokenListener
202     * ssoTokenIDString : PolicySSOTokenListener
203     *
204     * Used to clean up cache on ssoToken notifications
205     */
206    public static Map ssoListenerRegistry =
207              Collections.synchronizedMap(new HashMap());
208
209    /*
210     * The policy change listener registry for policy decision cache.
211     * To avoid adding multiple listeners for the same service, we 
212     * use this registry to make sure the listener is registered only 
213     * once for each service. 
214     *
215     * Key is serviceTypeName and value is <code>PolicyDecisionCacheListener
216     * </code>
217     * serviceTypeName : PolicyDecisionCacheListener for service type
218     *
219     * Used to clean up the decision cache on policy change notification
220     */
221    private static Map policyListenerRegistry =
222              Collections.synchronizedMap(new HashMap());
223
224    /**
225     * The user <code>nsRole</code> attribute cache.
226     * AMSDK cache stops caching a user's nsRole attribute in 6.2
227     * due to notification issue. Adding this cache in policy to 
228     * avoid performance impact caused by the AMSDK change. This 
229     * cache uses a user's token as the key to map to the user's
230     * <code>nsRole</code> attribute values.
231     *
232     * Key is tokenId and value is set of role DN(s)
233     * ssoTokenIDString : set of role DN(s)
234     */
235    static Map userNSRoleCache = 
236              Collections.synchronizedMap(new HashMap());
237
238    // TTL value for entries in the user's nsRole attribute values.
239    private static long userNSRoleCacheTTL = 0;
240
241    /**
242     * listener object to be used in cleaning up the
243     * userNSRoleCache, subjectEvaluationCache , user role
244     * cache in LDAPRoles and policyResultsCache 
245     * upon user token  expiration.
246     */
247    public static SSOTokenListener ssoListener = 
248                                 new PolicySSOTokenListener(); 
249               
250    /*
251     * Cache for sub resources keyed by resource name 
252     * The structure is a Map of
253     * serviceType(String) : resourceNamesCache(Cache)
254     * Key for resourceNamesCache is a root resource name and value is
255     * a <code>Set</code> of sub resource names for the root resource name
256     *
257     * serviceType: resourceName : resourceNames
258     */
259    private static Map resourceNamesMap = new HashMap(); 
260
261    /**
262     * Constant key for passing organization name in the environment map during
263     * policy evaluation. The value for the key would be a <code>Set</code> 
264     * with one element of type String. The string is the name of the 
265     * organization the policy evaluator has been instantiated for.
266     */
267     static final String ORGANIZATION_NAME = "organizationName";
268
269    /**
270     * Constant key for passing service type name in the environment map during
271     * policy evaluation. The value for the key would be a <code>Set</code> 
272     * with one element of type String. The string is the name of the 
273     * <code>ServiceType</code> the  policy evaluator has been instantiated for.
274     */
275     static final String SERVICE_TYPE_NAME = "serviceTypeName";
276
277     static final Object lock = new Object();
278
279    /**
280     * Constructor to create a <code>PolicyEvaluator</code> given the <code>
281     * ServiceType</code> name.
282     *
283     * @param serviceTypeName the name of the <code>ServiceType</code> for 
284     * which this evaluator can be used.
285     * @throws SSOException if <code>SSOToken</code> used by
286     *                      <code>PolicyEvaluator</code> is invalid
287     * @throws NameNotFoundException if the service with name 
288     *                      <code>serviceTypeName</code> is not found
289     * @throws PolicyException for any other abnormal condition
290     *
291     * @supported.api
292     */
293    public PolicyEvaluator(String serviceTypeName)
294        throws SSOException, NameNotFoundException, PolicyException {
295
296        this("", serviceTypeName);
297
298        /* Register a policy listener for updating policy decision 
299         * cache if there is none already registered
300         */
301        synchronized (lock) {
302            if (!(policyListenerRegistry.containsKey(serviceTypeName))) {
303                listener = new PolicyDecisionCacheListener(serviceTypeName);
304                try {
305                    PolicyCache.getInstance().addPolicyListener(listener);
306                } catch (PolicyException pe) {
307                    DEBUG.error("PolicyEvaluator: registering policy decision "
308                            + " cache listener failed");
309                }
310                policyListenerRegistry.put(serviceTypeName, listener);
311                if (DEBUG.messageEnabled()) {
312                    DEBUG.message("PolicyEvaluator:policy listener for service "
313                            + serviceTypeName + " added");
314                }
315            } else {
316                listener = (PolicyDecisionCacheListener)
317                    policyListenerRegistry.get(serviceTypeName);
318            }
319        }
320    }
321
322    /**
323     * Constructor to create a <code>PolicyEvaluator</code> given organization
324     * name and the <code>ServiceType</code> name.
325     *
326     * @param orgName the name of the organization under which the evaluation
327     * is being done
328     * @param serviceTypeName the name of the <code>ServiceType</code> for 
329     * which this evaluator can be used.
330     */
331    public PolicyEvaluator(String orgName, String serviceTypeName)
332            throws SSOException, PolicyException, NameNotFoundException {
333        
334        if ( (orgName == null) || (orgName.equals("/")) 
335                    || (orgName.length() == 0) ) {
336            orgName = ServiceManager.getBaseDN();
337        } else {
338            orgName = com.sun.identity.sm.DNMapper.orgNameToDN(orgName);
339        }
340        this.orgName = orgName;
341
342        this.realm = com.sun.identity.sm.DNMapper.orgNameToRealmName(orgName);
343        this.serviceTypeName = serviceTypeName;
344
345        this.policyCache = PolicyCache.getInstance();
346
347        ServiceTypeManager stm = ServiceTypeManager.getServiceTypeManager();
348        serviceType = stm.getServiceType(serviceTypeName);
349        policyManager = policyCache.getPolicyManager(orgName);
350        this.orgNames.add(policyManager.getOrganizationDN());
351        this.serviceTypeNames.add(serviceTypeName);
352        resourceIndexManager = policyManager.getResourceIndexManager();
353
354        String resultsCacheSessionCapString 
355                = SystemProperties.get(RESULTS_CACHE_SESSION_CAP);
356        if (resultsCacheSessionCapString != null) {
357            try {
358                resultsCacheSessionCap 
359                        = Integer.parseInt(resultsCacheSessionCapString);
360            } catch (NumberFormatException nfe) {
361                if (PolicyManager.debug.warningEnabled()) {
362                    PolicyManager.debug.warning("PolicyEvaluator:"
363                            + "number format exception: "
364                            + "defaulting resultsCacheSessionCap to "
365                            + DEFAULT_RESULTS_CACHE_SESSION_CAP);
366                }
367                resultsCacheSessionCap = DEFAULT_RESULTS_CACHE_SESSION_CAP;
368            }
369        } else {
370            if (PolicyManager.debug.warningEnabled()) {
371                PolicyManager.debug.warning("PolicyEvaluator:"
372                        + "resultsCacheSessionCap not specified, "
373                        + "defaulting resultsCacheSessionCap to "
374                        + DEFAULT_RESULTS_CACHE_SESSION_CAP);
375            }
376            resultsCacheSessionCap = DEFAULT_RESULTS_CACHE_SESSION_CAP;
377        }
378        if (PolicyManager.debug.messageEnabled()) {
379            PolicyManager.debug.message("PolicyEvaluator:"
380                    + "resultsCacheSessionCap=" + resultsCacheSessionCap);
381        }
382
383        String resultsCacheResourceCapString 
384                = SystemProperties.get(RESULTS_CACHE_RESOURCE_CAP);
385        if (resultsCacheResourceCapString != null) {
386            try {
387                resultsCacheResourceCap 
388                        = Integer.parseInt(resultsCacheResourceCapString);
389            } catch (NumberFormatException nfe) {
390                if (PolicyManager.debug.warningEnabled()) {
391                    PolicyManager.debug.warning("PolicyEvaluator:"
392                            + "number format exception: "
393                            + "defaulting resultsCacheResourceCap to "
394                            + DEFAULT_RESULTS_CACHE_RESOURCE_CAP);
395                }
396                resultsCacheResourceCap = DEFAULT_RESULTS_CACHE_RESOURCE_CAP;
397            }
398        } else {
399            if (PolicyManager.debug.warningEnabled()) {
400                PolicyManager.debug.warning("PolicyEvaluator:"
401                        + "resultsCacheResourceCap not specified, "
402                        + "defaulting resultsCacheResourceCap to "
403                        + DEFAULT_RESULTS_CACHE_RESOURCE_CAP);
404            }
405            resultsCacheResourceCap = DEFAULT_RESULTS_CACHE_RESOURCE_CAP;
406        }
407        if (PolicyManager.debug.messageEnabled()) {
408            PolicyManager.debug.message("PolicyEvaluator:"
409                    + "resultsCacheResourceCap=" + resultsCacheResourceCap);
410        }
411
412    }        
413    
414    /**
415     * Evaluates a simple privilege of boolean type. The privilege indicate
416     * if the user can perform specified action on the specified resource.
417     * Invoking this method would result in <code>PolicyException</code>,
418     * if the syntax for the <code>actionName</code> is not declared to be
419     * boolean, in the service schema.
420     *
421     * @param token single sign on token of the user evaluating policies
422     * @param resourceName name of the resource the user is trying to access
423     * @param actionName name of the action the user is trying to perform on
424     * the resource
425     *
426     * @return the result of the evaluation as a boolean value
427     *
428     * @exception SSOException single-sign-on token invalid or expired
429     * 
430     */
431    public boolean isAllowed(SSOToken token, String resourceName,
432        String actionName) throws PolicyException, SSOException {
433        return (isAllowed(token, resourceName, actionName, 
434                new HashMap()));
435    }
436
437    /**
438     * Evaluates simple privileges of boolean type. The privilege indicate
439     * if the user can perform specified action on the specified resource.
440     * The evaluation depends on user's application environment parameters.
441     * Invoking this method would result in <code>PolicyException</code>,
442     * if the syntax for the <code>actionName</code> is not declared to be
443     * boolean, in the service schema.
444     *
445     * @param token single sign on token of the user evaluating policies
446     * @param resourceName name of the resource the user is trying to access
447     * @param actionName name of the action the user is trying to perform on
448     * the resource
449     * @param envParameters run-time environment parameters
450     *
451     * @return the result of the evaluation as a boolean value
452     *
453     * @throws SSOException single-sign-on token invalid or expired
454     * @throws PolicyException for any other abnormal condition
455     * 
456     * @supported.api
457     */
458    public boolean isAllowed(SSOToken token, String resourceName,
459        String actionName, Map envParameters) throws SSOException,
460        PolicyException {
461        if (PolicyManager.isMigratedToEntitlementService()) {
462            return isAllowedE(token, resourceName, actionName, envParameters);
463        }
464        return isAllowedO(token, resourceName, actionName, envParameters);
465    }
466
467    public boolean isAllowedO(SSOToken token, String resourceName,
468            String actionName, Map envParameters) throws SSOException,
469            PolicyException {
470
471        ActionSchema schema = serviceType.getActionSchema(actionName);
472
473        // Cache the false values for the action names
474        if (booleanActionNameFalseValues == null) {
475            booleanActionNameFalseValues = new HashMap(10);
476        }
477        String falseValue = null;
478        if ((falseValue = (String)
479                booleanActionNameFalseValues.get(actionName)) == null) {
480            falseValue = schema.getFalseValue();
481            // Add it to the cache
482            booleanActionNameFalseValues.put(actionName, falseValue);
483        }
484
485
486        // Cache the true values for the action names
487        if (booleanActionNameTrueValues == null) {
488            booleanActionNameTrueValues = new HashMap(10);
489        }
490
491        String trueValue = null;
492        if ((trueValue = (String)
493                booleanActionNameTrueValues.get(actionName)) == null) {
494            trueValue = schema.getTrueValue();
495            // Add it to the cache
496            booleanActionNameTrueValues.put(actionName, trueValue);
497        }
498
499        if (!AttributeSchema.Syntax.BOOLEAN.equals(schema.getSyntax())) {
500            String objs[] = {actionName};
501            throw new PolicyException(
502                    ResBundleUtils.rbName,
503                    "action_does_not_have_boolean_syntax", objs, null);
504        }
505
506        boolean actionAllowed = false;
507        HashSet actionNames = new HashSet(2);
508        actionNames.add(actionName);
509        PolicyDecision policyDecision = getPolicyDecision(token, resourceName,
510                                   actionNames, envParameters);
511        ActionDecision actionDecision =
512                (ActionDecision) policyDecision.getActionDecisions()
513                .get(actionName);
514
515        if ( actionDecision != null ) {
516            Set set = (Set) actionDecision.getValues();
517            if ( (set != null) ) {
518                if ( set.contains(falseValue) ) {
519                    actionAllowed = false;
520                } else if ( set.contains(trueValue) ) {
521                    actionAllowed = true;
522                }
523            }
524        }
525
526        return actionAllowed;
527    }
528
529    private void padEnvParameters(SSOToken token, String resourceName,
530        String actionName, Map envParameters) throws PolicyException, SSOException {
531        if ((resourceName == null) || (resourceName.trim().length() == 0)) {
532            resourceName = Rule.EMPTY_RESOURCE_NAME;
533        }
534
535        Set originalResourceNames = new HashSet(2);
536        originalResourceNames.add(resourceName);
537
538        String realmName = (DN.isDN(realm)) ?
539            DNMapper.orgNameToRealmName(realm) : realm;
540        try {
541            Application appl = ApplicationManager.getApplication(
542                PrivilegeManager.superAdminSubject,
543                realmName, serviceTypeName);
544            resourceName = appl.getResourceComparator().canonicalize(
545                resourceName);
546        } catch (EntitlementException e) {
547            throw new PolicyException(e);
548        }
549        //Add request resourceName and request actionNames to the envParameters
550        //so that Condition(s)/ResponseProvider(s) can use them if necessary
551        Set resourceNames = new HashSet(2);
552        resourceNames.add(resourceName);
553
554        Set actions = new HashSet();
555        if (actionName != null) {
556            actions.add(actionName);
557        } else {
558            Set actionNames = serviceType.getActionNames();
559            if (actionNames != null) {
560                actions.addAll(actionNames);
561            }
562        }
563
564        envParameters.put(SUN_AM_REQUESTED_RESOURCE, resourceNames);
565        envParameters.put(SUN_AM_ORIGINAL_REQUESTED_RESOURCE,
566                originalResourceNames);
567        envParameters.put(SUN_AM_REQUESTED_ACTIONS, actions);
568        envParameters.put(SUN_AM_POLICY_CONFIG,
569            policyManager.getPolicyConfig());
570        
571        // Fix for OPENAM-811
572        String userid = null; 
573        Principal principal = token.getPrincipal();
574        if (principal != null) {
575            userid = principal.getName();
576        }
577        if ((userid != null) && (userid.length() != 0)) {
578           HashSet<String> set = new HashSet<String>();
579           set.add(userid);
580           // Required by the AMIdentityMembershipCondition
581           envParameters.put(Condition.INVOCATOR_PRINCIPAL_UUID, set);
582        } else {
583            if (DEBUG.messageEnabled()) {
584                DEBUG.message("PolicyEvaluator.padEnvParameters() unable to get userid from token.");
585            }
586        }
587    }
588
589    private boolean isAllowedE(SSOToken token, String resourceName,
590        String actionName, Map envParameters) throws SSOException,
591        PolicyException {
592
593        if ((envParameters == null) || envParameters.isEmpty()) {
594            envParameters = new HashMap();
595        }
596
597        padEnvParameters(token, resourceName, actionName, envParameters);
598
599        ActionSchema schema = serviceType.getActionSchema(actionName);
600        
601        if (!AttributeSchema.Syntax.BOOLEAN.equals(schema.getSyntax())) {
602            String objs[] = {actionName};
603            throw new PolicyException(
604                    ResBundleUtils.rbName,
605                    "action_does_not_have_boolean_syntax", objs, null);
606        }
607
608        HashSet actions = new HashSet(2);
609        actions.add(actionName);
610        SSOToken adminSSOToken = (SSOToken) AccessController.doPrivileged(
611            AdminTokenAction.getInstance());
612
613        try {
614            Subject adminSubject =  SubjectUtils.createSubject(token);
615
616            Entitlement entitlement = new Entitlement(serviceTypeName, resourceName, actions);
617            entitlement.canonicalizeResources(adminSubject, realm);
618
619            Evaluator eval = new Evaluator(adminSubject, serviceTypeName);
620            return eval.hasEntitlement(realm, SubjectUtils.createSubject(token), entitlement, envParameters);
621
622        } catch (EntitlementException e) {
623            throw new PolicyException(e);
624        }
625    }
626
627    private String getActionFalseBooleanValue(String actionName)
628        throws InvalidNameException {
629
630        if (serviceType == null) {
631            return Boolean.FALSE.toString();
632        }
633
634        ActionSchema schema = serviceType.getActionSchema(actionName);
635
636        // Cache the false values for the action names
637        if (booleanActionNameFalseValues == null) {
638            booleanActionNameFalseValues = new HashMap(10);
639        }
640        String falseValue = null;
641        if ((falseValue = (String)
642                booleanActionNameFalseValues.get(actionName)) == null) {
643            falseValue = schema.getFalseValue();
644            // Add it to the cache
645            booleanActionNameFalseValues.put(actionName, falseValue);
646        }
647        return falseValue;
648    }
649
650    private String getActionTrueBooleanValue(String actionName)
651        throws InvalidNameException {
652
653        if (serviceType == null) {
654            return Boolean.TRUE.toString();
655        }
656
657        ActionSchema schema = serviceType.getActionSchema(actionName);
658
659        // Cache the true values for the action names
660        if (booleanActionNameTrueValues == null) {
661            booleanActionNameTrueValues = new HashMap(10);
662        }
663
664        String trueValue = null;
665        if ((trueValue = (String)
666            booleanActionNameTrueValues.get(actionName)) == null) {
667            trueValue = schema.getTrueValue();
668            booleanActionNameTrueValues.put(actionName, trueValue);
669        }
670
671        return trueValue;
672    }
673
674    /**
675     * Evaluates privileges of the user to perform the specified actions
676     * on the specified resource.
677     *
678     * @param token single sign on token of the user evaluating policies
679     * @param resourceName name of the resource the user is trying to access
680     * @param actionNames a <code>Set</code> of <code>Sting</code> objects
681     * representing names of the actions the user is trying to perform on
682     * the resource
683     *
684     * @return policy decision
685     *
686     * @exception SSOException single-sign-on token invalid or expired
687     * @exception PolicyException for any other abnormal condition.
688     */
689    public PolicyDecision getPolicyDecision(SSOToken token, String resourceName,
690        Set actionNames) throws PolicyException, SSOException {
691        return getPolicyDecision(token, resourceName, actionNames, null);
692    }
693    
694
695    /**
696     * Evaluates privileges of the user to perform the specified actions
697     * on the specified resource. The evaluation depends on user's
698     * application environment parameters.
699     *
700     * @param token single sign on token of the user evaluating policies
701     * @param resourceName name of the resource the user is trying to access
702     * @param actionNames <code>Set</code> of names(<code>String</code>) of 
703     * the action the user is trying to perform on the resource
704     * @param envParameters <code>Map</code> of run-time environment parameters
705     *
706     * @return policy decision
707     *
708     * @throws SSOException single-sign-on token invalid or expired
709     * @throws PolicyException for any other abnormal condition
710     * 
711     * @supported.api
712     */
713    public PolicyDecision getPolicyDecision(
714            SSOToken token, String resourceName, Set actionNames,
715            Map envParameters)  throws SSOException, PolicyException {
716        if ( (resourceName == null) || (resourceName.length() == 0) ) {
717            resourceName = Rule.EMPTY_RESOURCE_NAME;
718        }
719
720        Set originalResourceNames = new HashSet(2);
721        originalResourceNames.add(resourceName);
722
723        resourceName = serviceType.canonicalize(resourceName);
724
725        //Add request resourceName and request actionNames to the envParameters
726        //so that Condition(s)/ResponseProvider(s) can use them if necessary
727        Set resourceNames = new HashSet(2);
728        resourceNames.add(resourceName);
729
730        /* compute for all action names if passed in actionNames is
731           null or empty */
732        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
733            actionNames = serviceType.getActionNames();
734        }
735
736        Set actions = new HashSet();
737        if (actionNames != null) {
738            actions.addAll(actionNames);
739        }
740
741        /*
742         * We create new HashMap in place of empty map since
743         * Collections.EMPTY_MAP can not be modified
744         */
745        if ((envParameters == null) || envParameters.isEmpty()) {
746            envParameters = new HashMap();
747        }
748
749        envParameters.put(SUN_AM_REQUESTED_RESOURCE, resourceNames);
750        envParameters.put(SUN_AM_ORIGINAL_REQUESTED_RESOURCE, 
751                originalResourceNames);
752        envParameters.put(SUN_AM_REQUESTED_ACTIONS, actions);
753        envParameters.put(SUN_AM_POLICY_CONFIG, 
754                policyManager.getPolicyConfig());
755
756        return getPolicyDecision(token, resourceName, actionNames,
757                envParameters, new HashSet());
758    }
759
760    /**
761     * Evaluates privileges of the user to perform the specified actions
762     * on the specified resource. The evaluation depends on user's
763     * application environment parameters.
764     *
765     * @param token single sign on token of the user evaluating policies
766     * @param resourceName name of the resource the user is trying to access
767     * @param actionNames <code>Set</code> of names(<code>String</code>) of the
768     * action the user is trying to perform on the resource.
769     * @param envParameters run-time environment parameters
770     * @param visitedOrgs names of organizations that have been already visited
771     *                    during policy evaluation for this request
772     *
773     * @return policy decision
774     *
775     * @exception SSOException single-sign-on token invalid or expired
776     * @exception PolicyException if any policy evaluation error.
777     */
778    private PolicyDecision getPolicyDecision(
779        SSOToken token, String resourceName, Set actionNames,
780        Map envParameters, Set visitedOrgs)
781        throws PolicyException, SSOException {
782        if (MonitoringUtil.isRunning()) {
783            SsoServerPolicySvcImpl sspsi =
784                Agent.getPolicySvcMBean();
785            sspsi.incPolicyEvalsIn();
786        }
787
788        try {
789            return (PolicyManager.isMigratedToEntitlementService()) ? 
790                getPolicyDecisionE(token, resourceName, actionNames,
791                envParameters) : getPolicyDecisionO(token, resourceName,
792                actionNames,
793                envParameters, visitedOrgs);
794        } finally {
795            if (MonitoringUtil.isRunning()) {
796                SsoServerPolicySvcImpl sspsi =
797                        Agent.getPolicySvcMBean();
798                sspsi.incPolicyEvalsOut();
799            }
800        }
801    }
802
803
804    /**
805     * Evaluates privileges of the user to perform the specified actions
806     * on the specified resource. The evaluation depends on user's
807     * application environment parameters.
808     *
809     * @param token single sign on token of the user evaluating policies
810     * @param resourceName name of the resource the user is trying to access
811     * @param actionNames <code>Set</code> of names(<code>String</code>) of the
812     * action the user is trying to perform on the resource.
813     * @param envParameters run-time environment parameters
814     * @return policy decision
815     *
816     * @exception SSOException single-sign-on token invalid or expired
817     * @exception PolicyException if any policy evaluation error.
818     */
819    private PolicyDecision getPolicyDecisionE(
820        SSOToken token, String resourceName, Set actionNames,
821        Map envParameters)
822        throws PolicyException, SSOException {
823
824        if ( DEBUG.messageEnabled() ) {
825            DEBUG.message("Evaluating policies at org " + orgName);
826        }
827
828        /* compute for all action names if passed in actionNames is
829           null or empty */
830        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
831            actionNames = serviceType.getActionNames();
832        }
833
834        SSOToken adminSSOToken = (SSOToken) AccessController.doPrivileged(
835            AdminTokenAction.getInstance());
836
837        try {
838            Evaluator eval = new Evaluator(
839                SubjectUtils.createSubject(adminSSOToken), serviceTypeName);
840            Subject sbj = (token != null) ? SubjectUtils.createSubject(token) :
841                null;
842            List<Entitlement> entitlements = eval.evaluate(
843                orgName, sbj, resourceName, envParameters, false);
844            if ((entitlements != null) && !entitlements.isEmpty()) {
845                Entitlement e = entitlements.iterator().next();
846                return (entitlementToPolicyDecision(e, actionNames));
847            }
848        } catch (EntitlementException e) {
849            throw new PolicyException(e);
850        }
851        return (new PolicyDecision());
852    }
853
854    private PolicyDecision getPolicyDecisionO(
855            SSOToken token, String resourceName, Set actionNames,
856            Map envParameters, Set visitedOrgs)
857            throws PolicyException, SSOException {
858
859        if ( DEBUG.messageEnabled() ) {
860            DEBUG.message("Evaluating policies at org " + orgName);
861        }
862
863        /* compute for all action names if passed in actionNames is
864           null or empty */
865        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
866            actionNames = serviceType.getActionNames();
867        }
868
869        Set actions = new HashSet();
870        actions.addAll(actionNames);
871
872        PolicyDecision mergedPolicyDecision = null;
873        Set policyNameSet = null;
874        Set toRemovePolicyNameSet = null;
875        policyNameSet = resourceIndexManager.getPolicyNames(
876                serviceType, resourceName, INCLUDE_SUPER_RESOURCE_POLCIES);
877        if ( DEBUG.messageEnabled() ) {
878            String tokenPrincipal =
879                    (token != null) ? token.getPrincipal().getName()
880                    : PolicyUtils.EMPTY_STRING;
881            DEBUG.message(new StringBuffer("at PolicyEvaluator")
882                .append(".getPolicyDecision()")
883                .append(" principal, resource name, ")
884                .append("action names, policy names,")
885                .append(" orgName =")
886                .append(tokenPrincipal) .append(",  ")
887                .append(resourceName) .append(",  ")
888                .append(actionNames) .append(",  ")
889                .append(policyNameSet).append(",  ")
890                .append(orgName).toString());
891        }
892        Iterator policyIter = policyNameSet.iterator();
893        while ( policyIter.hasNext() ) {
894            String policyName = (String) policyIter.next();
895            Policy policy = policyManager.getPolicy(policyName,
896                USE_POLICY_CACHE);
897            if ( policy != null && policy.isActive()) {
898                //policy might have been removed or inactivated
899                PolicyDecision policyDecision = policy.getPolicyDecision(token,
900                       serviceTypeName, resourceName, actions, envParameters);
901                if (!policy.isReferralPolicy() && policyDecision.hasAdvices()) {
902                    addAdvice(policyDecision, ADVICING_ORGANIZATION, orgName);
903                }
904
905                // Let us log all policy evaluation results
906                if (PolicyUtils.logStatus && (token != null)) {
907                    String decision = policyDecision.toString();
908                    if (decision != null && decision.length() != 0) {
909                        String[] objs = { policyName, orgName, serviceTypeName,
910                                        resourceName, actionNames.toString(),
911                                        decision };
912                            PolicyUtils.logAccessMessage("POLICY_EVALUATION",
913                                                objs, token, serviceTypeName);
914                    }
915                }
916                if ( mergedPolicyDecision == null ) {
917                    mergedPolicyDecision = policyDecision;
918                } else {
919                    mergePolicyDecisions(serviceType, policyDecision,
920                           mergedPolicyDecision);
921                }
922
923                if (!PolicyConfig.continueEvaluationOnDenyDecision()) {
924                    actions.removeAll(getFinalizedActions(serviceType,
925                            mergedPolicyDecision));
926                }
927
928                if ( actions.isEmpty() ) {
929                    break;
930                }
931            } else { // add policy names to toRemovePolicyNameSet
932                if (toRemovePolicyNameSet == null) {
933                    toRemovePolicyNameSet = new HashSet();
934                }
935                toRemovePolicyNameSet.add(policyName);
936                if ( DEBUG.messageEnabled() ) {
937                    DEBUG.message("PolicyEvaluator.getPolicyDecision():"
938                        +policyName+ " is inactive or non-existent");
939                }
940            }
941        }
942
943        // remove inactive/missing policies from policyNameSet
944        if (toRemovePolicyNameSet != null) {
945            policyNameSet.removeAll(toRemovePolicyNameSet);
946        }
947
948        Set orgsToVisit = getOrgsToVisit(policyNameSet);
949
950        if (PolicyConfig.orgAliasMappedResourcesEnabled()
951                    && PolicyManager.WEB_AGENT_SERVICE.equalsIgnoreCase(
952                    serviceTypeName)) {
953            String orgAlias = policyManager.getOrgAliasWithResource(
954                    resourceName);
955            if (orgAlias != null) {
956                String orgWithAlias = policyManager.getOrgNameWithAlias(
957                        orgAlias);
958                if (orgWithAlias != null) {
959                    if ( DEBUG.messageEnabled() ) {
960                        DEBUG.message("PolicyEvaluator.getPolicyDecision():"
961                                + "adding orgWithAlias to orgsToVisit="
962                                + orgWithAlias);
963                    }
964                    orgsToVisit.add(orgWithAlias);
965                }
966            }
967        }
968
969        if ( DEBUG.messageEnabled() ) {
970            DEBUG.message(new StringBuffer("at PolicyEvaluator")
971                .append(".getPolicyDecision()")
972                .append(" orgsToVist=").append(orgsToVisit.toString())
973                .toString());
974        }
975        orgsToVisit.removeAll(visitedOrgs);
976        if ( DEBUG.messageEnabled() ) {
977            DEBUG.message(new StringBuffer("at PolicyEvaluator")
978                .append(".getPolicyDecision()")
979                .append(" orgsToVist(after removing already visited orgs=")
980                .append(orgsToVisit.toString())
981                .toString() );
982        }
983        while ( !orgsToVisit.isEmpty() && !actions.isEmpty() ) {
984            String orgToVisit = (String) orgsToVisit.iterator().next();
985            orgsToVisit.remove(orgToVisit);
986            visitedOrgs.add(orgToVisit);
987            try {
988                // need to use admin sso token here. Need all privileges to
989                // check for the organzation
990                policyManager.verifyOrgName(orgToVisit);
991            } catch (NameNotFoundException nnfe) {
992                if( DEBUG.warningEnabled()) {
993                    DEBUG.warning("Organization does not exist - "
994                            + "skipping referral to " + orgToVisit);
995                }
996                continue;
997            }
998            PolicyEvaluator pe = new PolicyEvaluator(orgToVisit,
999                    serviceTypeName);
1000            /**
1001             * save policy config before passing control down to
1002             * sub realm
1003             */
1004            Map savedPolicyConfig =(Map)envParameters.get(SUN_AM_POLICY_CONFIG);
1005            // Update env to point to the realm policy config data.
1006            envParameters.put(SUN_AM_POLICY_CONFIG, PolicyConfig.
1007                getPolicyConfig(orgToVisit));
1008            PolicyDecision policyDecision
1009                    = pe.getPolicyDecision(token, resourceName, actionNames,
1010                    envParameters,visitedOrgs);
1011            // restore back the policy config data for the parent realm
1012            envParameters.put(SUN_AM_POLICY_CONFIG, savedPolicyConfig);
1013            if ( mergedPolicyDecision == null ) {
1014                mergedPolicyDecision = policyDecision;
1015            } else {
1016                mergePolicyDecisions(serviceType, policyDecision,
1017                       mergedPolicyDecision);
1018            }
1019            if (!PolicyConfig.continueEvaluationOnDenyDecision()) {
1020                actions.removeAll(getFinalizedActions(serviceType,
1021                        mergedPolicyDecision));
1022            }
1023        }
1024
1025        if ( mergedPolicyDecision == null ) {
1026            mergedPolicyDecision = new PolicyDecision();
1027        }
1028
1029        return mergedPolicyDecision;
1030    }
1031
1032    /**
1033     * Gets protected resources for a user identified by single sign on token
1034     * Conditions defined  in the policies are ignored while 
1035     * computing protected resources. 
1036     * Only resources that are sub resources of the  given 
1037     * <code>rootResource</code> or equal to the given <code>rootResource</code>
1038     * would be returned. 
1039     * If all policies applicable to a resource are 
1040     * only referral policies, no <code>ProtectedResource</code> would be
1041     * returned for such a resource.
1042     *
1043     * @param token single sign on token of the user
1044     * @param rootResource  only resources that are sub resources of the  
1045     *                      given <code>rootResource</code> or equal to the
1046     *                      given <code>rootResource</code> would be returned
1047     *                      <code>rootResource</code> would be returned.
1048     *                      If <code>PolicyEvaluator.ALL_RESOURCES</code> is 
1049     *                      passed as <code>rootResource</code>, resources under
1050     *                      all root  resources of the service 
1051     *                      type are considered while computing protected 
1052     *                      resources.
1053     * @return <code>Set</code> of protected resources. The set 
1054     *         contains <code>ProtectedResource</code> objects. 
1055     *
1056     * @throws SSOException if single sign on token is invalid
1057     * @throws PolicyException for any other abnormal condition
1058     * @see ProtectedResource
1059     *
1060     * @supported.api
1061     *
1062     */
1063    public Set getProtectedResourcesIgnoreConditions(
1064        SSOToken token, String rootResource)  
1065        throws SSOException, PolicyException 
1066    {
1067        if ( (rootResource == null) || (rootResource.equals("")) ) {
1068            rootResource = EMPTY_RESOURCE_NAME;
1069        }
1070        Set protectedResources = new HashSet();
1071        Set topLevelResources = null;
1072        if (rootResource.equals(ALL_RESOURCES)) {
1073            topLevelResources 
1074                    = resourceIndexManager.getTopLevelResourceNames(
1075                    serviceType);
1076        } else {
1077            topLevelResources = new HashSet();
1078            topLevelResources.add(rootResource);
1079        }
1080        Iterator iter = topLevelResources.iterator();
1081        while (iter.hasNext()) {
1082            String topLevelResource = (String)iter.next();
1083            Set resourceNames 
1084                    = getResourceNames(token, topLevelResource, true);
1085            Iterator resourceIter = resourceNames.iterator();
1086            while (resourceIter.hasNext()) {
1087                String resourceName = (String)resourceIter.next();
1088                Set protectingPolicies 
1089                        = getProtectingPolicies(token, resourceName);
1090                if ((protectingPolicies != null) 
1091                            && (!protectingPolicies.isEmpty())) {
1092                    boolean allReferralPolicies = true;
1093                    Iterator iter1 = protectingPolicies.iterator();
1094                    while (iter1.hasNext()){
1095                        Policy policy = (Policy)iter1.next();
1096                        if (!policy.isReferralPolicy()) {
1097                            allReferralPolicies = false;
1098                            break;
1099                        }
1100                    }
1101                    if (!allReferralPolicies) {
1102                        protectedResources.add(
1103                                new ProtectedResource(resourceName, 
1104                                protectingPolicies));
1105                    }
1106                }
1107            }
1108        }
1109        return protectedResources;
1110    }
1111
1112    /**
1113     * Gets policies applicable to user that are  protecting 
1114     * the specified resource.
1115     *
1116     * @param token single sign on token of the user evaluating policies
1117     * @param resourceName name of the resource the user is trying to access
1118     *
1119     * @return set of policies applicable to user that are protecting the 
1120     *         specified resource
1121     *
1122     * @throws PolicyException policy exception coming from policy framework
1123     * @throws SSOException single-sign-on token invalid or expired
1124     * 
1125     */
1126    Set getProtectingPolicies(
1127        SSOToken token, String resourceName)  
1128        throws PolicyException, SSOException 
1129    {
1130        return getProtectingPolicies(token, resourceName, new HashSet());
1131    }
1132
1133    /**
1134     * Gets policies applicable to user that are  protecting 
1135     * the specified resource.
1136     *
1137     * @param token single sign on token of the user evaluating policies
1138     * @param resourceName name of the resource the user is trying to access
1139     *
1140     * @param visitedOrgs names of organizations that have been 
1141     *            already visited during evaluation for this request
1142     * @return set of policies applicable to user that are protecting the 
1143     *         specified resource
1144     *
1145     * @throws PolicyException policy exception coming from policy framework
1146     * @throws SSOException single-sign-on token invalid or expired
1147     * 
1148     */
1149    private Set getProtectingPolicies(
1150        SSOToken token, String resourceName, Set visitedOrgs)  
1151        throws PolicyException, SSOException 
1152    {
1153
1154        Set protectingPolicies = new HashSet();
1155
1156
1157        // false - do not include super resource policies
1158        // includes EXACT_MATCH and WILD_CARD_MATCH
1159        Set policyNameSet = resourceIndexManager.getPolicyNames(
1160                serviceType, resourceName, false);
1161        Set toRemovePolicyNameSet = null;
1162        if ( DEBUG.messageEnabled() ) {
1163            String tokenPrincipal = 
1164                    (token != null) ? token.getPrincipal().getName()
1165                    : PolicyUtils.EMPTY_STRING;
1166            DEBUG.message(new StringBuffer(
1167                    "at PolicyEvaluator.getProtectingPolicies()")
1168                .append(" principal, resource name, policy names,")
1169                .append(" orgName =")
1170                .append(tokenPrincipal) .append(",  ")
1171                .append(resourceName) .append(",  ")
1172                .append(policyNameSet).append(",  ")
1173                .append(orgName).toString());
1174        }
1175        Iterator policyIter = policyNameSet.iterator();
1176        while ( policyIter.hasNext() ) {
1177            String policyName = (String) policyIter.next();
1178            Policy policy = policyManager.getPolicy(policyName);
1179            if ( policy != null && policy.isActive()) { 
1180                //policy might have been removed or inactivated
1181                if (!policy.isReferralPolicy()) {
1182                    if (policy.isApplicableToUser(token)) {
1183                        policy.setOrganizationName(orgName);
1184                        protectingPolicies.add(policy); 
1185                    }
1186                } else {
1187                    policy.setOrganizationName(orgName);
1188                    protectingPolicies.add(policy);
1189                }
1190            } else { // add policy names to toRemovePolicyNameSet
1191                if (toRemovePolicyNameSet == null) {
1192                    toRemovePolicyNameSet = new HashSet();
1193                }
1194                toRemovePolicyNameSet.add(policyName);
1195                if ( DEBUG.messageEnabled() ) {
1196                    DEBUG.message("PolicyEvaluator.getProtectingPolicies():"
1197                        +policyName+ " is inactive or non-existent");
1198                }
1199            }
1200        }
1201
1202        // remove inactive/missing policies from policyNameSet
1203        if (toRemovePolicyNameSet != null) {
1204            policyNameSet.removeAll(toRemovePolicyNameSet);
1205        }
1206
1207        //include super resource policies provided they are referral policies
1208        policyNameSet = resourceIndexManager.getSuperResourcePolicyNames(
1209                serviceType, resourceName);
1210        if (toRemovePolicyNameSet != null) {
1211            toRemovePolicyNameSet.clear();
1212        }
1213        policyIter = policyNameSet.iterator();
1214        while ( policyIter.hasNext() ) {
1215            String policyName = (String) policyIter.next();
1216            Policy policy = policyManager.getPolicy(policyName);
1217            if ( policy != null && policy.isActive()) { 
1218                //policy might have been removed or inactivated
1219                if (policy.isReferralPolicy()) {
1220                        policy.setOrganizationName(orgName);
1221                        protectingPolicies.add(policy);
1222                }
1223            } else { // add policy names to toRemovePolicyNameSet
1224                if (toRemovePolicyNameSet == null) {
1225                    toRemovePolicyNameSet = new HashSet();
1226                }
1227                toRemovePolicyNameSet.add(policyName);
1228                if ( DEBUG.messageEnabled() ) {
1229                    DEBUG.message("PolicyEvaluator.getProtectingPolicies():"
1230                        +policyName+ " is inactive or non-existent");
1231                }
1232            }
1233        }
1234        // remove inactive/missing policies from policyNameSet
1235        if (toRemovePolicyNameSet != null) {
1236            policyNameSet.removeAll(toRemovePolicyNameSet);
1237        }
1238
1239        Set orgsToVisit = getOrgsToVisit(policyNameSet);
1240        if ( DEBUG.messageEnabled() ) {
1241            DEBUG.message(new StringBuffer(
1242                    "at PolicyEvaluator.getProtectingPolicies()")
1243                .append(" orgsToVist=").append(orgsToVisit.toString())
1244                .toString());
1245        }
1246
1247        if (PolicyConfig.orgAliasMappedResourcesEnabled()
1248                    && PolicyManager.WEB_AGENT_SERVICE.equalsIgnoreCase(
1249                    serviceTypeName)) {
1250            String orgAlias = policyManager.getOrgAliasWithResource(
1251                    resourceName); 
1252            if (orgAlias != null) {
1253                String orgWithAlias = policyManager.getOrgNameWithAlias(
1254                        orgAlias);
1255                if (orgWithAlias != null) {
1256                    if ( DEBUG.messageEnabled() ) {
1257                        DEBUG.message("PolicyEvaluator.getProtectingPolicies():"
1258                                + "adding orgWithAlias to orgsToVisit="
1259                                + orgWithAlias);
1260                    }
1261                    orgsToVisit.add(orgWithAlias);
1262                }
1263            }
1264        }
1265
1266        orgsToVisit.removeAll(visitedOrgs);
1267        if ( DEBUG.messageEnabled() ) {
1268            DEBUG.message(new StringBuffer(
1269                    "at PolicyEvaluator.getProtectingPolicies()")
1270                .append(" orgsToVist(after removing already visited orgs=")
1271                .append(orgsToVisit.toString())
1272                .toString() );
1273        }
1274        while (!orgsToVisit.isEmpty() ) {
1275            String orgToVisit = (String) orgsToVisit.iterator().next();
1276            orgsToVisit.remove(orgToVisit);
1277            visitedOrgs.add(orgToVisit);
1278            try {
1279                // need to use admin sso token here. Need all privileges to
1280                // check for the organzation
1281                policyManager.verifyOrgName(orgToVisit);
1282            } catch (NameNotFoundException nnfe) {
1283                if( DEBUG.warningEnabled()) {
1284                    DEBUG.warning("Organization does not exist - "
1285                            + "skipping referral to " + orgToVisit);
1286                }
1287                continue;
1288            }
1289            PolicyEvaluator pe 
1290                    = new PolicyEvaluator(orgToVisit, serviceTypeName);
1291            Set pp = pe.getProtectingPolicies(token, resourceName,
1292                    visitedOrgs); 
1293            protectingPolicies.addAll(pp);
1294        }
1295
1296        String principalName =  (token != null) 
1297                ? token.getPrincipal().getName()
1298                : PolicyUtils.EMPTY_STRING;
1299
1300        StringBuffer sb = null;
1301        String pp = null;
1302        if (PolicyManager.debug.messageEnabled() || PolicyUtils.logStatus) {
1303            sb = new StringBuffer();
1304            Iterator pIter = protectingPolicies.iterator();
1305            while (pIter.hasNext()) {
1306                Policy policy = (Policy)pIter.next();
1307                sb.append(policy.getOrganizationName()).append(":")
1308                        .append(policy.getName()) .append(",");
1309            }
1310            pp = sb.toString();
1311        }
1312
1313
1314        if (PolicyManager.debug.messageEnabled()) {
1315            PolicyManager.debug.message("Computed policies "
1316                    + " protecting resource "
1317                    + resourceName
1318                    + "for principal:" + principalName + " " + pp);
1319        }
1320
1321        if (PolicyUtils.logStatus && (token != null)) {
1322            String[] objs = { principalName, 
1323                    resourceName, pp };
1324            PolicyUtils.logAccessMessage("PROTECTED_RESOURCES", objs, token,
1325                    serviceTypeName);
1326        }
1327        return protectingPolicies;
1328    }
1329
1330    /**
1331     * Gets resource result objects given a resource name. The set
1332     * contains <code>ResourceResult</code> objects for all resources 
1333     * that would affect policy decisions for any resource associated with the 
1334     * argument resource name. To determine whether to include the
1335     * <code>ResourceResult</code> of a resource,  we compare argument resource
1336     * name and policy resource name, treating wild characters in the policy 
1337     * resource name as wild. If the comparison resulted in
1338     * <code>EXACT_MATCH</code>, <code>WILD_CARD_MACTH</code> or
1339     * <code>SUB_RESOURCE_MACTH</code>, the resource result would be
1340     * included.
1341     *
1342     * @param token single sign on token of the user evaluating policies
1343     * @param resourceName name of the resource 
1344     * @param scope indicates whether to compute the resource result based on
1345     *              the policy decision for only the <code>resourceName</code>
1346     *              or all the resources associated with the resource name.
1347     *              The valid scope values are:
1348     *              <ul>
1349     *              <li><code>ResourceResult.SUBTREE_SCOPE</code>
1350     *              <li><code>ResourceResult.STRICT_SUBTREE_SCOPE</code>
1351     *              <li><code>ResourceResult.SELF_SCOPE</code>
1352     *              <ul>
1353     *              If the scope is <code>ResourceResult.SUBTREE_SCOPE</code>,
1354     *              the method will return a set of <code>ResourceResult</code>
1355     *              objects, one of them for the <code>resourceName</code> and
1356     *              its sub resources; the others are for resources that match
1357     *              the <code>resourceName</code> by wildcard. If the scope is
1358     *              <code>ResourceResult.STRICT_SUBTREE_SCOPE</code>, the 
1359     *              method will return a set object that contains one 
1360     *              <code>ResourceResult</code> object. The
1361     *              <code>ResourceResult</code> contains the policy decisions
1362     *              regarding the <code>resourceName</code> and its sub
1363     *              resources. If the scope is
1364     *              <code>ResourceResult.SELF_SCOPE</code>, the method will
1365     *              return a set object that contains one
1366     *              <code>ResourceResult</code> object.
1367     *              The <code>ResourceResult</code> contains the policy decision
1368     *              regarding the <code>resourceName</code> only.
1369     *
1370     * @param envParameters run-time environment parameters
1371     *
1372     * @return set of <code>ResourceResult</code> objects
1373     *
1374     * @throws SSOException if <code>token</code> is invalid
1375     * @throws PolicyException for any other abnormal condition
1376     *
1377     * @see ResourceMatch#EXACT_MATCH
1378     * @see ResourceMatch#SUB_RESOURCE_MATCH
1379     * @see ResourceMatch#WILDCARD_MATCH
1380     * @see ResourceResult#SUBTREE_SCOPE
1381     * @see ResourceResult#STRICT_SUBTREE_SCOPE
1382     * @see ResourceResult#SELF_SCOPE
1383     *
1384     * 
1385     * @supported.api
1386     */
1387    public Set getResourceResults(SSOToken token, 
1388            String resourceName, String scope, Map envParameters) 
1389            throws SSOException, PolicyException {
1390        return (PolicyManager.isMigratedToEntitlementService()) ?
1391            getResourceResultsE(token, resourceName, scope, envParameters) :
1392            getResourceResultsO(token, resourceName, scope, envParameters);
1393    }
1394    
1395    private Set getResourceResultsO(SSOToken token,
1396            String resourceName, String scope, Map envParameters)
1397            throws SSOException, PolicyException {
1398        Set resultsSet;
1399
1400        if (ResourceResult.SUBTREE_SCOPE.equals(scope)) {
1401            resultsSet = getResourceResultTree(token, resourceName, scope,
1402                                         envParameters).getResourceResults();
1403        } else if (ResourceResult.STRICT_SUBTREE_SCOPE.equals(scope)
1404                   || ResourceResult.SELF_SCOPE.equals(scope)) {
1405            ResourceResult result = getResourceResultTree(token, resourceName,
1406                                         scope, envParameters);
1407            resultsSet = new HashSet();
1408            resultsSet.add(result);
1409        } else {
1410            DEBUG.error("PolicyEvaluator: invalid request scope: " + scope);
1411            String objs[] = {scope};
1412            throw new PolicyException(ResBundleUtils.rbName,
1413                "invalid_request_scope", objs, null);
1414        }
1415
1416        return resultsSet;
1417    }
1418
1419    private Set getResourceResultsE(SSOToken token,
1420            String resourceName, String scope, Map envParameters)
1421            throws SSOException, PolicyException {
1422
1423        if ((envParameters == null) || envParameters.isEmpty()) {
1424            envParameters = new HashMap();
1425        }
1426        padEnvParameters(token, resourceName, null, envParameters);
1427
1428        Set resultsSet;
1429        boolean subTreeSearch = false;
1430
1431        if (ResourceResult.SUBTREE_SCOPE.equals(scope)) {
1432            subTreeSearch = true;
1433            //resultsSet = getResourceResultTree(token, resourceName, scope,
1434            //                            envParameters).getResourceResults();
1435        } else if (ResourceResult.STRICT_SUBTREE_SCOPE.equals(scope)
1436                   || ResourceResult.SELF_SCOPE.equals(scope)) {
1437            /*
1438            ResourceResult result = getResourceResultTree(token, resourceName,
1439                                         scope, envParameters);
1440            resultsSet = new HashSet();
1441            resultsSet.add(result);*/
1442        } else {
1443            DEBUG.error("PolicyEvaluator: invalid request scope: " + scope);
1444            String objs[] = {scope};
1445            throw new PolicyException(ResBundleUtils.rbName,
1446                "invalid_request_scope", objs, null);
1447        }
1448
1449        SSOToken adminSSOToken = (SSOToken)AccessController.doPrivileged(
1450            AdminTokenAction.getInstance());
1451
1452        try {
1453            // Parse the resource name before proceeding.
1454            resourceName = serviceType.canonicalize(resourceName);
1455
1456            Subject userSubject = SubjectUtils.createSubject(token);
1457            Evaluator eval = new Evaluator(
1458                SubjectUtils.createSubject(adminSSOToken), serviceTypeName);
1459
1460            List<Entitlement> entitlements = eval.evaluate(
1461                realm, userSubject, resourceName,
1462                envParameters, subTreeSearch);
1463            resultsSet = new HashSet();
1464
1465            if (!entitlements.isEmpty()) {
1466                if (!subTreeSearch) {
1467                    resultsSet.add(entitlementToResourceResult(
1468                        (Entitlement)entitlements.iterator().next()));
1469                } else {
1470                    ResourceResult virtualResourceResult =
1471                        new ResourceResult(ResourceResult.VIRTUAL_ROOT,
1472                            new PolicyDecision());
1473                    for (Entitlement ent : entitlements ) {
1474                        ResourceResult r = entitlementToResourceResult(ent);
1475                        virtualResourceResult.addResourceResult(r, serviceType);
1476                    }
1477
1478                    resultsSet.addAll(
1479                        virtualResourceResult.getResourceResults());
1480                }
1481            }
1482        } catch (Exception e) {
1483            DEBUG.error("Error in getResourceResults", e);
1484            throw new PolicyException(e.getMessage()); //TOFIX
1485        }
1486
1487        return resultsSet;
1488    }
1489
1490   
1491    private ResourceResult entitlementToResourceResult(
1492        Entitlement entitlement
1493    ) throws PolicyException {
1494        return new ResourceResult(entitlement.getResourceName(),
1495            entitlementToPolicyDecision(entitlement, Collections.EMPTY_SET));
1496    }
1497    
1498    private PolicyDecision entitlementToPolicyDecision(
1499        Entitlement entitlement,
1500        Set<String> actionNames
1501    ) throws PolicyException {
1502        PolicyDecision pd = new PolicyDecision();
1503        Map actionValues = entitlement.getActionValues();
1504
1505        if ((actionValues != null) && !actionValues.isEmpty()) {
1506            for (Iterator i = actionValues.keySet().iterator(); i.hasNext();) {
1507                String actionName = (String) i.next();
1508                Set set = new HashSet();
1509                boolean isBooleanAction = true;
1510                if (serviceType != null) {
1511                    ActionSchema as = null;
1512                    try {
1513                        as = serviceType.getActionSchema(actionName);
1514                    } catch (InvalidNameException inex) {
1515                        if (DEBUG.warningEnabled()) {
1516                            DEBUG.warning("PolicyEvaluator." +
1517                                "entitlementToPolicyDecision:", inex);
1518                        }
1519                    }
1520                    isBooleanAction = (as != null) &&
1521                        as.getSyntax().equals(AttributeSchema.Syntax.BOOLEAN);
1522                }
1523
1524                if (isBooleanAction) {
1525
1526                    Boolean values = (Boolean) actionValues.get(actionName);
1527
1528                    if (values.booleanValue()) {
1529                        set.add(getActionTrueBooleanValue(actionName));
1530                    } else {
1531                        set.add(getActionFalseBooleanValue(actionName));
1532                    }
1533                } else {
1534                    // Parse the action name to get the value
1535                    int index = actionName.indexOf('_');
1536                    if (index != -1) {
1537                        set.add(actionName.substring(index+1));
1538                        actionName = actionName.substring(0, index);
1539                    } else {
1540                        set.add(actionName);
1541                    }
1542                }
1543
1544                ActionDecision ad = new ActionDecision(actionName, set);
1545                ad.setAdvices(entitlement.getAdvices());
1546                ad.setTimeToLive(entitlement.getTTL());
1547                pd.addActionDecision(ad, serviceType);
1548            }
1549        } else {
1550            Map advices = entitlement.getAdvices();
1551            if ((advices != null) && (!advices.isEmpty()) &&
1552                ((actionNames == null) || actionNames.isEmpty())) {
1553                actionNames = serviceType.getActionNames();
1554            }
1555            for (String actionName : actionNames) {
1556                Set set = new HashSet();
1557                // Determinte if the serviceType have boolean action values
1558                ActionSchema as = null;
1559                if (serviceType != null) {
1560                    try {
1561                        as = serviceType.getActionSchema(actionName);
1562                    } catch (InvalidNameException inex) {
1563                        if (DEBUG.warningEnabled()) {
1564                            DEBUG.warning("PolicyEvaluator." +
1565                                "entitlementToPolicyDecision:", inex);
1566                        }
1567                    }
1568                }
1569                if ((as == null) ||
1570                    as.getSyntax().equals(AttributeSchema.Syntax.BOOLEAN)) {
1571                    set.add(getActionFalseBooleanValue(actionName));
1572                } else {
1573                    set.addAll(as.getDefaultValues());
1574                }
1575                ActionDecision ad = new ActionDecision(actionName, set);
1576                ad.setAdvices(entitlement.getAdvices());
1577                ad.setTimeToLive(entitlement.getTTL());
1578                pd.addActionDecision(ad, serviceType);
1579            }
1580        }
1581
1582        pd.setTimeToLive(entitlement.getTTL());
1583        pd.setResponseAttributes(entitlement.getAttributes());
1584        return pd;
1585    }
1586
1587    /**
1588     * Gets resource result given a resource name. <code>ResourceResult</code>
1589     * is a tree representation of policy decisions for all resources rooted 
1590     * at the resource name.
1591     * To determine whether a resource defined in the policy
1592     * is a sub resource of argument resource name, argument resource name 
1593     * and policy resource name are compared, treating wild characters as 
1594     * literals. If comparison resulted in <code>EXACT_MACTH</code> or
1595     * <code>SUB_RESOURCE_MACTH</code>, the resource would be included
1596     *
1597     * @param token single sign on token of the user evaluating policies
1598     * @param resourceName name of the resource 
1599     * @param scope indicates whether to compute the resource result based on
1600     *              the policy decision for only the <code>resourceName</code>
1601     *              or all the resources associated with the resource name.
1602     *              The valid scope values are:
1603     *              <ul>
1604     *              <li><code>ResourceResult.SUBTREE_SCOPE</code>
1605     *              <li><code>ResourceResult.STRICT_SUBTREE_SCOPE</code>
1606     *              <li><code>ResourceResult.SELF_SCOPE</code>
1607     *              </ul>
1608     *              If the scope is <code>ResourceResult.SUBTREE_SCOPE</code> or
1609     *              <code>ResourceResult.STRICT_SUBTREE_SCOPE</code>, the method
1610     *              will return a <code>ResourceResult</code> object that
1611     *              contains the policy decisions regarding the
1612     *              <code>resourceName</code> and its sub resources.
1613     *              If the scope is <code>ResourceResult.SELF_SCOPE</code>, the
1614     *              method will return a <code>ResourceResult</code> object that
1615     *              contains the policy decision regarding the
1616     *              <code>resourceName</code> only. Note, scope values
1617     *              <code>ResourceResult.SUBTREE_SCOPE</code> and
1618     *              <code>ResourceResult.STRICT_SUBTREE_SCOPE</code> are being
1619     *              treated as the same for backword compatibility reasons. This
1620     *              method is being deprecated. The method
1621     *              <code>getResourceResults()</code> should be used instead. 
1622     *
1623     * @param envParameters run-time environment parameters
1624     *
1625     * @return <code>ResourceResult</code>.
1626     *
1627     * @throws SSOException if <code>token</code> is invalid 
1628     * @throws PolicyException for any other abnormal condition
1629     *
1630     * @see ResourceMatch#EXACT_MATCH
1631     * @see ResourceMatch#SUB_RESOURCE_MATCH
1632     * @see ResourceMatch#WILDCARD_MATCH
1633     * @see ResourceResult#SUBTREE_SCOPE
1634     * @see ResourceResult#STRICT_SUBTREE_SCOPE
1635     * @see ResourceResult#SELF_SCOPE
1636     *
1637     * @deprecated Use <code>getResourceResults()</code>
1638     *
1639     * @supported.api
1640     *
1641     */
1642    public ResourceResult getResourceResult(SSOToken token, 
1643            String resourceName, String scope, Map envParameters) 
1644            throws SSOException, PolicyException {
1645        if (ResourceResult.SUBTREE_SCOPE.equals(scope)
1646                || ResourceResult.STRICT_SUBTREE_SCOPE.equals(scope) 
1647                || ResourceResult.SELF_SCOPE.equals(scope)) {
1648            if (ResourceResult.SUBTREE_SCOPE.equals(scope)) {
1649                scope = ResourceResult.STRICT_SUBTREE_SCOPE; 
1650            }
1651            return getResourceResultTree(token, resourceName, scope, 
1652                    envParameters); 
1653        } else {
1654            DEBUG.error("PolicyEvaluator: invalid request scope: " + scope);
1655            String objs[] = {scope};
1656            throw new PolicyException(ResBundleUtils.rbName,
1657                "invalid_request_scope", objs, null);
1658        }
1659    }
1660
1661    /**
1662     * Gets resource result given a resource name. <code>ResourceResult</code>
1663     * is a tree representation of policy decisions for all resources 
1664     * that are sub resources of argument resource name. 
1665     *
1666     * @param token single sign on token of the user evaluating policies
1667     * @param resourceName name of the resource 
1668     * @param scope indicates whether to compute the resource result based on
1669     *              the policy decision for only the <code>resourceName</code>
1670     *              or all the resources associated with the resource name.
1671     * @param envParameters run-time environment parameters
1672     *
1673     * @return <code>ResourceResult</code>.
1674     *
1675     * @exception SSOException if <code>token</code> is invalid
1676     * @exception PolicyException for any other abnormal condition
1677     *
1678     * @see ResourceMatch#EXACT_MATCH
1679     * @see ResourceMatch#SUB_RESOURCE_MATCH
1680     * @see ResourceMatch#WILDCARD_MATCH
1681     *
1682     */
1683    private ResourceResult getResourceResultTree(SSOToken token, 
1684            String resourceName, String scope, Map envParameters)
1685            throws PolicyException, SSOException {
1686
1687        String userSSOTokenIDStr =  (token != null) 
1688                ? token.getTokenID().toString() 
1689                : PolicyUtils.EMPTY_STRING;
1690
1691        if (token == null) {
1692            if (DEBUG.messageEnabled()) {
1693                DEBUG.message("user sso token is null, forcing ResourceResult"
1694                        + " evaluation to self_scope");
1695            }
1696            scope = ResourceResult.SELF_SCOPE;
1697
1698        }
1699
1700        ResourceResult resourceResult = null;
1701
1702        if ( (resourceName == null) || (resourceName.equals("")) ) {
1703            resourceName = Rule.EMPTY_RESOURCE_NAME;
1704        }
1705        resourceName = serviceType.canonicalize(resourceName);
1706        Map clientEnv = PolicyUtils.cloneMap(envParameters);
1707
1708
1709        // check if we already have the result in the cache
1710        // policyResultsCache: 
1711        // serviceType -> resource -> sessionId -> scope -> result
1712        synchronized(policyResultsCache) {
1713            // rscCACHE: resource -> sessionId -> scope -> result
1714            Map rscCache = (Map)policyResultsCache.get(serviceTypeName);
1715            if (rscCache != null) {
1716                // resultCACHE: sessionId -> scope -> resourceResult
1717                Map resultsCache = (Map)rscCache.get(resourceName);
1718                if (resultsCache != null) {
1719                    Map results = (Map)resultsCache.get(userSSOTokenIDStr);
1720                    if (results != null) {
1721                        resourceResult = (ResourceResult)results.get(scope);
1722                        if (resourceResult != null) {
1723                            long currentTime = System.currentTimeMillis();
1724                            long ttlMinimal = resourceResult.getTimeToLive();
1725                            if (ttlMinimal > currentTime) {
1726
1727                                //check envMap equality of request and cache
1728                                Map cachedEnv = resourceResult.getEnvMap();
1729                                if ( ((clientEnv == null) 
1730                                            && (cachedEnv == null))
1731                                        || ((clientEnv != null)
1732                                            && clientEnv.equals(cachedEnv)) ) {
1733                                    if (DEBUG.messageEnabled()) {
1734                                        DEBUG.message("PolicyEvaluator."
1735                                        + " getResourceResult(): we get the "
1736                                        + "result from the cache.\n" 
1737                                        + resourceResult.toXML());
1738                                    }
1739                                    return resourceResult;
1740                                } else {
1741                                    if (PolicyManager.debug.messageEnabled()) {
1742                                        PolicyManager.debug.message(
1743                                        "PolicyEvaluator.getResourceesultTree()"
1744                                        + ":cached envMap does not equal "
1745                                        + "request envMap, request envMap = " 
1746                                        + clientEnv 
1747                                        + ", cachedEnv=" + cachedEnv
1748                                        );
1749                                    }
1750                                }
1751                            }
1752                        }
1753                    }
1754                }
1755            }
1756        }
1757
1758        /* compute all action names if passed in actionNames is
1759           null or empty */
1760        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
1761            actionNames = serviceType.getActionNames();
1762        }
1763
1764        if (DEBUG.messageEnabled()) {
1765            DEBUG.message("PolicyEvaluator:computing policy decisions "
1766                    + " for resource : " + resourceName);
1767        }
1768        PolicyDecision policyDecision = getPolicyDecision(token, resourceName,
1769                actionNames, envParameters);
1770        resourceResult =  new ResourceResult(resourceName, policyDecision);
1771
1772        if (ResourceResult.SUBTREE_SCOPE.equals(scope)) {
1773            ResourceResult virtualResourceResult 
1774                    = new ResourceResult(ResourceResult.VIRTUAL_ROOT, 
1775                    new PolicyDecision());
1776            virtualResourceResult.addResourceResult(resourceResult, 
1777                    serviceType);
1778            resourceResult = virtualResourceResult;
1779        }
1780
1781        if (ResourceResult.SUBTREE_SCOPE.equals(scope)
1782                || ResourceResult.STRICT_SUBTREE_SCOPE.equals(scope)) {
1783            Map resourceNamesCache    
1784                    = (Map)resourceNamesMap.get(serviceTypeName);
1785            if (resourceNamesCache == null) {
1786                resourceNamesCache = new Cache(resultsCacheResourceCap);
1787                resourceNamesMap.put(serviceTypeName, resourceNamesCache);
1788            }
1789            Set resourceNames = (Set)resourceNamesCache.get(resourceName);
1790            if (resourceNames == null) {
1791                if (DEBUG.messageEnabled()) {
1792                    DEBUG.message("Computing subresources for:  "
1793                            + resourceName);
1794                }
1795                // true indicates to follow referral
1796                resourceNames = getResourceNames(token, resourceName, true);
1797                resourceNames = removeDuplicateResourceNames(resourceNames,
1798                        serviceType);
1799                resourceNames = removeResourceName(resourceNames,
1800                        serviceType, resourceName);
1801                resourceNamesCache.put(resourceName, resourceNames);
1802            }
1803            if (DEBUG.messageEnabled()) {
1804                DEBUG.message("PolicyEvaluator:computing policy decisions "
1805                        + " for subresources : " + resourceNames);
1806            }
1807
1808            Iterator resourceNameIter = resourceNames.iterator();
1809            while (resourceNameIter.hasNext()) {
1810                String subResourceName = (String) resourceNameIter.next();
1811                if (ResourceResult.SUBTREE_SCOPE.equals(scope) ||
1812                        (serviceType.compare(resourceName,
1813                        subResourceName, false).equals(
1814                        ResourceMatch.SUB_RESOURCE_MATCH))) {
1815                    PolicyDecision pDecision = getPolicyDecision(token, 
1816                            subResourceName, actionNames, envParameters);
1817                    resourceResult.addResourceResult(
1818                            new ResourceResult(subResourceName, pDecision),
1819                            serviceType);
1820                }
1821            }
1822        }
1823  
1824        // Do not cache policy decision with advices
1825        if ( (resourceResult != null) 
1826                    && !resourceResult.hasAdvices()) {
1827            resourceResult.setEnvMap(clientEnv);
1828            // add the evaluation result to the result cache
1829            Map scopeElem = null;
1830            //cacheElem: sessionId -> scope -> resourceResult
1831            Map cacheElem = null;
1832            Map rscElem = null;
1833            // serviceType -> resourceName -> sessionId -> scope -> resourceResult
1834            synchronized(policyResultsCache) { 
1835                // rscElemCACHE: resourceName -> sessionId -> scope -> resourceResult
1836                rscElem = (Map)policyResultsCache.get(
1837                                                serviceTypeName);
1838                if (rscElem != null) { // serviceType has been seen earlier
1839                    //CACHEElem: sessionId -> scope -> resourceResult
1840                    cacheElem = (Map)rscElem.get(resourceName);
1841                    if (cacheElem != null) { // resource seen earlier
1842                        scopeElem = (Map)cacheElem.get(
1843                                                userSSOTokenIDStr);
1844                        if (scopeElem == null) { // seeing sessionId first time
1845                            scopeElem = new HashMap();
1846                        }
1847                    } else { // seeing the resource first time
1848                        if (PolicyManager.debug.messageEnabled()) {
1849                            PolicyManager.debug.message(
1850                                "PolicyEvaluator.getResourceResultTree()"
1851                                + " Create Cache for:" 
1852                                + ", resourceName=" + resourceName
1853                                + ", sessionId=" + userSSOTokenIDStr
1854                                + ", scope=" + scope);
1855                        }
1856                        cacheElem = new Cache(resultsCacheSessionCap); 
1857                        scopeElem = new HashMap();
1858                    }
1859                } else { // seeing service for first time
1860                    // rscElemCACHE: resourceName -> sessionId -> scope -> resourceResult
1861                    rscElem = new Cache(resultsCacheResourceCap);
1862                    //CACHEElem: sessionId -> scope -> resourceResult
1863                    if (PolicyManager.debug.messageEnabled()) {
1864                            PolicyManager.debug.message(
1865                                "PolicyEvaluator.getResourceResultTree()"
1866                                + " Create Cache for:" 
1867                                + ", resourceName=" + resourceName
1868                                + ", sessionId=" + userSSOTokenIDStr
1869                                + ", scope=" + scope
1870                                + ", serviceType=" + serviceTypeName);
1871                    }
1872                    cacheElem = new Cache(resultsCacheSessionCap);
1873                    scopeElem = new HashMap();
1874                }
1875                scopeElem.put(scope, resourceResult);
1876                cacheElem.put(userSSOTokenIDStr, scopeElem);
1877                if (PolicyManager.debug.messageEnabled()) {
1878                        PolicyManager.debug.message(
1879                            "PolicyEvaluator.getResourceResultTree()"
1880                            + " Create Cache for:" 
1881                            + ", resourceName=" + resourceName
1882                            + ", sessionId=" + userSSOTokenIDStr
1883                            + ", scope=" + scope
1884                            + ", cacheSize=" + cacheElem.size());
1885                }
1886                rscElem.put(resourceName, cacheElem);
1887                policyResultsCache.put(serviceTypeName, rscElem);
1888            } 
1889
1890            if ( (token != null) 
1891                        && !(ssoListenerRegistry.containsKey(
1892                        userSSOTokenIDStr))) {
1893                try {
1894                    token.addSSOTokenListener(ssoListener);
1895                } catch (SSOException se) {
1896                    DEBUG.error("PolicyEvaluator:"
1897                            + "failed to add sso token listener");
1898                }
1899                ssoListenerRegistry.put(userSSOTokenIDStr, ssoListener);
1900                if (DEBUG.messageEnabled()) {
1901                    DEBUG.message("PolicyEvaluator.getResourceResultTree():"
1902                            + " sso listener added .\n");
1903                }
1904            }
1905            if (DEBUG.messageEnabled()) {
1906                DEBUG.message("PolicyEvaluator: we added the evaluation "
1907                        + " result to the cache");
1908            }
1909        } 
1910
1911        return resourceResult;
1912    }
1913
1914
1915    /**
1916     * Gets resource names that are exact matches, sub resources or 
1917     * wild card matches of argument resource name.
1918     * To determine whether to include a
1919     * resource name of a resource,  we compare argument resource name and 
1920     * policy resource name, treating wild characters in the policy 
1921     * resource name as wild. If the comparison resulted in
1922     * <code>EXACT_MATCH</code>, <code>WILD_CARD_MACTH</code> or
1923     * <code>SUB_RESOURCE_MACTH</code>, the resource result would be
1924     * included.
1925     *
1926     * @param token single sign on token
1927     *
1928     * @param resourceName resoure name
1929     * @param followReferral indicates whether to follow the referrals 
1930     *                       defined in policies to compute resource names
1931     * @return names of sub resources for the given <code>resourceName</code>.
1932     *         The return value would also include the
1933     *         <code>resourceName</code>.
1934     *
1935     * @exception SSOException if <code>token</code> is invalid
1936     * @exception PolicyException for any other abnormal condition
1937     *
1938     * @see ResourceMatch#EXACT_MATCH
1939     * @see ResourceMatch#SUB_RESOURCE_MATCH
1940     * @see ResourceMatch#WILDCARD_MATCH
1941     *
1942     */
1943     public Set getResourceNames(SSOToken token, String resourceName, 
1944             boolean followReferral) throws PolicyException, SSOException {
1945         Set visitedOrgs = new HashSet();
1946         visitedOrgs.add(policyManager.getOrganizationDN());
1947         return getResourceNames(token, resourceName, followReferral,
1948                 visitedOrgs);
1949     }
1950
1951    /**Gets resource names that are exact matches, sub resources or 
1952     * wild card matches of argument resource name.
1953     * To determine whether to include a
1954     * resource name of a resource,  we compare argument resource name and 
1955     * policy resource name, treating wild characters in the policy 
1956     * resource name as wild. If the comparsion resulted in 
1957     * <code>EXACT_MATCH</code>, <code>WILD_CARD_MACTH</code> or 
1958     * <code>SUB_RESOURCE_MACTH</code>, the resource result would be
1959     * included.
1960     *
1961     * @param token single sign on token
1962     *
1963     * @param resourceName resoure name
1964     * @param followReferral indicates whether to follow the referrals 
1965     *                       defined in policies to compute resource names
1966     * @param visitedOrgs organizations that were already visited to 
1967     *                    compute resource names
1968     * @return names of sub resources for the given <code>resourceName</code>.
1969     *         The return value would also include the
1970     *         <code>resourceName</code>.
1971     *
1972     * @exception SSOException if <code>token</code> is invalid
1973     * @exception PolicyException for any other abnormal condition
1974     *
1975     * @see ResourceMatch#EXACT_MATCH
1976     * @see ResourceMatch#SUB_RESOURCE_MATCH
1977     * @see ResourceMatch#WILDCARD_MATCH
1978     *
1979     */
1980     public Set getResourceNames(SSOToken token, String resourceName, 
1981             boolean followReferral, Set visitedOrgs) 
1982             throws PolicyException, SSOException {
1983         DEBUG.message("PolicyEvaluator.getResourceNames():entering");
1984         Set resourceNames = new HashSet();
1985         Set policyNameSet = null;
1986         Set toRemovePolicyNameSet = null;
1987         Set orgsToVisit = new HashSet();
1988         policyNameSet = resourceIndexManager.getSubResourcePolicyNames(
1989                serviceType, resourceName);
1990         policyNameSet.addAll(
1991                resourceIndexManager.getPolicyNames(serviceType,
1992                resourceName, true)); //include policies of super resources
1993         policyNameSet.addAll(
1994                resourceIndexManager.getWildSubResourcePolicyNames(
1995                serviceType, resourceName));
1996         if ( (policyNameSet != null) && (!policyNameSet.isEmpty()) ) {
1997             Iterator policyIter = policyNameSet.iterator();
1998             while (policyIter.hasNext()) {
1999                 String policyName = (String) policyIter.next();
2000                 Policy policy = policyManager.getPolicy(policyName, 
2001                        USE_POLICY_CACHE);
2002                 // policy could have been deleted
2003                 if ( policy != null && policy.isActive()) {
2004                     // true inidicates to follow referrals
2005                     Set pResourceNames = policy.getResourceNames(token, 
2006                             serviceTypeName, resourceName, true);
2007                     if (pResourceNames != null) {
2008                         resourceNames.addAll(pResourceNames);
2009                     }
2010                 } else { // add policy names to toRemovePolicyNameSet
2011                    if (toRemovePolicyNameSet == null) {
2012                        toRemovePolicyNameSet = new HashSet();
2013                    }
2014                    toRemovePolicyNameSet.add(policyName);
2015                    if ( DEBUG.messageEnabled() ) {
2016                        DEBUG.message("PolicyEvaluator.getResourceNames():"
2017                            +policyName+ " is inactive or non-existent");
2018                    }
2019                 }
2020             }
2021             // remove inactive/missing policies from policyNameSet
2022             if (toRemovePolicyNameSet != null) {
2023                 policyNameSet.removeAll(toRemovePolicyNameSet);
2024             }
2025
2026             orgsToVisit.addAll(getOrgsToVisit(policyNameSet));
2027
2028             if ( DEBUG.messageEnabled() ) {
2029                 DEBUG.message("PolicyEvaluator.getResourceNames():"
2030                     + "realmAliasEnabled=" 
2031                     + PolicyConfig.orgAliasMappedResourcesEnabled()
2032                     + ", serviceTypeName=" + serviceTypeName);
2033             }
2034         }
2035         if (PolicyConfig.orgAliasMappedResourcesEnabled()
2036                && PolicyManager.WEB_AGENT_SERVICE.equalsIgnoreCase(
2037                serviceTypeName)) {
2038             String orgAlias = policyManager.getOrgAliasWithResource(
2039                    resourceName); 
2040             if (orgAlias != null) {
2041                 String orgWithAlias = policyManager.getOrgNameWithAlias(
2042                        orgAlias);
2043                 if (orgWithAlias != null) {
2044                     if ( DEBUG.messageEnabled() ) {
2045                         DEBUG.message("PolicyEvaluator."
2046                                 + "getgetResourceNames():"
2047                                 + "adding orgWithAlias to orgsToVisit="
2048                                 + orgWithAlias);
2049                     }
2050                     orgsToVisit.add(orgWithAlias);
2051                 } else {
2052                     if ( DEBUG.messageEnabled() ) {
2053                         DEBUG.message("PolicyEvaluator."
2054                                 + "getgetResourceNames():"
2055                                 + "no realm matched orgAlias:" + orgAlias);
2056                     }
2057                 }
2058             }
2059         }
2060
2061         orgsToVisit.removeAll(visitedOrgs);
2062         while (!orgsToVisit.isEmpty() ) {
2063             String orgToVisit = (String) orgsToVisit.iterator().next();
2064             orgsToVisit.remove(orgToVisit);
2065             visitedOrgs.add(orgToVisit);
2066             //resourceNames.add(resourceName);
2067             try {
2068                 // need to use admin sso token here. Need all privileges to
2069                 // check for the organzation
2070                 policyManager.verifyOrgName(orgToVisit);
2071             } catch (NameNotFoundException nnfe) {
2072                 if( DEBUG.warningEnabled()) {
2073                     DEBUG.warning("PolicyEvaluator."
2074                            + "getgetResourceNames():"
2075                             + "Organization does not exist - "
2076                             + "skipping referral to " + orgToVisit);
2077                 }
2078                 continue;
2079             }
2080             PolicyEvaluator pe = new PolicyEvaluator(orgToVisit, 
2081                    serviceTypeName);
2082             resourceNames.addAll(pe.getResourceNames(token, 
2083                    resourceName, true,
2084                    visitedOrgs)); 
2085         }
2086         return resourceNames; 
2087     }
2088
2089     /** Adds a policy listener that would be notified whenever a policy
2090      *  is added, removed or changed
2091      *
2092      *  @param policyListener the listener to be added
2093      * 
2094      * @supported.api
2095      */
2096      public void addPolicyListener(PolicyListener policyListener) {
2097          policyCache.addPolicyListener(policyListener);
2098      }
2099
2100     /** Removes a policy listener that was previously registered 
2101      *  to receive notifications whenever a policy is added, removed
2102      *  or changed. It is not an error to attempt to remove a listener
2103      *  that was not registered. It would return silently.
2104      *
2105      *  @param policyListener the listener to be removed
2106      * 
2107      * @supported.api
2108      */
2109      public void removePolicyListener(PolicyListener policyListener) {
2110          policyCache.removePolicyListener(policyListener);
2111      }
2112     
2113      /** Merges two policy decisions.
2114       *  Merging policy decisions merges each action decision of the 
2115       *  policy with the corresponding action decision of the other 
2116       *  policy. This method also merges ResponseProviderDecision of one
2117       *  policy ( response attributes per policy) 
2118       *  with that of the other policy.
2119       *  These are the rules followed to merge each action decision:
2120       *  If the action schema has boolean syntax, boolean false value
2121       *  overrides boolean true value. The time to live of boolean false 
2122       *  value overrides the time to live of boolean true value.
2123       *  Otherwise, action values are simply  aggregated. Time to live
2124       *  is set to the minimum of time to live(s) of all values of the
2125       *  action.
2126       *  For response attributes, all response attributes are aggregated.
2127       *  In case of mutiple values for the same attribute 
2128       *  they appear as multi valued data for the attribute.
2129       *  @param serviceType service type that would be consulted to merge the
2130       *         policy decisions
2131       *  @param pd1 policy decision 1
2132       *  @param pd2 policy decision 2
2133       *  @return the merged policy decision. 
2134       *          Policy decisions pd1 and pd2 are merged into pd2 and 
2135       *          pd2 is returned.
2136       */
2137       static PolicyDecision mergePolicyDecisions(ServiceType
2138            serviceType, PolicyDecision pd1, PolicyDecision pd2) {
2139          Map actionDecisions1 = pd1.getActionDecisions();
2140          Set actions = new HashSet();
2141          actions.addAll(actionDecisions1.keySet());
2142          Iterator iter = actions.iterator();
2143          while ( iter.hasNext() ) {
2144              String action = (String) iter.next();
2145              ActionDecision ad1 = (ActionDecision) actionDecisions1.get(
2146                    action);
2147              pd2.addActionDecision(ad1, serviceType);
2148          }
2149          Map mergedReponseAttrsMap = new HashMap();
2150          PolicyUtils.appendMapToMap(pd1.getResponseAttributes(),
2151                mergedReponseAttrsMap);
2152          PolicyUtils.appendMapToMap(pd2.getResponseAttributes(), 
2153                mergedReponseAttrsMap);
2154          pd2.setResponseAttributes(mergedReponseAttrsMap);
2155          return pd2;
2156      }
2157
2158      /** Gets a set of action names for which final values have been 
2159       *  determined. We assume the final values have been determined
2160       *  for an action if the action schema syntax is boolean and 
2161       *  the value is boolean false value
2162       *
2163       *  @param serviceType service type that would be consulted to decide
2164       *         the final values for actions
2165       *  @param pd policy decision 
2166       */
2167      static Set getFinalizedActions(ServiceType
2168            serviceType, PolicyDecision pd) {
2169        Set finalizedActions = new HashSet();
2170        Map actionDecisions = pd.getActionDecisions();
2171        Iterator actions = actionDecisions.keySet().iterator();
2172        while ( actions.hasNext() ) {
2173            String action = (String) actions.next();
2174            ActionDecision actionDecision 
2175                  = (ActionDecision) actionDecisions.get(action);
2176            Set values = actionDecision.getValues();
2177            if ( (values != null) && !values.isEmpty() ) {
2178                try {
2179                    ActionSchema schema 
2180                            = serviceType.getActionSchema(action);
2181                    if ((AttributeSchema.Syntax.BOOLEAN.equals(
2182                                schema.getSyntax()))
2183                                && values.contains(schema.getFalseValue()) ) {
2184                        finalizedActions.add(action);
2185                    }
2186                } catch(InvalidNameException e) {
2187                    DEBUG.error("can not find action schmea for action = " +
2188                            action, e );
2189                }
2190
2191            }
2192              
2193
2194        }
2195        return finalizedActions;
2196      }
2197
2198    /**
2199     *  Gets names of organizations to visit for policy evaluation
2200     *  based on the give policy names.  This is used to follow 
2201     *  OrgReferral(s) defined in the policies
2202     *
2203     *  @return names of organization to visit
2204     *  @exception SSOException if <code>token</code> is invalid
2205     *  @exception PolicyException for any other abnormal condition
2206     */
2207    private Set getOrgsToVisit(Set policyNameSet) 
2208            throws PolicyException, SSOException {
2209        Set orgsToVisit = new HashSet();
2210        Iterator policyNames = policyNameSet.iterator();
2211        while ( policyNames.hasNext() ) {
2212            String policyName = (String) policyNames.next();
2213            Policy policy = policyManager.getPolicy(policyName, 
2214                USE_POLICY_CACHE);
2215            if (policy != null) {
2216                orgsToVisit.addAll(policy.getReferredToOrganizations());
2217            }
2218        }
2219        return orgsToVisit;
2220    }
2221
2222    /**
2223     *   This would be a costly operation.
2224     *   Can be avoided if ResourceName has api for getting canonical name.
2225     *   When the policies are stored, resource names would be converted to and 
2226     *   stored as canonical name.
2227     */
2228    private static Set removeDuplicateResourceNames(Set resourceNames,
2229            ServiceType serviceType) {
2230        Set answer = resourceNames;
2231        if ( (resourceNames != null) && (serviceType != null) ) {
2232            answer = new HashSet(resourceNames.size());
2233            Iterator iter = resourceNames.iterator();
2234            while ( iter.hasNext() ) {
2235                String resourceName = (String) iter.next();
2236                Iterator answerIter = answer.iterator();
2237                boolean duplicate = false;
2238                while (answerIter.hasNext()) {
2239                    String answerResourceName = (String) answerIter.next();
2240
2241                    if ( serviceType.compare(resourceName,
2242                            answerResourceName, false)
2243                            .equals(ResourceMatch.EXACT_MATCH) ) {
2244                        duplicate = true;
2245                        break;
2246                    } 
2247                } 
2248                if (!duplicate) {
2249                    answer.add(resourceName);
2250                }
2251            }
2252
2253        }
2254        return answer;
2255    }
2256
2257    /**
2258     * Removes the <code>resourceName</code> from the <code>Set</code>
2259     * of resource names matching on <code>serviceType</code> and
2260     * performing a <code>ResourceMatch.EXACT_MATCH</code>
2261     */
2262
2263    private static Set removeResourceName(Set resourceNames, 
2264            ServiceType serviceType, String resourceName) {
2265        Set answer = resourceNames;
2266        if ( (resourceNames != null) && (serviceType != null) 
2267                    && (resourceName != null) ) {
2268            answer = new HashSet(resourceNames.size());
2269            answer.addAll(resourceNames);
2270            Iterator iter = resourceNames.iterator();
2271            while ( iter.hasNext() ) {
2272                String rName = (String) iter.next();
2273                if ( serviceType.compare(resourceName,
2274                        rName, false).equals(ResourceMatch.EXACT_MATCH) ) {
2275                    answer.remove(rName);
2276                }
2277            }
2278
2279        }
2280        return answer;
2281    }
2282
2283
2284    /**
2285     * Handles policyChanged notifications - clears the cached resource
2286     * names for the service type name
2287     *
2288     * @param serviceTypeName service type name
2289     * @param pe policy event
2290     */
2291    static void policyChanged(String serviceTypeName, PolicyEvent pe) {
2292
2293        if (DEBUG.messageEnabled()) {
2294            DEBUG.message("PolicyEvaulator.policyChanged():serviceTypeName="
2295                    + serviceTypeName);
2296        }
2297        resourceNamesMap.remove(serviceTypeName);
2298
2299        Cache resourceNamesCache    
2300                = (Cache)resourceNamesMap.get(serviceTypeName);
2301        if ((resourceNamesCache == null) || (resourceNamesCache.isEmpty())) {
2302            return;
2303        }
2304        try {
2305            DEBUG.error("PolicyEvaluator.policyChanged: enterred try block");
2306            ServiceTypeManager stm = ServiceTypeManager.getServiceTypeManager();
2307            ServiceType serviceType = stm.getServiceType(serviceTypeName);
2308            Set resourceNamesToRemove = new HashSet();
2309            synchronized(resourceNamesCache) {
2310                Enumeration resourceNames = resourceNamesCache.keys();
2311                while (resourceNames.hasMoreElements()) {
2312                    String resourceName = (String)resourceNames.nextElement();
2313                    if (resourceNamesToRemove.contains(resourceName)) {
2314                        continue;
2315                    }
2316                    Set affectedResourceNames = pe.getResourceNames();
2317                    Iterator iter = affectedResourceNames.iterator();
2318                    while (iter.hasNext())  {
2319                        String affectedResourceName = (String)iter.next();
2320                        if (serviceType.compare(resourceName, 
2321                                    affectedResourceName)
2322                                    != ResourceMatch.NO_MATCH) {
2323                            resourceNamesToRemove.add(resourceName);
2324                        }
2325                    }
2326                }
2327                Iterator iter1 = resourceNamesToRemove.iterator();
2328                while (iter1.hasNext()) {
2329                    String resourceNameToRemove = (String) iter1.next();
2330                    resourceNamesCache.remove(resourceNameToRemove);
2331                }
2332            }
2333        } catch (SSOException e) {
2334            DEBUG.error("PolicyEvaluator.policyChanged:", e);
2335        } catch (PolicyException pex) {
2336            DEBUG.error("PolicyEvaluator.policyChanged:", pex);
2337        }
2338        if (DEBUG.messageEnabled()) {
2339            DEBUG.message("PolicyEvaulator.policyChanged():serviceTypeName="
2340                    + serviceTypeName
2341                    + ", new cached resoruceNames=" 
2342                    + resourceNamesMap.get(serviceTypeName));
2343        }
2344    }
2345
2346    /**
2347     * Add an advice to the policy decision.
2348     * @param pd <code>PolicyDecision</code> in which to add the advice.
2349     * @param adviceKey key to the condition generating the advice
2350     *        like SessionCondition.SESSION_CONDITION_ADVICE, 
2351     *        AuthSchemeCondition.AUTH_SCHEME_CONDITION_ADVICE
2352     * @param adviceValue advice message to be added to the advice
2353     */
2354    private static void addAdvice(PolicyDecision pd, String adviceKey, 
2355            String adviceValue) {
2356        if ((pd != null) 
2357                    && (pd.hasAdvices())) {
2358            Map actionDecisions = pd.getActionDecisions();
2359            Iterator actionDecisionIter = actionDecisions.keySet().iterator();
2360            while (actionDecisionIter.hasNext()) {
2361                String key = (String) actionDecisionIter.next();
2362                ActionDecision ad = (ActionDecision) actionDecisions.get(key);
2363                Map advices = ad.getAdvices();
2364                if ((advices != null) && !advices.isEmpty()) {
2365                    Set values = (Set)advices.get(adviceKey);
2366                    if (values == null) {
2367                        values = new HashSet();
2368                    }
2369                    values.add(adviceValue);
2370                    advices.put(adviceKey, values);
2371                }
2372            }
2373        }
2374    }
2375
2376    /**
2377     * Get the policy decision for a resource ignoring the subject
2378     */
2379
2380    PolicyDecision getPolicyDecisionIgnoreSubjects(String resourceName, 
2381            Set actionNames, Map env) throws PolicyException, SSOException  {
2382
2383        Set originalResourceNames = new HashSet(2);
2384        originalResourceNames.add(resourceName);
2385
2386        /*
2387         * Add request resourceName and request actionNames to the envParameters
2388         * so that Condition(s)/ResponseProvider(s) can use them if necessary
2389         */
2390        Set resourceNames = new HashSet(2);
2391        resourceNames.add(resourceName);
2392
2393        /* compute for all action names if passed in actionNames is
2394           null or empty */
2395        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
2396            actionNames = serviceType.getActionNames();
2397        }
2398
2399        Set actions = new HashSet();
2400        if (actionNames != null) {
2401            actions.addAll(actionNames);
2402        }
2403
2404        //We create new HashMap in place of empty map since
2405        //Collections.EMPTY_MAP can not be modified
2406        if ((env == null) || env.isEmpty()) {
2407            env = new HashMap();
2408        }
2409
2410        env.put(SUN_AM_REQUESTED_RESOURCE, resourceNames);
2411        env.put(SUN_AM_ORIGINAL_REQUESTED_RESOURCE, 
2412                originalResourceNames);
2413        env.put(SUN_AM_REQUESTED_ACTIONS, actions);
2414        env.put(SUN_AM_POLICY_CONFIG, 
2415                policyManager.getPolicyConfig());
2416
2417        return getPolicyDecision(null, resourceName, actionNames, env,
2418                new HashSet());
2419    }
2420
2421
2422    /**
2423     * Get the set of role DNs of a user. The role DNs are cached to 
2424     * improve the performance of IdentityServerRole subject membership
2425     * validation.
2426     *
2427     * @param token single sign on token of the user evaluating policies
2428     *
2429     * @return The set of user <code>nsRole</code> attribute values
2430     *
2431     * @exception SSOException single-sign-on token invalid or expired
2432     * @exception PolicyException if an error occured while getting the
2433     *            user's nsRole attribute value set
2434     */
2435     public static Set getUserNSRoleValues(SSOToken token)
2436        throws SSOException, PolicyException {
2437        if (userNSRoleCacheTTL == 0) {
2438            synchronized(userNSRoleCache) {
2439                String orgName = ServiceManager.getBaseDN();
2440                Map pConfigValues = PolicyConfig.getPolicyConfig(orgName);
2441                userNSRoleCacheTTL = 
2442                     PolicyConfig.getSubjectsResultTtl(pConfigValues);
2443                if (userNSRoleCacheTTL <= 0) {
2444                    userNSRoleCacheTTL = DEFAULT_USER_NSROLE_CACHE_TTL;
2445                    if (DEBUG.warningEnabled()) {
2446                        DEBUG.warning("Invalid TTL got from configuration."
2447                                    + " Set TTL to default:" 
2448                                    + userNSRoleCacheTTL);
2449                    }
2450                }
2451                if (DEBUG.messageEnabled()) {
2452                    DEBUG.message("userNSRoleCacheTTL=" 
2453                                   + userNSRoleCacheTTL);
2454                }
2455            }
2456        }
2457        if (token == null) {
2458            return null;
2459        }
2460        String tokenIDStr = token.getTokenID().toString();
2461        Object[] element = (Object[])userNSRoleCache.get(tokenIDStr);
2462        if (element != null) {
2463            Long timeStamp = (Long)element[0];
2464            long timeToLive = 0;
2465            if (timeStamp != null) {
2466                timeToLive = timeStamp.longValue();
2467            }
2468            long currentTime = System.currentTimeMillis();
2469            if (timeToLive > currentTime) {
2470                if (DEBUG.messageEnabled()) {
2471                    DEBUG.message("PolicyEvaluator.getUserNSRoleValues():"
2472                              + " get the nsRole values from cache.\n");
2473                }
2474                return (HashSet)element[1];
2475            }
2476        }
2477        // add or update the cache entry.
2478        // we come here either the token is first registered with the
2479        // cache or the cache element is out of date. 
2480        try {
2481            AMStoreConnection am = new AMStoreConnection(token);
2482            AMUser user = am.getUser(token.getPrincipal().getName());
2483            if ((user == null) || !(user.isActivated())) {
2484                return null;
2485            }
2486            Set roleSet = new HashSet();
2487            Set roles = new HashSet();
2488            // get all the roles assigned to the user
2489            Set staticRoles = user.getRoleDNs();
2490            Set filteredRoles = user.getFilteredRoleDNs();
2491            if (staticRoles != null) {
2492                roles.addAll(staticRoles);
2493            }
2494            if (filteredRoles != null) {
2495                roles.addAll(filteredRoles);
2496            }
2497            if (!roles.isEmpty()) {
2498                Iterator iter = roles.iterator();
2499                while (iter.hasNext()) {
2500                    String role = (String) iter.next();
2501                    if (role != null) { 
2502                        roleSet.add((new DN(role)).toRFCString().toLowerCase());
2503                    }
2504                }
2505            }
2506            if (DEBUG.messageEnabled()) {
2507                DEBUG.message("PolicyEvaluator.getUserNSRoleValues():"
2508                            + " added user nsRoles: " + roleSet);
2509            }
2510            Object[] elem = new Object[2];
2511            elem[0] = new Long(System.currentTimeMillis() 
2512                               + userNSRoleCacheTTL);
2513            elem[1] = roleSet;
2514            userNSRoleCache.put(tokenIDStr, elem);
2515            if (!ssoListenerRegistry.containsKey(tokenIDStr)) {
2516                token.addSSOTokenListener(ssoListener);
2517                ssoListenerRegistry.put(tokenIDStr, ssoListener);
2518                if (DEBUG.messageEnabled()) {
2519                    DEBUG.message("PolicyEvaluator.getUserNSRoleValues():"
2520                            + " sso listener added .\n");
2521                }
2522            }
2523            return roleSet;
2524        } catch (AMException e) {
2525            throw (new PolicyException(e));
2526        }
2527    }
2528
2529    /**
2530     * record stats for policyResultsCache,  ssoListenerRegistry, 
2531     * policyListenerRegistry, userNSRoleCache, resouceNamesMap
2532     */
2533    static void printStats(Stats policyStats) {
2534
2535
2536        int resultsCacheSize = 0;
2537        synchronized (policyResultsCache) {
2538            resultsCacheSize = policyResultsCache.size();
2539        }
2540        policyStats.record("PolicyEvaluator: Number of services in "
2541                + " resultsCache: " + resultsCacheSize);
2542
2543        policyStats.record("PolicyEvaluator: Number of token IDs in "
2544                + " sessionListernerRgistry:"
2545                + ssoListenerRegistry.size());
2546
2547        policyStats.record("PolicyEvaluator: Number of serviceNames "
2548                + " in policyListenerRegistry: "
2549                + policyListenerRegistry.size());
2550
2551        policyStats.record("PolicyEvaluator: Number of token IDs "
2552                + " in role cahce: " + userNSRoleCache.size());
2553
2554        policyStats.record("PolicyEvaluator:Number of serviceNames in "
2555                + " resourceNames cache: " 
2556                + resourceNamesMap.size());
2557    }
2558}