|
@@ -17,12 +17,14 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
|
|
|
|
|
import org.junit.Before;
|
|
|
import org.junit.Test;
|
|
|
+import org.mockito.ArgumentCaptor;
|
|
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
|
|
+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;
|
|
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
|
-import org.springframework.security.oauth2.server.authorization.OAuth2TokenRevocationService;
|
|
|
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
|
|
|
import org.springframework.security.oauth2.server.authorization.TokenType;
|
|
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
@@ -30,8 +32,10 @@ import org.springframework.security.oauth2.server.authorization.client.TestRegis
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
|
import static org.mockito.Mockito.mock;
|
|
|
+import static org.mockito.Mockito.never;
|
|
|
import static org.mockito.Mockito.verify;
|
|
|
import static org.mockito.Mockito.when;
|
|
|
|
|
@@ -39,38 +43,27 @@ import static org.mockito.Mockito.when;
|
|
|
* Tests for {@link OAuth2TokenRevocationAuthenticationProvider}.
|
|
|
*
|
|
|
* @author Vivek Babu
|
|
|
+ * @author Joe Grandja
|
|
|
*/
|
|
|
public class OAuth2TokenRevocationAuthenticationProviderTests {
|
|
|
private RegisteredClient registeredClient;
|
|
|
- private OAuth2AuthorizationService oAuth2AuthorizationService;
|
|
|
- private OAuth2TokenRevocationService oAuth2TokenRevocationService;
|
|
|
+ private OAuth2AuthorizationService authorizationService;
|
|
|
private OAuth2TokenRevocationAuthenticationProvider authenticationProvider;
|
|
|
|
|
|
@Before
|
|
|
public void setUp() {
|
|
|
this.registeredClient = TestRegisteredClients.registeredClient().build();
|
|
|
- this.oAuth2AuthorizationService = mock(OAuth2AuthorizationService.class);
|
|
|
- this.oAuth2TokenRevocationService = mock(OAuth2TokenRevocationService.class);
|
|
|
- this.authenticationProvider = new OAuth2TokenRevocationAuthenticationProvider(oAuth2AuthorizationService,
|
|
|
- oAuth2TokenRevocationService);
|
|
|
+ this.authorizationService = mock(OAuth2AuthorizationService.class);
|
|
|
+ this.authenticationProvider = new OAuth2TokenRevocationAuthenticationProvider(this.authorizationService);
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
public void constructorWhenAuthorizationServiceNullThenThrowIllegalArgumentException() {
|
|
|
- assertThatThrownBy(() -> new OAuth2TokenRevocationAuthenticationProvider(null,
|
|
|
- oAuth2TokenRevocationService))
|
|
|
+ assertThatThrownBy(() -> new OAuth2TokenRevocationAuthenticationProvider(null))
|
|
|
.isInstanceOf(IllegalArgumentException.class)
|
|
|
.hasMessage("authorizationService cannot be null");
|
|
|
}
|
|
|
|
|
|
- @Test
|
|
|
- public void constructorWhenRevocationServiceNullThenThrowIllegalArgumentException() {
|
|
|
- assertThatThrownBy(() -> new OAuth2TokenRevocationAuthenticationProvider(oAuth2AuthorizationService,
|
|
|
- null))
|
|
|
- .isInstanceOf(IllegalArgumentException.class)
|
|
|
- .hasMessage("tokenRevocationService cannot be null");
|
|
|
- }
|
|
|
-
|
|
|
@Test
|
|
|
public void supportsWhenTypeOAuth2TokenRevocationAuthenticationTokenThenReturnTrue() {
|
|
|
assertThat(this.authenticationProvider.supports(OAuth2TokenRevocationAuthenticationToken.class)).isTrue();
|
|
@@ -81,7 +74,7 @@ public class OAuth2TokenRevocationAuthenticationProviderTests {
|
|
|
TestingAuthenticationToken clientPrincipal = new TestingAuthenticationToken(
|
|
|
this.registeredClient.getClientId(), this.registeredClient.getClientSecret());
|
|
|
OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
|
|
- "token", clientPrincipal, "access_token");
|
|
|
+ "token", clientPrincipal, TokenType.ACCESS_TOKEN.getValue());
|
|
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
@@ -92,9 +85,9 @@ public class OAuth2TokenRevocationAuthenticationProviderTests {
|
|
|
@Test
|
|
|
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
|
|
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
|
|
- this.registeredClient.getClientId(), this.registeredClient.getClientSecret());
|
|
|
+ this.registeredClient.getClientId(), this.registeredClient.getClientSecret(), null);
|
|
|
OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
|
|
- "token", clientPrincipal, "access_token");
|
|
|
+ "token", clientPrincipal, TokenType.ACCESS_TOKEN.getValue());
|
|
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
@@ -103,48 +96,99 @@ public class OAuth2TokenRevocationAuthenticationProviderTests {
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenInvalidTokenThenAuthenticate() {
|
|
|
+ public void authenticateWhenInvalidTokenTypeThenThrowOAuth2AuthenticationException() {
|
|
|
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient);
|
|
|
OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
|
|
- "token", clientPrincipal, "access_token");
|
|
|
+ "token", clientPrincipal, "unsupported_token_type");
|
|
|
+ assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
+ .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
+ .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
+ .extracting("errorCode")
|
|
|
+ .isEqualTo("unsupported_token_type");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void authenticateWhenInvalidTokenThenNotRevoked() {
|
|
|
+ OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient);
|
|
|
+ OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
|
|
+ "token", clientPrincipal, TokenType.ACCESS_TOKEN.getValue());
|
|
|
OAuth2TokenRevocationAuthenticationToken authenticationResult =
|
|
|
(OAuth2TokenRevocationAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
- assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
- assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(this.registeredClient.getClientId());
|
|
|
- assertThat(authenticationResult.getRegisteredClient()).isEqualTo(this.registeredClient);
|
|
|
+ assertThat(authenticationResult.isAuthenticated()).isFalse();
|
|
|
+ verify(this.authorizationService, never()).save(any());
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenAuthorizationIssuedToAnotherClientThenThrowOAuth2AuthenticationException() {
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations.authorization().build();
|
|
|
- when(this.oAuth2AuthorizationService.findByTokenAndTokenType(eq("token"), eq(TokenType.ACCESS_TOKEN)))
|
|
|
+ public void authenticateWhenTokenIssuedToAnotherClientThenThrowOAuth2AuthenticationException() {
|
|
|
+ OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(
|
|
|
+ TestRegisteredClients.registeredClient2().build()).build();
|
|
|
+ when(this.authorizationService.findByToken(
|
|
|
+ eq("token"),
|
|
|
+ eq(TokenType.ACCESS_TOKEN)))
|
|
|
.thenReturn(authorization);
|
|
|
- OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
|
|
- TestRegisteredClients.registeredClient2().build());
|
|
|
+
|
|
|
+ OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient);
|
|
|
OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
|
|
- "token", clientPrincipal, "access_token");
|
|
|
+ "token", clientPrincipal, TokenType.ACCESS_TOKEN.getValue());
|
|
|
+
|
|
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
.extracting("errorCode")
|
|
|
- .isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
|
|
|
+ .isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenValidAccessTokenThenInvalidateTokenAndAuthenticate() {
|
|
|
+ public void authenticateWhenValidRefreshTokenThenRevoked() {
|
|
|
+ OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(
|
|
|
+ this.registeredClient).build();
|
|
|
+ when(this.authorizationService.findByToken(
|
|
|
+ eq(authorization.getTokens().getRefreshToken().getTokenValue()),
|
|
|
+ eq(TokenType.REFRESH_TOKEN)))
|
|
|
+ .thenReturn(authorization);
|
|
|
+
|
|
|
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient);
|
|
|
OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
|
|
- "token", clientPrincipal, "access_token");
|
|
|
- OAuth2Authorization mockAuthorization = mock(OAuth2Authorization.class);
|
|
|
- when(oAuth2AuthorizationService.findByTokenAndTokenType(eq("token"), eq(TokenType.ACCESS_TOKEN))).
|
|
|
- thenReturn(mockAuthorization);
|
|
|
- when(mockAuthorization.getRegisteredClientId()).thenReturn(this.registeredClient.getClientId());
|
|
|
+ authorization.getTokens().getRefreshToken().getTokenValue(), clientPrincipal, TokenType.REFRESH_TOKEN.getValue());
|
|
|
+
|
|
|
OAuth2TokenRevocationAuthenticationToken authenticationResult =
|
|
|
(OAuth2TokenRevocationAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
- verify(this.oAuth2TokenRevocationService).revoke(eq("token"), eq(TokenType.ACCESS_TOKEN));
|
|
|
+ assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
+
|
|
|
+ ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
|
|
+ verify(this.authorizationService).save(authorizationCaptor.capture());
|
|
|
+
|
|
|
+ OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue();
|
|
|
+ OAuth2RefreshToken refreshToken = updatedAuthorization.getTokens().getRefreshToken();
|
|
|
+ assertThat(updatedAuthorization.getTokens().getTokenMetadata(refreshToken).isInvalidated()).isTrue();
|
|
|
+ OAuth2AccessToken accessToken = updatedAuthorization.getTokens().getAccessToken();
|
|
|
+ assertThat(updatedAuthorization.getTokens().getTokenMetadata(accessToken).isInvalidated()).isTrue();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void authenticateWhenValidAccessTokenThenRevoked() {
|
|
|
+ OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(
|
|
|
+ this.registeredClient).build();
|
|
|
+ when(this.authorizationService.findByToken(
|
|
|
+ eq(authorization.getTokens().getAccessToken().getTokenValue()),
|
|
|
+ eq(TokenType.ACCESS_TOKEN)))
|
|
|
+ .thenReturn(authorization);
|
|
|
+
|
|
|
+ OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient);
|
|
|
+ OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
|
|
+ authorization.getTokens().getAccessToken().getTokenValue(), clientPrincipal, TokenType.ACCESS_TOKEN.getValue());
|
|
|
|
|
|
+ OAuth2TokenRevocationAuthenticationToken authenticationResult =
|
|
|
+ (OAuth2TokenRevocationAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
- assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(this.registeredClient.getClientId());
|
|
|
- assertThat(authenticationResult.getRegisteredClient()).isEqualTo(this.registeredClient);
|
|
|
+
|
|
|
+ ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
|
|
+ verify(this.authorizationService).save(authorizationCaptor.capture());
|
|
|
+
|
|
|
+ OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue();
|
|
|
+ OAuth2AccessToken accessToken = updatedAuthorization.getTokens().getAccessToken();
|
|
|
+ assertThat(updatedAuthorization.getTokens().getTokenMetadata(accessToken).isInvalidated()).isTrue();
|
|
|
+ OAuth2RefreshToken refreshToken = updatedAuthorization.getTokens().getRefreshToken();
|
|
|
+ assertThat(updatedAuthorization.getTokens().getTokenMetadata(refreshToken).isInvalidated()).isFalse();
|
|
|
}
|
|
|
}
|