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(