diff --git a/core/src/main/java/org/springframework/security/authorization/method/AbstractAuthorizationManagerRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/AbstractAuthorizationManagerRegistry.java index d40c51c1f6b..5a2b4fba7f0 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AbstractAuthorizationManagerRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AbstractAuthorizationManagerRegistry.java @@ -22,7 +22,6 @@ import org.aopalliance.intercept.MethodInvocation; -import org.springframework.aop.support.AopUtils; import org.springframework.core.MethodClassKey; import org.springframework.lang.NonNull; import org.springframework.security.authorization.AuthorizationManager; @@ -46,7 +45,7 @@ abstract class AbstractAuthorizationManagerRegistry { final AuthorizationManager getManager(MethodInvocation methodInvocation) { Method method = methodInvocation.getMethod(); Object target = methodInvocation.getThis(); - Class targetClass = (target != null) ? AopUtils.getTargetClass(target) : null; + Class targetClass = (target != null) ? target.getClass() : null; MethodClassKey cacheKey = new MethodClassKey(method, targetClass); return this.cachedManagers.computeIfAbsent(cacheKey, (k) -> resolveManager(method, targetClass)); } diff --git a/core/src/main/java/org/springframework/security/authorization/method/AbstractExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/AbstractExpressionAttributeRegistry.java index 17defe9cde8..42b7cd92c03 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AbstractExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AbstractExpressionAttributeRegistry.java @@ -22,7 +22,6 @@ import org.aopalliance.intercept.MethodInvocation; -import org.springframework.aop.support.AopUtils; import org.springframework.core.MethodClassKey; import org.springframework.lang.NonNull; @@ -43,7 +42,7 @@ abstract class AbstractExpressionAttributeRegistry targetClass = (target != null) ? AopUtils.getTargetClass(target) : null; + Class targetClass = (target != null) ? target.getClass() : null; return getAttribute(method, targetClass); } diff --git a/core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManagerTests.java b/core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManagerTests.java index d570923666d..83cbe5cdb93 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManagerTests.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; +import org.springframework.aop.TargetClassAware; import org.springframework.core.annotation.AnnotationConfigurationException; import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; @@ -133,6 +134,19 @@ public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationE .isThrownBy(() -> manager.check(authentication, methodInvocation)); } + @Test + public void checkTargetClassAwareWhenInterfaceLevelAnnotationsThenApplies() throws Exception { + MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestTargetClassAware(), + TestTargetClassAware.class, "doSomething"); + PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager(); + AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation); + assertThat(decision).isNotNull(); + assertThat(decision.isGranted()).isFalse(); + decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation); + assertThat(decision).isNotNull(); + assertThat(decision.isGranted()).isTrue(); + } + public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo { public void doSomething() { @@ -198,4 +212,33 @@ public interface InterfaceAnnotationsThree { } + @PreAuthorize("hasRole('ADMIN')") + public interface InterfaceLevelAnnotations { + + } + + public static class TestTargetClassAware extends TestClass implements TargetClassAware, InterfaceLevelAnnotations { + + @Override + public Class getTargetClass() { + return TestClass.class; + } + + @Override + public void doSomething() { + super.doSomething(); + } + + @Override + public String doSomethingString(String s) { + return super.doSomethingString(s); + } + + @Override + public void inheritedAnnotations() { + super.inheritedAnnotations(); + } + + } + } diff --git a/core/src/test/java/org/springframework/security/authorization/method/SecuredAuthorizationManagerTests.java b/core/src/test/java/org/springframework/security/authorization/method/SecuredAuthorizationManagerTests.java index db730feb361..f546d8cb033 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/SecuredAuthorizationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/SecuredAuthorizationManagerTests.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; +import org.springframework.aop.TargetClassAware; import org.springframework.core.annotation.AnnotationConfigurationException; import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.intercept.method.MockMethodInvocation; @@ -127,6 +128,19 @@ public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationE .isThrownBy(() -> manager.check(authentication, methodInvocation)); } + @Test + public void checkTargetClassAwareWhenInterfaceLevelAnnotationsThenApplies() throws Exception { + MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestTargetClassAware(), + TestTargetClassAware.class, "doSomething"); + SecuredAuthorizationManager manager = new SecuredAuthorizationManager(); + AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation); + assertThat(decision).isNotNull(); + assertThat(decision.isGranted()).isFalse(); + decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation); + assertThat(decision).isNotNull(); + assertThat(decision.isGranted()).isTrue(); + } + public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo { public void doSomething() { @@ -192,4 +206,33 @@ public interface InterfaceAnnotationsThree { } + @Secured("ROLE_ADMIN") + public interface InterfaceLevelAnnotations { + + } + + public static class TestTargetClassAware extends TestClass implements TargetClassAware, InterfaceLevelAnnotations { + + @Override + public Class getTargetClass() { + return TestClass.class; + } + + @Override + public void doSomething() { + super.doSomething(); + } + + @Override + public void securedUserOrAdmin() { + super.securedUserOrAdmin(); + } + + @Override + public void inheritedAnnotations() { + super.inheritedAnnotations(); + } + + } + }