Add client secret POST authentication method support
Added support for client secret POST authentication method. Added validation of client authentication method when authenticating a client. Closes gh-134
This commit is contained in:
parent
90fbbea126
commit
e1f491bd61
@ -84,6 +84,11 @@ public class OAuth2ClientAuthenticationProvider implements AuthenticationProvide
|
|||||||
|
|
||||||
boolean authenticatedCredentials = false;
|
boolean authenticatedCredentials = false;
|
||||||
|
|
||||||
|
if (!registeredClient.getClientAuthenticationMethods().contains(
|
||||||
|
clientAuthentication.getClientAuthenticationMethod())) {
|
||||||
|
throwInvalidClient();
|
||||||
|
}
|
||||||
|
|
||||||
if (clientAuthentication.getCredentials() != null) {
|
if (clientAuthentication.getCredentials() != null) {
|
||||||
String clientSecret = clientAuthentication.getCredentials().toString();
|
String clientSecret = clientAuthentication.getCredentials().toString();
|
||||||
// TODO Use PasswordEncoder.matches()
|
// TODO Use PasswordEncoder.matches()
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
|||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.server.authorization.Version;
|
import org.springframework.security.oauth2.server.authorization.Version;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
@ -30,6 +31,7 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @author Patryk Kostrzewa
|
* @author Patryk Kostrzewa
|
||||||
|
* @author Anoop Garlapati
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
* @see AbstractAuthenticationToken
|
* @see AbstractAuthenticationToken
|
||||||
* @see RegisteredClient
|
* @see RegisteredClient
|
||||||
@ -39,6 +41,7 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
|||||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||||
private String clientId;
|
private String clientId;
|
||||||
private String clientSecret;
|
private String clientSecret;
|
||||||
|
private ClientAuthenticationMethod clientAuthenticationMethod;
|
||||||
private Map<String, Object> additionalParameters;
|
private Map<String, Object> additionalParameters;
|
||||||
private RegisteredClient registeredClient;
|
private RegisteredClient registeredClient;
|
||||||
|
|
||||||
@ -47,13 +50,17 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
|||||||
*
|
*
|
||||||
* @param clientId the client identifier
|
* @param clientId the client identifier
|
||||||
* @param clientSecret the client secret
|
* @param clientSecret the client secret
|
||||||
|
* @param clientAuthenticationMethod the authentication method used by the client
|
||||||
* @param additionalParameters the additional parameters
|
* @param additionalParameters the additional parameters
|
||||||
*/
|
*/
|
||||||
public OAuth2ClientAuthenticationToken(String clientId, String clientSecret,
|
public OAuth2ClientAuthenticationToken(String clientId, String clientSecret,
|
||||||
|
ClientAuthenticationMethod clientAuthenticationMethod,
|
||||||
@Nullable Map<String, Object> additionalParameters) {
|
@Nullable Map<String, Object> additionalParameters) {
|
||||||
this(clientId, additionalParameters);
|
this(clientId, additionalParameters);
|
||||||
Assert.hasText(clientSecret, "clientSecret cannot be empty");
|
Assert.hasText(clientSecret, "clientSecret cannot be empty");
|
||||||
|
Assert.notNull(clientAuthenticationMethod, "clientAuthenticationMethod cannot be null");
|
||||||
this.clientSecret = clientSecret;
|
this.clientSecret = clientSecret;
|
||||||
|
this.clientAuthenticationMethod = clientAuthenticationMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,6 +76,7 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
|||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.additionalParameters = additionalParameters != null ?
|
this.additionalParameters = additionalParameters != null ?
|
||||||
Collections.unmodifiableMap(additionalParameters) : null;
|
Collections.unmodifiableMap(additionalParameters) : null;
|
||||||
|
this.clientAuthenticationMethod = ClientAuthenticationMethod.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,4 +120,13 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
|||||||
public @Nullable RegisteredClient getRegisteredClient() {
|
public @Nullable RegisteredClient getRegisteredClient() {
|
||||||
return this.registeredClient;
|
return this.registeredClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ClientAuthenticationMethod client authentication method}.
|
||||||
|
*
|
||||||
|
* @return the {@link ClientAuthenticationMethod}
|
||||||
|
*/
|
||||||
|
public @Nullable ClientAuthenticationMethod getClientAuthenticationMethod() {
|
||||||
|
return this.clientAuthenticationMethod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package org.springframework.security.oauth2.server.authorization.web;
|
|||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
@ -85,7 +86,8 @@ public class ClientSecretBasicAuthenticationConverter implements AuthenticationC
|
|||||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST), ex);
|
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OAuth2ClientAuthenticationToken(clientID, clientSecret, extractAdditionalParameters(request));
|
return new OAuth2ClientAuthenticationToken(clientID, clientSecret, ClientAuthenticationMethod.BASIC,
|
||||||
|
extractAdditionalParameters(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Object> extractAdditionalParameters(HttpServletRequest request) {
|
private static Map<String, Object> extractAdditionalParameters(HttpServletRequest request) {
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.oauth2.server.authorization.web;
|
||||||
|
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to extract client credentials from POST parameters of {@link HttpServletRequest}
|
||||||
|
* and then converts to an {@link OAuth2ClientAuthenticationToken} used for authenticating the client.
|
||||||
|
*
|
||||||
|
* @author Anoop Garlapati
|
||||||
|
* @since 0.1.0
|
||||||
|
* @see OAuth2ClientAuthenticationToken
|
||||||
|
* @see OAuth2ClientAuthenticationFilter
|
||||||
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-2.3.1">Section 2.3.1 Client Password</a>
|
||||||
|
*/
|
||||||
|
public class ClientSecretPostAuthenticationConverter implements AuthenticationConverter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication convert(HttpServletRequest request) {
|
||||||
|
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
|
||||||
|
|
||||||
|
// client_id (REQUIRED)
|
||||||
|
String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);
|
||||||
|
if (!StringUtils.hasText(clientId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
||||||
|
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
// client_secret (REQUIRED)
|
||||||
|
String clientSecret = parameters.getFirst(OAuth2ParameterNames.CLIENT_SECRET);
|
||||||
|
if (!StringUtils.hasText(clientSecret)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.get(OAuth2ParameterNames.CLIENT_SECRET).size() != 1) {
|
||||||
|
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OAuth2ClientAuthenticationToken(clientId, clientSecret, ClientAuthenticationMethod.POST,
|
||||||
|
extractAdditionalParameters(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> extractAdditionalParameters(HttpServletRequest request) {
|
||||||
|
Map<String, Object> additionalParameters = Collections.emptyMap();
|
||||||
|
if (OAuth2EndpointUtils.matchesPkceTokenRequest(request)) {
|
||||||
|
// Confidential clients can also leverage PKCE
|
||||||
|
additionalParameters = new HashMap<>(OAuth2EndpointUtils.getParameters(request).toSingleValueMap());
|
||||||
|
additionalParameters.remove(OAuth2ParameterNames.CLIENT_ID);
|
||||||
|
additionalParameters.remove(OAuth2ParameterNames.CLIENT_SECRET);
|
||||||
|
}
|
||||||
|
return additionalParameters;
|
||||||
|
}
|
||||||
|
}
|
@ -77,6 +77,7 @@ public class OAuth2ClientAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
this.authenticationConverter = new DelegatingAuthenticationConverter(
|
this.authenticationConverter = new DelegatingAuthenticationConverter(
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
new ClientSecretBasicAuthenticationConverter(),
|
new ClientSecretBasicAuthenticationConverter(),
|
||||||
|
new ClientSecretPostAuthenticationConverter(),
|
||||||
new PublicClientAuthenticationConverter()));
|
new PublicClientAuthenticationConverter()));
|
||||||
this.authenticationSuccessHandler = this::onAuthenticationSuccess;
|
this.authenticationSuccessHandler = this::onAuthenticationSuccess;
|
||||||
this.authenticationFailureHandler = this::onAuthenticationFailure;
|
this.authenticationFailureHandler = this::onAuthenticationFailure;
|
||||||
|
@ -181,9 +181,7 @@ public class OAuth2AuthorizationCodeGrantTests {
|
|||||||
public void requestWhenPublicClientWithPkceThenReturnAccessTokenResponse() throws Exception {
|
public void requestWhenPublicClientWithPkceThenReturnAccessTokenResponse() throws Exception {
|
||||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||||
|
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient()
|
||||||
.clientSecret(null)
|
|
||||||
.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
|
|
||||||
.tokenSettings(tokenSettings -> tokenSettings.enableRefreshTokens(false))
|
.tokenSettings(tokenSettings -> tokenSettings.enableRefreshTokens(false))
|
||||||
.build();
|
.build();
|
||||||
when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||||
|
@ -19,6 +19,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||||
@ -119,7 +120,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
|||||||
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||||
registeredClient.getClientId(), registeredClient.getClientSecret(), null);
|
registeredClient.getClientId(), registeredClient.getClientSecret(), ClientAuthenticationMethod.BASIC, null);
|
||||||
OAuth2AuthorizationCodeAuthenticationToken authentication =
|
OAuth2AuthorizationCodeAuthenticationToken authentication =
|
||||||
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, null, null);
|
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, null, null);
|
||||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
@ -45,6 +46,7 @@ import static org.mockito.Mockito.when;
|
|||||||
* @author Patryk Kostrzewa
|
* @author Patryk Kostrzewa
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @author Daniel Garnier-Moiroux
|
* @author Daniel Garnier-Moiroux
|
||||||
|
* @author Anoop Garlapati
|
||||||
*/
|
*/
|
||||||
public class OAuth2ClientAuthenticationProviderTests {
|
public class OAuth2ClientAuthenticationProviderTests {
|
||||||
private static final String PLAIN_CODE_VERIFIER = "pkce-key";
|
private static final String PLAIN_CODE_VERIFIER = "pkce-key";
|
||||||
@ -95,7 +97,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|||||||
.thenReturn(registeredClient);
|
.thenReturn(registeredClient);
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||||
registeredClient.getClientId() + "-invalid", registeredClient.getClientSecret(), null);
|
registeredClient.getClientId() + "-invalid", registeredClient.getClientSecret(), ClientAuthenticationMethod.BASIC, null);
|
||||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||||
@ -110,7 +112,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|||||||
.thenReturn(registeredClient);
|
.thenReturn(registeredClient);
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||||
registeredClient.getClientId(), registeredClient.getClientSecret() + "-invalid", null);
|
registeredClient.getClientId(), registeredClient.getClientSecret() + "-invalid", ClientAuthenticationMethod.BASIC, null);
|
||||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||||
@ -140,7 +142,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|||||||
.thenReturn(registeredClient);
|
.thenReturn(registeredClient);
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||||
registeredClient.getClientId(), registeredClient.getClientSecret(), null);
|
registeredClient.getClientId(), registeredClient.getClientSecret(), ClientAuthenticationMethod.BASIC, null);
|
||||||
OAuth2ClientAuthenticationToken authenticationResult =
|
OAuth2ClientAuthenticationToken authenticationResult =
|
||||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||||
@ -275,7 +277,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void authenticateWhenPkceAndPlainMethodAndValidCodeVerifierThenAuthenticated() {
|
public void authenticateWhenPkceAndPlainMethodAndValidCodeVerifierThenAuthenticated() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
||||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||||
.thenReturn(registeredClient);
|
.thenReturn(registeredClient);
|
||||||
|
|
||||||
@ -300,7 +302,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void authenticateWhenPkceAndMissingMethodThenDefaultPlainMethodAndAuthenticated() {
|
public void authenticateWhenPkceAndMissingMethodThenDefaultPlainMethodAndAuthenticated() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
||||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||||
.thenReturn(registeredClient);
|
.thenReturn(registeredClient);
|
||||||
|
|
||||||
@ -327,7 +329,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void authenticateWhenPkceAndS256MethodAndValidCodeVerifierThenAuthenticated() {
|
public void authenticateWhenPkceAndS256MethodAndValidCodeVerifierThenAuthenticated() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
||||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||||
.thenReturn(registeredClient);
|
.thenReturn(registeredClient);
|
||||||
|
|
||||||
@ -352,7 +354,7 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void authenticateWhenPkceAndUnsupportedCodeChallengeMethodThenThrowOAuth2AuthenticationException() {
|
public void authenticateWhenPkceAndUnsupportedCodeChallengeMethodThenThrowOAuth2AuthenticationException() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
||||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||||
.thenReturn(registeredClient);
|
.thenReturn(registeredClient);
|
||||||
|
|
||||||
@ -377,6 +379,21 @@ public class OAuth2ClientAuthenticationProviderTests {
|
|||||||
.isEqualTo(OAuth2ErrorCodes.SERVER_ERROR);
|
.isEqualTo(OAuth2ErrorCodes.SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void authenticateWhenClientAuthenticationWithUnregisteredClientAuthenticationMethodThenThrowOAuth2AuthenticationException() {
|
||||||
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||||
|
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||||
|
.thenReturn(registeredClient);
|
||||||
|
|
||||||
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||||
|
registeredClient.getClientId(), registeredClient.getClientSecret(), ClientAuthenticationMethod.POST, null);
|
||||||
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||||
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||||
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||||
|
.extracting("errorCode")
|
||||||
|
.isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
private static Map<String, Object> createPkceTokenParameters(String codeVerifier) {
|
private static Map<String, Object> createPkceTokenParameters(String codeVerifier) {
|
||||||
Map<String, Object> parameters = new HashMap<>();
|
Map<String, Object> parameters = new HashMap<>();
|
||||||
parameters.put(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
parameters.put(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package org.springframework.security.oauth2.server.authorization.authentication;
|
package org.springframework.security.oauth2.server.authorization.authentication;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
||||||
|
|
||||||
@ -29,23 +30,31 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|||||||
* Tests for {@link OAuth2ClientAuthenticationToken}.
|
* Tests for {@link OAuth2ClientAuthenticationToken}.
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
|
* @author Anoop Garlapati
|
||||||
*/
|
*/
|
||||||
public class OAuth2ClientAuthenticationTokenTests {
|
public class OAuth2ClientAuthenticationTokenTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void constructorWhenClientIdNullThenThrowIllegalArgumentException() {
|
public void constructorWhenClientIdNullThenThrowIllegalArgumentException() {
|
||||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken(null, "secret", null))
|
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken(null, "secret", ClientAuthenticationMethod.BASIC, null))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("clientId cannot be empty");
|
.hasMessage("clientId cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void constructorWhenClientSecretNullThenThrowIllegalArgumentException() {
|
public void constructorWhenClientSecretNullThenThrowIllegalArgumentException() {
|
||||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken("clientId", null, null))
|
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken("clientId", null, ClientAuthenticationMethod.BASIC, null))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("clientSecret cannot be empty");
|
.hasMessage("clientSecret cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void constructorWhenClientAuthenticationMethodNullThenThrowIllegalArgumentException() {
|
||||||
|
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken("clientId", "clientSecret", null, null))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
|
.hasMessage("clientAuthenticationMethod cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void constructorWhenRegisteredClientNullThenThrowIllegalArgumentException() {
|
public void constructorWhenRegisteredClientNullThenThrowIllegalArgumentException() {
|
||||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken(null))
|
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken(null))
|
||||||
@ -55,11 +64,13 @@ public class OAuth2ClientAuthenticationTokenTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void constructorWhenClientCredentialsProvidedThenCreated() {
|
public void constructorWhenClientCredentialsProvidedThenCreated() {
|
||||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken("clientId", "secret", null);
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken("clientId", "secret",
|
||||||
|
ClientAuthenticationMethod.BASIC, null);
|
||||||
assertThat(authentication.isAuthenticated()).isFalse();
|
assertThat(authentication.isAuthenticated()).isFalse();
|
||||||
assertThat(authentication.getPrincipal().toString()).isEqualTo("clientId");
|
assertThat(authentication.getPrincipal().toString()).isEqualTo("clientId");
|
||||||
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
||||||
assertThat(authentication.getRegisteredClient()).isNull();
|
assertThat(authentication.getRegisteredClient()).isNull();
|
||||||
|
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -72,6 +83,7 @@ public class OAuth2ClientAuthenticationTokenTests {
|
|||||||
assertThat(authentication.getCredentials()).isNull();
|
assertThat(authentication.getCredentials()).isNull();
|
||||||
assertThat(authentication.getAdditionalParameters()).isEqualTo(additionalParameters);
|
assertThat(authentication.getAdditionalParameters()).isEqualTo(additionalParameters);
|
||||||
assertThat(authentication.getRegisteredClient()).isNull();
|
assertThat(authentication.getRegisteredClient()).isNull();
|
||||||
|
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -83,4 +95,15 @@ public class OAuth2ClientAuthenticationTokenTests {
|
|||||||
assertThat(authentication.getCredentials()).isNull();
|
assertThat(authentication.getCredentials()).isNull();
|
||||||
assertThat(authentication.getRegisteredClient()).isEqualTo(registeredClient);
|
assertThat(authentication.getRegisteredClient()).isEqualTo(registeredClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void constructorWhenClientCredentialsAndClientAuthenticationMethodProvidedThenCreated() {
|
||||||
|
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken("clientId", "secret",
|
||||||
|
ClientAuthenticationMethod.BASIC, null);
|
||||||
|
assertThat(authentication.isAuthenticated()).isFalse();
|
||||||
|
assertThat(authentication.getPrincipal().toString()).isEqualTo("clientId");
|
||||||
|
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
||||||
|
assertThat(authentication.getRegisteredClient()).isNull();
|
||||||
|
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import org.junit.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
import org.springframework.security.oauth2.jose.JoseHeaderNames;
|
import org.springframework.security.oauth2.jose.JoseHeaderNames;
|
||||||
@ -104,7 +105,7 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests {
|
|||||||
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||||
registeredClient.getClientId(), registeredClient.getClientSecret(), null);
|
registeredClient.getClientId(), registeredClient.getClientSecret(), ClientAuthenticationMethod.BASIC, null);
|
||||||
OAuth2ClientCredentialsAuthenticationToken authentication = new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal);
|
OAuth2ClientCredentialsAuthenticationToken authentication = new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal);
|
||||||
|
|
||||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||||
|
@ -20,6 +20,7 @@ import org.junit.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||||
@ -234,7 +235,7 @@ public class OAuth2RefreshTokenAuthenticationProviderTests {
|
|||||||
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||||
registeredClient.getClientId(), registeredClient.getClientSecret(), null);
|
registeredClient.getClientId(), registeredClient.getClientSecret(), ClientAuthenticationMethod.BASIC, null);
|
||||||
OAuth2RefreshTokenAuthenticationToken authentication = new OAuth2RefreshTokenAuthenticationToken(
|
OAuth2RefreshTokenAuthenticationToken authentication = new OAuth2RefreshTokenAuthenticationToken(
|
||||||
"refresh-token", clientPrincipal);
|
"refresh-token", clientPrincipal);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
@ -86,7 +87,7 @@ public class OAuth2TokenRevocationAuthenticationProviderTests {
|
|||||||
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||||
registeredClient.getClientId(), registeredClient.getClientSecret(), null);
|
registeredClient.getClientId(), registeredClient.getClientSecret(), ClientAuthenticationMethod.BASIC, null);
|
||||||
OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
OAuth2TokenRevocationAuthenticationToken authentication = new OAuth2TokenRevocationAuthenticationToken(
|
||||||
"token", clientPrincipal, TokenType.ACCESS_TOKEN.getValue());
|
"token", clientPrincipal, TokenType.ACCESS_TOKEN.getValue());
|
||||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||||
|
@ -51,4 +51,16 @@ public class TestRegisteredClients {
|
|||||||
.scope("scope1")
|
.scope("scope1")
|
||||||
.scope("scope2");
|
.scope("scope2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RegisteredClient.Builder registeredPublicClient() {
|
||||||
|
return RegisteredClient.withId("registration-3")
|
||||||
|
.clientId("client-3")
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
|
.clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
|
||||||
|
.redirectUri("https://example.com")
|
||||||
|
.scope("openid")
|
||||||
|
.scope("profile")
|
||||||
|
.scope("email")
|
||||||
|
.clientSettings(clientSettings -> clientSettings.requireProofKey(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import org.springframework.http.HttpHeaders;
|
|||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
@ -98,6 +99,7 @@ public class ClientSecretBasicAuthenticationConverterTests {
|
|||||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||||
assertThat(authentication.getPrincipal()).isEqualTo("clientId");
|
assertThat(authentication.getPrincipal()).isEqualTo("clientId");
|
||||||
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
||||||
|
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -107,6 +109,7 @@ public class ClientSecretBasicAuthenticationConverterTests {
|
|||||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||||
assertThat(authentication.getPrincipal()).isEqualTo("clientId");
|
assertThat(authentication.getPrincipal()).isEqualTo("clientId");
|
||||||
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
||||||
|
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||||
assertThat(authentication.getAdditionalParameters())
|
assertThat(authentication.getAdditionalParameters())
|
||||||
.containsOnly(
|
.containsOnly(
|
||||||
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||||
|
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.oauth2.server.authorization.web;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link ClientSecretPostAuthenticationConverter}.
|
||||||
|
*
|
||||||
|
* @author Anoop Garlapati
|
||||||
|
*/
|
||||||
|
public class ClientSecretPostAuthenticationConverterTests {
|
||||||
|
private final ClientSecretPostAuthenticationConverter converter = new ClientSecretPostAuthenticationConverter();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertWhenMissingClientIdThenReturnNull() {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
Authentication authentication = this.converter.convert(request);
|
||||||
|
assertThat(authentication).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertWhenMultipleClientIdsThenInvalidRequestError() {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1");
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-2");
|
||||||
|
assertThatThrownBy(() -> this.converter.convert(request))
|
||||||
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||||
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||||
|
.extracting("errorCode")
|
||||||
|
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertWhenMissingClientSecretThenReturnNull() {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1");
|
||||||
|
Authentication authentication = this.converter.convert(request);
|
||||||
|
assertThat(authentication).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertWhenMultipleClientSecretsThenInvalidRequestError() {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1");
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_SECRET, "client-secret-1");
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_SECRET, "client-secret-2");
|
||||||
|
assertThatThrownBy(() -> this.converter.convert(request))
|
||||||
|
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||||
|
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||||
|
.extracting("errorCode")
|
||||||
|
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertWhenPostWithValidCredentialsThenReturnClientAuthenticationToken() {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1");
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_SECRET, "client-secret");
|
||||||
|
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||||
|
assertThat(authentication.getPrincipal()).isEqualTo("client-1");
|
||||||
|
assertThat(authentication.getCredentials()).isEqualTo("client-secret");
|
||||||
|
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.POST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertWhenConfidentialClientWithPkceParametersThenAdditionalParametersIncluded() {
|
||||||
|
MockHttpServletRequest request = createPkceTokenRequest();
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1");
|
||||||
|
request.addParameter(OAuth2ParameterNames.CLIENT_SECRET, "client-secret");
|
||||||
|
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||||
|
assertThat(authentication.getPrincipal()).isEqualTo("client-1");
|
||||||
|
assertThat(authentication.getCredentials()).isEqualTo("client-secret");
|
||||||
|
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.POST);
|
||||||
|
assertThat(authentication.getAdditionalParameters())
|
||||||
|
.containsOnly(
|
||||||
|
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||||
|
entry(OAuth2ParameterNames.CODE, "code"),
|
||||||
|
entry(PkceParameterNames.CODE_VERIFIER, "code-verifier-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MockHttpServletRequest createPkceTokenRequest() {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.addParameter(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
||||||
|
request.addParameter(OAuth2ParameterNames.CODE, "code");
|
||||||
|
request.addParameter(PkceParameterNames.CODE_VERIFIER, "code-verifier-1");
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
|||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
@ -162,7 +163,7 @@ public class OAuth2ClientAuthenticationFilterTests {
|
|||||||
@Test
|
@Test
|
||||||
public void doFilterWhenRequestMatchesAndBadCredentialsThenInvalidClientError() throws Exception {
|
public void doFilterWhenRequestMatchesAndBadCredentialsThenInvalidClientError() throws Exception {
|
||||||
when(this.authenticationConverter.convert(any(HttpServletRequest.class))).thenReturn(
|
when(this.authenticationConverter.convert(any(HttpServletRequest.class))).thenReturn(
|
||||||
new OAuth2ClientAuthenticationToken("clientId", "invalid-secret", null));
|
new OAuth2ClientAuthenticationToken("clientId", "invalid-secret", ClientAuthenticationMethod.BASIC, null));
|
||||||
when(this.authenticationManager.authenticate(any(Authentication.class))).thenThrow(
|
when(this.authenticationManager.authenticate(any(Authentication.class))).thenThrow(
|
||||||
new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT)));
|
new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT)));
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ public class OAuth2ClientAuthenticationFilterTests {
|
|||||||
public void doFilterWhenRequestMatchesAndValidCredentialsThenProcessed() throws Exception {
|
public void doFilterWhenRequestMatchesAndValidCredentialsThenProcessed() throws Exception {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||||
when(this.authenticationConverter.convert(any(HttpServletRequest.class))).thenReturn(
|
when(this.authenticationConverter.convert(any(HttpServletRequest.class))).thenReturn(
|
||||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), registeredClient.getClientSecret(), null));
|
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), registeredClient.getClientSecret(), ClientAuthenticationMethod.BASIC, null));
|
||||||
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(
|
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(
|
||||||
new OAuth2ClientAuthenticationToken(registeredClient));
|
new OAuth2ClientAuthenticationToken(registeredClient));
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import org.junit.Test;
|
|||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
@ -82,6 +83,7 @@ public class PublicClientAuthenticationConverterTests {
|
|||||||
MockHttpServletRequest request = createPkceTokenRequest();
|
MockHttpServletRequest request = createPkceTokenRequest();
|
||||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||||
assertThat(authentication.getPrincipal()).isEqualTo("client-1");
|
assertThat(authentication.getPrincipal()).isEqualTo("client-1");
|
||||||
|
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.NONE);
|
||||||
assertThat(authentication.getAdditionalParameters())
|
assertThat(authentication.getAdditionalParameters())
|
||||||
.containsOnly(
|
.containsOnly(
|
||||||
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||||
|
Loading…
Reference in New Issue
Block a user