diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/CodeVerifierAuthenticator.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/CodeVerifierAuthenticator.java index 71a293126..df3ff81a9 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/CodeVerifierAuthenticator.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/CodeVerifierAuthenticator.java @@ -137,11 +137,14 @@ private boolean authenticate(OAuth2ClientAuthenticationToken clientAuthenticatio } private static boolean authorizationCodeGrant(Map parameters) { - // @formatter:off - return AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals( - parameters.get(OAuth2ParameterNames.GRANT_TYPE)) && - parameters.get(OAuth2ParameterNames.CODE) != null; - // @formatter:on + if (!AuthorizationGrantType.AUTHORIZATION_CODE.getValue() + .equals(parameters.get(OAuth2ParameterNames.GRANT_TYPE))) { + return false; + } + if (!StringUtils.hasText((String) parameters.get(OAuth2ParameterNames.CODE))) { + throwInvalidGrant(OAuth2ParameterNames.CODE); + } + return true; } private boolean codeVerifierValid(String codeVerifier, String codeChallenge, String codeChallengeMethod) { diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java index bf0258942..d794baf5e 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java @@ -515,6 +515,28 @@ public void requestWhenPublicClientWithPkceAndCustomRefreshTokenGeneratorThenRet .isEqualTo(true); } + // gh-1680 + @Test + public void requestWhenPublicClientWithPkceAndEmptyCodeThenBadRequest() throws Exception { + this.spring.register(AuthorizationServerConfiguration.class).autowire(); + + RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build(); + this.registeredClientRepository.save(registeredClient); + + MultiValueMap tokenRequestParameters = new LinkedMultiValueMap<>(); + tokenRequestParameters.set(OAuth2ParameterNames.GRANT_TYPE, + AuthorizationGrantType.AUTHORIZATION_CODE.getValue()); + tokenRequestParameters.set(OAuth2ParameterNames.CODE, ""); + tokenRequestParameters.set(OAuth2ParameterNames.REDIRECT_URI, + registeredClient.getRedirectUris().iterator().next()); + + this.mvc + .perform(post(DEFAULT_TOKEN_ENDPOINT_URI).params(tokenRequestParameters) + .param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId()) + .param(PkceParameterNames.CODE_VERIFIER, S256_CODE_VERIFIER)) + .andExpect(status().isBadRequest()); + } + @Test public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenBadRequest() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire();