From e4ce97b8877f3b5f93b322e79950ad76244698bd Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Wed, 22 Sep 2021 10:22:39 -0400 Subject: [PATCH] Access token is active after revoke then refresh Closes gh-432 --- ...th2RefreshTokenAuthenticationProvider.java | 6 ++- .../OAuth2RefreshTokenGrantTests.java | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProvider.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProvider.java index 651d60d4..b9e1dec0 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProvider.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProvider.java @@ -237,8 +237,10 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic // @formatter:off OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.from(authorization) .token(accessToken, - (metadata) -> - metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, jwtAccessToken.getClaims())) + (metadata) -> { + metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, jwtAccessToken.getClaims()); + metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, false); + }) .refreshToken(currentRefreshToken); if (idToken != null) { authorizationBuilder diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java index 9473cd13..4cc0bddf 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java @@ -54,6 +54,9 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2Token; +import org.springframework.security.oauth2.core.OAuth2TokenType; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; @@ -93,6 +96,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. */ public class OAuth2RefreshTokenGrantTests { private static final String DEFAULT_TOKEN_ENDPOINT_URI = "/oauth2/token"; + private static final String DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI = "/oauth2/revoke"; private static final String AUTHORITIES_CLAIM = "authorities"; private static EmbeddedDatabase db; private static JWKSource jwkSource; @@ -181,6 +185,37 @@ public class OAuth2RefreshTokenGrantTests { assertThat(authoritiesClaim).containsExactlyInAnyOrderElementsOf(userAuthorities); } + // gh-432 + @Test + public void requestWhenRevokeAndRefreshThenAccessTokenActive() throws Exception { + this.spring.register(AuthorizationServerConfiguration.class).autowire(); + + RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); + this.registeredClientRepository.save(registeredClient); + + OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); + this.authorizationService.save(authorization); + + OAuth2AccessToken token = authorization.getAccessToken().getToken(); + OAuth2TokenType tokenType = OAuth2TokenType.ACCESS_TOKEN; + + this.mvc.perform(post(DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI) + .params(getTokenRevocationRequestParameters(token, tokenType)) + .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth( + registeredClient.getClientId(), registeredClient.getClientSecret()))) + .andExpect(status().isOk()); + + this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI) + .params(getRefreshTokenRequestParameters(authorization)) + .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth( + registeredClient.getClientId(), registeredClient.getClientSecret()))) + .andExpect(status().isOk()); + + OAuth2Authorization updatedAuthorization = this.authorizationService.findById(authorization.getId()); + OAuth2Authorization.Token accessToken = updatedAuthorization.getAccessToken(); + assertThat(accessToken.isActive()).isTrue(); + } + private static MultiValueMap getRefreshTokenRequestParameters(OAuth2Authorization authorization) { MultiValueMap parameters = new LinkedMultiValueMap<>(); parameters.set(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.REFRESH_TOKEN.getValue()); @@ -188,6 +223,13 @@ public class OAuth2RefreshTokenGrantTests { return parameters; } + private static MultiValueMap getTokenRevocationRequestParameters(OAuth2Token token, OAuth2TokenType tokenType) { + MultiValueMap parameters = new LinkedMultiValueMap<>(); + parameters.set(OAuth2ParameterNames.TOKEN, token.getTokenValue()); + parameters.set(OAuth2ParameterNames.TOKEN_TYPE_HINT, tokenType.getValue()); + return parameters; + } + private static String encodeBasicAuth(String clientId, String secret) throws Exception { clientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8.name()); secret = URLEncoder.encode(secret, StandardCharsets.UTF_8.name());