From a19a3a1a783687e73ef1cee00e1f3fc078333849 Mon Sep 17 00:00:00 2001 From: Felix Hellman Date: Fri, 17 Nov 2023 09:24:46 +0100 Subject: [PATCH] Adds paramater name to JwtClientAssertion validation error Fixes gh-1449 --- .../JwtClientAssertionAuthenticationConverter.java | 14 ++++++++++---- ...lientAssertionAuthenticationConverterTests.java | 11 ++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/JwtClientAssertionAuthenticationConverter.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/JwtClientAssertionAuthenticationConverter.java index ce6118d5bb..3b0d26ca08 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/JwtClientAssertionAuthenticationConverter.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/JwtClientAssertionAuthenticationConverter.java @@ -19,10 +19,13 @@ import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.lang.Nullable; 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; @@ -44,7 +47,6 @@ public final class JwtClientAssertionAuthenticationConverter implements AuthenticationConverter { private static final ClientAuthenticationMethod JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD = new ClientAuthenticationMethod("urn:ietf:params:oauth:client-assertion-type:jwt-bearer"); - @Nullable @Override public Authentication convert(HttpServletRequest request) { @@ -58,7 +60,7 @@ public Authentication convert(HttpServletRequest request) { // client_assertion_type (REQUIRED) String clientAssertionType = parameters.getFirst(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE); if (parameters.get(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE).size() != 1) { - throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST); + throwException(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE); } if (!JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD.getValue().equals(clientAssertionType)) { return null; @@ -67,14 +69,14 @@ public Authentication convert(HttpServletRequest request) { // client_assertion (REQUIRED) String jwtAssertion = parameters.getFirst(OAuth2ParameterNames.CLIENT_ASSERTION); if (parameters.get(OAuth2ParameterNames.CLIENT_ASSERTION).size() != 1) { - throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST); + throwException(OAuth2ParameterNames.CLIENT_ASSERTION); } // client_id (OPTIONAL as per specification but REQUIRED by this implementation) String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID); if (!StringUtils.hasText(clientId) || parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) { - throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST); + throwException(OAuth2ParameterNames.CLIENT_ID); } Map additionalParameters = OAuth2EndpointUtils.getParametersIfMatchesAuthorizationCodeGrantRequest(request, @@ -86,4 +88,8 @@ public Authentication convert(HttpServletRequest request) { jwtAssertion, additionalParameters); } + public void throwException(String parameterName) { + throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST), "Required parameter %s is missing or invalid".formatted(parameterName)); + } + } diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/authentication/JwtClientAssertionAuthenticationConverterTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/authentication/JwtClientAssertionAuthenticationConverterTests.java index 13fb648841..d55f2b35bb 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/authentication/JwtClientAssertionAuthenticationConverterTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/authentication/JwtClientAssertionAuthenticationConverterTests.java @@ -60,7 +60,7 @@ public void convertWhenMultipleClientAssertionTypeThenInvalidRequestError() { request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, JWT_BEARER_TYPE); request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, "other-client-assertion-type"); request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION, "jwt-assertion"); - assertThrown(request, OAuth2ErrorCodes.INVALID_REQUEST); + assertThrown(request, OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ASSERTION_TYPE); } @Test @@ -78,7 +78,7 @@ public void convertWhenMultipleClientAssertionThenInvalidRequestError() { request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, JWT_BEARER_TYPE); request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION, "jwt-assertion"); request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION, "other-jwt-assertion"); - assertThrown(request, OAuth2ErrorCodes.INVALID_REQUEST); + assertThrown(request, OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ASSERTION); } @Test @@ -86,7 +86,7 @@ public void convertWhenMissingClientIdThenInvalidRequestError() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, JWT_BEARER_TYPE); request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION, "jwt-assertion"); - assertThrown(request, OAuth2ErrorCodes.INVALID_REQUEST); + assertThrown(request, OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID); } @Test @@ -96,7 +96,7 @@ public void convertWhenMultipleClientIdThenInvalidRequestError() { request.addParameter(OAuth2ParameterNames.CLIENT_ASSERTION, "jwt-assertion"); request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1"); request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-2"); - assertThrown(request, OAuth2ErrorCodes.INVALID_REQUEST); + assertThrown(request, OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID); } @Test @@ -121,9 +121,10 @@ public void convertWhenJwtAssertionThenReturnClientAuthenticationToken() { entry("custom-param-2", new String[] {"custom-value-1", "custom-value-2"})); } - private void assertThrown(MockHttpServletRequest request, String errorCode) { + private void assertThrown(MockHttpServletRequest request, String errorCode, String parameter) { assertThatThrownBy(() -> this.converter.convert(request)) .isInstanceOf(OAuth2AuthenticationException.class) + .hasMessageContaining(parameter) .extracting(ex -> ((OAuth2AuthenticationException) ex).getError()) .extracting("errorCode") .isEqualTo(errorCode);