1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.shiro.authz; 20 21 import org.apache.shiro.authz.permission.PermissionResolver; 22 import org.apache.shiro.authz.permission.PermissionResolverAware; 23 import org.apache.shiro.authz.permission.RolePermissionResolver; 24 import org.apache.shiro.authz.permission.RolePermissionResolverAware; 25 import org.apache.shiro.realm.Realm; 26 import org.apache.shiro.subject.PrincipalCollection; 27 28 import java.util.Collection; 29 import java.util.List; 30 31 32 /** 33 * A <tt>ModularRealmAuthorizer</tt> is an <tt>Authorizer</tt> implementation that consults one or more configured 34 * {@link Realm Realm}s during an authorization operation. 35 * 36 * @since 0.2 37 */ 38 public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware { 39 40 /** 41 * The realms to consult during any authorization check. 42 */ 43 protected Collection<Realm> realms; 44 45 /** 46 * A PermissionResolver to be used by <em>all</em> configured realms. Leave <code>null</code> if you wish 47 * to configure different resolvers for different realms. 48 */ 49 protected PermissionResolver permissionResolver; 50 51 /** 52 * A RolePermissionResolver to be used by <em>all</em> configured realms. Leave <code>null</code> if you wish 53 * to configure different resolvers for different realms. 54 */ 55 protected RolePermissionResolver rolePermissionResolver; 56 57 /** 58 * Default no-argument constructor, does nothing. 59 */ 60 public ModularRealmAuthorizer() { 61 } 62 63 /** 64 * Constructor that accepts the <code>Realm</code>s to consult during an authorization check. Immediately calls 65 * {@link #setRealms setRealms(realms)}. 66 * 67 * @param realms the realms to consult during an authorization check. 68 */ 69 public ModularRealmAuthorizer(Collection<Realm> realms) { 70 setRealms(realms); 71 } 72 73 /** 74 * Returns the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check. 75 * 76 * @return the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check. 77 */ 78 public Collection<Realm> getRealms() { 79 return this.realms; 80 } 81 82 /** 83 * Sets the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check. 84 * 85 * @param realms the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check. 86 */ 87 public void setRealms(Collection<Realm> realms) { 88 this.realms = realms; 89 applyPermissionResolverToRealms(); 90 applyRolePermissionResolverToRealms(); 91 } 92 93 /** 94 * Returns the PermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default) 95 * if all realm instances will each configure their own permission resolver. 96 * 97 * @return the PermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default) 98 * if realm instances will each configure their own permission resolver. 99 * @since 1.0 100 */ 101 public PermissionResolver getPermissionResolver() { 102 return this.permissionResolver; 103 } 104 105 /** 106 * Sets the specified {@link PermissionResolver PermissionResolver} on <em>all</em> of the wrapped realms that 107 * implement the {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} interface. 108 * <p/> 109 * Only call this method if you want the permission resolver to be passed to all realms that implement the 110 * <code>PermissionResolver</code> interface. If you do not want this to occur, the realms must 111 * configure themselves individually (or be configured individually). 112 * 113 * @param permissionResolver the permissionResolver to set on all of the wrapped realms that implement the 114 * {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} interface. 115 */ 116 public void setPermissionResolver(PermissionResolver permissionResolver) { 117 this.permissionResolver = permissionResolver; 118 applyPermissionResolverToRealms(); 119 } 120 121 /** 122 * Sets the internal {@link #getPermissionResolver} on any internal configured 123 * {@link #getRealms Realms} that implement the {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} interface. 124 * <p/> 125 * This method is called after setting a permissionResolver on this ModularRealmAuthorizer via the 126 * {@link #setPermissionResolver(org.apache.shiro.authz.permission.PermissionResolver) setPermissionResolver} method. 127 * <p/> 128 * It is also called after setting one or more realms via the {@link #setRealms setRealms} method to allow these 129 * newly available realms to be given the <code>PermissionResolver</code> already in use. 130 * 131 * @since 1.0 132 */ 133 protected void applyPermissionResolverToRealms() { 134 PermissionResolver resolver = getPermissionResolver(); 135 Collection<Realm> realms = getRealms(); 136 if (resolver != null && realms != null && !realms.isEmpty()) { 137 for (Realm realm : realms) { 138 if (realm instanceof PermissionResolverAware) { 139 ((PermissionResolverAware) realm).setPermissionResolver(resolver); 140 } 141 } 142 } 143 } 144 145 /** 146 * Returns the RolePermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default) 147 * if all realm instances will each configure their own permission resolver. 148 * 149 * @return the RolePermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default) 150 * if realm instances will each configure their own role permission resolver. 151 * @since 1.0 152 */ 153 public RolePermissionResolver getRolePermissionResolver() { 154 return this.rolePermissionResolver; 155 } 156 157 /** 158 * Sets the specified {@link RolePermissionResolver RolePermissionResolver} on <em>all</em> of the wrapped realms that 159 * implement the {@link org.apache.shiro.authz.permission.RolePermissionResolverAware PermissionResolverAware} interface. 160 * <p/> 161 * Only call this method if you want the permission resolver to be passed to all realms that implement the 162 * <code>RolePermissionResolver</code> interface. If you do not want this to occur, the realms must 163 * configure themselves individually (or be configured individually). 164 * 165 * @param rolePermissionResolver the rolePermissionResolver to set on all of the wrapped realms that implement the 166 * {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} interface. 167 */ 168 public void setRolePermissionResolver(RolePermissionResolver rolePermissionResolver) { 169 this.rolePermissionResolver = rolePermissionResolver; 170 applyRolePermissionResolverToRealms(); 171 } 172 173 174 /** 175 * Sets the internal {@link #getRolePermissionResolver} on any internal configured 176 * {@link #getRealms Realms} that implement the {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} interface. 177 * <p/> 178 * This method is called after setting a rolePermissionResolver on this ModularRealmAuthorizer via the 179 * {@link #setRolePermissionResolver(org.apache.shiro.authz.permission.RolePermissionResolver) setRolePermissionResolver} method. 180 * <p/> 181 * It is also called after setting one or more realms via the {@link #setRealms setRealms} method to allow these 182 * newly available realms to be given the <code>RolePermissionResolver</code> already in use. 183 * 184 * @since 1.0 185 */ 186 protected void applyRolePermissionResolverToRealms() { 187 RolePermissionResolver resolver = getRolePermissionResolver(); 188 Collection<Realm> realms = getRealms(); 189 if (resolver != null && realms != null && !realms.isEmpty()) { 190 for (Realm realm : realms) { 191 if (realm instanceof RolePermissionResolverAware) { 192 ((RolePermissionResolverAware) realm).setRolePermissionResolver(resolver); 193 } 194 } 195 } 196 } 197 198 199 /** 200 * Used by the {@link Authorizer Authorizer} implementation methods to ensure that the {@link #setRealms realms} 201 * has been set. The default implementation ensures the property is not null and not empty. 202 * 203 * @throws IllegalStateException if the <tt>realms</tt> property is configured incorrectly. 204 */ 205 protected void assertRealmsConfigured() throws IllegalStateException { 206 Collection<Realm> realms = getRealms(); 207 if (realms == null || realms.isEmpty()) { 208 String msg = "Configuration error: No realms have been configured! One or more realms must be " + 209 "present to execute an authorization operation."; 210 throw new IllegalStateException(msg); 211 } 212 } 213 214 /** 215 * Returns <code>true</code> if any of the configured realms' 216 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, String)} returns <code>true</code>, 217 * <code>false</code> otherwise. 218 */ 219 public boolean isPermitted(PrincipalCollection principals, String permission) { 220 assertRealmsConfigured(); 221 for (Realm realm : getRealms()) { 222 if (!(realm instanceof Authorizer)) continue; 223 if (((Authorizer) realm).isPermitted(principals, permission)) { 224 return true; 225 } 226 } 227 return false; 228 } 229 230 /** 231 * Returns <code>true</code> if any of the configured realms' 232 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, Permission)} call returns <code>true</code>, 233 * <code>false</code> otherwise. 234 */ 235 public boolean isPermitted(PrincipalCollection principals, Permission permission) { 236 assertRealmsConfigured(); 237 for (Realm realm : getRealms()) { 238 if (!(realm instanceof Authorizer)) continue; 239 if (((Authorizer) realm).isPermitted(principals, permission)) { 240 return true; 241 } 242 } 243 return false; 244 } 245 246 /** 247 * Returns <code>true</code> if any of the configured realms' 248 * {@link #isPermittedAll(org.apache.shiro.subject.PrincipalCollection, String...)} call returns 249 * <code>true</code>, <code>false</code> otherwise. 250 */ 251 public boolean[] isPermitted(PrincipalCollection principals, String... permissions) { 252 assertRealmsConfigured(); 253 if (permissions != null && permissions.length > 0) { 254 boolean[] isPermitted = new boolean[permissions.length]; 255 for (int i = 0; i < permissions.length; i++) { 256 isPermitted[i] = isPermitted(principals, permissions[i]); 257 } 258 return isPermitted; 259 } 260 return new boolean[0]; 261 } 262 263 /** 264 * Returns <code>true</code> if any of the configured realms' 265 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, List)} call returns <code>true</code>, 266 * <code>false</code> otherwise. 267 */ 268 public boolean[] isPermitted(PrincipalCollection principals, List<Permission> permissions) { 269 assertRealmsConfigured(); 270 if (permissions != null && !permissions.isEmpty()) { 271 boolean[] isPermitted = new boolean[permissions.size()]; 272 int i = 0; 273 for (Permission p : permissions) { 274 isPermitted[i++] = isPermitted(principals, p); 275 } 276 return isPermitted; 277 } 278 279 return new boolean[0]; 280 } 281 282 /** 283 * Returns <code>true</code> if any of the configured realms' 284 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, String)} call returns <code>true</code> 285 * for <em>all</em> of the specified string permissions, <code>false</code> otherwise. 286 */ 287 public boolean isPermittedAll(PrincipalCollection principals, String... permissions) { 288 assertRealmsConfigured(); 289 if (permissions != null && permissions.length > 0) { 290 for (String perm : permissions) { 291 if (!isPermitted(principals, perm)) { 292 return false; 293 } 294 } 295 } 296 return true; 297 } 298 299 /** 300 * Returns <code>true</code> if any of the configured realms' 301 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, Permission)} call returns <code>true</code> 302 * for <em>all</em> of the specified Permissions, <code>false</code> otherwise. 303 */ 304 public boolean isPermittedAll(PrincipalCollection principals, Collection<Permission> permissions) { 305 assertRealmsConfigured(); 306 if (permissions != null && !permissions.isEmpty()) { 307 for (Permission permission : permissions) { 308 if (!isPermitted(principals, permission)) { 309 return false; 310 } 311 } 312 } 313 return true; 314 } 315 316 /** 317 * If !{@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, String) isPermitted(permission)}, throws 318 * an <code>UnauthorizedException</code> otherwise returns quietly. 319 */ 320 public void checkPermission(PrincipalCollection principals, String permission) throws AuthorizationException { 321 assertRealmsConfigured(); 322 if (!isPermitted(principals, permission)) { 323 throw new UnauthorizedException("Subject does not have permission [" + permission + "]"); 324 } 325 } 326 327 /** 328 * If !{@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, Permission) isPermitted(permission)}, throws 329 * an <code>UnauthorizedException</code> otherwise returns quietly. 330 */ 331 public void checkPermission(PrincipalCollection principals, Permission permission) throws AuthorizationException { 332 assertRealmsConfigured(); 333 if (!isPermitted(principals, permission)) { 334 throw new UnauthorizedException("Subject does not have permission [" + permission + "]"); 335 } 336 } 337 338 /** 339 * If !{@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, String...) isPermitted(permission)}, 340 * throws an <code>UnauthorizedException</code> otherwise returns quietly. 341 */ 342 public void checkPermissions(PrincipalCollection principals, String... permissions) throws AuthorizationException { 343 assertRealmsConfigured(); 344 if (permissions != null && permissions.length > 0) { 345 for (String perm : permissions) { 346 checkPermission(principals, perm); 347 } 348 } 349 } 350 351 /** 352 * If !{@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, Permission) isPermitted(permission)} for 353 * <em>all</em> the given Permissions, throws 354 * an <code>UnauthorizedException</code> otherwise returns quietly. 355 */ 356 public void checkPermissions(PrincipalCollection principals, Collection<Permission> permissions) throws AuthorizationException { 357 assertRealmsConfigured(); 358 if (permissions != null) { 359 for (Permission permission : permissions) { 360 checkPermission(principals, permission); 361 } 362 } 363 } 364 365 /** 366 * Returns <code>true</code> if any of the configured realms' 367 * {@link #hasRole(org.apache.shiro.subject.PrincipalCollection, String)} call returns <code>true</code>, 368 * <code>false</code> otherwise. 369 */ 370 public boolean hasRole(PrincipalCollection principals, String roleIdentifier) { 371 assertRealmsConfigured(); 372 for (Realm realm : getRealms()) { 373 if (!(realm instanceof Authorizer)) continue; 374 if (((Authorizer) realm).hasRole(principals, roleIdentifier)) { 375 return true; 376 } 377 } 378 return false; 379 } 380 381 /** 382 * Calls {@link #hasRole(org.apache.shiro.subject.PrincipalCollection, String)} for each role name in the specified 383 * collection and places the return value from each call at the respective location in the returned array. 384 */ 385 public boolean[] hasRoles(PrincipalCollection principals, List<String> roleIdentifiers) { 386 assertRealmsConfigured(); 387 if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) { 388 boolean[] hasRoles = new boolean[roleIdentifiers.size()]; 389 int i = 0; 390 for (String roleId : roleIdentifiers) { 391 hasRoles[i++] = hasRole(principals, roleId); 392 } 393 return hasRoles; 394 } 395 396 return new boolean[0]; 397 } 398 399 /** 400 * Returns <code>true</code> iff any of the configured realms' 401 * {@link #hasRole(org.apache.shiro.subject.PrincipalCollection, String)} call returns <code>true</code> for 402 * <em>all</em> roles specified, <code>false</code> otherwise. 403 */ 404 public boolean hasAllRoles(PrincipalCollection principals, Collection<String> roleIdentifiers) { 405 assertRealmsConfigured(); 406 for (String roleIdentifier : roleIdentifiers) { 407 if (!hasRole(principals, roleIdentifier)) { 408 return false; 409 } 410 } 411 return true; 412 } 413 414 /** 415 * If !{@link #hasRole(org.apache.shiro.subject.PrincipalCollection, String) hasRole(role)}, throws 416 * an <code>UnauthorizedException</code> otherwise returns quietly. 417 */ 418 public void checkRole(PrincipalCollection principals, String role) throws AuthorizationException { 419 assertRealmsConfigured(); 420 if (!hasRole(principals, role)) { 421 throw new UnauthorizedException("Subject does not have role [" + role + "]"); 422 } 423 } 424 425 /** 426 * Calls {@link #checkRoles(PrincipalCollection principals, String... roles) checkRoles(PrincipalCollection principals, String... roles) }. 427 */ 428 public void checkRoles(PrincipalCollection principals, Collection<String> roles) throws AuthorizationException { 429 //SHIRO-234 - roles.toArray() -> roles.toArray(new String[roles.size()]) 430 if (roles != null && !roles.isEmpty()) checkRoles(principals, roles.toArray(new String[roles.size()])); 431 } 432 433 /** 434 * Calls {@link #checkRole(org.apache.shiro.subject.PrincipalCollection, String) checkRole} for each role specified. 435 */ 436 public void checkRoles(PrincipalCollection principals, String... roles) throws AuthorizationException { 437 assertRealmsConfigured(); 438 if (roles != null) { 439 for (String role : roles) { 440 checkRole(principals, role); 441 } 442 } 443 } 444 }