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.guice.aop;
20  
21  import com.google.inject.Binding;
22  import com.google.inject.Key;
23  import com.google.inject.name.Named;
24  import com.google.inject.name.Names;
25  import com.google.inject.spi.Element;
26  import com.google.inject.spi.Elements;
27  import com.google.inject.spi.InterceptorBinding;
28  import org.aopalliance.intercept.MethodInterceptor;
29  import org.apache.shiro.aop.*;
30  import org.apache.shiro.authz.annotation.*;
31  import org.apache.shiro.authz.aop.*;
32  import org.junit.Before;
33  import org.junit.Test;
34  
35  import java.lang.annotation.*;
36  import java.lang.reflect.Method;
37  import java.util.HashMap;
38  import java.util.List;
39  import java.util.Map;
40  
41  import static org.junit.Assert.*;
42  
43  public class ShiroAopModuleTest {
44      @Test
45      public void testGetAnnotationResolver() {
46  
47          final AnnotationResolver annotationResolver = new DefaultAnnotationResolver();
48  
49          ShiroAopModule underTest = new ShiroAopModule() {
50  
51              @Override
52              protected AnnotationResolver createAnnotationResolver() {
53                  return annotationResolver;
54              }
55  
56              @Override
57              protected void configureDefaultInterceptors(AnnotationResolver resolver) {
58                  assertSame(annotationResolver, resolver);
59                  bind(Object.class).annotatedWith(Names.named("configureDefaultInterceptors"));
60              }
61  
62              @Override
63              protected void configureInterceptors(AnnotationResolver resolver) {
64                  assertSame(annotationResolver, resolver);
65                  bind(Object.class).annotatedWith(Names.named("configureInterceptors"));
66              }
67          };
68  
69          boolean calledDefault = false;
70          boolean calledCustom = false;
71  
72          for (Element e : Elements.getElements(underTest)) {
73              if (e instanceof Binding) {
74                  Key key = ((Binding) e).getKey();
75                  if (Named.class.isAssignableFrom(key.getAnnotation().annotationType())
76                          && "configureInterceptors".equals(((Named) key.getAnnotation()).value())
77                          && key.getTypeLiteral().getRawType().equals(Object.class)) {
78                      calledCustom = true;
79                  }
80                  if (Named.class.isAssignableFrom(key.getAnnotation().annotationType())
81                          && "configureDefaultInterceptors".equals(((Named) key.getAnnotation()).value())
82                          && key.getTypeLiteral().getRawType().equals(Object.class)) {
83                      calledDefault = true;
84                  }
85              }
86          }
87      }
88  
89      @Test
90      public void testBindShiroInterceptor() {
91  
92  
93          ShiroAopModule underTest = new ShiroAopModule() {
94              @Override
95              protected void configureInterceptors(AnnotationResolver resolver) {
96                  bindShiroInterceptor(new MyAnnotationMethodInterceptor());
97              }
98          };
99  
100         List<Element> elements = Elements.getElements(underTest);
101 
102         for (Element element : elements) {
103             if (element instanceof InterceptorBinding) {
104                 InterceptorBinding binding = (InterceptorBinding) element;
105                 assertTrue(binding.getClassMatcher().matches(getClass()));
106                 Method method = null;
107                 Class<? extends Annotation> theAnnotation = null;
108 
109                 for (Class<? extends Annotation> annotation : protectedMethods.keySet()) {
110                     if (binding.getMethodMatcher().matches(protectedMethods.get(annotation))) {
111                         method = protectedMethods.get(annotation);
112                         theAnnotation = annotation;
113                         protectedMethods.remove(annotation);
114                         break;
115                     }
116                 }
117 
118                 if (method == null) {
119                     fail("Did not expect interceptor binding " + binding.getInterceptors());
120                 }
121 
122                 List<MethodInterceptor> interceptors = binding.getInterceptors();
123                 assertEquals(1, interceptors.size());
124                 assertTrue(interceptors.get(0) instanceof AopAllianceMethodInterceptorAdapter);
125                 assertTrue(interceptorTypes.get(theAnnotation).isInstance(((AopAllianceMethodInterceptorAdapter) interceptors.get(0)).shiroInterceptor));
126 
127             }
128         }
129 
130         assertTrue("Not all interceptors were bound.", protectedMethods.isEmpty());
131     }
132 
133     @Target({ElementType.TYPE, ElementType.METHOD})
134     @Retention(RetentionPolicy.RUNTIME)
135     private static @interface MyTestAnnotation {
136     }
137 
138     private static class MyAnnotationHandler extends AnnotationHandler {
139 
140         /**
141          * Constructs an <code>AnnotationHandler</code> who processes annotations of the
142          * specified type.  Immediately calls {@link #setAnnotationClass(Class)}.
143          *
144          * @param annotationClass the type of annotation this handler will process.
145          */
146         public MyAnnotationHandler(Class<? extends Annotation> annotationClass) {
147             super(annotationClass);
148         }
149     }
150 
151     private static class MyAnnotationMethodInterceptor extends AnnotationMethodInterceptor {
152         public MyAnnotationMethodInterceptor() {
153             super(new MyAnnotationHandler(MyTestAnnotation.class));
154         }
155 
156         public Object invoke(MethodInvocation methodInvocation) throws Throwable {
157             return null;
158         }
159     }
160 
161 
162     @RequiresRoles("role")
163     public void roleProtected() {
164 
165     }
166 
167     @RequiresPermissions("permission")
168     public void permissionProtected() {
169 
170     }
171 
172     @RequiresAuthentication
173     public void authProtected() {
174 
175     }
176 
177     @RequiresUser
178     public void userProtected() {
179 
180     }
181 
182     @RequiresGuest
183     public void guestProtected() {
184 
185     }
186 
187     @ShiroAopModuleTest.MyTestAnnotation
188     public void myTestProtected() {
189 
190     }
191 
192     private Map<Class<? extends Annotation>, Method> protectedMethods;
193     private Map<Class<? extends Annotation>, Class<? extends AnnotationMethodInterceptor>> interceptorTypes;
194 
195     @Before
196     public void setup() throws NoSuchMethodException {
197         protectedMethods = new HashMap<Class<? extends Annotation>, Method>();
198         protectedMethods.put(RequiresRoles.class, getClass().getMethod("roleProtected"));
199         protectedMethods.put(RequiresPermissions.class, getClass().getMethod("permissionProtected"));
200         protectedMethods.put(RequiresAuthentication.class, getClass().getMethod("authProtected"));
201         protectedMethods.put(RequiresUser.class, getClass().getMethod("userProtected"));
202         protectedMethods.put(RequiresGuest.class, getClass().getMethod("guestProtected"));
203         protectedMethods.put(MyTestAnnotation.class, getClass().getMethod("myTestProtected"));
204 
205         interceptorTypes = new HashMap<Class<? extends Annotation>, Class<? extends AnnotationMethodInterceptor>>();
206         interceptorTypes.put(RequiresRoles.class, RoleAnnotationMethodInterceptor.class);
207         interceptorTypes.put(RequiresPermissions.class, PermissionAnnotationMethodInterceptor.class);
208         interceptorTypes.put(RequiresAuthentication.class, AuthenticatedAnnotationMethodInterceptor.class);
209         interceptorTypes.put(RequiresUser.class, UserAnnotationMethodInterceptor.class);
210         interceptorTypes.put(RequiresGuest.class, GuestAnnotationMethodInterceptor.class);
211         interceptorTypes.put(MyTestAnnotation.class, MyAnnotationMethodInterceptor.class);
212     }
213 }