|
@@ -26,6 +26,7 @@ import java.util.Arrays;
|
|
|
import java.util.Base64;
|
|
|
import java.util.Collection;
|
|
|
import java.util.List;
|
|
|
+import java.util.function.Consumer;
|
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
@@ -45,7 +46,10 @@ import org.springframework.security.core.context.SecurityContext;
|
|
|
import org.springframework.security.core.context.SecurityContextHolder;
|
|
|
import org.springframework.security.core.userdetails.User;
|
|
|
import org.springframework.security.core.userdetails.UserDetails;
|
|
|
+import org.springframework.security.oauth2.jwt.Jwt;
|
|
|
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
|
|
import org.springframework.security.test.context.TestSecurityContextHolder;
|
|
|
+import org.springframework.security.test.support.JwtAuthenticationTokenTestingBuilder;
|
|
|
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
|
|
import org.springframework.security.test.web.support.WebTestUtils;
|
|
|
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
|
@@ -195,6 +199,37 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|
|
return new UserDetailsRequestPostProcessor(user);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Establish a {@link SecurityContext} that has a
|
|
|
+ * {@link JwtAuthenticationToken} for the
|
|
|
+ * {@link Authentication} and a {@link Jwt} for the
|
|
|
+ * {@link Authentication#getPrincipal()}. All details are
|
|
|
+ * declarative and do not require the JWT to be valid.
|
|
|
+ *
|
|
|
+ * <p>
|
|
|
+ * The support works by associating the authentication to the HttpServletRequest. To associate
|
|
|
+ * the request to the SecurityContextHolder you need to ensure that the
|
|
|
+ * SecurityContextPersistenceFilter is associated with the MockMvc instance. A few
|
|
|
+ * ways to do this are:
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * <ul>
|
|
|
+ * <li>Invoking apply {@link SecurityMockMvcConfigurers#springSecurity()}</li>
|
|
|
+ * <li>Adding Spring Security's FilterChainProxy to MockMvc</li>
|
|
|
+ * <li>Manually adding {@link SecurityContextPersistenceFilter} to the MockMvc
|
|
|
+ * instance may make sense when using MockMvcBuilders standaloneSetup</li>
|
|
|
+ * </ul>
|
|
|
+ *
|
|
|
+ * @return the {@link JwtRequestPostProcessor} for additional customization
|
|
|
+ */
|
|
|
+ public static JwtRequestPostProcessor jwt() {
|
|
|
+ return new JwtRequestPostProcessor();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static JwtRequestPostProcessor jwt(Consumer<Jwt.Builder<?>> jwt) {
|
|
|
+ return jwt().token(jwt);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Establish a {@link SecurityContext} that uses the specified {@link Authentication}
|
|
|
* for the {@link Authentication#getPrincipal()} and a custom {@link UserDetails}. All
|
|
@@ -555,7 +590,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|
|
* Support class for {@link RequestPostProcessor}'s that establish a Spring Security
|
|
|
* context
|
|
|
*/
|
|
|
- private static abstract class SecurityContextRequestPostProcessorSupport {
|
|
|
+ static class SecurityContextRequestPostProcessorSupport {
|
|
|
|
|
|
/**
|
|
|
* Saves the specified {@link Authentication} into an empty
|
|
@@ -564,7 +599,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|
|
* @param authentication the {@link Authentication} to save
|
|
|
* @param request the {@link HttpServletRequest} to use
|
|
|
*/
|
|
|
- final void save(Authentication authentication, HttpServletRequest request) {
|
|
|
+ static final void save(Authentication authentication, HttpServletRequest request) {
|
|
|
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
|
|
securityContext.setAuthentication(authentication);
|
|
|
save(securityContext, request);
|
|
@@ -576,7 +611,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|
|
* @param securityContext the {@link SecurityContext} to save
|
|
|
* @param request the {@link HttpServletRequest} to use
|
|
|
*/
|
|
|
- final void save(SecurityContext securityContext, HttpServletRequest request) {
|
|
|
+ static final void save(SecurityContext securityContext, HttpServletRequest request) {
|
|
|
SecurityContextRepository securityContextRepository = WebTestUtils
|
|
|
.getSecurityContextRepository(request);
|
|
|
boolean isTestRepository = securityContextRepository instanceof TestSecurityContextRepository;
|
|
@@ -604,7 +639,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|
|
* stateless mode
|
|
|
*/
|
|
|
static class TestSecurityContextRepository implements SecurityContextRepository {
|
|
|
- private final static String ATTR_NAME = TestSecurityContextRepository.class
|
|
|
+ final static String ATTR_NAME = TestSecurityContextRepository.class
|
|
|
.getName().concat(".REPO");
|
|
|
|
|
|
private final SecurityContextRepository delegate;
|
|
@@ -716,8 +751,6 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|
|
|
|
|
@Override
|
|
|
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
|
|
- SecurityContext context = SecurityContextHolder.createEmptyContext();
|
|
|
- context.setAuthentication(this.authentication);
|
|
|
save(this.authentication, request);
|
|
|
return request;
|
|
|
}
|
|
@@ -907,4 +940,20 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|
|
|
|
|
private SecurityMockMvcRequestPostProcessors() {
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @author Jérôme Wacongne <ch4mp@c4-soft.com>
|
|
|
+ * @since 5.2
|
|
|
+ */
|
|
|
+ public static class JwtRequestPostProcessor extends JwtAuthenticationTokenTestingBuilder<JwtRequestPostProcessor>
|
|
|
+ implements
|
|
|
+ RequestPostProcessor {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
|
|
+ SecurityContextRequestPostProcessorSupport.save(build(), request);
|
|
|
+ return request;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
}
|