From f8272a884494f60853b81e2260e28aaac53a658c 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 9c5b8b1377..75c12eac47 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
@@ -308,7 +308,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 359fda57bc..ffb0c6f6f8 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
@@ -28,6 +28,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;
@@ -326,6 +327,14 @@ public class UniqueSecurityAnnotationScannerTests {
.isThrownBy(() -> this.parameterScanner.scan(parameter));
}
+ // 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();
+ }
+
interface UserService {
void add(@CustomParameterAnnotation("one") String user);
@@ -764,4 +773,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.
+
+ }
+
}