001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.shiro.realm; 020 021import org.apache.shiro.authc.credential.CredentialsMatcher; 022import org.apache.shiro.authz.*; 023import org.apache.shiro.authz.permission.*; 024import org.apache.shiro.cache.Cache; 025import org.apache.shiro.cache.CacheManager; 026import org.apache.shiro.subject.PrincipalCollection; 027import org.apache.shiro.util.CollectionUtils; 028import org.apache.shiro.util.Initializable; 029import org.apache.shiro.util.StringUtils; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033import java.util.*; 034import java.util.concurrent.atomic.AtomicInteger; 035 036 037/** 038 * An {@code AuthorizingRealm} extends the {@code AuthenticatingRealm}'s capabilities by adding Authorization 039 * (access control) support. 040 * <p/> 041 * This implementation will perform all role and permission checks automatically (and subclasses do not have to 042 * write this logic) as long as the 043 * {@link #getAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)} method returns an 044 * {@link AuthorizationInfo}. Please see that method's JavaDoc for an in-depth explanation. 045 * <p/> 046 * If you find that you do not want to utilize the {@link AuthorizationInfo AuthorizationInfo} construct, 047 * you are of course free to subclass the {@link AuthenticatingRealm AuthenticatingRealm} directly instead and 048 * implement the remaining Realm interface methods directly. You might do this if you want have better control 049 * over how the Role and Permission checks occur for your specific data source. However, using AuthorizationInfo 050 * (and its default implementation {@link org.apache.shiro.authz.SimpleAuthorizationInfo SimpleAuthorizationInfo}) is sufficient in the large 051 * majority of Realm cases. 052 * 053 * @see org.apache.shiro.authz.SimpleAuthorizationInfo 054 * @since 0.2 055 */ 056public abstract class AuthorizingRealm extends AuthenticatingRealm 057 implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware { 058 059 //TODO - complete JavaDoc 060 061 /*------------------------------------------- 062 | C O N S T A N T S | 063 ============================================*/ 064 private static final Logger log = LoggerFactory.getLogger(AuthorizingRealm.class); 065 066 /** 067 * The default suffix appended to the realm name for caching AuthorizationInfo instances. 068 */ 069 private static final String DEFAULT_AUTHORIZATION_CACHE_SUFFIX = ".authorizationCache"; 070 071 private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger(); 072 073 /*------------------------------------------- 074 | I N S T A N C E V A R I A B L E S | 075 ============================================*/ 076 /** 077 * The cache used by this realm to store AuthorizationInfo instances associated with individual Subject principals. 078 */ 079 private boolean authorizationCachingEnabled; 080 private Cache<Object, AuthorizationInfo> authorizationCache; 081 private String authorizationCacheName; 082 083 private PermissionResolver permissionResolver; 084 085 private RolePermissionResolver permissionRoleResolver; 086 087 /*------------------------------------------- 088 | C O N S T R U C T O R S | 089 ============================================*/ 090 091 public AuthorizingRealm() { 092 this(null, null); 093 } 094 095 public AuthorizingRealm(CacheManager cacheManager) { 096 this(cacheManager, null); 097 } 098 099 public AuthorizingRealm(CredentialsMatcher matcher) { 100 this(null, matcher); 101 } 102 103 public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) { 104 super(); 105 if (cacheManager != null) setCacheManager(cacheManager); 106 if (matcher != null) setCredentialsMatcher(matcher); 107 108 this.authorizationCachingEnabled = true; 109 this.permissionResolver = new WildcardPermissionResolver(); 110 111 int instanceNumber = INSTANCE_COUNT.getAndIncrement(); 112 this.authorizationCacheName = getClass().getName() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX; 113 if (instanceNumber > 0) { 114 this.authorizationCacheName = this.authorizationCacheName + "." + instanceNumber; 115 } 116 } 117 118 /*------------------------------------------- 119 | A C C E S S O R S / M O D I F I E R S | 120 ============================================*/ 121 122 public void setName(String name) { 123 super.setName(name); 124 String authzCacheName = this.authorizationCacheName; 125 if (authzCacheName != null && authzCacheName.startsWith(getClass().getName())) { 126 //get rid of the default class-name based cache name. Create a more meaningful one 127 //based on the application-unique Realm name: 128 this.authorizationCacheName = name + DEFAULT_AUTHORIZATION_CACHE_SUFFIX; 129 } 130 } 131 132 public void setAuthorizationCache(Cache<Object, AuthorizationInfo> authorizationCache) { 133 this.authorizationCache = authorizationCache; 134 } 135 136 public Cache<Object, AuthorizationInfo> getAuthorizationCache() { 137 return this.authorizationCache; 138 } 139 140 public String getAuthorizationCacheName() { 141 return authorizationCacheName; 142 } 143 144 @SuppressWarnings({"UnusedDeclaration"}) 145 public void setAuthorizationCacheName(String authorizationCacheName) { 146 this.authorizationCacheName = authorizationCacheName; 147 } 148 149 /** 150 * Returns {@code true} if authorization caching should be utilized if a {@link CacheManager} has been 151 * {@link #setCacheManager(org.apache.shiro.cache.CacheManager) configured}, {@code false} otherwise. 152 * <p/> 153 * The default value is {@code true}. 154 * 155 * @return {@code true} if authorization caching should be utilized, {@code false} otherwise. 156 */ 157 public boolean isAuthorizationCachingEnabled() { 158 return isCachingEnabled() && authorizationCachingEnabled; 159 } 160 161 /** 162 * Sets whether or not authorization caching should be utilized if a {@link CacheManager} has been 163 * {@link #setCacheManager(org.apache.shiro.cache.CacheManager) configured}, {@code false} otherwise. 164 * <p/> 165 * The default value is {@code true}. 166 * 167 * @param authenticationCachingEnabled the value to set 168 */ 169 @SuppressWarnings({"UnusedDeclaration"}) 170 public void setAuthorizationCachingEnabled(boolean authenticationCachingEnabled) { 171 this.authorizationCachingEnabled = authenticationCachingEnabled; 172 if (authenticationCachingEnabled) { 173 setCachingEnabled(true); 174 } 175 } 176 177 public PermissionResolver getPermissionResolver() { 178 return permissionResolver; 179 } 180 181 public void setPermissionResolver(PermissionResolver permissionResolver) { 182 if (permissionResolver == null) throw new IllegalArgumentException("Null PermissionResolver is not allowed"); 183 this.permissionResolver = permissionResolver; 184 } 185 186 public RolePermissionResolver getRolePermissionResolver() { 187 return permissionRoleResolver; 188 } 189 190 public void setRolePermissionResolver(RolePermissionResolver permissionRoleResolver) { 191 this.permissionRoleResolver = permissionRoleResolver; 192 } 193 194 /*-------------------------------------------- 195 | M E T H O D S | 196 ============================================*/ 197 198 /** 199 * Initializes this realm and potentially enables a cache, depending on configuration. 200 * <p/> 201 * When this method is called, the following logic is executed: 202 * <ol> 203 * <li>If the {@link #setAuthorizationCache cache} property has been set, it will be 204 * used to cache the AuthorizationInfo objects returned from {@link #getAuthorizationInfo} 205 * method invocations. 206 * All future calls to {@code getAuthorizationInfo} will attempt to use this cache first 207 * to alleviate any potentially unnecessary calls to an underlying data store.</li> 208 * <li>If the {@link #setAuthorizationCache cache} property has <b>not</b> been set, 209 * the {@link #setCacheManager cacheManager} property will be checked. 210 * If a {@code cacheManager} has been set, it will be used to create an authorization 211 * {@code cache}, and this newly created cache which will be used as specified in #1.</li> 212 * <li>If neither the {@link #setAuthorizationCache (org.apache.shiro.cache.Cache) cache} 213 * or {@link #setCacheManager(org.apache.shiro.cache.CacheManager) cacheManager} 214 * properties are set, caching will be disabled and authorization look-ups will be delegated to 215 * subclass implementations for each authorization check.</li> 216 * </ol> 217 */ 218 protected void onInit() { 219 super.onInit(); 220 //trigger obtaining the authorization cache if possible 221 getAvailableAuthorizationCache(); 222 } 223 224 protected void afterCacheManagerSet() { 225 super.afterCacheManagerSet(); 226 //trigger obtaining the authorization cache if possible 227 getAvailableAuthorizationCache(); 228 } 229 230 private Cache<Object, AuthorizationInfo> getAuthorizationCacheLazy() { 231 232 if (this.authorizationCache == null) { 233 234 if (log.isDebugEnabled()) { 235 log.debug("No authorizationCache instance set. Checking for a cacheManager..."); 236 } 237 238 CacheManager cacheManager = getCacheManager(); 239 240 if (cacheManager != null) { 241 String cacheName = getAuthorizationCacheName(); 242 if (log.isDebugEnabled()) { 243 log.debug("CacheManager [" + cacheManager + "] has been configured. Building " + 244 "authorization cache named [" + cacheName + "]"); 245 } 246 this.authorizationCache = cacheManager.getCache(cacheName); 247 } else { 248 if (log.isDebugEnabled()) { 249 log.debug("No cache or cacheManager properties have been set. Authorization cache cannot " + 250 "be obtained."); 251 } 252 } 253 } 254 255 return this.authorizationCache; 256 } 257 258 private Cache<Object, AuthorizationInfo> getAvailableAuthorizationCache() { 259 Cache<Object, AuthorizationInfo> cache = getAuthorizationCache(); 260 if (cache == null && isAuthorizationCachingEnabled()) { 261 cache = getAuthorizationCacheLazy(); 262 } 263 return cache; 264 } 265 266 /** 267 * Returns an account's authorization-specific information for the specified {@code principals}, 268 * or {@code null} if no account could be found. The resulting {@code AuthorizationInfo} object is used 269 * by the other method implementations in this class to automatically perform access control checks for the 270 * corresponding {@code Subject}. 271 * <p/> 272 * This implementation obtains the actual {@code AuthorizationInfo} object from the subclass's 273 * implementation of 274 * {@link #doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection) doGetAuthorizationInfo}, and then 275 * caches it for efficient reuse if caching is enabled (see below). 276 * <p/> 277 * Invocations of this method should be thought of as completely orthogonal to acquiring 278 * {@link #getAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) authenticationInfo}, since either could 279 * occur in any order. 280 * <p/> 281 * For example, in "Remember Me" scenarios, the user identity is remembered (and 282 * assumed) for their current session and an authentication attempt during that session might never occur. 283 * But because their identity would be remembered, that is sufficient enough information to call this method to 284 * execute any necessary authorization checks. For this reason, authentication and authorization should be 285 * loosely coupled and not depend on each other. 286 * <h3>Caching</h3> 287 * The {@code AuthorizationInfo} values returned from this method are cached for efficient reuse 288 * if caching is enabled. Caching is enabled automatically when an {@link #setAuthorizationCache authorizationCache} 289 * instance has been explicitly configured, or if a {@link #setCacheManager cacheManager} has been configured, which 290 * will be used to lazily create the {@code authorizationCache} as needed. 291 * <p/> 292 * If caching is enabled, the authorization cache will be checked first and if found, will return the cached 293 * {@code AuthorizationInfo} immediately. If caching is disabled, or there is a cache miss, the authorization 294 * info will be looked up from the underlying data store via the 295 * {@link #doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)} method, which must be implemented 296 * by subclasses. 297 * <h4>Changed Data</h4> 298 * If caching is enabled and if any authorization data for an account is changed at 299 * runtime, such as adding or removing roles and/or permissions, the subclass implementation should clear the 300 * cached AuthorizationInfo for that account via the 301 * {@link #clearCachedAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection) clearCachedAuthorizationInfo} 302 * method. This ensures that the next call to {@code getAuthorizationInfo(PrincipalCollection)} will 303 * acquire the account's fresh authorization data, where it will then be cached for efficient reuse. This 304 * ensures that stale authorization data will not be reused. 305 * 306 * @param principals the corresponding Subject's identifying principals with which to look up the Subject's 307 * {@code AuthorizationInfo}. 308 * @return the authorization information for the account associated with the specified {@code principals}, 309 * or {@code null} if no account could be found. 310 */ 311 protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { 312 313 if (principals == null) { 314 return null; 315 } 316 317 AuthorizationInfo info = null; 318 319 if (log.isTraceEnabled()) { 320 log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]"); 321 } 322 323 Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache(); 324 if (cache != null) { 325 if (log.isTraceEnabled()) { 326 log.trace("Attempting to retrieve the AuthorizationInfo from cache."); 327 } 328 Object key = getAuthorizationCacheKey(principals); 329 info = cache.get(key); 330 if (log.isTraceEnabled()) { 331 if (info == null) { 332 log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]"); 333 } else { 334 log.trace("AuthorizationInfo found in cache for principals [" + principals + "]"); 335 } 336 } 337 } 338 339 340 if (info == null) { 341 // Call template method if the info was not found in a cache 342 info = doGetAuthorizationInfo(principals); 343 // If the info is not null and the cache has been created, then cache the authorization info. 344 if (info != null && cache != null) { 345 if (log.isTraceEnabled()) { 346 log.trace("Caching authorization info for principals: [" + principals + "]."); 347 } 348 Object key = getAuthorizationCacheKey(principals); 349 cache.put(key, info); 350 } 351 } 352 353 return info; 354 } 355 356 protected Object getAuthorizationCacheKey(PrincipalCollection principals) { 357 return principals; 358 } 359 360 /** 361 * Clears out the AuthorizationInfo cache entry for the specified account. 362 * <p/> 363 * This method is provided as a convenience to subclasses so they can invalidate a cache entry when they 364 * change an account's authorization data (add/remove roles or permissions) during runtime. Because an account's 365 * AuthorizationInfo can be cached, there needs to be a way to invalidate the cache for only that account so that 366 * subsequent authorization operations don't used the (old) cached value if account data changes. 367 * <p/> 368 * After this method is called, the next authorization check for that same account will result in a call to 369 * {@link #getAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection) getAuthorizationInfo}, and the 370 * resulting return value will be cached before being returned so it can be reused for later authorization checks. 371 * <p/> 372 * If you wish to clear out all associated cached data (and not just authorization data), use the 373 * {@link #clearCache(org.apache.shiro.subject.PrincipalCollection)} method instead (which will in turn call this 374 * method by default). 375 * 376 * @param principals the principals of the account for which to clear the cached AuthorizationInfo. 377 */ 378 protected void clearCachedAuthorizationInfo(PrincipalCollection principals) { 379 if (principals == null) { 380 return; 381 } 382 383 Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache(); 384 //cache instance will be non-null if caching is enabled: 385 if (cache != null) { 386 Object key = getAuthorizationCacheKey(principals); 387 cache.remove(key); 388 } 389 } 390 391 /** 392 * Retrieves the AuthorizationInfo for the given principals from the underlying data store. When returning 393 * an instance from this method, you might want to consider using an instance of 394 * {@link org.apache.shiro.authz.SimpleAuthorizationInfo SimpleAuthorizationInfo}, as it is suitable in most cases. 395 * 396 * @param principals the primary identifying principals of the AuthorizationInfo that should be retrieved. 397 * @return the AuthorizationInfo associated with this principals. 398 * @see org.apache.shiro.authz.SimpleAuthorizationInfo 399 */ 400 protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals); 401 402 //visibility changed from private to protected per SHIRO-332 403 protected Collection<Permission> getPermissions(AuthorizationInfo info) { 404 Set<Permission> permissions = new HashSet<Permission>(); 405 406 if (info != null) { 407 Collection<Permission> perms = info.getObjectPermissions(); 408 if (!CollectionUtils.isEmpty(perms)) { 409 permissions.addAll(perms); 410 } 411 perms = resolvePermissions(info.getStringPermissions()); 412 if (!CollectionUtils.isEmpty(perms)) { 413 permissions.addAll(perms); 414 } 415 416 perms = resolveRolePermissions(info.getRoles()); 417 if (!CollectionUtils.isEmpty(perms)) { 418 permissions.addAll(perms); 419 } 420 } 421 422 if (permissions.isEmpty()) { 423 return Collections.emptySet(); 424 } else { 425 return Collections.unmodifiableSet(permissions); 426 } 427 } 428 429 private Collection<Permission> resolvePermissions(Collection<String> stringPerms) { 430 Collection<Permission> perms = Collections.emptySet(); 431 PermissionResolver resolver = getPermissionResolver(); 432 if (resolver != null && !CollectionUtils.isEmpty(stringPerms)) { 433 perms = new LinkedHashSet<Permission>(stringPerms.size()); 434 for (String strPermission : stringPerms) { 435 if (StringUtils.clean(strPermission) != null) { 436 Permission permission = resolver.resolvePermission(strPermission); 437 perms.add(permission); 438 } 439 } 440 } 441 return perms; 442 } 443 444 private Collection<Permission> resolveRolePermissions(Collection<String> roleNames) { 445 Collection<Permission> perms = Collections.emptySet(); 446 RolePermissionResolver resolver = getRolePermissionResolver(); 447 if (resolver != null && !CollectionUtils.isEmpty(roleNames)) { 448 perms = new LinkedHashSet<Permission>(roleNames.size()); 449 for (String roleName : roleNames) { 450 Collection<Permission> resolved = resolver.resolvePermissionsInRole(roleName); 451 if (!CollectionUtils.isEmpty(resolved)) { 452 perms.addAll(resolved); 453 } 454 } 455 } 456 return perms; 457 } 458 459 public boolean isPermitted(PrincipalCollection principals, String permission) { 460 Permission p = getPermissionResolver().resolvePermission(permission); 461 return isPermitted(principals, p); 462 } 463 464 public boolean isPermitted(PrincipalCollection principals, Permission permission) { 465 AuthorizationInfo info = getAuthorizationInfo(principals); 466 return isPermitted(permission, info); 467 } 468 469 //visibility changed from private to protected per SHIRO-332 470 protected boolean isPermitted(Permission permission, AuthorizationInfo info) { 471 Collection<Permission> perms = getPermissions(info); 472 if (perms != null && !perms.isEmpty()) { 473 for (Permission perm : perms) { 474 if (perm.implies(permission)) { 475 return true; 476 } 477 } 478 } 479 return false; 480 } 481 482 public boolean[] isPermitted(PrincipalCollection subjectIdentifier, String... permissions) { 483 List<Permission> perms = new ArrayList<Permission>(permissions.length); 484 for (String permString : permissions) { 485 perms.add(getPermissionResolver().resolvePermission(permString)); 486 } 487 return isPermitted(subjectIdentifier, perms); 488 } 489 490 public boolean[] isPermitted(PrincipalCollection principals, List<Permission> permissions) { 491 AuthorizationInfo info = getAuthorizationInfo(principals); 492 return isPermitted(permissions, info); 493 } 494 495 protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) { 496 boolean[] result; 497 if (permissions != null && !permissions.isEmpty()) { 498 int size = permissions.size(); 499 result = new boolean[size]; 500 int i = 0; 501 for (Permission p : permissions) { 502 result[i++] = isPermitted(p, info); 503 } 504 } else { 505 result = new boolean[0]; 506 } 507 return result; 508 } 509 510 public boolean isPermittedAll(PrincipalCollection subjectIdentifier, String... permissions) { 511 if (permissions != null && permissions.length > 0) { 512 Collection<Permission> perms = new ArrayList<Permission>(permissions.length); 513 for (String permString : permissions) { 514 perms.add(getPermissionResolver().resolvePermission(permString)); 515 } 516 return isPermittedAll(subjectIdentifier, perms); 517 } 518 return false; 519 } 520 521 public boolean isPermittedAll(PrincipalCollection principal, Collection<Permission> permissions) { 522 AuthorizationInfo info = getAuthorizationInfo(principal); 523 return info != null && isPermittedAll(permissions, info); 524 } 525 526 protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) { 527 if (permissions != null && !permissions.isEmpty()) { 528 for (Permission p : permissions) { 529 if (!isPermitted(p, info)) { 530 return false; 531 } 532 } 533 } 534 return true; 535 } 536 537 public void checkPermission(PrincipalCollection subjectIdentifier, String permission) throws AuthorizationException { 538 Permission p = getPermissionResolver().resolvePermission(permission); 539 checkPermission(subjectIdentifier, p); 540 } 541 542 public void checkPermission(PrincipalCollection principal, Permission permission) throws AuthorizationException { 543 AuthorizationInfo info = getAuthorizationInfo(principal); 544 checkPermission(permission, info); 545 } 546 547 protected void checkPermission(Permission permission, AuthorizationInfo info) { 548 if (!isPermitted(permission, info)) { 549 String msg = "User is not permitted [" + permission + "]"; 550 throw new UnauthorizedException(msg); 551 } 552 } 553 554 public void checkPermissions(PrincipalCollection subjectIdentifier, String... permissions) throws AuthorizationException { 555 if (permissions != null) { 556 for (String permString : permissions) { 557 checkPermission(subjectIdentifier, permString); 558 } 559 } 560 } 561 562 public void checkPermissions(PrincipalCollection principal, Collection<Permission> permissions) throws AuthorizationException { 563 AuthorizationInfo info = getAuthorizationInfo(principal); 564 checkPermissions(permissions, info); 565 } 566 567 protected void checkPermissions(Collection<Permission> permissions, AuthorizationInfo info) { 568 if (permissions != null && !permissions.isEmpty()) { 569 for (Permission p : permissions) { 570 checkPermission(p, info); 571 } 572 } 573 } 574 575 public boolean hasRole(PrincipalCollection principal, String roleIdentifier) { 576 AuthorizationInfo info = getAuthorizationInfo(principal); 577 return hasRole(roleIdentifier, info); 578 } 579 580 protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) { 581 return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier); 582 } 583 584 public boolean[] hasRoles(PrincipalCollection principal, List<String> roleIdentifiers) { 585 AuthorizationInfo info = getAuthorizationInfo(principal); 586 boolean[] result = new boolean[roleIdentifiers != null ? roleIdentifiers.size() : 0]; 587 if (info != null) { 588 result = hasRoles(roleIdentifiers, info); 589 } 590 return result; 591 } 592 593 protected boolean[] hasRoles(List<String> roleIdentifiers, AuthorizationInfo info) { 594 boolean[] result; 595 if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) { 596 int size = roleIdentifiers.size(); 597 result = new boolean[size]; 598 int i = 0; 599 for (String roleName : roleIdentifiers) { 600 result[i++] = hasRole(roleName, info); 601 } 602 } else { 603 result = new boolean[0]; 604 } 605 return result; 606 } 607 608 public boolean hasAllRoles(PrincipalCollection principal, Collection<String> roleIdentifiers) { 609 AuthorizationInfo info = getAuthorizationInfo(principal); 610 return info != null && hasAllRoles(roleIdentifiers, info); 611 } 612 613 private boolean hasAllRoles(Collection<String> roleIdentifiers, AuthorizationInfo info) { 614 if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) { 615 for (String roleName : roleIdentifiers) { 616 if (!hasRole(roleName, info)) { 617 return false; 618 } 619 } 620 } 621 return true; 622 } 623 624 public void checkRole(PrincipalCollection principal, String role) throws AuthorizationException { 625 AuthorizationInfo info = getAuthorizationInfo(principal); 626 checkRole(role, info); 627 } 628 629 protected void checkRole(String role, AuthorizationInfo info) { 630 if (!hasRole(role, info)) { 631 String msg = "User does not have role [" + role + "]"; 632 throw new UnauthorizedException(msg); 633 } 634 } 635 636 public void checkRoles(PrincipalCollection principal, Collection<String> roles) throws AuthorizationException { 637 AuthorizationInfo info = getAuthorizationInfo(principal); 638 checkRoles(roles, info); 639 } 640 641 public void checkRoles(PrincipalCollection principal, String... roles) throws AuthorizationException { 642 checkRoles(principal, Arrays.asList(roles)); 643 } 644 645 protected void checkRoles(Collection<String> roles, AuthorizationInfo info) { 646 if (roles != null && !roles.isEmpty()) { 647 for (String roleName : roles) { 648 checkRole(roleName, info); 649 } 650 } 651 } 652 653 /** 654 * Calls {@code super.doClearCache} to ensure any cached authentication data is removed and then calls 655 * {@link #clearCachedAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)} to remove any cached 656 * authorization data. 657 * <p/> 658 * If overriding in a subclass, be sure to call {@code super.doClearCache} to ensure this behavior is maintained. 659 * 660 * @param principals the principals of the account for which to clear any cached AuthorizationInfo 661 * @since 1.2 662 */ 663 @Override 664 protected void doClearCache(PrincipalCollection principals) { 665 super.doClearCache(principals); 666 clearCachedAuthorizationInfo(principals); 667 } 668}