PKCE should return error if code_verifier sent but no code_challenge in the authorization request
Closes #26430 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
5401c63c9e
commit
720c5c6576
3 changed files with 35 additions and 1 deletions
|
@ -84,6 +84,12 @@ public class PkceUtils {
|
||||||
throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "PKCE code verifier not specified", Response.Status.BAD_REQUEST);
|
throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "PKCE code verifier not specified", Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (codeChallenge == null && codeVerifier != null) {
|
||||||
|
logger.warnf("PKCE code verifier specified but challenge not present in authorization, authUserId = %s, authUsername = %s", authUserId, authUsername);
|
||||||
|
event.error(Errors.INVALID_CODE_VERIFIER);
|
||||||
|
throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "PKCE code verifier specified but challenge not present in authorization", Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
if (codeChallenge != null) {
|
if (codeChallenge != null) {
|
||||||
verifyCodeVerifier(codeVerifier, codeChallenge, codeChallengeMethod, authUserId, authUsername, event, cors);
|
verifyCodeVerifier(codeVerifier, codeChallenge, codeChallengeMethod, authUserId, authUsername, event, cors);
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,9 @@ public abstract class AbstractFAPITest extends AbstractClientPoliciesTest {
|
||||||
List<NameValuePair> parameters = new LinkedList<>();
|
List<NameValuePair> parameters = new LinkedList<>();
|
||||||
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
|
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
|
||||||
parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
|
parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
|
||||||
parameters.add(new BasicNameValuePair(OAuth2Constants.CODE_VERIFIER, codeVerifier));
|
if (codeVerifier != null) {
|
||||||
|
parameters.add(new BasicNameValuePair(OAuth2Constants.CODE_VERIFIER, codeVerifier));
|
||||||
|
}
|
||||||
parameters.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, oauth.getRedirectUri()));
|
parameters.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, oauth.getRedirectUri()));
|
||||||
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
|
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
|
||||||
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, signedJwt));
|
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, signedJwt));
|
||||||
|
|
|
@ -404,6 +404,32 @@ public class OAuthProofKeyForCodeExchangeTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
events.expectCodeToToken(codeId, sessionId).error(Errors.INVALID_CODE_VERIFIER).clearDetails().assertEvent();
|
events.expectCodeToToken(codeId, sessionId).error(Errors.INVALID_CODE_VERIFIER).clearDetails().assertEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void accessTokenRequestInPKCECodeVerifierWithNoCodeChallenge() throws Exception {
|
||||||
|
String codeVerifier = "12345678e01234567890g2345678h012a4567j90123"; // 43
|
||||||
|
|
||||||
|
// send oauth request without code_challenge because intercepted
|
||||||
|
oauth.codeChallenge(null);
|
||||||
|
oauth.codeChallengeMethod(null);
|
||||||
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
|
||||||
|
EventRepresentation loginEvent = events.expectLogin().assertEvent();
|
||||||
|
String sessionId = loginEvent.getSessionId();
|
||||||
|
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||||
|
|
||||||
|
// get the code and add codeVerifier
|
||||||
|
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||||
|
oauth.codeVerifier(codeVerifier);
|
||||||
|
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||||
|
|
||||||
|
// assert invalid code because no challenge in authorization
|
||||||
|
assertEquals(400, response.getStatusCode());
|
||||||
|
assertEquals(OAuthErrorException.INVALID_GRANT, response.getError());
|
||||||
|
assertEquals("PKCE code verifier specified but challenge not present in authorization", response.getErrorDescription());
|
||||||
|
|
||||||
|
events.expectCodeToToken(codeId, sessionId).error(Errors.INVALID_CODE_VERIFIER).clearDetails().assertEvent();
|
||||||
|
}
|
||||||
|
|
||||||
private String generateS256CodeChallenge(String codeVerifier) throws Exception {
|
private String generateS256CodeChallenge(String codeVerifier) throws Exception {
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||||
|
|
Loading…
Reference in a new issue