From 05caf3d8fbdba89f42de621c04dce454317431e8 Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Mon, 16 Sep 2019 09:00:04 -0600 Subject: [PATCH] Use Jwt.Builder Fixes gh-7443 --- .../config/annotation/rsocket/JwtITests.java | 27 +++--- .../client/OAuth2LoginConfigurerTests.java | 21 +++-- .../OAuth2ResourceServerConfigurerTests.java | 7 +- .../config/web/server/OAuth2LoginTests.java | 24 +++-- .../server/OAuth2ResourceServerSpecTests.java | 8 +- .../spring-security-oauth2-client.gradle | 1 + ...zationCodeAuthenticationProviderTests.java | 35 +++---- ...odeReactiveAuthenticationManagerTests.java | 36 ++++---- .../OidcIdTokenValidatorTests.java | 26 ++++-- .../security/oauth2/jwt/Jwt.java | 1 + .../security/oauth2/jwt/NimbusJwtDecoder.java | 12 +-- .../oauth2/jwt/NimbusReactiveJwtDecoder.java | 8 +- .../oauth2/jwt/JwtIssuerValidatorTests.java | 40 +------- .../jwt/JwtTimestampValidatorTests.java | 91 +++++-------------- .../security/oauth2/jwt/TestJwts.java | 40 ++++++++ ...ing-security-oauth2-resource-server.gradle | 1 + .../JwtAuthenticationConverterTests.java | 23 ++--- .../JwtAuthenticationProviderTests.java | 21 +---- .../JwtGrantedAuthoritiesConverterTests.java | 81 +++++++---------- ...JwtReactiveAuthenticationManagerTests.java | 15 +-- ...wtAuthenticationConverterAdapterTests.java | 37 +++----- ...activeJwtAuthenticationConverterTests.java | 24 ++--- ...antedAuthoritiesConverterAdapterTests.java | 21 +---- ...SecurityMockServerConfigurersJwtTests.java | 18 ++-- ...yMockMvcRequestPostProcessorsJwtTests.java | 20 ++-- 25 files changed, 248 insertions(+), 390 deletions(-) create mode 100644 oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/TestJwts.java diff --git a/config/src/test/java/org/springframework/security/config/annotation/rsocket/JwtITests.java b/config/src/test/java/org/springframework/security/config/annotation/rsocket/JwtITests.java index 7968bcca8e..23b2b8a53f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/rsocket/JwtITests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/rsocket/JwtITests.java @@ -15,6 +15,10 @@ */ package org.springframework.security.config.annotation.rsocket; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import io.rsocket.RSocketFactory; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.transport.netty.server.CloseableChannel; @@ -23,6 +27,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -34,6 +40,7 @@ import org.springframework.security.config.Customizer; import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; +import org.springframework.security.oauth2.jwt.TestJwts; import org.springframework.security.rsocket.core.PayloadSocketAcceptorInterceptor; import org.springframework.security.rsocket.core.SecuritySocketAcceptorInterceptor; import org.springframework.security.rsocket.metadata.BasicAuthenticationEncoder; @@ -41,14 +48,6 @@ import org.springframework.security.rsocket.metadata.BearerTokenMetadata; import org.springframework.stereotype.Controller; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; -import reactor.core.publisher.Mono; - -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; @@ -114,13 +113,11 @@ public class JwtITests { } private Jwt jwt() { - Map claims = new HashMap<>(); - claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com"); - claims.put(IdTokenClaimNames.SUB, "rob"); - claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id")); - Instant issuedAt = Instant.now(); - Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); - return new Jwt("token", issuedAt, expiresAt, claims, claims); + return TestJwts.jwt() + .claim(IdTokenClaimNames.ISS, "https://issuer.example.com") + .claim(IdTokenClaimNames.SUB, "rob") + .claim(IdTokenClaimNames.AUD, Arrays.asList("client-id")) + .build(); } private RSocketRequester.Builder requester() { diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index d541baa52a..8b35e92581 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -15,11 +15,20 @@ */ package org.springframework.security.config.annotation.web.configurers.oauth2.client; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.apache.http.HttpHeaders; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; + import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; @@ -79,19 +88,12 @@ import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -937,8 +939,7 @@ public class OAuth2LoginConfigurerTests { claims.put(IdTokenClaimNames.ISS, "http://localhost/iss"); claims.put(IdTokenClaimNames.AUD, Arrays.asList("clientId", "a", "u", "d")); claims.put(IdTokenClaimNames.AZP, "clientId"); - Jwt jwt = new Jwt("token123", Instant.now(), Instant.now().plusSeconds(3600), - Collections.singletonMap("header1", "value1"), claims); + Jwt jwt = jwt().claims(c -> c.putAll(claims)).build(); JwtDecoder jwtDecoder = mock(JwtDecoder.class); when(jwtDecoder.decode(any())).thenReturn(jwt); return jwtDecoder; diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index e55d069e8e..7d45f45bdd 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -83,16 +83,15 @@ import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrinci import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2TokenValidator; import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimNames; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtException; import org.springframework.security.oauth2.jwt.JwtTimestampValidator; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; -import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint; @@ -131,6 +130,7 @@ import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.oauth2.core.TestOAuth2AccessTokens.noScopes; import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSetUri; import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withPublicKey; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -150,9 +150,8 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST; public class OAuth2ResourceServerConfigurerTests { private static final String JWT_TOKEN = "token"; private static final String JWT_SUBJECT = "mock-test-subject"; - private static final Map JWT_HEADERS = Collections.singletonMap("alg", JwsAlgorithms.RS256); private static final Map JWT_CLAIMS = Collections.singletonMap(JwtClaimNames.SUB, JWT_SUBJECT); - private static final Jwt JWT = new Jwt(JWT_TOKEN, Instant.MIN, Instant.MAX, JWT_HEADERS, JWT_CLAIMS); + private static final Jwt JWT = jwt().build(); private static final String JWK_SET_URI = "https://mock.org"; private static final JwtAuthenticationToken JWT_AUTHENTICATION_TOKEN = new JwtAuthenticationToken(JWT, Collections.emptyList()); diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java index 0a516d1274..083ec3721b 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java @@ -16,7 +16,6 @@ package org.springframework.security.config.web.server; -import java.time.Instant; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -25,15 +24,6 @@ import org.junit.Rule; import org.junit.Test; import org.mockito.stubbing.Answer; import org.openqa.selenium.WebDriver; - -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.core.OAuth2Error; -import org.springframework.security.web.server.WebFilterExchange; -import org.springframework.security.web.server.authentication.RedirectServerAuthenticationFailureHandler; -import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler; -import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler; -import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler; import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; @@ -46,6 +36,7 @@ import org.springframework.security.config.annotation.web.reactive.EnableWebFlux import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; import org.springframework.security.config.test.SpringTestRule; import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextImpl; @@ -56,14 +47,16 @@ import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuth import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; import org.springframework.security.oauth2.client.endpoint.ReactiveOAuth2AccessTokenResponseClient; import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeReactiveAuthenticationManager; -import org.springframework.security.oauth2.client.oidc.web.server.logout.OidcClientInitiatedServerLogoutSuccessHandler; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; +import org.springframework.security.oauth2.client.oidc.web.server.logout.OidcClientInitiatedServerLogoutSuccessHandler; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService; import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.TestOAuth2AccessTokens; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; @@ -84,7 +77,12 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoderFactory; import org.springframework.security.test.web.reactive.server.WebTestClientBuilder; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.WebFilterChainProxy; +import org.springframework.security.web.server.WebFilterExchange; +import org.springframework.security.web.server.authentication.RedirectServerAuthenticationFailureHandler; +import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler; import org.springframework.security.web.server.authentication.ServerAuthenticationConverter; +import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler; +import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler; import org.springframework.security.web.server.context.ServerSecurityContextRepository; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; import org.springframework.test.web.reactive.server.WebTestClient; @@ -100,6 +98,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * @author Rob Winch @@ -514,8 +513,7 @@ public class OAuth2LoginTests { claims.put(IdTokenClaimNames.ISS, "http://localhost/issuer"); claims.put(IdTokenClaimNames.AUD, Collections.singletonList("client")); claims.put(IdTokenClaimNames.AZP, "client"); - Jwt jwt = new Jwt("id-token", Instant.now(), Instant.now().plusSeconds(3600), - Collections.singletonMap("header1", "value1"), claims); + Jwt jwt = jwt().claims(c -> c.putAll(claims)).build(); return Mono.just(jwt); }; } diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java index 75918cc97f..3f0d5483ed 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java @@ -23,9 +23,7 @@ import java.security.NoSuchAlgorithmException; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPublicKeySpec; -import java.time.Instant; import java.util.Base64; -import java.util.Collections; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -61,7 +59,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; @@ -88,6 +85,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * Tests for {@link org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2ResourceServerSpec} @@ -114,9 +112,7 @@ public class OAuth2ResourceServerSpecTests { " ]\n" + "}\n"; - private Jwt jwt = new Jwt("token", Instant.MIN, Instant.MAX, - Collections.singletonMap("alg", JwsAlgorithms.RS256), - Collections.singletonMap("sub", "user")); + private Jwt jwt = jwt().build(); private String clientId = "client"; private String clientSecret = "secret"; diff --git a/oauth2/oauth2-client/spring-security-oauth2-client.gradle b/oauth2/oauth2-client/spring-security-oauth2-client.gradle index 624125ee28..e73446c28f 100644 --- a/oauth2/oauth2-client/spring-security-oauth2-client.gradle +++ b/oauth2/oauth2-client/spring-security-oauth2-client.gradle @@ -12,6 +12,7 @@ dependencies { optional 'org.springframework:spring-webflux' testCompile project(path: ':spring-security-oauth2-core', configuration: 'tests') + testCompile project(path: ':spring-security-oauth2-jose', configuration: 'tests') testCompile powerMock2Dependencies testCompile 'com.squareup.okhttp3:mockwebserver' testCompile 'com.fasterxml.jackson.core:jackson-databind' diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java index 77dba3d87a..85169e809e 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java @@ -15,12 +15,22 @@ */ package org.springframework.security.oauth2.client.oidc.authentication; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.ArgumentCaptor; import org.mockito.stubbing.Answer; + import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; @@ -44,24 +54,18 @@ import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtException; -import java.time.Instant; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.ArgumentMatchers.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.springframework.security.oauth2.client.registration.TestClientRegistrations.clientRegistration; import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests.request; import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses.error; import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses.success; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * Tests for {@link OidcAuthorizationCodeAuthenticationProvider}. @@ -299,16 +303,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests { } private void setUpIdToken(Map claims) { - Instant issuedAt = Instant.now(); - Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); - this.setUpIdToken(claims, issuedAt, expiresAt); - } - - private void setUpIdToken(Map claims, Instant issuedAt, Instant expiresAt) { - Map headers = new HashMap<>(); - headers.put("alg", "RS256"); - - Jwt idToken = new Jwt("id-token", issuedAt, expiresAt, headers, claims); + Jwt idToken = jwt().claims(c -> c.putAll(claims)).build(); JwtDecoder jwtDecoder = mock(JwtDecoder.class); when(jwtDecoder.decode(anyString())).thenReturn(idToken); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManagerTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManagerTests.java index 937babdea2..cbeb598a1f 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManagerTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManagerTests.java @@ -16,12 +16,20 @@ package org.springframework.security.oauth2.client.oidc.authentication; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import reactor.core.publisher.Mono; + import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken; @@ -46,17 +54,13 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtException; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; -import reactor.core.publisher.Mono; -import java.time.Instant; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * @author Rob Winch @@ -171,9 +175,7 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests { claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com"); claims.put(IdTokenClaimNames.SUB, "rob"); claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id")); - Instant issuedAt = Instant.now(); - Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); - Jwt idToken = new Jwt("id-token", issuedAt, expiresAt, claims, claims); + Jwt idToken = jwt().claims(c -> c.putAll(claims)).build(); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); when(this.userService.loadUser(any())).thenReturn(Mono.empty()); @@ -193,9 +195,7 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests { claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com"); claims.put(IdTokenClaimNames.SUB, "rob"); claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id")); - Instant issuedAt = Instant.now(); - Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); - Jwt idToken = new Jwt("id-token", issuedAt, expiresAt, claims, claims); + Jwt idToken = jwt().claims(c -> c.putAll(claims)).build(); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); DefaultOidcUser user = new DefaultOidcUser(AuthorityUtils.createAuthorityList("ROLE_USER"), this.idToken); @@ -222,9 +222,7 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests { claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com"); claims.put(IdTokenClaimNames.SUB, "rob"); claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id")); - Instant issuedAt = Instant.now(); - Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); - Jwt idToken = new Jwt("id-token", issuedAt, expiresAt, claims, claims); + Jwt idToken = jwt().claims(c -> c.putAll(claims)).build(); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); DefaultOidcUser user = new DefaultOidcUser(AuthorityUtils.createAuthorityList("ROLE_USER"), this.idToken); @@ -257,9 +255,7 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests { claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com"); claims.put(IdTokenClaimNames.SUB, "rob"); claims.put(IdTokenClaimNames.AUD, Arrays.asList(clientRegistration.getClientId())); - Instant issuedAt = Instant.now(); - Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); - Jwt idToken = new Jwt("id-token", issuedAt, expiresAt, claims, claims); + Jwt idToken = jwt().claims(c -> c.putAll(claims)).build(); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); DefaultOidcUser user = new DefaultOidcUser(AuthorityUtils.createAuthorityList("ROLE_USER"), this.idToken); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidatorTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidatorTests.java index bad2f80969..6152ab7afa 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidatorTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidatorTests.java @@ -15,15 +15,6 @@ */ package org.springframework.security.oauth2.client.oidc.authentication; -import org.junit.Before; -import org.junit.Test; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.TestClientRegistrations; -import org.springframework.security.oauth2.core.OAuth2Error; -import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; -import org.springframework.security.oauth2.jwt.Jwt; - import java.time.Duration; import java.time.Instant; import java.util.Arrays; @@ -32,6 +23,16 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.TestClientRegistrations; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; +import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; +import org.springframework.security.oauth2.jwt.Jwt; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -240,7 +241,12 @@ public class OidcIdTokenValidatorTests { } private Collection validateIdToken() { - Jwt idToken = new Jwt("token123", this.issuedAt, this.expiresAt, this.headers, this.claims); + Jwt idToken = Jwt.withTokenValue("token") + .issuedAt(this.issuedAt) + .expiresAt(this.expiresAt) + .headers(h -> h.putAll(this.headers)) + .claims(c -> c.putAll(this.claims)) + .build(); OidcIdTokenValidator validator = new OidcIdTokenValidator(this.registration.build()); validator.setClockSkew(this.clockSkew); return validator.validate(idToken).getErrors(); diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/Jwt.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/Jwt.java index ab35ed8d65..e5e09f0117 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/Jwt.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/Jwt.java @@ -62,6 +62,7 @@ public class Jwt extends AbstractOAuth2Token implements JwtClaimAccessor { * @param expiresAt the expiration time on or after which the JWT MUST NOT be accepted * @param headers the JOSE header(s) * @param claims the JWT Claims Set + * */ public Jwt(String tokenValue, Instant issuedAt, Instant expiresAt, Map headers, Map claims) { diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java index acfb590d32..8478a58bf6 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java @@ -21,7 +21,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.security.interfaces.RSAPublicKey; import java.text.ParseException; -import java.time.Instant; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -136,8 +135,6 @@ public final class NimbusJwtDecoder implements JwtDecoder { } private Jwt createJwt(String token, JWT parsedJwt) { - Jwt jwt; - try { // Verify the signature JWTClaimsSet jwtClaimsSet = this.jwtProcessor.process(parsedJwt, null); @@ -145,9 +142,10 @@ public final class NimbusJwtDecoder implements JwtDecoder { Map headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject()); Map claims = this.claimSetConverter.convert(jwtClaimsSet.getClaims()); - Instant expiresAt = (Instant) claims.get(JwtClaimNames.EXP); - Instant issuedAt = (Instant) claims.get(JwtClaimNames.IAT); - jwt = new Jwt(token, issuedAt, expiresAt, headers, claims); + return Jwt.withTokenValue(token) + .headers(h -> h.putAll(headers)) + .claims(c -> c.putAll(claims)) + .build(); } catch (RemoteKeySourceException ex) { if (ex.getCause() instanceof ParseException) { throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, "Malformed Jwk set")); @@ -161,8 +159,6 @@ public final class NimbusJwtDecoder implements JwtDecoder { throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex); } } - - return jwt; } private Jwt validateJwt(Jwt jwt){ diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java index fa5e4062a9..1779d49f50 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java @@ -16,7 +16,6 @@ package org.springframework.security.oauth2.jwt; import java.security.interfaces.RSAPublicKey; -import java.time.Instant; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -165,9 +164,10 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder { Map headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject()); Map claims = this.claimSetConverter.convert(jwtClaimsSet.getClaims()); - Instant expiresAt = (Instant) claims.get(JwtClaimNames.EXP); - Instant issuedAt = (Instant) claims.get(JwtClaimNames.IAT); - return new Jwt(parsedJwt.getParsedString(), issuedAt, expiresAt, headers, claims); + return Jwt.withTokenValue(parsedJwt.getParsedString()) + .headers(h -> h.putAll(headers)) + .claims(c -> c.putAll(claims)) + .build(); } private Jwt validateJwt(Jwt jwt) { diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtIssuerValidatorTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtIssuerValidatorTests.java index 85f3ad30e5..ba0a42c0ca 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtIssuerValidatorTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtIssuerValidatorTests.java @@ -15,41 +15,26 @@ */ package org.springframework.security.oauth2.jwt; -import java.time.Instant; -import java.util.Collections; -import java.util.Map; - import org.junit.Test; import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * @author Josh Cummings * @since 5.1 */ public class JwtIssuerValidatorTests { - private static final String MOCK_TOKEN = "token"; - private static final Instant MOCK_ISSUED_AT = Instant.MIN; - private static final Instant MOCK_EXPIRES_AT = Instant.MAX; - private static final Map MOCK_HEADERS = - Collections.singletonMap("alg", JwsAlgorithms.RS256); - private static final String ISSUER = "https://issuer"; private final JwtIssuerValidator validator = new JwtIssuerValidator(ISSUER); @Test public void validateWhenIssuerMatchesThenReturnsSuccess() { - Jwt jwt = new Jwt( - MOCK_TOKEN, - MOCK_ISSUED_AT, - MOCK_EXPIRES_AT, - MOCK_HEADERS, - Collections.singletonMap("iss", ISSUER)); + Jwt jwt = jwt().claim("iss", ISSUER).build(); assertThat(this.validator.validate(jwt)) .isEqualTo(OAuth2TokenValidatorResult.success()); @@ -57,12 +42,7 @@ public class JwtIssuerValidatorTests { @Test public void validateWhenIssuerMismatchesThenReturnsError() { - Jwt jwt = new Jwt( - MOCK_TOKEN, - MOCK_ISSUED_AT, - MOCK_EXPIRES_AT, - MOCK_HEADERS, - Collections.singletonMap(JwtClaimNames.ISS, "https://other")); + Jwt jwt = jwt().claim(JwtClaimNames.ISS, "https://other").build(); OAuth2TokenValidatorResult result = this.validator.validate(jwt); @@ -71,12 +51,7 @@ public class JwtIssuerValidatorTests { @Test public void validateWhenJwtHasNoIssuerThenReturnsError() { - Jwt jwt = new Jwt( - MOCK_TOKEN, - MOCK_ISSUED_AT, - MOCK_EXPIRES_AT, - MOCK_HEADERS, - Collections.singletonMap(JwtClaimNames.AUD, "https://aud")); + Jwt jwt = jwt().claim(JwtClaimNames.AUD, "https://aud").build(); OAuth2TokenValidatorResult result = this.validator.validate(jwt); assertThat(result.getErrors()).isNotEmpty(); @@ -85,12 +60,7 @@ public class JwtIssuerValidatorTests { // gh-6073 @Test public void validateWhenIssuerMatchesAndIsNotAUriThenReturnsSuccess() { - Jwt jwt = new Jwt( - MOCK_TOKEN, - MOCK_ISSUED_AT, - MOCK_EXPIRES_AT, - MOCK_HEADERS, - Collections.singletonMap(JwtClaimNames.ISS, "issuer")); + Jwt jwt = jwt().claim(JwtClaimNames.ISS, "issuer").build(); JwtIssuerValidator validator = new JwtIssuerValidator("issuer"); assertThat(validator.validate(jwt)) diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java index 2101d22eca..ee2f85825f 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java @@ -29,12 +29,11 @@ import org.junit.Test; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.jwt.JwtClaimNames; -import org.springframework.security.oauth2.jwt.JwtTimestampValidator; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; +import static org.springframework.security.oauth2.jwt.JwtClaimNames.EXP; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * Tests verifying {@link JwtTimestampValidator} @@ -52,12 +51,7 @@ public class JwtTimestampValidatorTests { public void validateWhenJwtIsExpiredThenErrorMessageIndicatesExpirationTime() { Instant oneHourAgo = Instant.now().minusSeconds(3600); - Jwt jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - oneHourAgo, - MOCK_HEADER, - MOCK_CLAIM_SET); + Jwt jwt = jwt().expiresAt(oneHourAgo).build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); @@ -71,12 +65,7 @@ public class JwtTimestampValidatorTests { public void validateWhenJwtIsTooEarlyThenErrorMessageIndicatesNotBeforeTime() { Instant oneHourFromNow = Instant.now().plusSeconds(3600); - Jwt jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - null, - MOCK_HEADER, - Collections.singletonMap(JwtClaimNames.NBF, oneHourFromNow)); + Jwt jwt = jwt().notBefore(oneHourFromNow).build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); @@ -97,21 +86,14 @@ public class JwtTimestampValidatorTests { Instant justOverOneDayAgo = now.minus(oneDayOff).minusSeconds(10); Instant justOverOneDayFromNow = now.plus(oneDayOff).plusSeconds(10); - Jwt jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - almostOneDayAgo, - MOCK_HEADER, - Collections.singletonMap(JwtClaimNames.NBF, almostOneDayFromNow)); + Jwt jwt = jwt() + .expiresAt(almostOneDayAgo) + .notBefore(almostOneDayFromNow) + .build(); assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); - jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - justOverOneDayAgo, - MOCK_HEADER, - MOCK_CLAIM_SET); + jwt = jwt().expiresAt(justOverOneDayAgo).build(); OAuth2TokenValidatorResult result = jwtValidator.validate(jwt); Collection messages = @@ -120,12 +102,7 @@ public class JwtTimestampValidatorTests { assertThat(result.hasErrors()).isTrue(); assertThat(messages).contains("Jwt expired at " + justOverOneDayAgo); - jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - null, - MOCK_HEADER, - Collections.singletonMap(JwtClaimNames.NBF, justOverOneDayFromNow)); + jwt = jwt().notBefore(justOverOneDayFromNow).build(); result = jwtValidator.validate(jwt); messages = @@ -138,36 +115,21 @@ public class JwtTimestampValidatorTests { @Test public void validateWhenConfiguredWithFixedClockThenValidatesUsingFixedTime() { - Jwt jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - Instant.now(MOCK_NOW), - MOCK_HEADER, - Collections.singletonMap("some", "claim")); + Jwt jwt = jwt().expiresAt(Instant.now(MOCK_NOW)).build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(Duration.ofNanos(0)); jwtValidator.setClock(MOCK_NOW); assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); - jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - null, - MOCK_HEADER, - Collections.singletonMap(JwtClaimNames.NBF, Instant.now(MOCK_NOW))); + jwt = jwt().notBefore(Instant.now(MOCK_NOW)).build(); assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); } @Test public void validateWhenNeitherExpiryNorNotBeforeIsSpecifiedThenReturnsSuccessfulResult() { - Jwt jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - null, - MOCK_HEADER, - MOCK_CLAIM_SET); + Jwt jwt = jwt().claims(c -> c.remove(EXP)).build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); @@ -175,12 +137,10 @@ public class JwtTimestampValidatorTests { @Test public void validateWhenNotBeforeIsValidAndExpiryIsNotSpecifiedThenReturnsSuccessfulResult() { - Jwt jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - null, - MOCK_HEADER, - Collections.singletonMap(JwtClaimNames.NBF, Instant.MIN)); + Jwt jwt = jwt() + .claims(c -> c.remove(EXP)) + .notBefore(Instant.MIN) + .build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); @@ -188,12 +148,7 @@ public class JwtTimestampValidatorTests { @Test public void validateWhenExpiryIsValidAndNotBeforeIsNotSpecifiedThenReturnsSuccessfulResult() { - Jwt jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - Instant.MAX, - MOCK_HEADER, - MOCK_CLAIM_SET); + Jwt jwt = jwt().build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); @@ -201,12 +156,10 @@ public class JwtTimestampValidatorTests { @Test public void validateWhenBothExpiryAndNotBeforeAreValidThenReturnsSuccessfulResult() { - Jwt jwt = new Jwt( - MOCK_TOKEN_VALUE, - MOCK_ISSUED_AT, - Instant.now(MOCK_NOW), - MOCK_HEADER, - Collections.singletonMap(JwtClaimNames.NBF, Instant.now(MOCK_NOW))); + Jwt jwt = jwt() + .expiresAt(Instant.now(MOCK_NOW)) + .notBefore(Instant.now(MOCK_NOW)) + .build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(Duration.ofNanos(0)); jwtValidator.setClock(MOCK_NOW); diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/TestJwts.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/TestJwts.java new file mode 100644 index 0000000000..b253a79616 --- /dev/null +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/TestJwts.java @@ -0,0 +1,40 @@ +/* + * 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.oauth2.jwt; + +import java.time.Instant; +import java.util.Arrays; + +public class TestJwts { + public static Jwt.Builder jwt() { + return Jwt.withTokenValue("token") + .header("alg", "none") + .audience(Arrays.asList("https://audience.example.org")) + .expiresAt(Instant.MAX) + .issuedAt(Instant.MIN) + .issuer("https://issuer.example.org") + .jti("jti") + .notBefore(Instant.MIN) + .subject("mock-test-subject"); + } + + public static Jwt user() { + return jwt() + .claim("sub", "mock-test-subject") + .build(); + } +} diff --git a/oauth2/oauth2-resource-server/spring-security-oauth2-resource-server.gradle b/oauth2/oauth2-resource-server/spring-security-oauth2-resource-server.gradle index 10159c9a8d..3cfcaebefc 100644 --- a/oauth2/oauth2-resource-server/spring-security-oauth2-resource-server.gradle +++ b/oauth2/oauth2-resource-server/spring-security-oauth2-resource-server.gradle @@ -13,6 +13,7 @@ dependencies { provided 'javax.servlet:javax.servlet-api' + testCompile project(path: ':spring-security-oauth2-jose', configuration: 'tests') testCompile 'com.squareup.okhttp3:mockwebserver' testCompile 'com.fasterxml.jackson.core:jackson-databind' testCompile 'io.projectreactor.netty:reactor-netty' diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverterTests.java index 7f72e8d21a..62fbd20ed3 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverterTests.java @@ -16,15 +16,8 @@ package org.springframework.security.oauth2.server.resource.authentication; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -import java.time.Instant; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import org.junit.Test; @@ -32,9 +25,12 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jwt.Jwt; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; + /** * Tests for {@link JwtAuthenticationConverter} * @@ -45,7 +41,7 @@ public class JwtAuthenticationConverterTests { @Test public void convertWhenDefaultGrantedAuthoritiesConverterSet() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write")); + Jwt jwt = jwt().claim("scope", "message:read message:write").build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt); Collection authorities = authentication.getAuthorities(); @@ -64,7 +60,7 @@ public class JwtAuthenticationConverterTests { @Test public void convertWithOverriddenGrantedAuthoritiesConverter() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write")); + Jwt jwt = jwt().claim("scope", "message:read message:write").build(); Converter> grantedAuthoritiesConverter = token -> Arrays.asList(new SimpleGrantedAuthority("blah")); @@ -77,11 +73,4 @@ public class JwtAuthenticationConverterTests { assertThat(authorities).containsExactly( new SimpleGrantedAuthority("blah")); } - - private Jwt jwt(Map claims) { - Map headers = new HashMap<>(); - headers.put("alg", JwsAlgorithms.RS256); - - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims); - } } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java index 15a25a66e7..381c5bb38e 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java @@ -15,10 +15,6 @@ */ package org.springframework.security.oauth2.server.resource.authentication; -import java.time.Instant; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.function.Predicate; import org.junit.Before; @@ -29,7 +25,6 @@ import org.mockito.junit.MockitoJUnitRunner; import org.springframework.core.convert.converter.Converter; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtException; @@ -40,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * Tests for {@link JwtAuthenticationProvider} @@ -67,9 +63,7 @@ public class JwtAuthenticationProviderTests { public void authenticateWhenJwtDecodesThenAuthenticationHasAttributesContainedInJwt() { BearerTokenAuthenticationToken token = this.authentication(); - Map claims = new HashMap<>(); - claims.put("name", "value"); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt().claim("name", "value").build(); when(this.jwtDecoder.decode("token")).thenReturn(jwt); when(this.jwtAuthenticationConverter.convert(jwt)).thenReturn(new JwtAuthenticationToken(jwt)); @@ -77,7 +71,7 @@ public class JwtAuthenticationProviderTests { JwtAuthenticationToken authentication = (JwtAuthenticationToken) this.provider.authenticate(token); - assertThat(authentication.getTokenAttributes()).isEqualTo(claims); + assertThat(authentication.getTokenAttributes()).containsEntry("name", "value"); } @Test @@ -110,7 +104,7 @@ public class JwtAuthenticationProviderTests { Object details = mock(Object.class); token.setDetails(details); - Jwt jwt = this.jwt(Collections.singletonMap("some", "value")); + Jwt jwt = jwt().build(); JwtAuthenticationToken authentication = new JwtAuthenticationToken(jwt); when(this.jwtDecoder.decode(token.getToken())).thenReturn(jwt); @@ -130,13 +124,6 @@ public class JwtAuthenticationProviderTests { return new BearerTokenAuthenticationToken("token"); } - private Jwt jwt(Map claims) { - Map headers = new HashMap<>(); - headers.put("alg", JwsAlgorithms.RS256); - - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims); - } - private Predicate errorCode(String errorCode) { return failed -> ((OAuth2AuthenticationException) failed).getError().getErrorCode() == errorCode; diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java index 8c4333d906..d8c6d91177 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java @@ -16,23 +16,19 @@ package org.springframework.security.oauth2.server.resource.authentication; -import static org.assertj.core.api.Assertions.assertThat; - -import java.time.Instant; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import org.assertj.core.util.Maps; import org.junit.Test; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jwt.Jwt; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; + /** * Tests for {@link JwtGrantedAuthoritiesConverter} * @@ -43,7 +39,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasScopeAttributeThenTranslatedToAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write")); + Jwt jwt = jwt().claim("scope", "message:read message:write").build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -55,7 +51,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWithCustomAuthorityPrefixWhenTokenHasScopeAttributeThenTranslatedToAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write")); + Jwt jwt = jwt().claim("scope", "message:read message:write").build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_"); @@ -68,7 +64,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasEmptyScopeAttributeThenTranslatedToNoAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "")); + Jwt jwt = jwt().claim("scope", "").build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -78,7 +74,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasScpAttributeThenTranslatedToAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scp", Arrays.asList("message:read", "message:write"))); + Jwt jwt = jwt().claim("scp", Arrays.asList("message:read", "message:write")).build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -90,7 +86,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWithCustomAuthorityPrefixWhenTokenHasScpAttributeThenTranslatedToAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scp", Arrays.asList("message:read", "message:write"))); + Jwt jwt = jwt().claim("scp", Arrays.asList("message:read", "message:write")).build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_"); @@ -103,7 +99,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasEmptyScpAttributeThenTranslatedToNoAuthorities() { - Jwt jwt = this.jwt(Maps.newHashMap("scp", Collections.emptyList())); + Jwt jwt = jwt().claim("scp", Collections.emptyList()).build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -113,10 +109,10 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasBothScopeAndScpThenScopeAttributeIsTranslatedToAuthorities() { - Map claims = new HashMap<>(); - claims.put("scp", Arrays.asList("message:read", "message:write")); - claims.put("scope", "missive:read missive:write"); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt() + .claim("scp", Arrays.asList("message:read", "message:write")) + .claim("scope", "missive:read missive:write") + .build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -128,10 +124,10 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasEmptyScopeAndNonEmptyScpThenScopeAttributeIsTranslatedToNoAuthorities() { - Map claims = new HashMap<>(); - claims.put("scp", Arrays.asList("message:read", "message:write")); - claims.put("scope", ""); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt() + .claim("scp", Arrays.asList("message:read", "message:write")) + .claim("scope", "") + .build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -141,10 +137,10 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasEmptyScopeAndEmptyScpAttributeThenTranslatesToNoAuthorities() { - Map claims = new HashMap<>(); - claims.put("scp", Collections.emptyList()); - claims.put("scope", Collections.emptyList()); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt() + .claim("scp", Collections.emptyList()) + .claim("scope", Collections.emptyList()) + .build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -154,9 +150,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasNoScopeAndNoScpAttributeThenTranslatesToNoAuthorities() { - Map claims = new HashMap<>(); - claims.put("roles", Arrays.asList("message:read", "message:write")); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt().claim("roles", Arrays.asList("message:read", "message:write")).build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -166,9 +160,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasUnsupportedTypeForScopeThenTranslatesToNoAuthorities() { - Map claims = new HashMap<>(); - claims.put("scope", new String[] {"message:read", "message:write"}); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt().claim("scope", new String[] {"message:read", "message:write"}).build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt); @@ -178,10 +170,10 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToAuthorities() { - Map claims = new HashMap<>(); - claims.put("roles", Arrays.asList("message:read", "message:write")); - claims.put("scope", "missive:read missive:write"); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt() + .claim("roles", Arrays.asList("message:read", "message:write")) + .claim("scope", "missive:read missive:write") + .build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles"); @@ -194,10 +186,10 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasEmptyCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToNoAuthorities() { - Map claims = new HashMap<>(); - claims.put("roles", Collections.emptyList()); - claims.put("scope", "missive:read missive:write"); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt() + .claim("roles", Collections.emptyList()) + .claim("scope", "missive:read missive:write") + .build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles"); @@ -208,9 +200,7 @@ public class JwtGrantedAuthoritiesConverterTests { @Test public void convertWhenTokenHasNoCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToNoAuthorities() { - Map claims = new HashMap<>(); - claims.put("scope", "missive:read missive:write"); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt().claim("scope", "missive:read missive:write").build(); JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles"); @@ -218,11 +208,4 @@ public class JwtGrantedAuthoritiesConverterTests { assertThat(authorities).isEmpty(); } - - private Jwt jwt(Map claims) { - Map headers = new HashMap<>(); - headers.put("alg", JwsAlgorithms.RS256); - - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims); - } } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java index fff71f4b13..2e52bd69cb 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java @@ -21,6 +21,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import reactor.core.publisher.Mono; + import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -29,16 +31,12 @@ import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtException; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; -import reactor.core.publisher.Mono; - -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * @author Rob Winch @@ -56,12 +54,7 @@ public class JwtReactiveAuthenticationManagerTests { @Before public void setup() { this.manager = new JwtReactiveAuthenticationManager(this.jwtDecoder); - - Map claims = new HashMap<>(); - claims.put("scope", "message:read message:write"); - Instant issuedAt = Instant.now(); - Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); - this.jwt = new Jwt("jwt", issuedAt, expiresAt, claims, claims); + this.jwt = jwt().claim("scope", "message:read message:write").build(); } @Test diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterAdapterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterAdapterTests.java index 6eeaba6257..6e076f0677 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterAdapterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterAdapterTests.java @@ -16,12 +16,8 @@ package org.springframework.security.oauth2.server.resource.authentication; -import java.time.Instant; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import org.junit.Test; @@ -29,10 +25,10 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jwt.Jwt; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; /** * Tests for {@link ReactiveJwtAuthenticationConverterAdapter} @@ -46,7 +42,7 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { @Test public void convertWhenTokenHasScopeAttributeThenTranslatedToAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write")); + Jwt jwt = jwt().claim("scope", "message:read message:write").build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); Collection authorities = authentication.getAuthorities(); @@ -58,7 +54,7 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { @Test public void convertWhenTokenHasEmptyScopeAttributeThenTranslatedToNoAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "")); + Jwt jwt = jwt().claim("scope", "").build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); @@ -69,7 +65,7 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { @Test public void convertWhenTokenHasScpAttributeThenTranslatedToAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scp", Arrays.asList("message:read", "message:write"))); + Jwt jwt = jwt().claim("scp", Arrays.asList("message:read", "message:write")).build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); @@ -82,7 +78,7 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { @Test public void convertWhenTokenHasEmptyScpAttributeThenTranslatedToNoAuthorities() { - Jwt jwt = this.jwt(Collections.singletonMap("scp", Arrays.asList())); + Jwt jwt = jwt().claim("scp", Arrays.asList()).build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); @@ -93,10 +89,10 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { @Test public void convertWhenTokenHasBothScopeAndScpThenScopeAttributeIsTranslatedToAuthorities() { - Map claims = new HashMap<>(); - claims.put("scp", Arrays.asList("message:read", "message:write")); - claims.put("scope", "missive:read missive:write"); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt() + .claim("scp", Arrays.asList("message:read", "message:write")) + .claim("scope", "missive:read missive:write") + .build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); @@ -109,10 +105,10 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { @Test public void convertWhenTokenHasEmptyScopeAndNonEmptyScpThenScopeAttributeIsTranslatedToNoAuthorities() { - Map claims = new HashMap<>(); - claims.put("scp", Arrays.asList("message:read", "message:write")); - claims.put("scope", ""); - Jwt jwt = this.jwt(claims); + Jwt jwt = jwt() + .claim("scp", Arrays.asList("message:read", "message:write")) + .claim("scope", "") + .build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); @@ -120,11 +116,4 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { assertThat(authorities).containsExactly(); } - - private Jwt jwt(Map claims) { - Map headers = new HashMap<>(); - headers.put("alg", JwsAlgorithms.RS256); - - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims); - } } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterTests.java index 67bcc56d28..809c76be1d 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterTests.java @@ -16,26 +16,21 @@ package org.springframework.security.oauth2.server.resource.authentication; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -import java.time.Instant; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import org.junit.Test; - import reactor.core.publisher.Flux; import org.springframework.core.convert.converter.Converter; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jwt.Jwt; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; + /** * Tests for {@link ReactiveJwtAuthenticationConverter} * @@ -47,7 +42,7 @@ public class ReactiveJwtAuthenticationConverterTests { @Test public void convertWhenDefaultGrantedAuthoritiesConverterSet() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write")); + Jwt jwt = jwt().claim("scope", "message:read message:write").build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); Collection authorities = authentication.getAuthorities(); @@ -66,7 +61,7 @@ public class ReactiveJwtAuthenticationConverterTests { @Test public void convertWithOverriddenGrantedAuthoritiesConverter() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write")); + Jwt jwt = jwt().claim("scope", "message:read message:write").build(); Converter> grantedAuthoritiesConverter = token -> Flux.just(new SimpleGrantedAuthority("blah")); @@ -79,11 +74,4 @@ public class ReactiveJwtAuthenticationConverterTests { assertThat(authorities).containsExactly( new SimpleGrantedAuthority("blah")); } - - private Jwt jwt(Map claims) { - Map headers = new HashMap<>(); - headers.put("alg", JwsAlgorithms.RS256); - - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims); - } } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtGrantedAuthoritiesConverterAdapterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtGrantedAuthoritiesConverterAdapterTests.java index 378a2ce55a..e7ff494522 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtGrantedAuthoritiesConverterAdapterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtGrantedAuthoritiesConverterAdapterTests.java @@ -16,15 +16,8 @@ package org.springframework.security.oauth2.server.resource.authentication; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -import java.time.Instant; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.stream.Collectors; import org.junit.Test; @@ -32,9 +25,12 @@ import org.junit.Test; 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.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jwt.Jwt; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.springframework.security.oauth2.jwt.TestJwts.jwt; + /** * Tests for {@link ReactiveJwtGrantedAuthoritiesConverterAdapter} * @@ -44,7 +40,7 @@ import org.springframework.security.oauth2.jwt.Jwt; public class ReactiveJwtGrantedAuthoritiesConverterAdapterTests { @Test public void convertWithGrantedAuthoritiesConverter() { - Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write")); + Jwt jwt = jwt().claim("scope", "message:read message:write").build(); Converter> grantedAuthoritiesConverter = token -> Arrays.asList(new SimpleGrantedAuthority("blah")); @@ -65,11 +61,4 @@ public class ReactiveJwtGrantedAuthoritiesConverterAdapterTests { .isThrownBy(() -> new ReactiveJwtGrantedAuthoritiesConverterAdapter(null)) .withMessage("grantedAuthoritiesConverter cannot be null"); } - - private Jwt jwt(Map claims) { - Map headers = new HashMap<>(); - headers.put("alg", JwsAlgorithms.RS256); - - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims); - } } diff --git a/test/src/test/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurersJwtTests.java b/test/src/test/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurersJwtTests.java index 8e763af4cb..70aebf81d1 100644 --- a/test/src/test/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurersJwtTests.java +++ b/test/src/test/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurersJwtTests.java @@ -15,12 +15,8 @@ */ package org.springframework.security.test.web.reactive.server; -import java.time.Instant; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Collections; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,8 +29,8 @@ import org.springframework.http.MediaType; 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.jwt.TestJwts; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.web.reactive.result.method.annotation.CurrentSecurityContextArgumentResolver; import org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter; @@ -145,11 +141,11 @@ public class SecurityMockServerConfigurersJwtTests extends AbstractMockServerCon @Test public void mockJwtWhenProvidingPreparedJwtThenProducesJwtAuthentication() { - 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); - client + Jwt originalToken = TestJwts.jwt() + .header("header1", "value1") + .subject("some_user") + .build(); + this.client .mutateWith(mockJwt(originalToken)) .get() .exchange() @@ -160,7 +156,7 @@ public class SecurityMockServerConfigurersJwtTests extends AbstractMockServerCon JwtAuthenticationToken.class); JwtAuthenticationToken retrievedToken = (JwtAuthenticationToken) context.getAuthentication(); assertThat(retrievedToken.getToken().getSubject()).isEqualTo("some_user"); - assertThat(retrievedToken.getToken().getTokenValue()).isEqualTo("token123"); + assertThat(retrievedToken.getToken().getTokenValue()).isEqualTo("token"); assertThat(retrievedToken.getToken().getHeaders().get("header1")).isEqualTo("value1"); } } 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 97d4a5aee1..fd69f4b02c 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,13 +15,8 @@ */ package org.springframework.security.test.web.servlet.request; -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 java.util.List; import javax.servlet.http.HttpServletResponse; import org.junit.After; @@ -39,8 +34,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.jwt.TestJwts; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.test.context.TestSecurityContextHolder; import org.springframework.security.test.web.support.WebTestUtils; @@ -164,19 +159,18 @@ public class SecurityMockMvcRequestPostProcessorsJwtTests { @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 = TestJwts.jwt() + .header("header1", "value1") + .subject("some_user") + .build(); 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().getTokenValue()).isEqualTo("token"); assertThat(retrievedToken.getToken().getHeaders().get("header1")).isEqualTo("value1"); } }