From 5faa467e302d9dfb0dfc640518c08e28af5b2d07 Mon Sep 17 00:00:00 2001 From: Thomas Diesler Date: Mon, 27 Apr 2026 16:23:46 +0200 Subject: [PATCH] [OID4VCI-FAPI2] SecureRequestObjectExecutor fails on PAR closes #48506 Signed-off-by: Thomas Diesler --- .../executor/SecureRequestObjectExecutor.java | 21 ++++++++++++------- .../policies/ClientPoliciesExecutorTest.java | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/services/src/main/java/org/keycloak/services/clientpolicy/executor/SecureRequestObjectExecutor.java b/services/src/main/java/org/keycloak/services/clientpolicy/executor/SecureRequestObjectExecutor.java index 6899d39aec1d..a3b97dccf077 100644 --- a/services/src/main/java/org/keycloak/services/clientpolicy/executor/SecureRequestObjectExecutor.java +++ b/services/src/main/java/org/keycloak/services/clientpolicy/executor/SecureRequestObjectExecutor.java @@ -28,6 +28,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.endpoints.request.AuthzEndpointRequestParser; +import org.keycloak.protocol.oidc.endpoints.request.RequestUriType; import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation; import org.keycloak.services.Urls; import org.keycloak.services.clientpolicy.ClientPolicyContext; @@ -39,6 +40,7 @@ import org.jboss.logging.Logger; import static org.keycloak.OAuthErrorException.INVALID_REQUEST_OBJECT; +import static org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequestParserProcessor.getRequestUriType; /** * @author Takashi Norimatsu @@ -48,7 +50,7 @@ public class SecureRequestObjectExecutor implements ClientPolicyExecutorProvider private static final Logger logger = Logger.getLogger(SecureRequestObjectExecutor.class); public static final Integer DEFAULT_AVAILABLE_PERIOD = Integer.valueOf(3600); // (sec) from FAPI 1.0 Advanced requirement - public static final Integer DEAULT_ALLOWED_CLOCK_SKEW = Integer.valueOf(15); // (sec) from FAPI 2.0 requirement + public static final Integer DEFAULT_ALLOWED_CLOCK_SKEW = Integer.valueOf(15); // (sec) from FAPI 2.0 requirement private final KeycloakSession session; private Configuration configuration; @@ -64,7 +66,7 @@ public void setupConfiguration(SecureRequestObjectExecutor.Configuration config) configuration.setVerifyNbf(Boolean.TRUE); configuration.setAvailablePeriod(DEFAULT_AVAILABLE_PERIOD); configuration.setEncryptionRequired(Boolean.FALSE); - configuration.setAllowedClockSkew(DEAULT_ALLOWED_CLOCK_SKEW); + configuration.setAllowedClockSkew(DEFAULT_ALLOWED_CLOCK_SKEW); } else { configuration = config; if (config.isVerifyNbf() == null) { @@ -77,7 +79,7 @@ public void setupConfiguration(SecureRequestObjectExecutor.Configuration config) configuration.setEncryptionRequired(Boolean.FALSE); } if (config.getAllowedClockSkew() == null) { - configuration.setAllowedClockSkew(DEAULT_ALLOWED_CLOCK_SKEW); + configuration.setAllowedClockSkew(DEFAULT_ALLOWED_CLOCK_SKEW); } } } @@ -160,7 +162,7 @@ private void executeOnAuthorizationRequest(AuthorizationRequestContext context) String requestParam = params.getFirst(OIDCLoginProtocol.REQUEST_PARAM); String requestUriParam = params.getFirst(OIDCLoginProtocol.REQUEST_URI_PARAM); - // check whether whether request object exists + // check whether the request object exists if (requestParam == null && requestUriParam == null) { logger.trace("request object not exist."); throwClientPolicyException(OAuthErrorException.INVALID_REQUEST, "Missing parameter: 'request' or 'request_uri'", @@ -171,8 +173,13 @@ private void executeOnAuthorizationRequest(AuthorizationRequestContext context) // check whether request object exists if (requestObject == null || requestObject.isEmpty()) { + RequestUriType requestUriType = getRequestUriType(requestUriParam); + if (requestUriType == RequestUriType.PAR) { + logger.trace("Nothing to do for 'request_uri' type PAR"); + return; + } logger.trace("request object not exist."); - throwClientPolicyException(OAuthErrorException.INVALID_REQUEST, "Invalid parameter: : 'request' or 'request_uri'", + throwClientPolicyException(OAuthErrorException.INVALID_REQUEST, "Empty parameter: 'request'", context); } @@ -185,7 +192,7 @@ private void executeOnAuthorizationRequest(AuthorizationRequestContext context) // check whether "exp" claim exists if (requestObject.get("exp") == null) { - logger.trace("exp claim not incuded."); + logger.trace("exp claim not included."); throwClientPolicyException(INVALID_REQUEST_OBJECT, "Missing parameter in the 'request' object: exp", context); } @@ -289,4 +296,4 @@ private void throwClientPolicyException(String error, String message, throw new ClientPolicyException(error, message); } -} \ No newline at end of file +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/policies/ClientPoliciesExecutorTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/policies/ClientPoliciesExecutorTest.java index 0acdda4bc51b..9c4c18d5f9cf 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/policies/ClientPoliciesExecutorTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/policies/ClientPoliciesExecutorTest.java @@ -480,7 +480,7 @@ public void testSecureResponseTypeExecutorAllowTokenResponseType() throws Except @Test public void testSecureRequestObjectExecutor() throws Exception { Integer availablePeriod = SecureRequestObjectExecutor.DEFAULT_AVAILABLE_PERIOD + 400; - Integer allowedClockSkew = SecureRequestObjectExecutor.DEAULT_ALLOWED_CLOCK_SKEW + 15; // 30 sec + Integer allowedClockSkew = SecureRequestObjectExecutor.DEFAULT_ALLOWED_CLOCK_SKEW + 15; // 30 sec // register profiles String json = (new ClientProfilesBuilder()).addProfile(