From e5694ac7b5e4394b920c6cab48b7bfbd871f84bd Mon Sep 17 00:00:00 2001
From: Josh Cummings <3627351+jzheaux@users.noreply.github.com>
Date: Mon, 15 Sep 2025 09:16:50 -0600
Subject: [PATCH] Fallback to Object When Determining Overridden Methods
Closes gh-17898
---
.../UniqueSecurityAnnotationScanner.java | 2 +-
.../UniqueSecurityAnnotationScannerTests.java | 32 +++++++++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java
index 3a2576b276..2ea80d31fd 100644
--- a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java
+++ b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java
@@ -252,7 +252,7 @@ final class UniqueSecurityAnnotationScanner extends Abstra
}
for (int i = 0; i < rootParameterTypes.length; i++) {
Class> resolvedParameterType = ResolvableType.forMethodParameter(candidateMethod, i, sourceDeclaringClass)
- .resolve();
+ .toClass();
if (rootParameterTypes[i] != resolvedParameterType) {
return false;
}
diff --git a/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java b/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java
index 757e35a254..88d73ef053 100644
--- a/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java
+++ b/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java
@@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.annotation.AnnotationConfigurationException;
import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -275,6 +276,14 @@ public class UniqueSecurityAnnotationScannerTests {
assertThat(pre).isNotNull();
}
+ // gh-17898
+ @Test
+ void scanWhenAnnotationOnParameterizedUndeclaredMethodAndThenLocates() throws Exception {
+ Method method = ClassUtils.getMethod(GenericInterfaceImpl.class, "processOneAndTwo", Long.class, Object.class);
+ PreAuthorize pre = this.scanner.scan(method, method.getDeclaringClass());
+ assertThat(pre).isNotNull();
+ }
+
@PreAuthorize("one")
private interface AnnotationOnInterface {
@@ -637,4 +646,27 @@ public class UniqueSecurityAnnotationScannerTests {
}
+ interface GenericInterface {
+
+ @PreAuthorize("hasAuthority('thirtythree')")
+ void processOneAndTwo(A value1, B value2);
+
+ }
+
+ abstract static class GenericAbstractSuperclass implements GenericInterface {
+
+ @Override
+ public void processOneAndTwo(Long value1, C value2) {
+ }
+
+ }
+
+ static class GenericInterfaceImpl extends GenericAbstractSuperclass {
+
+ // The compiler does not require us to declare a concrete
+ // processOneAndTwo(Long, String) method, and we intentionally
+ // do not declare one here.
+
+ }
+
}