Invalidate tokens previously issued when code is reused
Closes gh-1152
This commit is contained in:
@@ -17,6 +17,7 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
@@ -55,6 +56,25 @@ final class OAuth2AuthenticationProviderUtils {
|
||||
(metadata) ->
|
||||
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
|
||||
|
||||
if (OAuth2AuthorizationCode.class.isAssignableFrom(token.getClass())) {
|
||||
OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getAccessToken();
|
||||
if (accessToken != null && !accessToken.isInvalidated()) {
|
||||
authorizationBuilder.token(
|
||||
accessToken.getToken(),
|
||||
(metadata) ->
|
||||
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
|
||||
}
|
||||
|
||||
OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken = authorization.getRefreshToken();
|
||||
if (refreshToken != null && !refreshToken.isInvalidated()) {
|
||||
authorizationBuilder.token(
|
||||
refreshToken.getToken(),
|
||||
(metadata) ->
|
||||
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (OAuth2RefreshToken.class.isAssignableFrom(token.getClass())) {
|
||||
authorizationBuilder.token(
|
||||
authorization.getAccessToken().getToken(),
|
||||
|
||||
@@ -149,6 +149,13 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
|
||||
}
|
||||
|
||||
if (!authorizationCode.isActive()) {
|
||||
if (authorizationCode.isInvalidated()) {
|
||||
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, authorizationCode.getToken());
|
||||
this.authorizationService.save(authorization);
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn(LogMessage.format("Invalidated authorization tokens previously issued based on the authorization code"));
|
||||
}
|
||||
}
|
||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
|
||||
}
|
||||
|
||||
@@ -169,7 +176,12 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
|
||||
.authorizationGrant(authorizationCodeAuthentication);
|
||||
// @formatter:on
|
||||
|
||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.from(authorization);
|
||||
// @formatter:off
|
||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.from(authorization)
|
||||
// Invalidate the authorization code as it can only be used once
|
||||
.token(authorizationCode.getToken(), metadata ->
|
||||
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
|
||||
// @formatter:on
|
||||
|
||||
// ----- Access token -----
|
||||
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
|
||||
@@ -250,9 +262,6 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
|
||||
|
||||
authorization = authorizationBuilder.build();
|
||||
|
||||
// Invalidate the authorization code as it can only be used once
|
||||
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, authorizationCode.getToken());
|
||||
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
@@ -305,5 +314,4 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
|
||||
}
|
||||
return sessionInformation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -271,6 +271,12 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
verify(this.authorizationService).save(authorizationCaptor.capture());
|
||||
OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue();
|
||||
assertThat(updatedAuthorization.getAccessToken().isInvalidated()).isTrue();
|
||||
assertThat(updatedAuthorization.getRefreshToken().isInvalidated()).isTrue();
|
||||
}
|
||||
|
||||
// gh-290
|
||||
|
||||
Reference in New Issue
Block a user