X509 client certificate authentication triggers when client id is provided
Closes gh-1635
This commit is contained in:
@@ -240,10 +240,10 @@ public final class OAuth2ClientAuthenticationConfigurer extends AbstractOAuth2Co
|
|||||||
List<AuthenticationConverter> authenticationConverters = new ArrayList<>();
|
List<AuthenticationConverter> authenticationConverters = new ArrayList<>();
|
||||||
|
|
||||||
authenticationConverters.add(new JwtClientAssertionAuthenticationConverter());
|
authenticationConverters.add(new JwtClientAssertionAuthenticationConverter());
|
||||||
authenticationConverters.add(new X509ClientCertificateAuthenticationConverter());
|
|
||||||
authenticationConverters.add(new ClientSecretBasicAuthenticationConverter());
|
authenticationConverters.add(new ClientSecretBasicAuthenticationConverter());
|
||||||
authenticationConverters.add(new ClientSecretPostAuthenticationConverter());
|
authenticationConverters.add(new ClientSecretPostAuthenticationConverter());
|
||||||
authenticationConverters.add(new PublicClientAuthenticationConverter());
|
authenticationConverters.add(new PublicClientAuthenticationConverter());
|
||||||
|
authenticationConverters.add(new X509ClientCertificateAuthenticationConverter());
|
||||||
|
|
||||||
return authenticationConverters;
|
return authenticationConverters;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,10 +114,10 @@ public final class OAuth2ClientAuthenticationFilter extends OncePerRequestFilter
|
|||||||
this.authenticationConverter = new DelegatingAuthenticationConverter(
|
this.authenticationConverter = new DelegatingAuthenticationConverter(
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
new JwtClientAssertionAuthenticationConverter(),
|
new JwtClientAssertionAuthenticationConverter(),
|
||||||
new X509ClientCertificateAuthenticationConverter(),
|
|
||||||
new ClientSecretBasicAuthenticationConverter(),
|
new ClientSecretBasicAuthenticationConverter(),
|
||||||
new ClientSecretPostAuthenticationConverter(),
|
new ClientSecretPostAuthenticationConverter(),
|
||||||
new PublicClientAuthenticationConverter()));
|
new PublicClientAuthenticationConverter(),
|
||||||
|
new X509ClientCertificateAuthenticationConverter()));
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,11 @@ public final class X509ClientCertificateAuthenticationConverter implements Authe
|
|||||||
|
|
||||||
// client_id (REQUIRED)
|
// client_id (REQUIRED)
|
||||||
String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);
|
String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);
|
||||||
if (!StringUtils.hasText(clientId) || parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
if (!StringUtils.hasText(clientId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
||||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST);
|
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -309,6 +309,28 @@ public class OAuth2ClientCredentialsGrantTests {
|
|||||||
verify(jwtCustomizer).customize(any());
|
verify(jwtCustomizer).customize(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-1635
|
||||||
|
@Test
|
||||||
|
public void requestWhenTokenRequestIncludesBasicClientCredentialsAndX509ClientCertificateThenTokenResponse()
|
||||||
|
throws Exception {
|
||||||
|
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||||
|
|
||||||
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
||||||
|
this.registeredClientRepository.save(registeredClient);
|
||||||
|
|
||||||
|
this.mvc
|
||||||
|
.perform(post(DEFAULT_TOKEN_ENDPOINT_URI).with(x509(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE))
|
||||||
|
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||||
|
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2")
|
||||||
|
.header(HttpHeaders.AUTHORIZATION,
|
||||||
|
"Basic " + encodeBasicAuth(registeredClient.getClientId(), registeredClient.getClientSecret())))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||||
|
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
|
||||||
|
|
||||||
|
verify(jwtCustomizer).customize(any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void requestWhenTokenEndpointCustomizedThenUsed() throws Exception {
|
public void requestWhenTokenEndpointCustomizedThenUsed() throws Exception {
|
||||||
this.spring.register(AuthorizationServerConfigurationCustomTokenEndpoint.class).autowire();
|
this.spring.register(AuthorizationServerConfigurationCustomTokenEndpoint.class).autowire();
|
||||||
@@ -394,10 +416,10 @@ public class OAuth2ClientCredentialsGrantTests {
|
|||||||
List<AuthenticationConverter> authenticationConverters = authenticationConvertersCaptor.getValue();
|
List<AuthenticationConverter> authenticationConverters = authenticationConvertersCaptor.getValue();
|
||||||
assertThat(authenticationConverters).allMatch((converter) -> converter == authenticationConverter
|
assertThat(authenticationConverters).allMatch((converter) -> converter == authenticationConverter
|
||||||
|| converter instanceof JwtClientAssertionAuthenticationConverter
|
|| converter instanceof JwtClientAssertionAuthenticationConverter
|
||||||
|| converter instanceof X509ClientCertificateAuthenticationConverter
|
|
||||||
|| converter instanceof ClientSecretBasicAuthenticationConverter
|
|| converter instanceof ClientSecretBasicAuthenticationConverter
|
||||||
|| converter instanceof ClientSecretPostAuthenticationConverter
|
|| converter instanceof ClientSecretPostAuthenticationConverter
|
||||||
|| converter instanceof PublicClientAuthenticationConverter);
|
|| converter instanceof PublicClientAuthenticationConverter
|
||||||
|
|| converter instanceof X509ClientCertificateAuthenticationConverter);
|
||||||
|
|
||||||
verify(authenticationProvider).authenticate(eq(clientPrincipal));
|
verify(authenticationProvider).authenticate(eq(clientPrincipal));
|
||||||
|
|
||||||
|
|||||||
@@ -58,14 +58,12 @@ public class X509ClientCertificateAuthenticationConverterTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void convertWhenMissingClientIdThenInvalidRequestError() {
|
public void convertWhenMissingClientIdThenReturnNull() {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
request.setAttribute("jakarta.servlet.request.X509Certificate",
|
request.setAttribute("jakarta.servlet.request.X509Certificate",
|
||||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
||||||
assertThatThrownBy(() -> this.converter.convert(request)).isInstanceOf(OAuth2AuthenticationException.class)
|
Authentication authentication = this.converter.convert(request);
|
||||||
.extracting((ex) -> ((OAuth2AuthenticationException) ex).getError())
|
assertThat(authentication).isNull();
|
||||||
.extracting("errorCode")
|
|
||||||
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user