Throw invalid_grant when invalid token request with PKCE

Closes gh-581
This commit is contained in:
Daniel Garnier-Moiroux
2022-01-17 14:37:48 +01:00
committed by Joe Grandja
parent 4d5b288116
commit a1e513b35d
3 changed files with 23 additions and 13 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* Copyright 2020-2022 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.
@@ -228,7 +228,7 @@ public final class OAuth2ClientAuthenticationProvider implements AuthenticationP
(String) parameters.get(OAuth2ParameterNames.CODE),
AUTHORIZATION_CODE_TOKEN_TYPE);
if (authorization == null) {
throwInvalidClient(OAuth2ParameterNames.CODE);
throwInvalidGrant(OAuth2ParameterNames.CODE);
}
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
@@ -238,7 +238,7 @@ public final class OAuth2ClientAuthenticationProvider implements AuthenticationP
.get(PkceParameterNames.CODE_CHALLENGE);
if (!StringUtils.hasText(codeChallenge)) {
if (registeredClient.getClientSettings().isRequireProofKey()) {
throwInvalidClient(PkceParameterNames.CODE_CHALLENGE);
throwInvalidGrant(PkceParameterNames.CODE_CHALLENGE);
} else {
return false;
}
@@ -248,7 +248,7 @@ public final class OAuth2ClientAuthenticationProvider implements AuthenticationP
.get(PkceParameterNames.CODE_CHALLENGE_METHOD);
String codeVerifier = (String) parameters.get(PkceParameterNames.CODE_VERIFIER);
if (!codeVerifierValid(codeVerifier, codeChallenge, codeChallengeMethod)) {
throwInvalidClient(PkceParameterNames.CODE_VERIFIER);
throwInvalidGrant(PkceParameterNames.CODE_VERIFIER);
}
return true;
@@ -291,10 +291,20 @@ public final class OAuth2ClientAuthenticationProvider implements AuthenticationP
throw new OAuth2AuthenticationException(error, error.toString(), cause);
}
private static void throwInvalidGrant(String parameterName) {
OAuth2Error error = new OAuth2Error(
OAuth2ErrorCodes.INVALID_GRANT,
"Client authentication failed: " + parameterName,
null
);
throw new OAuth2AuthenticationException(error);
}
private static class JwtClientAssertionDecoderFactory implements JwtDecoderFactory<RegisteredClient> {
private static final String JWT_CLIENT_AUTHENTICATION_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc7523#section-3";
private static final Map<JwsAlgorithm, String> JCA_ALGORITHM_MAPPINGS;
static {
Map<JwsAlgorithm, String> mappings = new HashMap<>();
mappings.put(MacAlgorithm.HS256, "HmacSHA256");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* Copyright 2020-2022 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.
@@ -396,7 +396,7 @@ public class OAuth2AuthorizationCodeGrantTests {
}
@Test
public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenUnauthorized() throws Exception {
public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenBadRequest() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
@@ -421,7 +421,7 @@ public class OAuth2AuthorizationCodeGrantTests {
.params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization))
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
.header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(registeredClient)))
.andExpect(status().isUnauthorized());
.andExpect(status().isBadRequest());
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* Copyright 2020-2022 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.
@@ -279,7 +279,7 @@ public class OAuth2ClientAuthenticationProviderTests {
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
.satisfies(error -> {
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
assertThat(error.getDescription()).contains(OAuth2ParameterNames.CODE);
});
}
@@ -305,7 +305,7 @@ public class OAuth2ClientAuthenticationProviderTests {
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
.satisfies(error -> {
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
});
}
@@ -331,7 +331,7 @@ public class OAuth2ClientAuthenticationProviderTests {
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
.satisfies(error -> {
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
});
}
@@ -357,7 +357,7 @@ public class OAuth2ClientAuthenticationProviderTests {
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
.satisfies(error -> {
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
});
}
@@ -383,7 +383,7 @@ public class OAuth2ClientAuthenticationProviderTests {
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
.satisfies(error -> {
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
});
}