[java-idp-oidc] branch main updated: JOIDC-73 - Add validation of request_uri
Scott Cantor
cantor.2 at osu.edu
Fri Jan 28 18:29:30 UTC 2022
This is an automated email from the git hooks/post-receive script.
scantor 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=300cb7ad16ccd543291c3de0fd4962b1f9f7d412
The following commit(s) were added to refs/heads/main by this push:
new 300cb7ad JOIDC-73 - Add validation of request_uri
300cb7ad is described below
commit 300cb7ad16ccd543291c3de0fd4962b1f9f7d412
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Jan 28 13:29:27 2022 -0500
JOIDC-73 - Add validation of request_uri
https://shibboleth.atlassian.net/browse/JOIDC-73
---
.../impl/SetRequestObjectToResponseContext.java | 32 +++++-
.../oidc/op/static/openid-configuration.json | 2 +-
.../SetRequestObjectToResponseContextTest.java | 126 +++++++++++++++++++++
3 files changed, 156 insertions(+), 4 deletions(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContext.java
index 9c0bf1c0..2364de01 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContext.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContext.java
@@ -18,7 +18,10 @@
package net.shibboleth.idp.plugin.oidc.op.profile.impl;
import java.io.IOException;
+import java.net.URI;
import java.text.ParseException;
+import java.util.Set;
+
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.http.HttpResponse;
@@ -35,6 +38,7 @@ import org.opensaml.security.httpclient.HttpClientSecuritySupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nimbusds.jwt.JWTParser;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
import net.shibboleth.idp.plugin.oidc.op.profile.OidcEventIds;
@@ -44,14 +48,13 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/**
* Action that stored request object to {@link OIDCAuthenticationResponseContext}. The request
- * object may be given by value with request parameter or by reference with
- * request_uri parameter.
+ * object may be given by value with request parameter or by reference with request_uri parameter.
*/
public class SetRequestObjectToResponseContext extends AbstractOIDCAuthenticationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(SetRequestObjectToResponseContext.class);
-
+
/** HTTP Client used to post the data. */
@NonnullAfterInit private HttpClient httpClient;
@@ -106,16 +109,19 @@ public class SetRequestObjectToResponseContext extends AbstractOIDCAuthenticatio
if (!super.doPreExecute(profileRequestContext)) {
return false;
}
+
if (!getAuthenticationRequest().specifiesRequestObject()) {
log.debug("{} No request_uri or request by value, nothing to do", getLogPrefix());
return false;
}
+
if (getAuthenticationRequest().getRequestObject() != null
&& getAuthenticationRequest().getRequestURI() != null) {
log.error("{} request_uri and request object cannot be both set", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.REQUEST_OBJECT_AND_URI);
return false;
}
+
return true;
}
@@ -128,6 +134,26 @@ public class SetRequestObjectToResponseContext extends AbstractOIDCAuthenticatio
getOidcResponseContext().getRequestObject().serialize());
return;
}
+
+ // Request URI must be found in metadata.
+ boolean authorized = false;
+ if (getMetadataContext().getClientInformation() != null) {
+ final OIDCClientMetadata metadata = getMetadataContext().getClientInformation().getOIDCMetadata();
+ if (metadata != null) {
+ final Set<URI> allowedURIs = metadata.getRequestObjectURIs();
+ if (allowedURIs != null) {
+ authorized = allowedURIs.contains(getAuthenticationRequest().getRequestURI());
+ }
+ }
+ }
+
+ if (!authorized) {
+ log.error("{} Unregistered request URI blocked: {}", getLogPrefix(),
+ getAuthenticationRequest().getRequestURI());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_REQUEST_URI);
+ return;
+ }
+
final HttpGet httpRequest = new HttpGet(getAuthenticationRequest().getRequestURI());
final HttpClientContext httpContext = buildHttpContext(httpRequest);
try {
diff --git a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/static/openid-configuration.json b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/static/openid-configuration.json
index 32010b07..a78991c2 100644
--- a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/static/openid-configuration.json
+++ b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/static/openid-configuration.json
@@ -89,7 +89,7 @@
"claims_parameter_supported":true,
"request_parameter_supported":true,
"request_uri_parameter_supported":true,
- "require_request_uri_registration":false,
+ "require_request_uri_registration":true,
"display_values_supported":[
"page"
],
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContextTest.java
new file mode 100644
index 00000000..fe4a5407
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContextTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.OidcEventIds;
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+import net.shibboleth.utilities.java.support.httpclient.HttpClientBuilder;
+import net.shibboleth.utilities.java.support.httpclient.HttpClientSupport;
+import net.shibboleth.utilities.java.support.test.repository.RepositorySupport;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Set;
+
+import org.springframework.webflow.execution.Event;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.net.UrlEscapers;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.PlainJWT;
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+/** {@link SetRequestObjectToResponseContext} unit test. */
+public class SetRequestObjectToResponseContextTest extends BaseOIDCResponseActionTest {
+
+ /** Action. */
+ private SetRequestObjectToResponseContext action;
+
+ /** Init. */
+ @BeforeMethod
+ public void setUp() throws Exception {
+ super.setUp();
+
+ action = new SetRequestObjectToResponseContext();
+ final HttpClientBuilder builder = new HttpClientBuilder();
+ builder.setTLSSocketFactory(HttpClientSupport.buildNoTrustTLSSocketFactory());
+ action.setHttpClient(builder.buildClient());
+ action.initialize();
+ }
+
+ /** Test when no request object or URI is used. */
+ @Test
+ public void testNothingToDo() {
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ /**
+ * Test on request object.
+ *
+ * @throws ParseException
+ */
+ @Test
+ public void testRequestObject() throws ParseException {
+ final JWTClaimsSet ro = new JWTClaimsSet.Builder()
+ .claim("redirect_uri", "https://rp.example.org/redirect_uri")
+ .build();
+ final PlainJWT requestObject = new PlainJWT(ro);
+ setAuthenticationRequest(
+ AuthenticationRequest.parse("client_id=mockClientId&request=" + requestObject.serialize()));
+
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ Assert.assertNotNull(respCtx.getRequestObject());
+ }
+
+ /**
+ * Test on invalid request_uri.
+ *
+ * @throws ParseException
+ * @throws URISyntaxException
+ */
+ @Test
+ public void testInvalidRequestURI() throws ParseException, URISyntaxException {
+ metadataCtx.getClientInformation().getOIDCMetadata().setRequestObjectURIs(
+ Set.of(new URI("https://localhost/foobar")));
+ setAuthenticationRequest(
+ AuthenticationRequest.parse("client_id=mockClientId&request_uri=http://localhost/foo"));
+
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_REQUEST_URI);
+ }
+
+ /**
+ * Test a valid request_uri.
+ *
+ * @throws URISyntaxException
+ * @throws ParseException
+ */
+ @Test
+ public void testRequestURI() throws URISyntaxException, ParseException {
+
+ final String uri = RepositorySupport.buildHTTPSResourceURL("java-idp-oidc",
+ "idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/oidc/profile/impl/oidc-authreq.json");
+
+ metadataCtx.getClientInformation().getOIDCMetadata().setRequestObjectURIs(Set.of(new URI(uri)));
+
+ setAuthenticationRequest(
+ AuthenticationRequest.parse("client_id=" + clientId +
+ "&request_uri=" + UrlEscapers.urlFormParameterEscaper().escape(uri)));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ Assert.assertNotNull(respCtx.getRequestObject());
+ Assert.assertTrue(respCtx.getRequestObject() instanceof SignedJWT);
+ }
+
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list