Skip to content

Commit 5131714

Browse files
neochae1jgrandja
authored andcommitted
Invalidate tokens previously issued when code is reused
Closes gh-1152
1 parent 2ecb776 commit 5131714

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed

Diff for: oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthenticationProviderUtils.java

+20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import org.springframework.security.authentication.AuthenticationProvider;
1919
import org.springframework.security.core.Authentication;
20+
import org.springframework.security.oauth2.core.OAuth2AccessToken;
2021
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
2122
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
2223
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
@@ -55,6 +56,25 @@ static <T extends OAuth2Token> OAuth2Authorization invalidate(
5556
(metadata) ->
5657
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
5758

59+
if (OAuth2AuthorizationCode.class.isAssignableFrom(token.getClass())) {
60+
OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getAccessToken();
61+
if (accessToken != null && !accessToken.isInvalidated()) {
62+
authorizationBuilder.token(
63+
accessToken.getToken(),
64+
(metadata) ->
65+
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
66+
}
67+
68+
OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken = authorization.getRefreshToken();
69+
if (refreshToken != null && !refreshToken.isInvalidated()) {
70+
authorizationBuilder.token(
71+
refreshToken.getToken(),
72+
(metadata) ->
73+
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
74+
}
75+
76+
}
77+
5878
if (OAuth2RefreshToken.class.isAssignableFrom(token.getClass())) {
5979
authorizationBuilder.token(
6080
authorization.getAccessToken().getToken(),

Diff for: oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ public Authentication authenticate(Authentication authentication) throws Authent
149149
}
150150

151151
if (!authorizationCode.isActive()) {
152+
if (authorizationCode.isInvalidated()) {
153+
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, authorizationCode.getToken());
154+
this.authorizationService.save(authorization);
155+
if (this.logger.isWarnEnabled()) {
156+
this.logger.warn(LogMessage.format("Invalidated authorization tokens previously issued based on the authorization code"));
157+
}
158+
}
152159
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
153160
}
154161

@@ -169,7 +176,12 @@ public Authentication authenticate(Authentication authentication) throws Authent
169176
.authorizationGrant(authorizationCodeAuthentication);
170177
// @formatter:on
171178

172-
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.from(authorization);
179+
// @formatter:off
180+
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.from(authorization)
181+
// Invalidate the authorization code as it can only be used once
182+
.token(authorizationCode.getToken(), metadata ->
183+
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
184+
// @formatter:on
173185

174186
// ----- Access token -----
175187
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
@@ -250,9 +262,6 @@ public Authentication authenticate(Authentication authentication) throws Authent
250262

251263
authorization = authorizationBuilder.build();
252264

253-
// Invalidate the authorization code as it can only be used once
254-
authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, authorizationCode.getToken());
255-
256265
this.authorizationService.save(authorization);
257266

258267
if (this.logger.isTraceEnabled()) {
@@ -305,5 +314,4 @@ private SessionInformation getSessionInformation(Authentication principal) {
305314
}
306315
return sessionInformation;
307316
}
308-
309317
}

Diff for: oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java

+6
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,12 @@ public void authenticateWhenInvalidatedCodeThenThrowOAuth2AuthenticationExceptio
271271
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
272272
.extracting("errorCode")
273273
.isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
274+
275+
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
276+
verify(this.authorizationService).save(authorizationCaptor.capture());
277+
OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue();
278+
assertThat(updatedAuthorization.getAccessToken().isInvalidated()).isTrue();
279+
assertThat(updatedAuthorization.getRefreshToken().isInvalidated()).isTrue();
274280
}
275281

276282
// gh-290

0 commit comments

Comments
 (0)