Browse Source

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
sandmannn 6 years ago
parent
commit
9323d8e821

+ 29 - 0
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.
+	 *
+	 * <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>
+	 *
+	 * @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

+ 26 - 1
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<GrantedAuthority>) context.getAuthentication().getAuthorities())
 				.containsOnly(this.authority1);
 	}
+
+	@Test
+	public void jwtWhenProvidingPreparedJwtThenUsesItForAuthentication() {
+		Map<String, Object> 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");
+	}
 }