[java-idp-plugin-oidc-rp] branch main updated: Changes to support request object generation
Phil Smart
philip.smart at jisc.ac.uk
Fri Jul 1 12:58:47 UTC 2022
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-idp-plugin-oidc-rp.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-oidc-rp.git;a=commit;h=eb512cbf357baba719196eec45544769a19a42f7
The following commit(s) were added to refs/heads/main by this push:
new eb512cb Changes to support request object generation
eb512cb is described below
commit eb512cbf357baba719196eec45544769a19a42f7
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Jul 1 13:58:40 2022 +0100
Changes to support request object generation
- Add basic claims
- Population of signing parameters
- Cleanup flow
- Refactor how parameters are added to the authentication request
---
idp-oidc-rp-api/pom.xml | 5 +
...TokenDecryptionConfigurationLookupFunction.java | 8 +-
...atureValidationConfigurationLookupFunction.java | 8 +-
.../InboundMessageContextFromProxyPRC.java | 55 ++++
...gnatureSigningConfigurationLookupFunction.java} | 19 +-
...rInfoDecryptionConfigurationLookupFunction.java | 8 +-
...atureValidationConfigurationLookupFunction.java | 9 +-
.../rp/context/ResponseTypeAndModeContext.java | 86 ------
.../logic/RequestObjectRequiredAndSupported.java | 98 +++++++
...tObjectSupportedSignatureSigningAlgorithms.java | 44 +++
.../impl/AbstractHttpOIDCAuthenticationAction.java | 2 +-
...> AbstractOIDCAuthenticationRequestAction.java} | 99 ++++---
.../AbstractOIDCAuthenticationResponseAction.java | 30 +-
.../oidc/rp/impl/AddOIDCAuthenticationRequest.java | 311 ---------------------
.../oidc/rp/impl/AuthorizationController.java | 21 +-
.../authn/oidc/rp/impl/BuildRequestObject.java | 76 +++++
.../rp/impl/InitializeAuthorizationRequest.java | 111 ++++++++
.../plugin/authn/oidc/rp/impl/PopulateACRs.java | 88 ++++++
.../authn/oidc/rp/impl/PopulateEndpointURI.java | 49 ++++
.../rp/impl/PopulateForceAuthenticationPrompt.java | 64 +++++
.../plugin/authn/oidc/rp/impl/PopulateNonce.java | 75 +++++
...ntext.java => PopulateResponseTypeAndMode.java} | 57 ++--
.../plugin/authn/oidc/rp/impl/PopulateScopes.java | 52 ++++
.../authn/oidc/rp/impl/ProcessEndUserClaims.java | 2 +-
.../authn/oidc/rp/impl/SignRequestObject.java | 50 ++++
.../rp/impl/ValidateOAuthAccessTokenResponse.java | 2 +-
.../authn/oidc/rp/impl/ValidateResponseState.java | 2 +-
.../authn/oidc/rp/impl/ValidateTokenClaims.java | 2 +-
.../META-INF/net.shibboleth.idp/postconfig.xml | 15 +-
.../oidc-relying-party-authn-beans.xml | 214 +++++++++-----
.../oidc-relying-party-authn-flow.xml | 49 +++-
.../idp/service/relying-party/postconfig.xml | 37 ++-
.../authn/oidc/rp/conf/authn/rp-credentials.xml | 6 +
.../plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java | 158 +++++++++--
...t.java => PopulateResponseTypeAndModeTest.java} | 47 ++--
.../resources/conf/test-relying-party-system.xml | 24 +-
36 files changed, 1271 insertions(+), 712 deletions(-)
diff --git a/idp-oidc-rp-api/pom.xml b/idp-oidc-rp-api/pom.xml
index b09663f..7b08294 100644
--- a/idp-oidc-rp-api/pom.xml
+++ b/idp-oidc-rp-api/pom.xml
@@ -51,6 +51,11 @@
<groupId>net.shibboleth.oidc</groupId>
<artifactId>oidc-common-profile-api</artifactId>
<scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.shibboleth.oidc</groupId>
+ <artifactId>oidc-common-metadata-api</artifactId>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenDecryptionConfigurationLookupFunction.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenDecryptionConfigurationLookupFunction.java
index e6ff572..4157f5f 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenDecryptionConfigurationLookupFunction.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenDecryptionConfigurationLookupFunction.java
@@ -68,9 +68,9 @@ public class IDTokenDecryptionConfigurationLookupFunction
final ProfileConfiguration pc = rpc.getProfileConfig();
if (pc != null && pc.getSecurityConfiguration(input) instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getIdtokenJwtDecryptionConfig() != null) {
+ .getIdtokenJwtDecryptionConfiguration() != null) {
configs.add(((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getIdtokenJwtDecryptionConfig());
+ .getIdtokenJwtDecryptionConfiguration());
}
}
@@ -80,9 +80,9 @@ public class IDTokenDecryptionConfigurationLookupFunction
rpResolver.getDefaultSecurityConfiguration(input.getProfileId());
if (defaultConfig instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) defaultConfig)
- .getIdtokenJwtDecryptionConfig() != null) {
+ .getIdtokenJwtDecryptionConfiguration() != null) {
configs.add(
- ((OIDCSecurityConfiguration) defaultConfig).getIdtokenJwtDecryptionConfig());
+ ((OIDCSecurityConfiguration) defaultConfig).getIdtokenJwtDecryptionConfiguration());
}
}
// TODO: Support for Global Default configuration?
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java
index e29535f..75928d4 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java
@@ -70,9 +70,9 @@ public class IDTokenSignatureValidationConfigurationLookupFunction
final ProfileConfiguration pc = rpc.getProfileConfig();
if (pc != null && pc.getSecurityConfiguration(input) instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getIdTokenJwtSignatureValidationConfig() != null) {
+ .getIdTokenJwtSignatureValidationConfiguration() != null) {
configs.add(((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getIdTokenJwtSignatureValidationConfig());
+ .getIdTokenJwtSignatureValidationConfiguration());
}
}
@@ -82,9 +82,9 @@ public class IDTokenSignatureValidationConfigurationLookupFunction
rpResolver.getDefaultSecurityConfiguration(input.getProfileId());
if (defaultConfig instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) defaultConfig)
- .getIdTokenJwtSignatureValidationConfig() != null) {
+ .getIdTokenJwtSignatureValidationConfiguration() != null) {
configs.add(
- ((OIDCSecurityConfiguration) defaultConfig).getIdTokenJwtSignatureValidationConfig());
+ ((OIDCSecurityConfiguration) defaultConfig).getIdTokenJwtSignatureValidationConfiguration());
}
}
// TODO: Support for Global Default configuration?
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/InboundMessageContextFromProxyPRC.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/InboundMessageContextFromProxyPRC.java
new file mode 100644
index 0000000..ebd79cb
--- /dev/null
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/InboundMessageContextFromProxyPRC.java
@@ -0,0 +1,55 @@
+/*
+ * 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.authn.oidc.rp.config.navigate;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+
+/**
+ * A {@link ContextDataLookupFunction} that returns the inbound {@link MessageContext} for a
+ * {@link ProfileRequestContext} located inside an {@link AuthenticationContext} i.e. for use in the proxy case.
+ */
+public class InboundMessageContextFromProxyPRC
+ implements ContextDataLookupFunction<ProfileRequestContext, MessageContext> {
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ public MessageContext apply(@Nullable final ProfileRequestContext input) {
+
+ if (input == null) {
+ return null;
+ }
+ final AuthenticationContext authContext = input.getSubcontext(AuthenticationContext.class);
+ if (authContext == null) {
+ return null;
+ }
+ final ProfileRequestContext nestedProfileRequestContext =
+ authContext.getSubcontext(ProfileRequestContext.class);
+ if (nestedProfileRequestContext != null) {
+ return nestedProfileRequestContext.getInboundMessageContext();
+ }
+ return null;
+ }
+
+}
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/RequestObjectSignatureSigningConfigurationLookupFunction.java
similarity index 81%
copy from idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java
copy to idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/RequestObjectSignatureSigningConfigurationLookupFunction.java
index e29535f..a3e4951 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/RequestObjectSignatureSigningConfigurationLookupFunction.java
@@ -23,6 +23,7 @@ import java.util.List;
import javax.annotation.Nullable;
import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.xmlsec.SignatureSigningConfiguration;
import com.nimbusds.jwt.SignedJWT;
@@ -35,15 +36,15 @@ import net.shibboleth.oidc.profile.config.OIDCSecurityConfiguration;
import net.shibboleth.oidc.security.SignatureValidationConfiguration;
/**
- * A function that returns a {@link SignatureValidationConfiguration} list for id_token signature validation by way
+ * A function that returns a {@link SignatureSigningConfiguration} list for request object signing by way
* of various lookup strategies.
*
* <p>
* If a specific setting is unavailable, a null value is returned.
* </p>
*/
-public class IDTokenSignatureValidationConfigurationLookupFunction
- extends AbstractRelyingPartyLookupFunction<List<SignatureValidationConfiguration<SignedJWT>>> {
+public class RequestObjectSignatureSigningConfigurationLookupFunction
+ extends AbstractRelyingPartyLookupFunction<List<SignatureSigningConfiguration>> {
/** A resolver for default security configurations. */
@Nullable
@@ -61,18 +62,18 @@ public class IDTokenSignatureValidationConfigurationLookupFunction
/** {@inheritDoc} */
@Override
@Nullable
- public List<SignatureValidationConfiguration<SignedJWT>> apply(@Nullable final ProfileRequestContext input) {
+ public List<SignatureSigningConfiguration> apply(@Nullable final ProfileRequestContext input) {
- final List<SignatureValidationConfiguration<SignedJWT>> configs = new ArrayList<>();
+ final List<SignatureSigningConfiguration> configs = new ArrayList<>();
final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
if (rpc != null) {
final ProfileConfiguration pc = rpc.getProfileConfig();
if (pc != null && pc.getSecurityConfiguration(input) instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getIdTokenJwtSignatureValidationConfig() != null) {
+ .getRequestObjectSignatureSigningConfiguration() != null) {
configs.add(((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getIdTokenJwtSignatureValidationConfig());
+ .getRequestObjectSignatureSigningConfiguration());
}
}
@@ -82,9 +83,9 @@ public class IDTokenSignatureValidationConfigurationLookupFunction
rpResolver.getDefaultSecurityConfiguration(input.getProfileId());
if (defaultConfig instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) defaultConfig)
- .getIdTokenJwtSignatureValidationConfig() != null) {
+ .getRequestObjectSignatureSigningConfiguration() != null) {
configs.add(
- ((OIDCSecurityConfiguration) defaultConfig).getIdTokenJwtSignatureValidationConfig());
+ ((OIDCSecurityConfiguration) defaultConfig).getRequestObjectSignatureSigningConfiguration());
}
}
// TODO: Support for Global Default configuration?
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/UserInfoDecryptionConfigurationLookupFunction.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/UserInfoDecryptionConfigurationLookupFunction.java
index 273d5f6..9bc34f7 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/UserInfoDecryptionConfigurationLookupFunction.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/UserInfoDecryptionConfigurationLookupFunction.java
@@ -68,9 +68,9 @@ public class UserInfoDecryptionConfigurationLookupFunction
final ProfileConfiguration pc = rpc.getProfileConfig();
if (pc != null && pc.getSecurityConfiguration(input) instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getUserInfoJwtDecryptionConfig() != null) {
+ .getUserInfoJwtDecryptionConfiguration() != null) {
configs.add(((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getUserInfoJwtDecryptionConfig());
+ .getUserInfoJwtDecryptionConfiguration());
}
}
@@ -80,9 +80,9 @@ public class UserInfoDecryptionConfigurationLookupFunction
rpResolver.getDefaultSecurityConfiguration(input.getProfileId());
if (defaultConfig instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) defaultConfig)
- .getUserInfoJwtDecryptionConfig() != null) {
+ .getUserInfoJwtDecryptionConfiguration() != null) {
configs.add(
- ((OIDCSecurityConfiguration) defaultConfig).getUserInfoJwtDecryptionConfig());
+ ((OIDCSecurityConfiguration) defaultConfig).getUserInfoJwtDecryptionConfiguration());
}
}
// TODO: Support for Global Default configuration?
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/UserInfoTokenSignatureValidationConfigurationLookupFunction.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/UserInfoTokenSignatureValidationConfigurationLookupFunction.java
index 19ac0c0..5c2b766 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/UserInfoTokenSignatureValidationConfigurationLookupFunction.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/UserInfoTokenSignatureValidationConfigurationLookupFunction.java
@@ -70,9 +70,9 @@ public class UserInfoTokenSignatureValidationConfigurationLookupFunction
final ProfileConfiguration pc = rpc.getProfileConfig();
if (pc != null && pc.getSecurityConfiguration(input) instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getUserInfoTokenJwtSignatureValidationConfig() != null) {
+ .getUserInfoTokenJwtSignatureValidationConfiguration() != null) {
configs.add(((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
- .getUserInfoTokenJwtSignatureValidationConfig());
+ .getUserInfoTokenJwtSignatureValidationConfiguration());
}
}
@@ -82,9 +82,10 @@ public class UserInfoTokenSignatureValidationConfigurationLookupFunction
rpResolver.getDefaultSecurityConfiguration(input.getProfileId());
if (defaultConfig instanceof OIDCSecurityConfiguration
&& ((OIDCSecurityConfiguration) defaultConfig)
- .getUserInfoTokenJwtSignatureValidationConfig() != null) {
+ .getUserInfoTokenJwtSignatureValidationConfiguration() != null) {
configs.add(
- ((OIDCSecurityConfiguration) defaultConfig).getUserInfoTokenJwtSignatureValidationConfig());
+ ((OIDCSecurityConfiguration) defaultConfig)
+ .getUserInfoTokenJwtSignatureValidationConfiguration());
}
}
// TODO: Support for Global Default configuration?
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/ResponseTypeAndModeContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/ResponseTypeAndModeContext.java
deleted file mode 100644
index d919db8..0000000
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/ResponseTypeAndModeContext.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package net.shibboleth.idp.plugin.authn.oidc.rp.context;
-
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.BaseContext;
-
-import com.nimbusds.oauth2.sdk.ResponseMode;
-import com.nimbusds.oauth2.sdk.ResponseType;
-
-/**
- * Context hold the response_type and response_mode to be used with the ongoing authentication request.
- */
-public class ResponseTypeAndModeContext extends BaseContext {
-
- /** The chosen response type.*/
- @Nullable private ResponseType responseType;
-
- /**
- * The chosen response mode.
- */
- @Nullable private ResponseMode responseMode;
-
- /**
- * The default response mode for the given response_type. Can be used
- * to determine if the response_mode should be included in an authentication
- * request.
- */
- @Nullable private ResponseMode defaultResponseMode;
-
- /**
- * Set the response type to be used with the ongoing authentication request.
- *
- * @param type the response type.
- */
- public void setResponseType(@Nullable final ResponseType type) {
- responseType = type;
- }
-
- /**
- * Get the response_type to use with this authentication request.
- *
- * @return the response_type.
- */
- @Nullable public ResponseType getResponseType() {
- return responseType;
- }
-
- /**
- * Set the response mode to be used with the ongoing authentication request.
- * This can be {@literal null} if the default response_mode is
- * to be used by the OP.
- *
- * @param mode the response mode. {@literal null} if default mode is to be used.
- */
- public void setResponseMode(@Nullable final ResponseMode mode) {
- responseMode = mode;
- }
-
- /**
- * Get the response_mode to use with this authentication request.
- *
- * @return the response_mode.
- */
- @Nullable public ResponseMode getResponseMode() {
- return responseMode;
- }
-
- /**
- * Set the default response_mode for the given response_type.
- *
- * @param mode the default response_mode for the given response_type
- */
- public void setDefaultResponseMode(@Nullable final ResponseMode mode) {
- defaultResponseMode = mode;
- }
-
- /**
- * Get the response_mode to use with this authentication request.
- *
- * @return the default response_mode
- */
- @Nullable public ResponseMode getDefaultResponseMode() {
- return defaultResponseMode;
- }
-
-}
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/logic/RequestObjectRequiredAndSupported.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/logic/RequestObjectRequiredAndSupported.java
new file mode 100644
index 0000000..3246ed0
--- /dev/null
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/logic/RequestObjectRequiredAndSupported.java
@@ -0,0 +1,98 @@
+/*
+ * 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.authn.oidc.rp.messaging.context.logic;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.logic.AbstractRelyingPartyPredicate;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** Tests whether a request object should be build, and if it is supported by the downstream OP.*/
+public class RequestObjectRequiredAndSupported extends AbstractRelyingPartyPredicate {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(RequestObjectRequiredAndSupported.class);
+
+ /** Strategy that will return {@link OIDCProviderMetadata}. */
+ @Nonnull private
+ Function<ProfileRequestContext, OIDCProviderMetadataContext> oidcProviderMetadataContextLookupStrategy;
+
+ /** Constructor.*/
+ public RequestObjectRequiredAndSupported() {
+ oidcProviderMetadataContextLookupStrategy = new ChildContextLookup<>(OIDCProviderMetadataContext.class)
+ .compose(new ChildContextLookup<>(OIDCPeerEntityContext.class))
+ .compose(new InboundMessageContextLookup());
+ }
+
+ /**
+ * Set the lookup strategy to use to locate the {@link OIDCProviderMetadataContext}.
+ *
+ * @param strategy lookup function to use
+ */
+ public void setOidcProviderMetadataContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,OIDCProviderMetadataContext> strategy) {
+
+ oidcProviderMetadataContextLookupStrategy =
+ Constraint.isNotNull(strategy,
+ "OidcProviderMetadataContextLookupStrategy lookup strategy cannot be null");
+ }
+
+ @Override
+ public boolean test(final ProfileRequestContext input) {
+
+ boolean requestObjectRequestedFromConfig = false;
+ final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+ if (rpc != null && rpc.getProfileConfig() instanceof OIDCAuthorizationConfiguration) {
+ requestObjectRequestedFromConfig = ((OIDCAuthorizationConfiguration)
+ rpc.getProfileConfig()).isUseRequestObject(input);
+ }
+
+ final OIDCProviderMetadataContext metadata = oidcProviderMetadataContextLookupStrategy.apply(input);
+ if (metadata == null || metadata.getProviderInformation() == null) {
+ // Should not happen at the time this predicate is called.
+ log.warn("OIDC Provider Metadata is not available, can not determine if request object is supported");
+ return false;
+ }
+
+ final boolean requestedAndSupport =
+ requestObjectRequestedFromConfig && metadata.getProviderInformation().supportsRequestParam();
+ if (requestedAndSupport) {
+ log.debug("Authentication request RequestObject was requested and is supported");
+ } else {
+ log.debug("Authentication request RequestObject not requested or not supported");
+ }
+
+ return requestedAndSupport;
+
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/RequestObjectSupportedSignatureSigningAlgorithms.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/RequestObjectSupportedSignatureSigningAlgorithms.java
new file mode 100644
index 0000000..533a024
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/RequestObjectSupportedSignatureSigningAlgorithms.java
@@ -0,0 +1,44 @@
+/*
+ * 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.authn.oidc.rp.config;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nullable;
+
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+/**
+ * Pull out the request object supported signature signing algorithms from the metadata.
+ */
+public class RequestObjectSupportedSignatureSigningAlgorithms implements Function<OIDCProviderMetadata, List<String>>{
+
+ @Override
+ @Nullable public List<String> apply(@Nullable final OIDCProviderMetadata metadata) {
+
+ if (metadata == null || metadata.getRequestObjectJWSAlgs() == null) {
+ return null;
+ }
+ return metadata.getRequestObjectJWSAlgs()
+ .stream().map(JWSAlgorithm::getName).collect(Collectors.toList());
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractHttpOIDCAuthenticationAction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractHttpOIDCAuthenticationAction.java
index f3007eb..738a730 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractHttpOIDCAuthenticationAction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractHttpOIDCAuthenticationAction.java
@@ -44,7 +44,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
*
* @param <T> the response type of the object returned as a result of the request.
*/
-public class AbstractHttpOIDCAuthenticationAction<T> extends AbstractOIDCAuthenticationAction {
+public class AbstractHttpOIDCAuthenticationAction<T> extends AbstractOIDCAuthenticationResponseAction {
/** Class logger.*/
@Nonnull private final Logger log = LoggerFactory.getLogger(AbstractHttpOIDCAuthenticationAction.class);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationRequestAction.java
similarity index 69%
copy from idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
copy to idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationRequestAction.java
index b301d15..9cb40ec 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationRequestAction.java
@@ -32,13 +32,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
-import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
import net.shibboleth.idp.authn.AbstractAuthenticationAction;
import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -48,81 +49,79 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
* Abstract class for actions performing actions on {@link AuthenticationResponse} located under
* {@link ProfileRequestContext#getOutboundMessageContext()#getM}.
*
- * FIXME: this is very close to that in the OP AbstractOIDCAuthenticationResponseAction. Maybe consolidate
- * TODO create one of these for the outbound phase (auth request) and one for the other phases which will
- * include the response.
*/
-abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAction {
+abstract class AbstractOIDCAuthenticationRequestAction extends AbstractAuthenticationAction {
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractOIDCAuthenticationAction.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractOIDCAuthenticationRequestAction.class);
/** Lookup strategy to locate the OP metadata to use.*/
@Nonnull private Function<ProfileRequestContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
-
- /** Lookup strategy to locate the metadata of the client to use to communicate with the OP.*/
- @Nonnull private Function<ProfileRequestContext,OIDCMetadataContext> clientMetadataLookupStrategy;
-
- /** OIDC authentication response from downstream OP. */
- @Nullable private AuthenticationSuccessResponse authnResponse;
-
+
/** OIDC authentication request built by the IdP. */
@Nullable private OIDCAuthenticationRequest authnRequest;
/** OIDC Metadata context. */
@Nullable private OIDCProviderMetadataContext providerMetadataContext;
+ /** Applicable profile configuration. */
+ @Nullable private OIDCAuthorizationConfiguration profileConfiguration;
+
+ /** Lookup function for relying party context. */
+ @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+
/** Constructor.*/
- protected AbstractOIDCAuthenticationAction() {
+ protected AbstractOIDCAuthenticationRequestAction() {
providerMetadataLookupStrategy = new ChildContextLookup<>(OIDCProviderMetadataContext.class).compose(
new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
new OutboundMessageContextLookup()));
- clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
- new OutboundMessageContextLookup());
+ relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
}
/**
- * Set the lookup strategy to locate the OpenID providers metadata.
+ * Set lookup strategy for relying party context.
*
- * @param strategy the strategy.
+ * @param strategy lookup strategy
*/
- public void setProviderMetadataLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCProviderMetadataContext> strategy) {
+ public void setRelyingPartyContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- providerMetadataLookupStrategy =
- Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");
+ relyingPartyContextLookupStrategy =
+ Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
}
/**
- * Set the lookup strategy to locate the OpenID client metadata.
+ * Set the lookup strategy to locate the OpenID providers metadata.
*
* @param strategy the strategy.
*/
- public void setClientMetadataLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
+ public void setProviderMetadataLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, OIDCProviderMetadataContext> strategy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- clientMetadataLookupStrategy = Constraint.isNotNull(strategy,"Client metadata lookup strategy can not be null");
+ providerMetadataLookupStrategy =
+ Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");
}
+
/**
- * Returns the authentication response from the downstream OP.
+ * Returns the authentication request build by this IdP.
*
- * @return the authentication response.
+ * @return the authentication request.
*/
- @Nullable public AuthenticationSuccessResponse getAuthenticationResponse() {
- return authnResponse;
+ @Nullable protected OIDCAuthenticationRequest getAuthenticationRequest() {
+ return authnRequest;
}
/**
- * Returns the authentication request build by this IdP.
+ * Returns the profile configuration associated with this request.
*
- * @return the authentication request.
+ * @return the profile configuration
*/
- @Nullable public OIDCAuthenticationRequest getAuthenticationRequest() {
- return authnRequest;
+ @Nullable protected OIDCAuthorizationConfiguration getProfileConfiguration() {
+ return profileConfiguration;
}
@@ -131,12 +130,10 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
*
* @return The provider metadata context.
*/
- @Nullable public OIDCProviderMetadataContext getProviderMetadataContext() {
+ @Nullable protected OIDCProviderMetadataContext getProviderMetadataContext() {
return providerMetadataContext;
}
- //TODO these come from the outbound message context, so are not general to other actions
-
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@Nonnull final AuthenticationContext authenticationContext) {
@@ -148,19 +145,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
return false;
}
- if (inboundMessageCtx.getMessage() == null) {
- log.error("{} No inbound message", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return false;
- }
-
- if (!(inboundMessageCtx.getMessage() instanceof AuthenticationSuccessResponse)) {
- log.error("{} No inbound authentication success response", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return false;
- }
- authnResponse = (AuthenticationSuccessResponse)inboundMessageCtx.getMessage();
-
+
final MessageContext outboundMsgContext = profileRequestContext.getOutboundMessageContext();
if (outboundMsgContext == null) {
log.error("{} Outbound message context was null", getLogPrefix());
@@ -180,6 +165,18 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
return false;
}
+
+ final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+ if (rpCtx != null && rpCtx.getConfiguration() != null &&
+ rpCtx.getProfileConfig() instanceof OIDCAuthorizationConfiguration) {
+ profileConfiguration = (OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
+ }
+ if (profileConfiguration == null) {
+ log.error("{} OIDCCoreProtocolConfiguration not found", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+ return false;
+ }
+
return true;
}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
index b301d15..085c60a 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
@@ -37,7 +37,6 @@ import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
import net.shibboleth.idp.authn.AbstractAuthenticationAction;
import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -48,20 +47,14 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
* Abstract class for actions performing actions on {@link AuthenticationResponse} located under
* {@link ProfileRequestContext#getOutboundMessageContext()#getM}.
*
- * FIXME: this is very close to that in the OP AbstractOIDCAuthenticationResponseAction. Maybe consolidate
- * TODO create one of these for the outbound phase (auth request) and one for the other phases which will
- * include the response.
*/
-abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAction {
+abstract class AbstractOIDCAuthenticationResponseAction extends AbstractAuthenticationAction {
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractOIDCAuthenticationAction.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractOIDCAuthenticationResponseAction.class);
/** Lookup strategy to locate the OP metadata to use.*/
@Nonnull private Function<ProfileRequestContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
-
- /** Lookup strategy to locate the metadata of the client to use to communicate with the OP.*/
- @Nonnull private Function<ProfileRequestContext,OIDCMetadataContext> clientMetadataLookupStrategy;
/** OIDC authentication response from downstream OP. */
@Nullable private AuthenticationSuccessResponse authnResponse;
@@ -73,13 +66,11 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
@Nullable private OIDCProviderMetadataContext providerMetadataContext;
/** Constructor.*/
- protected AbstractOIDCAuthenticationAction() {
+ protected AbstractOIDCAuthenticationResponseAction() {
providerMetadataLookupStrategy = new ChildContextLookup<>(OIDCProviderMetadataContext.class).compose(
new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
new OutboundMessageContextLookup()));
-
- clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
- new OutboundMessageContextLookup());
+
}
/**
@@ -95,17 +86,6 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");
}
- /**
- * Set the lookup strategy to locate the OpenID client metadata.
- *
- * @param strategy the strategy.
- */
- public void setClientMetadataLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- clientMetadataLookupStrategy = Constraint.isNotNull(strategy,"Client metadata lookup strategy can not be null");
- }
/**
* Returns the authentication response from the downstream OP.
@@ -135,8 +115,6 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
return providerMetadataContext;
}
- //TODO these come from the outbound message context, so are not general to other actions
-
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@Nonnull final AuthenticationContext authenticationContext) {
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddOIDCAuthenticationRequest.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddOIDCAuthenticationRequest.java
deleted file mode 100644
index 5864c03..0000000
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddOIDCAuthenticationRequest.java
+++ /dev/null
@@ -1,311 +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.authn.oidc.rp.impl;
-
-import java.security.Principal;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.messaging.context.navigate.ParentContextLookup;
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
-import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.nimbusds.oauth2.sdk.ParseException;
-import com.nimbusds.oauth2.sdk.id.ClientID;
-import com.nimbusds.openid.connect.sdk.Nonce;
-import com.nimbusds.openid.connect.sdk.Prompt;
-import com.nimbusds.openid.connect.sdk.claims.ACR;
-
-import net.shibboleth.idp.authn.AbstractAuthenticationAction;
-import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.OAuth2ClientContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
-import net.shibboleth.idp.profile.IdPEventIds;
-import net.shibboleth.idp.profile.context.RelyingPartyContext;
-import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
-import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
-import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
-import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-
-/**
- * Action that creates an {@link OIDCAuthenticationRequest} and sets it as the message returned by
- * {@link ProfileRequestContext#getOutboundMessageContext()}.
- *
- * <p>Note, this is an OIDC authentication request on top of an OAuth 2.0 authorization request.</p>
- *
- * @event {@link EventIds#PROCEED_EVENT_ID}
- * @event {@link EventIds#INVALID_MSG_CTX}
- * @event {@link EventIds#INVALID_PROFILE_CTX}
- * @event {@link IdPEventIds#INVALID_PROFILE_CONFIG}
- *
- * @post ProfileRequestContext.getOutboundMessageContext().getMessage() != null
- */
-public class AddOIDCAuthenticationRequest extends AbstractAuthenticationAction {
-
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(AddOIDCAuthenticationRequest.class);
-
- /** Overwrite an existing message? */
- private boolean overwriteExisting;
-
- /** Applicable profile configuration. */
- @Nullable private OIDCAuthorizationConfiguration profileConfiguration;
-
- /** The metadata belonging to the OpenID Provider.*/
- @Nullable private OIDCProviderMetadataContext providerMetadata;
-
- /** The response type and mode context.*/
- @Nullable private ResponseTypeAndModeContext responseTypeAndModeContext;
-
- /** The strategy used to lookup or create the {@link OAuth2ClientContext} for storing the client_id.*/
- @Nonnull
- private Function<ProfileRequestContext, OAuth2ClientContext> oauth2ClientContextLookupStrategy;
-
- /** The stashed OAuth2 client context.*/
- @Nullable private OAuth2ClientContext oauth2ClientContext;
-
- /** Lookup strategy to locate the OP metadata to use.*/
- @Nonnull private Function<ProfileRequestContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
-
- /** Lookup strategy to locate the response_mode and response_type context.*/
- @Nonnull private Function<ProfileRequestContext,ResponseTypeAndModeContext> responseTypeAndModeLookupStrategy;
-
- /** Constructor.*/
- public AddOIDCAuthenticationRequest() {
- // Fool the parent class into looking above instead of below the PRC for the context.
- setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
-
- providerMetadataLookupStrategy = new ChildContextLookup<>(OIDCProviderMetadataContext.class).compose(
- new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
- new InboundMessageContextLookup()));
-
- responseTypeAndModeLookupStrategy = new ChildContextLookup<>(ResponseTypeAndModeContext.class).compose(
- new OutboundMessageContextLookup());
-
- // Default under OIDCPeerEntityContext in the outbound context (create true).
- oauth2ClientContextLookupStrategy = new ChildContextLookup<>(OAuth2ClientContext.class, true).compose(
- new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
- new OutboundMessageContextLookup()));
- }
-
- /**
- * Set the lookup strategy to locate the OpenID providers metadata.
- *
- * @param strategy the strategy.
- */
- public void setProviderMetadataLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCProviderMetadataContext> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- providerMetadataLookupStrategy =
- Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");
- }
-
- /**
- * Set the strategy to lookup the {@link OAuth2ClientContext}
- * from the {@link ProfileRequestContext}.
- *
- * @param strgy the strategy.
- */
- public void setOAuth2ClientContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OAuth2ClientContext> strgy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
-
- oauth2ClientContextLookupStrategy = Constraint.isNotNull(strgy,
- "OAuth2 client context lookup strategy cannot be null");
- }
-
-
- /**
- * Set the lookup strategy to locate the response type and mode context.
- *
- * @param strategy the strategy.
- */
- public void setResponseTypeAndModeLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, ResponseTypeAndModeContext> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- responseTypeAndModeLookupStrategy = Constraint.isNotNull(strategy,
- "ResponseTypeAndMode context lookup strategy can not be null");
- }
-
- /**
- * Set whether to overwrite an existing message.
- *
- * @param flag flag to set
- */
- public void setOverwriteExisting(final boolean flag) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- overwriteExisting = flag;
- }
-
- @Override
- protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final AuthenticationContext authenticationContext) {
-
- if (!super.doPreExecute(profileRequestContext, authenticationContext)) {
- return false;
- }
-
-
- final RelyingPartyContext rpCtx = profileRequestContext.getSubcontext(RelyingPartyContext.class);
- if (rpCtx != null && rpCtx.getConfiguration() != null &&
- rpCtx.getProfileConfig() instanceof OIDCAuthorizationConfiguration) {
- profileConfiguration = (OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
- }
- if (profileConfiguration == null) {
- log.error("{} OIDCCoreProtocolConfiguration not found", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
- return false;
- }
-
- final MessageContext outboundMessageCtx = profileRequestContext.getOutboundMessageContext();
- if (outboundMessageCtx == null) {
- log.debug("{} No outbound message context", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return false;
- } else if (!overwriteExisting && outboundMessageCtx.getMessage() != null) {
- log.debug("{} Outbound message context already contains a message", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return false;
- }
-
- responseTypeAndModeContext = responseTypeAndModeLookupStrategy.apply(profileRequestContext);
- if (responseTypeAndModeContext == null) {
- log.error("{} ResponseTypeContext not found", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
- return false;
- }
-
- oauth2ClientContext = oauth2ClientContextLookupStrategy.apply(profileRequestContext);
- if (oauth2ClientContext == null) {
- log.error("{} OAuth2 client context not found", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
- return false;
- }
-
- providerMetadata = providerMetadataLookupStrategy.apply(profileRequestContext);
- if (providerMetadata == null) {
- log.debug("{} Inbound message context did not contain provider metadata", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return false;
- }
-
- profileRequestContext.getOutboundMessageContext().setMessage(null);
-
- return true;
- }
-
- @Override
- protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final AuthenticationContext authenticationContext) {
-
- log.debug("{} Building AuthzRequest for upstream OP ({})",
- getLogPrefix(), authenticationContext.getAuthenticatingAuthority());
-
-
- final OIDCAuthenticationRequest request =
- new OIDCAuthenticationRequest(new ClientID(oauth2ClientContext.getClientId()));
-
- request.setResponseType(responseTypeAndModeContext.getResponseType());
- // Only set the response_mode if not equal to the default for that response_type
- if (!responseTypeAndModeContext.getDefaultResponseMode().equals(responseTypeAndModeContext.getResponseMode())){
- request.setResponseMode(responseTypeAndModeContext.getResponseMode());
- }
- request.setEndpointURI(providerMetadata.getProviderInformation().getAuthorizationEndpointURI());
-
- final Set<String> scopes = profileConfiguration.getScopes(profileRequestContext);
- if (scopes != null && !scopes.isEmpty()) {
- scopes.forEach(s -> request.getScope().add(s));
- }
-
- request.setNonce(new Nonce(OIDCProxySupport.generateNonce(16)));
-
- // ForceAuthn comes from configuration, which by default will take into account the
- // AuthenticationContext parent's state (but may be overridden by deployer).
- if (profileConfiguration.isForceAuthn(profileRequestContext)) {
- log.debug("{} Setting prompt=login (ForceAuthn) for OIDC AuthnRequest", getLogPrefix());
- try {
- request.setPrompt(Prompt.parse(Prompt.Type.LOGIN.toString()));
- } catch (final ParseException e) {
- // This should never happen
- log.error("{} Unable to honour force-authn, setting prompt to 'login' failed", getLogPrefix(), e);
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.AUTHN_EXCEPTION);
- return;
- }
- }
-
- final List<ACR> acrs = buildRequestedAuthnContext(profileRequestContext);
- if (acrs != null) {
- log.debug("{} setting ACRs to '{}'", getLogPrefix(), acrs);
- request.setAcrs(acrs);
- }
-
- log.debug("{} Built authorization request for endpoint '{}' for client '{}'",getLogPrefix(),
- request.getEndpointURI(), oauth2ClientContext.getClientId());
- profileRequestContext.getOutboundMessageContext().setMessage(request);
-
-
- }
-
- /**
- * Build a list of {@link ACR}s if warranted. Converted from any default authentication method {@link Principal}s.
- *
- * <p>By default for this proxy case, the authentication methods are
- *
- * @param profileRequestContext current profile request context
- *
- * @return the list of ACRs.
- */
- @Nullable private List<ACR> buildRequestedAuthnContext(
- @Nullable final ProfileRequestContext profileRequestContext) {
-
- // RequestedAuthnContext also based on profile configuration.
- final List<Principal> principals = profileConfiguration.getDefaultAuthenticationMethods(profileRequestContext);
- if (principals.isEmpty()) {
- return null;
- }
-
- return principals.stream()
- .filter(AuthenticationContextClassReferencePrincipal.class::isInstance)
- .map(AuthenticationContextClassReferencePrincipal.class::cast)
- .map(p -> new ACR(p.getName()))
- .collect(Collectors.toUnmodifiableList());
- }
-
-
-}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthorizationController.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthorizationController.java
index 456afc8..b57c363 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthorizationController.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthorizationController.java
@@ -53,7 +53,6 @@ import net.shibboleth.idp.plugin.authn.oidc.rp.OIDCProxyException;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OAuth2ClientContext;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCAuthnContext;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -322,24 +321,28 @@ public class AuthorizationController extends AbstractInitializableComponent {
ExternalAuthentication.finishExternalAuthentication(key, httpRequest, httpResponse);
return;
}
- // Find which response mode to expect.
- final ResponseTypeAndModeContext responseCtx =
- nestedPRC.getOutboundMessageContext().getSubcontext(ResponseTypeAndModeContext.class);
- if (responseCtx == null) {
- log.error("ResponseTypeAndMode context not found, cannot decode incomming request");
+ // Find which response mode to expect from that set in the authentication request
+ OIDCAuthenticationRequest authnRequest = null;
+ if (nestedPRC.getOutboundMessageContext() != null &&
+ nestedPRC.getOutboundMessageContext().getMessage() instanceof OIDCAuthenticationRequest) {
+ authnRequest = (OIDCAuthenticationRequest) nestedPRC.getOutboundMessageContext().getMessage();
+ }
+
+ if (authnRequest == null) {
+ log.error("Authentication request not found in context, cannot decode incomming request");
httpRequest.setAttribute(ExternalAuthentication.AUTHENTICATION_ERROR_KEY, EventIds.INVALID_PROFILE_CTX);
ExternalAuthentication.finishExternalAuthentication(key, httpRequest, httpResponse);
return;
}
log.debug("OIDC response_type '{}' and response_mode '{}' requested, decoding incoming request",
- responseCtx.getResponseType(), responseCtx.getResponseMode());
+ authnRequest.getResponseType(), authnRequest.getResponseMode());
try {
final MessageDecoder decoder =
- oidcContext.getMessageDecoderFactory().apply(responseCtx.getResponseMode().getValue());
+ oidcContext.getMessageDecoderFactory().apply(authnRequest.getResponseMode().getValue());
if (decoder == null) {
throw new MessageDecodingException("Unable to obtain MessageDecoder for response_mode: "
- + responseCtx.getResponseMode().getValue());
+ + authnRequest.getResponseMode().getValue());
}
try {
decoder.initialize();
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/BuildRequestObject.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/BuildRequestObject.java
new file mode 100644
index 0000000..8fb8afd
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/BuildRequestObject.java
@@ -0,0 +1,76 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jwt.JWT;
+import com.nimbusds.jwt.PlainJWT;
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.id.Audience;
+import com.nimbusds.oauth2.sdk.id.Issuer;
+import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
+
+
+/**
+ * Action that creates a Request Object {@link JWT} object, and sets it to work context
+ * {@link OIDCAuthenticationRequest} located under {@link ProfileRequestContext#getOutboundMessageContext()}.
+ */
+public class BuildRequestObject extends AbstractOIDCAuthenticationRequestAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(BuildRequestObject.class);
+
+ /** The RelyingPartyContext to operate on. */
+ @Nullable private RelyingPartyContext rpCtx;
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+ log.debug("{} Building a Request Object JWT for the authentication request", getLogPrefix());
+ final ClaimsSet requestObjectClaims = new ClaimsSet();
+
+ //TODO check we are signing if we have selected a signing params, or if we just say must sign?
+
+ requestObjectClaims.setClaim("client_id", getAuthenticationRequest().getClientID().getValue());
+ requestObjectClaims.setAudience(
+ new Audience(getProviderMetadataContext().getProviderInformation().getIssuer().getValue()));
+ requestObjectClaims.setIssuer(new Issuer(getAuthenticationRequest().getClientID().getValue()));
+
+ //FIXME: replace with static claim names?
+ requestObjectClaims.setClaim("nonce", getAuthenticationRequest().getNonce().getValue());
+
+ requestObjectClaims.setClaim("response_type", getAuthenticationRequest().getResponseType());
+ // Only set the response_mode if not equal to the default for that response_type
+ if (!getAuthenticationRequest().getDefaultResponseMode().equals(getAuthenticationRequest().getResponseMode())){
+ requestObjectClaims.setClaim("response_mode", getAuthenticationRequest().getResponseMode());
+ }
+
+ requestObjectClaims.setClaim("scope", getAuthenticationRequest().getScope());
+
+ if (log.isDebugEnabled()) {
+ log.debug("{} Setting request object response claims to authentication context {}", getLogPrefix(),
+ requestObjectClaims.toJSONString());
+ }
+
+ // Create a plain JWT at first, can be signed and encrypted later
+ try {
+ getAuthenticationRequest().setRequestObject(new PlainJWT(requestObjectClaims.toJWTClaimsSet()));
+ } catch (final ParseException e) {
+ log.error("{} Unable to set request object claims as JWT claims", getLogPrefix(), e);
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX);
+ }
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeAuthorizationRequest.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeAuthorizationRequest.java
new file mode 100644
index 0000000..5799e3d
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeAuthorizationRequest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.authn.oidc.rp.impl;
+
+import java.util.function.Function;
+
+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.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.id.ClientID;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.OAuth2ClientContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * And action that creates an {@link OIDCAuthenticationRequest} shell to build and sets it to the
+ * outbound message context.
+ */
+public class InitializeAuthorizationRequest extends AbstractProfileAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(InitializeAuthorizationRequest.class);
+
+ /** The strategy used to lookup or create the {@link OAuth2ClientContext} for storing the client_id.*/
+ @Nonnull
+ private Function<ProfileRequestContext, OAuth2ClientContext> oauth2ClientContextLookupStrategy;
+
+ /** The stashed OAuth2 client context.*/
+ @Nullable private OAuth2ClientContext oauth2ClientContext;
+
+ /** Constructor.*/
+ public InitializeAuthorizationRequest() {
+ // Default under OIDCPeerEntityContext in the outbound context (create true).
+ oauth2ClientContextLookupStrategy = new ChildContextLookup<>(OAuth2ClientContext.class, true).compose(
+ new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
+ new OutboundMessageContextLookup()));
+ }
+
+ /**
+ * Set the strategy to lookup the {@link OAuth2ClientContext}
+ * from the {@link ProfileRequestContext}.
+ *
+ * @param strgy the strategy.
+ */
+ public void setOAuth2ClientContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, OAuth2ClientContext> strgy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+ oauth2ClientContextLookupStrategy = Constraint.isNotNull(strgy,
+ "OAuth2 client context lookup strategy cannot be null");
+ }
+
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+
+ oauth2ClientContext = oauth2ClientContextLookupStrategy.apply(profileRequestContext);
+ if (oauth2ClientContext == null) {
+ log.error("{} OAuth2 client context not found", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ super.doExecute(profileRequestContext);
+
+ final OIDCAuthenticationRequest authRequest =
+ new OIDCAuthenticationRequest(new ClientID(oauth2ClientContext.getClientId()));
+
+ profileRequestContext.getOutboundMessageContext().setMessage(authRequest);
+ log.debug("{} Adding shell OIDC authentication request to outbound context for client '{}'", getLogPrefix(),
+ oauth2ClientContext.getClientId());
+
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateACRs.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateACRs.java
new file mode 100644
index 0000000..acd439c
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateACRs.java
@@ -0,0 +1,88 @@
+/*
+ * 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.authn.oidc.rp.impl;
+
+import java.security.Principal;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.openid.connect.sdk.claims.ACR;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
+
+/**
+ * An action that adds any authentication context class references from the those derived from the
+ * profile config - which may be proxied and mapped from the upstream request.
+ */
+public class PopulateACRs extends AbstractOIDCAuthenticationRequestAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PopulateACRs.class);
+
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+ final List<ACR> acrs = buildRequestedAuthnContext(profileRequestContext);
+ if (acrs != null) {
+ log.debug("{} setting ACRs to '{}' for client '{}'", getLogPrefix(), acrs,
+ getAuthenticationRequest().getClientID());
+ getAuthenticationRequest().setAcrs(acrs);
+ } else {
+ log.debug("{} no ACRs requested for client '{}'", getLogPrefix(), getAuthenticationRequest().getClientID());
+ }
+ }
+
+ /**
+ * Build a list of {@link ACR}s if warranted. Converted from any default authentication method {@link Principal}s.
+ *
+ * <p>By default for this proxy case, the authentication methods are mapped from the upstream request.
+ *
+ * @param profileRequestContext current profile request context
+ *
+ * @return the list of ACRs.
+ */
+ @Nullable private List<ACR> buildRequestedAuthnContext(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+
+ // RequestedAuthnContext also based on profile configuration.
+ final List<Principal> principals = getProfileConfiguration()
+ .getDefaultAuthenticationMethods(profileRequestContext);
+ if (principals.isEmpty()) {
+ return null;
+ }
+
+ return principals.stream()
+ .filter(AuthenticationContextClassReferencePrincipal.class::isInstance)
+ .map(AuthenticationContextClassReferencePrincipal.class::cast)
+ .map(p -> new ACR(p.getName()))
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateEndpointURI.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateEndpointURI.java
new file mode 100644
index 0000000..4929dba
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateEndpointURI.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.authn.oidc.rp.impl;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+
+/**
+ * An action that adds the authorization endpoint URI from the providers metadata
+ * to the under constructions authentication request.
+ */
+public class PopulateEndpointURI extends AbstractOIDCAuthenticationRequestAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PopulateEndpointURI.class);
+
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+ getAuthenticationRequest().setEndpointURI(getProviderMetadataContext().getProviderInformation()
+ .getAuthorizationEndpointURI());
+ log.trace("{} Added authorization endpoint '{}' to authentication request for client '{}'",getLogPrefix(),
+ getAuthenticationRequest().getEndpointURI(), getAuthenticationRequest().getClientID());
+ }
+
+
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateForceAuthenticationPrompt.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateForceAuthenticationPrompt.java
new file mode 100644
index 0000000..ab75c82
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateForceAuthenticationPrompt.java
@@ -0,0 +1,64 @@
+/*
+ * 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.authn.oidc.rp.impl;
+
+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.ParseException;
+import com.nimbusds.openid.connect.sdk.Prompt;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+
+/**
+ * An action that set the Prompt parameter to 'Prompt' if force authn was requested by the upstream SP.
+ */
+public class PopulateForceAuthenticationPrompt extends AbstractOIDCAuthenticationRequestAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PopulateForceAuthenticationPrompt.class);
+
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+ if (getProfileConfiguration().isForceAuthn(profileRequestContext)) {
+ log.debug("{} Setting prompt=login (ForceAuthn) for OIDC AuthnRequest for client '{}'", getLogPrefix(),
+ getAuthenticationRequest().getClientID());
+ try {
+ getAuthenticationRequest().setPrompt(Prompt.parse(Prompt.Type.LOGIN.toString()));
+ } catch (final ParseException e) {
+ // This should never happen
+ log.error("{} Unable to honour force-authn, setting prompt to 'login' failed", getLogPrefix(), e);
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.AUTHN_EXCEPTION);
+ return;
+ }
+ } else {
+ log.debug("{} No ForceAuthn requirement, so no prompt set for client '{}'", getLogPrefix(),
+ getAuthenticationRequest().getClientID());
+ }
+ }
+
+
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateNonce.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateNonce.java
new file mode 100644
index 0000000..30df967
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateNonce.java
@@ -0,0 +1,75 @@
+/*
+ * 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.authn.oidc.rp.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.openid.connect.sdk.Nonce;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * An action that adds the nonce from a lookup strategy to the under constructions authentication request.
+ */
+public class PopulateNonce extends AbstractOIDCAuthenticationRequestAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PopulateNonce.class);
+
+ /** Strategy used to generate a nonce.*/
+ @Nonnull private Function<ProfileRequestContext, Nonce> nonceGenerationStrategy;
+
+ /** Constructor.*/
+ public PopulateNonce() {
+ nonceGenerationStrategy = prc -> new Nonce(OIDCProxySupport.generateNonce(16));
+ }
+
+ /**
+ * Set the nonce generation strategy to use.
+ *
+ * @param strategy the strategy
+ */
+ public void setNonceGenerationStrategy(@Nonnull final Function<ProfileRequestContext, Nonce> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+ nonceGenerationStrategy = Constraint.isNotNull(strategy, "Nonce generation strategy can not be null");
+ }
+
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+
+ getAuthenticationRequest().setNonce(nonceGenerationStrategy.apply(profileRequestContext));
+
+ log.debug("{} Added nonce '{}' to authentication request for client '{}'",getLogPrefix(),
+ getAuthenticationRequest().getNonce(), getAuthenticationRequest().getClientID());
+ }
+
+
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndMode.java
similarity index 80%
rename from idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeContext.java
rename to idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndMode.java
index 80f672d..232bcc6 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndMode.java
@@ -26,15 +26,13 @@ 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.opensaml.profile.context.navigate.OutboundMessageContextLookup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nimbusds.oauth2.sdk.ResponseMode;
import com.nimbusds.oauth2.sdk.ResponseType;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
-import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
@@ -42,44 +40,30 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * Action that populates the outbound ResponseTypeContext from various stratagies, by default from the
- * profile configuration.
+ * Action that populates the authentication request response_mode and response_type from various stratagies,
+ * by default from the profile configuration.
*
* TODO finish
*/
-public class PopulateResponseTypeAndModeContext extends AbstractProfileAction {
+public class PopulateResponseTypeAndMode extends AbstractOIDCAuthenticationRequestAction {
/** The Default response type if none is selected.*/
@Nonnull private static final ResponseType DEFAULT_RESPONSE_TYPE = ResponseType.CODE;
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(PopulateResponseTypeAndModeContext.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PopulateResponseTypeAndMode.class);
/**
* Strategy used to locate the {@link RelyingPartyContext} associated with a given {@link ProfileRequestContext}.
*/
@Nonnull private Function<ProfileRequestContext, RelyingPartyContext> relyingPartyContextLookupStrategy;
-
- /**
- * Strategy used to locate the {@link ResponseTypeAndModeContext} associated with a
- * given {@link ProfileRequestContext}.
- */
- @Nonnull
- private final Function<ProfileRequestContext, ResponseTypeAndModeContext> responseTypeAndModeContextLookupStrategy;
-
+
/** Applicable stashed profile configuration. */
@Nullable private OIDCAuthorizationConfiguration profileConfiguration;
- /** The stashed response type and mode context.*/
- @Nullable private ResponseTypeAndModeContext responseTypeAndModeContext;
/** Constructor.*/
- public PopulateResponseTypeAndModeContext() {
- // Default under the outbound message context, create is true
- responseTypeAndModeContextLookupStrategy =
- new ChildContextLookup<>(ResponseTypeAndModeContext.class, true).compose(
- new OutboundMessageContextLookup());
-
+ public PopulateResponseTypeAndMode() {
relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
}
@@ -100,9 +84,10 @@ public class PopulateResponseTypeAndModeContext extends AbstractProfileAction {
@Override
- protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
- if (!super.doPreExecute(profileRequestContext)) {
+ if (!super.doPreExecute(profileRequestContext, authenticationContext)) {
return false;
}
@@ -113,13 +98,6 @@ public class PopulateResponseTypeAndModeContext extends AbstractProfileAction {
return false;
}
- responseTypeAndModeContext = responseTypeAndModeContextLookupStrategy.apply(profileRequestContext);
- if (responseTypeAndModeContext == null) {
- log.error("{} No response type and mode context found or created", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
- return false;
- }
-
final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
if (rpCtx != null && rpCtx.getConfiguration() != null &&
rpCtx.getProfileConfig() instanceof OIDCAuthorizationConfiguration) {
@@ -136,7 +114,8 @@ public class PopulateResponseTypeAndModeContext extends AbstractProfileAction {
}
/** {@inheritDoc} */
- @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
final String responseTypeFromProfile = profileConfiguration.getResponseType(profileRequestContext);
final ResponseType responseType = parseResponseType(responseTypeFromProfile);
@@ -152,22 +131,22 @@ public class PopulateResponseTypeAndModeContext extends AbstractProfileAction {
final ResponseMode compatibleMode = ResponseMode.resolve(null, responseType);
log.trace("{} Compatible response mode '{}' resolved from response type '{}'", getLogPrefix(), compatibleMode,
responseTypeFromProfile);
- responseTypeAndModeContext.setDefaultResponseMode(compatibleMode);
+ getAuthenticationRequest().setDefaultResponseMode(compatibleMode);
if (responseModeOverride != null && !responseModeOverride.equals(compatibleMode)) {
log.debug("{} Response_mode override '{}' exists in the profile configuration and is different than the"
+ " default mode '{}' for response_type '{}'",
getLogPrefix(), responseModeFromProfile, compatibleMode, responseType);
- responseTypeAndModeContext.setResponseMode(responseModeOverride);
+ getAuthenticationRequest().setResponseMode(responseModeOverride);
} else {
- responseTypeAndModeContext.setResponseMode(compatibleMode);
+ getAuthenticationRequest().setResponseMode(compatibleMode);
}
- responseTypeAndModeContext.setResponseType(responseType);
- log.debug("{} Response_type '{}' selected", getLogPrefix(), responseTypeAndModeContext.getResponseType());
- log.debug("{} Response_mode '{}' selected", getLogPrefix(), responseTypeAndModeContext.getResponseMode());
+ getAuthenticationRequest().setResponseType(responseType);
+ log.debug("{} Response_type '{}' selected", getLogPrefix(), getAuthenticationRequest().getResponseType());
+ log.debug("{} Response_mode '{}' selected", getLogPrefix(), getAuthenticationRequest().getResponseMode());
}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateScopes.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateScopes.java
new file mode 100644
index 0000000..07d1d82
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateScopes.java
@@ -0,0 +1,52 @@
+/*
+ * 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.authn.oidc.rp.impl;
+
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+
+/**
+ * An action that adds the scopes from the profile request object to the under constructions authentication request.
+ */
+public class PopulateScopes extends AbstractOIDCAuthenticationRequestAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PopulateScopes.class);
+
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+ final Set<String> scopes = getProfileConfiguration().getScopes(profileRequestContext);
+ if (scopes != null && !scopes.isEmpty()) {
+ scopes.forEach(s -> getAuthenticationRequest().getScope().add(s));
+ }
+ log.trace("{} Added scopes '{}' to authentication request for client '{}'",getLogPrefix(),
+ getAuthenticationRequest().getScope(), getAuthenticationRequest().getClientID());
+ }
+
+
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ProcessEndUserClaims.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ProcessEndUserClaims.java
index 51cabc8..224d721 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ProcessEndUserClaims.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ProcessEndUserClaims.java
@@ -53,7 +53,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
* be empty i.e. claims from the UserInfo endpoint were not requested.</p>
*/
//TODO similar too ValidateUserInfoClaims, do we need to extend OIDC action
-public class ProcessEndUserClaims extends AbstractOIDCAuthenticationAction {
+public class ProcessEndUserClaims extends AbstractOIDCAuthenticationResponseAction {
/** Class logger.*/
@Nonnull private final Logger log = LoggerFactory.getLogger(ProcessEndUserClaims.class);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/SignRequestObject.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/SignRequestObject.java
new file mode 100644
index 0000000..cc4d130
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/SignRequestObject.java
@@ -0,0 +1,50 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import javax.annotation.Nonnull;
+
+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 com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.openid.connect.sdk.claims.IDTokenClaimsSet;
+
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.AbstractSignJWTAction;
+import net.shibboleth.idp.plugin.oidc.op.profile.impl.SignIDToken;
+
+/**
+ * Action that signs a request object and sets it to ???.
+ */
+public class SignRequestObject extends AbstractSignJWTAction {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(SignRequestObject.class);
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+
+ if (getOidcResponseContext().getIDToken() == null) {
+ log.error("{} No id token available", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+ return false;
+ }
+ try {
+ idTokenClaims = getOidcResponseContext().getIDToken().toJWTClaimsSet();
+ } catch (final ParseException e) {
+ log.error("{} id token parsing failed {}", getLogPrefix(), e.getMessage());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateOAuthAccessTokenResponse.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateOAuthAccessTokenResponse.java
index 6460116..3c69f12 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateOAuthAccessTokenResponse.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateOAuthAccessTokenResponse.java
@@ -39,7 +39,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/** Validation action that validates the OAuth Access Token Response against RFC 6749 section 5.1
* and OpenID Connect Core 1.0 section 3.1.3.3.*/
-public class ValidateOAuthAccessTokenResponse extends AbstractOIDCAuthenticationAction {
+public class ValidateOAuthAccessTokenResponse extends AbstractOIDCAuthenticationResponseAction {
/** Class logger. */
@Nonnull @NotEmpty private final Logger log = LoggerFactory.getLogger(ValidateOAuthAccessTokenResponse.class);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateResponseState.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateResponseState.java
index 1af7cf3..67fd511 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateResponseState.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateResponseState.java
@@ -47,7 +47,7 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
* </pre>
*
*/
-public class ValidateResponseState extends AbstractOIDCAuthenticationAction {
+public class ValidateResponseState extends AbstractOIDCAuthenticationResponseAction {
/** Class logger. */
@Nonnull @NotEmpty private final Logger log = LoggerFactory.getLogger(ValidateResponseState.class);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateTokenClaims.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateTokenClaims.java
index e2e357b..9747f38 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateTokenClaims.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateTokenClaims.java
@@ -76,7 +76,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
* @event {@link net.shibboleth.idp.authn.AuthnEventIds#AUTHN_EXCEPTION}
* @event {@link net.shibboleth.idp.authn.AuthnEventIds#NO_CREDENTIALS}
*/
-public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
+public class ValidateTokenClaims extends AbstractOIDCAuthenticationResponseAction {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(ValidateTokenClaims.class);
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index c8d8250..fd0fae4 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -40,6 +40,15 @@
<ref bean="shibboleth.ChildLookup.OIDCPeerEntityFromOutbound" />
</constructor-arg>
</bean>
+
+ <bean id="shibboleth.ChildLookup.OIDCProviderMetadataContextFromInbound" parent="shibboleth.Functions.Compose">
+ <constructor-arg name="g">
+ <ref bean="shibboleth.ChildLookup.OIDCProviderMetadataContext" />
+ </constructor-arg>
+ <constructor-arg name="f">
+ <ref bean="shibboleth.ChildLookup.OIDCPeerEntityFromInbound" />
+ </constructor-arg>
+ </bean>
<bean id="shibboleth.ChildLookup.ProviderMetadataFromProviderContext"
class="net.shibboleth.idp.profile.context.navigate.SpringExpressionContextLookupFunction"
@@ -77,10 +86,14 @@
</constructor-arg>
</bean>
- <!-- Find OIDCPeerEntity Context under outbound message -->
<bean id="shibboleth.ChildLookup.OIDCPeerEntityFromOutbound" parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookup.OIDCPeerEntityContext" c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+
+ <bean id="shibboleth.ChildLookup.OIDCPeerEntityFromInbound" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookup.OIDCPeerEntityContext" c:f-ref="shibboleth.MessageContextLookup.Inbound" />
+ <bean id="shibboleth.ChildLookup.Proxy.MessageContextLookup.Inbound"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.InboundMessageContextFromProxyPRC"/>
<!-- The authentication flow descriptor -->
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
index 6459687..70919f0 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
@@ -99,11 +99,71 @@
<bean id="SelectProfileConfiguration" class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration"
scope="prototype" p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
+
+
+ <bean id="InitializeAuthorizationRequest"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.InitializeAuthorizationRequest"
+ scope="prototype" p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"/>
+
+ <bean id="PopulateResponseTypeAndMode" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateResponseTypeAndMode"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
+
+ <bean id="PopulateScopes" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateScopes"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
+
+ <bean id="PopulateNonce" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateNonce"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
+
+ <bean id="PopulateEndpointURI" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateEndpointURI"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
+
+ <bean id="PopulateACRs" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateACRs"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
+
+ <bean id="PopulateForceAuthenticationPrompt" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateForceAuthenticationPrompt"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
+
+ <!-- Build RequestObject if required -->
+ <bean id="RequestObjectRequiredAndSupportedPredicate"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.RequestObjectRequiredAndSupported" />
- <bean id="PopulateResponseTypeAndModeContext" scope="prototype"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateResponseTypeAndModeContext"
- p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
+
+ <bean id="PopulateRequestObjectSignatureSigningParameters"
+ class="net.shibboleth.oidc.security.impl.PopulateJWTSignatureSigningParameters"
+ c:strategy-ref="shibboleth.ChildLookup.Proxy.MessageContextLookup.Inbound"
+ p:configurationLookupStrategy-ref="RequestObjectSignatureSigningConfigurationLookup"
+ p:providerMetadataContextLookupStrategy-ref="shibboleth.ChildLookup.OIDCProviderMetadataContextFromOutbound"
+ p:signatureSigningParametersResolver-ref="shibboleth.authn.oidc.rp.RequestObjectSignatureSigningParametersResolver"/>
+
+ <bean id="shibboleth.authn.oidc.rp.RequestObjectSignatureSigningParametersResolver"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.RelyingPartyProxySigningParametersResolver"
+ p:providerMetadataAlgorithmLookupStrategy-ref="shibboleth.authn.oidc.rp.RequestObjectSupportedSignatureSigningAlgorithms"/>
+
+ <bean id="shibboleth.authn.oidc.rp.RequestObjectSupportedSignatureSigningAlgorithms"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.config.RequestObjectSupportedSignatureSigningAlgorithms"/>
+
+ <bean id="RequestObjectSignatureSigningConfigurationLookup" lazy-init="true"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.RequestObjectSignatureSigningConfigurationLookupFunction"
+ p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyConfigurationResolver" />
+ <bean id="BuildRequestObject" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.BuildRequestObject"
+ scope="prototype"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
+
+ <!-- Build the authentication request -->
<bean id="AddOIDCAuthenticationRequest" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.AddOIDCAuthenticationRequest"
p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
@@ -167,12 +227,14 @@
<bean id="ValidateExternalAuthenticationContext" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateExternalAuthenticationContext" />
- <bean id="ValidateAuthenticationResponseResult" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <bean id="ValidateAuthenticationResponseResult" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateAuthenticationResponseResult"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
- <bean id="ValidateResponseStateMatchesRequest" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <bean id="ValidateResponseStateMatchesRequest" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateResponseState"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
<!-- Create a new OIDCPeerEntityContext and add it to the existing inbound context -->
@@ -193,24 +255,26 @@
<!-- CODE flow beans -->
- <bean id="InitializeOAuth2ClientAuthenticationContext" parent="NestedWebFlowProfileActionAdaptor"
- scope="prototype"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.InitializeOAuth2ClientAuthenticationContext" />
+ <bean id="InitializeOAuth2ClientAuthenticationContext" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.InitializeOAuth2ClientAuthenticationContext"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
- <bean id="ExchangeCodeForAccessToken" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <bean id="ExchangeCodeForAccessToken" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExchangeCodeForAccessToken"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
p:httpClient="#{getObject('shibboleth.authn.oidc.rp.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
p:httpClientSecurityParameters="#{getObject('shibboleth.authn.oidc.rp.HttpClientSecurityParameters')}"
p:httpResponseDecoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenResponseDecoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultTokenResponseDecoder')}"
p:httpRequestEncoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenRequestEncoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultAuthCodeTokenResponseEncoder')}" />
- <bean id="ValidateOAuthAccessTokenResponse" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <bean id="ValidateOAuthAccessTokenResponse" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOAuthAccessTokenResponse"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
- <bean id="ExtractIDTokenFromTokenResponse" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <bean id="ExtractIDTokenFromTokenResponse" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExtractIDTokenFromResponse"
p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:rawIdTokenLookupStrategy-ref="TokenResponseIDTokenLookupStrategy" />
@@ -253,13 +317,11 @@
<!-- ID_TOKEN Decryption -->
- <bean id="PopulateIDTokenDecryptionParameters" parent="NestedWebFlowProfileActionAdaptor" scope="prototype">
- <constructor-arg>
- <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateJWTDecryptionParameters"
- p:configurationLookupStrategy-ref="IDTokenDecryptionConfigurationLookup"
- p:decryptionParametersResolver-ref="JWTDecryptionParametersResolver" />
- </constructor-arg>
- </bean>
+ <bean id="PopulateIDTokenDecryptionParameters"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateJWTDecryptionParameters" scope="prototype"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:configurationLookupStrategy-ref="IDTokenDecryptionConfigurationLookup"
+ p:decryptionParametersResolver-ref="JWTDecryptionParametersResolver" />
<bean id="JWTDecryptionParametersResolver"
class="net.shibboleth.oidc.security.impl.DefaultJWTDecryptionParametersResolver" />
@@ -271,20 +333,17 @@
<bean id="IDTokenInAccessTokenUpdateStrategy"
class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.IDTokenInAccessTokenUpdateStrategy" />
- <bean id="DecryptJWT" parent="NestedWebFlowProfileActionAdaptor" scope="prototype">
- <constructor-arg>
- <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DecryptJWT">
- <property name="jwtTokenLookupStrategy">
- <bean class="net.shibboleth.idp.profile.context.navigate.SpringExpressionContextLookupFunction"
- c:_0="#{ T(org.opensaml.profile.context.ProfileRequestContext) }"
- c:outputType="#{T(com.nimbusds.jwt.EncryptedJWT)}"
- c:expression="#input.getInboundMessageContext().getSubcontext(T(net.shibboleth.idp.plugin.authn.oidc.rp.context.AccessTokenResponseContext)).getIdToken()" />
- </property>
- <property name="jwtUpdateStrategy">
- <ref bean="IDTokenInAccessTokenUpdateStrategy" />
- </property>
- </bean>
- </constructor-arg>
+ <bean id="DecryptJWT" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DecryptJWT" scope="prototype"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext">
+ <property name="jwtTokenLookupStrategy">
+ <bean class="net.shibboleth.idp.profile.context.navigate.SpringExpressionContextLookupFunction"
+ c:_0="#{ T(org.opensaml.profile.context.ProfileRequestContext) }"
+ c:outputType="#{T(com.nimbusds.jwt.EncryptedJWT)}"
+ c:expression="#input.getInboundMessageContext().getSubcontext(T(net.shibboleth.idp.plugin.authn.oidc.rp.context.AccessTokenResponseContext)).getIdToken()" />
+ </property>
+ <property name="jwtUpdateStrategy">
+ <ref bean="IDTokenInAccessTokenUpdateStrategy" />
+ </property>
</bean>
@@ -294,6 +353,7 @@
scope="prototype">
<constructor-arg>
<bean class="net.shibboleth.oidc.security.impl.PopulateJWTSignatureValidationParameters"
+ c:strategy-ref="shibboleth.MessageContextLookup.Inbound"
p:configurationLookupStrategy-ref="shibboleth.authn.oidc.rp.IDTokenSignatureValidationConfigurationLookup"
p:signatureValidationParametersResolver-ref="shibboleth.authn.oidc.rp.IDTokenJwtSignatureValidationParametersResolver" />
</constructor-arg>
@@ -367,8 +427,9 @@
<!-- Default id_token and some UserInfo JWT validation wiring. -->
<!-- No default cleanup, maybe could be to remove nonce etc. -->
- <bean id="ValidateIDTokenClaims" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <bean id="ValidateIDTokenClaims" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.idtoken.jwt.claims.CleanUpHook')
?: getObject('DefaultCleanupHook')}"
@@ -477,18 +538,18 @@
<ref bean="NotBeforeClaimsValidator" />
<ref bean="NonceClaimValidator" />
<!-- missing ACR? and auth_time, access_token at_hash. -->
- <!-- TODO at_hash if contained in id_token should exact match (via some steps) a derivation of the access_token-->
+ <!-- TODO at_hash if contained in id_token should exact match (via some steps) a derivation of the access_token -->
</util:list>
<bean id="CheckUserInfoRequiredCondition"
class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoLookupCondition" />
-
<!-- UserInfo endpoint beans -->
- <bean id="UserInfoEndpointLookup" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <bean id="UserInfoEndpointLookup" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.UserInfoEndpointLookup"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
p:httpClient="#{getObject('shibboleth.authn.oidc.rp.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
p:httpClientSecurityParameters="#{getObject('shibboleth.authn.oidc.rp.HttpClientSecurityParameters')}"
@@ -507,13 +568,12 @@
<!-- FIXME: (might not be an issue) Will populate the same security params context as the id_token, but overright the
decryption config -->
- <bean id="PopulateUserInfoDecryptionParameters" parent="NestedWebFlowProfileActionAdaptor" scope="prototype">
- <constructor-arg>
- <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateJWTDecryptionParameters"
- p:configurationLookupStrategy-ref="UserInfoTokenDecryptionConfigurationLookup"
- p:decryptionParametersResolver-ref="JWTDecryptionParametersResolver" />
- </constructor-arg>
- </bean>
+ <bean id="PopulateUserInfoDecryptionParameters"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateJWTDecryptionParameters" scope="prototype"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:configurationLookupStrategy-ref="UserInfoTokenDecryptionConfigurationLookup"
+ p:decryptionParametersResolver-ref="JWTDecryptionParametersResolver" />
+
<bean id="UserInfoTokenDecryptionConfigurationLookup" lazy-init="true"
class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.UserInfoDecryptionConfigurationLookupFunction"
@@ -522,26 +582,24 @@
<bean id="UserInfoInUserInfoResponseContextUpdateStrategy"
class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.UserInfoInUserInfoResponseContextUpdateStrategy" />
- <bean id="DecryptUserInfoJWT" parent="NestedWebFlowProfileActionAdaptor" scope="prototype">
- <constructor-arg>
- <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DecryptJWT">
- <property name="jwtTokenLookupStrategy">
- <bean class="net.shibboleth.idp.profile.context.navigate.SpringExpressionContextLookupFunction"
- c:_0="#{ T(org.opensaml.profile.context.ProfileRequestContext) }"
- c:outputType="#{T(com.nimbusds.jwt.EncryptedJWT)}"
- c:expression="#input.getInboundMessageContext().getSubcontext(T(net.shibboleth.idp.plugin.authn.oidc.rp.context.UserInfoResponseContext)).getUserInfo().getResponseJwt()" />
- </property>
- <property name="jwtUpdateStrategy">
- <ref bean="UserInfoInUserInfoResponseContextUpdateStrategy" />
- </property>
- </bean>
- </constructor-arg>
+ <bean id="DecryptUserInfoJWT" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DecryptJWT" scope="prototype"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext">
+ <property name="jwtTokenLookupStrategy">
+ <bean class="net.shibboleth.idp.profile.context.navigate.SpringExpressionContextLookupFunction"
+ c:_0="#{ T(org.opensaml.profile.context.ProfileRequestContext) }"
+ c:outputType="#{T(com.nimbusds.jwt.EncryptedJWT)}"
+ c:expression="#input.getInboundMessageContext().getSubcontext(T(net.shibboleth.idp.plugin.authn.oidc.rp.context.UserInfoResponseContext)).getUserInfo().getResponseJwt()" />
+ </property>
+ <property name="jwtUpdateStrategy">
+ <ref bean="UserInfoInUserInfoResponseContextUpdateStrategy" />
+ </property>
</bean>
<bean id="PopulateUserInfoTokenSignatureValidationParameters" parent="NestedWebFlowProfileActionAdaptor"
scope="prototype">
<constructor-arg>
<bean class="net.shibboleth.oidc.security.impl.PopulateJWTSignatureValidationParameters"
+ c:strategy-ref="shibboleth.MessageContextLookup.Inbound"
p:configurationLookupStrategy-ref="UserInfoTokenSignatureValidationConfigurationLookup"
p:signatureValidationParametersResolver-ref="UserInfoTokenJwtSignatureValidationParametersResolver" />
</constructor-arg>
@@ -578,17 +636,18 @@
<ref bean="shibboleth.ChildLookup.OIDCProviderMetadataFromPeerEntityContext" />
</property>
</bean>
- <!-- TODO WE NEED TO CHECK JWT CLAIMS HERE see spec-->
+ <!-- TODO WE NEED TO CHECK JWT CLAIMS HERE see spec -->
</list>
</property>
</bean>
</constructor-arg>
</bean>
-
- <!-- UserInfo response JWT validation -->
- <bean id="ValidateUserInfoTokenClaims" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <!-- UserInfo response JWT validation -->
+
+ <bean id="ValidateUserInfoTokenClaims" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.userinfo.jwt.claims.CleanUpHook')}"
p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.userinfo.UserInfoTokenClaimsValidator')
@@ -604,12 +663,12 @@
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultUserInfoTokenLookupStrategy" />
<util:list id="UserInfoClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
- <ref bean="SubClaimRequiredValidator"/>
- <ref bean="SubMatchesIDTokenClaimValidator"/>
+ <ref bean="SubClaimRequiredValidator" />
+ <ref bean="SubMatchesIDTokenClaimValidator" />
<ref bean="IssuerClaimsValidator" />
<ref bean="AudienceClaimsValidator" />
- </util:list>
-
+ </util:list>
+
<bean id="SubClaimRequiredValidator"
class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator">
<property name="requiredClaims">
@@ -618,22 +677,22 @@
</list>
</property>
</bean>
-
- <bean id="SubMatchesIDTokenClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
- p:claimName="sub">
+
+ <bean id="SubMatchesIDTokenClaimValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator" p:claimName="sub">
<property name="valueToMatchLookupStrategy">
- <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.SubFromIDTokenLookupFunction"/>
+ <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.SubFromIDTokenLookupFunction" />
</property>
- </bean>
-
-
+ </bean>
+
+
<!-- UserInfo Decryption and Signature Validation Done -->
- <!-- This is a very simplified and hard coded version of the claims verification used for a JWT. Maybe look to replace -->
- <bean id="ValidateUserInfoPlainResponseClaims" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+ <!-- This is a very simplified and hard coded version of the claims verification used for a JWT. Maybe look to replace -->
+ <bean id="ValidateUserInfoPlainResponseClaims" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateUserInfoJSONObjectClaims"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
@@ -645,11 +704,12 @@
<bean id="CheckUserInfoPlainResponseTypeCondition"
class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoPlainResponseTypeCondition" />
-
+
<!-- Final validation and proxy authentication result -->
- <bean id="ValidateOIDCAuthentication" parent="NestedWebFlowProfileActionAdaptor"
+ <bean id="ValidateOIDCAuthentication"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOIDCAuthentication" scope="prototype"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
p:responderLookupStrategy-ref="shibboleth.RelyingPartyIdLookup.Simple"
p:requesterLookupStrategy-ref="shibboleth.ResponderIdLookup.Simple"
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
index 8c6c8e9..543c056 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
@@ -34,15 +34,40 @@
<evaluate expression="InitializeOutboundMessageContext" />
<evaluate expression="SelectProfileConfiguration" />
<evaluate expression="InitializeOAuth2ClientContext" />
- <evaluate expression="PopulateResponseTypeAndModeContext" />
- <evaluate expression="AddOIDCAuthenticationRequest" />
- <!-- <evaluate expression="PostRequestPopulateAuditContext" /> <evaluate expression="WriteAuditLog" /> -->
+ <evaluate expression="InitializeAuthorizationRequest" />
+ <evaluate expression="PopulateResponseTypeAndMode" />
+ <evaluate expression="PopulateScopes" />
+ <evaluate expression="PopulateNonce" />
+ <evaluate expression="PopulateForceAuthenticationPrompt" />
+ <evaluate expression="PopulateEndpointURI"/>
+ <evaluate expression="PopulateACRs"/>
+ <!-- <evaluate expression="PostRequestPopulateAuditContext" />
+ <evaluate expression="WriteAuditLog" /> -->
<!-- <evaluate expression="InitializeMessageChannelSecurityContext" /> -->
<evaluate expression="'proceed'" />
- <transition on="proceed" to="AuthRequest" />
+ <transition on="proceed" to="RequestObjectRequiredAndSupported" />
+ </action-state>
+
+ <!-- Is a request object requested by the config, and does the OP support it? -->
+ <decision-state id="RequestObjectRequiredAndSupported">
+ <if test="RequestObjectRequiredAndSupportedPredicate.test(opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext').getSubcontext('org.opensaml.profile.context.ProfileRequestContext'))"
+ then="BuildRequestObject" else="AuthRequest"/>
+ </decision-state>
+
+ <action-state id="BuildRequestObject">
+ <evaluate expression="PopulateRequestObjectSignatureSigningParameters"/>
+ <evaluate expression="BuildRequestObject" />
+ <!-- <evaluate expression="'proceed'" />
+ <transition on="proceed" to="AuthRequest" /> -->
</action-state>
+
+ <!-- <action-state id="FinaliseAuthenticationRequest">
+ <evaluate expression="AddOIDCAuthenticationRequest" />
+ <evaluate expression="'proceed'" />
+ <transition on="proceed" to="AuthRequest" />
+ </action-state> -->
<view-state id="AuthRequest"
view="externalRedirect:#{T(net.shibboleth.idp.authn.ExternalAuthentication).getExternalRedirect(flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.authn.OIDC.externalAuthnPath'), flowExecutionContext.getKey().toString())}">
@@ -76,23 +101,23 @@
<!-- check a null response_type first, should never get here -->
<if
test="opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext')
- .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getSubcontext('net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext').getResponseType() == null"
+ .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getMessage().getResponseType() == null"
then="UnsupportedFlow" />
<!-- Check for CODE flow -->
<if
test="opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext')
- .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getSubcontext('net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext').getResponseType().impliesCodeFlow()"
+ .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getMessage().getResponseType().impliesCodeFlow()"
then="CodeFlow" />
<!-- Check for Hybrid flow -->
<if
test="opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext')
- .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getSubcontext('net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext').getResponseType().impliesImplicitFlow()"
+ .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getMessage().getResponseType().impliesImplicitFlow()"
then="HybridFlow" />
<!-- Check for IMPLICIT flow -->
<!-- final IF has an else if an unsupported flow is used (should not happen) -->
<if
test="opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext')
- .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getSubcontext('net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext').getResponseType().impliesHybridFlow()"
+ .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getMessage().getResponseType().impliesHybridFlow()"
then="ImplicitFlow" else="UnsupportedFlow" />
</decision-state>
@@ -118,8 +143,8 @@
<transition on="proceed" to="CheckUserInfoClaimsRequired" />
</action-state>
- <decision-state id="CheckUserInfoClaimsRequired"> <if
- test="CheckUserInfoRequiredCondition.test(opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext').getSubcontext('org.opensaml.profile.context.ProfileRequestContext'))"
+ <decision-state id="CheckUserInfoClaimsRequired">
+ <if test="CheckUserInfoRequiredCondition.test(opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext').getSubcontext('org.opensaml.profile.context.ProfileRequestContext'))"
then="UserInfoRequest" else="FinalizeResponse" />
<!-- if else here, we need to set id_token claims into EndUserClaimsContext -->
</decision-state>
@@ -132,8 +157,8 @@
</action-state>
<!-- A plain JWT will skip token validation and go straight to claims validation -->
- <decision-state id="CheckUserInfoResponseType"> <if
- test="CheckUserInfoPlainResponseTypeCondition.test(opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext').getSubcontext('org.opensaml.profile.context.ProfileRequestContext'))"
+ <decision-state id="CheckUserInfoResponseType">
+ <if test="CheckUserInfoPlainResponseTypeCondition.test(opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext').getSubcontext('org.opensaml.profile.context.ProfileRequestContext'))"
then="ValidateUserInfoPlaimClaimsSet" else="ValidateUserInfoJWT"/>
</decision-state>
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index dd554f4..19bfa73 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -65,23 +65,52 @@
<bean id="shibboleth.authn.oidc.rp.DefaultSecurityConfiguration"
class="net.shibboleth.oidc.profile.config.OIDCSecurityConfiguration">
- <property name="idTokenJwtDecryptionConfig">
+ <property name="idTokenJwtDecryptionConfiguration">
<ref
bean="#{'%{dp.authn.oidc.rp.idtoken.decrypt.config:shibboleth.authn.oidc.rp.DefaultJWTDecryptionConfiguration}'.trim()}" />
</property>
- <property name="idTokenJwtSignatureValidationConfig">
+ <property name="idTokenJwtSignatureValidationConfiguration">
<ref
bean="#{'%{dp.authn.oidc.rp.idtoken.valid.config:shibboleth.authn.oidc.rp.DefaultJWTSignatureValidationConfiguration}'.trim()}" />
</property>
<!-- User info config is actually the same by default as id_token, not sure we need seperation, although could be overriden -->
- <property name="userInfoJwtDecryptionConfig">
+ <property name="userInfoJwtDecryptionConfiguration">
<ref
bean="#{'%{dp.authn.oidc.rp.userinfotoken.decrypt.config:shibboleth.authn.oidc.rp.DefaultJWTDecryptionConfiguration}'.trim()}" />
</property>
- <property name="userInfoTokenJwtSignatureValidationConfig">
+ <property name="userInfoTokenJwtSignatureValidationConfiguration">
<ref
bean="#{'%{dp.authn.oidc.rp.userinfotoken.valid.config:shibboleth.authn.oidc.rp.DefaultJWTSignatureValidationConfiguration}'.trim()}" />
</property>
+ <property name="requestObjectSignatureSigningConfiguration">
+ <ref
+ bean="#{'%{dp.authn.oidc.rp.requestobject.signing.config:shibboleth.authn.oidc.rp.DefaultRequestObjectSigningConfiguration}'.trim()}" />
+ </property>
+ </bean>
+
+ <!--
+ Configuration for credentials and supported algorithms for request object request signing.
+ Any shared secret credential from the RP's configuration will be included in the set of usable credentials
+ -->
+ <bean id="shibboleth.authn.oidc.rp.DefaultRequestObjectSigningConfiguration"
+ parent="shibboleth.BasicSignatureSigningConfiguration"
+ p:signingCredentials="#{getObject('shibboleth.authn.oidc.rp.SigningCredentialss')}">
+ <property name="signatureAlgorithms">
+ <list>
+ <util:constant
+ static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_256" />
+ <util:constant
+ static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_384" />
+ <util:constant
+ static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_512" />
+ <util:constant
+ static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_256" />
+ <util:constant
+ static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_384" />
+ <util:constant
+ static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_512" />
+ </list>
+ </property>
</bean>
diff --git a/idp-oidc-rp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/oidc/rp/conf/authn/rp-credentials.xml b/idp-oidc-rp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/oidc/rp/conf/authn/rp-credentials.xml
index 7dc5a6f..d660e13 100644
--- a/idp-oidc-rp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/oidc/rp/conf/authn/rp-credentials.xml
+++ b/idp-oidc-rp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/oidc/rp/conf/authn/rp-credentials.xml
@@ -15,4 +15,10 @@
p:resource="%{idp.authn.oidc.rp.client.enc.key:#{null}}" />
</util:list>
+ <!-- Default signing credentials -->
+ <util:list id="shibboleth.authn.oidc.rp.SigningCredentials">
+ <bean parent="shibboleth.authn.oidc.rp.JWKCredential" p:failIfResourceIsNull="false"
+ p:resource="%{idp.authn.oidc.rp.client.sig.key:#{null}}" />
+ </util:list>
+
</beans>
\ No newline at end of file
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
index 12a27f8..607412e 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
@@ -36,11 +36,13 @@ import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.junit.Test;
+import org.opensaml.core.config.InitializationException;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.security.credential.Credential;
import org.opensaml.security.credential.CredentialResolver;
import org.opensaml.security.credential.UsageType;
+import org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -75,7 +77,6 @@ import net.shibboleth.idp.authn.impl.ExternalAuthenticationImpl;
import net.shibboleth.idp.authn.principal.UsernamePrincipal;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OAuth2ClientContext;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
import net.shibboleth.idp.plugin.authn.test.flow.AbstractAuthnXmlFlowExecutionTests;
import net.shibboleth.idp.plugin.authn.test.flow.mock.MockFlowBuilder;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
@@ -111,6 +112,9 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
private static final String OP_ISSUER_ID = "https://localhost:9918";
+ /** The OP Issuer to use with an override in the config to use the request object authn param.*/
+ private static final String OP_ISSUER_ID_REQUESTOBJECT_TRUE = "https://localhost:9919";
+
private final String RP_ALLOWED_ORIGINS = "https://localhost";
private static final String CLIENT_ID = "demo_rp";
@@ -179,6 +183,73 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
+ "\"urn:ietf:params:oauth:grant-type:jwt-bearer\"\n"
+ "]\n"
+ "}";
+
+ /**
+ * Example of good provider metadata. Endpoints are localhost to support the
+ * mock server that is started. This OP supports the use of the request object.
+ */
+ private final static String GOOD_PROVIDER_CONFIGURATION_INFO_USE_REQUEST_OBJECT = "{\n"
+ + "\"issuer\": \"https://localhost:9919\",\n"
+ + "\"authorization_endpoint\": \"https://localhost:9919/o/oauth2/v2/auth\",\n"
+ + "\"device_authorization_endpoint\": \"https://localhost:9919/device/code\",\n"
+ + "\"token_endpoint\": \"https://localhost:9919/token\",\n"
+ + "\"userinfo_endpoint\": \"https://localhost:9919/v1/userinfo\",\n"
+ + "\"revocation_endpoint\": \"https://localhost:9919/revoke\",\n"
+ + "\"jwks_uri\": \"https://localhost:9918/oauth2/v3/certs\",\n"
+ + "\"request_parameter_supported\":true,\n"
+ + "\"response_types_supported\": [\n"
+ + "\"code\",\n"
+ + "\"token\",\n"
+ + "\"id_token\",\n"
+ + "\"code token\",\n"
+ + "\"code id_token\",\n"
+ + "\"token id_token\",\n"
+ + "\"code token id_token\",\n"
+ + "\"none\"\n"
+ + "],\n"
+ + "\"subject_types_supported\": [\n"
+ + "\"public\"\n"
+ + "],\n"
+ + "\"id_token_signing_alg_values_supported\": [\n"
+ + "\"RS256\"\n"
+ + "],\n"
+ + "\"request_object_signing_alg_values_supported\": [\n"
+ + "\"HS256\"\n"
+ + "],\n"
+ + "\"scopes_supported\": [\n"
+ + "\"openid\",\n"
+ + "\"email\",\n"
+ + "\"profile\"\n"
+ + "],\n"
+ + "\"token_endpoint_auth_methods_supported\": [\n"
+ + "\"client_secret_post\",\n"
+ + "\"client_secret_basic\"\n"
+ + "],\n"
+ + "\"claims_supported\": [\n"
+ + "\"aud\",\n"
+ + "\"email\",\n"
+ + "\"email_verified\",\n"
+ + "\"exp\",\n"
+ + "\"family_name\",\n"
+ + "\"given_name\",\n"
+ + "\"iat\",\n"
+ + "\"iss\",\n"
+ + "\"locale\",\n"
+ + "\"name\",\n"
+ + "\"picture\",\n"
+ + "\"sub\"\n"
+ + "],\n"
+ + "\"code_challenge_methods_supported\": [\n"
+ + "\"plain\",\n"
+ + "\"S256\"\n"
+ + "],\n"
+ + "\"grant_types_supported\": [\n"
+ + "\"authorization_code\",\n"
+ + "\"refresh_token\",\n"
+ + "\"urn:ietf:params:oauth:grant-type:device_code\",\n"
+ + "\"urn:ietf:params:oauth:grant-type:jwt-bearer\"\n"
+ + "]\n"
+ + "}";
/** Mock JSON Object response from the UserInfo endpoint.*/
@@ -280,7 +351,10 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
addBeanDefinition(builderContext, "shibboleth.SAML2AuthnContextClassRef",BeanDefinitionBuilder.
genericBeanDefinition(net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal.class)
.setAbstract(true).getBeanDefinition());
-
+
+ addBeanDefinition(builderContext, "shibboleth.BasicSignatureSigningConfiguration",BeanDefinitionBuilder.
+ genericBeanDefinition(org.opensaml.xmlsec.impl.BasicSignatureSigningConfiguration.class)
+ .setAbstract(true).getBeanDefinition());
try {
// Create a HttpClient which turns off hostname verification and trusts all certificates (for TESTS!)
@@ -292,6 +366,15 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
} catch (final Exception e) {
log.error("Could not mock HTTP response",e);
}
+
+ //Create an algorithm registry here, as opensaml init will not take place for these tests
+ try {
+ final GlobalAlgorithmRegistryInitializer gar = new GlobalAlgorithmRegistryInitializer();
+ gar.init();
+ } catch (final InitializationException e) {
+ log.error("Could not initialise the algorithm registry");
+ fail();
+ }
loadBeanDefinitionsFromXmlFile(builderContext,
new ClassPathResource("META-INF/net.shibboleth.idp/postconfig.xml"),
@@ -366,6 +449,8 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
final OIDCAuthenticationRequest request = new OIDCAuthenticationRequest(new ClientID(OP_ISSUER_ID));
request.setState(new State("8df98fd63a53fa5b5433d6f8754bca5d.65317332"));
request.setNonce(new Nonce("abadnonce"));
+ request.setResponseMode(ResponseMode.QUERY);
+ request.setResponseType(ResponseType.CODE);
return request;
}
@@ -378,18 +463,6 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
}
- /**
- * Create a response mode and type context.
- *
- * @return the context.
- */
- private ResponseTypeAndModeContext createResponseTypeAndModeContext() {
- final ResponseTypeAndModeContext respCtx = new ResponseTypeAndModeContext();
- respCtx.setResponseMode(ResponseMode.QUERY);
- respCtx.setResponseType(ResponseType.CODE);
- return respCtx;
- }
-
/**
* Create an authentication response.
*
@@ -468,7 +541,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
@Nonnull protected ProfileRequestContext buildProfileRequestContext(@Nonnull final String flowId,
@Nonnull final boolean forceAuthn,
@Nonnull final boolean addC14Context) {
- return super.buildProfileRequestContext(flowId, forceAuthn, addC14Context);
+ return super.buildProfileRequestContext(flowId, forceAuthn, addC14Context);
}
@Test
@@ -505,6 +578,40 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
assertCurrentStateEquals("AuthRequest");
}
+ @Test
+ public void testFlowToAuthorizationRedirect_UsingRequestObject() throws Exception {
+ setFlowPath(FLOW);
+ setFlowModelResources(flowResources);
+ setSubflows(subflows);
+
+ final Map<String,String> mockProperties = Map.of(
+ "idp.service.clientinfo.failFast","false",
+ "idp.entityID", "http://idp.example.com/",
+ "idp.authn.oidc.rp.proxyIssuer",OP_ISSUER_ID_REQUESTOBJECT_TRUE,
+ "idp.oidc.rp.redirecturl.allowedOrigins", RP_ALLOWED_ORIGINS);
+
+ setMockProperties(mockProperties);
+
+ final MockWebServer mockOPServer = createSimpleServer();
+ // First is metadata exchange
+ mockOPServer.enqueue(new MockResponse().setResponseCode(200)
+ .setHeader("content-type", "application/json")
+ .setBody(GOOD_PROVIDER_CONFIGURATION_INFO_USE_REQUEST_OBJECT));
+
+ mockOPServer.start(9919);
+
+ final LocalAttributeMap<Object> inputMap = new LocalAttributeMap<Object>();
+ inputMap.put("calledAsSubflow", true);
+
+ final ProfileRequestContext prc = buildProfileRequestContext("authn/OIDCRelyingParty",false,true);
+
+ final FlowExecution flowExecution = getFlowExecutionFactory().createFlowExecution(getFlowDefinition());
+ flowExecution.getConversationScope().put("opensamlProfileRequestContext",prc);
+ updateFlowExecution(flowExecution);
+ flowExecution.start(inputMap, externalContext);
+ assertCurrentStateEquals("AuthRequest");
+ }
+
@Test
public void testFlowToAuthorizationRedirect_WithACRs() throws Exception {
setFlowPath(FLOW);
@@ -560,22 +667,22 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
idTokenSigValConfig.setSignatureTrustEngine(
new ExplicitKeySignedJWTTrustEngine(new CriterionCredentialResolver(),
new BasicJOSEObjectCredentialResolver()));
- securityConfig.setIdTokenJwtSignatureValidationConfig(idTokenSigValConfig);
+ securityConfig.setIdTokenJwtSignatureValidationConfiguration(idTokenSigValConfig);
final var userInfoTokenSigValConfig = new BasicSignatureValidationConfiguration<SignedJWT>();
userInfoTokenSigValConfig.setSignatureTrustEngine(
new ExplicitKeySignedJWTTrustEngine(new CriterionCredentialResolver(),
new BasicJOSEObjectCredentialResolver()));
- securityConfig.setUserInfoTokenJwtSignatureValidationConfig(userInfoTokenSigValConfig);
+ securityConfig.setUserInfoTokenJwtSignatureValidationConfiguration(userInfoTokenSigValConfig);
//The CEK resolver just resolves keys from the criteria set.
final var idTokenDecryptConfig = new BasicJWTDecryptionConfiguration();
idTokenDecryptConfig.setContentEncryptionKeyCredentialResolver(new CriterionCredentialResolver());
- securityConfig.setIdTokenJwtDecryptionConfig(idTokenDecryptConfig);
+ securityConfig.setIdTokenJwtDecryptionConfiguration(idTokenDecryptConfig);
final var userInfoDecryptConfig = new BasicJWTDecryptionConfiguration();
userInfoDecryptConfig.setContentEncryptionKeyCredentialResolver(new CriterionCredentialResolver());
- securityConfig.setUserInfoJwtDecryptionConfig(userInfoDecryptConfig);
+ securityConfig.setUserInfoJwtDecryptionConfiguration(userInfoDecryptConfig);
return securityConfig;
@@ -804,7 +911,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
sigValidation.setSignatureTrustEngine(new ExplicitKeySignedJWTTrustEngine(
new CriterionCredentialResolver(), new BasicJOSEObjectCredentialResolver()));
- secConfig.setIdTokenJwtSignatureValidationConfig(sigValidation);
+ secConfig.setIdTokenJwtSignatureValidationConfiguration(sigValidation);
final var idTokenDecryptConfig = new BasicJWTDecryptionConfiguration();
idTokenDecryptConfig.setContentEncryptionKeyCredentialResolver(new CriterionCredentialResolver());
@@ -831,8 +938,8 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
return List.of(resolveSingle(criteria));
}
});
- secConfig.setIdTokenJwtDecryptionConfig(idTokenDecryptConfig);
- secConfig.setUserInfoJwtDecryptionConfig(userInfoDecryptConfig);
+ secConfig.setIdTokenJwtDecryptionConfiguration(idTokenDecryptConfig);
+ secConfig.setUserInfoJwtDecryptionConfiguration(userInfoDecryptConfig);
//Signature config for userinfo token
final BasicSignatureValidationConfiguration<SignedJWT> sigValidationUserInfo =
@@ -859,7 +966,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
}
}, new BasicJOSEObjectCredentialResolver()));
- secConfig.setUserInfoTokenJwtSignatureValidationConfig(sigValidationUserInfo);
+ secConfig.setUserInfoTokenJwtSignatureValidationConfiguration(sigValidationUserInfo);
partyConfig.setSecurityConfiguration(secConfig);
@@ -930,7 +1037,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
sigValidation.setSignatureTrustEngine(new ExplicitKeySignedJWTTrustEngine(
new CriterionCredentialResolver(), new BasicJOSEObjectCredentialResolver()));
- secConfig.setIdTokenJwtSignatureValidationConfig(sigValidation);
+ secConfig.setIdTokenJwtSignatureValidationConfiguration(sigValidation);
final var idTokenDecryptConfig = new BasicJWTDecryptionConfiguration();
idTokenDecryptConfig.setKEKCredentialResolver(new CredentialResolver() {
@@ -954,7 +1061,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
}
});
- secConfig.setIdTokenJwtDecryptionConfig(idTokenDecryptConfig);
+ secConfig.setIdTokenJwtDecryptionConfiguration(idTokenDecryptConfig);
partyConfig.setSecurityConfiguration(secConfig);
@@ -1055,7 +1162,6 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
final MessageContext outMsgCtx = new MessageContext();
outMsgCtx.setMessage(createAuthenticationRequest());
outMsgCtx.addSubcontext(createPeerContext());
- outMsgCtx.addSubcontext(createResponseTypeAndModeContext());
nestPrc.setOutboundMessageContext(outMsgCtx);
outMsgCtx.getSubcontext(OIDCPeerEntityContext.class).addSubcontext(createOAuth2ClientContext(CLIENT_ID,null));
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeContextTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeTest.java
similarity index 61%
rename from idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeContextTest.java
rename to idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeTest.java
index 40ce278..5e226f3 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeContextTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PopulateResponseTypeAndModeTest.java
@@ -5,6 +5,7 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.ParentContextLookup;
import org.opensaml.profile.context.ProfileRequestContext;
import org.springframework.webflow.execution.Event;
import org.testng.annotations.BeforeMethod;
@@ -14,17 +15,17 @@ import com.nimbusds.oauth2.sdk.ResponseMode;
import com.nimbusds.oauth2.sdk.ResponseType;
import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
-/** Tests for the PopulateResponseTypeAndModeContext action.*/
-public class PopulateResponseTypeAndModeContextTest extends AbstractOIDCTest {
+/** Tests for the PopulateResponseTypeAndMode action.*/
+public class PopulateResponseTypeAndModeTest extends AbstractOIDCTest {
- private PopulateResponseTypeAndModeContext action;
+ private PopulateResponseTypeAndMode action;
private RelyingPartyContext rpc;
@@ -35,7 +36,7 @@ public class PopulateResponseTypeAndModeContextTest extends AbstractOIDCTest {
@BeforeMethod
public void setup() throws Exception {
super.setup();
- action = new PopulateResponseTypeAndModeContext();
+ action = new PopulateResponseTypeAndMode();
rpc = prc.getSubcontext(RelyingPartyContext.class, true);
oidcAuthzConfig = new OIDCAuthorizationConfiguration();
final RelyingPartyConfiguration rpConfig = new RelyingPartyConfiguration();
@@ -45,7 +46,9 @@ public class PopulateResponseTypeAndModeContextTest extends AbstractOIDCTest {
action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
new ChildContextLookup<>(AuthenticationContext.class)
- .compose(new WebflowRequestContextProfileRequestContextLookup())));
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+
+ action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
}
@Test
@@ -57,15 +60,13 @@ public class PopulateResponseTypeAndModeContextTest extends AbstractOIDCTest {
final Event event = action.execute(src);
assertNull(event);
- assertNotNull(prc.getOutboundMessageContext().getSubcontext(ResponseTypeAndModeContext.class));
- assertNotNull(prc.getOutboundMessageContext()
- .getSubcontext(ResponseTypeAndModeContext.class).getResponseMode());
- assertNotNull(prc.getOutboundMessageContext()
- .getSubcontext(ResponseTypeAndModeContext.class).getResponseType());
- assertEquals(ResponseMode.FORM_POST, prc.getOutboundMessageContext()
- .getSubcontext(ResponseTypeAndModeContext.class).getResponseMode());
- assertEquals(ResponseType.CODE, prc.getOutboundMessageContext()
- .getSubcontext(ResponseTypeAndModeContext.class).getResponseType());
+ assertNotNull(prc.getOutboundMessageContext().getMessage());
+ assertNotNull(((OIDCAuthenticationRequest)prc.getOutboundMessageContext().getMessage()).getResponseMode());
+ assertNotNull(((OIDCAuthenticationRequest)prc.getOutboundMessageContext().getMessage()).getResponseType());
+ assertEquals(ResponseMode.FORM_POST, (
+ (OIDCAuthenticationRequest)prc.getOutboundMessageContext().getMessage()).getResponseMode());
+ assertEquals(ResponseType.CODE, (
+ (OIDCAuthenticationRequest)prc.getOutboundMessageContext().getMessage()).getResponseType());
}
@Test
@@ -77,15 +78,13 @@ public class PopulateResponseTypeAndModeContextTest extends AbstractOIDCTest {
final Event event = action.execute(src);
assertNull(event);
- assertNotNull(prc.getOutboundMessageContext().getSubcontext(ResponseTypeAndModeContext.class));
- assertNotNull(prc.getOutboundMessageContext()
- .getSubcontext(ResponseTypeAndModeContext.class).getResponseMode());
- assertNotNull(prc.getOutboundMessageContext()
- .getSubcontext(ResponseTypeAndModeContext.class).getResponseType());
- assertEquals(ResponseMode.QUERY, prc.getOutboundMessageContext()
- .getSubcontext(ResponseTypeAndModeContext.class).getResponseMode());
- assertEquals(ResponseType.CODE, prc.getOutboundMessageContext()
- .getSubcontext(ResponseTypeAndModeContext.class).getResponseType());
+ assertNotNull((prc.getOutboundMessageContext().getMessage()));
+ assertNotNull(((OIDCAuthenticationRequest)prc.getOutboundMessageContext().getMessage()).getResponseMode());
+ assertNotNull(((OIDCAuthenticationRequest)prc.getOutboundMessageContext().getMessage()).getResponseType());
+ assertEquals(ResponseMode.QUERY,
+ ((OIDCAuthenticationRequest)prc.getOutboundMessageContext().getMessage()).getResponseMode());
+ assertEquals(ResponseType.CODE,
+ ((OIDCAuthenticationRequest)prc.getOutboundMessageContext().getMessage()).getResponseType());
}
@Test
diff --git a/idp-oidc-rp-impl/src/test/resources/conf/test-relying-party-system.xml b/idp-oidc-rp-impl/src/test/resources/conf/test-relying-party-system.xml
index ad811bc..15518de 100644
--- a/idp-oidc-rp-impl/src/test/resources/conf/test-relying-party-system.xml
+++ b/idp-oidc-rp-impl/src/test/resources/conf/test-relying-party-system.xml
@@ -49,24 +49,16 @@
<!-- Container for any overrides you want to add. -->
<util:list id="shibboleth.RelyingPartyOverrides">
-
+ <!-- This override is used in the OIDCRPFlowTest#testFlowToAuthorizationRedirect_UsingRequestObject test -->
+ <bean id="TestRequestObject" parent="RelyingPartyByName" c:relyingPartyIds="https://localhost:9919">
+ <property name="profileConfigurations">
+ <list>
+ <bean parent="OIDC.SSO" p:useRequestObject="true"/>
+ </list>
+ </property>
+ </bean>
</util:list>
-
- <!--
- Map clients to appropriate client authentication - only supports client_secret_basic and client_secret_post
- -->
-
- <!-- <util:map id="shibboleth.authn.oidc.rp.ClientIdToClientAuthenticationMap">
- <entry key="mytestclient">
- <bean parent="shibboleth.authn.oidc.rp.ClientAuthenticationDetails" c:clientSecret="mytestsecret"
- c:tokenEndpointAuthMethod="client_secret_basic" />
- </entry>
- <entry key="demo_rp">
- <bean parent="shibboleth.authn.oidc.rp.ClientAuthenticationDetails" c:clientSecret="mytestsecret"
- c:tokenEndpointAuthMethod="client_secret_basic" />
- </entry>
- </util:map> -->
</beans>
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list