From 05e3f271b62ffbecb2f1f0defe96d4959334843f Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 19 Nov 2020 21:11:23 +0000 Subject: [PATCH] Consistently apply PrincipalMethodArgumentResolver Closes gh-26117 --- .../ExceptionHandlerExceptionResolver.java | 3 + .../RequestMappingHandlerAdapter.java | 1 + ...MappingHandlerAdapterIntegrationTests.java | 71 +++++++++++++++---- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java index 15b504430db..9d731f6101a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java @@ -342,6 +342,9 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce resolvers.addAll(getCustomArgumentResolvers()); } + // Catch-all + resolvers.add(new PrincipalMethodArgumentResolver()); + return resolvers; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java index 6b051220021..9e5ea44432e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java @@ -681,6 +681,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter } // Catch-all + resolvers.add(new PrincipalMethodArgumentResolver()); resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true)); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java index 9aeddcaa566..6c53d75cda9 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,12 @@ package org.springframework.web.servlet.mvc.method.annotation; -import java.awt.Color; +import java.awt.*; +import java.lang.annotation.Documented; +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.net.URI; import java.security.Principal; @@ -70,6 +75,7 @@ import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.bind.support.SessionStatus; import org.springframework.web.bind.support.WebArgumentResolver; +import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletWebRequest; @@ -77,6 +83,7 @@ import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.InvocableHandlerMethod; +import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.testfixture.servlet.MockHttpServletRequest; @@ -114,6 +121,7 @@ public class RequestMappingHandlerAdapterIntegrationTests { List customResolvers = new ArrayList<>(); customResolvers.add(new ServletWebArgumentResolverAdapter(new ColorArgumentResolver())); + customResolvers.add(new CustomPrincipalArgumentResolver()); GenericWebApplicationContext context = new GenericWebApplicationContext(); context.refresh(); @@ -145,7 +153,7 @@ public class RequestMappingHandlerAdapterIntegrationTests { Class[] parameterTypes = new Class[] {int.class, String.class, String.class, String.class, Map.class, Date.class, Map.class, String.class, String.class, TestBean.class, Errors.class, TestBean.class, Color.class, HttpServletRequest.class, HttpServletResponse.class, TestBean.class, TestBean.class, - User.class, OtherUser.class, Model.class, UriComponentsBuilder.class}; + User.class, OtherUser.class, Principal.class, Model.class, UriComponentsBuilder.class}; String datePattern = "yyyy.MM.dd"; String formattedDate = "2011.03.16"; @@ -214,6 +222,7 @@ public class RequestMappingHandlerAdapterIntegrationTests { assertThat(model.get("customArg") instanceof Color).isTrue(); assertThat(model.get("user").getClass()).isEqualTo(User.class); assertThat(model.get("otherUser").getClass()).isEqualTo(OtherUser.class); + assertThat(((Principal) model.get("customUser")).getName()).isEqualTo("Custom User"); assertThat(model.get("sessionAttribute")).isSameAs(sessionAttribute); assertThat(model.get("requestAttribute")).isSameAs(requestAttribute); @@ -476,16 +485,24 @@ public class RequestMappingHandlerAdapterIntegrationTests { HttpServletResponse response, @SessionAttribute TestBean sessionAttribute, @RequestAttribute TestBean requestAttribute, - User user, + @Nullable User user, // gh-26117, gh-26117 (for @Nullable) @ModelAttribute OtherUser otherUser, + @AuthenticationPrincipal Principal customUser, // gh-25780 Model model, UriComponentsBuilder builder) { - model.addAttribute("cookie", cookieV).addAttribute("pathvar", pathvarV).addAttribute("header", headerV) - .addAttribute("systemHeader", systemHeader).addAttribute("headerMap", headerMap) - .addAttribute("dateParam", dateParam).addAttribute("paramMap", paramMap) - .addAttribute("paramByConvention", paramByConvention).addAttribute("value", value) - .addAttribute("customArg", customArg).addAttribute(user) + model.addAttribute("cookie", cookieV) + .addAttribute("pathvar", pathvarV) + .addAttribute("header", headerV) + .addAttribute("systemHeader", systemHeader) + .addAttribute("headerMap", headerMap) + .addAttribute("dateParam", dateParam) + .addAttribute("paramMap", paramMap) + .addAttribute("paramByConvention", paramByConvention) + .addAttribute("value", value) + .addAttribute("customArg", customArg) + .addAttribute(user) + .addAttribute("customUser", customUser) .addAttribute("sessionAttribute", sessionAttribute) .addAttribute("requestAttribute", requestAttribute) .addAttribute("url", builder.path("/path").build().toUri()); @@ -520,10 +537,15 @@ public class RequestMappingHandlerAdapterIntegrationTests { Model model, UriComponentsBuilder builder) { - model.addAttribute("cookie", cookieV).addAttribute("pathvar", pathvarV).addAttribute("header", headerV) - .addAttribute("systemHeader", systemHeader).addAttribute("headerMap", headerMap) - .addAttribute("dateParam", dateParam).addAttribute("paramMap", paramMap) - .addAttribute("paramByConvention", paramByConvention).addAttribute("value", value) + model.addAttribute("cookie", cookieV) + .addAttribute("pathvar", pathvarV) + .addAttribute("header", headerV) + .addAttribute("systemHeader", systemHeader) + .addAttribute("headerMap", headerMap) + .addAttribute("dateParam", dateParam) + .addAttribute("paramMap", paramMap) + .addAttribute("paramByConvention", paramByConvention) + .addAttribute("value", value) .addAttribute("customArg", customArg).addAttribute(user) .addAttribute("sessionAttribute", sessionAttribute) .addAttribute("requestAttribute", requestAttribute) @@ -598,7 +620,6 @@ public class RequestMappingHandlerAdapterIntegrationTests { } } - private static class User implements Principal { @Override @@ -616,4 +637,26 @@ public class RequestMappingHandlerAdapterIntegrationTests { } } + private static class CustomPrincipalArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return (Principal.class.isAssignableFrom(parameter.getParameterType()) && + parameter.hasParameterAnnotation(AuthenticationPrincipal.class)); + } + + @Nullable + @Override + public Object resolveArgument( + MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) { + + return (Principal) () -> "Custom User"; + } + } + + @Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE }) + @Retention(RetentionPolicy.RUNTIME) + @Documented + public @interface AuthenticationPrincipal {} }