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