diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java index f1f5baf728..36ac97637b 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java @@ -19,6 +19,7 @@ package org.springframework.web.servlet.mvc.method.annotation; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.lang.annotation.Annotation; import java.security.Principal; import java.time.ZoneId; import java.util.Locale; @@ -84,12 +85,13 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume @Override public boolean supportsParameter(MethodParameter parameter) { Class paramType = parameter.getParameterType(); + final Annotation[] parameterAnnotations = parameter.getParameterAnnotations(); return (WebRequest.class.isAssignableFrom(paramType) || ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType) || HttpSession.class.isAssignableFrom(paramType) || (pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) || - Principal.class.isAssignableFrom(paramType) || + (Principal.class.isAssignableFrom(paramType) && parameterAnnotations.length == 0) || InputStream.class.isAssignableFrom(paramType) || Reader.class.isAssignableFrom(paramType) || HttpMethod.class == paramType || diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java index cddb9624d0..ee8f131cb3 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java @@ -18,6 +18,10 @@ package org.springframework.web.servlet.mvc.method.annotation; import java.io.InputStream; import java.io.Reader; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Method; import java.security.Principal; import java.time.ZoneId; @@ -122,6 +126,19 @@ public class ServletRequestMethodArgumentResolverTests { assertThat(result).as("Invalid result").isNull(); } + // spring-security already provides the @AuthenticationPrincipal annotation to inject the Principal taken from SecurityContext.getAuthentication.getPrincipal() + // but ServletRequestMethodArgumentResolver used to take precedence over @AuthenticationPrincipal resolver org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver + // and we used to get the wrong Principal in methods. See https://github.com/spring-projects/spring-framework/pull/25780 + @Test + public void annotatedPrincipal() throws Exception { + Principal principal = () -> "Foo"; + servletRequest.setUserPrincipal(principal); + Method principalMethod = getClass().getMethod("supportedParamsWithAnnotatedPrincipal", Principal.class); + + MethodParameter principalParameter = new MethodParameter(principalMethod, 0); + assertThat(resolver.supportsParameter(principalParameter)).as("Principal not supported").isFalse(); + } + @Test public void locale() throws Exception { Locale locale = Locale.ENGLISH; @@ -245,6 +262,14 @@ public class ServletRequestMethodArgumentResolverTests { assertThat(result).as("Invalid result").isSameAs(pushBuilder); } + @Target({ ElementType.PARAMETER }) + @Retention(RetentionPolicy.RUNTIME) + public @interface PlaceHolder {} + + @SuppressWarnings("unused") + public void supportedParamsWithAnnotatedPrincipal(@PlaceHolder Principal p) { + + } @SuppressWarnings("unused") public void supportedParams(ServletRequest p0,