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.aop;
20  
21  import org.apache.shiro.authz.AuthorizationException;
22  import org.apache.shiro.authz.annotation.Logical;
23  import org.apache.shiro.authz.annotation.RequiresPermissions;
24  import org.apache.shiro.authz.annotation.RequiresRoles;
25  import org.apache.shiro.subject.Subject;
26  
27  import java.lang.annotation.Annotation;
28  
29  /**
30   * Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotation is
31   * declared, and if so, performs a permission check to see if the calling <code>Subject</code> is allowed continued
32   * access.
33   *
34   * @since 0.9.0
35   */
36  public class PermissionAnnotationHandler extends AuthorizingAnnotationHandler {
37  
38      /**
39       * Default no-argument constructor that ensures this handler looks for
40       * {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotations.
41       */
42      public PermissionAnnotationHandler() {
43          super(RequiresPermissions.class);
44      }
45  
46      /**
47       * Returns the annotation {@link RequiresPermissions#value value}, from which the Permission will be constructed.
48       *
49       * @param a the RequiresPermissions annotation being inspected.
50       * @return the annotation's <code>value</code>, from which the Permission will be constructed.
51       */
52      protected String[] getAnnotationValue(Annotation a) {
53          RequiresPermissions rpAnnotation = (RequiresPermissions) a;
54          return rpAnnotation.value();
55      }
56  
57      /**
58       * Ensures that the calling <code>Subject</code> has the Annotation's specified permissions, and if not, throws an
59       * <code>AuthorizingException</code> indicating access is denied.
60       *
61       * @param a the RequiresPermission annotation being inspected to check for one or more permissions
62       * @throws org.apache.shiro.authz.AuthorizationException
63       *          if the calling <code>Subject</code> does not have the permission(s) necessary to
64       *          continue access or execution.
65       */
66      public void assertAuthorized(Annotation a) throws AuthorizationException {
67          if (!(a instanceof RequiresPermissions)) return;
68  
69          RequiresPermissions rpAnnotation = (RequiresPermissions) a;
70          String[] perms = getAnnotationValue(a);
71          Subject subject = getSubject();
72  
73          if (perms.length == 1) {
74              subject.checkPermission(perms[0]);
75              return;
76          }
77          if (Logical.AND.equals(rpAnnotation.logical())) {
78              getSubject().checkPermissions(perms);
79              return;
80          }
81          if (Logical.OR.equals(rpAnnotation.logical())) {
82              // Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first
83              boolean hasAtLeastOnePermission = false;
84              for (String permission : perms) if (getSubject().isPermitted(permission)) hasAtLeastOnePermission = true;
85              // Cause the exception if none of the role match, note that the exception message will be a bit misleading
86              if (!hasAtLeastOnePermission) getSubject().checkPermission(perms[0]);
87              
88          }
89      }
90  }