diff --git a/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java b/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java index 3c76bacb66..c7784836ba 100644 --- a/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java +++ b/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java @@ -62,8 +62,8 @@ public Annotation getAnnotation(MethodInvocation mi, Class Annotation annotation = m.getAnnotation(clazz); if (annotation == null) { Object miThis = mi.getThis(); - //SHIRO-473 - miThis could be null for static methods, just return null - annotation = miThis != null ? getAnnotationFromClassHierarchy(miThis.getClass(), clazz) : null; + Class targetClass = miThis != null ? miThis.getClass() : m.getDeclaringClass(); + annotation = getAnnotationFromClassHierarchy(targetClass, clazz); } return annotation; } diff --git a/support/aspectj/src/test/java/org/apache/shiro/aspectj/DummyServiceTest.java b/support/aspectj/src/test/java/org/apache/shiro/aspectj/DummyServiceTest.java index 53779b8267..2a243f5b27 100644 --- a/support/aspectj/src/test/java/org/apache/shiro/aspectj/DummyServiceTest.java +++ b/support/aspectj/src/test/java/org/apache/shiro/aspectj/DummyServiceTest.java @@ -203,4 +203,11 @@ void testRetrieveRestricted_asAdmin() throws Exception { restrictedService.retrieve(); } + @Test + void testStaticMethodOnClassLevelRequiresRoles_asUser() throws Exception { + assertThatExceptionOfType(UnauthorizedException.class).isThrownBy(() -> { + loginAsUser(); + StaticDummyService.staticAdminOnly(); + }); + } } diff --git a/support/aspectj/src/test/java/org/apache/shiro/aspectj/StaticDummyService.java b/support/aspectj/src/test/java/org/apache/shiro/aspectj/StaticDummyService.java new file mode 100644 index 0000000000..eb19b3c25d --- /dev/null +++ b/support/aspectj/src/test/java/org/apache/shiro/aspectj/StaticDummyService.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.shiro.aspectj; + +import org.apache.shiro.authz.annotation.RequiresRoles; + +@RequiresRoles("admin") +public class StaticDummyService { + public static void staticAdminOnly() { + // no-op + } + + public void instanceAdminOnly() { + // no-op + } +} diff --git a/support/cdi/src/main/java/org/apache/shiro/cdi/AopHelper.java b/support/cdi/src/main/java/org/apache/shiro/cdi/AopHelper.java index fc6ea6a909..7f211f1976 100644 --- a/support/cdi/src/main/java/org/apache/shiro/cdi/AopHelper.java +++ b/support/cdi/src/main/java/org/apache/shiro/cdi/AopHelper.java @@ -83,25 +83,20 @@ class AopHelper { */ static List createSecurityInterceptors(Method method, Class clazz) { List result = new ArrayList<>(); + boolean checkClassAnnotations = isInterceptOnClassAnnotation(method.getModifiers()); - if (isInterceptOnClassAnnotation(method.getModifiers())) { - for (Class ac - : getAuthorizationAnnotationClasses()) { - Annotation annotationOnClass = clazz.getAnnotation(ac); - if (annotationOnClass != null) { - result.add(new SecurityInterceptor(annotationOnClass)); + for (Class ac : getAuthorizationAnnotationClasses()) { + Annotation methodAnnotation = method.getAnnotation(ac); + if (methodAnnotation != null) { + result.add(new SecurityInterceptor(methodAnnotation)); + } else if (checkClassAnnotations) { + Annotation classAnnotation = clazz.getAnnotation(ac); + if (classAnnotation != null) { + result.add(new SecurityInterceptor(classAnnotation)); } } } - for (Class ac - : getAuthorizationAnnotationClasses()) { - Annotation annotation = method.getAnnotation(ac); - if (annotation != null) { - result.add(new SecurityInterceptor(annotation)); - } - } - return result; } diff --git a/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ShiroAnnotationFilterFeature.java b/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ShiroAnnotationFilterFeature.java index 536545629c..4e24ba0b1c 100644 --- a/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ShiroAnnotationFilterFeature.java +++ b/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ShiroAnnotationFilterFeature.java @@ -69,14 +69,13 @@ public void configure(ResourceInfo resourceInfo, FeatureContext context) { for (Class annotationClass : annotations) { // XXX What is the performance of getAnnotation vs getAnnotations? - Annotation classAuthzSpec = resourceInfo.getResourceClass().getAnnotation(annotationClass); Annotation methodAuthzSpec = resourceInfo.getResourceMethod().getAnnotation(annotationClass); + Annotation classAuthzSpec = resourceInfo.getResourceClass().getAnnotation(annotationClass); - if (classAuthzSpec != null) { - authzSpecs.add(classAuthzSpec); - } if (methodAuthzSpec != null) { authzSpecs.add(methodAuthzSpec); + } else if (classAuthzSpec != null) { + authzSpecs.add(classAuthzSpec); } }