[java-idp-oidc] branch main updated: JOIDC-217 - Support for OAuth2 JWT-Secured Authorization Request (JAR)
Henri Mikkonen
henri.mikkonen at iki.fi
Wed Jun 19 12:00:17 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=95928d3e0997dc23db156fb4c43c6303895d80c6
The following commit(s) were added to refs/heads/main by this push:
new 95928d3e JOIDC-217 - Support for OAuth2 JWT-Secured Authorization Request (JAR)
95928d3e is described below
commit 95928d3e0997dc23db156fb4c43c6303895d80c6
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Jun 19 14:59:48 2024 +0300
JOIDC-217 - Support for OAuth2 JWT-Secured Authorization Request (JAR)
https://shibboleth.atlassian.net/browse/JOIDC-217
- Changed authorization/authentication request lookup functions to exploit a predicate for only using request object values
- By default the predicate returns true if the request is not OIDC authentication request and contains request object
- Updated authorize and PAR flows to enforce request object signing whenever non-OIDC authorization request contains request object
- Improved flow tests
---
...AbstractAuthorizationRequestLookupFunction.java | 47 +++++++++++++++++++++-
.../DefaultRequestAudienceLookupFunction.java | 2 +-
.../DefaultRequestCodeChallengeLookupFunction.java | 3 +-
...ltRequestCodeChallengeMethodLookupFunction.java | 3 +-
.../DefaultRequestDPoPJktLookupFunction.java | 5 ++-
.../DefaultRequestLoginHintLookupFunction.java | 2 +-
.../DefaultRequestMaxAgeLookupFunction.java | 3 +-
.../DefaultRequestNonceLookupFunction.java | 2 +-
.../DefaultRequestRedirectURILookupFunction.java | 4 +-
.../DefaultRequestResponseModeLookupFunction.java | 2 +-
.../DefaultRequestResponseTypeLookupFunction.java | 2 +-
.../DefaultRequestStateLookupFunction.java | 2 +-
.../DefaultRequestedAcrLookupFunction.java | 2 +-
.../DefaultRequestedClaimsLookupFunction.java | 2 +-
.../DefaultRequestedPromptLookupFunction.java | 2 +-
.../DefaultRequestedScopeLookupFunction.java | 2 +-
.../DefaultUseOnlyRequestObjectPredicate.java | 39 ++++++++++++++++++
.../DefaultRequestedScopeLookupFunctionTest.java | 3 +-
.../pushed-authorization-beans.xml | 26 ++++++++++--
.../idp/flows/oidc/authorize/authorize-beans.xml | 33 +++++++++++++--
.../oidc/op/profile/flow/AuthorizeFlowTest.java | 34 +++++++++++++---
.../op/profile/flow/PushedAuthorizeFlowTest.java | 30 ++++++++++++--
22 files changed, 216 insertions(+), 34 deletions(-)
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunction.java
index 5d0577fb..1915146c 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunction.java
@@ -14,11 +14,14 @@
package net.shibboleth.idp.plugin.oidc.op.profile.context.navigate;
+import java.util.function.BiPredicate;
+
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
import com.nimbusds.jwt.JWT;
import com.nimbusds.oauth2.sdk.AuthorizationRequest;
@@ -26,6 +29,7 @@ import com.nimbusds.oauth2.sdk.PushedAuthorizationRequest;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
/**
* A Abstract function extended by lookups searching fields from authorization request.
@@ -37,12 +41,18 @@ import net.shibboleth.shared.logic.Constraint;
public abstract class AbstractAuthorizationRequestLookupFunction<T>
implements ContextDataLookupFunction<ProfileRequestContext,T> {
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(AbstractAuthorizationRequestLookupFunction.class);
+
/** Request. */
@Nullable private JWT requestObject;
/** The request message class to verify that the actual request is an instance of. */
@Nonnull private final Class<? extends AuthorizationRequest> messageClass;
+ /** The predicate to decide if the parameter values may only be set in the request object. */
+ @Nonnull private BiPredicate<AuthorizationRequest, String> useOnlyRequestObjectPredicate;
+
/**
* Constructor.
*/
@@ -57,6 +67,19 @@ public abstract class AbstractAuthorizationRequestLookupFunction<T>
*/
protected AbstractAuthorizationRequestLookupFunction(@Nonnull final Class<? extends AuthorizationRequest> clazz) {
messageClass = Constraint.isNotNull(clazz, "Message class cannot be null");
+ useOnlyRequestObjectPredicate = new DefaultUseOnlyRequestObjectPredicate();
+ }
+
+ /**
+ * Set the predicate to decide if the parameter values may only be set in the request object.
+ *
+ * @param predicate the predicate to decide if the parameter values may only be set in the request object.
+ *
+ * @since 4.2.0
+ */
+ public void setUseOnlyRequestObjectPredicate(@Nonnull final BiPredicate<AuthorizationRequest, String> predicate) {
+ useOnlyRequestObjectPredicate = Constraint.isNotNull(predicate,
+ "Use only request object predicate cannot be null");
}
/**
@@ -102,5 +125,27 @@ public abstract class AbstractAuthorizationRequestLookupFunction<T>
@Nullable public JWT getRequestObject() {
return requestObject;
}
-
+
+ /**
+ * Check if the given {@link AuthorizationRequest} and parameter should only be set in the request object. It's
+ * tested with {@link #useOnlyRequestObjectPredicate}: if it returns true, the default result is returned
+ * instead of the parameter value.
+ *
+ * @param authorizationRequest the authorization request being processed.
+ * @param parameterName the parameter name.
+ * @param parameterValue the value found from the parameters.
+ * @param defaultResult the default value to be used if the request contained OAuth2 JAR request object.
+ * @return the parameter value to be used, depending on the authorization request message contents.
+ *
+ * @since 4.2.0
+ */
+ @Nullable protected T checkRequestObject(@Nonnull final AuthorizationRequest authorizationRequest,
+ @Nonnull final String parameterName, @Nullable final T parameterValue, @Nullable T defaultResult) {
+ if (useOnlyRequestObjectPredicate.test(authorizationRequest, parameterName)) {
+ log.debug("Ignoring value {}={} from authorization request as request object is defined", parameterName,
+ parameterValue);
+ return defaultResult;
+ }
+ return parameterValue;
+ }
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestAudienceLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestAudienceLookupFunction.java
index 0b7a0776..51ade30d 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestAudienceLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestAudienceLookupFunction.java
@@ -66,7 +66,7 @@ public class DefaultRequestAudienceLookupFunction extends AbstractAuthorizationR
return null;
}
- return req.getCustomParameter(CUSTOM_RESOURCE_PARAM_NAME);
+ return checkRequestObject(req, "resource", req.getCustomParameter(CUSTOM_RESOURCE_PARAM_NAME), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestCodeChallengeLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestCodeChallengeLookupFunction.java
index 4ecd3e94..8ff2d1ba 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestCodeChallengeLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestCodeChallengeLookupFunction.java
@@ -54,7 +54,8 @@ public class DefaultRequestCodeChallengeLookupFunction extends AbstractAuthoriza
log.error("Unable to parse code challenge from request object code_challenge value");
return null;
}
- return req.getCodeChallenge() == null ? null : req.getCodeChallenge().getValue();
+ return req.getCodeChallenge() == null ? null :
+ checkRequestObject(req, "code_challenge", req.getCodeChallenge().getValue(), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestCodeChallengeMethodLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestCodeChallengeMethodLookupFunction.java
index e68e0e55..be2ea11f 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestCodeChallengeMethodLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestCodeChallengeMethodLookupFunction.java
@@ -55,7 +55,8 @@ public class DefaultRequestCodeChallengeMethodLookupFunction
log.error("Unable to parse code challenge method from request object code_challenge_method value");
return null;
}
- return req.getCodeChallengeMethod() == null ? null : req.getCodeChallengeMethod().getValue();
+ return req.getCodeChallengeMethod() == null ? null :
+ checkRequestObject(req, "code_challenge_method", req.getCodeChallengeMethod().getValue(), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestDPoPJktLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestDPoPJktLookupFunction.java
index 68bc7463..ec4f8c59 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestDPoPJktLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestDPoPJktLookupFunction.java
@@ -56,8 +56,9 @@ public class DefaultRequestDPoPJktLookupFunction extends AbstractAuthorizationRe
log.error("Unable to parse dpop_jkt from request object dpop_jkt value");
return null;
}
- return req.getDPoPJWKThumbprintConfirmation() == null ?
- null : req.getDPoPJWKThumbprintConfirmation().getValue().toString();
+ return req.getDPoPJWKThumbprintConfirmation() == null ? null :
+ checkRequestObject(req, "dpop_jkt", req.getDPoPJWKThumbprintConfirmation().getValue().toString(),
+ null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestLoginHintLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestLoginHintLookupFunction.java
index 99628838..cb83710c 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestLoginHintLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestLoginHintLookupFunction.java
@@ -52,6 +52,6 @@ public class DefaultRequestLoginHintLookupFunction extends AbstractAuthenticatio
log.error("Unable to parse login hint from request object login_hint value");
return null;
}
- return req.getLoginHint();
+ return checkRequestObject(req, "login_hint", req.getLoginHint(), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestMaxAgeLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestMaxAgeLookupFunction.java
index 17892346..2f3f398c 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestMaxAgeLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestMaxAgeLookupFunction.java
@@ -48,6 +48,7 @@ public class DefaultRequestMaxAgeLookupFunction extends AbstractAuthenticationRe
log.error("Unable to parse state from request object state value");
return null;
}
- return req.getMaxAge() == -1 ? null : Duration.ofSeconds(req.getMaxAge());
+ return req.getMaxAge() == -1 ? null :
+ checkRequestObject(req, "max_age", Duration.ofSeconds(req.getMaxAge()), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestNonceLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestNonceLookupFunction.java
index e7fb2d28..2a060f6b 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestNonceLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestNonceLookupFunction.java
@@ -54,7 +54,7 @@ public class DefaultRequestNonceLookupFunction extends AbstractAuthenticationReq
return null;
}
if (req.getNonce() != null) {
- return new Nonce(req.getNonce().getValue());
+ return checkRequestObject(req, "nonce", new Nonce(req.getNonce().getValue()), null);
}
return null;
}
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestRedirectURILookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestRedirectURILookupFunction.java
index d252849a..a77b41ac 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestRedirectURILookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestRedirectURILookupFunction.java
@@ -35,7 +35,7 @@ public class DefaultRequestRedirectURILookupFunction extends AbstractAuthorizati
/** Class logger. */
@Nonnull
private Logger log = LoggerFactory.getLogger(DefaultRequestRedirectURILookupFunction.class);
-
+
/** {@inheritDoc} */
@Override
protected URI doLookup(@Nonnull final AuthorizationRequest req) {
@@ -54,6 +54,6 @@ public class DefaultRequestRedirectURILookupFunction extends AbstractAuthorizati
log.error("Unable to parse redirect URI from request object redirect_uri value");
return null;
}
- return req.getRedirectionURI();
+ return checkRequestObject(req, "redirect_uri", req.getRedirectionURI(), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestResponseModeLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestResponseModeLookupFunction.java
index 3083bf8c..38971a64 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestResponseModeLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestResponseModeLookupFunction.java
@@ -58,6 +58,6 @@ public class DefaultRequestResponseModeLookupFunction
if (req.getResponseMode() == null) {
return null;
}
- return new ResponseMode(req.getResponseMode().getValue());
+ return checkRequestObject(req, "response_mode", new ResponseMode(req.getResponseMode().getValue()), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestResponseTypeLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestResponseTypeLookupFunction.java
index c086ab97..4fb936c1 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestResponseTypeLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestResponseTypeLookupFunction.java
@@ -53,6 +53,6 @@ public class DefaultRequestResponseTypeLookupFunction
if (requestedType != null) {
result.addAll(requestedType);
}
- return result;
+ return checkRequestObject(req, "response_type", result, new ResponseType());
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestStateLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestStateLookupFunction.java
index 36eb00bc..7b7e40c2 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestStateLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestStateLookupFunction.java
@@ -56,6 +56,6 @@ public class DefaultRequestStateLookupFunction extends AbstractAuthorizationRequ
if (req.getState() == null) {
return null;
}
- return new State(req.getState().getValue());
+ return checkRequestObject(req, "state", new State(req.getState().getValue()), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedAcrLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedAcrLookupFunction.java
index 2fcbd20c..4643618d 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedAcrLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedAcrLookupFunction.java
@@ -59,6 +59,6 @@ public class DefaultRequestedAcrLookupFunction extends AbstractAuthenticationReq
}
final List<ACR> requestParameterAcr = new ArrayList<ACR>();
requestParameterAcr.addAll(req.getACRValues());
- return requestParameterAcr;
+ return checkRequestObject(req, "acr_values", requestParameterAcr, null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedClaimsLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedClaimsLookupFunction.java
index a4b5969b..1dc0d6d2 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedClaimsLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedClaimsLookupFunction.java
@@ -60,7 +60,7 @@ public class DefaultRequestedClaimsLookupFunction
log.error("unable to parse claims claim {}", e.getMessage());
return null;
}
- return req.getOIDCClaims();
+ return checkRequestObject(req, "claims", req.getOIDCClaims(), null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedPromptLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedPromptLookupFunction.java
index 0edf0e53..98770ac7 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedPromptLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedPromptLookupFunction.java
@@ -52,6 +52,6 @@ public class DefaultRequestedPromptLookupFunction extends AbstractAuthorizationR
}
final Prompt requestParameterPrompt = new Prompt();
requestParameterPrompt.addAll(req.getPrompt());
- return requestParameterPrompt;
+ return checkRequestObject(req, "prompt", requestParameterPrompt, null);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedScopeLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedScopeLookupFunction.java
index d6acbef5..20545fcb 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedScopeLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedScopeLookupFunction.java
@@ -52,6 +52,6 @@ public class DefaultRequestedScopeLookupFunction extends AbstractAuthorizationRe
if (requestParameterScope != null) {
result.addAll(requestParameterScope);
}
- return result;
+ return checkRequestObject(req, "scope", result, new Scope());
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultUseOnlyRequestObjectPredicate.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultUseOnlyRequestObjectPredicate.java
new file mode 100644
index 00000000..0822c6d4
--- /dev/null
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultUseOnlyRequestObjectPredicate.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed 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.context.navigate;
+
+import java.util.function.BiPredicate;
+
+import javax.annotation.Nullable;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
+import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+/**
+ * Default predicate for using only request object parameters if the authorization request (1) contains request object
+ * and (2) is not OIDC authentication request.
+ */
+public class DefaultUseOnlyRequestObjectPredicate implements BiPredicate<AuthorizationRequest, String> {
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean test(@Nullable final AuthorizationRequest authorizationRequest, @Nullable final String parameter) {
+ if (authorizationRequest == null) {
+ return false;
+ }
+ return (!(authorizationRequest instanceof AuthenticationRequest)
+ && authorizationRequest.specifiesRequestObject());
+ }
+}
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedScopeLookupFunctionTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedScopeLookupFunctionTest.java
index bbc3a49e..c3f778cf 100644
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedScopeLookupFunctionTest.java
+++ b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultRequestedScopeLookupFunctionTest.java
@@ -35,6 +35,7 @@ public class DefaultRequestedScopeLookupFunctionTest extends BaseDefaultRequestL
@BeforeMethod
protected void setUp() throws Exception {
lookup = new DefaultRequestedScopeLookupFunction();
+ oidcCtx.setRequestObject(null);
}
@Test
@@ -102,7 +103,7 @@ public class DefaultRequestedScopeLookupFunctionTest extends BaseDefaultRequestL
@Test
public void testWithEmptyScopeInRequest() {
- AuthorizationRequest req = new AuthorizationRequest.Builder(URI.create("https://example.com/callback"),
+ AuthorizationRequest req = new AuthorizationRequest.Builder(ResponseType.CODE,
new ClientID("000123")).state(new State()).scope(new Scope()).build();
msgCtx.setMessage(req);
final Scope result = lookup.apply(prc);
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 4d9c4461..213e9c47 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
@@ -210,12 +210,32 @@
<ref bean="RequestObjectSignedCondition" />
</constructor-arg>
<constructor-arg>
- <bean parent="shibboleth.Conditions.AND">
+ <bean parent="shibboleth.Conditions.OR">
<constructor-arg>
- <ref bean="UseRequestObjectPredicate" />
+ <bean parent="shibboleth.Conditions.AND">
+ <constructor-arg>
+ <ref bean="UseRequestObjectPredicate" />
+ </constructor-arg>
+ <constructor-arg>
+ <ref bean="SignRequestObjectPredicate" />
+ </constructor-arg>
+ </bean>
</constructor-arg>
<constructor-arg>
- <ref bean="SignRequestObjectPredicate" />
+ <bean parent="shibboleth.Conditions.AND">
+ <constructor-arg>
+ <bean id="RequestObjectInvolved" parent="shibboleth.Conditions.Expression"
+ c:expression="#input.ensureOutboundMessageContext().ensureSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).getRequestObject() != null" />
+ </constructor-arg>
+ <constructor-arg>
+ <bean parent="shibboleth.Conditions.NOT">
+ <constructor-arg>
+ <bean id="ScopeContainsOpenid" parent="shibboleth.Conditions.Expression" p:customObject-ref="shibboleth.HttpServletRequestSupplier"
+ c:expression="#custom.get().getParameter('scope') != null and #custom.get().getParameter('scope').contains('openid')" />
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ </bean>
</constructor-arg>
</bean>
</constructor-arg>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
index 2c359a4d..2ce554a8 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
@@ -300,12 +300,39 @@
<ref bean="RequestObjectSignedCondition" />
</constructor-arg>
<constructor-arg>
- <bean parent="shibboleth.Conditions.AND">
+ <bean parent="shibboleth.Conditions.OR">
<constructor-arg>
- <ref bean="UseRequestObjectPredicate" />
+ <bean parent="shibboleth.Conditions.AND">
+ <constructor-arg>
+ <ref bean="UseRequestObjectPredicate" />
+ </constructor-arg>
+ <constructor-arg>
+ <ref bean="SignRequestObjectPredicate" />
+ </constructor-arg>
+ </bean>
</constructor-arg>
<constructor-arg>
- <ref bean="SignRequestObjectPredicate" />
+ <bean parent="shibboleth.Conditions.AND">
+ <constructor-arg>
+ <bean parent="shibboleth.Conditions.AND">
+ <constructor-arg>
+ <bean id="RequestObjectInvolved" parent="shibboleth.Conditions.Expression"
+ c:expression="#input.ensureOutboundMessageContext().ensureSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).getRequestObject() != null" />
+ </constructor-arg>
+ <constructor-arg>
+ <bean id="RequestObjectNotVerified" parent="shibboleth.Conditions.Expression"
+ c:expression="#input.ensureOutboundMessageContext().ensureSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).isRequestObjectValidated() == false" />
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg>
+ <bean parent="shibboleth.Conditions.NOT">
+ <constructor-arg>
+ <ref bean="ScopeContainsOpenid" />
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ </bean>
</constructor-arg>
</bean>
</constructor-arg>
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
index 86aa61d2..608ec2ea 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
@@ -1811,6 +1811,25 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
assertRequestObjectError(new PlainJWT(ro));
}
+ @Test
+ public void testWithPlainOAuth2ReqObject() throws IOException, SessionException, JOSEException {
+ final JWTClaimsSet ro = new JWTClaimsSet.Builder()
+ .claim("redirect_uri", redirectUri)
+ .claim("response_type", "code")
+ .claim("scope", "profile")
+ .build();
+ final PlainJWT requestObject = new PlainJWT(ro);
+ request.setMethod("GET");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("request", requestObject.serialize())));
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ Assert.assertEquals(result.getOutcome().getId(), "ErrorView");
+ }
+
@Test
public void testWitnOpenIDReqObjectResponseTypeParameter() throws IOException, SessionException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
@@ -1852,11 +1871,14 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithOAuth2ReqObjectResponseTypeParameter() throws IOException, SessionException {
+ public void testWithOAuth2ReqObjectResponseTypeParameter() throws IOException, SessionException, JOSEException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
+ .claim("iss", clientId)
+ .claim("aud", issuer)
+ .claim("redirect_uri", "https://example.org/cb")
.claim("response_type", "code")
.build();
- final PlainJWT requestObject = new PlainJWT(ro);
+ final SignedJWT requestObject = createSecretJWT(ro, clientSecret);
request.setMethod("GET");
setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
new Pair<>("scope", "profile"),
@@ -1876,11 +1898,13 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithOAuth2ReqObjectNoResponseType() throws IOException, SessionException {
+ public void testWithOAuth2ReqObjectNoResponseType() throws IOException, SessionException, JOSEException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
- .claim("redirect_uri", redirectUri)
+ .claim("iss", clientId)
+ .claim("aud", issuer)
+ .claim("redirect_uri", "https://example.org/cb")
.build();
- final PlainJWT requestObject = new PlainJWT(ro);
+ final SignedJWT requestObject = createSecretJWT(ro, clientSecret);
request.setMethod("GET");
setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
new Pair<>("scope", "profile"),
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 048daadd..3880c86d 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
@@ -32,10 +32,12 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
+import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
+import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.OAuth2Error;
import com.nimbusds.oauth2.sdk.PushedAuthorizationSuccessResponse;
import com.nimbusds.oauth2.sdk.Scope;
@@ -271,6 +273,21 @@ public class PushedAuthorizeFlowTest extends AbstractOidcClientAuthenticationFlo
verifyAuthorizeEndpoint(clientId, response.getRequestURI().toString());
}
+ @Test
+ public void testOAuth2PlainRO() throws IOException, NoSuchAlgorithmException, URISyntaxException,
+ DataSealerException, ComponentInitializationException {
+ storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org/cb");
+ setBasicAuth(clientId, clientSecret);
+ final JWTClaimsSet ro = new JWTClaimsSet.Builder()
+ .claim("redirect_uri", "https://example.org/cb")
+ .claim("response_type", "code")
+ .build();
+ final PlainJWT requestObject = new PlainJWT(ro);
+ setHttpFormRequest("POST", createRequestParameters(clientId, "profile", null, requestObject.serialize()));
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, OAuth2Error.INVALID_REQUEST_CODE);
+ }
+
@Test
public void testOIDCNoResponseType() throws IOException, NoSuchAlgorithmException, URISyntaxException,
DataSealerException, ComponentInitializationException {
@@ -323,13 +340,15 @@ public class PushedAuthorizeFlowTest extends AbstractOidcClientAuthenticationFlo
@Test
public void testOAuth2NoResponseTypeRO() throws IOException, NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException {
+ 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("aud", issuer)
.claim("redirect_uri", "https://example.org/cb")
.build();
- final PlainJWT requestObject = new PlainJWT(ro);
+ final SignedJWT requestObject = createSecretJWT(ro, clientSecret);
setHttpFormRequest("POST", createRequestParameters(clientId, "profile", null, requestObject.serialize()));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
assertErrorCode(result, OAuth2Error.INVALID_REQUEST_CODE);
@@ -337,13 +356,16 @@ public class PushedAuthorizeFlowTest extends AbstractOidcClientAuthenticationFlo
@Test
public void testOAuth2ResponseTypeInRO() throws IOException, NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException {
+ 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("aud", issuer)
+ .claim("redirect_uri", "https://example.org/cb")
.claim("response_type", "code")
.build();
- final PlainJWT requestObject = new PlainJWT(ro);
+ final SignedJWT requestObject = createSecretJWT(ro, clientSecret);
setHttpFormRequest("POST", createRequestParameters(clientId, "profile", null,
requestObject.serialize()));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list