Selaa lähdekoodia

Merge branch '6.4.x'

Josh Cummings 5 kuukautta sitten
vanhempi
commit
3468b7f85f

+ 55 - 7
core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java

@@ -20,8 +20,10 @@ import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Executable;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.Parameter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -30,6 +32,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.springframework.core.MethodClassKey;
+import org.springframework.core.ResolvableType;
 import org.springframework.core.annotation.AnnotationConfigurationException;
 import org.springframework.core.annotation.MergedAnnotation;
 import org.springframework.core.annotation.MergedAnnotations;
@@ -221,18 +224,15 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
 			return Collections.emptyList();
 		}
 		classesToSkip.add(targetClass);
-		try {
-			Method methodToUse = targetClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
+		Method methodToUse = findMethod(method, targetClass);
+		if (methodToUse != null) {
 			List<MergedAnnotation<A>> annotations = findDirectAnnotations(methodToUse);
 			if (!annotations.isEmpty()) {
 				return annotations;
 			}
 		}
-		catch (NoSuchMethodException ex) {
-			// move on
-		}
-		List<MergedAnnotation<A>> annotations = new ArrayList<>();
-		annotations.addAll(findClosestMethodAnnotations(method, targetClass.getSuperclass(), classesToSkip));
+		List<MergedAnnotation<A>> annotations = new ArrayList<>(
+				findClosestMethodAnnotations(method, targetClass.getSuperclass(), classesToSkip));
 		for (Class<?> inter : targetClass.getInterfaces()) {
 			annotations.addAll(findClosestMethodAnnotations(method, inter, classesToSkip));
 		}
@@ -264,4 +264,52 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
 			.toList();
 	}
 
+	private static Method findMethod(Method method, Class<?> targetClass) {
+		for (Method candidate : targetClass.getDeclaredMethods()) {
+			if (candidate == method) {
+				return candidate;
+			}
+			if (isOverride(method, candidate)) {
+				return candidate;
+			}
+		}
+		return null;
+	}
+
+	private static boolean isOverride(Method rootMethod, Method candidateMethod) {
+		return (!Modifier.isPrivate(candidateMethod.getModifiers())
+				&& candidateMethod.getName().equals(rootMethod.getName())
+				&& hasSameParameterTypes(rootMethod, candidateMethod));
+	}
+
+	private static boolean hasSameParameterTypes(Method rootMethod, Method candidateMethod) {
+		if (candidateMethod.getParameterCount() != rootMethod.getParameterCount()) {
+			return false;
+		}
+		Class<?>[] rootParameterTypes = rootMethod.getParameterTypes();
+		Class<?>[] candidateParameterTypes = candidateMethod.getParameterTypes();
+		if (Arrays.equals(candidateParameterTypes, rootParameterTypes)) {
+			return true;
+		}
+		return hasSameGenericTypeParameters(rootMethod, candidateMethod, rootParameterTypes);
+	}
+
+	private static boolean hasSameGenericTypeParameters(Method rootMethod, Method candidateMethod,
+			Class<?>[] rootParameterTypes) {
+
+		Class<?> sourceDeclaringClass = rootMethod.getDeclaringClass();
+		Class<?> candidateDeclaringClass = candidateMethod.getDeclaringClass();
+		if (!candidateDeclaringClass.isAssignableFrom(sourceDeclaringClass)) {
+			return false;
+		}
+		for (int i = 0; i < rootParameterTypes.length; i++) {
+			Class<?> resolvedParameterType = ResolvableType.forMethodParameter(candidateMethod, i, sourceDeclaringClass)
+				.resolve();
+			if (rootParameterTypes[i] != resolvedParameterType) {
+				return false;
+			}
+		}
+		return true;
+	}
+
 }

+ 60 - 0
core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java

@@ -295,6 +295,30 @@ public class UniqueSecurityAnnotationScannerTests {
 			.isThrownBy(() -> this.parameterScanner.scan(parameter));
 	}
 
+	// gh-16751
+	@Test
+	void scanWhenAnnotationOnParameterizedInterfaceTheLocates() throws Exception {
+		Method method = MyServiceImpl.class.getDeclaredMethod("get", String.class);
+		PreAuthorize pre = this.scanner.scan(method, method.getDeclaringClass());
+		assertThat(pre).isNotNull();
+	}
+
+	// gh-16751
+	@Test
+	void scanWhenAnnotationOnParameterizedSuperClassThenLocates() throws Exception {
+		Method method = MyServiceImpl.class.getDeclaredMethod("getExt", Long.class);
+		PreAuthorize pre = this.scanner.scan(method, method.getDeclaringClass());
+		assertThat(pre).isNotNull();
+	}
+
+	// gh-16751
+	@Test
+	void scanWhenAnnotationOnParameterizedMethodThenLocates() throws Exception {
+		Method method = MyServiceImpl.class.getDeclaredMethod("getExtByClass", Class.class, Long.class);
+		PreAuthorize pre = this.scanner.scan(method, method.getDeclaringClass());
+		assertThat(pre).isNotNull();
+	}
+
 	interface UserService {
 
 		void add(@CustomParameterAnnotation("one") String user);
@@ -681,4 +705,40 @@ public class UniqueSecurityAnnotationScannerTests {
 
 	}
 
+	interface MyService<C, U> {
+
+		@PreAuthorize("thirty")
+		C get(U u);
+
+	}
+
+	abstract static class MyServiceExt<T> implements MyService<Integer, String> {
+
+		@PreAuthorize("thirtyone")
+		abstract T getExt(T t);
+
+		@PreAuthorize("thirtytwo")
+		abstract <S extends Number> S getExtByClass(Class<S> clazz, T t);
+
+	}
+
+	static class MyServiceImpl extends MyServiceExt<Long> {
+
+		@Override
+		public Integer get(final String s) {
+			return 0;
+		}
+
+		@Override
+		Long getExt(Long o) {
+			return 0L;
+		}
+
+		@Override
+		<S extends Number> S getExtByClass(Class<S> clazz, Long l) {
+			return null;
+		}
+
+	}
+
 }