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.authz; 020 021import org.apache.shiro.authz.permission.PermissionResolver; 022import org.apache.shiro.authz.permission.PermissionResolverAware; 023import org.apache.shiro.authz.permission.RolePermissionResolver; 024import org.apache.shiro.authz.permission.RolePermissionResolverAware; 025import org.apache.shiro.realm.Realm; 026import org.apache.shiro.subject.PrincipalCollection; 027 028import java.util.Collection; 029import java.util.List; 030 031 032/** 033 * A <tt>ModularRealmAuthorizer</tt> is an <tt>Authorizer</tt> implementation that consults one or more configured 034 * {@link Realm Realm}s during an authorization operation. 035 * 036 * @since 0.2 037 */ 038public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware { 039 040 /** 041 * The realms to consult during any authorization check. 042 */ 043 protected Collection<Realm> realms; 044 045 /** 046 * A PermissionResolver to be used by <em>all</em> configured realms. Leave <code>null</code> if you wish 047 * to configure different resolvers for different realms. 048 */ 049 protected PermissionResolver permissionResolver; 050 051 /** 052 * A RolePermissionResolver to be used by <em>all</em> configured realms. Leave <code>null</code> if you wish 053 * to configure different resolvers for different realms. 054 */ 055 protected RolePermissionResolver rolePermissionResolver; 056 057 /** 058 * Default no-argument constructor, does nothing. 059 */ 060 public ModularRealmAuthorizer() { 061 } 062 063 /** 064 * Constructor that accepts the <code>Realm</code>s to consult during an authorization check. Immediately calls 065 * {@link #setRealms setRealms(realms)}. 066 * 067 * @param realms the realms to consult during an authorization check. 068 */ 069 public ModularRealmAuthorizer(Collection<Realm> realms) { 070 setRealms(realms); 071 } 072 073 /** 074 * Returns the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check. 075 * 076 * @return the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check. 077 */ 078 public Collection<Realm> getRealms() { 079 return this.realms; 080 } 081 082 /** 083 * Sets the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check. 084 * 085 * @param realms the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check. 086 */ 087 public void setRealms(Collection<Realm> realms) { 088 this.realms = realms; 089 applyPermissionResolverToRealms(); 090 applyRolePermissionResolverToRealms(); 091 } 092 093 /** 094 * Returns the PermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default) 095 * if all realm instances will each configure their own permission resolver. 096 * 097 * @return the PermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default) 098 * if realm instances will each configure their own permission resolver. 099 * @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 the wrapped realms that implement the 114 * {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} 115 * interface. 116 */ 117 public void setPermissionResolver(PermissionResolver permissionResolver) { 118 this.permissionResolver = permissionResolver; 119 applyPermissionResolverToRealms(); 120 } 121 122 /** 123 * Sets the internal {@link #getPermissionResolver} on any internal configured 124 * {@link #getRealms Realms} that implement 125 * the {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware}interface. 126 * <p/> 127 * This method is called after setting a permissionResolver on this ModularRealmAuthorizer via the 128 * {@link #setPermissionResolver(org.apache.shiro.authz.permission.PermissionResolver) setPermissionResolver} method. 129 * <p/> 130 * It is also called after setting one or more realms via the {@link #setRealms setRealms} method to allow these 131 * newly available realms to be given the <code>PermissionResolver</code> already in use. 132 * 133 * @since 1.0 134 */ 135 protected void applyPermissionResolverToRealms() { 136 PermissionResolver resolver = getPermissionResolver(); 137 Collection<Realm> realms = getRealms(); 138 if (resolver != null && realms != null && !realms.isEmpty()) { 139 for (Realm realm : realms) { 140 if (realm instanceof PermissionResolverAware) { 141 ((PermissionResolverAware) realm).setPermissionResolver(resolver); 142 } 143 } 144 } 145 } 146 147 /** 148 * Returns the RolePermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default) 149 * if all realm instances will each configure their own permission resolver. 150 * 151 * @return the RolePermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default) 152 * if realm instances will each configure their own role permission resolver. 153 * @since 1.0 154 */ 155 public RolePermissionResolver getRolePermissionResolver() { 156 return this.rolePermissionResolver; 157 } 158 159 /** 160 * Sets the specified {@link RolePermissionResolver RolePermissionResolver} on <em>all</em> of the wrapped realms that 161 * implement the {@link org.apache.shiro.authz.permission.RolePermissionResolverAware PermissionResolverAware} interface. 162 * <p/> 163 * Only call this method if you want the permission resolver to be passed to all realms that implement the 164 * <code>RolePermissionResolver</code> interface. If you do not want this to occur, the realms must 165 * configure themselves individually (or be configured individually). 166 * 167 * @param rolePermissionResolver the rolePermissionResolver to set on all the wrapped realms that implement the 168 * {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} 169 * interface. 170 */ 171 public void setRolePermissionResolver(RolePermissionResolver rolePermissionResolver) { 172 this.rolePermissionResolver = rolePermissionResolver; 173 applyRolePermissionResolverToRealms(); 174 } 175 176 177 /** 178 * Sets the internal {@link #getRolePermissionResolver} on any internal configured 179 * {@link #getRealms Realms} that implement the 180 * {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} interface. 181 * <p/> 182 * This method is called after setting a rolePermissionResolver on this ModularRealmAuthorizer via the 183 * {@link #setRolePermissionResolver(org.apache.shiro.authz.permission.RolePermissionResolver) setRolePermissionResolver} 184 * method. 185 * <p/> 186 * It is also called after setting one or more realms via the {@link #setRealms setRealms} method to allow these 187 * newly available realms to be given the <code>RolePermissionResolver</code> already in use. 188 * 189 * @since 1.0 190 */ 191 protected void applyRolePermissionResolverToRealms() { 192 RolePermissionResolver resolver = getRolePermissionResolver(); 193 Collection<Realm> realms = getRealms(); 194 if (resolver != null && realms != null && !realms.isEmpty()) { 195 for (Realm realm : realms) { 196 if (realm instanceof RolePermissionResolverAware) { 197 ((RolePermissionResolverAware) realm).setRolePermissionResolver(resolver); 198 } 199 } 200 } 201 } 202 203 204 /** 205 * Used by the {@link Authorizer Authorizer} implementation methods to ensure that the {@link #setRealms realms} 206 * has been set. The default implementation ensures the property is not null and not empty. 207 * 208 * @throws IllegalStateException if the <tt>realms</tt> property is configured incorrectly. 209 */ 210 protected void assertRealmsConfigured() throws IllegalStateException { 211 Collection<Realm> realms = getRealms(); 212 if (realms == null || realms.isEmpty()) { 213 String msg = "Configuration error: No realms have been configured! One or more realms must be " 214 + "present to execute an authorization operation."; 215 throw new IllegalStateException(msg); 216 } 217 } 218 219 /** 220 * Returns <code>true</code> if any of the configured realms' 221 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, String)} returns <code>true</code>, 222 * <code>false</code> otherwise. 223 */ 224 public boolean isPermitted(PrincipalCollection principals, String permission) { 225 assertRealmsConfigured(); 226 for (Realm realm : getRealms()) { 227 if (!(realm instanceof Authorizer)) { 228 continue; 229 } 230 if (((Authorizer) realm).isPermitted(principals, permission)) { 231 return true; 232 } 233 } 234 return false; 235 } 236 237 /** 238 * Returns <code>true</code> if any of the configured realms' 239 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, Permission)} call returns <code>true</code>, 240 * <code>false</code> otherwise. 241 */ 242 public boolean isPermitted(PrincipalCollection principals, Permission permission) { 243 assertRealmsConfigured(); 244 for (Realm realm : getRealms()) { 245 if (!(realm instanceof Authorizer)) { 246 continue; 247 } 248 if (((Authorizer) realm).isPermitted(principals, permission)) { 249 return true; 250 } 251 } 252 return false; 253 } 254 255 /** 256 * Returns <code>true</code> if any of the configured realms' 257 * {@link #isPermittedAll(org.apache.shiro.subject.PrincipalCollection, String...)} call returns 258 * <code>true</code>, <code>false</code> otherwise. 259 */ 260 public boolean[] isPermitted(PrincipalCollection principals, String... permissions) { 261 assertRealmsConfigured(); 262 if (permissions != null && permissions.length > 0) { 263 boolean[] isPermitted = new boolean[permissions.length]; 264 for (int i = 0; i < permissions.length; i++) { 265 isPermitted[i] = isPermitted(principals, permissions[i]); 266 } 267 return isPermitted; 268 } 269 return new boolean[0]; 270 } 271 272 /** 273 * Returns <code>true</code> if any of the configured realms' 274 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, List)} call returns <code>true</code>, 275 * <code>false</code> otherwise. 276 */ 277 public boolean[] isPermitted(PrincipalCollection principals, List<Permission> permissions) { 278 assertRealmsConfigured(); 279 if (permissions != null && !permissions.isEmpty()) { 280 boolean[] isPermitted = new boolean[permissions.size()]; 281 int i = 0; 282 for (Permission p : permissions) { 283 isPermitted[i++] = isPermitted(principals, p); 284 } 285 return isPermitted; 286 } 287 288 return new boolean[0]; 289 } 290 291 /** 292 * Returns <code>true</code> if any of the configured realms' 293 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, String)} call returns <code>true</code> 294 * for <em>all</em> of the specified string permissions, <code>false</code> otherwise. 295 */ 296 public boolean isPermittedAll(PrincipalCollection principals, String... permissions) { 297 assertRealmsConfigured(); 298 if (permissions != null && permissions.length > 0) { 299 for (String perm : permissions) { 300 if (!isPermitted(principals, perm)) { 301 return false; 302 } 303 } 304 } 305 return true; 306 } 307 308 /** 309 * Returns <code>true</code> if any of the configured realms' 310 * {@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, Permission)} call returns <code>true</code> 311 * for <em>all</em> of the specified Permissions, <code>false</code> otherwise. 312 */ 313 public boolean isPermittedAll(PrincipalCollection principals, Collection<Permission> permissions) { 314 assertRealmsConfigured(); 315 if (permissions != null && !permissions.isEmpty()) { 316 for (Permission permission : permissions) { 317 if (!isPermitted(principals, permission)) { 318 return false; 319 } 320 } 321 } 322 return true; 323 } 324 325 /** 326 * If !{@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, String) isPermitted(permission)}, throws 327 * an <code>UnauthorizedException</code> otherwise returns quietly. 328 */ 329 public void checkPermission(PrincipalCollection principals, String permission) throws AuthorizationException { 330 assertRealmsConfigured(); 331 if (!isPermitted(principals, permission)) { 332 throw new UnauthorizedException("Subject does not have permission [" + permission + "]"); 333 } 334 } 335 336 /** 337 * If !{@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, Permission) isPermitted(permission)}, throws 338 * an <code>UnauthorizedException</code> otherwise returns quietly. 339 */ 340 public void checkPermission(PrincipalCollection principals, Permission permission) throws AuthorizationException { 341 assertRealmsConfigured(); 342 if (!isPermitted(principals, permission)) { 343 throw new UnauthorizedException("Subject does not have permission [" + permission + "]"); 344 } 345 } 346 347 /** 348 * If !{@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, String...) isPermitted(permission)}, 349 * throws an <code>UnauthorizedException</code> otherwise returns quietly. 350 */ 351 public void checkPermissions(PrincipalCollection principals, String... permissions) throws AuthorizationException { 352 assertRealmsConfigured(); 353 if (permissions != null && permissions.length > 0) { 354 for (String perm : permissions) { 355 checkPermission(principals, perm); 356 } 357 } 358 } 359 360 /** 361 * If !{@link #isPermitted(org.apache.shiro.subject.PrincipalCollection, Permission) isPermitted(permission)} for 362 * <em>all</em> the given Permissions, throws 363 * an <code>UnauthorizedException</code> otherwise returns quietly. 364 */ 365 public void checkPermissions(PrincipalCollection principals, Collection<Permission> permissions) 366 throws AuthorizationException { 367 assertRealmsConfigured(); 368 if (permissions != null) { 369 for (Permission permission : permissions) { 370 checkPermission(principals, permission); 371 } 372 } 373 } 374 375 /** 376 * Returns <code>true</code> if any of the configured realms' 377 * {@link #hasRole(org.apache.shiro.subject.PrincipalCollection, String)} call returns <code>true</code>, 378 * <code>false</code> otherwise. 379 */ 380 public boolean hasRole(PrincipalCollection principals, String roleIdentifier) { 381 assertRealmsConfigured(); 382 for (Realm realm : getRealms()) { 383 if (!(realm instanceof Authorizer)) { 384 continue; 385 } 386 if (((Authorizer) realm).hasRole(principals, roleIdentifier)) { 387 return true; 388 } 389 } 390 return false; 391 } 392 393 /** 394 * Calls {@link #hasRole(org.apache.shiro.subject.PrincipalCollection, String)} for each role name in the specified 395 * collection and places the return value from each call at the respective location in the returned array. 396 */ 397 public boolean[] hasRoles(PrincipalCollection principals, List<String> roleIdentifiers) { 398 assertRealmsConfigured(); 399 if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) { 400 boolean[] hasRoles = new boolean[roleIdentifiers.size()]; 401 int i = 0; 402 for (String roleId : roleIdentifiers) { 403 hasRoles[i++] = hasRole(principals, roleId); 404 } 405 return hasRoles; 406 } 407 408 return new boolean[0]; 409 } 410 411 /** 412 * Returns <code>true</code> iff any of the configured realms' 413 * {@link #hasRole(org.apache.shiro.subject.PrincipalCollection, String)} call returns <code>true</code> for 414 * <em>all</em> roles specified, <code>false</code> otherwise. 415 */ 416 public boolean hasAllRoles(PrincipalCollection principals, Collection<String> roleIdentifiers) { 417 assertRealmsConfigured(); 418 for (String roleIdentifier : roleIdentifiers) { 419 if (!hasRole(principals, roleIdentifier)) { 420 return false; 421 } 422 } 423 return true; 424 } 425 426 /** 427 * If !{@link #hasRole(org.apache.shiro.subject.PrincipalCollection, String) hasRole(role)}, throws 428 * an <code>UnauthorizedException</code> otherwise returns quietly. 429 */ 430 public void checkRole(PrincipalCollection principals, String role) throws AuthorizationException { 431 assertRealmsConfigured(); 432 if (!hasRole(principals, role)) { 433 throw new UnauthorizedException("Subject does not have role [" + role + "]"); 434 } 435 } 436 437 /** 438 * Calls {@link #checkRoles(PrincipalCollection principals, String... roles) 439 * checkRoles(PrincipalCollection principals, String... roles) }. 440 */ 441 public void checkRoles(PrincipalCollection principals, Collection<String> roles) throws AuthorizationException { 442 //SHIRO-234 - roles.toArray() -> roles.toArray(new String[roles.size()]) 443 if (roles != null && !roles.isEmpty()) { 444 checkRoles(principals, roles.toArray(new String[roles.size()])); 445 } 446 } 447 448 /** 449 * Calls {@link #checkRole(org.apache.shiro.subject.PrincipalCollection, String) checkRole} for each role specified. 450 */ 451 public void checkRoles(PrincipalCollection principals, String... roles) throws AuthorizationException { 452 assertRealmsConfigured(); 453 if (roles != null) { 454 for (String role : roles) { 455 checkRole(principals, role); 456 } 457 } 458 } 459}