[java-idp-oidc] branch main updated: JOIDC-128 - Support OAuth authorization requests
Henri Mikkonen
henri.mikkonen at iki.fi
Mon Oct 3 15:01:20 UTC 2022
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=81cce0a57cbf12100b6e9443e871710b59f141a5
The following commit(s) were added to refs/heads/main by this push:
new 81cce0a5 JOIDC-128 - Support OAuth authorization requests
81cce0a5 is described below
commit 81cce0a57cbf12100b6e9443e871710b59f141a5
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Mon Oct 3 17:57:41 2022 +0300
JOIDC-128 - Support OAuth authorization requests
https://shibboleth.atlassian.net/browse/JOIDC-128
Authorize-flow now contains a decision-state before decoding: if the requested scope contains
‘openid’, the request is considered as OIDC authentication request. OAuth authorization request
otherwise.
Moved the following actions into oauth2.profile.impl package: DecryptRequestObject,
SetAuthorizationCodeToResponseContext, SetRequestObjectToResponseContext, ValidateCodeChallenge,
ValidateRedirectURI, ValidateRequestObject, ValidateResponseType, ValidateScope.
Also updated various lookup functions to be compatible with OAuth authorization requests if not
only related to OIDC.
---
...bstractAuthenticationRequestLookupFunction.java | 47 +--
...bstractAuthorizationRequestLookupFunction.java} | 35 +-
.../navigate/DefaultClientIDLookupFunction.java | 7 +-
.../DefaultRequestAudienceLookupFunction.java | 9 +-
.../DefaultRequestCodeChallengeLookupFunction.java | 11 +-
...ltRequestCodeChallengeMethodLookupFunction.java | 11 +-
.../DefaultRequestRedirectURILookupFunction.java | 9 +-
.../DefaultRequestResponseModeLookupFunction.java | 9 +-
.../DefaultRequestResponseTypeLookupFunction.java | 9 +-
.../DefaultRequestStateLookupFunction.java | 9 +-
.../DefaultRequestedPromptLookupFunction.java | 11 +-
.../DefaultRequestedScopeLookupFunction.java | 11 +-
.../DefaultValidResponseTypesLookupFunction.java | 54 +++
...actAuthenticationRequestLookupFunctionTest.java | 9 +
...actAuthorizationRequestLookupFunctionTest.java} | 23 +-
.../impl/OAuth2AuthorizationRequestDecoder.java | 80 ++++
.../AbstractOAuthAuthorizationRequestAction.java | 49 +++
.../AbstractOAuthAuthorizationResponseAction.java | 97 +++++
.../profile/impl/DecryptRequestObject.java | 4 +-
.../SetAuthorizationCodeToResponseContext.java | 6 +-
.../impl/SetRequestObjectToResponseContext.java | 20 +-
.../profile/impl/ValidateCodeChallenge.java | 4 +-
.../profile/impl/ValidateRedirectURI.java | 4 +-
.../profile/impl/ValidateRequestObject.java | 8 +-
.../oauth2/profile/impl/ValidateResponseType.java | 101 +++++
.../{ => oauth2}/profile/impl/ValidateScope.java | 37 +-
.../FormOutboundAuthenticationResponseMessage.java | 28 +-
.../oidc/op/profile/impl/ValidateResponseType.java | 53 ---
.../idp/flows/oidc/authorize/authorize-beans.xml | 42 +-
.../idp/flows/oidc/authorize/authorize-flow.xml | 20 +-
.../idp/flows/oidc/token/token-beans.xml | 4 +-
.../idp/flows/oidc/userinfo/userinfo-beans.xml | 2 +-
.../profile/impl/DecryptRequestObjectTest.java | 2 +-
.../SetAuthorizationCodeToResponseContextTest.java | 3 +-
.../SetRequestObjectToResponseContextTest.java | 3 +-
.../profile/impl/ValidateCodeChallengeTest.java | 3 +-
.../profile/impl/ValidateRedirectURITest.java | 3 +-
.../profile/impl/ValidateRequestObjectTest.java | 2 +-
.../profile/impl/ValidateResponseTypeTest.java | 3 +-
.../profile/impl/ValidateScopeTest.java | 9 +-
.../oidc/op/profile/flow/AuthorizeFlowTest.java | 432 ++++++++++++++++-----
.../src/test/resources/conf/attribute-filter.xml | 15 +
42 files changed, 983 insertions(+), 315 deletions(-)
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunction.java
index 76dc1111..81cf4f1d 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunction.java
@@ -23,59 +23,38 @@ import javax.annotation.Nullable;
import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
import org.opensaml.profile.context.ProfileRequestContext;
-import com.nimbusds.jwt.JWT;
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
-
/**
* A Abstract function extended by lookups searching fields from authentication request.
*
* @param <T> type of lookup result to return.
*/
public abstract class AbstractAuthenticationRequestLookupFunction<T>
+ extends AbstractAuthorizationRequestLookupFunction<T>
implements ContextDataLookupFunction<ProfileRequestContext,T> {
- /** Request. */
- @Nullable private JWT requestObject;
-
+ public AbstractAuthenticationRequestLookupFunction() {
+ super(AuthenticationRequest.class);
+ }
/**
* Implemented to perform the actual lookup.
*
- * @param req authentication request to perform the lookup from.
+ * @param req auhtorization request to perform the lookup from.
* @return lookup value.
*/
- @Nullable protected abstract T doLookup(@Nonnull AuthenticationRequest req);
-
- /** {@inheritDoc} */
- @Nullable
- public T apply(@Nullable final ProfileRequestContext input) {
- if (input == null || input.getInboundMessageContext() == null) {
- return null;
- }
- final Object message = input.getInboundMessageContext().getMessage();
- if (message == null || !(message instanceof AuthenticationRequest)) {
- return null;
- }
- if (input.getOutboundMessageContext() != null) {
- final OIDCAuthenticationResponseContext ctx =
- input.getOutboundMessageContext().getSubcontext(OIDCAuthenticationResponseContext.class, false);
- if (ctx != null) {
- requestObject = ctx.getRequestObject();
- }
- }
-
- return doLookup((AuthenticationRequest) message);
+ @Nullable protected T doLookup(@Nonnull final AuthorizationRequest req) {
+ return doLookup((AuthenticationRequest) req);
}
/**
- * Gets the request object.
+ * Implemented to perform the actual lookup from OIDC authentication request.
*
- * @return the request object.
+ * @param req authentication request to perform the lookup from.
+ * @return lookup value.
*/
- @Nullable public JWT getRequestObject() {
- return requestObject;
- }
-
+ @Nullable protected abstract T doLookup(@Nonnull final AuthenticationRequest req);
+
}
\ 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/AbstractAuthenticationRequestLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunction.java
similarity index 67%
copy from idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunction.java
copy to idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunction.java
index 76dc1111..f6c5aae5 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunction.java
@@ -24,29 +24,50 @@ import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
import org.opensaml.profile.context.ProfileRequestContext;
import com.nimbusds.jwt.JWT;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * A Abstract function extended by lookups searching fields from authentication request.
+ * A Abstract function extended by lookups searching fields from authorization request.
*
* @param <T> type of lookup result to return.
+ *
+ * @since 3.3.0
*/
-public abstract class AbstractAuthenticationRequestLookupFunction<T>
+public abstract class AbstractAuthorizationRequestLookupFunction<T>
implements ContextDataLookupFunction<ProfileRequestContext,T> {
/** 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;
+
+ /**
+ * Constructor.
+ */
+ public AbstractAuthorizationRequestLookupFunction() {
+ this(AuthorizationRequest.class);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param clazz request message class to verify that the actual request is an instance of.
+ */
+ protected AbstractAuthorizationRequestLookupFunction(@Nonnull final Class<? extends AuthorizationRequest> clazz) {
+ messageClass = Constraint.isNotNull(clazz, "Message class cannot be null");
+ }
/**
* Implemented to perform the actual lookup.
*
- * @param req authentication request to perform the lookup from.
+ * @param req authorization request to perform the lookup from.
* @return lookup value.
*/
- @Nullable protected abstract T doLookup(@Nonnull AuthenticationRequest req);
+ @Nullable protected abstract T doLookup(@Nonnull final AuthorizationRequest req);
/** {@inheritDoc} */
@Nullable
@@ -55,7 +76,7 @@ public abstract class AbstractAuthenticationRequestLookupFunction<T>
return null;
}
final Object message = input.getInboundMessageContext().getMessage();
- if (message == null || !(message instanceof AuthenticationRequest)) {
+ if (message == null || !(messageClass.isInstance(message))) {
return null;
}
if (input.getOutboundMessageContext() != null) {
@@ -66,7 +87,7 @@ public abstract class AbstractAuthenticationRequestLookupFunction<T>
}
}
- return doLookup((AuthenticationRequest) message);
+ return doLookup((AuthorizationRequest) message);
}
/**
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultClientIDLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultClientIDLookupFunction.java
index 93b48670..9c52f900 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultClientIDLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultClientIDLookupFunction.java
@@ -21,8 +21,9 @@ import javax.annotation.Nullable;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.oauth2.sdk.id.ClientID;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
/**
* A function that returns client id of the authentication request via a lookup function. This default lookup locates
@@ -36,9 +37,9 @@ public class DefaultClientIDLookupFunction implements ContextDataLookupFunction<
return null;
}
final Object message = input.getMessage();
- if (!(message instanceof AuthenticationRequest)) {
+ if (!(message instanceof AuthorizationRequest)) {
return null;
}
- return ((AuthenticationRequest) message).getClientID();
+ return ((AuthorizationRequest) message).getClientID();
}
}
\ 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 b8b72b50..c70e0665 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
@@ -28,20 +28,21 @@ import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
/**
- * A function that returns resource value of the authentication request.
+ * A function that returns resource value of the authorization request.
*
* @since 3.2.0
*/
-public class DefaultRequestAudienceLookupFunction extends AbstractAuthenticationRequestLookupFunction<List<String>> {
+public class DefaultRequestAudienceLookupFunction extends AbstractAuthorizationRequestLookupFunction<List<String>> {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(DefaultRequestAudienceLookupFunction.class);
/** {@inheritDoc} */
- @Nullable protected List<String> doLookup(@Nonnull final AuthenticationRequest req) {
+ @Nullable protected List<String> doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null && getRequestObject().getJWTClaimsSet().getClaim("resource") != null) {
final Object resource = getRequestObject().getJWTClaimsSet().getClaim("resource");
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 6abf656d..f076c8a0 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
@@ -23,21 +23,22 @@ import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
/**
- * A function that returns code challenge value of the authentication request via a lookup function. This default lookup
- * locates code challenge from oidc authentication request if available. If information is not available, null is
+ * A function that returns code challenge value of the authorization request via a lookup function. This default lookup
+ * locates code challenge from OAuth authorization request if available. If information is not available, null is
* returned. If there is code_challenge in request object it is used instead of code_challenge parameter.
*/
-public class DefaultRequestCodeChallengeLookupFunction extends AbstractAuthenticationRequestLookupFunction<String> {
+public class DefaultRequestCodeChallengeLookupFunction extends AbstractAuthorizationRequestLookupFunction<String> {
/** Class logger. */
@Nonnull
private Logger log = LoggerFactory.getLogger(DefaultRequestCodeChallengeLookupFunction.class);
/** {@inheritDoc} */
- @Nullable protected String doLookup(@Nonnull final AuthenticationRequest req) {
+ @Nullable protected String doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null && getRequestObject().getJWTClaimsSet().getClaim("code_challenge") != null) {
final Object codeChallenge = getRequestObject().getJWTClaimsSet().getClaim("code_challenge");
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 5c347971..bb01adef 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
@@ -21,16 +21,17 @@ import java.text.ParseException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
/**
- * A function that returns code challenge method value of the authentication request via a lookup function. This default
- * lookup locates code challenge method from oidc authentication request if available. If information is not available,
+ * A function that returns code challenge method value of the authorization request via a lookup function. This default
+ * lookup locates code challenge method from OAuth authorization request if available. If information is not available,
* null is returned. If there is code_challenge_method in request object it is used instead of code_challenge_method
* parameter.
*/
public class DefaultRequestCodeChallengeMethodLookupFunction
- extends AbstractAuthenticationRequestLookupFunction<String> {
+ extends AbstractAuthorizationRequestLookupFunction<String> {
/** Class logger. */
@Nonnull
@@ -38,7 +39,7 @@ public class DefaultRequestCodeChallengeMethodLookupFunction
/** {@inheritDoc} */
@Override
- protected String doLookup(@Nonnull final AuthenticationRequest req) {
+ protected String doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null &&
getRequestObject().getJWTClaimsSet().getClaim("code_challenge_method") != 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 5240a99e..706e4271 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
@@ -23,14 +23,15 @@ import java.text.ParseException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
/**
* A function that returns redirect uri of the authentication request via a lookup function. This default lookup locates
- * redirect uri from oidc authentication request if available. If information is not available, null is returned. If
+ * redirect uri from OAuth authorization request if available. If information is not available, null is returned. If
* there is redirect uri in request object it is used instead of redirect_uri parameter.
*/
-public class DefaultRequestRedirectURILookupFunction extends AbstractAuthenticationRequestLookupFunction<URI> {
+public class DefaultRequestRedirectURILookupFunction extends AbstractAuthorizationRequestLookupFunction<URI> {
/** Class logger. */
@Nonnull
@@ -38,7 +39,7 @@ public class DefaultRequestRedirectURILookupFunction extends AbstractAuthenticat
/** {@inheritDoc} */
@Override
- protected URI doLookup(@Nonnull final AuthenticationRequest req) {
+ protected URI doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null && getRequestObject().getJWTClaimsSet().getClaim("redirect_uri") != null) {
final Object redirect = getRequestObject().getJWTClaimsSet().getClaim("redirect_uri");
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 ff6fadd5..96704d46 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
@@ -22,16 +22,17 @@ import java.text.ParseException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.oauth2.sdk.ResponseMode;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
/**
* A function that returns copy of the response mode of the request via a lookup function. This default lookup locates
- * response mode from oidc authentication request if available. If information is not available, null is returned. If
+ * response mode from OAuth authorization request if available. If information is not available, null is returned. If
* there is response mode in request object it is used instead of response_mode parameter.
*/
public class DefaultRequestResponseModeLookupFunction
- extends AbstractAuthenticationRequestLookupFunction<ResponseMode> {
+ extends AbstractAuthorizationRequestLookupFunction<ResponseMode> {
/** Class logger. */
@Nonnull
@@ -39,7 +40,7 @@ public class DefaultRequestResponseModeLookupFunction
/** {@inheritDoc} */
@Override
- protected ResponseMode doLookup(@Nonnull final AuthenticationRequest req) {
+ protected ResponseMode doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null && getRequestObject().getJWTClaimsSet().getClaim("response_mode") != null) {
final Object rMode = getRequestObject().getJWTClaimsSet().getClaim("response_mode");
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 c7cee3c3..af1ece21 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
@@ -21,16 +21,17 @@ import java.text.ParseException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.oauth2.sdk.ResponseType;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
/**
* A function that returns copy of response type via a lookup function. This default lookup locates response type from
- * oidc authentication request if available. If information is not available, null is returned. If there is response
+ * OAuth authorization request if available. If information is not available, null is returned. If there is response
* type in request object it is used instead of response_type parameter.
*/
public class DefaultRequestResponseTypeLookupFunction
- extends AbstractAuthenticationRequestLookupFunction<ResponseType> {
+ extends AbstractAuthorizationRequestLookupFunction<ResponseType> {
/** Class logger. */
@Nonnull
@@ -38,7 +39,7 @@ public class DefaultRequestResponseTypeLookupFunction
/** {@inheritDoc} */
@Override
- protected ResponseType doLookup(@Nonnull final AuthenticationRequest req) {
+ protected ResponseType doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null && getRequestObject().getJWTClaimsSet().getClaim("response_type") != null) {
return ResponseType.parse((String) getRequestObject().getJWTClaimsSet().getClaim("response_type"));
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 8bdd6cd6..12a67e51 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
@@ -21,15 +21,16 @@ import java.text.ParseException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.oauth2.sdk.id.State;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
/**
* A function that returns copy of the state the request via a lookup function. This default lookup locates state from
- * oidc authentication request if available. If information is not available, null is returned. If there is state in
+ * OAuth authorization request if available. If information is not available, null is returned. If there is state in
* request object it is used instead of state parameter.
*/
-public class DefaultRequestStateLookupFunction extends AbstractAuthenticationRequestLookupFunction<State> {
+public class DefaultRequestStateLookupFunction extends AbstractAuthorizationRequestLookupFunction<State> {
/** Class logger. */
@Nonnull
@@ -37,7 +38,7 @@ public class DefaultRequestStateLookupFunction extends AbstractAuthenticationReq
/** {@inheritDoc} */
@Override
- protected State doLookup(@Nonnull final AuthenticationRequest req) {
+ protected State doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null && getRequestObject().getJWTClaimsSet().getClaim("state") != null) {
final Object state = getRequestObject().getJWTClaimsSet().getClaim("state");
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 d731158e..e3c4bae2 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
@@ -21,15 +21,16 @@ import java.text.ParseException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.openid.connect.sdk.Prompt;
/**
- * A function that returns copy of requested prompt via a lookup function. This default lookup locates prompt from oidc
- * authentication request if available. If information is not available, null is returned. If there is prompt in request
+ * A function that returns copy of requested prompt via a lookup function. This default lookup locates prompt from OAuth
+ * authorization request if available. If information is not available, null is returned. If there is prompt in request
* object it is used instead of prompt parameter.
*/
-public class DefaultRequestedPromptLookupFunction extends AbstractAuthenticationRequestLookupFunction<Prompt> {
+public class DefaultRequestedPromptLookupFunction extends AbstractAuthorizationRequestLookupFunction<Prompt> {
/** Class logger. */
@Nonnull
@@ -37,7 +38,7 @@ public class DefaultRequestedPromptLookupFunction extends AbstractAuthentication
/** {@inheritDoc} */
@Override
- protected Prompt doLookup(@Nonnull final AuthenticationRequest req) {
+ protected Prompt doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null && getRequestObject().getJWTClaimsSet().getClaim("prompt") != null) {
return Prompt.parse((String) getRequestObject().getJWTClaimsSet().getClaim("prompt"));
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 309281be..c35cc528 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
@@ -21,15 +21,16 @@ import java.text.ParseException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.oauth2.sdk.Scope;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
/**
- * A function that returns copy of requested scopes via a lookup function. This default lookup locates scope from oidc
- * authentication request if available. If information is not available, null is returned. If there is scope in request
+ * A function that returns copy of requested scopes via a lookup function. This default lookup locates scope from OAuth
+ * authorization request if available. If information is not available, null is returned. If there is scope in request
* object it is used instead of scope parameter.
*/
-public class DefaultRequestedScopeLookupFunction extends AbstractAuthenticationRequestLookupFunction<Scope> {
+public class DefaultRequestedScopeLookupFunction extends AbstractAuthorizationRequestLookupFunction<Scope> {
/** Class logger. */
@Nonnull
@@ -37,7 +38,7 @@ public class DefaultRequestedScopeLookupFunction extends AbstractAuthenticationR
/** {@inheritDoc} */
@Override
- protected Scope doLookup(@Nonnull final AuthenticationRequest req) {
+ protected Scope doLookup(@Nonnull final AuthorizationRequest req) {
try {
if (getRequestObject() != null && getRequestObject().getJWTClaimsSet().getClaim("scope") != null) {
return Scope.parse((String) getRequestObject().getJWTClaimsSet().getClaim("scope"));
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultValidResponseTypesLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultValidResponseTypesLookupFunction.java
new file mode 100644
index 00000000..970c561a
--- /dev/null
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/DefaultValidResponseTypesLookupFunction.java
@@ -0,0 +1,54 @@
+/*
+ * 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.context.navigate;
+
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
+import com.nimbusds.oauth2.sdk.ResponseType;
+import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+/**
+ * A function that returns a set of valid response type for the authorization request. If the authorization request is
+ * valid OIDC authentication request, the set specified by the OIDC core specification is returned. Otherwise the set
+ * consisting of OAuth2 code and implicit (token) flow is returned.
+ *
+ * @since 3.3.0
+ */
+public class DefaultValidResponseTypesLookupFunction
+ extends AbstractAuthorizationRequestLookupFunction<Set<ResponseType>> {
+
+ /** Class logger. */
+ @Nonnull
+ private Logger log = LoggerFactory.getLogger(DefaultValidResponseTypesLookupFunction.class);
+
+ /** {@inheritDoc} */
+ @Override
+ protected Set<ResponseType> doLookup(@Nonnull final AuthorizationRequest req) {
+ if (req instanceof AuthenticationRequest) {
+ return Set.of(ResponseType.CODE, ResponseType.CODE_IDTOKEN, ResponseType.CODE_IDTOKEN_TOKEN,
+ ResponseType.CODE_TOKEN, ResponseType.IDTOKEN, ResponseType.IDTOKEN_TOKEN);
+ } else {
+ return Set.of(ResponseType.CODE, ResponseType.TOKEN);
+ }
+ }
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunctionTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunctionTest.java
index f18fc85f..abd6304e 100644
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunctionTest.java
+++ b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunctionTest.java
@@ -30,6 +30,7 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.oauth2.sdk.ResponseType;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.id.ClientID;
@@ -65,6 +66,14 @@ public class AbstractAuthenticationRequestLookupFunctionTest {
Assert.assertEquals("OK", mock.apply(prc));
}
+ @Test
+ public void testAuthorizationRequest() {
+ final AuthorizationRequest req = new AuthorizationRequest.Builder(new ResponseType("code"),
+ new ClientID("000123")).state(new State()).build();
+ msgCtx.setMessage(req);
+ Assert.assertNull(mock.apply(prc));
+ }
+
@Test
public void testNoInboundCtxts() {
// No profilecontext
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunctionTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunctionTest.java
similarity index 77%
copy from idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunctionTest.java
copy to idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunctionTest.java
index f18fc85f..a96a8e26 100644
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthenticationRequestLookupFunctionTest.java
+++ b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractAuthorizationRequestLookupFunctionTest.java
@@ -30,13 +30,14 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.oauth2.sdk.ResponseType;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.id.State;
import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
-public class AbstractAuthenticationRequestLookupFunctionTest {
+public class AbstractAuthorizationRequestLookupFunctionTest {
protected ProfileRequestContext prc;
@@ -52,8 +53,8 @@ public class AbstractAuthenticationRequestLookupFunctionTest {
prc = new WebflowRequestContextProfileRequestContextLookup().apply(requestCtx);
msgCtx = new MessageContext();
prc.setInboundMessageContext(msgCtx);
- AuthenticationRequest req = new AuthenticationRequest.Builder(new ResponseType("code"), new Scope("openid"),
- new ClientID("000123"), URI.create("https://example.com/callback")).state(new State()).build();
+ final AuthorizationRequest req = new AuthorizationRequest.Builder(new ResponseType("code"),
+ new ClientID("000123")).state(new State()).build();
msgCtx.setMessage(req);
prc.setOutboundMessageContext(new MessageContext());
oidcCtx = new OIDCAuthenticationResponseContext();
@@ -61,10 +62,20 @@ public class AbstractAuthenticationRequestLookupFunctionTest {
}
@Test
- public void testOK() {
+ public void testAuthorizationRequest() {
Assert.assertEquals("OK", mock.apply(prc));
}
+ @Test
+ public void testAuthenticationRequest() {
+ final AuthenticationRequest req = new AuthenticationRequest.Builder(new ResponseType("code"),
+ new Scope("openid"), new ClientID("000123"), URI.create("https://example.com/callback"))
+ .state(new State())
+ .build();
+ msgCtx.setMessage(req);
+ Assert.assertEquals(mock.apply(prc), "OK");
+ }
+
@Test
public void testNoInboundCtxts() {
// No profilecontext
@@ -78,10 +89,10 @@ public class AbstractAuthenticationRequestLookupFunctionTest {
Assert.assertNull(mock.apply(prc));
}
- class MockOKLookupFunction extends AbstractAuthenticationRequestLookupFunction<String> {
+ class MockOKLookupFunction extends AbstractAuthorizationRequestLookupFunction<String> {
@Override
- protected String doLookup(AuthenticationRequest req) {
+ protected String doLookup(AuthorizationRequest req) {
return req != null ? new String("OK") : new String("NOK");
}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2AuthorizationRequestDecoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2AuthorizationRequestDecoder.java
new file mode 100644
index 00000000..621e6928
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2AuthorizationRequestDecoder.java
@@ -0,0 +1,80 @@
+/*
+ * 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.oauth2.decoding.impl;
+
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.decoder.MessageDecodingException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
+import com.nimbusds.oauth2.sdk.http.HTTPRequest;
+import com.nimbusds.oauth2.sdk.http.ServletUtils;
+
+import net.shibboleth.idp.plugin.oidc.op.decoding.impl.RequestUtil;
+
+/**
+ * Message decoder decoding OAuth2 {@link AuthorizationRequest}s.
+ */
+public class OAuth2AuthorizationRequestDecoder extends BaseOAuth2RequestDecoder<AuthorizationRequest> {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(OAuth2AuthorizationRequestDecoder.class);
+
+ /** {@inheritDoc} */
+ @Override
+ protected AuthorizationRequest parseMessage() throws MessageDecodingException {
+ try {
+ final HTTPRequest httpReq = ServletUtils.createHTTPRequest(getHttpServletRequest());
+ getProtocolMessageLog().trace("Inbound request {}", RequestUtil.toString(httpReq));
+ return AuthorizationRequest.parse(httpReq);
+ } catch (final com.nimbusds.oauth2.sdk.ParseException | IOException e) {
+ log.error("Unable to decode inbound request: {}", e.getMessage());
+ throw new MessageDecodingException(e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String getMessageToLog(@Nullable final AuthorizationRequest message) {
+ return message == null ? null : MoreObjects.toStringHelper(this).omitNullValues()
+ .add("clientId", message.getClientID())
+ .add("codeChallenge", message.getCodeChallenge())
+ .add("codeChallengeMethod", message.getCodeChallengeMethod())
+ .add("customParameters", message.getCustomParameters())
+ .add("endpointURI", message.getEndpointURI())
+ .add("prompt", message.getPrompt())
+ .add("redirectionURI", message.getRedirectionURI())
+ .add("requestObject", message.getRequestObject() == null ?
+ null : message.getRequestObject().serialize())
+ .add("requestURI", message.getRequestURI())
+ .add("resources", message.getResources())
+ .add("responseMode", message.getResponseMode())
+ .add("responseType", message.getResponseType())
+ .add("scope", message.getScope())
+ .add("state", message.getState())
+ .toString();
+ }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractOAuthAuthorizationRequestAction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractOAuthAuthorizationRequestAction.java
new file mode 100644
index 00000000..bcc66888
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractOAuthAuthorizationRequestAction.java
@@ -0,0 +1,49 @@
+/*
+ * 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.oauth2.profile.impl;
+
+import javax.annotation.Nonnull;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.AuthorizationRequest;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.AbstractOIDCRequestAction;
+
+/**
+ * Abstract class for actions performing actions on {@link AuthorizationRequest} found via
+ * {@link ProfileRequestContext#getInboundMessageContext()} and {@link MessageContext#getMessage()}.
+ */
+public abstract class AbstractOAuthAuthorizationRequestAction extends AbstractOIDCRequestAction<AuthorizationRequest> {
+
+ /** Class logger. */
+ @Nonnull
+ private Logger log = LoggerFactory.getLogger(AbstractOAuthAuthorizationRequestAction.class);
+
+ /**
+ * Returns OAuth authorization request.
+ *
+ * @return request
+ */
+ public AuthorizationRequest getAuthorizationRequest() {
+ return getRequest();
+ }
+
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractOAuthAuthorizationResponseAction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractOAuthAuthorizationResponseAction.java
new file mode 100644
index 00000000..9a423d42
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractOAuthAuthorizationResponseAction.java
@@ -0,0 +1,97 @@
+/*
+ * 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.oauth2.profile.impl;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+
+/**
+ *
+ * Abstract class for actions performing actions on {@link OIDCAuthenticationResponseContext} located under
+ * {@link ProfileRequestContext#getOutboundMessageContext()}. Extends baseclass that offers actions on
+ * {@link AuthorizationRequest} found via {@link MessageContext#getMessage()}.
+ */
+public abstract class AbstractOAuthAuthorizationResponseAction extends AbstractOAuthAuthorizationRequestAction {
+
+ /** Class logger. */
+ @Nonnull
+ private Logger log = LoggerFactory.getLogger(AbstractOAuthAuthorizationResponseAction.class);
+
+ /** oidc response context. */
+ @Nonnull
+ private OIDCAuthenticationResponseContext oidcResponseContext;
+
+ /** OIDC Metadata context. */
+ @Nonnull
+ private OIDCMetadataContext oidcMetadataContext;
+
+ /**
+ * Returns oidc response context.
+ *
+ * @return ctx.
+ */
+ @Nonnull
+ public OIDCAuthenticationResponseContext getOidcResponseContext() {
+ return oidcResponseContext;
+ }
+
+ /**
+ * Returns the OIDC Metadata context.
+ *
+ * @return The OIDC Metadata context.
+ */
+ public OIDCMetadataContext getMetadataContext() {
+ return oidcMetadataContext;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+ final MessageContext outboundMessageCtx = profileRequestContext.getOutboundMessageContext();
+ if (outboundMessageCtx == null) {
+ log.error("{} No outbound message context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+ return false;
+ }
+
+ oidcResponseContext = outboundMessageCtx.getSubcontext(OIDCAuthenticationResponseContext.class);
+ if (oidcResponseContext == null) {
+ log.error("{} No OIDC response context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+ return false;
+ }
+
+ oidcMetadataContext = profileRequestContext.getInboundMessageContext().getSubcontext(OIDCMetadataContext.class);
+
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/DecryptRequestObject.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/DecryptRequestObject.java
similarity index 98%
rename from idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/DecryptRequestObject.java
rename to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/DecryptRequestObject.java
index 152ece8c..3b553d18 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/DecryptRequestObject.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/DecryptRequestObject.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.security.PrivateKey;
import java.security.interfaces.ECPrivateKey;
@@ -55,7 +55,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/**
* Action decrypts request object if it is encrypted. Decrypted object is updated to response context.
*/
-public class DecryptRequestObject extends AbstractOIDCAuthenticationResponseAction {
+public class DecryptRequestObject extends AbstractOAuthAuthorizationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(DecryptRequestObject.class);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/SetAuthorizationCodeToResponseContext.java
similarity index 99%
rename from idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContext.java
rename to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/SetAuthorizationCodeToResponseContext.java
index dbd9fb0c..26a630f2 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContext.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/SetAuthorizationCodeToResponseContext.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.text.ParseException;
import java.time.Duration;
@@ -68,7 +68,7 @@ import net.shibboleth.utilities.java.support.security.impl.SecureRandomIdentifie
* {@link OIDCAuthenticationResponseContext#getAuthorizationCode()} located under
* {@link ProfileRequestContext#getOutboundMessageContext()}.
*/
-public class SetAuthorizationCodeToResponseContext extends AbstractOIDCAuthenticationResponseAction {
+public class SetAuthorizationCodeToResponseContext extends AbstractOAuthAuthorizationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(SetAuthorizationCodeToResponseContext.class);
@@ -341,7 +341,7 @@ public class SetAuthorizationCodeToResponseContext extends AbstractOIDCAuthentic
final Scope scope = responseCtx.getScope();
final AuthorizeCodeClaimsSet claimsSet = new AuthorizeCodeClaimsSet.Builder()
.setJWTID(idGenerator)
- .setClientID(getAuthenticationRequest().getClientID())
+ .setClientID(getAuthorizationRequest().getClientID())
.setIssuer(issuerLookupStrategy.apply(profileRequestContext))
.setPrincipal(subjectCtx.getPrincipalName())
.setSubject(responseCtx.getSubject())
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/oauth2/profile/impl/SetRequestObjectToResponseContext.java
similarity index 91%
rename from idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContext.java
rename to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/SetRequestObjectToResponseContext.java
index 69433df5..11f9ebd9 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/oauth2/profile/impl/SetRequestObjectToResponseContext.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.io.IOException;
import java.net.URI;
@@ -50,7 +50,7 @@ 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.
*/
-public class SetRequestObjectToResponseContext extends AbstractOIDCAuthenticationResponseAction {
+public class SetRequestObjectToResponseContext extends AbstractOAuthAuthorizationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(SetRequestObjectToResponseContext.class);
@@ -110,13 +110,13 @@ public class SetRequestObjectToResponseContext extends AbstractOIDCAuthenticatio
return false;
}
- if (!getAuthenticationRequest().specifiesRequestObject()) {
+ if (!getAuthorizationRequest().specifiesRequestObject()) {
log.debug("{} No request_uri or request by value, nothing to do", getLogPrefix());
return false;
}
- if (getAuthenticationRequest().getRequestObject() != null
- && getAuthenticationRequest().getRequestURI() != null) {
+ if (getAuthorizationRequest().getRequestObject() != null
+ && getAuthorizationRequest().getRequestURI() != null) {
log.error("{} request_uri and request object cannot be both set", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.REQUEST_OBJECT_AND_URI);
return false;
@@ -128,8 +128,8 @@ public class SetRequestObjectToResponseContext extends AbstractOIDCAuthenticatio
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- if (getAuthenticationRequest().getRequestObject() != null) {
- getOidcResponseContext().setRequestObject(getAuthenticationRequest().getRequestObject());
+ if (getAuthorizationRequest().getRequestObject() != null) {
+ getOidcResponseContext().setRequestObject(getAuthorizationRequest().getRequestObject());
log.debug("{} Request object {} by value stored to oidc response context", getLogPrefix(),
getOidcResponseContext().getRequestObject().serialize());
return;
@@ -142,19 +142,19 @@ public class SetRequestObjectToResponseContext extends AbstractOIDCAuthenticatio
if (metadata != null) {
final Set<URI> allowedURIs = metadata.getRequestObjectURIs();
if (allowedURIs != null) {
- authorized = allowedURIs.contains(getAuthenticationRequest().getRequestURI());
+ authorized = allowedURIs.contains(getAuthorizationRequest().getRequestURI());
}
}
}
if (!authorized) {
log.error("{} Unregistered request URI blocked: {}", getLogPrefix(),
- getAuthenticationRequest().getRequestURI());
+ getAuthorizationRequest().getRequestURI());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_REQUEST_URI);
return;
}
- final HttpGet httpRequest = new HttpGet(getAuthenticationRequest().getRequestURI());
+ final HttpGet httpRequest = new HttpGet(getAuthorizationRequest().getRequestURI());
final HttpClientContext httpContext = buildHttpContext(httpRequest);
try {
final HttpResponse response = httpClient.execute(httpRequest, httpContext);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallenge.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateCodeChallenge.java
similarity index 97%
rename from idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallenge.java
rename to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateCodeChallenge.java
index 29e236b4..47539722 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallenge.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateCodeChallenge.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -39,7 +39,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/**
* Validates the presence of PKCE code challenge parameter from the incoming authentication request.
*/
-public class ValidateCodeChallenge extends AbstractOIDCAuthenticationResponseAction {
+public class ValidateCodeChallenge extends AbstractOAuthAuthorizationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(ValidateCodeChallenge.class);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURI.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRedirectURI.java
similarity index 98%
rename from idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURI.java
rename to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRedirectURI.java
index efa29d55..21c3e17a 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURI.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRedirectURI.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.net.URI;
import java.util.Set;
@@ -38,7 +38,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/**
* Action that validates redirect uri is expected. Validated redirect uri is stored to response context.
*/
-public class ValidateRedirectURI extends AbstractOIDCAuthenticationResponseAction {
+public class ValidateRedirectURI extends AbstractOAuthAuthorizationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(ValidateRedirectURI.class);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRequestObject.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRequestObject.java
similarity index 97%
rename from idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRequestObject.java
rename to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRequestObject.java
index 51251f29..22cd7d71 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRequestObject.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRequestObject.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.text.ParseException;
import java.util.function.Function;
@@ -51,7 +51,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/**
* Action validates request object in response context.
*/
-public class ValidateRequestObject extends AbstractOIDCAuthenticationResponseAction {
+public class ValidateRequestObject extends AbstractOAuthAuthorizationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(ValidateRequestObject.class);
@@ -180,14 +180,14 @@ public class ValidateRequestObject extends AbstractOIDCAuthenticationResponseAct
try {
claimsSet = requestObject.getJWTClaimsSet();
if (claimsSet.getClaims().containsKey("client_id")
- && !getAuthenticationRequest().getClientID()
+ && !getAuthorizationRequest().getClientID()
.equals(new ClientID((String) claimsSet.getClaim("client_id")))) {
log.error("{} client_id in request object not matching client_id request parameter", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_REQUEST_OBJECT);
return;
}
if (claimsSet.getClaims().containsKey("response_type")
- && !getAuthenticationRequest().getResponseType().equals(new ResponseType(
+ && !getAuthorizationRequest().getResponseType().equals(new ResponseType(
((String) requestObject.getJWTClaimsSet().getClaim("response_type")).split(" ")))) {
log.error("{} response_type in request object not matching response_type request parameter",
getLogPrefix());
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateResponseType.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateResponseType.java
new file mode 100644
index 00000000..28398938
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateResponseType.java
@@ -0,0 +1,101 @@
+/*
+ * 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.oauth2.profile.impl;
+
+import java.util.Set;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.nimbusds.oauth2.sdk.ResponseType;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestResponseTypeLookupFunction;
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultValidResponseTypesLookupFunction;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * An action that validates the requested response_type is (1) registered to the requesting RP and (2) valid for the
+ * protocol used for request.
+ */
+public class ValidateResponseType extends AbstractOAuthAuthorizationResponseAction {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(ValidateResponseType.class);
+
+ /** Lookup strategy for fetching the requested response type. */
+ @NonnullAfterInit private Function<ProfileRequestContext, ResponseType> requestedResponseTypeLookupStrategy;
+
+ /** Lookup strategy for fetching the valid response types matching the request message. */
+ @NonnullAfterInit private Function<ProfileRequestContext, Set<ResponseType>> validResponseTypesLookupStrategy;
+
+ /**
+ * Constructor.
+ */
+ public ValidateResponseType() {
+ requestedResponseTypeLookupStrategy = new DefaultRequestResponseTypeLookupFunction();
+ validResponseTypesLookupStrategy = new DefaultValidResponseTypesLookupFunction();
+ }
+
+ /**
+ * Set the lookup strategy for fetching the requested response type.
+ *
+ * @param strategy What to set.
+ */
+ public void setRequestedResponseTypeLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, ResponseType> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ requestedResponseTypeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Set the lookup strategy for fetching the valid response types matching the request message.
+ *
+ * @param strategy What to set.
+ */
+ public void setValidResponseTypesLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, Set<ResponseType>> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ validResponseTypesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ final Set<ResponseType> registeredTypes = getMetadataContext() != null
+ ? getMetadataContext().getClientInformation().getMetadata().getResponseTypes()
+ : null;
+ final ResponseType requestedType = requestedResponseTypeLookupStrategy.apply(profileRequestContext);
+ if (registeredTypes == null || registeredTypes.isEmpty() || !registeredTypes.contains(requestedType)) {
+ log.warn("{} The response type {} is not registered for this RP", getLogPrefix(), requestedType);
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_RESPONSE_TYPE);
+ }
+ final Set<ResponseType> validTypes = validResponseTypesLookupStrategy.apply(profileRequestContext);
+ if (validTypes == null || validTypes.isEmpty() || !validTypes.contains(requestedType)) {
+ log.warn("{} The response type {} is not valid for this request", getLogPrefix(), requestedType);
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_RESPONSE_TYPE);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScope.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateScope.java
similarity index 92%
rename from idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScope.java
rename to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateScope.java
index 1b801ea1..5b860f85 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScope.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateScope.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.util.Iterator;
import java.util.function.Function;
@@ -24,6 +24,8 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,7 +49,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
* and stores the resulting set in the response context.
*
* <p>Requested scopes come from the inbound message and are possible but optional for both
- * authorization and token requests. They come from lookup functions aware of each message type.</p>
+ * authorization and token requests. They come from lookup functions aware of each message type. If the request
+ * contains 'openid' scope but it's not allowed for this request, an error event published.</p>
*
* <p>Previously granted scopes are stored in the response context's slot for previous authorization
* grant claims. In the case where no scopes are explicitly requested, we still filter the previous
@@ -60,7 +63,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
* <p>The "offline_access" scope is ignored and stripped for the authentication endpoint unless the
* response type includes "code".</p>
*/
-public class ValidateScope extends AbstractOIDCAuthenticationResponseAction {
+public class ValidateScope extends AbstractOAuthAuthorizationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(ValidateScope.class);
@@ -147,14 +150,7 @@ public class ValidateScope extends AbstractOIDCAuthenticationResponseAction {
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final String clientId = relyingPartyIdLookupStrategy.apply(profileRequestContext);
-
- // These typically come from metadata but may be supplemented or substituted from elsewhere.
- final Scope allowedScopes = allowedScopeLookupStrategy.apply(profileRequestContext);
- if (allowedScopes == null || allowedScopes.isEmpty()) {
- log.debug("{} No allowed scope for client {}, nothing to do", getLogPrefix(), clientId);
- return;
- }
-
+
// These come from a previous authorization grant (authz code or access/refresh token).
Scope previouslyGrantedScopes = null;
if (getOidcResponseContext().getAuthorizationGrantClaimsSet() != null) {
@@ -170,7 +166,24 @@ public class ValidateScope extends AbstractOIDCAuthenticationResponseAction {
requestedScopes = previouslyGrantedScopes;
previouslyGrantedScopes = null;
}
-
+
+ // These typically come from metadata but may be supplemented or substituted from elsewhere.
+ final Scope allowedScopes = allowedScopeLookupStrategy.apply(profileRequestContext);
+
+ final String oidcScope = OIDCScopeValue.OPENID.getValue();
+ if (requestedScopes != null && requestedScopes.contains(oidcScope) &&
+ (allowedScopes == null || !allowedScopes.contains(oidcScope))) {
+ log.warn("{} OIDC sequence was requested but no openid scope granted for RP {}", getLogPrefix(),
+ clientId);
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+ return;
+ }
+
+ if (allowedScopes == null || allowedScopes.isEmpty()) {
+ log.debug("{} No allowed scope for client {}, nothing to do", getLogPrefix(), clientId);
+ return;
+ }
+
boolean reducedRequestedScopes = false;
for (Iterator<Scope.Value> i = requestedScopes.iterator(); i.hasNext();) {
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/FormOutboundAuthenticationResponseMessage.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/FormOutboundAuthenticationResponseMessage.java
index cd425f9a..254e13ae 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/FormOutboundAuthenticationResponseMessage.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/FormOutboundAuthenticationResponseMessage.java
@@ -28,10 +28,14 @@ import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.nimbusds.oauth2.sdk.AuthorizationResponse;
+import com.nimbusds.oauth2.sdk.AuthorizationSuccessResponse;
import com.nimbusds.oauth2.sdk.id.Issuer;
+import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
+import net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.AbstractOAuthAuthorizationResponseAction;
import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestResponseModeLookupFunction;
import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestStateLookupFunction;
import net.shibboleth.idp.profile.IdPEventIds;
@@ -45,7 +49,7 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
* Action that forms outbound message based on request and response context. Formed message is set to
* {@link ProfileRequestContext#getOutboundMessageContext()}.
*/
-public class FormOutboundAuthenticationResponseMessage extends AbstractOIDCAuthenticationResponseAction {
+public class FormOutboundAuthenticationResponseMessage extends AbstractOAuthAuthorizationResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(FormOutboundAuthenticationResponseMessage.class);
@@ -120,11 +124,21 @@ public class FormOutboundAuthenticationResponseMessage extends AbstractOIDCAuthe
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
return;
}
- final AuthenticationResponse resp = new AuthenticationSuccessResponse(getOidcResponseContext().getRedirectURI(),
- getOidcResponseContext().getAuthorizationCode(), getOidcResponseContext().getProcessedToken(),
- getOidcResponseContext().getAccessToken(),
- new DefaultRequestStateLookupFunction().apply(profileRequestContext), null, issuer,
- new DefaultRequestResponseModeLookupFunction().apply(profileRequestContext));
- profileRequestContext.getOutboundMessageContext().setMessage(resp);
+ if (getAuthorizationRequest() instanceof AuthenticationRequest) {
+ final AuthenticationResponse resp = new AuthenticationSuccessResponse(
+ getOidcResponseContext().getRedirectURI(),
+ getOidcResponseContext().getAuthorizationCode(), getOidcResponseContext().getProcessedToken(),
+ getOidcResponseContext().getAccessToken(),
+ new DefaultRequestStateLookupFunction().apply(profileRequestContext), null, issuer,
+ new DefaultRequestResponseModeLookupFunction().apply(profileRequestContext));
+ profileRequestContext.getOutboundMessageContext().setMessage(resp);
+ } else {
+ final AuthorizationResponse resp = new AuthorizationSuccessResponse(
+ getOidcResponseContext().getRedirectURI(),
+ getOidcResponseContext().getAuthorizationCode(), getOidcResponseContext().getAccessToken(),
+ new DefaultRequestStateLookupFunction().apply(profileRequestContext), issuer,
+ new DefaultRequestResponseModeLookupFunction().apply(profileRequestContext));
+ profileRequestContext.getOutboundMessageContext().setMessage(resp);
+ }
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateResponseType.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateResponseType.java
deleted file mode 100644
index e3055390..00000000
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateResponseType.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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 java.util.Set;
-import javax.annotation.Nonnull;
-
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.nimbusds.oauth2.sdk.ResponseType;
-
-import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestResponseTypeLookupFunction;
-import net.shibboleth.oidc.profile.core.OidcEventIds;
-
-/**
- * An action that validates the requested response_type is registered to the requesting RP.
- */
-public class ValidateResponseType extends AbstractOIDCAuthenticationResponseAction {
-
- /** Class logger. */
- @Nonnull private Logger log = LoggerFactory.getLogger(ValidateResponseType.class);
-
- /** {@inheritDoc} */
- @Override
- protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- final Set<ResponseType> registeredTypes = getMetadataContext() != null
- ? getMetadataContext().getClientInformation().getMetadata().getResponseTypes()
- : null;
- final ResponseType requestedType = new DefaultRequestResponseTypeLookupFunction().apply(profileRequestContext);
- if (registeredTypes == null || registeredTypes.isEmpty() || !registeredTypes.contains(requestedType)) {
- log.warn("{} The response type {} is not registered for this RP", getLogPrefix(), requestedType);
- ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_RESPONSE_TYPE);
- }
- }
-
-}
\ No newline at end of file
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 20f96972..9c2ca708 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
@@ -14,13 +14,20 @@
<bean id="shibboleth.oidc.loggingId" class="java.lang.String" c:_0="%{idp.service.logging.oidcsso:OIDC.SSO}" />
- <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
+ <bean id="DecodeOIDCMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
<bean class="net.shibboleth.idp.plugin.oidc.op.decoding.impl.OIDCAuthenticationRequestDecoder"
scope="prototype" p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
</constructor-arg>
</bean>
+ <bean id="DecodeOAuthMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
+ <constructor-arg>
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oauth2.decoding.impl.OAuth2AuthorizationRequestDecoder"
+ scope="prototype" p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
+ </constructor-arg>
+ </bean>
+
<bean id="InitializeAuthenticationContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeAuthenticationContext" scope="prototype"
p:loginHintLookupStrategy-ref="%{idp.oidc.LoginHintLookupStrategy:DefaultRequestLoginHintLookupFunction}"/>
@@ -39,7 +46,8 @@
scope="prototype" />
<bean id="SetRequestedSubjectToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestedSubjectToResponseContext" scope="prototype" />
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestedSubjectToResponseContext" scope="prototype"
+ p:activationCondition-ref="ScopeContainsOpenid"/>
<bean id="SetSessionIdToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSessionIdToResponseContext" scope="prototype"
@@ -47,7 +55,8 @@
<bean id="SetRequestedClaimsToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestedClaimsToResponseContext" scope="prototype"
- p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
+ p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
+ p:activationCondition-ref="ScopeContainsOpenid"/>
<bean id="PopulatePostAuthnInterceptContext"
class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext" scope="prototype"
@@ -106,14 +115,14 @@
p:parameterType="#{T(net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureValidationParametersResolver.ParameterType).REQUEST_OBJECT_VALIDATION}" />
<bean id="SetRequestObjectToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestObjectToResponseContext" scope="prototype"
+ class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.SetRequestObjectToResponseContext" scope="prototype"
p:httpClient="#{getObject('shibboleth.oidc.NonBrowser.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
p:httpClientSecurityParameters="#{getObject('shibboleth.oidc.NonBrowser.HttpClientSecurityParameters')}" />
- <bean id="DecryptRequestObject" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.DecryptRequestObject"
+ <bean id="DecryptRequestObject" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.DecryptRequestObject"
scope="prototype" />
- <bean id="ValidateRequestObject" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateRequestObject"
+ <bean id="ValidateRequestObject" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateRequestObject"
scope="prototype"
p:plainClaimsValidator-ref="shibboleth.oidc.PlainRequestObjectClaimsValidation"
p:signedClaimsValidator-ref="shibboleth.oidc.SignedRequestObjectClaimsValidation">
@@ -171,16 +180,16 @@
<ref bean="AudienceClaimsValidator" />
</util:list>
- <bean id="ValidateRedirectURI" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateRedirectURI"
+ <bean id="ValidateRedirectURI" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateRedirectURI"
scope="prototype" p:requireRequestedValue="true" />
- <bean id="ValidateResponseType" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateResponseType"
+ <bean id="ValidateResponseType" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateResponseType"
scope="prototype" />
- <bean id="ValidateCodeChallenge" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateCodeChallenge"
+ <bean id="ValidateCodeChallenge" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateCodeChallenge"
scope="prototype" />
- <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateScope" scope="prototype"
+ <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateScope" scope="prototype"
p:allowedScopeLookupStrategy="#{getObject('shibboleth.oidc.AllowedScopeStrategy') ?: getObject('shibboleth.oidc.DefaultAllowedScopeStrategy')}" />
<bean id="ValidateAudience"
@@ -362,7 +371,8 @@
</bean>
<bean id="VerifyRequestedSubjectIdentifier"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.VerifyRequestedSubjectIdentifier" scope="prototype" />
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.VerifyRequestedSubjectIdentifier" scope="prototype"
+ p:activationCondition-ref="ScopeContainsOpenid"/>
<bean id="SetTokenDeliveryAttributesToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetTokenDeliveryAttributesToResponseContext" scope="prototype"
@@ -383,7 +393,7 @@
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetConsentToResponseContext" scope="prototype" />
<bean id="SetAuthorizationCodeToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthorizationCodeToResponseContext" scope="prototype"
+ class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.SetAuthorizationCodeToResponseContext" scope="prototype"
p:dataSealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}">
<property name="identifierGeneratorLookupStrategy">
<bean class="net.shibboleth.idp.profile.config.navigate.IdentifierGenerationStrategyLookupFunction"
@@ -633,4 +643,12 @@
</constructor-arg>
</bean>
+ <bean id="ScopeContainsOpenid" parent="shibboleth.Conditions.Expression" p:customObject-ref="shibboleth.HttpServletRequest">
+ <constructor-arg>
+ <value>
+ #custom.getParameter('scope') != null and #custom.getParameter('scope').contains('openid')
+ </value>
+ </constructor-arg>
+ </bean>
+
</beans>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
index 51f782e3..33be18f7 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
@@ -8,11 +8,25 @@
<evaluate expression="PopulateMetricContext" />
<evaluate expression="FlowStartPopulateAuditContext" />
<evaluate expression="'proceed'" />
- <transition on="proceed" to="DecodeMessage" />
+ <transition on="proceed" to="CheckRequestType">
+ <set name="flowScope.oidcAuthnRequest" value="ScopeContainsOpenid.test(opensamlProfileRequestContext)" />
+ </transition>
</action-state>
- <action-state id="DecodeMessage">
- <evaluate expression="DecodeMessage" />
+ <decision-state id="CheckRequestType">
+ <if test="oidcAuthnRequest" then="DecodeOIDCMessage" else="DecodeOAuthMessage" />
+ </decision-state>
+
+ <action-state id="DecodeOIDCMessage">
+ <evaluate expression="DecodeOIDCMessage" />
+ <evaluate expression="PostDecodePopulateAuditContext" />
+ <evaluate expression="'proceed'" />
+ <!-- DoMetadataLookup is expected to proceed to SelectConfiguration -->
+ <transition on="proceed" to="DoMetadataLookup" />
+ </action-state>
+
+ <action-state id="DecodeOAuthMessage">
+ <evaluate expression="DecodeOAuthMessage" />
<evaluate expression="PostDecodePopulateAuditContext" />
<evaluate expression="'proceed'" />
<!-- DoMetadataLookup is expected to proceed to SelectConfiguration -->
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
index 1ce78d1b..8f5f7222 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
@@ -66,7 +66,7 @@
<bean id="ValidatePKCE" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidatePKCE" scope="prototype" />
- <bean id="ValidateRedirectURI" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateRedirectURI"
+ <bean id="ValidateRedirectURI" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateRedirectURI"
scope="prototype"
p:activationCondition-ref="AuthorizationCodeGrantCondition"
p:redirectURILookupStrategy-ref="shibboleth.TokenRequestRedirectURILookupStrategy"
@@ -143,7 +143,7 @@
<!-- Common grant handling. -->
- <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateScope" scope="prototype"
+ <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateScope" scope="prototype"
p:requestedScopeLookupStrategy-ref="TokenRequestScopeLookupStrategy"
p:allowedScopeLookupStrategy="#{getObject('shibboleth.oidc.AllowedScopeStrategy') ?: getObject('shibboleth.oidc.DefaultAllowedScopeStrategy')}" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
index f7c36d64..4af5b42f 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
@@ -41,7 +41,7 @@
<bean id="ValidateAccessToken"
class="net.shibboleth.idp.plugin.oidc.op.userinfo.profile.impl.ValidateAccessToken" scope="prototype" />
- <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateScope" scope="prototype"
+ <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateScope" scope="prototype"
p:allowedScopeLookupStrategy="#{getObject('shibboleth.oidc.AllowedScopeStrategy') ?: getObject('shibboleth.oidc.DefaultAllowedScopeStrategy')}">
<property name="requestedScopeLookupStrategy">
<null/>
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/DecryptRequestObjectTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/DecryptRequestObjectTest.java
similarity index 99%
rename from idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/DecryptRequestObjectTest.java
rename to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/DecryptRequestObjectTest.java
index af3f9cde..e218c714 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/DecryptRequestObjectTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/DecryptRequestObjectTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/SetAuthorizationCodeToResponseContextTest.java
similarity index 98%
rename from idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContextTest.java
rename to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/SetAuthorizationCodeToResponseContextTest.java
index 3441dad6..1ccea4c9 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContextTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/SetAuthorizationCodeToResponseContextTest.java
@@ -15,11 +15,12 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseConsentContext;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseTokenClaimsContext;
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.BaseOIDCResponseActionTest;
import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
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/oauth2/profile/impl/SetRequestObjectToResponseContextTest.java
similarity index 97%
rename from idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestObjectToResponseContextTest.java
rename to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/SetRequestObjectToResponseContextTest.java
index 90cf356a..23cdd3a5 100644
--- 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/oauth2/profile/impl/SetRequestObjectToResponseContextTest.java
@@ -15,8 +15,9 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.BaseOIDCResponseActionTest;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.oidc.profile.core.OidcEventIds;
import net.shibboleth.utilities.java.support.httpclient.HttpClientBuilder;
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallengeTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateCodeChallengeTest.java
similarity index 98%
rename from idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallengeTest.java
rename to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateCodeChallengeTest.java
index 8983c4bc..3dc086ff 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallengeTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateCodeChallengeTest.java
@@ -15,10 +15,11 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.net.URISyntaxException;
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.BaseOIDCResponseActionTest;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.oidc.profile.core.OidcEventIds;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURITest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRedirectURITest.java
similarity index 97%
rename from idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURITest.java
rename to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRedirectURITest.java
index 344774c2..00bf129f 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURITest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRedirectURITest.java
@@ -15,12 +15,13 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Set;
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.BaseOIDCResponseActionTest;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.oidc.profile.core.OidcEventIds;
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRequestObjectTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRequestObjectTest.java
similarity index 99%
rename from idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRequestObjectTest.java
rename to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRequestObjectTest.java
index 5c2d7420..0ba44ab9 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRequestObjectTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateRequestObjectTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateResponseTypeTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateResponseTypeTest.java
similarity index 96%
rename from idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateResponseTypeTest.java
rename to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateResponseTypeTest.java
index 3138d21d..3c22c2a2 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateResponseTypeTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateResponseTypeTest.java
@@ -15,13 +15,14 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Set;
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.BaseOIDCResponseActionTest;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.oidc.profile.core.OidcEventIds;
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScopeTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateScopeTest.java
similarity index 97%
rename from idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScopeTest.java
rename to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateScopeTest.java
index 2cd22f34..eb36d64d 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScopeTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateScopeTest.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.net.URI;
import java.net.URISyntaxException;
@@ -23,11 +23,13 @@ import java.time.Instant;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseTokenClaimsContext;
import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestScopeLookupFunction;
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.BaseOIDCResponseActionTest;
import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import org.opensaml.profile.action.EventIds;
import org.springframework.webflow.execution.Event;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
@@ -113,11 +115,8 @@ public class ValidateScopeTest extends BaseOIDCResponseActionTest {
public void testAuthnNoScopes() throws ComponentInitializationException {
metaData.setScope(null);
final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertProceedEvent(event);
+ ActionTestingSupport.assertEvent(event, EventIds.INVALID_MESSAGE);
Assert.assertNull(respCtx.getScope());
- final OIDCAuthenticationResponseTokenClaimsContext tokenClaimsCtx =
- respCtx.getSubcontext(OIDCAuthenticationResponseTokenClaimsContext.class);
- Assert.assertNotNull(tokenClaimsCtx);
}
/**
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 16c84fa4..fbc73fec 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
@@ -18,6 +18,8 @@
package net.shibboleth.idp.plugin.oidc.op.profile.flow;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
import java.text.ParseException;
import java.time.Duration;
import java.time.Instant;
@@ -39,6 +41,8 @@ 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.AuthorizationResponse;
+import com.nimbusds.oauth2.sdk.AuthorizationSuccessResponse;
import com.nimbusds.oauth2.sdk.Response;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
@@ -52,6 +56,7 @@ import net.shibboleth.idp.plugin.oidc.op.token.support.AccessTokenClaimsSet;
import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
import net.shibboleth.idp.session.SessionException;
import net.shibboleth.oidc.profile.core.OidcError;
+import net.shibboleth.utilities.java.support.collection.Pair;
import net.shibboleth.utilities.java.support.security.DataSealerException;
/**
@@ -85,9 +90,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlow() throws IOException, SessionException {
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri);
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -106,8 +113,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowAndResource() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&resource=" + resource +
- "&redirect_uri=" + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("resource", resource)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -126,8 +136,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowIssInResponse() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdIssInResponse&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdIssInResponse"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientIdIssInResponse, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -147,20 +159,29 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowNoOpenid() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- Assert.assertEquals("ErrorView", result.getOutcome().getId());
+ final AuthorizationResponse responseMessage = parseSuccessResponse(result, AuthorizationResponse.class);
+ final AuthorizationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNull(successResponse.getIssuer());
}
@Test
public void testWithAuthorizationCodeFlowNoRedirectURI() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -172,8 +193,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithImplicitFlowNoNonce() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -185,8 +208,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithImplicitFlow() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile&redirect_uri="
- + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -205,8 +231,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithImplicitFlowIssInResponse() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdIssInResponse&response_type=id_token&scope=openid%20profile&redirect_uri="
- + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdIssInResponse"),
+ new Pair<>("response_type", "id_token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientIdIssInResponse, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -226,8 +255,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithImplicitFlowAndResource() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile&resource=" + resource
- + "&redirect_uri=" + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("resource", resource),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -246,8 +279,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithImplicitTokenFlow() throws IOException, SessionException, DataSealerException, ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=id_token+token&scope=openid%20profile"
- + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -274,8 +310,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithImplicitTokenFlowIssInResponse() throws IOException, SessionException, DataSealerException, ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdIssInResponse&response_type=id_token+token&scope=openid%20profile"
- + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdIssInResponse"),
+ new Pair<>("response_type", "id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientIdIssInResponse, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -303,8 +342,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithImplicitTokenFlowAndResource() throws IOException, SessionException, ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=id_token+token&scope=openid%20profile"
- + "&resource=" + resource + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("resource", resource),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -330,8 +373,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithImplicitTokenFlowNoNonce() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=id_token+token&scope=openid%20profile"
- + "&redirect_uri="+ redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -341,22 +386,47 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithImplicitFlowNoOpenIdScope() throws IOException, SessionException {
+ public void testWithImplicitOidcFlowNoOpenIdScopeRequested() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=id_token&scope=profile&redirect_uri="
- + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token token"),
+ new Pair<>("scope", "profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- Assert.assertEquals("ErrorView", result.getOutcome().getId());
+ assertErrorCode(result, "unsupported_response_type");
+ assertErrorDescriptionContains(result, "Unsupported response");
+ assertErrorResponseWithNoIssuer(result);
+ }
+
+ @Test
+ public void testWithImplicitOidcFlowNoOpenIdScopeRegistered() throws IOException, SessionException {
+ request.setMethod("GET");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
+ storeMetadata(storageService, clientId, clientSecret, Scope.parse("profile"), redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "invalid_request");
+ assertErrorDescriptionContains(result, "InvalidMessage");
+ assertErrorResponseWithNoIssuer(result);
}
@Test
public void testWithImplicitFlowNoRedirectURI() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "id_token token"),
+ new Pair<>("scope", "openid profile")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -368,8 +438,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithHybridIdTokenFlow() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code+id_token&scope=openid%20profile"
- + "&redirect_uri=" + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code id_token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -391,8 +464,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithHybridIdTokenFlowIssInResponse() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdIssInResponse&response_type=code+id_token&scope=openid%20profile"
- + "&redirect_uri=" + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdIssInResponse"),
+ new Pair<>("response_type", "code id_token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientIdIssInResponse, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -415,8 +491,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithHybridIdTokenFlowAndResource() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code+id_token&scope=openid%20profile"
- + "&resource=" + resource + "&redirect_uri=" + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code id_token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("resource", resource),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -437,8 +517,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithHybridIdTokenFlowNoNonce() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code+id_token&scope=openid%20profile"
- + "&redirect_uri=" + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code id_token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -450,8 +532,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithHybridTokenFlow() throws IOException, SessionException, ParseException, DataSealerException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code+token&scope=openid%20profile"
- + "&redirect_uri="+ redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -476,11 +560,48 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIssuer());
}
+ @Test
+ public void testWithHybridTokenFlowNoOpenidScopeRequested() throws IOException, SessionException, ParseException, DataSealerException {
+ request.setMethod("GET");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code token"),
+ new Pair<>("scope", "profile"),
+ new Pair<>("redirect_uri", redirectUri)));
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "unsupported_response_type");
+ assertErrorDescriptionContains(result, "Unsupported response");
+ assertErrorResponseWithNoIssuer(result);
+ }
+
+ @Test
+ public void testWithHybridTokenFlowNoOpenidScopeRegistered() throws IOException, SessionException, ParseException, DataSealerException {
+ request.setMethod("GET");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
+ storeMetadata(storageService, clientId, clientSecret, Scope.parse("profile"), redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "invalid_request");
+ assertErrorDescriptionContains(result, "InvalidMessage");
+ assertErrorResponseWithNoIssuer(result);
+ }
+
@Test
public void testWithHybridTokenFlowAndResource() throws IOException, SessionException, ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code+token&scope=openid%20profile"
- + "&resource=" + resource + "&redirect_uri="+ redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("resource", resource),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -507,8 +628,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithHybridIdTokenTokenFlow() throws IOException, SessionException, ParseException, DataSealerException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code+id_token+token&scope=openid%20profile"
- + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -532,12 +656,51 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(token.getClaimsSet().getStringClaim("eduPersonScopedAffiliation"));
}
+ @Test
+ public void testWithHybridIdTokenTokenFlowNoOpenidScopeRequested() throws IOException, SessionException, ParseException, DataSealerException {
+ request.setMethod("GET");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code id_token token"),
+ new Pair<>("scope", "profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "unsupported_response_type");
+ assertErrorDescriptionContains(result, "Unsupported response");
+ assertErrorResponseWithNoIssuer(result);
+ }
+
+ @Test
+ public void testWithHybridIdTokenTokenFlowNoOpenidScopeRegistered() throws IOException, SessionException, ParseException, DataSealerException {
+ request.setMethod("GET");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
+ storeMetadata(storageService, clientId, clientSecret, Scope.parse("profile"), redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "invalid_request");
+ assertErrorDescriptionContains(result, "InvalidMessage");
+ assertErrorResponseWithNoIssuer(result);
+ }
+
@Test
public void testWithHybridIdTokenTokenFlowWithCustomTokenClaim() throws IOException, SessionException,
ParseException, DataSealerException, com.nimbusds.oauth2.sdk.ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdCustomTokens&response_type=code+id_token+token&scope=openid%20profile"
- + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdCustomTokens"),
+ new Pair<>("response_type", "code id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientIdCustomTokens, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -574,8 +737,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithHybridIdTokenTokenFlowAndResource() throws IOException, SessionException, ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code+id_token+token&scope=openid%20profile"
- + "&resource=" + resource + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("resource", resource),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -603,8 +770,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithHybridIdTokenTokenFlowNoNonce() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code+id_token+token&scope=openid%20profile"
- + "&redirect_uri="+ redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -616,8 +785,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowUnforcedPKCE() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdPKCEPlainUnforced&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdPKCEPlainUnforced"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, "mockClientIdPKCEPlainUnforced", clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -635,8 +806,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowForcedPlainPKCEMissingChallenge() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdPKCEPlain"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, "mockClientIdPKCEPlain", clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -649,8 +822,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowForcedPlainPKCEUnknownChallenge() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=unsupported");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdPKCEPlain"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("code_challenge", "osdfojsfod"),
+ new Pair<>("code_challenge_method", "unsupported")));
storeMetadata(storageService, "mockClientIdPKCEPlain", clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -663,8 +840,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowForcedPlainPKCEValidChallenge() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=plain");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdPKCEPlain"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("code_challenge", "osdfojsfod"),
+ new Pair<>("code_challenge_method", "plain")));
storeMetadata(storageService, "mockClientIdPKCEPlain", clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -682,8 +863,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowForcedS256PKCEPlainChallenge() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=plain");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdPKCES256"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("code_challenge", "osdfojsfod"),
+ new Pair<>("code_challenge_method", "plain")));
storeMetadata(storageService, "mockClientIdPKCES256", clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -696,8 +881,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowForcedS256PKCEUnknownChallenge() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=unknown");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdPKCES256"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("code_challenge", "osdfojsfod"),
+ new Pair<>("code_challenge_method", "unknown")));
storeMetadata(storageService, "mockClientIdPKCES256", clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -710,8 +899,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowForcedS256PKCEValidChallenge() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=S256");
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdPKCES256"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("code_challenge", "osdfojsfod"),
+ new Pair<>("code_challenge_method", "S256")));
storeMetadata(storageService, "mockClientIdPKCES256", clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -727,45 +920,47 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowNoScopes() throws IOException, SessionException {
+ public void testWithAuthorizationCodeFlowNoScopesRegistered() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, null, redirectUri);
initializeThreadLocals();
- // TODO: Speculation this should fail more explicitly if openid scope isn't valid.
-
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
assertErrorCode(result, "invalid_request");
- assertErrorDescriptionContains(result, "InvalidSubject");
+ assertErrorDescriptionContains(result, "InvalidMessage");
assertErrorResponseWithNoIssuer(result);
}
@Test
- public void testWithAuthorizationCodeFlowNoScopesIssInResponse() throws IOException, SessionException {
+ public void testWithAuthorizationCodeFlowNoScopesRegisteredIssInResponse() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdIssInResponse&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdIssInResponse"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientIdIssInResponse, clientSecret, null, redirectUri);
initializeThreadLocals();
-
- // TODO: Speculation this should fail more explicitly if openid scope isn't valid.
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
assertErrorCode(result, "invalid_request");
- assertErrorDescriptionContains(result, "InvalidSubject");
+ assertErrorDescriptionContains(result, "InvalidMessage");
assertErrorResponseWithIssuer(result);
}
@Test
public void testWithAuthorizationCodeFlowWithIDTokenClaims() throws IOException, SessionException, DataSealerException, ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile"
- + "&claims=%7B%22id_token%22%3A%7B%22email%22%3A%7B%22essential%22%3Atrue%7D%7D%7D"
- + "&redirect_uri=" + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("claims", "{\"id_token\":{\"email\":{\"essential\":true}}}"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -794,9 +989,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowWithUIClaims() throws IOException, SessionException, DataSealerException, ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile"
- + "&claims=%7B%22userinfo%22%3A%7B%22email%22%3A%7B%22essential%22%3Atrue%7D%7D%7D"
- + "&redirect_uri=" + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("claims", "{\"userinfo\":{\"email\":{\"essential\":true}}}"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -825,9 +1022,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowWithCustomClaimInCode() throws IOException, SessionException, DataSealerException, ParseException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientIdCustomTokens&response_type=code&scope=openid%20profile"
- + "&claims=%7B%22userinfo%22%3A%7B%22email%22%3A%7B%22essential%22%3Atrue%7D%7D%7D"
- + "&redirect_uri=" + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientIdCustomTokens"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("claims", "{\"userinfo\":{\"email\":{\"essential\":true}}}"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientIdCustomTokens, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -852,8 +1051,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowUsingSAMLMetadata() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=mockSamlClientId&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "mockSamlClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -872,8 +1073,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@Test
public void testWithAuthorizationCodeFlowUsingUntrustedRP() throws IOException, SessionException {
request.setMethod("GET");
- request.setQueryString("client_id=notTrusted&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri);
+ setRequestParameters(List.of(new Pair<>("client_id", "notTrusted"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri)));
initializeThreadLocals();
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -904,8 +1107,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
.build();
final PlainJWT requestObject = new PlainJWT(ro);
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
- + "https://invalid.org/cb&request=" + requestObject.serialize());
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", "https://invalid.org/cb"),
+ new Pair<>("request", requestObject.serialize())));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -953,8 +1159,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final PlainJWT requestObject = new PlainJWT(ro);
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
- + "https://invalid.org/cb&request=" + requestObject.serialize());
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", "https://invalid.org/cb"),
+ new Pair<>("request", requestObject.serialize())));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -1036,8 +1245,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
.build();
final SignedJWT requestObject = createSecretJWT(ro, clientSecret);
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
- + "https://invalid.org/cb&request=" + requestObject.serialize());
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", "https://invalid.org/cb"),
+ new Pair<>("request", requestObject.serialize())));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -1084,8 +1296,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final JWTClaimsSet ro = JWTClaimsSet.parse(payload);
final SignedJWT requestObject = createSecretJWT(ro, clientSecret);
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri + "&request=" + requestObject.serialize());
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("request", requestObject.serialize())));
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -1122,8 +1337,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
protected void assertRequestObjectError(final JWT requestObject) throws IOException {
request.setMethod("GET");
- request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
- + redirectUri + "&request=" + requestObject.serialize());
+ setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
+ new Pair<>("response_type", "code"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("request", requestObject.serialize())));
+
storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
initializeThreadLocals();
@@ -1194,6 +1413,19 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
return null;
}
}
+
+ protected void setRequestParameters(final List<Pair<String, String>> pairs) {
+ final StringBuffer query = new StringBuffer();
+ for (final Pair<String, String> pair : pairs) {
+ request.addParameter(pair.getFirst(), pair.getSecond());
+ try {
+ query.append(pair.getFirst() + "=" + URLEncoder.encode(pair.getSecond(), "UTF-8") + "&");
+ } catch (UnsupportedEncodingException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+ request.setQueryString(query.toString());
+ }
@AfterMethod
public void removeMetadata() throws IOException {
diff --git a/idp-oidc-extension-impl/src/test/resources/conf/attribute-filter.xml b/idp-oidc-extension-impl/src/test/resources/conf/attribute-filter.xml
index 840261ae..6ad3c07e 100644
--- a/idp-oidc-extension-impl/src/test/resources/conf/attribute-filter.xml
+++ b/idp-oidc-extension-impl/src/test/resources/conf/attribute-filter.xml
@@ -109,6 +109,18 @@
<AttributeRule attributeID="eduPersonScopedAffiliation" permitAny="true" />
</AttributeFilterPolicy>
+ <AttributeFilterPolicy id="OAUTH_SUBJECT">
+ <PolicyRequirementRule xsi:type="AND">
+ <Rule xsi:type="NOT">
+ <Rule xsi:type="oidc:OIDCScope" value="openid" />
+ </Rule>
+ <Rule xsi:type="Profile" value="http://shibboleth.net/ns/profiles/oidc/sso/browser" />
+ </PolicyRequirementRule>
+ <AttributeRule attributeID="subject">
+ <PermitValueRule xsi:type="ANY" />
+ </AttributeRule>
+ </AttributeFilterPolicy>
+
<AttributeFilterPolicy id="OPENID_SCOPE">
<PolicyRequirementRule xsi:type="oidc:OIDCScope" value="openid" />
<AttributeRule attributeID="subject">
@@ -125,6 +137,9 @@
<AttributeFilterPolicy id="OPENID_SCOPE_PROFILE">
<PolicyRequirementRule xsi:type="oidc:OIDCScope" value="profile" />
+ <AttributeRule attributeID="subject">
+ <PermitValueRule xsi:type="ANY" />
+ </AttributeRule>
<AttributeRule attributeID="name">
<PermitValueRule xsi:type="ANY" />
</AttributeRule>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list