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 e3f5c9297c..8602015e6b 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 @@ -146,14 +146,10 @@ private List> findParameterAnnotations(Parameter current) { } Executable executable = current.getDeclaringExecutable(); if (executable instanceof Method method) { - Class clazz = method.getDeclaringClass(); - Set> visited = new HashSet<>(); - while (clazz != null && clazz != Object.class) { - directAnnotations = findClosestParameterAnnotations(method, clazz, current, visited); - if (!directAnnotations.isEmpty()) { - return directAnnotations; - } - clazz = clazz.getSuperclass(); + directAnnotations = findClosestParameterAnnotations(method, method.getDeclaringClass(), current, + new HashSet<>()); + if (!directAnnotations.isEmpty()) { + return directAnnotations; } } return Collections.emptyList(); @@ -161,10 +157,15 @@ private List> findParameterAnnotations(Parameter current) { private List> findClosestParameterAnnotations(Method method, Class clazz, Parameter current, Set> visited) { - if (!visited.add(clazz)) { + if (clazz == null || clazz == Object.class || !visited.add(clazz)) { return Collections.emptyList(); } - List> annotations = new ArrayList<>(findDirectParameterAnnotations(method, clazz, current)); + List> directAnnotations = findDirectParameterAnnotations(method, clazz, current); + if (!directAnnotations.isEmpty()) { + return directAnnotations; + } + List> annotations = new ArrayList<>( + findClosestParameterAnnotations(method, clazz.getSuperclass(), current, visited)); for (Class ifc : clazz.getInterfaces()) { annotations.addAll(findClosestParameterAnnotations(method, ifc, current, visited)); } 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 976e0879ab..6665ae34ad 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 @@ -295,6 +295,13 @@ void scanParameterAnnotationWhenInterfaceNoAnnotationsThenException() throws Exc .isThrownBy(() -> this.parameterScanner.scan(parameter)); } + @Test + void scanParameterAnnotationWhenPresentInParentAndInterfaceThenException() throws Exception { + Parameter parameter = DefaultUserService.class.getDeclaredMethod("batch", String[].class).getParameters()[0]; + assertThatExceptionOfType(AnnotationConfigurationException.class) + .isThrownBy(() -> this.parameterScanner.scan(parameter)); + } + interface UserService { void add(@CustomParameterAnnotation("one") String user); @@ -321,6 +328,8 @@ interface ThirdPartyUserService { interface RemoteUserService extends ThirdPartyUserService { + void batch(@CustomParameterAnnotation("six") String... user); + } static class UserServiceImpl implements UserService, OtherUserService, RemoteUserService { @@ -345,6 +354,20 @@ public void delete(String user) { } + @Override + public void batch(@CustomParameterAnnotation("seven") String... user) { + + } + + } + + static class DefaultUserService extends UserServiceImpl implements RemoteUserService { + + @Override + public void batch(String... user) { + + } + } @Target({ ElementType.PARAMETER })