|
@@ -32,8 +32,6 @@ import com.nimbusds.jose.proc.SecurityContext;
|
|
|
import org.junit.Before;
|
|
|
import org.junit.Test;
|
|
|
|
|
|
-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.ClientAuthenticationMethod;
|
|
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
|
@@ -60,31 +58,24 @@ import org.springframework.security.oauth2.server.authorization.client.Registere
|
|
|
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
|
|
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
|
|
|
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
|
|
|
+import org.springframework.security.oauth2.server.authorization.context.ProviderContext;
|
|
|
+import org.springframework.security.oauth2.server.authorization.context.ProviderContextHolder;
|
|
|
import org.springframework.web.util.UriComponentsBuilder;
|
|
|
|
|
|
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.spy;
|
|
|
import static org.mockito.Mockito.verify;
|
|
|
-import static org.mockito.Mockito.verifyNoInteractions;
|
|
|
import static org.mockito.Mockito.when;
|
|
|
|
|
|
/**
|
|
|
- * Tests for {@link OAuth2ClientAuthenticationProvider}.
|
|
|
+ * Tests for {@link JwtClientAssertionAuthenticationProvider}.
|
|
|
*
|
|
|
- * @author Patryk Kostrzewa
|
|
|
- * @author Joe Grandja
|
|
|
- * @author Daniel Garnier-Moiroux
|
|
|
- * @author Anoop Garlapati
|
|
|
* @author Rafal Lewczuk
|
|
|
+ * @author Joe Grandja
|
|
|
*/
|
|
|
-public class OAuth2ClientAuthenticationProviderTests {
|
|
|
- private static final String PLAIN_CODE_VERIFIER = "pkce-key";
|
|
|
- private static final String PLAIN_CODE_CHALLENGE = PLAIN_CODE_VERIFIER;
|
|
|
-
|
|
|
+public class JwtClientAssertionAuthenticationProviderTests {
|
|
|
// See RFC 7636: Appendix B. Example for the S256 code_challenge_method
|
|
|
// https://tools.ietf.org/html/rfc7636#appendix-B
|
|
|
private static final String S256_CODE_VERIFIER = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
|
|
@@ -98,53 +89,33 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
|
|
|
private RegisteredClientRepository registeredClientRepository;
|
|
|
private OAuth2AuthorizationService authorizationService;
|
|
|
- private OAuth2ClientAuthenticationProvider authenticationProvider;
|
|
|
- private PasswordEncoder passwordEncoder;
|
|
|
+ private JwtClientAssertionAuthenticationProvider authenticationProvider;
|
|
|
private ProviderSettings providerSettings;
|
|
|
|
|
|
@Before
|
|
|
public void setUp() {
|
|
|
this.registeredClientRepository = mock(RegisteredClientRepository.class);
|
|
|
this.authorizationService = mock(OAuth2AuthorizationService.class);
|
|
|
- this.authenticationProvider = new OAuth2ClientAuthenticationProvider(
|
|
|
+ this.authenticationProvider = new JwtClientAssertionAuthenticationProvider(
|
|
|
this.registeredClientRepository, this.authorizationService);
|
|
|
- this.passwordEncoder = spy(new PasswordEncoder() {
|
|
|
- @Override
|
|
|
- public String encode(CharSequence rawPassword) {
|
|
|
- return NoOpPasswordEncoder.getInstance().encode(rawPassword);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
|
|
- return NoOpPasswordEncoder.getInstance().matches(rawPassword, encodedPassword);
|
|
|
- }
|
|
|
- });
|
|
|
- this.authenticationProvider.setPasswordEncoder(this.passwordEncoder);
|
|
|
this.providerSettings = ProviderSettings.builder().issuer("https://auth-server.com").build();
|
|
|
- this.authenticationProvider.setProviderSettings(this.providerSettings);
|
|
|
+ ProviderContextHolder.setProviderContext(new ProviderContext(this.providerSettings, null));
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
public void constructorWhenRegisteredClientRepositoryNullThenThrowIllegalArgumentException() {
|
|
|
- assertThatThrownBy(() -> new OAuth2ClientAuthenticationProvider(null, this.authorizationService))
|
|
|
+ assertThatThrownBy(() -> new JwtClientAssertionAuthenticationProvider(null, this.authorizationService))
|
|
|
.isInstanceOf(IllegalArgumentException.class)
|
|
|
.hasMessage("registeredClientRepository cannot be null");
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
public void constructorWhenAuthorizationServiceNullThenThrowIllegalArgumentException() {
|
|
|
- assertThatThrownBy(() -> new OAuth2ClientAuthenticationProvider(this.registeredClientRepository, null))
|
|
|
+ assertThatThrownBy(() -> new JwtClientAssertionAuthenticationProvider(this.registeredClientRepository, null))
|
|
|
.isInstanceOf(IllegalArgumentException.class)
|
|
|
.hasMessage("authorizationService cannot be null");
|
|
|
}
|
|
|
|
|
|
- @Test
|
|
|
- public void setPasswordEncoderWhenNullThenThrowIllegalArgumentException() {
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.setPasswordEncoder(null))
|
|
|
- .isInstanceOf(IllegalArgumentException.class)
|
|
|
- .hasMessage("passwordEncoder cannot be null");
|
|
|
- }
|
|
|
-
|
|
|
@Test
|
|
|
public void supportsWhenTypeOAuth2ClientAuthenticationTokenThenReturnTrue() {
|
|
|
assertThat(this.authenticationProvider.supports(OAuth2ClientAuthenticationToken.class)).isTrue();
|
|
@@ -152,12 +123,16 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
|
|
|
@Test
|
|
|
public void authenticateWhenInvalidClientIdThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
|
|
+ // @formatter:off
|
|
|
+ RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
+ .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT)
|
|
|
+ .build();
|
|
|
+ // @formatter:on
|
|
|
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
.thenReturn(registeredClient);
|
|
|
|
|
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
|
|
- registeredClient.getClientId() + "-invalid", ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret(), null);
|
|
|
+ registeredClient.getClientId() + "-invalid", JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, "jwt-assertion", null);
|
|
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
@@ -174,7 +149,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
.thenReturn(registeredClient);
|
|
|
|
|
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
|
|
- registeredClient.getClientId(), ClientAuthenticationMethod.CLIENT_SECRET_POST, registeredClient.getClientSecret(), null);
|
|
|
+ registeredClient.getClientId(), JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, "jwt-assertion", null);
|
|
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
@@ -185,353 +160,28 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenInvalidClientSecretThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
|
|
- registeredClient.getClientId(), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret() + "-invalid", null);
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .satisfies(error -> {
|
|
|
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
|
- assertThat(error.getDescription()).contains(OAuth2ParameterNames.CLIENT_SECRET);
|
|
|
- });
|
|
|
- verify(this.passwordEncoder).matches(any(), any());
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenClientSecretNotProvidedThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, null, null);
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .satisfies(error -> {
|
|
|
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
|
- assertThat(error.getDescription()).contains("credentials");
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenValidCredentialsThenAuthenticated() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
|
|
- registeredClient.getClientId(), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret(), null);
|
|
|
- OAuth2ClientAuthenticationToken authenticationResult =
|
|
|
- (OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
-
|
|
|
- verify(this.passwordEncoder).matches(any(), any());
|
|
|
- assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
- assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
|
|
- assertThat(authenticationResult.getCredentials().toString()).isEqualTo(registeredClient.getClientSecret());
|
|
|
- assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenAuthorizationCodeGrantAndValidCredentialsThenAuthenticated() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(TestOAuth2Authorizations.authorization().build());
|
|
|
- OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
|
|
- registeredClient.getClientId(), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret(), createAuthorizationCodeTokenParameters());
|
|
|
- OAuth2ClientAuthenticationToken authenticationResult =
|
|
|
- (OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
-
|
|
|
- verify(this.passwordEncoder).matches(any(), any());
|
|
|
- assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
- assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
|
|
- assertThat(authenticationResult.getCredentials().toString()).isEqualTo(registeredClient.getClientSecret());
|
|
|
- assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndInvalidCodeThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
|
|
- parameters.put(OAuth2ParameterNames.CODE, "invalid-code");
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.NONE, null, parameters);
|
|
|
-
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .satisfies(error -> {
|
|
|
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
|
|
|
- assertThat(error.getDescription()).contains(OAuth2ParameterNames.CODE);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndPublicClientAndMissingCodeVerifierThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createAuthorizationCodeTokenParameters();
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.NONE, null, parameters);
|
|
|
-
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .satisfies(error -> {
|
|
|
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
|
|
|
- assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndConfidentialClientAndMissingCodeVerifierThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createAuthorizationCodeTokenParameters();
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret(), parameters);
|
|
|
-
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .satisfies(error -> {
|
|
|
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
|
|
|
- assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndPlainMethodAndInvalidCodeVerifierThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createPkceTokenParameters("invalid-code-verifier");
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.NONE, null, parameters);
|
|
|
-
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .satisfies(error -> {
|
|
|
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
|
|
|
- assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndS256MethodAndInvalidCodeVerifierThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, createPkceAuthorizationParametersS256())
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createPkceTokenParameters("invalid-code-verifier");
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.NONE, null, parameters);
|
|
|
-
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .satisfies(error -> {
|
|
|
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
|
|
|
- assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndPlainMethodAndValidCodeVerifierThenAuthenticated() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.NONE, null, parameters);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authenticationResult =
|
|
|
- (OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
- assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
- assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
|
|
- assertThat(authenticationResult.getCredentials()).isNull();
|
|
|
- assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndMissingMethodThenDefaultPlainMethodAndAuthenticated() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- Map<String, Object> authorizationRequestAdditionalParameters = createPkceAuthorizationParametersPlain();
|
|
|
- authorizationRequestAdditionalParameters.remove(PkceParameterNames.CODE_CHALLENGE_METHOD);
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, authorizationRequestAdditionalParameters)
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.NONE, null, parameters);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authenticationResult =
|
|
|
- (OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
- assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
- assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
|
|
- assertThat(authenticationResult.getCredentials()).isNull();
|
|
|
- assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndS256MethodAndValidCodeVerifierThenAuthenticated() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, createPkceAuthorizationParametersS256())
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createPkceTokenParameters(S256_CODE_VERIFIER);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.NONE, null, parameters);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authenticationResult =
|
|
|
- (OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
- assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
- assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
|
|
- assertThat(authenticationResult.getCredentials()).isNull();
|
|
|
- assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenPkceAndUnsupportedCodeChallengeMethodThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- Map<String, Object> authorizationRequestAdditionalParameters = createPkceAuthorizationParametersPlain();
|
|
|
- // This should never happen: the Authorization endpoint should not allow it
|
|
|
- authorizationRequestAdditionalParameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "unsupported-challenge-method");
|
|
|
- OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
- .authorization(registeredClient, authorizationRequestAdditionalParameters)
|
|
|
- .build();
|
|
|
- when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
- .thenReturn(authorization);
|
|
|
-
|
|
|
- Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication =
|
|
|
- new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), ClientAuthenticationMethod.NONE, null, parameters);
|
|
|
-
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .extracting("errorCode")
|
|
|
- .isEqualTo(OAuth2ErrorCodes.SERVER_ERROR);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenJwtClientAssertionAndInvalidClientIdThenThrowOAuth2AuthenticationException() {
|
|
|
+ public void authenticateWhenCredentialsNotProvidedThenThrowOAuth2AuthenticationException() {
|
|
|
// @formatter:off
|
|
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
- .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT)
|
|
|
+ .clientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT)
|
|
|
.build();
|
|
|
// @formatter:on
|
|
|
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
.thenReturn(registeredClient);
|
|
|
|
|
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
|
|
- registeredClient.getClientId() + "-invalid", JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, "jwt-assertion", null);
|
|
|
+ registeredClient.getClientId(), JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, null, null);
|
|
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
.satisfies(error -> {
|
|
|
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
|
- assertThat(error.getDescription()).contains(OAuth2ParameterNames.CLIENT_ID);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- public void authenticateWhenJwtClientAssertionAndUnsupportedClientAuthenticationMethodThenThrowOAuth2AuthenticationException() {
|
|
|
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
|
|
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
- .thenReturn(registeredClient);
|
|
|
-
|
|
|
- OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
|
|
- registeredClient.getClientId(), JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, "jwt-assertion", null);
|
|
|
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
|
- .isInstanceOf(OAuth2AuthenticationException.class)
|
|
|
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
|
|
- .satisfies(error -> {
|
|
|
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
|
|
- assertThat(error.getDescription()).contains("authentication_method");
|
|
|
+ assertThat(error.getDescription()).contains("credentials");
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenJwtClientAssertionAndMissingJwkSetUrlThenThrowOAuth2AuthenticationException() {
|
|
|
+ public void authenticateWhenMissingJwkSetUrlThenThrowOAuth2AuthenticationException() {
|
|
|
// @formatter:off
|
|
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
.clientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT)
|
|
@@ -558,7 +208,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenJwtClientAssertionAndMissingClientSecretThenThrowOAuth2AuthenticationException() {
|
|
|
+ public void authenticateWhenMissingClientSecretThenThrowOAuth2AuthenticationException() {
|
|
|
// @formatter:off
|
|
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
.clientSecret(null)
|
|
@@ -586,7 +236,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenJwtClientAssertionAndMissingSigningAlgorithmThenThrowOAuth2AuthenticationException() {
|
|
|
+ public void authenticateWhenMissingSigningAlgorithmThenThrowOAuth2AuthenticationException() {
|
|
|
// @formatter:off
|
|
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
.clientSecret(TestKeys.DEFAULT_ENCODED_SECRET_KEY)
|
|
@@ -609,7 +259,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenJwtClientAssertionAndInvalidCredentialsThenThrowOAuth2AuthenticationException() {
|
|
|
+ public void authenticateWhenInvalidCredentialsThenThrowOAuth2AuthenticationException() {
|
|
|
// @formatter:off
|
|
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
.clientSecret(TestKeys.DEFAULT_ENCODED_SECRET_KEY)
|
|
@@ -637,7 +287,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenJwtClientAssertionAndInvalidClaimsThenThrowOAuth2AuthenticationException() {
|
|
|
+ public void authenticateWhenInvalidClaimsThenThrowOAuth2AuthenticationException() {
|
|
|
// @formatter:off
|
|
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
.clientSecret(TestKeys.DEFAULT_ENCODED_SECRET_KEY)
|
|
@@ -680,7 +330,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
- public void authenticateWhenJwtClientAssertionAndValidCredentialsThenAuthenticated() {
|
|
|
+ public void authenticateWhenValidCredentialsThenAuthenticated() {
|
|
|
// @formatter:off
|
|
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
.clientSecret(TestKeys.DEFAULT_ENCODED_SECRET_KEY)
|
|
@@ -710,8 +360,53 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
OAuth2ClientAuthenticationToken authenticationResult =
|
|
|
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
|
|
|
- verifyNoInteractions(this.passwordEncoder);
|
|
|
+ assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
+ assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
|
|
+ assertThat(authenticationResult.getCredentials()).isInstanceOf(Jwt.class);
|
|
|
+ assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
|
|
+ assertThat(authenticationResult.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_JWT);
|
|
|
+ }
|
|
|
|
|
|
+ @Test
|
|
|
+ public void authenticateWhenPkceAndValidCodeVerifierThenAuthenticated() {
|
|
|
+ // @formatter:off
|
|
|
+ RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
|
|
+ .clientSecret(TestKeys.DEFAULT_ENCODED_SECRET_KEY)
|
|
|
+ .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT)
|
|
|
+ .clientSettings(
|
|
|
+ ClientSettings.builder()
|
|
|
+ .tokenEndpointAuthenticationSigningAlgorithm(MacAlgorithm.HS256)
|
|
|
+ .build()
|
|
|
+ )
|
|
|
+ .build();
|
|
|
+ // @formatter:on
|
|
|
+ when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
|
+ .thenReturn(registeredClient);
|
|
|
+
|
|
|
+ OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
|
+ .authorization(registeredClient, createPkceAuthorizationParametersS256())
|
|
|
+ .build();
|
|
|
+ when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
|
|
+ .thenReturn(authorization);
|
|
|
+
|
|
|
+ Map<String, Object> parameters = createPkceTokenParameters(S256_CODE_VERIFIER);
|
|
|
+
|
|
|
+ // @formatter:off
|
|
|
+ JoseHeader joseHeader = JoseHeader.withAlgorithm(MacAlgorithm.HS256)
|
|
|
+ .build();
|
|
|
+ JwtClaimsSet jwtClaimsSet = jwtClientAssertionClaims(registeredClient)
|
|
|
+ .build();
|
|
|
+ // @formatter:on
|
|
|
+
|
|
|
+ JwtEncoder jwsEncoder = createEncoder(TestKeys.DEFAULT_ENCODED_SECRET_KEY, "HmacSHA256");
|
|
|
+ Jwt jwtAssertion = jwsEncoder.encode(joseHeader, jwtClaimsSet);
|
|
|
+
|
|
|
+ OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
|
|
+ registeredClient.getClientId(), JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, jwtAssertion.getTokenValue(), parameters);
|
|
|
+ OAuth2ClientAuthenticationToken authenticationResult =
|
|
|
+ (OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
|
|
+
|
|
|
+ verify(this.authorizationService).findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE));
|
|
|
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
|
|
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
|
|
assertThat(authenticationResult.getCredentials()).isInstanceOf(Jwt.class);
|
|
@@ -755,13 +450,6 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|
|
return parameters;
|
|
|
}
|
|
|
|
|
|
- private static Map<String, Object> createPkceAuthorizationParametersPlain() {
|
|
|
- Map<String, Object> parameters = new HashMap<>();
|
|
|
- parameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "plain");
|
|
|
- parameters.put(PkceParameterNames.CODE_CHALLENGE, PLAIN_CODE_CHALLENGE);
|
|
|
- return parameters;
|
|
|
- }
|
|
|
-
|
|
|
private static Map<String, Object> createPkceAuthorizationParametersS256() {
|
|
|
Map<String, Object> parameters = new HashMap<>();
|
|
|
parameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256");
|