Add configuration for authorization code time-to-live

Closes gh-642
This commit is contained in:
Gyeongwon, Do
2022-06-19 21:21:28 +09:00
committed by Joe Grandja
parent 3f5e7c793b
commit 303043ea78
4 changed files with 61 additions and 4 deletions

View File

@@ -17,7 +17,6 @@ package org.springframework.security.oauth2.server.authorization.authentication;
import java.security.Principal;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
@@ -565,8 +564,10 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
!OAuth2ParameterNames.CODE.equals(context.getTokenType().getValue())) {
return null;
}
RegisteredClient registeredClient = context.getRegisteredClient();
Instant issuedAt = Instant.now();
Instant expiresAt = issuedAt.plus(5, ChronoUnit.MINUTES); // TODO Allow configuration for authorization code time-to-live
Instant expiresAt = issuedAt.plus(registeredClient.getTokenSettings().getAuthorizationCodeTimeToLive());
return new OAuth2AuthorizationCode(this.authorizationCodeGenerator.generateKey(), issuedAt, expiresAt);
}

View File

@@ -128,6 +128,11 @@ public final class ConfigurationSettingNames {
public static final class Token {
private static final String TOKEN_SETTINGS_NAMESPACE = SETTINGS_NAMESPACE.concat("token.");
/**
* Set the time-to-live for an authorization code.
*/
public static final String AUTHORIZATION_CODE_TIME_TO_LIVE = TOKEN_SETTINGS_NAMESPACE.concat("authorization-code-time-to-live");
/**
* Set the time-to-live for an access token.
*/

View File

@@ -37,6 +37,15 @@ public final class TokenSettings extends AbstractSettings {
super(settings);
}
/**
* Returns the time-to-live for an authorization code. The default is 5 minutes.
*
* @return the time-to-live for an authorization code
*/
public Duration getAuthorizationCodeTimeToLive() {
return getSetting(ConfigurationSettingNames.Token.AUTHORIZATION_CODE_TIME_TO_LIVE);
}
/**
* Returns the time-to-live for an access token. The default is 5 minutes.
*
@@ -91,6 +100,7 @@ public final class TokenSettings extends AbstractSettings {
*/
public static Builder builder() {
return new Builder()
.authorizationCodeTimeToLive(Duration.ofMinutes(5))
.accessTokenTimeToLive(Duration.ofMinutes(5))
.accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
.reuseRefreshTokens(true)
@@ -118,6 +128,19 @@ public final class TokenSettings extends AbstractSettings {
private Builder() {
}
/**
* Set the time-to-live for an access token. Must be greater than {@code Duration.ZERO}.
* A maximum authorization code lifetime of 10 minutes is RECOMMENDED
*
* @param authorizationCodeTimeToLive the time-to-live for an authorization code
* @return the {@link Builder} for further configuration
*/
public Builder authorizationCodeTimeToLive(Duration authorizationCodeTimeToLive) {
Assert.notNull(authorizationCodeTimeToLive, "authorizationCodeTimeToLive cannot be null");
Assert.isTrue(authorizationCodeTimeToLive.getSeconds() > 0, "authorizationCodeTimeToLive must be greater than Duration.ZERO");
return setting(ConfigurationSettingNames.Token.AUTHORIZATION_CODE_TIME_TO_LIVE, authorizationCodeTimeToLive);
}
/**
* Set the time-to-live for an access token. Must be greater than {@code Duration.ZERO}.
*

View File

@@ -35,7 +35,8 @@ public class TokenSettingsTests {
@Test
public void buildWhenDefaultThenDefaultsAreSet() {
TokenSettings tokenSettings = TokenSettings.builder().build();
assertThat(tokenSettings.getSettings()).hasSize(5);
assertThat(tokenSettings.getSettings()).hasSize(6);
assertThat(tokenSettings.getAuthorizationCodeTimeToLive()).isEqualTo(Duration.ofMinutes(5));
assertThat(tokenSettings.getAccessTokenTimeToLive()).isEqualTo(Duration.ofMinutes(5));
assertThat(tokenSettings.getAccessTokenFormat()).isEqualTo(OAuth2TokenFormat.SELF_CONTAINED);
assertThat(tokenSettings.isReuseRefreshTokens()).isTrue();
@@ -43,6 +44,33 @@ public class TokenSettingsTests {
assertThat(tokenSettings.getIdTokenSignatureAlgorithm()).isEqualTo(SignatureAlgorithm.RS256);
}
@Test
public void authorizationCodeTimeToLiveWhenProvidedThenSet() {
Duration authorizationCodeTimeToLive = Duration.ofMinutes(10);
TokenSettings tokenSettings = TokenSettings.builder()
.authorizationCodeTimeToLive(authorizationCodeTimeToLive)
.build();
assertThat(tokenSettings.getAuthorizationCodeTimeToLive()).isEqualTo(authorizationCodeTimeToLive);
}
@Test
public void authorizationCodeTimeToLiveWhenNullOrZeroOrNegativeThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> TokenSettings.builder().authorizationCodeTimeToLive(null))
.isInstanceOf(IllegalArgumentException.class)
.extracting(Throwable::getMessage)
.isEqualTo("authorizationCodeTimeToLive cannot be null");
assertThatThrownBy(() -> TokenSettings.builder().authorizationCodeTimeToLive(Duration.ZERO))
.isInstanceOf(IllegalArgumentException.class)
.extracting(Throwable::getMessage)
.isEqualTo("authorizationCodeTimeToLive must be greater than Duration.ZERO");
assertThatThrownBy(() -> TokenSettings.builder().authorizationCodeTimeToLive(Duration.ofSeconds(-10)))
.isInstanceOf(IllegalArgumentException.class)
.extracting(Throwable::getMessage)
.isEqualTo("authorizationCodeTimeToLive must be greater than Duration.ZERO");
}
@Test
public void accessTokenTimeToLiveWhenProvidedThenSet() {
Duration accessTokenTimeToLive = Duration.ofMinutes(10);
@@ -136,7 +164,7 @@ public class TokenSettingsTests {
.setting("name1", "value1")
.settings(settings -> settings.put("name2", "value2"))
.build();
assertThat(tokenSettings.getSettings()).hasSize(7);
assertThat(tokenSettings.getSettings()).hasSize(8);
assertThat(tokenSettings.<String>getSetting("name1")).isEqualTo("value1");
assertThat(tokenSettings.<String>getSetting("name2")).isEqualTo("value2");
}