From 9323d8e821ab633b2c53a4b82bb13fecd2544f8a Mon Sep 17 00:00:00 2001 From: sandmannn Date: Thu, 30 May 2019 21:53:33 +0200 Subject: [PATCH] Extended testing api for JWT Added new implementation of jwt() method that makes it possible to directly provide a previously prepared JWT token to the MockMvc request builder. Issue: spring-projectsgh-6896 --- .../SecurityMockMvcRequestPostProcessors.java | 29 +++++++++++++++++++ ...yMockMvcRequestPostProcessorsJwtTests.java | 27 ++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java index 05b259d0a6..2bef540d08 100644 --- a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java +++ b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java @@ -262,6 +262,35 @@ public final class SecurityMockMvcRequestPostProcessors { return new JwtRequestPostProcessor(jwtBuilder.build()); } + /** + * 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. + * + *

+ * 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: + *

+ * + * + * + * @param jwt The preliminary constructed {@link Jwt} + * @return the {@link JwtRequestPostProcessor} for additional customization + * @since 5.2 + */ + public static JwtRequestPostProcessor jwt(Jwt jwt) { + return new JwtRequestPostProcessor(jwt); + } + /** * Establish a {@link SecurityContext} that uses the specified {@link Authentication} * for the {@link Authentication#getPrincipal()} and a custom {@link UserDetails}. All diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsJwtTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsJwtTests.java index 565de65bc0..97d4a5aee1 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsJwtTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsJwtTests.java @@ -15,8 +15,13 @@ */ package org.springframework.security.test.web.servlet.request; -import java.util.Arrays; +import java.time.Instant; import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; +import java.util.Collections; + import javax.servlet.http.HttpServletResponse; import org.junit.After; @@ -34,6 +39,8 @@ import org.springframework.security.config.BeanIds; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; +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.web.support.WebTestUtils; @@ -154,4 +161,22 @@ public class SecurityMockMvcRequestPostProcessorsJwtTests { assertThat((List) context.getAuthentication().getAuthorities()) .containsOnly(this.authority1); } + + @Test + public void jwtWhenProvidingPreparedJwtThenUsesItForAuthentication() { + Map claims = new HashMap<>(); + claims.put(IdTokenClaimNames.SUB, "some_user"); + Jwt originalToken = new Jwt("token123", Instant.now(), Instant.now().plusSeconds(3600), + Collections.singletonMap("header1", "value1"), claims); + jwt(originalToken).postProcessRequest(this.request); + + + verify(this.repository).saveContext(this.contextCaptor.capture(), eq(this.request), + any(HttpServletResponse.class)); + SecurityContext context = this.contextCaptor.getValue(); + JwtAuthenticationToken retrievedToken = (JwtAuthenticationToken) context.getAuthentication(); + assertThat(retrievedToken.getToken().getSubject()).isEqualTo("some_user"); + assertThat(retrievedToken.getToken().getTokenValue()).isEqualTo("token123"); + assertThat(retrievedToken.getToken().getHeaders().get("header1")).isEqualTo("value1"); + } }