[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