[java-idp-oidc] 02/02: JOIDC-200 - Support for OAuth2 Pushed Authorization Requests (PAR)

Henri Mikkonen henri.mikkonen at iki.fi
Wed Oct 2 12:36:42 UTC 2024


This is an automated email from the git hooks/post-receive script.

hjmikkon pushed a commit to branch main
in repository java-idp-oidc.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=caa7f58c252c8c583c26f9bb7e815257f601bb9d

commit caa7f58c252c8c583c26f9bb7e815257f601bb9d
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Oct 2 15:36:11 2024 +0300

    JOIDC-200 - Support for OAuth2 Pushed Authorization Requests (PAR)
    
    https://shibboleth.atlassian.net/browse/JOIDC-200
    
    Wired the strict scope validation to the PAR flow.
    - The allowed scope lookup strategy may be customized via 'shibboleth.oauth2.par.AllowedScopeStrategy'
---
 .../pushed-authorization-beans.xml                 | 20 ++++++++---
 .../pushed-authorization-flow.xml                  |  1 +
 .../op/profile/flow/PushedAuthorizeFlowTest.java   | 42 +++++++++++++++++++++-
 .../flow/PushedAuthorizeRequestObjectJWETest.java  |  4 +--
 .../flow/PushedAuthorizeRequestObjectJWSTest.java  |  4 +--
 5 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-beans.xml
index d7547fc6..91721d52 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-beans.xml
@@ -280,13 +280,14 @@
         </property>
     </bean>
 
+    <bean id="RequestResponseTypeLookupFunction"
+        class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.DefaultRequestResponseTypeLookupFunction"
+        p:useOnlyRequestObjectPredicate-ref="#{'%{idp.oauth2.par.useOnlyRequestObject:DefaultParUseOnlyRequestObjectCondition}'.trim()}"/>
+    
     <bean id="ValidateResponseType" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateResponseType"
         scope="prototype"
-        p:unregisteredClientPolicyEnforcer="#{getObject('shibboleth.oidc.UnregisteredClientPolicyEnforcer') ?: getObject('shibboleth.oidc.DefaultUnregisteredClientPolicyEnforcer')}">
-        <property name="requestedResponseTypeLookupStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.DefaultRequestResponseTypeLookupFunction"
-                p:useOnlyRequestObjectPredicate-ref="#{'%{idp.oauth2.par.useOnlyRequestObject:DefaultParUseOnlyRequestObjectCondition}'.trim()}"/>
-        </property>
+        p:unregisteredClientPolicyEnforcer="#{getObject('shibboleth.oidc.UnregisteredClientPolicyEnforcer') ?: getObject('shibboleth.oidc.DefaultUnregisteredClientPolicyEnforcer')}"
+        p:requestedResponseTypeLookupStrategy-ref="RequestResponseTypeLookupFunction">
         <property name="validResponseTypesLookupStrategy">
             <bean class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.DefaultValidResponseTypesLookupFunction"/>            
         </property>
@@ -320,6 +321,15 @@
         </property>
     </bean>
 
+    <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateScope" scope="prototype"
+        p:allowedScopeLookupStrategy="#{getObject('shibboleth.oauth2.par.AllowedScopeStrategy') ?: getObject('shibboleth.oidc.DefaultAllowedScopeStrategy')}"
+        p:requestedResponseTypeLookupStrategy-ref="RequestResponseTypeLookupFunction">
+        <property name="requestedScopeLookupStrategy">
+            <bean class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.DefaultRequestedScopeLookupFunction"
+                p:useOnlyRequestObjectPredicate-ref="#{'%{idp.oauth2.par.useOnlyRequestObject:DefaultParUseOnlyRequestObjectCondition}'.trim()}"/>
+        </property>
+    </bean>
+
     <bean id="FormOutboundMessage"
         class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.FormOutbounPushedAuthorizationResponseMessage"
         scope="prototype"
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-flow.xml
index e688874b..496a74a9 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-flow.xml
@@ -42,6 +42,7 @@
         <evaluate expression="ValidateResponseMode" />
         <evaluate expression="ValidateCodeChallenge" />
         <evaluate expression="StoreDPoPProofKeyThumbprint" />
+        <evaluate expression="ValidateScope" />
         <evaluate expression="'proceed'" />
         
         <transition on="proceed" to="BuildResponseMessage" />
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeFlowTest.java
index 82714ccf..0386ef9e 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeFlowTest.java
@@ -155,7 +155,7 @@ public class PushedAuthorizeFlowTest extends AbstractOidcClientAuthenticationFlo
             URISyntaxException, DataSealerException, ComponentInitializationException {
         final String clientId = "policyAcceptedClient1";
         setBasicAuth(clientId, clientSecret);
-        setHttpFormRequest("POST", createRequestParameters(clientId));
+        setHttpFormRequest("POST", createRequestParameters(clientId, "openid", "code", null));
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
         assertSuccessResponse(result, clientId);
         final PushedAuthorizationSuccessResponse response =
@@ -163,6 +163,16 @@ public class PushedAuthorizeFlowTest extends AbstractOidcClientAuthenticationFlo
         verifyAuthorizeEndpoint(clientId, response.getRequestURI().toString());
     }
 
