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 */
019 package org.apache.shiro.authz;
020
021 import org.apache.shiro.authz.permission.PermissionResolver;
022 import org.apache.shiro.authz.permission.PermissionResolverAware;
023 import org.apache.shiro.authz.permission.RolePermissionResolver;
024 import org.apache.shiro.authz.permission.RolePermissionResolverAware;
025 import org.apache.shiro.realm.Realm;
026 import org.apache.shiro.subject.PrincipalCollection;
027
028 import java.util.Collection;
029 import 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 * @author Les Hazlewood
037 * @since 0.2
038 */
039 public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware {
040
041 /**
042 * The realms to consult during any authorization check.
043 */
044 protected Collection<Realm> realms;
045
046 /**
047 * A PermissionResolver to be used by <em>all</em> configured realms. Leave <code>null</code> if you wish
048 * to configure different resolvers for different realms.
049 */
050 protected PermissionResolver permissionResolver;
051
052 /**
053 * A RolePermissionResolver to be used by <em>all</em> configured realms. Leave <code>null</code> if you wish
054 * to configure different resolvers for different realms.
055 */
056 protected RolePermissionResolver rolePermissionResolver;
057
058 /**
059 * Default no-argument constructor, does nothing.
060 */
061 public ModularRealmAuthorizer() {
062 }
063
064 /**
065 * Constructor that accepts the <code>Realm</code>s to consult during an authorization check. Immediately calls
066 * {@link #setRealms setRealms(realms)}.
067 *
068 * @param realms the realms to consult during an authorization check.
069 */
070 @SuppressWarnings({"UnusedDeclaration"})
071 public ModularRealmAuthorizer(Collection<Realm> realms) {
072 setRealms(realms);
073 }
074
075 /**
076 * Returns the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check.
077 *
078 * @return the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check.
079 */
080 public Collection<Realm> getRealms() {
081 return this.realms;
082 }
083
084 /**
085 * Sets the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check.
086 *
087 * @param realms the realms wrapped by this <code>Authorizer</code> which are consulted during an authorization check.
088 */
089 public void setRealms(Collection<Realm> realms) {
090 this.realms = realms;
091 applyPermissionResolverToRealms();
092 applyRolePermissionResolverToRealms();
093 }
094
095 /**
096 * Returns the PermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default)
097 * if all realm instances will each configure their own permission resolver.
098 *
099 * @return the PermissionResolver to be used on <em>all</em> configured realms, or <code>null</code (the default)
100 * if realm instances will each configure their own permission resolver.
101 * @since 1.0
102 */
103 public PermissionResolver getPermissionResolver() {
104 return this.permissionResolver;
105 }
106
107 /**
108 * Sets the specified {@link PermissionResolver PermissionResolver} on <em>all</em> of the wrapped realms that
109 * implement the {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} interface.
110 * <p/>
111 * Only call this method if you want the permission resolver to be passed to all realms that implement the
112 * <code>PermissionResolver</code> interface. If you do not want this to occur, the realms must
113 * configure themselves individually (or be configured individually).
114 *
115 * @param permissionResolver the permissionResolver to set on all of the wrapped realms that implement the
116 * {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} interface.
117 */
118 public void setPermissionResolver(PermissionResolver permissionResolver) {
119 this.permissionResolver = permissionResolver;
120 applyPermissionResolverToRealms();
121 }
122
123 /**
124 * Sets the internal {@link #getPermissionResolver} on any internal configured
125 * {@link #getRealms Realms} that implement 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 of the wrapped realms that implement the
168 * {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} interface.
169 */
170 public void setRolePermissionResolver(RolePermissionResolver rolePermissionResolver) {
171 this.rolePermissionResolver = rolePermissionResolver;
172 applyRolePermissionResolverToRealms();
173 }
174
175
176 /**
177 * Sets the internal {@link #getRolePermissionResolver} on any internal configured
178 * {@link #getRealms Realms} that implement the {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} interface.
179 * <p/>
180 * This method is called after setting a rolePermissionResolver on this ModularRealmAuthorizer via the
181 * {@link #setRolePermissionResolver(org.apache.shiro.authz.permission.RolePermissionResolver) setRolePermissionResolver} method.
182 * <p/>
183 * It is also called after setting one or more realms via the {@link #setRealms setRealms} method to allow these
184 * newly available realms to be given the <code>RolePermissionResolver</code> already in use.
185 *
186 * @since 1.0
187 */
188 protected void applyRolePermissionResolverToRealms() {
189 RolePermissionResolver resolver = getRolePermissionResolver();
190 Collection<Realm> realms = getRealms();
191 if (resolver != null && realms != null && !realms.isEmpty()) {
192 for (Realm realm : realms) {
193 if (realm instanceof RolePermissionResolverAware) {
194 ((RolePermissionResolverAware) realm).setRolePermissionResolver(resolver);
195 }
196 }
197 }
198 }
199
200
201 /**
202 * Used by the {@link Authorizer Authorizer} implementation methods to ensure that the {@link #setRealms realms}
203 * has been set. The default implementation ensures the property is not null and not empty.
204 *
205 * @throws IllegalStateException if the <tt>realms</tt> property is configured incorrectly.
206 */
207 protected void assertRealmsConfigured() throws IllegalStateException {
208 Collection<Realm> realms = getRealms();
209 if (realms == null || realms.isEmpty()) {
210 String msg = "Configuration error: No realms have been configured! One or more realms must be " +
211 "present to execute an authorization operation.";
212 throw new IllegalStateException(msg);
213 }
214 }
215
216 /**
217 * Returns <code>true</code> if any of the configured realms'
218 * {@link Realm#isPermitted(org.apache.shiro.subject.PrincipalCollection , String)} returns <code>true</code>,
219 * <code>false</code> otherwise.
220 */
221 public boolean isPermitted(PrincipalCollection principals, String permission) {
222 assertRealmsConfigured();
223 for (Realm realm : getRealms()) {
224 if (realm.isPermitted(principals, permission)) {
225 return true;
226 }
227 }
228 return false;
229 }
230
231 /**
232 * Returns <code>true</code> if any of the configured realms'
233 * {@link Realm#isPermitted(org.apache.shiro.subject.PrincipalCollection , Permission)} call returns <code>true</code>,
234 * <code>false</code> otherwise.
235 */
236 public boolean isPermitted(PrincipalCollection principals, Permission permission) {
237 assertRealmsConfigured();
238 for (Realm realm : getRealms()) {
239 if (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 Realm#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 org.apache.shiro.realm.Realm#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 Realm#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 Realm#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 Realm#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.hasRole(principals, roleIdentifier)) {
374 return true;
375 }
376 }
377 return false;
378 }
379
380 /**
381 * Calls {@link #hasRole(org.apache.shiro.subject.PrincipalCollection , String)} for each role name in the specified
382 * collection and places the return value from each call at the respective location in the returned array.
383 */
384 public boolean[] hasRoles(PrincipalCollection principals, List<String> roleIdentifiers) {
385 assertRealmsConfigured();
386 if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) {
387 boolean[] hasRoles = new boolean[roleIdentifiers.size()];
388 int i = 0;
389 for (String roleId : roleIdentifiers) {
390 hasRoles[i++] = hasRole(principals, roleId);
391 }
392 return hasRoles;
393 }
394
395 return new boolean[0];
396 }
397
398 /**
399 * Returns <code>true</code> iff any of the configured realms'
400 * {@link Realm#hasRole(org.apache.shiro.subject.PrincipalCollection , String)} call returns <code>true</code> for
401 * <em>all</em> roles specified, <code>false</code> otherwise.
402 */
403 public boolean hasAllRoles(PrincipalCollection principals, Collection<String> roleIdentifiers) {
404 assertRealmsConfigured();
405 for (String roleIdentifier : roleIdentifiers) {
406 if (!hasRole(principals, roleIdentifier)) {
407 return false;
408 }
409 }
410 return true;
411 }
412
413 /**
414 * If !{@link #hasRole(org.apache.shiro.subject.PrincipalCollection , String) hasRole(role)}, throws
415 * an <code>UnauthorizedException</code> otherwise returns quietly.
416 */
417 public void checkRole(PrincipalCollection principals, String role) throws AuthorizationException {
418 assertRealmsConfigured();
419 if (!hasRole(principals, role)) {
420 throw new UnauthorizedException("Subject does not have role [" + role + "]");
421 }
422 }
423
424 /**
425 * Calls {@link #checkRole(org.apache.shiro.subject.PrincipalCollection , String) checkRole} for each role specified.
426 */
427 public void checkRoles(PrincipalCollection principals, Collection<String> roles) throws AuthorizationException {
428 assertRealmsConfigured();
429 if (roles != null) {
430 for (String role : roles) {
431 checkRole(principals, role);
432 }
433 }
434 }
435 }