This is an automated email from the ASF dual-hosted git repository.
lprimak pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/shiro.git
The following commit(s) were added to refs/heads/main by this push:
new 34baf83d4 bugfix(aop/guice): add support for retrieving annotations
from superc… (#2860)
34baf83d4 is described below
commit 34baf83d4bece6d3607ca34109240276e923be70
Author: Lenny Primak <[email protected]>
AuthorDate: Sun Aug 16 12:44:24 2026 -0500
bugfix(aop/guice): add support for retrieving annotations from superc…
(#2860)
---
.../apache/shiro/aop/DefaultAnnotationResolver.java | 14 +++++++++++++-
.../apache/shiro/aop/AnnotationResolverTest.java | 21 +++++++++++++++++++++
.../aspectj/ShiroAnnotationAuthorizingAspect.java | 17 +++++++++++------
.../shiro/aspectj/RestrictedDummyService.java | 4 ++--
4 files changed, 47 insertions(+), 9 deletions(-)
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 c020588ce..3c76bacb6 100644
--- a/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java
+++ b/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java
@@ -63,8 +63,20 @@ public class DefaultAnnotationResolver implements
AnnotationResolver {
if (annotation == null) {
Object miThis = mi.getThis();
//SHIRO-473 - miThis could be null for static methods, just return
null
- annotation = miThis != null ?
miThis.getClass().getAnnotation(clazz) : null;
+ annotation = miThis != null ?
getAnnotationFromClassHierarchy(miThis.getClass(), clazz) : null;
}
return annotation;
}
+
+ private Annotation getAnnotationFromClassHierarchy(Class<?> targetClass,
Class<? extends Annotation> clazz) {
+ Class<?> current = targetClass;
+ while (current != null) {
+ Annotation annotation = current.getDeclaredAnnotation(clazz);
+ if (annotation != null) {
+ return annotation;
+ }
+ current = current.getSuperclass();
+ }
+ return null;
+ }
}
diff --git
a/core/src/test/java/org/apache/shiro/aop/AnnotationResolverTest.java
b/core/src/test/java/org/apache/shiro/aop/AnnotationResolverTest.java
index c46b15f07..af4f09e24 100644
--- a/core/src/test/java/org/apache/shiro/aop/AnnotationResolverTest.java
+++ b/core/src/test/java/org/apache/shiro/aop/AnnotationResolverTest.java
@@ -42,6 +42,16 @@ public class AnnotationResolverTest {
}
}
+ @SuppressWarnings("unused")
+ @RequiresRoles("admin")
+ private static class ParentFixture {
+ public void operateParent() {
+ }
+ }
+
+ private static final class ChildFixture extends ParentFixture {
+ }
+
DefaultAnnotationResolver annotationResolver = new
DefaultAnnotationResolver();
@Test
@@ -64,6 +74,17 @@ public class AnnotationResolverTest {
assertThat(annotationResolver.getAnnotation(methodInvocation,
RequiresUser.class)).isNotNull();
}
+ @Test
+ void testAnnotationFoundFromSuperclass() throws SecurityException,
NoSuchMethodException {
+ ChildFixture childFixture = new ChildFixture();
+ MethodInvocation methodInvocation = createMock(MethodInvocation.class);
+ Method method = ParentFixture.class.getDeclaredMethod("operateParent");
+ expect(methodInvocation.getMethod()).andReturn(method);
+ expect(methodInvocation.getThis()).andReturn(childFixture);
+ replay(methodInvocation);
+ assertThat(annotationResolver.getAnnotation(methodInvocation,
RequiresRoles.class)).isNotNull();
+ }
+
@Test
void testNullMethodInvocation() throws SecurityException,
NoSuchMethodException {
MethodInvocation methodInvocation = createMock(MethodInvocation.class);
diff --git
a/support/aspectj/src/main/aspect/org/apache/shiro/aspectj/ShiroAnnotationAuthorizingAspect.java
b/support/aspectj/src/main/aspect/org/apache/shiro/aspectj/ShiroAnnotationAuthorizingAspect.java
index 913cfae0a..b02488ce5 100644
---
a/support/aspectj/src/main/aspect/org/apache/shiro/aspectj/ShiroAnnotationAuthorizingAspect.java
+++
b/support/aspectj/src/main/aspect/org/apache/shiro/aspectj/ShiroAnnotationAuthorizingAspect.java
@@ -24,23 +24,28 @@ import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
- * Aspect that adds a before advice for each invocation of an annotated method.
+ * Aspect that adds a before advice for each invocation of an annotated method
or class.
*/
-@Aspect()
+@Aspect
public class ShiroAnnotationAuthorizingAspect {
- private static final String pointCupExpression =
+ private static final String pointCutExpression =
"execution(@org.apache.shiro.authz.annotation.RequiresAuthentication * *(..))
|| " +
+ "execution(*
(@org.apache.shiro.authz.annotation.RequiresAuthentication *).*(..)) || " +
"execution(@org.apache.shiro.authz.annotation.RequiresGuest * *(..)) || " +
+ "execution(*
(@org.apache.shiro.authz.annotation.RequiresGuest *).*(..)) || " +
"execution(@org.apache.shiro.authz.annotation.RequiresPermissions * *(..)) || "
+
+ "execution(*
(@org.apache.shiro.authz.annotation.RequiresPermissions *).*(..)) || " +
"execution(@org.apache.shiro.authz.annotation.RequiresRoles * *(..)) || " +
- "execution(@org.apache.shiro.authz.annotation.RequiresUser
* *(..))";
+ "execution(*
(@org.apache.shiro.authz.annotation.RequiresRoles *).*(..)) || " +
+ "execution(@org.apache.shiro.authz.annotation.RequiresUser
* *(..)) || " +
+ "execution(*
(@org.apache.shiro.authz.annotation.RequiresUser *).*(..))";
- @Pointcut(pointCupExpression)
+ @Pointcut(pointCutExpression)
public void anyShiroAnnotatedMethod() {
}
- @Pointcut(pointCupExpression)
+ @Pointcut(pointCutExpression)
void anyShiroAnnotatedMethodCall(JoinPoint thisJoinPoint) {
}
diff --git
a/support/aspectj/src/test/java/org/apache/shiro/aspectj/RestrictedDummyService.java
b/support/aspectj/src/test/java/org/apache/shiro/aspectj/RestrictedDummyService.java
index 6c101889c..e8314d032 100644
---
a/support/aspectj/src/test/java/org/apache/shiro/aspectj/RestrictedDummyService.java
+++
b/support/aspectj/src/test/java/org/apache/shiro/aspectj/RestrictedDummyService.java
@@ -21,11 +21,11 @@ package org.apache.shiro.aspectj;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
- * Extends the secure dummy service and makes it some access more restrictive.
+ * Extends the secure dummy service and applies an additional class-level
restriction.
*/
+@RequiresPermissions("dummy:admin")
public class RestrictedDummyService extends SecuredDummyService {
- @RequiresPermissions("dummy:admin")
public void retrieve() {
log("retrieve *RESTRICTED*");
super.retrieve();