diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java index 83602d75..ab84a3bd 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java @@ -154,12 +154,12 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth if (!authorizationCode.isActive()) { if (authorizationCode.isInvalidated()) { - OAuth2Token token = authorization.getRefreshToken() != null ? - authorization.getRefreshToken().getToken() : - authorization.getAccessToken().getToken(); + OAuth2Authorization.Token token = authorization.getRefreshToken() != null ? + authorization.getRefreshToken() : + authorization.getAccessToken(); if (token != null) { // Invalidate the access (and refresh) token as the client is attempting to use the authorization code more than once - authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, token); + authorization = OAuth2AuthenticationProviderUtils.invalidate(authorization, token.getToken()); this.authorizationService.save(authorization); if (this.logger.isWarnEnabled()) { this.logger.warn(LogMessage.format("Invalidated authorization token(s) previously issued to registered client '%s'", registeredClient.getId())); 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 2378a559..802282ad 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 @@ -85,6 +85,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -283,6 +284,34 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { assertThat(updatedAuthorization.getRefreshToken().isInvalidated()).isTrue(); } + // gh-1233 + @Test + public void authenticateWhenInvalidatedCodeAndAccessTokenNullThenThrowOAuth2AuthenticationException() { + RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); + OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode( + AUTHORIZATION_CODE, Instant.now(), Instant.now().plusSeconds(120)); + OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient, authorizationCode) + .token(authorizationCode, (metadata) -> metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true)) + .build(); + when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE))) + .thenReturn(authorization); + + OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken( + registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret()); + OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute( + OAuth2AuthorizationRequest.class.getName()); + OAuth2AuthorizationCodeAuthenticationToken authentication = + new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); + + assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication)) + .isInstanceOf(OAuth2AuthenticationException.class) + .extracting(ex -> ((OAuth2AuthenticationException) ex).getError()) + .extracting("errorCode") + .isEqualTo(OAuth2ErrorCodes.INVALID_GRANT); + + verify(this.authorizationService, never()).save(any()); + } + // gh-290 @Test public void authenticateWhenExpiredCodeThenThrowOAuth2AuthenticationException() {