diff --git a/docs/modules/ROOT/pages/core-model-components.adoc b/docs/modules/ROOT/pages/core-model-components.adoc index 03032ce43..9dbf17b3a 100644 --- a/docs/modules/ROOT/pages/core-model-components.adoc +++ b/docs/modules/ROOT/pages/core-model-components.adoc @@ -392,7 +392,7 @@ The following example shows how to register an `OAuth2TokenGenerator` `@Bean`: @Bean public OAuth2TokenGenerator tokenGenerator() { JwtEncoder jwtEncoder = ... - JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder); + JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder, Clock.systemUTC()); OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator(); OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator(); return new DelegatingOAuth2TokenGenerator( @@ -440,7 +440,7 @@ The following example shows how to implement an `OAuth2TokenCustomizer tokenGenerator() { JwtEncoder jwtEncoder = ... - JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder); + JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder, Clock.systemUTC()); OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator(); accessTokenGenerator.setAccessTokenCustomizer(accessTokenCustomizer()); OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator(); @@ -472,7 +472,7 @@ The following example shows how to implement an `OAuth2TokenCustomizer tokenGenerator() { JwtEncoder jwtEncoder = ... - JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder); + JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder, Clock.systemUTC()); jwtGenerator.setJwtCustomizer(jwtCustomizer()); OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator(); OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator(); diff --git a/docs/src/main/java/sample/extgrant/SecurityConfig.java b/docs/src/main/java/sample/extgrant/SecurityConfig.java index 1044363b6..0e8ae7973 100644 --- a/docs/src/main/java/sample/extgrant/SecurityConfig.java +++ b/docs/src/main/java/sample/extgrant/SecurityConfig.java @@ -15,6 +15,7 @@ */ package sample.extgrant; +import java.time.Clock; import java.util.UUID; import com.nimbusds.jose.jwk.source.JWKSource; @@ -99,7 +100,7 @@ OAuth2AuthorizationService authorizationService() { @Bean OAuth2TokenGenerator tokenGenerator(JWKSource jwkSource) { - JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource)); + JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource), Clock.systemUTC()); OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator(); OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator(); return new DelegatingOAuth2TokenGenerator( diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2ConfigurerUtils.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2ConfigurerUtils.java index dd9bf859b..8a6e4a6f0 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2ConfigurerUtils.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2ConfigurerUtils.java @@ -15,6 +15,7 @@ */ package org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers; +import java.time.Clock; import java.util.Map; import com.nimbusds.jose.jwk.source.JWKSource; @@ -127,7 +128,7 @@ private static JwtGenerator getJwtGenerator(HttpSecurity httpSecurity) { if (jwtGenerator == null) { JwtEncoder jwtEncoder = getJwtEncoder(httpSecurity); if (jwtEncoder != null) { - jwtGenerator = new JwtGenerator(jwtEncoder); + jwtGenerator = new JwtGenerator(jwtEncoder, Clock.systemUTC()); jwtGenerator.setJwtCustomizer(getJwtCustomizer(httpSecurity)); httpSecurity.setSharedObject(JwtGenerator.class, jwtGenerator); } diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java index 249c86e3b..337fe35c5 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java @@ -15,6 +15,7 @@ */ package org.springframework.security.oauth2.server.authorization.token; +import java.time.Clock; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collections; @@ -61,6 +62,7 @@ public final class JwtGenerator implements OAuth2TokenGenerator { private final JwtEncoder jwtEncoder; + private final Clock clock; private OAuth2TokenCustomizer jwtCustomizer; @@ -68,9 +70,11 @@ public final class JwtGenerator implements OAuth2TokenGenerator { * Constructs a {@code JwtGenerator} using the provided parameters. * @param jwtEncoder the jwt encoder */ - public JwtGenerator(JwtEncoder jwtEncoder) { + public JwtGenerator(JwtEncoder jwtEncoder, Clock clock) { Assert.notNull(jwtEncoder, "jwtEncoder cannot be null"); + Assert.notNull(clock, "clock cannot be null"); this.jwtEncoder = jwtEncoder; + this.clock = clock; } @Nullable @@ -94,7 +98,7 @@ public Jwt generate(OAuth2TokenContext context) { } RegisteredClient registeredClient = context.getRegisteredClient(); - Instant issuedAt = Instant.now(); + Instant issuedAt = clock.instant(); Instant expiresAt; JwsAlgorithm jwsAlgorithm = SignatureAlgorithm.RS256; if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) { diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java index ed13047e4..1cec3427b 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java @@ -19,6 +19,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Principal; +import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -132,7 +133,7 @@ public void setUp() { this.authorizationService = mock(OAuth2AuthorizationService.class); this.jwtEncoder = mock(JwtEncoder.class); this.jwtCustomizer = mock(OAuth2TokenCustomizer.class); - JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder); + JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder, Clock.systemUTC()); jwtGenerator.setJwtCustomizer(this.jwtCustomizer); this.accessTokenCustomizer = mock(OAuth2TokenCustomizer.class); OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator(); diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java index 6ad95f50a..17bd90174 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java @@ -15,6 +15,7 @@ */ package org.springframework.security.oauth2.server.authorization.authentication; +import java.time.Clock; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collections; @@ -104,7 +105,7 @@ public void setUp() { this.authorizationService = mock(OAuth2AuthorizationService.class); this.jwtEncoder = mock(JwtEncoder.class); this.jwtCustomizer = mock(OAuth2TokenCustomizer.class); - JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder); + JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder, Clock.systemUTC()); jwtGenerator.setJwtCustomizer(this.jwtCustomizer); this.accessTokenCustomizer = mock(OAuth2TokenCustomizer.class); OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator(); diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java index 32eb57ed7..0039169f6 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java @@ -16,6 +16,7 @@ package org.springframework.security.oauth2.server.authorization.authentication; import java.security.Principal; +import java.time.Clock; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collections; @@ -119,7 +120,7 @@ public void setUp() { this.jwtEncoder = mock(JwtEncoder.class); given(this.jwtEncoder.encode(any())).willReturn(createJwt(Collections.singleton("scope1"))); this.jwtCustomizer = mock(OAuth2TokenCustomizer.class); - JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder); + JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder, Clock.systemUTC()); jwtGenerator.setJwtCustomizer(this.jwtCustomizer); this.accessTokenCustomizer = mock(OAuth2TokenCustomizer.class); OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator(); diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java index 4d8b1d678..52ef8776f 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java @@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets; import java.security.Principal; import java.text.MessageFormat; +import java.time.Clock; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Arrays; @@ -1233,7 +1234,7 @@ JwtEncoder jwtEncoder() { @Bean OAuth2TokenGenerator tokenGenerator() { - JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder()); + JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder(), Clock.systemUTC()); jwtGenerator.setJwtCustomizer(jwtCustomizer()); OAuth2TokenGenerator refreshTokenGenerator = new CustomRefreshTokenGenerator(); return new DelegatingOAuth2TokenGenerator(jwtGenerator, refreshTokenGenerator); @@ -1295,7 +1296,7 @@ JwtEncoder jwtEncoder() { @Bean OAuth2TokenGenerator tokenGenerator() { - JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder()); + JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder(), Clock.systemUTC()); jwtGenerator.setJwtCustomizer(jwtCustomizer()); OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator(); OAuth2TokenGenerator delegatingTokenGenerator = new DelegatingOAuth2TokenGenerator( diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OidcTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OidcTests.java index cd4de9ffe..5c6c235bc 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OidcTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OidcTests.java @@ -20,6 +20,7 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.Principal; +import java.time.Clock; import java.util.Base64; import java.util.HashSet; import java.util.List; @@ -719,7 +720,7 @@ SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) th @Bean OAuth2TokenGenerator tokenGenerator() { - JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource())); + JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource()), Clock.systemUTC()); jwtGenerator.setJwtCustomizer(jwtCustomizer()); OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator(); OAuth2TokenGenerator delegatingTokenGenerator = new DelegatingOAuth2TokenGenerator( @@ -760,7 +761,7 @@ SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) th @Bean OAuth2TokenGenerator tokenGenerator() { - JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource())); + JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource()), Clock.systemUTC()); jwtGenerator.setJwtCustomizer(jwtCustomizer()); OAuth2TokenGenerator refreshTokenGenerator = new CustomRefreshTokenGenerator(); return new DelegatingOAuth2TokenGenerator(jwtGenerator, refreshTokenGenerator); diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java index bb95c02e5..8e364880c 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java @@ -15,6 +15,7 @@ */ package org.springframework.security.oauth2.server.authorization.oidc.authentication; +import java.time.Clock; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -107,7 +108,7 @@ public void setUp() { this.registeredClientRepository = mock(RegisteredClientRepository.class); this.authorizationService = mock(OAuth2AuthorizationService.class); this.jwtEncoder = mock(JwtEncoder.class); - JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder); + JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder, Clock.systemUTC()); this.tokenGenerator = spy(new OAuth2TokenGenerator() { @Override public Jwt generate(OAuth2TokenContext context) { diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java index c457cf7d1..f092021af 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java @@ -16,6 +16,7 @@ package org.springframework.security.oauth2.server.authorization.token; import java.security.Principal; +import java.time.Clock; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Date; @@ -82,7 +83,7 @@ public class JwtGeneratorTests { public void setUp() { this.jwtEncoder = mock(JwtEncoder.class); this.jwtCustomizer = mock(OAuth2TokenCustomizer.class); - this.jwtGenerator = new JwtGenerator(this.jwtEncoder); + this.jwtGenerator = new JwtGenerator(this.jwtEncoder, Clock.systemUTC()); this.jwtGenerator.setJwtCustomizer(this.jwtCustomizer); AuthorizationServerSettings authorizationServerSettings = AuthorizationServerSettings.builder() .issuer("https://provider.com") @@ -92,10 +93,16 @@ public void setUp() { @Test public void constructorWhenJwtEncoderNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> new JwtGenerator(null)).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> new JwtGenerator(null, Clock.systemUTC())).isInstanceOf(IllegalArgumentException.class) .hasMessage("jwtEncoder cannot be null"); } + @Test + public void constructorWhenClockNullThenThrowIllegalArgumentException() { + assertThatThrownBy(() -> new JwtGenerator(this.jwtEncoder, null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage("clock cannot be null"); + } + @Test public void setJwtCustomizerWhenNullThenThrowIllegalArgumentException() { assertThatThrownBy(() -> this.jwtGenerator.setJwtCustomizer(null)).isInstanceOf(IllegalArgumentException.class)