1
0
mirror of synced 2026-05-22 21:33:16 +00:00

Mock Jwt Test Support and Jwt.Builder

Fixes: gh-6634
Fixes: gh-6851
This commit is contained in:
Jérôme Wacongne
2019-05-08 20:55:04 +02:00
committed by Josh Cummings
parent f6998547b8
commit e59d8a529b
13 changed files with 948 additions and 14 deletions
+2
View File
@@ -7,6 +7,8 @@ dependencies {
compile 'org.springframework:spring-test'
optional project(':spring-security-config')
optional project(':spring-security-oauth2-resource-server')
optional project(':spring-security-oauth2-jose')
optional 'io.projectreactor:reactor-core'
optional 'org.springframework:spring-webflux'
@@ -0,0 +1,140 @@
/*
* Copyright 2002-2019 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. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.security.test.support;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimNames;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.util.StringUtils;
/**
* @author Jérôme Wacongne <ch4mp@c4-soft.com>
* @since 5.2
*/
public class JwtAuthenticationTokenTestingBuilder<T extends JwtAuthenticationTokenTestingBuilder<T>>
extends
JwtAuthenticationToken.Builder<T> {
private static final String[] DEFAULT_SCOPES = { "USER" };
private final Set<GrantedAuthority> addedAuthorities;
public JwtAuthenticationTokenTestingBuilder(Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter) {
super(new JwtTestingBuilder(), authoritiesConverter);
this.addedAuthorities = new HashSet<>();
scopes(DEFAULT_SCOPES);
}
public JwtAuthenticationTokenTestingBuilder() {
this(new JwtGrantedAuthoritiesConverter());
}
/**
* How to extract authorities from token
* @param authoritiesConverter JWT to granted-authorities converter
* @return this builder to further configure
*/
public T authorities(Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter) {
return authoritiesConverter(authoritiesConverter);
}
/**
* Adds authorities to what is extracted from the token.<br>
* Please consider using {@link #authorities(Converter)} instead.
* @param authorities authorities to add to token ones
* @return this builder to further configure
*/
public T authorities(Stream<GrantedAuthority> authorities) {
addedAuthorities.addAll(authorities.collect(Collectors.toSet()));
return downcast();
}
/**
* Adds authorities to what is extracted from the token.<br>
* Please consider using {@link #authorities(Converter)} instead.
* @param authorities authorities to add to token ones
* @return this builder to further configure
*/
public T authorities(GrantedAuthority... authorities) {
return authorities(Stream.of(authorities));
}
/**
* Adds authorities to what is extracted from the token.<br>
* Please consider using {@link #authorities(Converter)} instead.
* @param authorities authorities to add to token ones
* @return this builder to further configure
*/
public T authorities(String... authorities) {
return authorities(Stream.of(authorities).map(SimpleGrantedAuthority::new));
}
@Override
public JwtAuthenticationToken build() {
final Jwt token = getToken();
return new JwtAuthenticationToken(token, getAuthorities(token));
}
@Override
protected Collection<GrantedAuthority> getAuthorities(Jwt token) {
final Collection<GrantedAuthority> principalAuthorities = super.getAuthorities(token);
return addedAuthorities.isEmpty() ? principalAuthorities
: Stream.concat(principalAuthorities.stream(), addedAuthorities.stream()).collect(Collectors.toSet());
}
/**
* @author Jérôme Wacongne &lt;ch4mp&#64;c4-soft.com&gt;
* @since 5.2
*/
static class JwtTestingBuilder extends Jwt.Builder<JwtTestingBuilder> {
private static final String DEFAULT_SUBJECT = "user";
private static final String DEFAULT_TOKEN_VALUE = "test.jwt.value";
private static final String DEFAULT_HEADER_NAME = "test-header";
private static final String DEFAULT_HEADER_VALUE = "test-header-value";
public JwtTestingBuilder() {
super();
}
@Override
public Jwt build() {
final Object subjectClaim = claims.get(JwtClaimNames.SUB);
if (!StringUtils.hasLength(tokenValue)) {
tokenValue(DEFAULT_TOKEN_VALUE);
}
if (!StringUtils.hasLength((String) subjectClaim)) {
claim(JwtClaimNames.SUB, DEFAULT_SUBJECT);
}
if (headers.size() == 0) {
header(DEFAULT_HEADER_NAME, DEFAULT_HEADER_VALUE);
}
return super.build();
}
}
}
@@ -16,6 +16,11 @@
package org.springframework.security.test.web.reactive.server;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -26,6 +31,9 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
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.support.JwtAuthenticationTokenTestingBuilder;
import org.springframework.security.web.server.csrf.CsrfWebFilter;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.test.web.reactive.server.MockServerConfigurer;
@@ -35,12 +43,8 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.core.publisher.Mono;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import reactor.core.publisher.Mono;
/**
* Test utilities for working with Spring Security and
@@ -109,6 +113,23 @@ public class SecurityMockServerConfigurers {
return new UserExchangeMutator(username);
}
/**
* 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.
*
* @return the {@link JwtMutator} to further configure or use
*/
public static JwtMutator mockJwt() {
return new JwtMutator();
}
public static JwtMutator mockJwt(Consumer<Jwt.Builder<?>> jwt) {
return new JwtMutator().token(jwt);
}
public static CsrfMutator csrf() {
return new CsrfMutator();
}
@@ -294,4 +315,31 @@ public class SecurityMockServerConfigurers {
return webFilterChain.filter(exchange);
}
}
/**
* @author Jérôme Wacongne &lt;ch4mp&#64;c4-soft.com&gt;
* @since 5.2
*/
public static class JwtMutator extends JwtAuthenticationTokenTestingBuilder<JwtMutator>
implements
WebTestClientConfigurer, MockServerConfigurer {
@Override
public void beforeServerCreated(WebHttpHandlerBuilder builder) {
mockAuthentication(build()).beforeServerCreated(builder);
}
@Override
public void afterConfigureAdded(WebTestClient.MockServerSpec<?> serverSpec) {
mockAuthentication(build()).afterConfigureAdded(serverSpec);
}
@Override
public void afterConfigurerAdded(
WebTestClient.Builder builder,
@Nullable WebHttpHandlerBuilder httpHandlerBuilder,
@Nullable ClientHttpConnector connector) {
mockAuthentication(build()).afterConfigurerAdded(builder, httpHandlerBuilder, connector);
}
}
}
@@ -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 &lt;ch4mp&#64;c4-soft.com&gt;
* @since 5.2
*/
public static class JwtRequestPostProcessor extends JwtAuthenticationTokenTestingBuilder<JwtRequestPostProcessor>
implements
RequestPostProcessor {
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
SecurityContextRequestPostProcessorSupport.save(build(), request);
return request;
}
}
}
@@ -0,0 +1,83 @@
/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.test.support;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimNames;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
/**
* @author Jérôme Wacongne &lt;ch4mp&#64;c4-soft.com&gt;
* @since 5.2
*/
public class JwtAuthenticationTokenTestingBuilderTests {
@Test
public void untouchedBuilderSetsDefaultValues() {
final JwtAuthenticationToken actual = new JwtAuthenticationTokenTestingBuilder<>().build();
assertThat(actual.getName()).isEqualTo("user");
assertThat(actual.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_USER"));
assertThat(actual.getPrincipal()).isInstanceOf(Jwt.class);
assertThat(actual.getCredentials()).isInstanceOf(Jwt.class);
assertThat(actual.getDetails()).isNull();
// Token default values are tested in JwtTestingBuilderTests
assertThat(actual.getToken()).isEqualTo(new JwtAuthenticationTokenTestingBuilder.JwtTestingBuilder().build());
}
@Test
public void nameOverridesDefaultValue() {
assertThat(new JwtAuthenticationTokenTestingBuilder<>().name("ch4mpy").build().getName()).isEqualTo("ch4mpy");
}
@Test
public void authoritiesAddsToDefaultValue() {
assertThat(new JwtAuthenticationTokenTestingBuilder<>().authorities("TEST").build().getAuthorities())
.containsExactlyInAnyOrder(new SimpleGrantedAuthority("SCOPE_USER"), new SimpleGrantedAuthority("TEST"));
}
@Test
public void scopesOveridesDefaultValue() {
assertThat(new JwtAuthenticationTokenTestingBuilder<>().scopes("TEST").build().getAuthorities())
.containsExactly(new SimpleGrantedAuthority("SCOPE_TEST"));
}
@Test
public void nameSetsAuthenticationNameAndTokenSubjectClaim() {
final JwtAuthenticationToken actual = new JwtAuthenticationTokenTestingBuilder<>().name("ch4mpy").build();
assertThat(actual.getName()).isEqualTo("ch4mpy");
assertThat(actual.getTokenAttributes().get(JwtClaimNames.SUB)).isEqualTo("ch4mpy");
}
@Test
public void buildMergesConvertedClaimsAndAuthorities() {
final JwtAuthenticationToken actual = new JwtAuthenticationTokenTestingBuilder<>().name("ch4mpy")
.authorities(new SimpleGrantedAuthority("TEST_AUTHORITY"))
.scopes("scope:claim")
.build();
assertThat(actual.getAuthorities()).containsExactlyInAnyOrder(
new SimpleGrantedAuthority("TEST_AUTHORITY"),
new SimpleGrantedAuthority("SCOPE_scope:claim"));
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.test.support;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Instant;
import org.junit.Test;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimNames;
import org.springframework.security.test.support.JwtAuthenticationTokenTestingBuilder.JwtTestingBuilder;
/**
*
*
* @author Jérôme Wacongne &lt;ch4mp&#64;c4-soft.com&gt;
*/
public class JwtTestingBuilderTests {
@Test
public void testDefaultValuesAreSet() {
final Jwt actual = new JwtTestingBuilder().build();
assertThat(actual.getTokenValue()).isEqualTo("test.jwt.value");
assertThat(actual.getClaimAsString(JwtClaimNames.SUB)).isEqualTo("user");
assertThat(actual.getHeaders()).hasSize(1);
}
@Test
public void iatClaimAndExpClaimSetIssuedAtAndExpiresAt() {
final Jwt actual = new JwtTestingBuilder()
.claim(JwtClaimNames.IAT, Instant.parse("2019-03-21T13:52:25Z"))
.claim(JwtClaimNames.EXP, Instant.parse("2019-03-22T13:52:25Z"))
.build();
assertThat(actual.getIssuedAt()).isEqualTo(Instant.parse("2019-03-21T13:52:25Z"));
assertThat(actual.getExpiresAt()).isEqualTo(Instant.parse("2019-03-22T13:52:25Z"));
assertThat(actual.getClaimAsInstant(JwtClaimNames.IAT)).isEqualTo(Instant.parse("2019-03-21T13:52:25Z"));
assertThat(actual.getClaimAsInstant(JwtClaimNames.EXP)).isEqualTo(Instant.parse("2019-03-22T13:52:25Z"));
}
}
@@ -0,0 +1,65 @@
/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.test.web.reactive.server;
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockJwt;
import org.junit.Test;
/**
* @author Jérôme Wacongne &lt;ch4mp&#64;c4-soft.com&gt;
* @since 5.2
*/
public class JwtMutatorTests {
// @formatter:off
@Test
public void defaultJwtConfigurerConfiguresAuthenticationDefaultNameAndAuthorities() {
TestController.clientBuilder()
.apply(mockJwt()).build()
.get().uri("/greet").exchange()
.expectStatus().isOk()
.expectBody().toString().equals("Hello user!");
TestController.clientBuilder()
.apply(mockJwt()).build()
.get().uri("/authorities").exchange()
.expectStatus().isOk()
.expectBody().toString().equals("[\"ROLE_USER\"]");
}
@Test
public void nameAndScopesConfigureAuthenticationNameAndAuthorities() {
TestController.clientBuilder()
.apply(mockJwt().name("ch4mpy").scopes("message:read")).build()
.get().uri("/greet").exchange()
.expectStatus().isOk()
.expectBody().toString().equals("Hello ch4mpy!");
TestController.clientBuilder()
.apply(mockJwt().name("ch4mpy").scopes("message:read")).build()
.get().uri("/authorities").exchange()
.expectStatus().isOk()
.expectBody().toString().equals("[\"SCOPE_message:read\"]");
TestController.clientBuilder()
.apply(mockJwt().name("ch4mpy").scopes("message:read")).build()
.get().uri("/jwt").exchange()
.expectStatus().isOk()
.expectBody().toString().equals(
"Hello,ch4mpy! You are sucessfully authenticated and granted with [message:read] scopes using a JavaWebToken.");
}
// @formatter:on
}
@@ -0,0 +1,78 @@
/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.test.web.reactive.server;
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;
import java.security.Principal;
import java.util.stream.Collectors;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter;
import org.springframework.security.web.server.csrf.CsrfWebFilter;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Jérôme Wacongne &lt;ch4mp&#64;c4-soft.com&gt;
* @since 5.2
*/
@RestController
public class TestController {
@GetMapping("/greet")
public String greet(final Principal authentication) {
return String.format("Hello, %s!", authentication.getName());
}
@GetMapping("/authorities")
public String authentication(final Authentication authentication) {
return authentication.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList())
.toString();
}
@GetMapping("/jwt")
// TODO: investigate why "@AuthenticationPrincipal Jwt token" does not work here
public String jwt(final Authentication authentication) {
final Jwt token = (Jwt) authentication.getPrincipal();
final String scopes = token.getClaimAsString("scope");
return String.format(
"Hello, %s! You are sucessfully authenticated and granted with %s scopes using a Jwt.",
token.getSubject(),
scopes);
}
public static WebTestClient.Builder clientBuilder() {
return WebTestClient.bindToController(new TestController())
.webFilter(new CsrfWebFilter(), new SecurityContextServerWebExchangeWebFilter())
.apply(springSecurity())
.configureClient()
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
}
public static WebTestClient client() {
return (WebTestClient) clientBuilder().build();
}
}
@@ -0,0 +1,67 @@
/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.test.web.servlet.request;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.JwtRequestPostProcessor;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.SecurityContextRequestPostProcessorSupport.TestSecurityContextRepository;
/**
* @author Jérôme Wacongne &lt;ch4mp&#64;c4-soft.com&gt;
* @since 5.2
*/
public class JwtRequestPostProcessorTests {
@Mock
MockHttpServletRequest request;
final static String TEST_NAME = "ch4mpy";
final static String[] TEST_AUTHORITIES = { "TEST_AUTHORITY" };
@Before
public void setup() throws Exception {
request = new MockHttpServletRequest();
}
@Test
public void nameAndAuthoritiesAndClaimsConfigureSecurityContextAuthentication() {
final JwtRequestPostProcessor rpp =
jwt().name(TEST_NAME).authorities(TEST_AUTHORITIES).scopes("test:claim");
final JwtAuthenticationToken actual = (JwtAuthenticationToken) authentication(rpp.postProcessRequest(request));
assertThat(actual.getName()).isEqualTo(TEST_NAME);
assertThat(actual.getAuthorities()).containsExactlyInAnyOrder(
new SimpleGrantedAuthority("TEST_AUTHORITY"),
new SimpleGrantedAuthority("SCOPE_test:claim"));
assertThat(actual.getTokenAttributes().get("scope")).isEqualTo("test:claim");
}
static Authentication authentication(final MockHttpServletRequest req) {
final SecurityContext securityContext = (SecurityContext) req.getAttribute(TestSecurityContextRepository.ATTR_NAME);
return securityContext == null ? null : securityContext.getAuthentication();
}
}