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}