[java-idp-plugin-oidc-rp] branch main updated: Add more functionality
Phil Smart
philip.smart at jisc.ac.uk
Thu Feb 3 11:50:28 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=13839d1415072f63c70a68a99571853b259b2c1d
The following commit(s) were added to refs/heads/main by this push:
new 13839d1 Add more functionality
13839d1 is described below
commit 13839d1415072f63c70a68a99571853b259b2c1d
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Feb 3 11:50:23 2022 +0000
Add more functionality
- Add validation for access_token
- Add id_token validation. Signature and encryption currently not dealt
with, claims are checked. ACR and nonce checks also missing.
- Move some classes into commons and update references
---
.../oidc/rp/AbstractOIDCAuthenticationAction.java | 149 ---------------
.../oidc/rp/context/TokenResponseContext.java | 23 +++
.../context/OIDCClientMetadataContext.java | 56 ------
.../context/OIDCProviderMetadataContext.java | 47 -----
.../impl/AbstractRequestEncoderFunction.java | 14 +-
.../encoding/impl/DefaultTokenRequestEncoder.java | 4 +
.../AbstractOIDCAuthenticationResponseAction.java | 14 +-
.../plugin/authn/oidc/rp/impl/AddAuthzRequest.java | 12 +-
.../oidc/rp/impl/DefaultIDTokenLookupStrategy.java | 50 +++++
.../rp/impl/DefaultResponseTypeLookupFunction.java | 6 +-
...rToken.java => ExchangeCodeForAccessToken.java} | 12 +-
.../oidc/rp/impl/ExtractIDTokenFromResponse.java | 66 +++++--
...OutboundAuthorizationRequestMessageContext.java | 21 +--
.../rp/impl/InitializeRelyingPartyContext.java | 6 +-
.../impl/ManyValuesIntegerComparisonPredicate.java | 34 +---
...viderMetadataFromOuboundPeerLookupStrategy.java | 32 ++++
.../impl/TokenResponseIDTokenLookupStrategy.java | 11 +-
.../rp/impl/ValidateOAuthAccessTokenResponse.java | 109 +++++++++++
.../authn/oidc/rp/impl/ValidateTokenClaims.java | 43 +++--
.../DefaultClientIDForIssuerLookupFunction.java | 2 +-
.../impl/OIDCClientMetadataLookupHandler.java | 8 +-
.../impl/OIDCProviderMetadataLookupHandler.java | 11 +-
.../oidc-relying-party-authn-beans.xml | 206 +++++++++++++--------
.../oidc-relying-party-authn-flow.xml | 19 +-
.../impl/DefaultTokenResponseDecoderTest.java | 2 +-
.../authn/oidc/rp/impl/AbstractOIDCTest.java | 14 +-
.../oidc/rp/impl/ExchangeCodeForTokenTest.java | 8 +-
.../rp/impl/ExtractIDTokenFromResponseTest.java | 71 +++++++
.../plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java | 114 ++++++++++--
.../TokenResponseIDTokenLookupStrategyTest.java | 74 ++++++++
30 files changed, 766 insertions(+), 472 deletions(-)
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/AbstractOIDCAuthenticationAction.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/AbstractOIDCAuthenticationAction.java
deleted file mode 100644
index 1a964e4..0000000
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/AbstractOIDCAuthenticationAction.java
+++ /dev/null
@@ -1,149 +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;
-
-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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-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.OpenIDConnectContext;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/**
- * <p>A base class for OIDC authentication related actions.</p>
- *
- * <p>In addition to the work performed by {@link AbstractAuthenticationAction}, this action also looks up
- * and makes available the {@link OpenIDConnectContext}.</p>
- *
- * <p>OIDC authentication action implementations should override the
- * {@link #doExecute(ProfileRequestContext, AuthenticationContext, OpenIDConnectContext)}
- * method.</p>
- *
- * @event {@link AuthnEventIds#INVALID_AUTHN_CTX}
- * @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class) != null</pre>
- * @post <pre>AuthenticationContext.getSubcontext(OpenIDConnectContext.class) != null</pre>
- */
-public abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAction {
-
- /** Class logger. */
- @Nonnull @NotEmpty private final Logger log = LoggerFactory.getLogger(AbstractOIDCAuthenticationAction.class);
-
- /** Lookup strategy to locate the OIDC authentication context. */
- @Nonnull private Function<ProfileRequestContext,OpenIDConnectContext> oidcContextLookupStrategy;
-
- /** The OIDC authentication Context.*/
- @Nullable private OpenIDConnectContext oidcContext;
-
-
- /** Constructor.*/
- protected AbstractOIDCAuthenticationAction() {
- //prc -> ac -> oidc_context
- oidcContextLookupStrategy = new ChildContextLookup<>(OpenIDConnectContext.class).
- compose(new ChildContextLookup<>(AuthenticationContext.class));
- }
-
-
- /**
- * Set OIDC authentication context lookup strategy to use.
- *
- * @param strategy lookup strategy
- */
- public void setOIDCContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext,OpenIDConnectContext> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
-
- oidcContextLookupStrategy = Constraint.isNotNull(strategy, "OIDCContextLookup strategy cannot be null");
- }
-
- /** {@inheritDoc} */
- @Override
- protected final boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final AuthenticationContext authenticationContext) {
-
- if (!super.doPreExecute(profileRequestContext, authenticationContext)) {
- return false;
- }
-
- oidcContext = oidcContextLookupStrategy.apply(profileRequestContext);
- if (oidcContext == null) {
- log.warn("{} No OIDC context returned by lookup strategy",getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX);
- return false;
-
- }
-
- return doPreExecute(profileRequestContext, authenticationContext, oidcContext);
- }
-
- /**
- * Delegates to {@link #doExecute(ProfileRequestContext, AuthenticationContext,
- * OpenIDConnectContext)} to perform the actual authentication. Implementations can not
- * override this method.
- *
- * @param profileRequestContext the current IdP profile request context
- * @param authenticationContext the current authentication context
- */
- @Override
- protected final void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final AuthenticationContext authenticationContext) {
- doExecute(profileRequestContext,authenticationContext,oidcContext);
- }
-
- /**
- * Performs this authentication action's pre-execute step. Default implementation just returns true.
- *
- * @param profileRequestContext the current IdP profile request context
- * @param authenticationContext the current authentication context
- * @param context the OIDC authentication context
- *
- * @return true iff execution should continue
- */
- protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final AuthenticationContext authenticationContext,
- @Nonnull final OpenIDConnectContext context) {
- return true;
- }
-
- /**
- * Performs this OIDC authentication action using the supplied OIDC context. Implementations
- * should override this method.
- *
- * @param profileRequestContext the current IdP profile request context
- * @param authenticationContext the current authentication context
- * @param context the OIDC authentication context
- */
- protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final AuthenticationContext authenticationContext,
- @Nonnull final OpenIDConnectContext context) {
-
- }
-
-}
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
index 56a78d8..104db77 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
@@ -23,12 +23,17 @@ import javax.annotation.Nullable;
import org.opensaml.messaging.context.BaseContext;
+import com.nimbusds.jwt.JWT;
+
/** A context to hold an OIDC token request response.*/
public class TokenResponseContext extends BaseContext {
/** The raw token response as a map.*/
@Nullable private Map<String, Object> rawTokenResponse;
+ /** The id_token, should match that in the rawTokenResponse if one exists.*/
+ @Nullable private JWT idToken;
+
/**
* Set the raw token response as a map.
*
@@ -46,5 +51,23 @@ public class TokenResponseContext extends BaseContext {
@Nullable public Map<String, Object> getRawTokenResponse() {
return rawTokenResponse;
}
+
+ /**
+ * Set the id_token.
+ *
+ * @param token the id_token.
+ */
+ public void setIdToken(@Nullable final JWT token) {
+ idToken = token;
+ }
+
+ /**
+ * Get the id_token.
+ *
+ * @return the id_token.
+ */
+ @Nullable public JWT getIdToken() {
+ return idToken;
+ }
}
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCClientMetadataContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCClientMetadataContext.java
deleted file mode 100644
index f0b9f5b..0000000
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCClientMetadataContext.java
+++ /dev/null
@@ -1,56 +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.messaging.context;
-
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.BaseContext;
-
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-
-/**
- * Subcontext carrying information on metadata of the relying party. This
- * context appears as a subcontext of the
- * {@link org.opensaml.messaging.context.MessageContext} that carries the actual
- * OIDC request message, in such cases the metadata carried herein applies to
- * the issuer of that message.
- */
-public class OIDCClientMetadataContext extends BaseContext {
-
- /** The client information. */
- @Nullable private OIDCClientInformation clientInformation;
-
- /**
- * Set the client information.
- *
- * @return The client information.
- */
- @Nullable
- public OIDCClientInformation getClientInformation() {
- return clientInformation;
- }
-
- /**
- * Set the client information.
- *
- * @param information The client information.
- */
- public void setClientInformation(@Nullable final OIDCClientInformation information) {
- clientInformation = information;
- }
-}
\ No newline at end of file
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCProviderMetadataContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCProviderMetadataContext.java
deleted file mode 100644
index 849edac..0000000
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCProviderMetadataContext.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
-
-import org.opensaml.messaging.context.BaseContext;
-
-import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
-
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/**
- * Subcontext carrying information on metadata of the openid provider. This
- * context appears as a subcontext of the
- * {@link org.opensaml.messaging.context.MessageContext} that carries the actual
- * OIDC request message, in such cases the metadata carried herein applies to
- * the issuer of that message.
- */
- at ThreadSafe
-public class OIDCProviderMetadataContext extends BaseContext {
-
- /** The client information. */
- @Nonnull private final OIDCProviderMetadata providerInformation;
-
- /**
- *
- * Constructor.
- *
- * @param metadata the provider configuration information.
- */
- //TODO not sure this is needed in constructor, make inline with other contexts.
- public OIDCProviderMetadataContext(@Nonnull final OIDCProviderMetadata metadata) {
- providerInformation = Constraint.isNotNull(metadata, "OIDC Provider Metadata can not be null");
- }
-
- /**
- * Set the client information.
- *
- * @return The client information.
- */
- @Nullable
- public OIDCProviderMetadata getProviderInformation() {
- return providerInformation;
- }
-
-}
\ No newline at end of file
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/AbstractRequestEncoderFunction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/AbstractRequestEncoderFunction.java
index bf4baa5..30fd576 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/AbstractRequestEncoderFunction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/AbstractRequestEncoderFunction.java
@@ -33,8 +33,8 @@ import org.slf4j.LoggerFactory;
import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
+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.AbstractInitializableComponent;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -52,7 +52,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
@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,OIDCClientMetadataContext> clientMetadataLookupStrategy;
+ @Nonnull private Function<ProfileRequestContext,OIDCMetadataContext> clientMetadataLookupStrategy;
/** OIDC authentication response from downstream OP. */
@Nullable private AuthenticationSuccessResponse authnResponse;
@@ -61,7 +61,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
@Nullable private OIDCAuthenticationRequest authnRequest;
/** OIDC client Metadata context. */
- @Nullable private OIDCClientMetadataContext clientMetadataContext;
+ @Nullable private OIDCMetadataContext clientMetadataContext;
/** OIDC Metadata context. */
@Nullable private OIDCProviderMetadataContext providerMetadataContext;
@@ -72,7 +72,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
new OutboundMessageContextLookup()));
- clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCClientMetadataContext.class).compose(
+ clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
new OutboundMessageContextLookup());
}
@@ -95,7 +95,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
* @param strategy the strategy.
*/
public void setClientMetadataLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCClientMetadataContext> strategy) {
+ @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
clientMetadataLookupStrategy = Constraint.isNotNull(strategy,"Client metadata lookup strategy can not be null");
@@ -124,7 +124,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
*
* @return The client metadata context.
*/
- @Nullable public OIDCClientMetadataContext getClientMetadataContext() {
+ @Nullable public OIDCMetadataContext getClientMetadataContext() {
return clientMetadataContext;
}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/DefaultTokenRequestEncoder.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/DefaultTokenRequestEncoder.java
index 797306f..3da272e 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/DefaultTokenRequestEncoder.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/DefaultTokenRequestEncoder.java
@@ -52,6 +52,10 @@ public class DefaultTokenRequestEncoder extends AbstractRequestEncoderFunction {
@Nullable public HttpUriRequest doApply(@Nonnull final ProfileRequestContext profileRequestContext) {
try {
+ if (getClientMetadataContext().getClientInformation() == null) {
+ log.warn("No client information present to base token request off");
+ return null;
+ }
// Mandate HTTPS, so construct the URL from that.
final URI uri = new URIBuilder().setScheme(HTTPS)
.setHost(getProviderMetadataContext()
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 d7b4d9d..83d8dc8 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,8 +37,8 @@ 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.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
+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;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -61,7 +61,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
@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,OIDCClientMetadataContext> clientMetadataLookupStrategy;
+ @Nonnull private Function<ProfileRequestContext,OIDCMetadataContext> clientMetadataLookupStrategy;
/** OIDC authentication response from downstream OP. */
@Nullable private AuthenticationSuccessResponse authnResponse;
@@ -70,7 +70,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
@Nullable private OIDCAuthenticationRequest authnRequest;
/** OIDC client Metadata context. */
- @Nullable private OIDCClientMetadataContext clientMetadataContext;
+ @Nullable private OIDCMetadataContext clientMetadataContext;
/** OIDC Metadata context. */
@Nullable private OIDCProviderMetadataContext providerMetadataContext;
@@ -81,7 +81,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
new OutboundMessageContextLookup()));
- clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCClientMetadataContext.class).compose(
+ clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
new OutboundMessageContextLookup());
}
@@ -104,7 +104,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
* @param strategy the strategy.
*/
public void setClientMetadataLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCClientMetadataContext> strategy) {
+ @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
clientMetadataLookupStrategy = Constraint.isNotNull(strategy,"Client metadata lookup strategy can not be null");
@@ -133,7 +133,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
*
* @return The client metadata context.
*/
- @Nullable public OIDCClientMetadataContext getClientMetadataContext() {
+ @Nullable public OIDCMetadataContext getClientMetadataContext() {
return clientMetadataContext;
}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthzRequest.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthzRequest.java
index 871c634..8049654 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthzRequest.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthzRequest.java
@@ -37,10 +37,10 @@ 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.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+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;
@@ -72,7 +72,7 @@ public class AddAuthzRequest extends AbstractAuthenticationAction {
@Nullable private OIDCAuthorizationConfiguration profileConfiguration;
/** The metadata belonging to the client registered with the current OpenID Provider.*/
- @Nullable private OIDCClientMetadataContext clientMetadata;
+ @Nullable private OIDCMetadataContext clientMetadata;
/** The metadata belonging to the OpenID Provider.*/
@Nullable private OIDCProviderMetadataContext providerMetadata;
@@ -84,7 +84,7 @@ public class AddAuthzRequest extends AbstractAuthenticationAction {
@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,OIDCClientMetadataContext> clientMetadataLookupStrategy;
+ @Nonnull private Function<ProfileRequestContext,OIDCMetadataContext> clientMetadataLookupStrategy;
/** Lookup strategy to locate the response_mode and response_type context.*/
@Nonnull private Function<ProfileRequestContext,ResponseTypeAndModeContext> responseTypeAndModeLookupStrategy;
@@ -98,7 +98,7 @@ public class AddAuthzRequest extends AbstractAuthenticationAction {
new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
new InboundMessageContextLookup()));
- clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCClientMetadataContext.class).compose(
+ clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
new InboundMessageContextLookup());
responseTypeAndModeLookupStrategy = new ChildContextLookup<>(ResponseTypeAndModeContext.class).compose(
@@ -124,7 +124,7 @@ public class AddAuthzRequest extends AbstractAuthenticationAction {
* @param strategy the strategy.
*/
public void setClientMetadataLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCClientMetadataContext> strategy) {
+ @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
clientMetadataLookupStrategy = Constraint.isNotNull(strategy,"Client metadata lookup strategy can not be null");
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultIDTokenLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultIDTokenLookupStrategy.java
new file mode 100644
index 0000000..ddad58f
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultIDTokenLookupStrategy.java
@@ -0,0 +1,50 @@
+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.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+
+import com.nimbusds.jwt.JWT;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** Function that extracts the id_token from the {@link TokenResponseContext}.*/
+public class DefaultIDTokenLookupStrategy implements Function<ProfileRequestContext, JWT> {
+
+ /** Strategy used to locate the TokenResponseContext to extract the id_token from.*/
+ @Nonnull private Function<ProfileRequestContext, TokenResponseContext> tokenResponseContextLookupStrategy;
+
+ /** Constructor.*/
+ public DefaultIDTokenLookupStrategy() {
+ tokenResponseContextLookupStrategy =
+ new ChildContextLookup<>(TokenResponseContext.class, true).compose(
+ new InboundMessageContextLookup());
+ }
+
+ /**
+ * Set the strategy used to look up a {@link TokenResponseContext}.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setTokenResponseContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, TokenResponseContext> strategy) {
+ tokenResponseContextLookupStrategy = Constraint.isNotNull(strategy,
+ "TokenResponseContext lookup strategy cannot be null");
+ }
+
+ @Override
+ @Nullable public JWT apply(@Nonnull final ProfileRequestContext prc) {
+ final TokenResponseContext tokenContext = tokenResponseContextLookupStrategy.apply(prc);
+ if (tokenContext == null) {
+ return null;
+ }
+ return tokenContext.getIdToken();
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultResponseTypeLookupFunction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultResponseTypeLookupFunction.java
index e08eacf..f2f5eaf 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultResponseTypeLookupFunction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultResponseTypeLookupFunction.java
@@ -29,7 +29,7 @@ import org.slf4j.LoggerFactory;
import com.nimbusds.oauth2.sdk.ResponseType;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
/**
* A lookup function that returns a response_type from the 'first' described in a client's metadata.
@@ -52,8 +52,8 @@ public class DefaultResponseTypeLookupFunction implements Function<ProfileReques
}
final MessageContext inboundMessageCtx = profileRequestContext.getInboundMessageContext();
- final OIDCClientMetadataContext clientMetadataCtx =
- inboundMessageCtx.getSubcontext(OIDCClientMetadataContext.class);
+ final OIDCMetadataContext clientMetadataCtx =
+ inboundMessageCtx.getSubcontext(OIDCMetadataContext.class);
if (clientMetadataCtx != null &&
clientMetadataCtx.getClientInformation() != null &&
clientMetadataCtx.getClientInformation().getOIDCMetadata() != null &&
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForToken.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForAccessToken.java
similarity index 95%
rename from idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForToken.java
rename to idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForAccessToken.java
index 2fc953d..b71ce90 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForToken.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForAccessToken.java
@@ -42,8 +42,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * Action to exchange the authorization code in the authentication response for a token response which
- * contains an id_token. Once obtained, adds the token to the {@link TokenResponseContext}.
+ * Action to exchange the authorization code in the authentication response for an OAuth access token which
+ * contains an OIDC id_token. Once obtained, adds the token to the {@link TokenResponseContext}.
*
* FIXME: these conditions
*
@@ -54,10 +54,10 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
* AuthenticationContext.getSubcontect(DuoOIDCAuthenticationContext.class,false)!=null</pre>
* @post Add the Duo authentication token to the context.
*/
-public class ExchangeCodeForToken extends AbstractHttpOIDCAuthenticationAction {
+public class ExchangeCodeForAccessToken extends AbstractHttpOIDCAuthenticationAction {
/** Class logger.*/
- @Nonnull private final Logger log = LoggerFactory.getLogger(ExchangeCodeForToken.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(ExchangeCodeForAccessToken.class);
/** The message encoder to use encode the token request into a HttpRequest.*/
@NonnullAfterInit private Function<ProfileRequestContext, HttpUriRequest> tokenRequestEncoderStrategy;
@@ -70,7 +70,7 @@ public class ExchangeCodeForToken extends AbstractHttpOIDCAuthenticationAction {
tokenResponseContextLookupStrategy;
/** Constructor.*/
- public ExchangeCodeForToken() {
+ public ExchangeCodeForAccessToken() {
tokenResponseContextLookupStrategy =
new ChildContextLookup<>(TokenResponseContext.class, true).compose(
new InboundMessageContextLookup());
@@ -114,7 +114,7 @@ public class ExchangeCodeForToken extends AbstractHttpOIDCAuthenticationAction {
tokenRequestEncoderStrategy = Constraint.isNotNull(strategy, "Token encoder strategy can not be null");
}
-
+
@Override protected void doExecute(@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/ExtractIDTokenFromResponse.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponse.java
index c286ec7..d76f4d8 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponse.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponse.java
@@ -22,8 +22,11 @@ import java.util.function.Function;
import javax.annotation.Nonnull;
+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.InboundMessageContextLookup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +34,11 @@ import com.nimbusds.jose.JOSEObject;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.PlainObject;
+import com.nimbusds.jwt.EncryptedJWT;
+import com.nimbusds.jwt.PlainJWT;
+import com.nimbusds.jwt.SignedJWT;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.oidc.profile.core.OidcEventIds;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
@@ -39,7 +46,7 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
-/** Action that extracts and id_token from the inbound message context and sets it onto a TODO context.*/
+/** Action that extracts an id_token from the inbound message context and sets it onto a TODO context.*/
public class ExtractIDTokenFromResponse extends AbstractProfileAction {
/** Class logger. */
@@ -48,6 +55,33 @@ public class ExtractIDTokenFromResponse extends AbstractProfileAction {
/** Function that looks up a raw id_token value as a base64 encoded string.*/
@NonnullAfterInit private Function<ProfileRequestContext, String> rawIdTokenLookupStrategy;
+ /** The token response context to add the decoded id_token too.*/
+ @NonnullAfterInit private TokenResponseContext responseCtx;
+
+ /** Strategy used to look up the {@link TokenResponseContext} to set the parameters for. */
+ @Nonnull private Function<ProfileRequestContext, TokenResponseContext>
+ tokenResponseContextLookupStrategy;
+
+ /** Constructor.*/
+ public ExtractIDTokenFromResponse() {
+ tokenResponseContextLookupStrategy =
+ new ChildContextLookup<>(TokenResponseContext.class).compose(
+ new InboundMessageContextLookup());
+ }
+
+ /**
+ * Set the strategy used to look up a {@link TokenResponseContext}.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setTokenResponseContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, TokenResponseContext> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ tokenResponseContextLookupStrategy = Constraint.isNotNull(strategy,
+ "TokenResponseContext lookup strategy cannot be null");
+ }
+
@Override
protected void doInitialize() throws ComponentInitializationException {
super.doInitialize();
@@ -56,7 +90,19 @@ public class ExtractIDTokenFromResponse extends AbstractProfileAction {
throw new ComponentInitializationException("RawIdTokenLookupStrategy cannot be null");
}
}
-
+
+ @Override protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ responseCtx = tokenResponseContextLookupStrategy.apply(profileRequestContext);
+ if (responseCtx == null) {
+ log.debug("{} No TokenResponseContext returned by lookup strategy", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+ return false;
+ }
+ return true;
+ }
+
+
/**
* Set the strategy used to lookup a base64 encoded JWT from the profile request context.
*
@@ -69,11 +115,6 @@ public class ExtractIDTokenFromResponse extends AbstractProfileAction {
rawIdTokenLookupStrategy = Constraint.isNotNull(strategy,"Raw id_token lookup strategy can not be null");
}
- @Override protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-
- return true;
- }
-
@Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final String rawIdTokenValue = rawIdTokenLookupStrategy.apply(profileRequestContext);
@@ -82,23 +123,22 @@ public class ExtractIDTokenFromResponse extends AbstractProfileAction {
ActionSupport.buildEvent(profileRequestContext,OidcEventIds.INVALID_ID_TOKEN);
return;
}
- log.trace("{} Base64 encoded id_token is '{}'",getLogPrefix(), rawIdTokenValue);
+ log.trace("{} (Assumed) Base64 encoded id_token is '{}'",getLogPrefix(), rawIdTokenValue);
try {
final JOSEObject joseObject = JOSEObject.parse(rawIdTokenValue);
log.trace("{} Parsed JOSE Object '{}'",getLogPrefix(), joseObject);
if (joseObject instanceof PlainObject) {
- final PlainObject plainObject = (PlainObject)joseObject;
+ responseCtx.setIdToken(PlainJWT.parse(rawIdTokenValue));
} else if (joseObject instanceof JWSObject) {
- final JWSObject jwsObject = (JWSObject)joseObject;
+ responseCtx.setIdToken(SignedJWT.parse(rawIdTokenValue));
} else if (joseObject instanceof JWEObject) {
- final JWEObject jweObject = (JWEObject)joseObject;
-
+ responseCtx.setIdToken(EncryptedJWT.parse(rawIdTokenValue));
}
} catch (final ParseException e) {
- log.warn("{}: Unable to parse id_token",getLogPrefix(), e);
+ log.warn("{} Unable to parse id_token",getLogPrefix(), e);
ActionSupport.buildEvent(profileRequestContext,OidcEventIds.INVALID_ID_TOKEN);
return;
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOutboundAuthorizationRequestMessageContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOutboundAuthorizationRequestMessageContext.java
index 0141ca1..692d844 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOutboundAuthorizationRequestMessageContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOutboundAuthorizationRequestMessageContext.java
@@ -33,11 +33,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -51,10 +51,10 @@ public class InitializeOutboundAuthorizationRequestMessageContext extends Abstra
/** The {@link OIDCPeerEntityContext} to base the outbound context on. */
@Nullable private OIDCPeerEntityContext peerEntityCtx;
- /** Strategy function to lookup the {@link OIDCClientMetadataContext} that represents this client during
+ /** Strategy function to lookup the {@link OIDCMetadataContext} that represents this client during
* communication with the given OIDC peer. */
@Nonnull
- private Function<ProfileRequestContext, OIDCClientMetadataContext> oidcClientMetadataCtxLookupStrategy;
+ private Function<ProfileRequestContext, OIDCMetadataContext> oidcClientMetadataCtxLookupStrategy;
/**
* Strategy used to locate the {@link RelyingPartyContext} associated with a given {@link ProfileRequestContext}.
@@ -66,7 +66,7 @@ public class InitializeOutboundAuthorizationRequestMessageContext extends Abstra
* Constructor.
*/
public InitializeOutboundAuthorizationRequestMessageContext() {
- oidcClientMetadataCtxLookupStrategy = new ChildContextLookup<>(OIDCClientMetadataContext.class).compose(
+ oidcClientMetadataCtxLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
new InboundMessageContextLookup());
relyingPartyCtxLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
}
@@ -78,7 +78,7 @@ public class InitializeOutboundAuthorizationRequestMessageContext extends Abstra
* @param strgy What to set.
*/
public void setOIDCClientMetadataContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCClientMetadataContext> strgy) {
+ @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strgy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
oidcClientMetadataCtxLookupStrategy = Constraint.isNotNull(strgy, "Injected Metadata Strategy cannot be null");
@@ -141,16 +141,15 @@ public class InitializeOutboundAuthorizationRequestMessageContext extends Abstra
if (inboundProviderMetadata != null) {
// Pass a reference here? we do not need to mutate the metadata
- final OIDCProviderMetadataContext outMetadata =
- new OIDCProviderMetadataContext(inboundProviderMetadata.getProviderInformation());
-
+ final OIDCProviderMetadataContext outMetadata = new OIDCProviderMetadataContext();
+ outMetadata.setProviderInformation(inboundProviderMetadata.getProviderInformation());
outboundPeerContext.addSubcontext(outMetadata);
}
- final OIDCClientMetadataContext inboundClientMetadata =
+ final OIDCMetadataContext inboundClientMetadata =
oidcClientMetadataCtxLookupStrategy.apply(profileRequestContext);
- final OIDCClientMetadataContext outboundClientMetadata = new OIDCClientMetadataContext();
+ final OIDCMetadataContext outboundClientMetadata = new OIDCMetadataContext();
outboundClientMetadata.setClientInformation(inboundClientMetadata.getClientInformation());
msgCtx.addSubcontext(outboundClientMetadata);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeRelyingPartyContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeRelyingPartyContext.java
index ac3bc54..4d1be9d 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeRelyingPartyContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeRelyingPartyContext.java
@@ -32,11 +32,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -58,7 +58,7 @@ public class InitializeRelyingPartyContext extends AbstractProfileAction {
/** Strategy that will return or create a {@link RelyingPartyContext}. */
@Nonnull private Function<ProfileRequestContext, RelyingPartyContext> relyingPartyContextCreationStrategy;
- /** Strategy that will return {@link OIDCClientMetadataContext}. */
+ /** Strategy that will return {@link OIDCMetadataContext}. */
@Nonnull
private Function<ProfileRequestContext, OIDCProviderMetadataContext> oidcProviderMetadataContextLookupStrategy;
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ManyValuesIntegerComparisonPredicate.java
similarity index 50%
copy from idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
copy to idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ManyValuesIntegerComparisonPredicate.java
index 56a78d8..eff2379 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ManyValuesIntegerComparisonPredicate.java
@@ -15,36 +15,16 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.authn.oidc.rp.context;
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
-import java.util.Map;
+import java.util.function.IntPredicate;
-import javax.annotation.Nullable;
+/** Predicate that returns true if the test integer is greater than 1.*/
+public class ManyValuesIntegerComparisonPredicate implements IntPredicate {
-import org.opensaml.messaging.context.BaseContext;
-
-/** A context to hold an OIDC token request response.*/
-public class TokenResponseContext extends BaseContext {
-
- /** The raw token response as a map.*/
- @Nullable private Map<String, Object> rawTokenResponse;
-
- /**
- * Set the raw token response as a map.
- *
- * @param rawResponse the raw response.
- */
- public void setRawTokenResponse(@Nullable final Map<String, Object> rawResponse) {
- rawTokenResponse = rawResponse;
- }
-
- /**
- * Get the raw token response map.
- *
- * @return the raw response map.
- */
- @Nullable public Map<String, Object> getRawTokenResponse() {
- return rawTokenResponse;
+ @Override
+ public boolean test(final int value) {
+ return value > 1;
}
}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCProviderMetadataFromOuboundPeerLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCProviderMetadataFromOuboundPeerLookupStrategy.java
new file mode 100644
index 0000000..85c0812
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCProviderMetadataFromOuboundPeerLookupStrategy.java
@@ -0,0 +1,32 @@
+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.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
+
+/**
+ * Lookup function to extract the {@link OIDCProviderMetadataContext} from the {@link OIDCPeerEntityContext} in the
+ * outbound message.
+ */
+public class OIDCProviderMetadataFromOuboundPeerLookupStrategy
+ implements Function<ProfileRequestContext, OIDCProviderMetadataContext>{
+
+ @Override
+ @Nullable public OIDCProviderMetadataContext apply(@Nonnull final ProfileRequestContext prc) {
+ if (prc.getOutboundMessageContext() == null) {
+ return null;
+ }
+ if (prc.getOutboundMessageContext().getSubcontext(OIDCPeerEntityContext.class) == null) {
+ return null;
+ }
+ return prc.getOutboundMessageContext()
+ .getSubcontext(OIDCPeerEntityContext.class).getSubcontext(OIDCProviderMetadataContext.class);
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategy.java
index 5edd244..49e7b63 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategy.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategy.java
@@ -24,21 +24,28 @@ import javax.annotation.Nullable;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
-/** Return the base64 encoded id_token from the TokenResponseContext, or null if not found.*/
+/** Return the raw base64 encoded id_token from the TokenResponseContext, or null if not found.*/
public class TokenResponseIDTokenLookupStrategy implements Function<ProfileRequestContext, String> {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(TokenResponseIDTokenLookupStrategy.class);
@Override
@Nullable public String apply(@Nonnull final ProfileRequestContext profileRequestContext) {
final MessageContext inbound = profileRequestContext.getInboundMessageContext();
if (inbound == null) {
+ log.debug("Inbound message context was null, no id_token found");
return null;
}
final TokenResponseContext tokenResponseContext = inbound.getSubcontext(TokenResponseContext.class);
if (tokenResponseContext == null) {
+ log.debug("Token response context was null, no id_token found");
return null;
}
if (tokenResponseContext.getRawTokenResponse() != null) {
@@ -46,7 +53,9 @@ public class TokenResponseIDTokenLookupStrategy implements Function<ProfileReque
if (idTokenObject instanceof String) {
return (String) idTokenObject;
}
+ log.debug("Token response was not a string, no id_token found");
}
+ log.debug("Raw token response was null, no id_token found");
return null;
}
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
new file mode 100644
index 0000000..f442388
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateOAuthAccessTokenResponse.java
@@ -0,0 +1,109 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import java.util.Map;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+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.InboundMessageContextLookup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+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 {
+
+ /** Class logger. */
+ @Nonnull @NotEmpty private final Logger log = LoggerFactory.getLogger(ValidateOAuthAccessTokenResponse.class);
+
+ /** Strategy used to look up the {@link TokenResponseContext} to validate. */
+ @Nonnull private Function<ProfileRequestContext, TokenResponseContext>
+ tokenResponseContextLookupStrategy;
+
+ /** Constructor.*/
+ public ValidateOAuthAccessTokenResponse() {
+ tokenResponseContextLookupStrategy =
+ new ChildContextLookup<>(TokenResponseContext.class, true).compose(
+ new InboundMessageContextLookup());
+ }
+
+ /**
+ * Set the strategy used to look up a {@link TokenResponseContext}.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setTokenResponseContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, TokenResponseContext> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ tokenResponseContextLookupStrategy = Constraint.isNotNull(strategy,
+ "TokenResponseContext lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+ final TokenResponseContext responseCtx = tokenResponseContextLookupStrategy.apply(profileRequestContext);
+ if (responseCtx == null) {
+ log.debug("{} No TokenResponseContext returned by lookup strategy", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+ return;
+ }
+ final Map<String, Object> rawTokenResponse = responseCtx.getRawTokenResponse();
+ if (rawTokenResponse == null) {
+ log.debug("{} No access token response found, response invalid", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+ return;
+ }
+ // Look for an error response. This may never get here depending on the upflow response decoder used.
+ if (rawTokenResponse.containsKey("error")) {
+ log.debug("{} Error response found instead of access token, error is '{}'", getLogPrefix(),
+ rawTokenResponse.get("error"));
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+ return;
+ }
+ // Otherwise check is valid success response
+ if (!rawTokenResponse.containsKey("access_token")) {
+ log.warn("{} Access token response is invalid, no access_token found", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+ return;
+ }
+ if (!rawTokenResponse.containsKey("token_type")) {
+ log.warn("{} Access token response is invalid, no token_type found", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+ return;
+ } else {
+ // Only support Bearer type
+ final Object tokenTypeObject = rawTokenResponse.get("token_type");
+ if (tokenTypeObject instanceof String) {
+ if (!"Bearer".equals((String)tokenTypeObject)) {
+ log.warn("{} Access token response is invalid, bearer token_type required", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+ return;
+ }
+ } else {
+ log.warn("{} Access token response is invalid, bearer token_type required", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+ return;
+ }
+ }
+ if (!rawTokenResponse.containsKey("expires_in")) {
+ log.trace("{} Expires_in not found in access token, is recomended ", getLogPrefix());
+ }
+
+
+ }
+
+}
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 3b4d560..a740a3d 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
@@ -2,6 +2,7 @@ package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
import java.text.ParseException;
import java.util.function.Consumer;
+import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -16,10 +17,9 @@ import com.nimbusds.jwt.JWTClaimsSet;
import net.shibboleth.idp.authn.AuthnEventIds;
import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.AbstractOIDCAuthenticationAction;
import net.shibboleth.idp.plugin.authn.oidc.rp.OIDCRPException;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OpenIDConnectContext;
-import net.shibboleth.oidc.jwt.claims.JWTClaimsValidation;
+import net.shibboleth.oidc.jwt.claims.ClaimsValidator;
import net.shibboleth.oidc.jwt.claims.JWTValidationException;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -27,8 +27,8 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * Action that validates the claims of the id_token using the supplied
- * {@link JWTClaimsValidation claims validator}. The verifier <b>must</b> be thread-safe and validate, at
+ * Action that validates the claims of a JWT using the supplied
+ * {@link ClaimsValidator claims validator}. The verifier <b>must</b> be thread-safe and validate, at
* minimum the claims set against the OpenID Connect core 1.0 section 3.1.3.7 specification.
*
* TODO: check these conditions
@@ -72,7 +72,10 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
@Nullable private JWTClaimsSet claimsSet;
/** The JWT claims validator used to verify the claimsset.*/
- @NonnullAfterInit private JWTClaimsValidation claimsValidator;
+ @NonnullAfterInit private ClaimsValidator claimsValidator;
+
+ /** Strategy used to pull out a JWT to validate from the context.*/
+ @NonnullAfterInit private Function<ProfileRequestContext, JWT> jwtLookupStrategy;
/** {@inheritDoc} */
@Override protected void doInitialize() throws ComponentInitializationException {
@@ -81,6 +84,21 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
if (claimsValidator == null) {
throw new ComponentInitializationException("JWT ClaimSet Validator cannot be null");
}
+ if (jwtLookupStrategy == null) {
+ throw new ComponentInitializationException("JWT lookup strategy cannot be null");
+ }
+ }
+
+ /**
+ * Set the lookup strategy that locates the JWT to validate from the context.
+ *
+ * @param strategy the strategy
+ */
+ public void setJwtLookupStrategy(@Nonnull final Function<ProfileRequestContext, JWT> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+ jwtLookupStrategy = Constraint.isNotNull(strategy," JWT lookup strategy can not be null");
}
/**
@@ -102,7 +120,7 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
* @param validator the claims validator.
*/
public void setClaimsValidator(
- @Nonnull final JWTClaimsValidation validator) {
+ @Nonnull final ClaimsValidator validator) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
@@ -112,12 +130,11 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
/** {@inheritDoc} */
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final AuthenticationContext authenticationContext,
- @Nonnull final OpenIDConnectContext oidcContext) {
+ @Nonnull final AuthenticationContext authenticationContext) {
- final JWT token = oidcContext.getIDToken();
+ final JWT token = jwtLookupStrategy.apply(profileRequestContext);
if (token == null) {
- log.error("{} id_token token is not available", getLogPrefix());
+ log.error("{} id_token was not located, nothing to validate", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX);
return false;
}
@@ -138,10 +155,10 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final AuthenticationContext authenticationContext,
- @Nonnull final OpenIDConnectContext oidcContext) {
+ @Nonnull final AuthenticationContext authenticationContext) {
- log.debug("{} Validating token claims for subject '{}'",getLogPrefix(),claimsSet.getSubject());
+ log.debug("{} Validating token claims for subject '{}'",getLogPrefix(),
+ claimsSet.getSubject() != null ? claimsSet.getSubject() : "unknown subject");
try {
claimsValidator.validate(claimsSet,profileRequestContext);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/DefaultClientIDForIssuerLookupFunction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/DefaultClientIDForIssuerLookupFunction.java
index 7ff6061..b381298 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/DefaultClientIDForIssuerLookupFunction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/DefaultClientIDForIssuerLookupFunction.java
@@ -13,7 +13,7 @@ import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.id.Issuer;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
import net.shibboleth.utilities.java.support.annotation.ParameterName;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java
index fcbccc7..f0ac8a9 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java
@@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
import com.nimbusds.oauth2.sdk.id.Issuer;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
import net.shibboleth.oidc.metadata.ClientInformationResolver;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.oidc.metadata.criterion.IssuerIDCriterion;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -42,7 +42,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
/**
* Handler for inbound OIDC protocol messages that attempts to locate OIDC metadata for a RP, and attaches it with a
- * {@link OIDCClientMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
+ * {@link OIDCMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
*/
public class OIDCClientMetadataLookupHandler extends AbstractMessageHandler {
@@ -116,13 +116,13 @@ public class OIDCClientMetadataLookupHandler extends AbstractMessageHandler {
return;
}
log.debug("{} Resolved client information for client '{}'", getLogPrefix(), clientInformation.getID());
- final OIDCClientMetadataContext oidcCtx = new OIDCClientMetadataContext();
+ final OIDCMetadataContext oidcCtx = new OIDCMetadataContext();
oidcCtx.setClientInformation(clientInformation);
messageContext.addSubcontext(oidcCtx);
// Based on that info we know 1) client is valid 2) we know valid
// redirect uris
log.debug("{} {} added to MessageContext as child of {}", getLogPrefix(),
- OIDCClientMetadataContext.class.getName(), messageContext.getClass().getName());
+ OIDCMetadataContext.class.getName(), messageContext.getClass().getName());
} catch (final ResolverException e) {
log.error("{} ResolverException thrown during client information lookup", getLogPrefix(), e);
}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
index bee1189..4939173 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
@@ -16,10 +16,9 @@ import com.nimbusds.oauth2.sdk.id.Issuer;
import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
-import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
import net.shibboleth.oidc.metadata.criterion.IssuerIDCriterion;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -31,7 +30,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
/**
* Handler for inbound OIDC protocol messages that attempts to locate OIDC metadata for a OP (issuer), and attaches it with a
- * {@link OIDCClientMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
+ * {@link OIDCMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
*/
//TODO This might need a way to set which base class to add the metadata too.
public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
@@ -126,7 +125,9 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
return;
}
log.debug("{} Found provider metadata for '{}'", getLogPrefix(), issuerId);
- entityCtx.addSubcontext(new OIDCProviderMetadataContext(issuerMetadata));
+ final OIDCProviderMetadataContext context = new OIDCProviderMetadataContext();
+ context.setProviderInformation(issuerMetadata);
+ entityCtx.addSubcontext(context);
} catch (final ResolverException e) {
log.error("{} ResolverException thrown during provider metadata lookup", getLogPrefix(), e);
}
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 11a5944..e78d544 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
@@ -200,8 +200,8 @@
<!-- CODE flow beans -->
- <bean id="ExchangeCodeForToken" scope="prototype"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExchangeCodeForToken"
+ <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')}"
@@ -209,6 +209,11 @@
p:tokenResponseDecoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenResponseDecoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultTokenResponseDecoder')}"
p:tokenRequestEncoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenRequestEncoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultTokenRequestEncoder')}"/>
+ <bean id="ValidateOAuthAccessTokenResponse"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOAuthAccessTokenResponse"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"/>
+
<bean id="ExtractIDTokenFromTokenResponse" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExtractIDTokenFromResponse"
p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
@@ -252,6 +257,129 @@
<!-- Process token -->
+ <!-- <bean id="PopulateTokenSignatureSigningParameters"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCSignatureSigningParameters " scope="prototype"
+ p:configurationLookupStrategy-ref="shibboleth.SignatureSigningConfigurationLookup"
+ p:signatureSigningParametersResolver-ref="shibboleth.oidc.TokenSignatureSigningParametersResolver">
+ <property name="securityParametersContextLookupStrategy">
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookupOrCreate.SecurityParameters"
+ c:f-ref="shibboleth.ChildLookup.RelyingParty" />
+ </property>
+ <property name="existingParametersContextLookupStrategy">
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookup.SecurityParameters"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </property>
+ </bean> -->
+
+ <!-- Default id_token JWT validation wiring. -->
+
+ <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.jwt.claims.CleanUpHook')
+ ?: getObject('shibboleth.authn.oidc.rp.jwt.claims.DefaultCleanupHook')}"
+ p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.IDTokenClaimsValidator')
+ ?: getObject('DefaultIDTokenClaimsValidator')}"
+ p:jwtLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.IDTokenLookupStrategy')
+ ?: getObject('DefaultIDTokenLookupStrategy')}"/>
+
+ <bean id="DefaultIDTokenLookupStrategy"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultIDTokenLookupStrategy"/>
+
+ <bean id="DefaultIDTokenClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator"
+ p:claimValidators-ref="ClaimsValidators" />
+
+ <bean id="OIDCProviderMetadataContextChildLookup"
+ class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+ c:type="#{ T(net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext) }" />
+
+ <bean id="ExpiryClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
+ p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
+
+ <bean id="NotBeforeClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.NotBeforeClaimsValidator"
+ p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
+
+ <bean id="IssuedAtClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
+ p:clockSkew="%{idp.policy.clockSkew:PT1M}"
+ p:messageLifetime="%{idp.policy.messageLifetime:PT1M}"
+ p:requiredRule="false" />
+
+ <bean id="IssuerClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+ p:claimName="iss" p:valueToMatchLookupStrategy-ref="IssuerIDFromOIDCProviderMetadataContextLookupFunction" />
+
+ <!-- check AZP is required if more than one audience value -->
+ <bean id="AzpClaimRequiredValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator">
+ <property name="activationCondition">
+ <bean id="MultipleValuesExist"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.NumberOfClaimValuesActivationCondition"
+ c:claimToCheck="aud"
+ c:numberOfValuesPredicate-ref="ManyValuesPredicate"/>
+ </property>
+ <property name="requiredClaims">
+ <list>
+ <value>azp</value>
+ </list>
+ </property>
+ </bean>
+
+ <!-- TODO, seems like this could be done in XML somehow -->
+ <bean id="ManyValuesPredicate"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ManyValuesIntegerComparisonPredicate" />
+
+ <bean id="AzpClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+ p:claimName="azp" p:valueToMatchLookupStrategy-ref="ClientIDFromOIDCMetadataContextLookupFunction">
+ <property name="activationCondition">
+ <bean id="AzpClaimExistsCondition"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ClaimExistsActivationCondition"
+ c:claimToCheck="azp"/>
+ </property>
+ </bean>
+
+ <bean id="IssuerIDFromOIDCProviderMetadataContextLookupFunction"
+ class="net.shibboleth.oidc.profile.logic.IssuerIDFromOIDCProviderMetadataContextLookupFunction"
+ p:oIDCMetadataContextLookupStrategy-ref="OIDCProviderMetadataContextFromOutboundPeerLookupStrategy"/>
+
+ <!-- TODO This bean could be replaced by XML functions? -->
+ <bean id="OIDCProviderMetadataContextFromOutboundPeerLookupStrategy"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.OIDCProviderMetadataFromOuboundPeerLookupStrategy"/>
+
+ <bean id="AudienceClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator"
+ p:audienceLookupStrategy-ref="ClientIDFromOIDCMetadataContextLookupFunction"/>
+
+ <bean id="ClientIDFromOIDCMetadataContextLookupFunction"
+ class="net.shibboleth.oidc.profile.logic.ClientIDFromOIDCMetadataContextLookupFunction">
+ <property name="oIDCMetadataContextLookupStrategy">
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="OIDCMetadataContextChildLookup"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </property>
+ </bean>
+
+ <bean id="OIDCMetadataContextChildLookup"
+ class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+ c:type="#{ T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext) }" />
+
+ <util:list id="ClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
+ <ref bean="ExpiryClaimsValidator" />
+ <ref bean="NotBeforeClaimsValidator" />
+ <ref bean="AzpClaimRequiredValidator"/>
+ <ref bean="AzpClaimsValidator"/>
+ <ref bean="IssuedAtClaimsValidator" />
+ <ref bean="IssuerClaimsValidator" /> <!-- TODO prevent: if it contains additional audiences not trusted by the Client. -->
+ <ref bean="AudienceClaimsValidator" />
+ </util:list>
+
<!-- OLD STUFF -->
@@ -270,81 +398,13 @@
<!-- Populate RP UI info from metadata? -->
<util:constant id="shibboleth.authn.oidc.rp.populateUIInfo" static-field="java.lang.Boolean.FALSE" />
- <!-- <bean id="SetOIDCInformation" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.SetOIDCInformation"
- p:redirectURI="%{idp.oidc.rp.redirectURI:}"
- p:clientID="%{idp.oidc.rp.clientID:null}"
- p:clientSecret="%{idp.oidc.rp.clientSecret:null}"
- p:providerMetadataLocation="%{idp.oidc.rp.providerConfigurationDocument:null}"
- p:scope="%{idp.oidc.rp.scope:null}">
-
- <property name="responseType" value="id_token token"/>
- </bean> -->
-
<bean id="ValidateIDTokenSignature"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateIDTokenSignature" />
- <bean id="ValidateOIDCAuthentication" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOIDCAuthentication" scope="prototype" />
+ <bean id="ValidateOIDCAuthentication"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOIDCAuthentication" scope="prototype" />
+
-
- <bean id="ValidateTokenClaims" scope="prototype"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
- p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.jwt.claims.CleanUpHook')
- ?: getObject('shibboleth.authn.oidc.rp.jwt.claims.DefaultCleanupHook')}"
- p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.RPTokenClaimsVerifier')
- ?: getObject('shibboleth.authn.oidc.rp.DefaultRPTokenClaimsVerifier')}" />
-
- <!-- TODO ensure these claims are correct in the general OIDC case. -->
- <!-- OIDC claims verification Other claim verifications e.g. ACR and AZP-->
- <bean id="shibboleth.authn.oidc.rp.DefaultRPTokenClaimsVerifier"
- class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator">
- <property name="claimValidators">
- <list>
- <bean id="requiredClaimsValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
- p:requiredClaims="#{getObject('shibboleth.authn.oidc.rp.RequiredOIDCClaims') ?:
- getObject('shibboleth.authn.oidc.rp.DefaultRequiredOIDCClaims')}"/>
- <bean id="issuerClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
- p:claimName="#{T(net.shibboleth.oidc.security.jwt.claims.impl.JWTClaims).ISSUER_CLAIM.claimName}"
- p:valueToMatchLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.IssuerLookupStrategy') ?:
- getObject('shibboleth.authn.oidc.rp.jwt.DefaultIssuerLookupStrategy')}"/>
- <bean id="audienceClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator"
- p:audienceLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.AudienceLookupStrategy') ?:
- getObject('shibboleth.authn.oidc.rp.jwt.DefaultAudienceLookupStrategy')}"/>
- <bean id="notBeforeClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.NotBeforeClaimsValidator"
- p:clockSkew="%{idp.duo.oidc.jwt.verifier.clockSkew:PT60S}"/>
- <bean id="expiryClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
- p:clockSkew="%{idp.duo.oidc.jwt.verifier.clockSkew:PT60S}"/>
- <bean id="issuedAtClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
- p:clockSkew="%{idp.duo.oidc.jwt.verifier.clockSkew:PT60S}"
- p:messageLifetime="%{idp.duo.oidc.jwt.verifier.messageLifetime:PT60S}"/>
-
- <bean id="authenticationTimeClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.AuthenticationTimeClaimsValidator"
- p:authnLifetime="%{idp.duo.oidc.jwt.verifier.authLifetime:PT60S}"
- p:clockSkew="%{idp.duo.oidc.jwt.verifier.clockSkew:PT60S}"
- p:activationCondition="#{getObject('shibboleth.authn.oidc.rp.jwt.AuthTimeActivationCondition') ?:
- getObject('shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeActivationCondition')}"
- p:requested="#{getObject('shibboleth.authn.oidc.rp.jwt.AuthTimeRequested') ?:
- getObject('shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeRequested')}"/>
- <!-- <bean id="nonceClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
- p:claimName="nonce"
- p:valueToMatchLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceLookupStrategy') ?:
- getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceLookupStrategy')}"
- p:activationCondition="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceActivationCondition') ?:
- getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition')}"/> -->
- <bean id="functionClaimValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.FunctionClaimsValidator"
- p:validator="#{getObject('shibboleth.authn.oidc.rp.ExtendedClaimsValidator')}"/>
- </list>
- </property>
- </bean>
-
<bean id="shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeActivationCondition"
class="net.shibboleth.oidc.security.jwt.claims.impl.ForcedAuthenticationActivationCondition"/>
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 ebcf8e6..443ed3b 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
@@ -62,12 +62,12 @@
<evaluate expression="ValidateAuthenticationResponseResult"/>
<evaluate expression="ValidateResponseStateMatchesRequest"/>
<evaluate expression="'proceed'" />
- <transition on="proceed" to="SwitchOnOIDCFlow" />
+ <transition on="proceed" to="SwitchOnGrantType" />
</action-state>
- <!-- Switch flow path based on OIDC response_type/flow used.
- TODO possible places for an NPE?-->
- <decision-state id="SwitchOnOIDCFlow">
+ <!-- Switch flow path based on OIDC grant_type used.
+ TODO possible places for an NPE, use strategy?-->
+ <decision-state id="SwitchOnGrantType">
<!-- 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"
@@ -88,7 +88,8 @@
</decision-state>
<action-state id="CodeFlow">
- <evaluate expression="ExchangeCodeForToken"/>
+ <evaluate expression="ExchangeCodeForAccessToken"/>
+ <evaluate expression="ValidateOAuthAccessTokenResponse"/>
<evaluate expression="ExtractIDTokenFromTokenResponse"/>
<evaluate expression="'proceed'" />
@@ -110,12 +111,14 @@
<action-state id="UnsupportedFlow">
<evaluate expression="'proceed'" />
- <transition on="proceed" to="ValidateToken" />
+ <transition on="proceed" to="END" />
</action-state>
+ <!-- TODO claim validation will differ per grant_type -->
<action-state id="ValidateToken">
-
-
+ <!-- <evaluate expression="PopulateTokenSignatureSigningParameters" /> -->
+ <!-- <evaluate expression="PopulateTokenEncryptionParameters" /> -->
+ <evaluate expression="ValidateIDTokenClaims" />
<transition on="proceed" to="SetPrincipal" />
</action-state>
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/decoding/impl/DefaultTokenResponseDecoderTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/decoding/impl/DefaultTokenResponseDecoderTest.java
index 57d01e1..b006417 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/decoding/impl/DefaultTokenResponseDecoderTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/decoding/impl/DefaultTokenResponseDecoderTest.java
@@ -60,7 +60,7 @@ public class DefaultTokenResponseDecoderTest extends AbstractOIDCTest {
when(mockStatusLine.getStatusCode()).thenReturn(200);
when(response.getStatusLine()).thenReturn(mockStatusLine);
when(response.getEntity()).thenReturn(mockHttpEntity);
- when(mockHttpEntity.getContent()).thenReturn(new ByteArrayInputStream(ID_TOKEN_RESPONSE.getBytes()));
+ when(mockHttpEntity.getContent()).thenReturn(new ByteArrayInputStream(ACCESS_TOKEN_RESPONSE.getBytes()));
final Map<String, Object> decodedResponse = decoder.apply(response);
assertNotNull(decodedResponse);
assertNotNull(decodedResponse.get("id_token"));
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCTest.java
index 0c183e7..efe5b44 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCTest.java
@@ -36,10 +36,10 @@ import net.minidev.json.JSONObject;
import net.minidev.json.parser.JSONParser;
import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+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.annotation.constraint.NotEmpty;
@@ -84,9 +84,9 @@ public abstract class AbstractOIDCTest {
+ "\"A192GCMKW\",\"A256GCMKW\",\"dir\"],\"userinfo_encryption_enc_values_supported\":[\"A128CBC-HS256\","
+ "\"A192CBC-HS384\",\"A256CBC-HS512\",\"A128GCM\",\"A192GCM\",\"A256GCM\"]}";
- /** Real response from openid connect tests,*/
+ /** Real response from openid connect tests.*/
@Nonnull @NotEmpty
- protected final String ID_TOKEN_RESPONSE = "{\n"
+ protected final String ACCESS_TOKEN_RESPONSE = "{\n"
+ " \"access_token\": \"W0y5aDNAzEPNpSzu1cuMG904BZuQFZJUUwG5F3ct0zydZWy1ji\",\n"
+ " \"token_type\": \"Bearer\",\n"
+ " \"id_token\": \"eyJraWQiOiJiNjliYzcyOS05NDJjLTQzNjItYmM2YS03OWU3MjAwOWY0Yzg"
@@ -151,14 +151,14 @@ public abstract class AbstractOIDCTest {
prc.setOutboundMessageContext(outMsgCtx);
final JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
- final OIDCClientMetadataContext metadataContext = new OIDCClientMetadataContext();
+ final OIDCMetadataContext metadataContext = new OIDCMetadataContext();
metadataContext.setClientInformation(
OIDCClientInformation.parse((JSONObject)((JSONArray)parser.parse(CLIENT_METADATA)).get(0)));
outMsgCtx.addSubcontext(metadataContext);
final OIDCPeerEntityContext peerEntitCtx = outMsgCtx.getSubcontext(OIDCPeerEntityContext.class,true);
- final OIDCProviderMetadataContext providerCtx =
- new OIDCProviderMetadataContext(
+ final OIDCProviderMetadataContext providerCtx = new OIDCProviderMetadataContext();
+ providerCtx.setProviderInformation(
OIDCProviderMetadata.parse((JSONObject)parser.parse(GOOD_PROVIDER_CONFIGURATION_INFO)));
peerEntitCtx.addSubcontext(providerCtx);
outMsgCtx.addSubcontext(peerEntitCtx);
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForTokenTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForTokenTest.java
index 21c54ed..c2dccf9 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForTokenTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForTokenTest.java
@@ -54,12 +54,12 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
/**
- * Tests for the {@link ExchangeCodeForToken} action.
+ * Tests for the {@link ExchangeCodeForAccessToken} action.
*/
public class ExchangeCodeForTokenTest extends AbstractOIDCTest {
/** The action to test.*/
- @Nonnull private ExchangeCodeForToken exchangeAction;
+ @Nonnull private ExchangeCodeForAccessToken exchangeAction;
@BeforeMethod
@@ -67,7 +67,7 @@ public class ExchangeCodeForTokenTest extends AbstractOIDCTest {
super.setup();
- exchangeAction = new ExchangeCodeForToken();
+ exchangeAction = new ExchangeCodeForAccessToken();
exchangeAction.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
exchangeAction.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
new ChildContextLookup<>(AuthenticationContext.class)
@@ -91,7 +91,7 @@ public class ExchangeCodeForTokenTest extends AbstractOIDCTest {
Mockito.when(httpResponse.getStatusLine()).thenReturn(statusLine);
Mockito.when(statusLine.getStatusCode()).thenReturn(200);
- Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(ID_TOKEN_RESPONSE));
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(ACCESS_TOKEN_RESPONSE));
Mockito.when(httpClient.execute((HttpUriRequest) Mockito.any(), (HttpContext) Mockito.any()))
.thenReturn(httpResponse);
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponseTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponseTest.java
new file mode 100644
index 0000000..3f16ce5
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponseTest.java
@@ -0,0 +1,71 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.io.ByteArrayInputStream;
+import java.util.Map;
+
+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;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.jose.shaded.json.parser.JSONParser;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/** Tests for ExtractIDTokenFromResponse.*/
+public class ExtractIDTokenFromResponseTest extends AbstractOIDCTest {
+
+ private ExtractIDTokenFromResponse action;
+
+
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ action = new ExtractIDTokenFromResponse();
+
+ final TokenResponseContext trc = new TokenResponseContext();
+ prc.getInboundMessageContext().addSubcontext(trc);
+
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+ }
+
+ @Test
+ public void testExtractSignedToken_Success() throws ComponentInitializationException {
+ action.setRawIdTokenLookupStrategy(prc -> "eyJraWQiOiJiNjliY"
+ + "zcyOS05NDJjLTQzNjItYmM2YS03OWU3MjAwOWY0YzgiLCJhbG"
+ + "ciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiM0pBZmFibUx4eWVnNj"
+ + "JJM2JiT0RrdyIsInN1YiI6InVzZXItc3ViamVjdC0xMjM0NTM"
+ + "xIiwiYXVkIjoibXl0ZXN0Y2xpZW50IiwiaXNzIjoiaHR0cHM6X"
+ + "C9cL3d3dy5jZXJ0aWZpY2F0aW9uLm9wZW5pZC5uZXRcL3Rlc3"
+ + "RcL2FcL3Rlc3RfcnBfcHJveHlcLyIsImV4cCI6MTY0MzI3NTQy"
+ + "NCwiaWF0IjoxNjQzMjc1MTI0fQ.igU798iSZYUR7Z6_MQQend"
+ + "FCqm9Pf6Xpd4KtnHcPGG5FxtXPiDhlyhP_7ewSIQtzWxQ5wEat"
+ + "ixDJWl2oRasivNCJyl6ZNeUG4YuT8S7xlgpUumoycBxrmomS7"
+ + "wgZSola8oZo8BuiRKlWzqLLtFkAChGi5iJEtHfVBe3k3PyQAs"
+ + "WRQdtixkvdxvyLqFLznIaPmMH-OZ82w7sJf4bpalZSAaR5NLpy"
+ + "zLFw-r81IOtOVrpQtnycCw0w_JxAP16GyZXCJc56vCEo8rji7"
+ + "juk3szTOclbsYFrrd9iokWHl0qJa0G1ev5XQLsiUxYxgO1Nw-"
+ + "CAnHtESZ9w7JIfLLX1YlY73g");
+
+ action.initialize();
+ final Event event = action.execute(src);
+ assertNull(event);
+ assertNotNull(prc.getInboundMessageContext().getSubcontext(TokenResponseContext.class).getIdToken());
+
+ }
+
+ //TODO need encrypted as well?
+
+}
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 9a7c66a..c78dd11 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
@@ -21,19 +21,25 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.io.IOException;
import java.net.URI;
+import java.time.Instant;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.StringEntity;
import org.apache.http.protocol.HttpContext;
import org.junit.Test;
+import org.mockito.Mockito;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
@@ -46,7 +52,14 @@ import org.springframework.webflow.engine.impl.FlowExecutionImpl;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.test.MockFlowBuilderContext;
-import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.KeyLengthException;
+import com.nimbusds.jose.crypto.MACSigner;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.ResponseMode;
import com.nimbusds.oauth2.sdk.ResponseType;
import com.nimbusds.oauth2.sdk.id.ClientID;
@@ -64,10 +77,10 @@ import net.shibboleth.idp.authn.context.ExternalAuthenticationContext;
import net.shibboleth.idp.authn.impl.ExternalAuthenticationImpl;
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.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
import net.shibboleth.idp.plugin.authn.test.flow.AbstractAuthnXmlFlowExecutionTests;
import net.shibboleth.idp.plugin.authn.test.flow.mock.MockFlowBuilder;
+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.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
@@ -78,12 +91,12 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
private final String GOOD_PROVIDER_CONFIGURATION_INFO = "{\n"
+ "\"issuer\": \"https://op.example.com\",\n"
- + "\"authorization_endpoint\": \"https://example.oidc.op.org/o/oauth2/v2/auth\",\n"
- + "\"device_authorization_endpoint\": \"https://oauth2.googleapis.com/device/code\",\n"
- + "\"token_endpoint\": \"https://oauth2.googleapis.com/token\",\n"
- + "\"userinfo_endpoint\": \"https://openidconnect.googleapis.com/v1/userinfo\",\n"
- + "\"revocation_endpoint\": \"https://oauth2.googleapis.com/revoke\",\n"
- + "\"jwks_uri\": \"https://www.googleapis.com/oauth2/v3/certs\",\n"
+ + "\"authorization_endpoint\": \"https://op.example.com/o/oauth2/v2/auth\",\n"
+ + "\"device_authorization_endpoint\": \"https://op.example.com/device/code\",\n"
+ + "\"token_endpoint\": \"https://op.example.com/token\",\n"
+ + "\"userinfo_endpoint\": \"https://op.example.com/v1/userinfo\",\n"
+ + "\"revocation_endpoint\": \"https://op.example.com/revoke\",\n"
+ + "\"jwks_uri\": \"https://op.example.com/oauth2/v3/certs\",\n"
+ "\"response_types_supported\": [\n"
+ "\"code\",\n"
+ "\"token\",\n"
@@ -143,12 +156,14 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
+ " \"https://192.168.0.150/static\"\n"
+ " ],\n"
+ " \"client_id\": \"demo_rp\",\n"
+ + " \"client_secret\": \"demo_rp_secret\",\n"
+ " \"response_types\": [\n"
+ " \"id_token\",\n"
+ " \"id_token token\"\n"
+ " ]\n"
+ " }"
+ "]";
+
/** Path to the flow to be tested.*/
@@ -203,27 +218,85 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
addBeanDefinition(builderContext, "shibboleth.IdentifiableBeanPostProcessor",BeanDefinitionBuilder.
genericBeanDefinition(IdentifiableBeanPostProcessor.class).getBeanDefinition());
-
- //create Mock HttpClient
- final HttpClient httpClient = mock(HttpClient.class);
- addBeanSingleton(builderContext, "shibboleth.InternalHttpClient", httpClient);
+ addBeanDefinition(builderContext, "shibboleth.ReplayCache",BeanDefinitionBuilder.
+ genericBeanDefinition(org.opensaml.storage.ReplayCache.class).getBeanDefinition());
+
try {
+ //create Mock HttpClient
+ /*
+ * This is brittle and only works because the HttpGet request for the metadata
+ * is different than that for the type of request to the token endpoint. If
+ * more endpoints are needed, this should be done properly.
+ */
+ final HttpClient httpClient = mock(HttpClient.class);
+
+ final HttpResponse httpResponse = Mockito.mock(HttpResponse.class);
+ final StatusLine statusLine = Mockito.mock(StatusLine.class);
+ when(httpResponse.getStatusLine()).thenReturn(statusLine);
+ when(statusLine.getStatusCode()).thenReturn(200);
+
when(httpClient.
- execute(any(HttpUriRequest.class),any(ResponseHandler.class),any(HttpContext.class)))
+ execute(any(HttpGet.class),any(ResponseHandler.class),any(HttpContext.class)))
.thenReturn(OIDCProviderMetadata.parse(GOOD_PROVIDER_CONFIGURATION_INFO));
- } catch (ParseException | IOException e) {
+
+
+
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(createAccessTokenResponseJSON()));
+ Mockito.when(httpClient.execute((HttpUriRequest) Mockito.any(), (HttpContext) Mockito.any()))
+ .thenReturn(httpResponse);
+
+ addBeanSingleton(builderContext, "shibboleth.InternalHttpClient", httpClient);
+
+
+ } catch (final Exception e) {
log.error("Could not mock HTTP response",e);
}
- loadBeanDefinitionsFromXmlFile(builderContext, new ClassPathResource("META-INF/net.shibboleth.idp/postconfig.xml"));
+ loadBeanDefinitionsFromXmlFile(builderContext,
+ new ClassPathResource("META-INF/net.shibboleth.idp/postconfig.xml"));
- loadBeanDefinitionsFromXmlFile(builderContext, new ClassPathResource("conf/test-relyingparty-resolver-service.xml"));
+ loadBeanDefinitionsFromXmlFile(builderContext,
+ new ClassPathResource("conf/test-relyingparty-resolver-service.xml"));
loadBeanDefinitionsFromXmlFile(builderContext, new ClassPathResource("conf/additional-system-beans.xml"));
}
+ /**
+ * Create an OAuth access token with a runtime constructed id_token. This allows the
+ * expiry to be current.
+ *
+ * TODO the JWT is signed with a local MAC and is not consistent with the OP metadata. Might need to change this
+ *
+ * @return a serialized access token response.
+ *
+ * @throws KeyLengthException on error
+ * @throws JOSEException on error
+ */
+ private String createAccessTokenResponseJSON() throws KeyLengthException, JOSEException {
+ final var header = new JWSHeader.Builder(JWSAlgorithm.HS256)
+ .type(JOSEObjectType.JWT)
+ .build();
+ final var payload = new JWTClaimsSet.Builder()
+ .issuer("https://op.example.com")
+ .audience(List.of("demo_rp","demo_rp2"))
+ .subject("jdoe")
+ .claim("azp", "demo_rp")
+ .expirationTime(Date.from(Instant.now().plusSeconds(120)))
+ .build();
+ final var signedJWT = new SignedJWT(header,payload);
+ signedJWT.sign(new MACSigner("Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$"));
+ final String accessTokenSerialized = "{\n"
+ + " \"access_token\": \"W0y5aDNAzEPNpSzu1cuMG904BZuQFZJUUwG5F3ct0zydZWy1ji\",\n"
+ + " \"token_type\": \"Bearer\",\n"
+ + " \"id_token\": \""+signedJWT.serialize()+"\",\n"
+ + " \"scope\": \"openid\"\n"
+ + "}";
+ log.debug("Access token: \n {}",accessTokenSerialized);
+ return accessTokenSerialized;
+ }
+
@Override
@Nonnull protected ProfileRequestContext buildProfileRequestContext(@Nonnull final String flowId,
@@ -301,7 +374,8 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
final OIDCPeerEntityContext peerCtx = new OIDCPeerEntityContext();
OIDCProviderMetadata providerMetadata = OIDCProviderMetadata.parse(GOOD_PROVIDER_CONFIGURATION_INFO);
- final OIDCProviderMetadataContext providerMetadataCtx = new OIDCProviderMetadataContext(providerMetadata);
+ final OIDCProviderMetadataContext providerMetadataCtx = new OIDCProviderMetadataContext();
+ providerMetadataCtx.setProviderInformation(providerMetadata);
peerCtx.addSubcontext(providerMetadataCtx);
outMsgCtx.addSubcontext(peerCtx);
@@ -313,7 +387,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
nestPrc.getOutboundMessageContext().addSubcontext(respCtx);
final JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
- final OIDCClientMetadataContext metadataContext = new OIDCClientMetadataContext();
+ final OIDCMetadataContext metadataContext = new OIDCMetadataContext();
metadataContext.setClientInformation(
OIDCClientInformation.parse((JSONObject)((JSONArray)parser.parse(CLIENT_METADATA)).get(0)));
nestPrc.getOutboundMessageContext().addSubcontext(metadataContext);
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategyTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategyTest.java
new file mode 100644
index 0000000..fcfd3bb
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategyTest.java
@@ -0,0 +1,74 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.io.ByteArrayInputStream;
+import java.util.Map;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
+
+/** Tests for TokenResponseIDTokenLookupStrategy.*/
+public class TokenResponseIDTokenLookupStrategyTest extends AbstractOIDCTest {
+
+ /** The strategy to test.*/
+ private TokenResponseIDTokenLookupStrategy strategy;
+
+
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ strategy = new TokenResponseIDTokenLookupStrategy();
+ ObjectMapper mapper = new ObjectMapper();
+
+ final Map<String, Object> rawResponse = mapper.readValue(
+ new ByteArrayInputStream(ACCESS_TOKEN_RESPONSE.getBytes()), new TypeReference<Map<String, Object>>() {});
+ final TokenResponseContext trc = new TokenResponseContext();
+ trc.setRawTokenResponse(rawResponse);
+ prc.getInboundMessageContext().addSubcontext(trc);
+
+ }
+
+ @Test
+ public void testLookup_Success() {
+ final String rawToken = strategy.apply(prc);
+ assertNotNull(rawToken);
+ assertEquals(rawToken, "eyJraWQiOiJiNjliYzcyOS05NDJjLTQzNjItYmM2YS0"
+ + "3OWU3MjAwOWY0YzgiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiM"
+ + "0pBZmFibUx4eWVnNjJJM2JiT0RrdyIsInN1YiI6InVzZXItc3ViamVj"
+ + "dC0xMjM0NTMxIiwiYXVkIjoibXl0ZXN0Y2xpZW50IiwiaXNzIjoiaHR0"
+ + "cHM6XC9cL3d3dy5jZXJ0aWZpY2F0aW9uLm9wZW5pZC5uZXRcL3Rlc3Rc"
+ + "L2FcL3Rlc3RfcnBfcHJveHlcLyIsImV4cCI6MTY0MzI3NTQyNCwiaWF0"
+ + "IjoxNjQzMjc1MTI0fQ.igU798iSZYUR7Z6_MQQendFCqm9Pf6Xpd4Ktn"
+ + "HcPGG5FxtXPiDhlyhP_7ewSIQtzWxQ5wEatixDJWl2oRasivNCJyl6ZN"
+ + "eUG4YuT8S7xlgpUumoycBxrmomS7wgZSola8oZo8BuiRKlWzqLLtFkAC"
+ + "hGi5iJEtHfVBe3k3PyQAsWRQdtixkvdxvyLqFLznIaPmMH-OZ82w7sJf"
+ + "4bpalZSAaR5NLpyzLFw-r81IOtOVrpQtnycCw0w_JxAP16GyZXCJc56v"
+ + "CEo8rji7juk3szTOclbsYFrrd9iokWHl0qJa0G1ev5XQLsiUxYxgO1Nw"
+ + "-CAnHtESZ9w7JIfLLX1YlY73g");
+ }
+
+ @Test
+ public void testLookup_NoResponseContext() {
+ prc.getInboundMessageContext().removeSubcontext(TokenResponseContext.class);
+ final String rawToken = strategy.apply(prc);
+ assertNull(rawToken);
+
+ }
+
+ @Test
+ public void testLookup_NoInboundContext() {
+ prc.setInboundMessageContext(null);
+ final String rawToken = strategy.apply(prc);
+ assertNull(rawToken);
+
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list