View Javadoc

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 }