[java-idp-plugin-oidc-rp] branch main updated: Add more tests, cleanup some code and JavaDoc
Phil Smart
philip.smart at jisc.ac.uk
Wed Sep 28 14:54:33 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=529ab2287c3ded150c5834f983b49fdbef91831c
The following commit(s) were added to refs/heads/main by this push:
new 529ab22 Add more tests, cleanup some code and JavaDoc
529ab22 is described below
commit 529ab2287c3ded150c5834f983b49fdbef91831c
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Sep 28 15:54:28 2022 +0100
Add more tests, cleanup some code and JavaDoc
---
.../oidc/rp/context/AbstractOIDCEntityContext.java | 17 ++
.../AddAuthenticationContextClassReferences.java | 5 +-
.../plugin/authn/oidc/rp/impl/AddEndpointURI.java | 12 +-
.../idp/plugin/authn/oidc/rp/impl/AddNonce.java | 5 +-
.../plugin/authn/oidc/rp/impl/AddRedirectURI.java | 7 +-
.../oidc/rp/impl/DefaultClaimMergingStrategy.java | 3 +-
.../authn/oidc/rp/impl/UserInfoEndpointLookup.java | 3 +-
.../impl/OIDCClientMetadataLookupHandler.java | 130 ------------
.../impl/OIDCProviderMetadataLookupHandler.java | 13 +-
.../idp/service/relying-party/postconfig.xml | 27 ++-
.../authn/oidc/rp/impl/AbstractOIDCTest.java | 28 +--
...ddAuthenticationContextClassReferencesTest.java | 99 +++++++++
.../authn/oidc/rp/impl/AddEndpointURITest.java | 91 ++++++++
.../rp/impl/AddForceAuthenticationPromptTest.java | 97 +++++++++
.../authn/oidc/rp/impl/AddRedirectURITest.java | 100 +++++++++
.../plugin/authn/oidc/rp/impl/AddScopesTest.java | 114 ++++++++++
...eOIDCSubjectIdentifierCanonicalizationTest.java | 111 ++++++++++
.../oidc/rp/impl/UserInfoEndpointLookupTest.java | 193 +++++++++++++++++
.../oidc/rp/impl/ValidateResponseStateTest.java | 119 +++++++++++
.../OIDCProviderMetadataLookupHandlerTest.java | 229 +++++++++++++++++++++
.../resources/conf/authn/oidc-rp-credentials.xml | 10 -
21 files changed, 1227 insertions(+), 186 deletions(-)
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/AbstractOIDCEntityContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/AbstractOIDCEntityContext.java
index 418d661..b58453f 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/AbstractOIDCEntityContext.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/AbstractOIDCEntityContext.java
@@ -1,3 +1,20 @@
+/*
+ * 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.context;
import javax.annotation.Nullable;
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthenticationContextClassReferences.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthenticationContextClassReferences.java
index 5b9e7cd..666ad04 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthenticationContextClassReferences.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthenticationContextClassReferences.java
@@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
import com.nimbusds.openid.connect.sdk.claims.ACR;
import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction;
import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
/**
@@ -59,7 +60,9 @@ public class AddAuthenticationContextClassReferences extends AbstractOIDCAuthent
/**
* Build a list of {@link ACR}s if warranted. Converted from any default authentication method {@link Principal}s.
*
- * <p>By default for this proxy case, the authentication methods are mapped from the upstream request.
+ * <p>By default for this proxy case, the authentication methods are mapped from the upstream request
+ * by the default authentication methods e.g. using the
+ * {@link ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction}.</p>
*
* @param profileRequestContext current profile request context
*
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddEndpointURI.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddEndpointURI.java
index 0d058e3..3e4d715 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddEndpointURI.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddEndpointURI.java
@@ -19,15 +19,18 @@ package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
import javax.annotation.Nonnull;
+import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
/**
* An action that adds the authorization endpoint URI from the providers metadata
- * to the under constructions authentication request.
+ * to the under constructions authentication request. If an authorization endpoint does
+ * not exist, an error event is returned.
*/
public class AddEndpointURI extends AbstractOIDCAuthenticationRequestAction {
@@ -38,6 +41,13 @@ public class AddEndpointURI extends AbstractOIDCAuthenticationRequestAction {
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@Nonnull final AuthenticationContext authenticationContext) {
+ if (getProviderMetadata().getAuthorizationEndpointURI() == null) {
+ log.error("{} OAuth 2.0 Authorization Endpoint URI not found in provider metadata",
+ getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_AUTHZ_ENDPOINT_URI);
+ return;
+ }
+
getAuthenticationRequest().setEndpointURI(getProviderMetadata().getAuthorizationEndpointURI());
log.trace("{} Added authorization endpoint '{}' to authentication request for client '{}'",getLogPrefix(),
getAuthenticationRequest().getEndpointURI(), getAuthenticationRequest().getClientID());
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddNonce.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddNonce.java
index 2022bde..cfb6e16 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddNonce.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddNonce.java
@@ -32,14 +32,15 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * An action that adds a nonce from a lookup strategy to the under constructions authentication request.
+ * An action that adds a nonce from a lookup strategy to the authentication request.
+ * The injected nonce generation strategy could generate a {@literal null} nonce.
*/
public class AddNonce extends AbstractOIDCAuthenticationRequestAction {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(AddNonce.class);
- /** Strategy used to generate a nonce.*/
+ /** Strategy used to generate a nonce. Could generate a {@literal null} nonce.*/
@Nonnull private Function<ProfileRequestContext, Nonce> nonceGenerationStrategy;
/** Constructor.*/
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddRedirectURI.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddRedirectURI.java
index 99be73c..cafd3f9 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddRedirectURI.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddRedirectURI.java
@@ -41,8 +41,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/**
* Action that adds a redirect_uri to the authentication request.
- *
- * TODO Events.*/
+ */
public class AddRedirectURI extends AbstractOIDCAuthenticationRequestAction {
/** Logger. */
@@ -105,11 +104,11 @@ public class AddRedirectURI extends AbstractOIDCAuthenticationRequestAction {
final URI redirectUri =
redirectUriCreationStrategy.apply(getHttpServletRequest(), profileRequestContext);
if (redirectUri == null) {
- log.error("{} Redirect URI could not be located or created from strategy", getLogPrefix());
+ log.error("{} Redirect URI could not be located or created using the strategy", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_REDIRECT_URI);
return;
}
- log.trace("Created redirect_uri '{}'", redirectUri);
+ log.trace("{} Created redirect_uri '{}'", getLogPrefix(), redirectUri);
getAuthenticationRequest().setRedirectURI(redirectUri);
}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultClaimMergingStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultClaimMergingStrategy.java
index 0c98915..b294140 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultClaimMergingStrategy.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultClaimMergingStrategy.java
@@ -38,7 +38,6 @@ import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
* is taken over that from the UserInfo response if the claim keys clash.</li>
* </ol>
*/
-//TODO maybe this should filter claims as well e.g. exp etc. Security check this logic.
public class DefaultClaimMergingStrategy implements BinaryOperator<ClaimsSet> {
/** Class logger.*/
@@ -69,7 +68,7 @@ public class DefaultClaimMergingStrategy implements BinaryOperator<ClaimsSet> {
// add UserInfo claims as a base
final Map<String, Object> mergedClaimsMap = new HashMap<String, Object>(userInfoClaimsAsMap);
- // Merge id_token claims into userInfo claims, take userinfo claim if conflict
+ // Merge id_token claims into userInfo claims, take id_token claim if conflict
idTokenAsMap.forEach((key, value) ->
mergedClaimsMap.merge(key, value, (v1, v2)-> {
log.trace("Claim '{}' exists in id_token and UserInfo response, taking id_token value '{}'",key, v2);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookup.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookup.java
index 29370c5..462c9b8 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookup.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookup.java
@@ -87,8 +87,7 @@ public class UserInfoEndpointLookup extends AbstractHttpOIDCAuthenticationAction
}
try {
- final UserInfoResponse responseObject = handleRequest(profileRequestContext);
- userInfoCtx.setUserInfo(responseObject);
+ userInfoCtx.setUserInfo(handleRequest(profileRequestContext));
} catch (final OIDCRPException e) {
log.error("{} Unable to return claims from UserInfo endpoint",getLogPrefix(),e);
ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.AUTHN_EXCEPTION);
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
deleted file mode 100644
index f0ac8a9..0000000
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java
+++ /dev/null
@@ -1,130 +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.metadata.impl;
-
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.handler.AbstractMessageHandler;
-import org.opensaml.messaging.handler.MessageHandlerException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.nimbusds.oauth2.sdk.id.Issuer;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-
-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;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-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 OIDCMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
- */
-public class OIDCClientMetadataLookupHandler extends AbstractMessageHandler {
-
- /** Logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(OIDCClientMetadataLookupHandler.class);
-
- /** Resolver used to look up OIDC client information. */
- @NonnullAfterInit private ClientInformationResolver clientResolver;
-
- /** Strategy used to obtain the issuer value for the authorization request. */
- @Nonnull
- private Function<MessageContext, String> issuerLookupStrategy;
-
- /**
- * Constructor.
- */
- public OIDCClientMetadataLookupHandler() {
- issuerLookupStrategy = new DefaultIssuerIDLookupFunction();
- }
-
- /**
- * Set the strategy used to locate the issuer (downstream OP) for the request.
- *
- * @param strategy lookup strategy
- */
- public void setIssuerLookupStrategy(@Nonnull final Function<MessageContext, String> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- issuerLookupStrategy =
- Constraint.isNotNull(strategy, "IssuerLookupStrategy lookup strategy cannot be null");
- }
-
- /**
- * Set the {@link ClientInformationResolver} to use.
- *
- * @param resolver The resolver to use.
- */
- public void setClientInformationResolver(@Nonnull final ClientInformationResolver resolver) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- clientResolver = Constraint.isNotNull(resolver, "ClientInformationResolver cannot be null");
- }
-
- /** {@inheritDoc} */
- @Override
- protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
-
- if (clientResolver == null) {
- throw new ComponentInitializationException("ClientInformationResolver cannot be null");
- }
- }
-
- //TODO test if no client returned
- /** {@inheritDoc} */
- @Override
- protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
- ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
- // Resolve issuer from inbound message
- final String issuerString = issuerLookupStrategy.apply(messageContext);
- if (issuerString == null) {
- log.warn("{} Issuer not found, client information can not be resolved", getLogPrefix());
- return;
- }
- // Resolve client metadata for given issuer
- final IssuerIDCriterion issuerCriterion = new IssuerIDCriterion(new Issuer(issuerString));
- final CriteriaSet criteria = new CriteriaSet(issuerCriterion);
- try {
- final OIDCClientInformation clientInformation = clientResolver.resolveSingle(criteria);
- if (clientInformation == null) {
- log.debug("{} No client information returned for issuer {}", getLogPrefix(), issuerString);
- return;
- }
- log.debug("{} Resolved client information for client '{}'", getLogPrefix(), clientInformation.getID());
- 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(),
- OIDCMetadataContext.class.getName(), messageContext.getClass().getName());
- } catch (final ResolverException e) {
- log.error("{} ResolverException thrown during client information lookup", getLogPrefix(), e);
- }
- }
-}
\ No newline at end of file
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 5a161bb..8aeff92 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
@@ -112,7 +112,7 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
- providerResolver = Constraint.isNotNull(resolver, "IssuerMetadataResolver cannot be null");
+ providerResolver = Constraint.isNotNull(resolver, "ProviderMetadataResolver cannot be null");
}
/** {@inheritDoc} */
@@ -121,7 +121,7 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
super.doInitialize();
if (providerResolver == null) {
- throw new ComponentInitializationException("IssuerMetadataResolver cannot be null");
+ throw new ComponentInitializationException("ProviderMetadataResolver cannot be null");
}
}
@@ -161,7 +161,9 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
context.setProviderInformation(issuerMetadata);
entityCtx.addSubcontext(context);
} catch (final ResolverException e) {
- log.error("{} ResolverException thrown during provider metadata lookup", getLogPrefix(), e);
+ log.error("{} ResolverException thrown during provider metadata lookup: {}",
+ getLogPrefix(), e.getMessage());
+ throw new MessageHandlerException(e);
}
}
@@ -198,9 +200,10 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
}
log.debug("{} Existing OIDCProviderMetadataContext was resolved, but the issuer "
+ "did not match the entity context data", getLogPrefix());
- }
- log.debug("{} Existing OIDCProviderMetadataContext was resolved, but was missing ProviderInformation "
+ } else {
+ log.debug("{} Existing OIDCProviderMetadataContext was resolved but is missing ProviderInformation "
+ "data", getLogPrefix());
+ }
} else {
log.debug("{} No existing OIDCProviderMetadataContext was resolved", getLogPrefix());
}
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index e4eb51d..296508f 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -176,25 +176,21 @@
</list>
</property>
</bean>
-
- <bean id="shibboleth.authn.oidc.rp.SigningCredentials"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.config.CredentialsListFactory"
- c:_0="#{getObject('shibboleth.authn.oidc.rp.DefaultSigningCredentials')}" />
-
- <bean id="shibboleth.authn.oidc.rp.RequestObjectKeyTransportEncryptionCredentials"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.config.CredentialsListFactory"
- c:_0="#{getObject('shibboleth.authn.oidc.rp.DefaultRequestObjectKeyTransportEncryptionCredentials')}" />
- <bean id="shibboleth.authn.oidc.rp.RequestObjectDataEncryptionCredentials"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.config.CredentialsListFactory"
- c:_0="#{getObject('shibboleth.authn.oidc.rp.DefaultRequestObjectDataEncryptionCredentials')}" />
-
<bean id="shibboleth.authn.oidc.rp.DefaultJWTDecryptionConfiguration"
parent="shibboleth.authn.oidc.rp.BasicDecryptionConfiguration"
p:KEKCredentialResolver-ref="defaultOIDCRPKeyDecryptionCredentialResolver"
p:contentEncryptionKeyCredentialResolver-ref="defaultOIDCRPContentDecryptionKeyCredentialResolver" />
+
+
+ <bean id="shibboleth.authn.oidc.rp.SigningCredentials"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.config.CredentialsListFactory"
+ c:_0="#{getObject('shibboleth.authn.oidc.rp.DefaultSigningCredentials')}" />
+
- <!-- A resolver to public/private key encryption keys global to the RP -->
+ <!--
+ A resolver to public/private key encryption keys global to the RP
+ -->
<bean id="defaultOIDCRPKeyDecryptionCredentialResolver"
class="net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver">
<constructor-arg>
@@ -213,7 +209,8 @@
</bean>
<!--
- A resolver to resolve a pre-shared Direct Encryption key e.g. a pairwise client_secret from the input criterion
+ A resolver to resolve a pre-shared Direct Encryption key e.g. a pairwise client_secret from the input criterion
+ from which to derive the decryption key.
-->
<bean id="defaultOIDCRPContentDecryptionKeyCredentialResolver"
class="net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver">
@@ -243,7 +240,7 @@
<!--
A resolver to resolve pre-shared Direct Encryption or Key Wrapping credentials based on the
client_secret in the input criterion. Returns the raw value, even though the key to use
- is a derivative of this key
+ is a derivative of this key.
-->
<bean id="defaultOIDCRPContentEncryptionKeyCredentialResolver"
class="net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver">
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 80e68b1..e207d2e 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
@@ -119,13 +119,15 @@ public abstract class AbstractOIDCTest {
/** Mock response from the UserInfo endpoint.*/
@Nonnull @NotEmpty
- protected final String USERINFO_RESPONSE ="{sub=user-subject-1234531, "
- + "website=https://openid.net/, "
- + "zoneinfo=America/Los_Angeles, "
- + "birthdate=2000-02-03, gender=female, "
- + "preferred_username=d.tu, "
- + "given_name=Demo, middle_name=Theresa, locale=en-US, "
- + "updated_at=1580000000, name=Demo T. User, nickname=Dee, family_name=User}";
+ protected final String USERINFO_RESPONSE ="{\n"
+ + " \"sub\": \"248289761001\",\n"
+ + " \"name\": \"Jane Doe\",\n"
+ + " \"given_name\": \"Jane\",\n"
+ + " \"family_name\": \"Doe\",\n"
+ + " \"preferred_username\": \"j.doe\",\n"
+ + " \"email\": \"janedoe at example.com\",\n"
+ + " \"picture\": \"http://example.com/janedoe/me.jpg\"\n"
+ + " }";
/** Client metadata.*/
@Nonnull protected final String CLIENT_METADATA = "[\n"
@@ -165,6 +167,9 @@ public abstract class AbstractOIDCTest {
/** The RP config.*/
protected OIDCAuthorizationConfiguration partyConfig;
+ /** The OIDC provider metadata context.*/
+ protected OIDCProviderMetadataContext providerCtx;
+
/**
* Setup the various contexts.
*
@@ -197,12 +202,7 @@ public abstract class AbstractOIDCTest {
outMsgCtx.setMessage(authnRequest);
prc.setOutboundMessageContext(outMsgCtx);
- // FIXME we should no longer need this context
final JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
- final OIDCMetadataContext metadataContext = new OIDCMetadataContext();
- metadataContext.setClientInformation(
- OIDCClientInformation.parse((JSONObject)((JSONArray)parser.parse(CLIENT_METADATA)).get(0)));
- outMsgCtx.addSubcontext(metadataContext);
final RelyingPartyContext partyContext = new RelyingPartyContext();
partyConfig = new OIDCAuthorizationConfiguration();
@@ -217,13 +217,13 @@ public abstract class AbstractOIDCTest {
prc.addSubcontext(partyContext);
peerEntityCtx = outMsgCtx.getSubcontext(OIDCPeerEntityContext.class,true);
- final OIDCProviderMetadataContext providerCtx = new OIDCProviderMetadataContext();
+ providerCtx = new OIDCProviderMetadataContext();
providerCtx.setProviderInformation(
OIDCProviderMetadata.parse((JSONObject)parser.parse(GOOD_PROVIDER_CONFIGURATION_INFO)));
peerEntityCtx.addSubcontext(providerCtx);
outMsgCtx.addSubcontext(peerEntityCtx);
- //Set the inbound reponse.
+ //Set the inbound response.
final MessageContext inMsgCtx = new MessageContext();
inMsgCtx.setMessage(AuthenticationResponseParser.parse(
new URI("/idp/profile/Authn/OIDC/RP/callback"
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthenticationContextClassReferencesTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthenticationContextClassReferencesTest.java
new file mode 100644
index 0000000..dd801ab
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthenticationContextClassReferencesTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.ParentContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+
+/** Tests for AddAuthenticationContextClassReferences.*/
+public class AddAuthenticationContextClassReferencesTest extends AbstractOIDCTest {
+
+ /** The action to test.*/
+ private AddAuthenticationContextClassReferences action;
+
+ /** The RPC.*/
+ private RelyingPartyContext rpc;
+
+ /** The profile config.*/
+ private OIDCAuthorizationConfiguration oidcAuthzConfig;
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ action = new AddAuthenticationContextClassReferences();
+
+ rpc = prc.getSubcontext(RelyingPartyContext.class, true);
+ oidcAuthzConfig = new OIDCAuthorizationConfiguration();
+ final RelyingPartyConfiguration rpConfig = new RelyingPartyConfiguration();
+ rpc.setProfileConfig(oidcAuthzConfig);
+ rpc.setConfiguration(rpConfig);
+
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+
+ action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
+
+ oidcAuthzConfig.setDefaultAuthenticationMethods(List.of(
+ new AuthenticationContextClassReferencePrincipal("test-value-1"),
+ new AuthenticationContextClassReferencePrincipal("test-value-2"),
+ new AuthenticationContextClassReferencePrincipal("test-value-3")));
+
+ }
+
+ @Test
+ public void testSuccess() throws Exception {
+ action.initialize();
+
+ action.execute(src);
+
+ assertEquals(authnRequest.getAcrs().size(),3);
+ assertEquals(authnRequest.getAcrs().get(0).getValue(),"test-value-1");
+ assertEquals(authnRequest.getAcrs().get(1).getValue(),"test-value-2");
+ assertEquals(authnRequest.getAcrs().get(2).getValue(),"test-value-3");
+ }
+
+ @Test
+ public void testSuccess_NoPrincipals() throws Exception {
+ oidcAuthzConfig.setDefaultAuthenticationMethods(Collections.emptyList());
+
+ action.initialize();
+
+ action.execute(src);
+
+ assertEquals(authnRequest.getAcrs().size(),0);
+
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddEndpointURITest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddEndpointURITest.java
new file mode 100644
index 0000000..b77e310
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddEndpointURITest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertEquals;
+
+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 net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/** Tests for {@link AddEndpointURI}.*/
+public class AddEndpointURITest extends AbstractOIDCTest {
+
+ /** The action to test.*/
+ private AddEndpointURI action;
+
+ /** The RPC.*/
+ private RelyingPartyContext rpc;
+
+ /** The profile config.*/
+ private OIDCAuthorizationConfiguration oidcAuthzConfig;
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ action = new AddEndpointURI();
+
+ rpc = prc.getSubcontext(RelyingPartyContext.class, true);
+ oidcAuthzConfig = new OIDCAuthorizationConfiguration();
+ final RelyingPartyConfiguration rpConfig = new RelyingPartyConfiguration();
+ rpc.setProfileConfig(oidcAuthzConfig);
+ rpc.setConfiguration(rpConfig);
+
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+
+ action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
+
+ }
+
+ @Test
+ public void testSuccess() throws ComponentInitializationException {
+ action.initialize();
+
+ action.execute(src);
+
+ assertEquals(authnRequest.getEndpointURI(),
+ providerCtx.getProviderInformation().getAuthorizationEndpointURI());
+ }
+
+ @Test
+ public void testNoAuthzEndpoint() throws ComponentInitializationException {
+
+ providerCtx.getProviderInformation().setAuthorizationEndpointURI(null);
+
+ action.initialize();
+
+ final Event event = action.execute(src);
+ assertEquals(event.getId(),OidcEventIds.INVALID_AUTHZ_ENDPOINT_URI);
+
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddForceAuthenticationPromptTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddForceAuthenticationPromptTest.java
new file mode 100644
index 0000000..558a821
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddForceAuthenticationPromptTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.ParentContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.nimbusds.openid.connect.sdk.Prompt;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/** Tests for {@link AddForceAuthenticationPrompt}.*/
+public class AddForceAuthenticationPromptTest extends AbstractOIDCTest {
+
+ /** The action to test.*/
+ private AddForceAuthenticationPrompt action;
+
+ /** The RPC.*/
+ private RelyingPartyContext rpc;
+
+ /** The profile config.*/
+ private OIDCAuthorizationConfiguration oidcAuthzConfig;
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ action = new AddForceAuthenticationPrompt();
+
+ rpc = prc.getSubcontext(RelyingPartyContext.class, true);
+ oidcAuthzConfig = new OIDCAuthorizationConfiguration();
+ final RelyingPartyConfiguration rpConfig = new RelyingPartyConfiguration();
+ rpc.setProfileConfig(oidcAuthzConfig);
+ rpc.setConfiguration(rpConfig);
+
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+
+ action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
+
+ }
+
+ @Test
+ public void testSuccess() throws ComponentInitializationException {
+
+ oidcAuthzConfig.setForceAuthn(true);
+
+ action.initialize();
+
+ action.execute(src);
+
+ assertEquals(authnRequest.getPrompt().size(), 1);
+ assertEquals(authnRequest.getPrompt().iterator().next(), Prompt.Type.LOGIN);
+ }
+
+ @Test
+ public void testForceAuthnNotRequired() throws ComponentInitializationException {
+
+ oidcAuthzConfig.setForceAuthn(false);
+
+ action.initialize();
+
+ action.execute(src);
+
+ assertNull(authnRequest.getPrompt());
+
+
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddRedirectURITest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddRedirectURITest.java
new file mode 100644
index 0000000..f592387
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddRedirectURITest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+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 net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/** Tests for {@link AddRedirectURI}.*/
+public class AddRedirectURITest extends AbstractOIDCTest {
+
+ /** The action to test.*/
+ private AddRedirectURI action;
+
+ /** The RPC.*/
+ private RelyingPartyContext rpc;
+
+ /** The profile config.*/
+ private OIDCAuthorizationConfiguration oidcAuthzConfig;
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ action = new AddRedirectURI();
+
+ rpc = prc.getSubcontext(RelyingPartyContext.class, true);
+ oidcAuthzConfig = new OIDCAuthorizationConfiguration();
+ final RelyingPartyConfiguration rpConfig = new RelyingPartyConfiguration();
+ rpc.setProfileConfig(oidcAuthzConfig);
+ rpc.setConfiguration(rpConfig);
+
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+
+ action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
+
+ }
+
+ @Test
+ public void testSuccess() throws ComponentInitializationException, URISyntaxException {
+
+ final URI redirectUri = new URI("https://rp.example.com/callback");
+
+ action.setRedirectUriCreationStrategy((http, prc) -> redirectUri);
+
+ action.initialize();
+
+ action.execute(src);
+
+ assertEquals(authnRequest.getRedirectURI(),redirectUri);
+ }
+
+ @Test
+ public void testNullURI() throws ComponentInitializationException, URISyntaxException {
+
+ action.setRedirectUriCreationStrategy((http, prc) -> null);
+
+ action.initialize();
+
+ final Event event = action.execute(src);
+
+ assertEquals(event.getId(), OidcEventIds.INVALID_REDIRECT_URI);
+ }
+
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddScopesTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddScopesTest.java
new file mode 100644
index 0000000..309d5f7
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddScopesTest.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URISyntaxException;
+import java.util.Set;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.ParentContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/** Tests for {@link AddScopes}.*/
+public class AddScopesTest extends AbstractOIDCTest {
+
+ /** The action to test.*/
+ private AddScopes action;
+
+ /** The RPC.*/
+ private RelyingPartyContext rpc;
+
+ /** The profile config.*/
+ private OIDCAuthorizationConfiguration oidcAuthzConfig;
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ action = new AddScopes();
+
+ rpc = prc.getSubcontext(RelyingPartyContext.class, true);
+ oidcAuthzConfig = new OIDCAuthorizationConfiguration();
+ final RelyingPartyConfiguration rpConfig = new RelyingPartyConfiguration();
+ rpc.setProfileConfig(oidcAuthzConfig);
+ rpc.setConfiguration(rpConfig);
+
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+
+ action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
+
+ }
+
+ @Test
+ public void testSuccessWithDefaultScope() throws ComponentInitializationException, URISyntaxException {
+
+ action.initialize();
+ action.execute(src);
+
+ // Always one more scope as openid is default
+ assertEquals(authnRequest.getScope().size(), 1);
+ assertEquals(authnRequest.getScope().iterator().next().getValue(), "openid");
+ }
+
+ @Test
+ public void testSuccess_AddScopes() throws ComponentInitializationException, URISyntaxException {
+
+ oidcAuthzConfig.setScopes(Set.of("profile","email"));
+
+ action.initialize();
+ action.execute(src);
+
+ // Always one more scope as openid is default
+ assertEquals(authnRequest.getScope().size(), 3);
+ assertTrue(authnRequest.getScope().contains("openid"));
+ assertTrue(authnRequest.getScope().contains("profile"));
+ assertTrue(authnRequest.getScope().contains("email"));
+
+ }
+
+ @Test
+ public void testSuccess_NullScopes() throws ComponentInitializationException, URISyntaxException {
+
+ oidcAuthzConfig.setScopes(null);
+
+ action.initialize();
+ action.execute(src);
+
+ // Always one more scope as openid is default
+ assertEquals(authnRequest.getScope().size(), 1);
+ assertTrue(authnRequest.getScope().contains("openid"));
+
+ }
+
+
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/SimpleOIDCSubjectIdentifierCanonicalizationTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/SimpleOIDCSubjectIdentifierCanonicalizationTest.java
new file mode 100644
index 0000000..31775ba
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/SimpleOIDCSubjectIdentifierCanonicalizationTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import java.util.Arrays;
+
+import javax.security.auth.Subject;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.springframework.webflow.execution.Event;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.principal.OIDCSubjectIdentifierPrincipal;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+import net.shibboleth.utilities.java.support.collection.Pair;
+
+/** Tests for {@link SimpleOIDCSubjectIdentifierCanonicalization}.*/
+public class SimpleOIDCSubjectIdentifierCanonicalizationTest extends AbstractOIDCTest {
+
+ private SimpleOIDCSubjectIdentifierCanonicalization action;
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ action = new SimpleOIDCSubjectIdentifierCanonicalization();
+ action.setTransforms(Arrays.asList(new Pair<>("^(.+)@osu\\.edu$", "$1")));
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+ action.setActivationCondition(Predicates.alwaysTrue());
+ action.initialize();
+ }
+
+ @Test public void testNoContext() {
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_SUBJECT_C14N_CTX);
+ }
+
+ @Test public void testNoPrincipal() {
+ final Subject subject = new Subject();
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setSubject(subject);
+
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_SUBJECT);
+ Assert.assertNotNull(prc.getSubcontext(SubjectCanonicalizationContext.class, false).getException());
+ }
+
+ @Test public void testMultiPrincipals() {
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new OIDCSubjectIdentifierPrincipal("foo"));
+ subject.getPrincipals().add(new OIDCSubjectIdentifierPrincipal("bar"));
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setSubject(subject);
+
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_SUBJECT);
+ Assert.assertNotNull(prc.getSubcontext(SubjectCanonicalizationContext.class, false).getException());
+ }
+
+ @Test public void testSuccess() {
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new OIDCSubjectIdentifierPrincipal("foo"));
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setSubject(subject);
+
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertProceedEvent(event);
+ final SubjectCanonicalizationContext sc = prc.getSubcontext(SubjectCanonicalizationContext.class, false);
+ Assert.assertEquals(sc.getPrincipalName(), "foo");
+ }
+
+ @Test public void testTransform() {
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new OIDCSubjectIdentifierPrincipal("foo at osu.edu"));
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setSubject(subject);
+
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertProceedEvent(event);
+ final SubjectCanonicalizationContext sc = prc.getSubcontext(SubjectCanonicalizationContext.class, false);
+ Assert.assertEquals(sc.getPrincipalName(), "foo");
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookupTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookupTest.java
new file mode 100644
index 0000000..3746325
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookupTest.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+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.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.protocol.HttpContext;
+import org.mockito.Mockito;
+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.util.StandardCharset;
+import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.UserInfoResponseContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.PlainUserInfoResponse;
+import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.UserInfoResponse;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+
+/**
+ * Tests for the {@link UserInfoEndpointLookup} action.
+ */
+public class UserInfoEndpointLookupTest extends AbstractOIDCTest {
+
+ /** The action to test.*/
+ @Nonnull private UserInfoEndpointLookup action;
+
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+
+ super.setup();
+
+ action = new UserInfoEndpointLookup();
+ action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+ }
+
+ /**
+ * Test the token exchange works using a mocked HTTP client and response.
+ * Does not check the signature is valid. Given the amount of mocking, is not
+ * a very thorough test.
+ *
+ * @throws Exception on error.
+ */
+ @Test
+ public void testLookupSuccess() throws Exception {
+
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final HttpResponse httpResponse = Mockito.mock(HttpResponse.class);
+ final StatusLine statusLine = Mockito.mock(StatusLine.class);
+
+ Mockito.when(httpResponse.getStatusLine()).thenReturn(statusLine);
+
+ Mockito.when(statusLine.getStatusCode()).thenReturn(200);
+ Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(USERINFO_RESPONSE));
+ Mockito.when(httpClient.execute((HttpUriRequest) Mockito.any(), (HttpContext) Mockito.any()))
+ .thenReturn(httpResponse);
+
+ // create new client with mock response
+ action.setHttpClient(httpClient);
+
+ action.setHttpRequestEncoderStrategy(prc -> {
+ URI uri;
+ try {
+ uri = new URIBuilder().setScheme("https")
+ .setHost("op.example.com")
+ .setPath("/userinfo")
+ .build();
+ } catch (final URISyntaxException e) {
+ return null;
+ }
+
+ // Add headers and create request.
+ final RequestBuilder rb = RequestBuilder.post().setUri(uri)
+ .setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.getMimeType())
+ .setCharset(StandardCharset.UTF_8);
+ return rb.build();
+ });
+ action.setHttpResponseDecoderStrategy(response -> {
+ final ObjectMapper mapper = new ObjectMapper();
+ try {
+ final Map<String, Object> responseMap = mapper.readValue(
+ httpResponse.getEntity().getContent(), new TypeReference<Map<String, Object>>() {});
+ final ClaimsSet claims = new ClaimsSet();
+ claims.putAll(responseMap);
+ return new PlainUserInfoResponse(claims);
+ } catch (final UnsupportedOperationException | IOException e) {
+ return null;
+ }
+ });
+
+ action.initialize();
+
+ final Event event = action.execute(src);
+ //Null is success
+ assertNull(event);
+ assertNotNull(prc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class));
+ assertNotNull(prc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class)
+ .getUserInfo());
+ assertNotNull(prc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class)
+ .getUserInfo().getClaimsSet());
+ assertNotNull(prc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class)
+ .getUserInfo().getClaimsSet().getClaim("sub"),"248289761001");
+
+ }
+
+ @Test
+ public void testNullUserInfoResponse() throws Exception {
+
+ final HttpClient httpClient = Mockito.mock(HttpClient.class);
+ final HttpResponse httpResponse = Mockito.mock(HttpResponse.class);
+ final StatusLine statusLine = Mockito.mock(StatusLine.class);
+ Mockito.when(httpResponse.getStatusLine()).thenReturn(statusLine);
+ Mockito.when(statusLine.getStatusCode()).thenReturn(200);
+
+ // create new client with mock response
+ action.setHttpClient(httpClient);
+
+ action.setHttpRequestEncoderStrategy(prc -> {
+ URI uri;
+ try {
+ uri = new URIBuilder().setScheme("https")
+ .setHost("op.example.com")
+ .setPath("/userinfo")
+ .build();
+ } catch (final URISyntaxException e) {
+ return null;
+ }
+
+ // Add headers and create request.
+ final RequestBuilder rb = RequestBuilder.post().setUri(uri)
+ .setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.getMimeType())
+ .setCharset(StandardCharset.UTF_8);
+ return rb.build();
+ });
+ action.setHttpResponseDecoderStrategy(response -> null);
+
+ action.initialize();
+
+ final Event event = action.execute(src);
+
+ //Null is success
+ assertNotNull(event);
+ assertEquals(event.getId(), AuthnEventIds.AUTHN_EXCEPTION);
+
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateResponseStateTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateResponseStateTest.java
new file mode 100644
index 0000000..6cf31ad
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateResponseStateTest.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+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.nimbusds.oauth2.sdk.id.State;
+import com.nimbusds.openid.connect.sdk.AuthenticationResponseParser;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/** Tests for {@link AddRedirectURI}.*/
+public class ValidateResponseStateTest extends AbstractOIDCTest {
+
+ /** The action to test.*/
+ private ValidateResponseState action;
+
+ /** The RPC.*/
+ private RelyingPartyContext rpc;
+
+ /** The profile config.*/
+ private OIDCAuthorizationConfiguration oidcAuthzConfig;
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ action = new ValidateResponseState();
+
+ rpc = prc.getSubcontext(RelyingPartyContext.class, true);
+ oidcAuthzConfig = new OIDCAuthorizationConfiguration();
+ final RelyingPartyConfiguration rpConfig = new RelyingPartyConfiguration();
+ rpc.setProfileConfig(oidcAuthzConfig);
+ rpc.setConfiguration(rpConfig);
+
+ action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)
+ .compose(new WebflowRequestContextProfileRequestContextLookup())));
+
+ action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
+
+ }
+
+ @Test
+ public void testSuccess() throws ComponentInitializationException, URISyntaxException {
+
+ action.initialize();
+ final Event event = action.execute(src);
+
+ assertNull(event);
+
+ }
+
+ @Test
+ public void testNoStateInRequest() throws ComponentInitializationException, URISyntaxException {
+
+ authnRequest.setState(null);
+ action.initialize();
+ final Event event = action.execute(src);
+
+ assertEquals(event.getId(), AuthnEventIds.NO_CREDENTIALS);
+ }
+
+ @Test
+ public void testNoStateInResponse() throws Exception {
+
+ prc.getInboundMessageContext().setMessage(AuthenticationResponseParser.parse(
+ new URI("/idp/profile/Authn/OIDC/RP/callback"
+ + "?state=wrong-state&code=z8C2DCp6sn0D9aGbEqlrFesdPVRXPtDX")));
+ action.initialize();
+ final Event event = action.execute(src);
+
+ assertEquals(event.getId(), AuthnEventIds.NO_CREDENTIALS);
+ }
+
+ @Test
+ public void testStateMismatch() throws ComponentInitializationException, URISyntaxException {
+
+ authnRequest.setState(new State("does-not-match"));
+ action.initialize();
+ final Event event = action.execute(src);
+
+ assertEquals(event.getId(), AuthnEventIds.NO_CREDENTIALS);
+ }
+
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandlerTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandlerTest.java
new file mode 100644
index 0000000..f501729
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandlerTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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.metadata.impl;
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.AbstractOIDCEntityContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.impl.AbstractOIDCTest;
+import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.metadata.criterion.IssuerIDCriterion;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/** Tests for OIDCClientMetadataLookupHandler.*/
+public class OIDCProviderMetadataLookupHandlerTest extends AbstractOIDCTest {
+
+ /** The handler to test.*/
+ private OIDCProviderMetadataLookupHandler handler;
+
+ private AbstractOIDCEntityContext ctx;
+
+ @Override
+ @BeforeMethod
+ public void setup() throws Exception {
+ super.setup();
+ handler = new OIDCProviderMetadataLookupHandler();
+ // Create a resolver that spits out metadata if the issuer criterion matches
+ handler.setProviderMetadataResolver(new ProviderMetadataResolver() {
+ @Override
+ public String getId() {
+ return "mock-resolver";
+ }
+ @Override
+ public OIDCProviderMetadata resolveSingle(final CriteriaSet criteria) throws ResolverException {
+ try {
+ final OIDCProviderMetadata metadata =
+ OIDCProviderMetadata.parse(GOOD_PROVIDER_CONFIGURATION_INFO);
+ if (criteria.get(IssuerIDCriterion.class).getIssuerID().equals(metadata.getIssuer())) {
+ return metadata;
+ }
+ return null;
+ } catch (final ParseException e) {
+ fail(e.getMessage());
+ return null;
+ }
+ }
+ @Override
+ public Iterable<OIDCProviderMetadata> resolve(final CriteriaSet criteria) throws ResolverException {
+ return List.of(resolveSingle(criteria));
+ }
+ });
+ ctx = new AbstractOIDCEntityContext();
+ ctx.setIdentifier("https://op.example.com/");
+ handler.setContextClassLookupStrategy(m -> ctx);
+ }
+
+ @Test
+ public void testLookupSuccess() throws Exception {
+ handler.initialize();
+
+ handler.invoke(prc.getOutboundMessageContext());
+ assertNotNull(ctx.getSubcontext(OIDCProviderMetadataContext.class));
+ assertNotNull(ctx.getSubcontext(OIDCProviderMetadataContext.class).getProviderInformation());
+ assertEquals(ctx.getSubcontext(OIDCProviderMetadataContext.class)
+ .getProviderInformation().getIssuer().getValue(),"https://op.example.com/");
+ }
+
+ @Test
+ public void testLookupCopyExisting() throws Exception {
+
+ handler.setCopyContextStrategy(msg -> {
+ final OIDCProviderMetadataContext ctxt = new OIDCProviderMetadataContext();
+ try {
+ ctxt.setProviderInformation(OIDCProviderMetadata.parse(GOOD_PROVIDER_CONFIGURATION_INFO));
+ } catch (final ParseException e) {
+ return null;
+ }
+ return ctxt;
+ });
+
+ handler.initialize();
+
+ handler.invoke(prc.getOutboundMessageContext());
+ assertNotNull(ctx.getSubcontext(OIDCProviderMetadataContext.class));
+ assertNotNull(ctx.getSubcontext(OIDCProviderMetadataContext.class).getProviderInformation());
+ assertEquals(ctx.getSubcontext(OIDCProviderMetadataContext.class)
+ .getProviderInformation().getIssuer().getValue(),"https://op.example.com/");
+ }
+
+ @Test
+ public void testLookupCopyExisting_NoProviderInformation() throws Exception {
+
+ // Prevent resolver from returning metadata if copy does not work
+ handler.setProviderMetadataResolver(new ProviderMetadataResolver() {
+ @Override
+ public String getId() {
+ return "mock-resolver";
+ }
+ @Override
+ public OIDCProviderMetadata resolveSingle(final CriteriaSet criteria) throws ResolverException {
+ return null;
+ }
+ @Override
+ public Iterable<OIDCProviderMetadata> resolve(final CriteriaSet criteria) throws ResolverException {
+ return List.of(resolveSingle(criteria));
+ }
+ });
+
+ // Do not set provider information
+ handler.setCopyContextStrategy(msg -> new OIDCProviderMetadataContext());
+
+ handler.initialize();
+
+ handler.invoke(prc.getOutboundMessageContext());
+ assertNull(ctx.getSubcontext(OIDCProviderMetadataContext.class));
+
+ }
+
+ @Test
+ public void testLookupCopyExisting_WrongIssuer() throws Exception {
+
+ ctx.setIdentifier("https://wrong-issuer.example.com/");
+ handler.setCopyContextStrategy(msg -> {
+ final OIDCProviderMetadataContext ctxt = new OIDCProviderMetadataContext();
+ try {
+ ctxt.setProviderInformation(OIDCProviderMetadata.parse(GOOD_PROVIDER_CONFIGURATION_INFO));
+ } catch (final ParseException e) {
+ return null;
+ }
+ return ctxt;
+ });
+
+ handler.initialize();
+
+ handler.invoke(prc.getOutboundMessageContext());
+ assertNull(ctx.getSubcontext(OIDCProviderMetadataContext.class));
+
+ }
+
+ @Test
+ public void testLookupNoMetadata() throws Exception {
+
+ handler.setProviderMetadataResolver(new ProviderMetadataResolver() {
+ @Override
+ public String getId() {
+ return "mock-resolver";
+ }
+ @Override
+ public OIDCProviderMetadata resolveSingle(final CriteriaSet criteria) throws ResolverException {
+ return null;
+ }
+ @Override
+ public Iterable<OIDCProviderMetadata> resolve(final CriteriaSet criteria) throws ResolverException {
+ return List.of(resolveSingle(criteria));
+ }
+ });
+
+ handler.initialize();
+
+ handler.invoke(prc.getOutboundMessageContext());
+ assertNull(ctx.getSubcontext(OIDCProviderMetadataContext.class));
+
+ }
+
+ @Test
+ public void testLookupWrongIssuer() throws Exception {
+
+ ctx.setIdentifier("https://wrong-issuer.example.com/");
+
+ handler.initialize();
+
+ handler.invoke(prc.getOutboundMessageContext());
+ assertNull(ctx.getSubcontext(OIDCProviderMetadataContext.class));
+ }
+
+ @Test(expectedExceptions = MessageHandlerException.class)
+ public void testLookupResolverException() throws Exception {
+
+ handler.setProviderMetadataResolver(new ProviderMetadataResolver() {
+ @Override
+ public String getId() {
+ return "mock-resolver";
+ }
+ @Override
+ public OIDCProviderMetadata resolveSingle(final CriteriaSet criteria) throws ResolverException {
+ throw new ResolverException("Resolver exception");
+ }
+ @Override
+ public Iterable<OIDCProviderMetadata> resolve(final CriteriaSet criteria) throws ResolverException {
+ throw new ResolverException("Resolver exception");
+ }
+ });
+
+ handler.initialize();
+
+ handler.invoke(prc.getOutboundMessageContext());
+
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/resources/conf/authn/oidc-rp-credentials.xml b/idp-oidc-rp-impl/src/test/resources/conf/authn/oidc-rp-credentials.xml
index b3e52af..4a925b6 100644
--- a/idp-oidc-rp-impl/src/test/resources/conf/authn/oidc-rp-credentials.xml
+++ b/idp-oidc-rp-impl/src/test/resources/conf/authn/oidc-rp-credentials.xml
@@ -24,16 +24,6 @@
p:resource="%{idp.authn.oidc.rp.client.enc.key:#{null}}" />
</util:list>
- <util:list id="shibboleth.authn.oidc.rp.DefaultRequestObjectKeyTransportEncryptionCredentials">
- <bean parent="shibboleth.authn.oidc.rp.JWKCredential" p:failIfResourceIsNull="false"
- p:resource="%{idp.authn.oidc.rp.client.requestobject.enc.symmetric.kw.key:#{null}}" />
- </util:list>
-
- <util:list id="shibboleth.authn.oidc.rp.DefaultRequestObjectDataEncryptionCredentials">
- <bean parent="shibboleth.authn.oidc.rp.JWKCredential" p:failIfResourceIsNull="false"
- p:resource="%{idp.authn.oidc.rp.client.requestobject.enc.symmetric.cek.key:#{null}}" />
- </util:list>
-
<!-- Default signing credentials -->
<util:list id="shibboleth.authn.oidc.rp.DefaultSigningCredentials">
<bean parent="shibboleth.authn.oidc.rp.JWKCredential" p:failIfResourceIsNull="false"
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list