+    @Test
+    public void testFailureUnverified_wrongRequestedScope() throws IOException, NoSuchAlgorithmException,
+            URISyntaxException, DataSealerException, ComponentInitializationException {
+        final String clientId = "policyAcceptedClient1";
+        setBasicAuth(clientId, clientSecret);
+        setHttpFormRequest("POST", createRequestParameters(clientId, "openid unAllowed", "code", null));
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, OAuth2Error.INVALID_SCOPE_CODE);
+    }
+
     @Test
     public void testSuccess() throws IOException, NoSuchAlgorithmException, URISyntaxException, DataSealerException,
             ComponentInitializationException {
@@ -178,6 +188,16 @@ public class PushedAuthorizeFlowTest extends AbstractOidcClientAuthenticationFlo
         }
     }
 
+    @Test
+    public void testFailure_unregisteredScope() throws IOException, NoSuchAlgorithmException, URISyntaxException, DataSealerException,
+            ComponentInitializationException {
+        storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org/cb");
+        setBasicAuth(clientId, clientSecret);
+        setHttpFormRequest("POST", createRequestParameters(clientId, "openid unAllowed", "code", null));
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, OAuth2Error.INVALID_SCOPE_CODE);
+    }
+
     @Test
     public void testSuccessWithPostAuth() throws IOException, NoSuchAlgorithmException, URISyntaxException,
             DataSealerException, ComponentInitializationException {
@@ -402,6 +422,26 @@ public class PushedAuthorizeFlowTest extends AbstractOidcClientAuthenticationFlo
         verifyAuthorizeEndpoint(clientId, response.getRequestURI().toString());
     }
 
+    @Test
+    public void testNonRegisteredScopeInRO() throws IOException, NoSuchAlgorithmException, URISyntaxException,
+            DataSealerException, ComponentInitializationException, JOSEException {
+        storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org/cb");
+        setBasicAuth(clientId, clientSecret);
+        final JWTClaimsSet ro = new JWTClaimsSet.Builder()
+                .claim("iss", clientId)
+                .claim("client_id", clientId)
+                .claim("aud", issuer)
+                .claim("response_type", "code")
+                .claim("redirect_uri", "https://example.org/cb")
+                .claim("scope", "openid profile notAllowed")
+                .build();
+        final SignedJWT requestObject = createSecretJWT(ro, clientSecret);
+        setHttpFormRequest("POST", createRequestParameters(clientId, null, null,
+                requestObject.serialize()));
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, OAuth2Error.INVALID_SCOPE_CODE);
+    }
+
     @Test
     public void testOAuth2NoResponseType() throws IOException, NoSuchAlgorithmException, URISyntaxException,
             DataSealerException, ComponentInitializationException {
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeRequestObjectJWETest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeRequestObjectJWETest.java
index a6b1de98..e780f379 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeRequestObjectJWETest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeRequestObjectJWETest.java
@@ -227,7 +227,7 @@ public class PushedAuthorizeRequestObjectJWETest extends IssuedEncryptedJWTTest
         }
         requestParams.put("request", requestObject);
 
-        metadata.setScope(new Scope("openid"));
+        metadata.setScope(Scope.parse("openid profile offline_access"));
         metadata.setRequestObjectJWSAlg(requestObjectSigAlg);
         metadata.setRequestObjectJWEAlg(requestObjectEncAlg);
         metadata.setRequestObjectJWEEnc(requestObjectEncMethod);
@@ -261,7 +261,7 @@ public class PushedAuthorizeRequestObjectJWETest extends IssuedEncryptedJWTTest
         } else {
             return;
         }
-        metadata.setScope(new Scope("openid"));
+        metadata.setScope(Scope.parse("openid profile offline_access"));
         metadata.setRequestObjectJWSAlg(requestObjectSigAlg);
         metadata.setRequestObjectJWEAlg(requestObjectEncAlg);
         metadata.setRequestObjectJWEEnc(requestObjectEncMethod);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeRequestObjectJWSTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeRequestObjectJWSTest.java
index 63d38a81..1af07e74 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeRequestObjectJWSTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeRequestObjectJWSTest.java
@@ -104,7 +104,7 @@ public class PushedAuthorizeRequestObjectJWSTest extends IssuedSignedJWTTest {
             return;
         }
         requestParams.put("request", requestObject);
-        metadata.setScope(new Scope("openid"));
+        metadata.setScope(Scope.parse("openid profile offline_access"));
         metadata.setRequestObjectJWSAlg(requestObjectSigAlg);
         if (publicKey != null) {
             metadata.setJWKSet(super.buildJWKSet(publicKey));
@@ -129,7 +129,7 @@ public class PushedAuthorizeRequestObjectJWSTest extends IssuedSignedJWTTest {
         final Map<String, String> requestParams = PushedAuthorizeFlowTest.createRequestParameters(clientId);
 
         final OIDCClientMetadata metadata = buildMetadataSkeleton();
-        metadata.setScope(new Scope("openid"));
+        metadata.setScope(Scope.parse("openid profile offline_access"));
         metadata.setRequestObjectJWSAlg(requestObjectSigAlg);
         if (clientSecret != null) {
             requestParams.put("client_secret", clientSecret);

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list