Isolate Jwt Test Support
Isolating Jwt test support inside JwtRequestPostProcessor and JwtMutator. Fixes gh-7641
This commit is contained in:
+42
-43
@@ -127,42 +127,7 @@ public class SecurityMockServerConfigurers {
|
||||
* @since 5.2
|
||||
*/
|
||||
public static JwtMutator mockJwt() {
|
||||
return mockJwt(jwt -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ServerWebExchange to 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.
|
||||
*
|
||||
* @param jwtBuilderConsumer For configuring the underlying {@link Jwt}
|
||||
* @return the {@link JwtMutator} to further configure or use
|
||||
* @since 5.2
|
||||
*/
|
||||
public static JwtMutator mockJwt(Consumer<Jwt.Builder> jwtBuilderConsumer) {
|
||||
Jwt.Builder jwtBuilder = Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.claim(SUB, "user")
|
||||
.claim("scope", "read");
|
||||
jwtBuilderConsumer.accept(jwtBuilder);
|
||||
return new JwtMutator(jwtBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ServerWebExchange to 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.
|
||||
*
|
||||
* @param jwt The preliminary constructed {@link Jwt}
|
||||
* @return the {@link JwtMutator} to further configure or use
|
||||
* @since 5.2
|
||||
*/
|
||||
public static JwtMutator mockJwt(Jwt jwt) {
|
||||
return new JwtMutator(jwt);
|
||||
return new JwtMutator();
|
||||
}
|
||||
|
||||
public static CsrfMutator csrf() {
|
||||
@@ -361,11 +326,45 @@ public class SecurityMockServerConfigurers {
|
||||
*/
|
||||
public static class JwtMutator implements WebTestClientConfigurer, MockServerConfigurer {
|
||||
private Jwt jwt;
|
||||
private Collection<GrantedAuthority> authorities;
|
||||
private Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter =
|
||||
new JwtGrantedAuthoritiesConverter();
|
||||
|
||||
private JwtMutator(Jwt jwt) {
|
||||
private JwtMutator() {
|
||||
jwt((jwt) -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Jwt.Builder} {@link Consumer} to configure the underlying {@link Jwt}
|
||||
*
|
||||
* This method first creates a default {@link Jwt.Builder} instance with default values for
|
||||
* the {@code alg}, {@code sub}, and {@code scope} claims. The {@link Consumer} can then modify
|
||||
* these or provide additional configuration.
|
||||
*
|
||||
* Calling {@link SecurityMockServerConfigurers#mockJwt()} is the equivalent of calling
|
||||
* {@code SecurityMockMvcRequestPostProcessors.mockJwt().jwt(() -> {})}.
|
||||
*
|
||||
* @param jwtBuilderConsumer For configuring the underlying {@link Jwt}
|
||||
* @return the {@link JwtMutator} for further configuration
|
||||
*/
|
||||
public JwtMutator jwt(Consumer<Jwt.Builder> jwtBuilderConsumer) {
|
||||
Jwt.Builder jwtBuilder = Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.claim(SUB, "user")
|
||||
.claim("scope", "read");
|
||||
jwtBuilderConsumer.accept(jwtBuilder);
|
||||
this.jwt = jwtBuilder.build();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Jwt}
|
||||
*
|
||||
* @param jwt The {@link Jwt} to use
|
||||
* @return the {@link JwtMutator} for further configuration
|
||||
*/
|
||||
public JwtMutator jwt(Jwt jwt) {
|
||||
this.jwt = jwt;
|
||||
this.authorities = new JwtGrantedAuthoritiesConverter().convert(jwt);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,7 +374,7 @@ public class SecurityMockServerConfigurers {
|
||||
*/
|
||||
public JwtMutator authorities(Collection<GrantedAuthority> authorities) {
|
||||
Assert.notNull(authorities, "authorities cannot be null");
|
||||
this.authorities = authorities;
|
||||
this.authoritiesConverter = jwt -> authorities;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -386,7 +385,7 @@ public class SecurityMockServerConfigurers {
|
||||
*/
|
||||
public JwtMutator authorities(GrantedAuthority... authorities) {
|
||||
Assert.notNull(authorities, "authorities cannot be null");
|
||||
this.authorities = Arrays.asList(authorities);
|
||||
this.authoritiesConverter = jwt -> Arrays.asList(authorities);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -400,7 +399,7 @@ public class SecurityMockServerConfigurers {
|
||||
*/
|
||||
public JwtMutator authorities(Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter) {
|
||||
Assert.notNull(authoritiesConverter, "authoritiesConverter cannot be null");
|
||||
this.authorities = authoritiesConverter.convert(this.jwt);
|
||||
this.authoritiesConverter = authoritiesConverter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -427,7 +426,7 @@ public class SecurityMockServerConfigurers {
|
||||
}
|
||||
|
||||
private <T extends WebTestClientConfigurer & MockServerConfigurer> T configurer() {
|
||||
return mockAuthentication(new JwtAuthenticationToken(this.jwt, this.authorities));
|
||||
return mockAuthentication(new JwtAuthenticationToken(this.jwt, this.authoritiesConverter.convert(this.jwt)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-71
@@ -227,70 +227,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
||||
* @return the {@link JwtRequestPostProcessor} for additional customization
|
||||
*/
|
||||
public static JwtRequestPostProcessor jwt() {
|
||||
return jwt(jwt -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 jwtBuilderConsumer For configuring the underlying {@link Jwt}
|
||||
* @return the {@link JwtRequestPostProcessor} for additional customization
|
||||
* @since 5.2
|
||||
*/
|
||||
public static JwtRequestPostProcessor jwt(Consumer<Jwt.Builder> jwtBuilderConsumer) {
|
||||
Jwt.Builder jwtBuilder = Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.claim(SUB, "user")
|
||||
.claim("scope", "read");
|
||||
jwtBuilderConsumer.accept(jwtBuilder);
|
||||
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);
|
||||
return new JwtRequestPostProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1000,11 +937,45 @@ public final class SecurityMockMvcRequestPostProcessors {
|
||||
*/
|
||||
public final static class JwtRequestPostProcessor implements RequestPostProcessor {
|
||||
private Jwt jwt;
|
||||
private Collection<? extends GrantedAuthority> authorities;
|
||||
private Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter =
|
||||
new JwtGrantedAuthoritiesConverter();
|
||||
|
||||
private JwtRequestPostProcessor(Jwt jwt) {
|
||||
private JwtRequestPostProcessor() {
|
||||
this.jwt((jwt) -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Jwt.Builder} {@link Consumer} to configure the underlying {@link Jwt}
|
||||
*
|
||||
* This method first creates a default {@link Jwt.Builder} instance with default values for
|
||||
* the {@code alg}, {@code sub}, and {@code scope} claims. The {@link Consumer} can then modify
|
||||
* these or provide additional configuration.
|
||||
*
|
||||
* Calling {@link SecurityMockMvcRequestPostProcessors#jwt()} is the equivalent of calling
|
||||
* {@code SecurityMockMvcRequestPostProcessors.jwt().jwt(() -> {})}.
|
||||
*
|
||||
* @param jwtBuilderConsumer For configuring the underlying {@link Jwt}
|
||||
* @return the {@link JwtRequestPostProcessor} for additional customization
|
||||
*/
|
||||
public JwtRequestPostProcessor jwt(Consumer<Jwt.Builder> jwtBuilderConsumer) {
|
||||
Jwt.Builder jwtBuilder = Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.claim(SUB, "user")
|
||||
.claim("scope", "read");
|
||||
jwtBuilderConsumer.accept(jwtBuilder);
|
||||
this.jwt = jwtBuilder.build();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Jwt}
|
||||
*
|
||||
* @param jwt The {@link Jwt} to use
|
||||
* @return the {@link JwtRequestPostProcessor} for additional customization
|
||||
*/
|
||||
public JwtRequestPostProcessor jwt(Jwt jwt) {
|
||||
this.jwt = jwt;
|
||||
this.authorities = new JwtGrantedAuthoritiesConverter().convert(jwt);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1014,7 +985,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
||||
*/
|
||||
public JwtRequestPostProcessor authorities(Collection<GrantedAuthority> authorities) {
|
||||
Assert.notNull(authorities, "authorities cannot be null");
|
||||
this.authorities = authorities;
|
||||
this.authoritiesConverter = jwt -> authorities;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1025,7 +996,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
||||
*/
|
||||
public JwtRequestPostProcessor authorities(GrantedAuthority... authorities) {
|
||||
Assert.notNull(authorities, "authorities cannot be null");
|
||||
this.authorities = Arrays.asList(authorities);
|
||||
this.authoritiesConverter = jwt -> Arrays.asList(authorities);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1039,14 +1010,15 @@ public final class SecurityMockMvcRequestPostProcessors {
|
||||
*/
|
||||
public JwtRequestPostProcessor authorities(Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter) {
|
||||
Assert.notNull(authoritiesConverter, "authoritiesConverter cannot be null");
|
||||
this.authorities = authoritiesConverter.convert(this.jwt);
|
||||
this.authoritiesConverter = authoritiesConverter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||
CsrfFilter.skipRequest(request);
|
||||
JwtAuthenticationToken token = new JwtAuthenticationToken(this.jwt, this.authorities);
|
||||
JwtAuthenticationToken token = new JwtAuthenticationToken(this.jwt,
|
||||
this.authoritiesConverter.convert(this.jwt));
|
||||
return new AuthenticationRequestPostProcessor(token).postProcessRequest(request);
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -85,7 +85,7 @@ public class SecurityMockServerConfigurersJwtTests extends AbstractMockServerCon
|
||||
public void mockJwtWhenProvidingBuilderConsumerThenProducesJwtAuthentication() {
|
||||
String name = new String("user");
|
||||
client
|
||||
.mutateWith(mockJwt(jwt -> jwt.subject(name)))
|
||||
.mutateWith(mockJwt().jwt(jwt -> jwt.subject(name)))
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
@@ -100,7 +100,7 @@ public class SecurityMockServerConfigurersJwtTests extends AbstractMockServerCon
|
||||
@Test
|
||||
public void mockJwtWhenProvidingCustomAuthoritiesThenProducesJwtAuthentication() {
|
||||
client
|
||||
.mutateWith(mockJwt(jwt -> jwt.claim("scope", "ignored authorities"))
|
||||
.mutateWith(mockJwt().jwt(jwt -> jwt.claim("scope", "ignored authorities"))
|
||||
.authorities(this.authority1, this.authority2))
|
||||
.get()
|
||||
.exchange()
|
||||
@@ -114,7 +114,7 @@ public class SecurityMockServerConfigurersJwtTests extends AbstractMockServerCon
|
||||
@Test
|
||||
public void mockJwtWhenProvidingScopedAuthoritiesThenProducesJwtAuthentication() {
|
||||
client
|
||||
.mutateWith(mockJwt(jwt -> jwt.claim("scope", "scoped authorities")))
|
||||
.mutateWith(mockJwt().jwt(jwt -> jwt.claim("scope", "scoped authorities")))
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
@@ -128,7 +128,7 @@ public class SecurityMockServerConfigurersJwtTests extends AbstractMockServerCon
|
||||
@Test
|
||||
public void mockJwtWhenProvidingGrantedAuthoritiesThenProducesJwtAuthentication() {
|
||||
client
|
||||
.mutateWith(mockJwt(jwt -> jwt.claim("scope", "ignored authorities"))
|
||||
.mutateWith(mockJwt().jwt(jwt -> jwt.claim("scope", "ignored authorities"))
|
||||
.authorities(jwt -> Arrays.asList(this.authority1)))
|
||||
.get()
|
||||
.exchange()
|
||||
@@ -146,7 +146,7 @@ public class SecurityMockServerConfigurersJwtTests extends AbstractMockServerCon
|
||||
.subject("some_user")
|
||||
.build();
|
||||
this.client
|
||||
.mutateWith(mockJwt(originalToken))
|
||||
.mutateWith(mockJwt().jwt(originalToken))
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
+5
-5
@@ -107,7 +107,7 @@ public class SecurityMockMvcRequestPostProcessorsJwtTests {
|
||||
@Test
|
||||
public void jwtWhenProvidingBuilderConsumerThenProducesJwtAuthentication() {
|
||||
String name = new String("user");
|
||||
jwt(jwt -> jwt.subject(name)).postProcessRequest(this.request);
|
||||
jwt().jwt(jwt -> jwt.subject(name)).postProcessRequest(this.request);
|
||||
|
||||
verify(this.repository).saveContext(this.contextCaptor.capture(), eq(this.request),
|
||||
any(HttpServletResponse.class));
|
||||
@@ -120,7 +120,7 @@ public class SecurityMockMvcRequestPostProcessorsJwtTests {
|
||||
|
||||
@Test
|
||||
public void jwtWhenProvidingCustomAuthoritiesThenProducesJwtAuthentication() {
|
||||
jwt(jwt -> jwt.claim("scope", "ignored authorities"))
|
||||
jwt().jwt(jwt -> jwt.claim("scope", "ignored authorities"))
|
||||
.authorities(this.authority1, this.authority2)
|
||||
.postProcessRequest(this.request);
|
||||
|
||||
@@ -133,7 +133,7 @@ public class SecurityMockMvcRequestPostProcessorsJwtTests {
|
||||
|
||||
@Test
|
||||
public void jwtWhenProvidingScopedAuthoritiesThenProducesJwtAuthentication() {
|
||||
jwt(jwt -> jwt.claim("scope", "scoped authorities"))
|
||||
jwt().jwt(jwt -> jwt.claim("scope", "scoped authorities"))
|
||||
.postProcessRequest(this.request);
|
||||
|
||||
verify(this.repository).saveContext(this.contextCaptor.capture(), eq(this.request),
|
||||
@@ -146,7 +146,7 @@ public class SecurityMockMvcRequestPostProcessorsJwtTests {
|
||||
|
||||
@Test
|
||||
public void jwtWhenProvidingGrantedAuthoritiesThenProducesJwtAuthentication() {
|
||||
jwt(jwt -> jwt.claim("scope", "ignored authorities"))
|
||||
jwt().jwt(jwt -> jwt.claim("scope", "ignored authorities"))
|
||||
.authorities(jwt -> Arrays.asList(this.authority1))
|
||||
.postProcessRequest(this.request);
|
||||
|
||||
@@ -163,7 +163,7 @@ public class SecurityMockMvcRequestPostProcessorsJwtTests {
|
||||
.header("header1", "value1")
|
||||
.subject("some_user")
|
||||
.build();
|
||||
jwt(originalToken).postProcessRequest(this.request);
|
||||
jwt().jwt(originalToken).postProcessRequest(this.request);
|
||||
|
||||
verify(this.repository).saveContext(this.contextCaptor.capture(), eq(this.request),
|
||||
any(HttpServletResponse.class));
|
||||
|
||||
Reference in New Issue
Block a user