[java-idp-oidc] branch dev/JOIDC-7 updated: Adapt authorize flow to handle JWT and resource/audience enhancements.
Scott Cantor
cantor.2 at osu.edu
Tue Apr 26 18:15:28 UTC 2022
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch dev/JOIDC-7
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=d097d284ca8bcae277f43ca4773b5cab58df5fc8
The following commit(s) were added to refs/heads/dev/JOIDC-7 by this push:
new d097d284 Adapt authorize flow to handle JWT and resource/audience enhancements.
d097d284 is described below
commit d097d284ca8bcae277f43ca4773b5cab58df5fc8
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Apr 26 14:15:25 2022 -0400
Adapt authorize flow to handle JWT and resource/audience enhancements.
Also restores nonce to access/refresh tokens.
---
.../op/token/support/AccessTokenClaimsSet.java | 1 +
.../op/token/support/RefreshTokenClaimsSet.java | 1 +
.../op/oauth2/profile/impl/BuildAccessToken.java | 6 +-
.../impl/SetAccessTokenToResponseContext.java | 332 ------------------
.../idp/flows/oidc/authorize/authorize-beans.xml | 381 +++++++++++++++------
.../idp/flows/oidc/authorize/authorize-flow.xml | 140 +++++++-
.../shibboleth/idp/flows/oidc/token/token-flow.xml | 2 +-
.../oidc/op/profile/flow/AbstractOidcFlowTest.java | 2 +-
.../oidc/op/profile/flow/AuthorizeFlowTest.java | 219 +++++++++---
.../impl/SetAccessTokenToResponseContextTest.java | 283 ---------------
10 files changed, 588 insertions(+), 779 deletions(-)
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/AccessTokenClaimsSet.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/AccessTokenClaimsSet.java
index 9c24d4c4..81347dbe 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/AccessTokenClaimsSet.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/AccessTokenClaimsSet.java
@@ -184,6 +184,7 @@ public final class AccessTokenClaimsSet extends TokenClaimsSet {
setPrincipal(existing.getPrincipal());
setSubject(existing.getClaimsSet().getSubject());
setACR(existing.getACR() == null ? null : new ACR(existing.getACR()));
+ setNonce(existing.getNonce());
setNotBefore(existing.getNotBefore());
setAuthenticationTime(existing.getAuthenticationTime());
setAudience(existing.getAudience());
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/RefreshTokenClaimsSet.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/RefreshTokenClaimsSet.java
index c3e77403..682363e9 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/RefreshTokenClaimsSet.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/RefreshTokenClaimsSet.java
@@ -137,6 +137,7 @@ public final class RefreshTokenClaimsSet extends TokenClaimsSet {
setSubject(existing.getClaimsSet().getSubject());
setACR(existing.getACR() == null ? null : new ACR(existing.getACR()));
setAuthenticationTime(existing.getAuthenticationTime());
+ setNonce(existing.getNonce());
setRedirectURI(existing.getRedirectURI());
setScope(existing.getScope());
setClaimsRequest(existing.getClaimsRequest());
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/BuildAccessToken.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/BuildAccessToken.java
index 8e627a3c..7460ed66 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/BuildAccessToken.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/BuildAccessToken.java
@@ -454,12 +454,10 @@ public class BuildAccessToken extends AbstractOIDCResponseAction {
try {
if (jwtTokenType) {
accessTokenCtx.setJWT(new PlainJWT(claimsSet.getClaimsSet()));
- log.debug("{} Claims stored to JWT access token: {}", getLogPrefix(), claimsSet.serialize(),
- accessTokenCtx.getJWT());
+ log.debug("{} Claims stored to JWT access token: {}", getLogPrefix(), claimsSet.serialize());
} else {
accessTokenCtx.setOpaque(claimsSet.serialize(dataSealer));
- log.debug("{} Claims '{}' converted to opaque access token: {}", getLogPrefix(), claimsSet.serialize(),
- accessTokenCtx.getOpaque());
+ log.debug("{} Claims converted to opaque access token: {}", getLogPrefix(), claimsSet.serialize());
}
} catch (final DataSealerException e) {
log.error("{} Access Token wrapping failed: {}", getLogPrefix(), e);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContext.java
deleted file mode 100644
index befe031a..00000000
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContext.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.function.Function;
-import java.util.function.Predicate;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.nimbusds.oauth2.sdk.Scope;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
-import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
-
-import net.minidev.json.JSONArray;
-import net.shibboleth.idp.authn.context.SubjectContext;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseConsentContext;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseTokenClaimsContext;
-import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.OIDCAuthenticationResponseContextLookupFunction;
-import net.shibboleth.idp.plugin.oidc.op.token.support.AccessTokenClaimsSet;
-import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
-import net.shibboleth.idp.plugin.oidc.op.token.support.RefreshTokenClaimsSet;
-import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
-import net.shibboleth.idp.profile.IdPEventIds;
-import net.shibboleth.idp.profile.context.navigate.ResponderIdLookupFunction;
-import net.shibboleth.oidc.profile.config.logic.AttributeConsentFlowEnabledPredicate;
-import net.shibboleth.oidc.profile.config.navigate.AccessTokenLifetimeLookupFunction;
-
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.profile.action.ActionSupport;
-
-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.logic.FunctionSupport;
-import net.shibboleth.utilities.java.support.security.DataSealer;
-import net.shibboleth.utilities.java.support.security.DataSealerException;
-import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
-import net.shibboleth.utilities.java.support.security.impl.SecureRandomIdentifierGenerationStrategy;
-
-/**
- * Action that creates a Access Token, and sets it to work context
- * {@link OIDCAuthenticationResponseContext#getAccessToken()} located under
- * {@link ProfileRequestContext#getOutboundMessageContext()}.
- */
-public class SetAccessTokenToResponseContext extends AbstractOIDCResponseAction {
-
- /** Class logger. */
- @Nonnull private Logger log = LoggerFactory.getLogger(SetAccessTokenToResponseContext.class);
-
- /** Data sealer for handling access token. */
- @NonnullAfterInit private DataSealer dataSealer;
-
- /** Authorize Code / Refresh Token the access token is based on. */
- @Nullable private TokenClaimsSet tokenClaimsSet;
-
- /** Strategy used to obtain the response issuer value. */
- @Nonnull private Function<ProfileRequestContext, String> issuerLookupStrategy;
-
- /** Strategy used to obtain the access token lifetime. */
- @Nonnull private Function<ProfileRequestContext,Duration> accessTokenLifetimeLookupStrategy;
-
- /** Predicate used to check if consent is enabled with a given {@link ProfileRequestContext}. */
- @Nonnull
- private Predicate<ProfileRequestContext> consentEnabledPredicate;
-
- /** Access Token lifetime. */
- @Nullable private Duration accessTokenLifetime;
-
- /** Subject context. */
- @Nullable private SubjectContext subjectCtx;
-
- /** The generator to use. */
- @Nullable private IdentifierGenerationStrategy idGenerator;
-
- /** Strategy used to locate the {@link IdentifierGenerationStrategy} to use. */
- @Nonnull private Function<ProfileRequestContext, IdentifierGenerationStrategy> idGeneratorLookupStrategy;
-
- /** Authentication request the token is based on. */
- @Nullable private AuthenticationRequest authenticationRequest;
-
- /** Strategy used to locate the {@link OIDCAuthenticationResponseTokenClaimsContext}. */
- @Nonnull
- private Function<ProfileRequestContext,OIDCAuthenticationResponseTokenClaimsContext>
- tokenClaimsContextLookupStrategy;
-
- /** Strategy used to locate the {@link OIDCAuthenticationResponseConsentContext}. */
- @Nonnull
- private Function<ProfileRequestContext, OIDCAuthenticationResponseConsentContext> consentContextLookupStrategy;
-
- /**
- * Constructor.
- */
- public SetAccessTokenToResponseContext() {
- tokenClaimsContextLookupStrategy =
- new ChildContextLookup<>(OIDCAuthenticationResponseTokenClaimsContext.class).compose(
- new OIDCAuthenticationResponseContextLookupFunction());
- consentContextLookupStrategy =
- new ChildContextLookup<>(OIDCAuthenticationResponseConsentContext.class).compose(
- new OIDCAuthenticationResponseContextLookupFunction());
- accessTokenLifetimeLookupStrategy = new AccessTokenLifetimeLookupFunction();
- consentEnabledPredicate = new AttributeConsentFlowEnabledPredicate();
- issuerLookupStrategy = new ResponderIdLookupFunction();
- idGeneratorLookupStrategy = FunctionSupport.constant(new SecureRandomIdentifierGenerationStrategy());
- }
-
- /**
- * Set the data sealer instance to use.
- *
- * @param sealer data sealer to use
- */
- public void setDataSealer(@Nonnull final DataSealer sealer) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
- }
-
- /**
- * Set the strategy used to locate the {@link OIDCAuthenticationResponseTokenClaimsContext} associated with a given
- * {@link ProfileRequestContext}.
- *
- * @param strategy lookup strategy
- */
- public void setOIDCAuthenticationResponseTokenClaimsContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCAuthenticationResponseTokenClaimsContext> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- tokenClaimsContextLookupStrategy = Constraint.isNotNull(strategy,
- "OIDCAuthenticationResponseTokenClaimsContextt lookup strategy cannot be null");
- }
-
- /**
- * Set the strategy used to locate the {@link OIDCAuthenticationResponseConsentContext} associated with a given
- * {@link ProfileRequestContext}.
- *
- * @param strategy lookup strategy
- */
- public void setOIDCAuthenticationResponseConsentContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCAuthenticationResponseConsentContext> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- consentContextLookupStrategy = Constraint.isNotNull(strategy,
- "OIDCAuthenticationResponseConsentContext lookup strategy cannot be null");
- }
-
- /**
- * Set the strategy used to obtain the access token lifetime.
- *
- * @param strategy lookup strategy
- */
- public void setAccessTokenLifetimeLookupStrategy(@Nonnull final Function<ProfileRequestContext,Duration> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- accessTokenLifetimeLookupStrategy =
- Constraint.isNotNull(strategy, "Access token lifetime lookup strategy cannot be null");
- }
-
- /**
- * Set the strategy used to locate the {@link IdentifierGenerationStrategy} to use.
- *
- * @param strategy lookup strategy
- */
- public void setIdentifierGeneratorLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, IdentifierGenerationStrategy> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- idGeneratorLookupStrategy =
- Constraint.isNotNull(strategy, "Identifier generation strategy cannot be null");
- }
-
- /**
- * Set the strategy used to locate the issuer value to use.
- *
- * @param strategy lookup strategy
- */
- public void setIssuerLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- issuerLookupStrategy = Constraint.isNotNull(strategy, "Issuer lookup strategy cannot be null");
- }
-
- /**
- * Set the predicate used to check if consent is enabled with a given {@link ProfileRequestContext}.
- *
- * @param predicate predicate used to check if consent is enabled with a given {@link ProfileRequestContext}.
- */
- public void setConsentEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> predicate) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
- consentEnabledPredicate =
- Constraint.isNotNull(predicate, "predicate used to check if consent is enabled cannot be null");
- }
-
- /** {@inheritDoc} */
- @Override
- protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
-
- if (dataSealer == null) {
- throw new ComponentInitializationException("DataSealer cannot be null");
- }
- }
-
- // Checkstyle: CyclomaticComplexity OFF
- /** {@inheritDoc} */
- @Override
- protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- if (!super.doPreExecute(profileRequestContext)) {
- return false;
- }
-
- accessTokenLifetime = accessTokenLifetimeLookupStrategy.apply(profileRequestContext);
- if (accessTokenLifetime == null) {
- log.warn("{} No lifetime supplied for access token", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
- return false;
- }
-
- tokenClaimsSet = getOidcResponseContext().getAuthorizationGrantClaimsSet();
- if (tokenClaimsSet != null && !(tokenClaimsSet instanceof RefreshTokenClaimsSet)
- && !(tokenClaimsSet instanceof AuthorizeCodeClaimsSet)) {
- log.error("{} No token grant if of illegal type", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
- return false;
- } else if (tokenClaimsSet == null) {
- /*
- * Alternate path possible only when access token is to be provided by authz endpoint without authorization
- * code This is the case only with "token id_token" response type. Unusually complex initialization.
- */
- subjectCtx = profileRequestContext.getSubcontext(SubjectContext.class, false);
- if (subjectCtx == null) {
- log.error("{} No subject context", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
- return false;
- }
- idGenerator = idGeneratorLookupStrategy.apply(profileRequestContext);
- if (idGenerator == null) {
- log.error("{} No identifier generation strategy", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
- return false;
- }
- if (profileRequestContext.getInboundMessageContext() == null
- || profileRequestContext.getInboundMessageContext().getMessage() == null || !(profileRequestContext
- .getInboundMessageContext().getMessage() instanceof AuthenticationRequest)) {
- log.error("{} No authentication request avalailable", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return false;
- }
- authenticationRequest =
- (AuthenticationRequest) profileRequestContext.getInboundMessageContext().getMessage();
- }
- return true;
- }
- // Checkstyle: CyclomaticComplexity ON
-
- /** {@inheritDoc} */
- @Override
- protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- final Instant dateExp = Instant.now().plus(accessTokenLifetime);
- ClaimsSet claims = null;
- ClaimsSet claimsUI = null;
- final OIDCAuthenticationResponseTokenClaimsContext tokenClaimsCtx =
- tokenClaimsContextLookupStrategy.apply(profileRequestContext);
- if (tokenClaimsCtx != null) {
- claims = tokenClaimsCtx.getClaims();
- claimsUI = tokenClaimsCtx.getUserinfoClaims();
- }
- final AccessTokenClaimsSet claimsSet;
- if (tokenClaimsSet != null) {
- // We may not use original claims as input for scope / delivery claims as they may have been reduced.
- claimsSet = new AccessTokenClaimsSet.Builder(tokenClaimsSet,
- getOidcResponseContext().getScope() != null ? getOidcResponseContext().getScope() : new Scope(),
- claims, claimsUI, Instant.now(), dateExp).build();
- } else {
- final OIDCAuthenticationResponseConsentContext consentCtx =
- consentContextLookupStrategy.apply(profileRequestContext);
- final JSONArray consented = consentCtx != null ? consentCtx.getConsentedAttributes() : null;
- // "token id_token" response type. Access token is not derived from Authorization code / Refresh token..
- claimsSet = new AccessTokenClaimsSet.Builder()
- .setJWTID(idGenerator)
- .setClientID(authenticationRequest.getClientID())
- .setIssuer(issuerLookupStrategy.apply(profileRequestContext))
- .setPrincipal(subjectCtx.getPrincipalName())
- .setSubject(getOidcResponseContext().getSubject())
- .setIssuedAt(Instant.now())
- .setExpiresAt(dateExp)
- .setAuthenticationTime(getOidcResponseContext().getAuthTime())
- .setRedirectURI(getOidcResponseContext().getRedirectURI())
- .setScope(getOidcResponseContext().getScope())
- .setACR(getOidcResponseContext().getAcr())
- .setNonce(authenticationRequest.getNonce())
- .setClaimsRequest(authenticationRequest.getOIDCClaims())
- .setDlClaims(claims)
- .setDlClaimsUI(claimsUI)
- .setConsentedClaims(consented)
- .setConsentEnabled(consentEnabledPredicate.test(profileRequestContext))
- .build();
- }
-
- try {
- getOidcResponseContext().setAccessToken(claimsSet.serialize(dataSealer), accessTokenLifetime);
- log.debug("{} Setting access token {} as {} to response context ", getLogPrefix(), claimsSet.serialize(),
- getOidcResponseContext().getAccessToken());
- } catch (final DataSealerException e) {
- log.error("{} Access Token generation failed {}", getLogPrefix(), e.getMessage());
- ActionSupport.buildEvent(profileRequestContext, EventIds.UNABLE_TO_ENCRYPT);
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
index bb60f197..61033f4a 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
@@ -45,9 +45,6 @@
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestedClaimsToResponseContext" scope="prototype"
p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
- <bean id="VerifyRequestedSubjectIdentifier"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.VerifyRequestedSubjectIdentifier" scope="prototype" />
-
<bean id="PopulatePostAuthnInterceptContext"
class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext" scope="prototype"
p:availableFlows="#{@'shibboleth.ProfileInterceptorFlowDescriptorManager'.getComponents()}"
@@ -190,35 +187,6 @@
<bean id="AuthenticationRequestAudienceLookupStrategy"
class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestAudienceLookupFunction" />
- <bean id="PopulateIDTokenSignatureSigningParameters"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCSignatureSigningParameters " scope="prototype"
- c:strategy-ref="shibboleth.MessageContextLookup.Inbound"
- p:configurationLookupStrategy-ref="shibboleth.SignatureSigningConfigurationLookup"
- p:signatureSigningParametersResolver-ref="shibboleth.oidc.TokenSignatureSigningParametersResolver">
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
- </property>
- <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>
-
- <bean id="PopulateIDTokenEncryptionParameters"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCEncryptionParameters" scope="prototype"
- p:configurationLookupStrategy-ref="shibboleth.EncryptionConfigurationLookup"
- p:encryptionParametersResolver-ref="shibboleth.oidc.EncryptionParametersResolver">
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
- </property>
- </bean>
-
<bean id="shibboleth.oidc.EncryptionParametersResolver"
class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver"
p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" p:keyFetchInterval="%{idp.oidc.jwksuri.fetchInterval:PT30M}" />
@@ -227,6 +195,171 @@
class="org.opensaml.storage.impl.client.PopulateClientStorageLoadContext" scope="prototype"
p:storageServices="#{ getObject('shibboleth.ClientStorageServices') ?: getObject('shibboleth.DefaultClientStorageServices') }" />
+ <bean id="RevokeConsent" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.RevokeConsent" scope="prototype" />
+
+ <bean id="SetAuthenticationTimeToResponseContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthenticationTimeToResponseContext" scope="prototype" />
+
+ <bean id="SetSectorIdentifierForAttributeResolution"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSectorIdentifierForAttributeResolution" scope="prototype" />
+
+ <bean id="SetAuthenticationContextClassReferenceToResponseContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthenticationContextClassReferenceToResponseContext"
+ scope="prototype" />
+
+ <!--
+ Do a metadata lookup for the primary audience of the token for encryption purposes.
+ Contexts are stored under the outbound MessageContext, including the new RelyingPartyContext.
+ -->
+
+ <bean id="AudienceOIDCMetadataLookup" class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor"
+ scope="prototype" c:executionDirection="OUTBOUND">
+ <constructor-arg name="messageHandler">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.profile.impl.OIDCMetadataLookupHandler" scope="prototype">
+ <property name="clientInformationResolver">
+ <ref bean="shibboleth.ClientInformationResolver" />
+ </property>
+ <property name="clientIDLookupStrategy">
+ <ref bean="AudienceClientIDLookupStrategy" />
+ </property>
+ </bean>
+ </constructor-arg>
+ </bean>
+
+ <bean id="AudienceClientIDLookupStrategy"
+ class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.AudienceClientIDLookupFunction" />
+
+ <bean id="InitializeAudienceRelyingPartyContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeRelyingPartyContext" scope="prototype"
+ p:relyingPartyContextCreationStrategy-ref="AudienceRelyingPartyCreationStrategy"
+ p:oidcMetadataContextLookupStrategy-ref="LookupOutboundOIDCMetadataContext"
+ p:clientIDLookupStrategy-ref="AudienceClientIDLookupStrategy"
+ p:inbound="false" />
+
+ <bean id="LookupOutboundOIDCMetadataContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultOIDCMetadataContextLookupFunction"
+ p:inbound="false" />
+
+ <bean id="AudienceRelyingPartyCreationStrategy" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookupOrCreate.RelyingPartyContext"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+
+ <bean id="AudienceSAMLProtocolAndRole"
+ class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
+ c:executionDirection="OUTBOUND"
+ p:activationCondition-ref="%{idp.oidc.metadata.saml:shibboleth.Conditions.TRUE}">
+ <constructor-arg name="messageHandler">
+ <bean class="org.opensaml.saml.common.binding.impl.SAMLProtocolAndRoleHandler" scope="prototype"
+ p:protocol="http://openid.net/specs/openid-connect-core-1_0.html"
+ p:role-ref="shibboleth.MetadataLookup.Role"
+ p:entityContextClass="org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext"/>
+ </constructor-arg>
+ </bean>
+
+ <bean id="SetAudienceEntityIdToSAMLPeerEntityContext"
+ class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
+ c:executionDirection="OUTBOUND"
+ p:errorEvent="#{T(org.opensaml.profile.action.EventIds).INVALID_MSG_CTX}"
+ p:activationCondition-ref="%{idp.oidc.metadata.saml:shibboleth.Conditions.TRUE}">
+ <constructor-arg name="messageHandler">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oauth2.messaging.impl.SetEntityIdToSAMLPeerEntityContext"
+ scope="prototype"
+ p:clientIDLookupStrategy-ref="AudienceClientIDLookupStrategy"
+ p:entityContextClass="org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext" />
+ </constructor-arg>
+ </bean>
+
+ <bean id="AudienceSAMLMetadataLookup"
+ class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
+ c:executionDirection="OUTBOUND"
+ p:activationCondition-ref="%{idp.oidc.metadata.saml:shibboleth.Conditions.TRUE}">
+ <constructor-arg name="messageHandler">
+ <bean class="org.opensaml.saml.common.binding.impl.SAMLMetadataLookupHandler" scope="prototype"
+ p:entityContextClass="org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext">
+ <property name="roleDescriptorResolver">
+ <bean class="org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver"
+ c:mdResolver-ref="shibboleth.MetadataResolver" />
+ </property>
+ </bean>
+ </constructor-arg>
+ </bean>
+
+ <bean id="PopulateAudienceOIDCMetadataContext"
+ class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
+ c:executionDirection="OUTBOUND"
+ p:activationCondition-ref="%{idp.oidc.metadata.saml:shibboleth.Conditions.TRUE}">
+ <constructor-arg name="messageHandler">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oauth2.messaging.impl.PopulateOIDCMetadataContext"
+ scope="prototype" />
+ </constructor-arg>
+ </bean>
+
+ <bean id="InitializeAudienceRelyingPartyContextFromSAMLPeer"
+ class="net.shibboleth.idp.saml.profile.impl.InitializeRelyingPartyContextFromSAMLPeer" scope="prototype"
+ p:relyingPartyContextCreationStrategy-ref="AudienceRelyingPartyCreationStrategy"
+ p:peerEntityContextLookupStrategy-ref="LookupOutboundPeerEntityContext" />
+
+ <bean id="LookupOutboundPeerEntityContext" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookup.SAMLPeerEntityContext"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound"/>
+
+ <bean id="SelectAudienceRelyingPartyConfiguration"
+ class="net.shibboleth.idp.profile.impl.SelectRelyingPartyConfiguration" scope="prototype"
+ p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy"
+ p:relyingPartyConfigurationResolver-ref="shibboleth.CriteriaRelyingPartyConfigurationResolver" />
+
+ <bean id="SelectAudienceProfileConfiguration"
+ class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration" scope="prototype"
+ p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy"
+ p:profileId="#{T(net.shibboleth.oidc.profile.oauth2.config.OAuth2TokenAudienceConfiguration).PROFILE_ID}" />
+
+ <bean id="ResolveAttributesForAudience" class="net.shibboleth.idp.profile.impl.ResolveAttributes" scope="prototype"
+ c:resolverService-ref="shibboleth.AttributeResolverService"
+ p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
+ p:maskFailures="%{idp.service.attribute.resolver.maskFailures:true}"
+ p:issuerLookupStrategy-ref="AudienceIssuerLookupFunction" />
+
+ <bean id="FilterAttributesForAudience" class="net.shibboleth.idp.profile.impl.FilterAttributes" scope="prototype"
+ c:filterService-ref="shibboleth.AttributeFilterService"
+ p:maskFailures="%{idp.service.attribute.filter.maskFailures:true}"
+ p:issuerLookupStrategy-ref="AudienceIssuerLookupFunction"
+ p:proxiedRequesterContextLookupStrategy-ref="AudienceProxiedRequesterLookupFunction"
+ p:proxiedRequesterMetadataContextLookupStrategy-ref="LookupOutboundSAMLEntityContext" />
+
+ <bean id="AudienceIssuerLookupFunction"
+ class="net.shibboleth.idp.profile.context.navigate.ResponderIdLookupFunction"
+ p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy" />
+
+ <bean id="AudienceProxiedRequesterLookupFunction" parent="shibboleth.Functions.Compose">
+ <constructor-arg name="g">
+ <bean class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+ c:type="#{ T(org.opensaml.profile.context.ProxiedRequesterContext) }" />
+ </constructor-arg>
+ <constructor-arg name="f">
+ <ref bean="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+
+ <bean id="LookupOutboundSAMLEntityContext" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookup.SAMLMetadataContext"
+ c:f-ref="LookupOutboundPeerEntityContext"/>
+
+ <!-- Back to token prep. -->
+
+ <bean id="SetSubjectToResponseContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSubjectToResponseContext" scope="prototype">
+ <property name="subjectLookupStrategy">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.AttributeResolutionSubjectLookupFunction"
+ p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
+ </property>
+ <property name="subjectTypeLookupStrategy">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultSubjectTypeStrategy" />
+ </property>
+ </bean>
+
+ <bean id="VerifyRequestedSubjectIdentifier"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.VerifyRequestedSubjectIdentifier" scope="prototype" />
+
<bean id="SetTokenDeliveryAttributesToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetTokenDeliveryAttributesToResponseContext" scope="prototype"
p:transcoderRegistry-ref="shibboleth.AttributeRegistryService">
@@ -245,8 +378,6 @@
<bean id="SetConsentToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetConsentToResponseContext" scope="prototype" />
- <bean id="RevokeConsent" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.RevokeConsent" scope="prototype" />
-
<bean id="SetAuthorizationCodeToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthorizationCodeToResponseContext" scope="prototype"
p:dataSealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}">
@@ -259,106 +390,147 @@
</property>
</bean>
- <bean id="SetAccessTokenToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAccessTokenToResponseContext" scope="prototype"
- p:dataSealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}">
- <property name="activationCondition">
- <ref bean="AccessTokenRequested" />
+ <!-- If access token is strictly for UserInfo endpoint... -->
+
+ <bean id="PopulateUserInfoAccessTokenSignatureSigningParameters"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCSignatureSigningParameters"
+ scope="prototype"
+ c:strategy-ref="shibboleth.MessageContextLookup.Inbound"
+ 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>
</bean>
- <bean id="SetSubjectToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSubjectToResponseContext" scope="prototype">
- <property name="subjectLookupStrategy">
- <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.AttributeResolutionSubjectLookupFunction"
- p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
- </property>
- <property name="subjectTypeLookupStrategy">
- <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultSubjectTypeStrategy" />
+ <bean id="BuildOIDCAccessToken"
+ class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.BuildAccessToken" scope="prototype"
+ p:dataSealer="#{getObject('%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim())}"
+ p:clientIDLookupStrategy-ref="RequestClientIDLookup" />
+
+ <bean id="RequestClientIDLookup" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ClientIDLookupStrategy"
+ c:f-ref="shibboleth.MessageContextLookup.Inbound" />
+
+ <bean id="SignOIDCAccessToken"
+ class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.SignAccessToken" scope="prototype"
+ p:typeHeader="at+jwt">
+ <property name="securityParametersLookupStrategy">
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookup.SecurityParameters"
+ c:f-ref="shibboleth.ChildLookup.RelyingParty" />
</property>
</bean>
+
+ <bean id="SetOAuthAccessTokenToResponseContext"
+ class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.SetAccessTokenToResponseContext"
+ scope="prototype" />
- <bean id="SetAuthenticationTimeToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthenticationTimeToResponseContext" scope="prototype" />
-
- <bean id="SetSectorIdentifierForAttributeResolution"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSectorIdentifierForAttributeResolution" scope="prototype" />
+ <!-- If access token is also for third-party resource... -->
- <bean id="SetAuthenticationContextClassReferenceToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthenticationContextClassReferenceToResponseContext"
- scope="prototype" />
+ <bean id="PopulateThirdPartyAccessTokenSignatureSigningParameters"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCSignatureSigningParameters"
+ scope="prototype"
+ c:strategy-ref="shibboleth.MessageContextLookup.Outbound"
+ p:configurationLookupStrategy-ref="shibboleth.SignatureSigningConfigurationLookup"
+ p:signatureSigningParametersResolver-ref="shibboleth.oidc.TokenSignatureSigningParametersResolver"
+ p:securityParametersContextLookupStrategy-ref="AudienceSecurityParametersCreationStrategy" />
+
+ <bean id="AudienceSecurityParametersCreationStrategy" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookupOrCreate.SecurityParameters"
+ c:f-ref="AudienceRelyingPartyCreationStrategy" />
+
+ <bean id="AddAttributeClaimsToAccessToken"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAttributesToClaimsSet" scope="prototype"
+ p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
+ p:responseClaimsSetLookupStrategy-ref="AccessTokenClaimsSetLookupFunction"
+ p:reservedClaimNames="#{getObject('shibboleth.oidc.AccessTokenReservedClaimNames') ?: getObject('shibboleth.oidc.DefaultAccessTokenReservedClaimNames')}" />
+
+ <bean id="AccessTokenClaimsSetLookupFunction"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.AccessTokenClaimsSetLookupFunction"
+ p:autoCreate="true" />
+
+ <bean id="BuildAccessToken"
+ class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.BuildAccessToken" scope="prototype"
+ p:dataSealer="#{getObject('%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim())}"
+ p:issuerLookupStrategy-ref="AudienceIssuerLookupFunction"
+ p:clientIDLookupStrategy-ref="RequestClientIDLookup"
+ p:accessTokenTypeLookupStrategy-ref="AccessTokenTypeLookupFunction"
+ p:accessTokenLifetimeLookupStrategy-ref="AccessTokenLifetimeLookupFunction" />
+
+ <bean id="AccessTokenTypeLookupFunction"
+ class="net.shibboleth.oidc.profile.config.navigate.AccessTokenTypeLookupFunction"
+ p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy" />
+
+ <bean id="AccessTokenLifetimeLookupFunction"
+ class="net.shibboleth.oidc.profile.config.navigate.AccessTokenLifetimeLookupFunction"
+ p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy" />
+
+ <bean id="SignAccessToken"
+ class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.SignAccessToken" scope="prototype"
+ p:securityParametersLookupStrategy-ref="AudienceSecurityParametersCreationStrategy"
+ p:typeHeader="at+jwt" />
+
+ <!-- ID token actions. -->
- <bean id="AddIDTokenShell" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddIDTokenShell" scope="prototype">
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
+ <bean id="PopulateIDTokenSignatureSigningParameters"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCSignatureSigningParameters " scope="prototype"
+ c:strategy-ref="shibboleth.MessageContextLookup.Inbound"
+ 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>
+ <bean id="PopulateIDTokenEncryptionParameters"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCEncryptionParameters" scope="prototype"
+ p:configurationLookupStrategy-ref="shibboleth.EncryptionConfigurationLookup"
+ p:encryptionParametersResolver-ref="shibboleth.oidc.EncryptionParametersResolver" />
+
+ <bean id="AddIDTokenShell" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddIDTokenShell" scope="prototype" />
+
<bean id="AddAttributeClaimsToIDToken"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAttributesToClaimsSet" scope="prototype"
p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
- p:reservedClaimNames="#{getObject('shibboleth.oidc.IDTokenReservedClaimNames') ?: getObject('shibboleth.oidc.DefaultIDTokenReservedClaimNames')}">
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
- </property>
- </bean>
+ p:reservedClaimNames="#{getObject('shibboleth.oidc.IDTokenReservedClaimNames') ?: getObject('shibboleth.oidc.DefaultIDTokenReservedClaimNames')}" />
<bean id="AddAuthTimeToIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAuthTimeToIDToken"
- scope="prototype">
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
- </property>
- </bean>
+ scope="prototype" />
- <bean id="AddAcrToIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAcrToIDToken" scope="prototype">
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
- </property>
- </bean>
+ <bean id="AddAcrToIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAcrToIDToken"
+ scope="prototype" />
<bean id="AddNonceToIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddNonceToIDToken"
- scope="prototype">
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
- </property>
- </bean>
+ scope="prototype" />
<bean id="AddAccessTokenHashToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAccessTokenHashToIDToken" scope="prototype">
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAccessTokenHashToIDToken" scope="prototype"
+ p:activationCondition-ref="AccessTokenRequested">
<property name="securityParametersLookupStrategy">
<bean parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookup.SecurityParameters"
c:f-ref="shibboleth.ChildLookup.RelyingParty" />
</property>
- <property name="activationCondition">
- <bean parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <ref bean="AccessTokenRequested" />
- </constructor-arg>
- <constructor-arg>
- <ref bean="IDTokenRequested" />
- </constructor-arg>
- </bean>
- </property>
</bean>
<bean id="AddAuthorizationCodeHashToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAuthorizationCodeHashToIDToken" scope="prototype">
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAuthorizationCodeHashToIDToken" scope="prototype"
+ p:activationCondition-ref="AuthorizeCodeRequested">
<property name="securityParametersLookupStrategy">
<bean parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookup.SecurityParameters"
c:f-ref="shibboleth.ChildLookup.RelyingParty" />
</property>
- <property name="activationCondition">
- <bean parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <ref bean="AuthorizeCodeRequested" />
- </constructor-arg>
- <constructor-arg>
- <ref bean="IDTokenRequested" />
- </constructor-arg>
- </bean>
- </property>
</bean>
<bean id="SignIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SignIDToken" scope="prototype">
@@ -367,17 +539,10 @@
c:g-ref="shibboleth.ChildLookup.SecurityParameters"
c:f-ref="shibboleth.ChildLookup.RelyingParty" />
</property>
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
- </property>
</bean>
<bean id="EncryptIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.EncryptProcessedToken"
- scope="prototype">
- <property name="activationCondition">
- <ref bean="IDTokenRequested" />
- </property>
- </bean>
+ scope="prototype" />
<bean id="UpdateSessionWithSPSession"
class="net.shibboleth.idp.session.impl.UpdateSessionWithSPSession" scope="prototype"
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
index 7578912b..48096df1 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
@@ -53,8 +53,6 @@
<evaluate expression="ValidateAudience" />
<evaluate expression="SetRequestedClaimsToResponseContext" />
<evaluate expression="SetRequestedSubjectToResponseContext" />
- <evaluate expression="PopulateIDTokenSignatureSigningParameters" />
- <evaluate expression="PopulateIDTokenEncryptionParameters" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="PopulateClientStorageLoadContext" />
</action-state>
@@ -87,17 +85,81 @@
<action-state id="SetAuthenticationInformationToResponseContext">
<evaluate expression="SetAuthenticationContextClassReferenceToResponseContext" />
<evaluate expression="SetAuthenticationTimeToResponseContext" />
+ <evaluate expression="SetSectorIdentifierForAttributeResolution" />
<evaluate expression="'proceed'" />
- <transition on="proceed" to="AttributeResolution" />
+ <transition on="proceed" to="CheckForAudience" />
</action-state>
- <action-state id="AttributeResolution">
- <evaluate expression="SetSectorIdentifierForAttributeResolution" />
+ <!-- Audience may or may not be a factor. -->
+ <decision-state id="CheckForAudience">
+ <if test="opensamlProfileRequestContext.getOutboundMessageContext().getSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).getAudience().isEmpty()"
+ then="AttributeResolutionForClient"
+ else="LookupAudienceMetadata" />
+ </decision-state>
+
+ <!-- May need to add a second Relying Party for the primary resource/audience. -->
+
+ <action-state id="LookupAudienceMetadata">
+ <evaluate expression="AudienceOIDCMetadataLookup" />
+ <evaluate expression="InitializeAudienceRelyingPartyContext" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="CheckIfAudienceFoundFromClientInformationService" />
+ </action-state>
+
+ <decision-state id="CheckIfAudienceFoundFromClientInformationService">
+ <if test="opensamlProfileRequestContext.getOutboundMessageContext().containsSubcontext(T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext))"
+ then="SelectAudienceProfileConfiguration" else="LookupAudienceSAMLMetadata" />
+ </decision-state>
+
+ <action-state id="LookupAudienceSAMLMetadata">
+ <evaluate expression="AudienceSAMLProtocolAndRole" />
+ <evaluate expression="SetAudienceEntityIdToSAMLPeerEntityContext" />
+ <evaluate expression="AudienceSAMLMetadataLookup" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="CheckIfAudienceFoundFromSAMLMetadata" />
+ </action-state>
+
+ <decision-state id="CheckIfAudienceFoundFromSAMLMetadata">
+ <if test="opensamlProfileRequestContext.getOutboundMessageContext().containsSubcontext(T(org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext)) and opensamlProfileRequestContext.getOutboundMessageContext().getSubcontext(T(org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext)).containsSubcontext(T(org.opensaml.saml.common.messaging.context.SAMLMetadataContext))"
+ then="PopulateAudienceOIDCMetadataContextFromSAML"
+ else="SelectAudienceProfileConfiguration" />
+ </decision-state>
+
+ <action-state id="PopulateAudienceOIDCMetadataContextFromSAML">
+ <evaluate expression="PopulateAudienceOIDCMetadataContext" />
+ <evaluate expression="InitializeAudienceRelyingPartyContextFromSAMLPeer" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="SelectAudienceProfileConfiguration" />
+ </action-state>
+
+ <action-state id="SelectAudienceProfileConfiguration">
+ <evaluate expression="SelectAudienceRelyingPartyConfiguration" />
+ <evaluate expression="SelectAudienceProfileConfiguration" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="AttributeResolutionForAudience" />
+ </action-state>
+
+ <action-state id="AttributeResolutionForClient">
<evaluate expression="ResolveAttributes" />
<evaluate expression="FilterAttributes" />
<evaluate expression="RevokeConsent" />
<evaluate expression="PopulatePostAuthnInterceptContext" />
<evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="CheckPostAuthnInterceptContext" />
+ </action-state>
+
+ <action-state id="AttributeResolutionForAudience">
+ <evaluate expression="ResolveAttributesForAudience" />
+ <evaluate expression="FilterAttributesForAudience" />
+ <evaluate expression="RevokeConsent" />
+ <evaluate expression="PopulatePostAuthnInterceptContext" />
+ <evaluate expression="'proceed'" />
+
<transition on="proceed" to="CheckPostAuthnInterceptContext" />
</action-state>
@@ -117,19 +179,75 @@
<evaluate expression="SetSubjectToResponseContext" />
<evaluate expression="VerifyRequestedSubjectIdentifier" />
<evaluate expression="'proceed'" />
- <transition on="proceed" to="BuildTokens" />
+
+ <transition on="proceed" to="BuildCode" />
</action-state>
- <action-state id="BuildTokens">
+ <action-state id="BuildCode">
<evaluate expression="SetTokenDeliveryAttributesToResponseContext" />
<evaluate expression="SetConsentToResponseContext" />
<evaluate expression="SetAuthorizationCodeToResponseContext" />
- <evaluate expression="SetAccessTokenToResponseContext" />
<evaluate expression="'proceed'" />
- <transition on="proceed" to="BuildResponse" />
+
+ <transition on="proceed" to="CheckIfAccessTokenNeeded" />
+ </action-state>
+
+ <decision-state id="CheckIfAccessTokenNeeded">
+ <if test="AccessTokenRequested.test(opensamlProfileRequestContext)"
+ then="CheckTokenRequirements"
+ else="CheckIfIDTokenNeeded" />
+ </decision-state>
+
+ <decision-state id="CheckTokenRequirements">
+ <if test="opensamlProfileRequestContext.getOutboundMessageContext().getSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).getAudience().isEmpty()"
+ then="BuildTokensForUserInfoAccess"
+ else="BuildTokensForThirdPartyAccess" />
+ </decision-state>
+
+ <!--
+ Note no JWT encryption here. The token shouldn't even be a JWT, but even if it is,
+ the only audience is us, and the client can't be expected to decrypt it, so it
+ wouldn't be usable. If it were encrypted to our key then there would be no point to
+ allowing it to be a JWT.
+
+ Note also no attribute claims are added to the access token since that isn't a proper
+ delivery mechanism for claims to the OIDC client.
+ -->
+ <action-state id="BuildTokensForUserInfoAccess">
+ <evaluate expression="PopulateUserInfoAccessTokenSignatureSigningParameters" />
+ <evaluate expression="BuildOIDCAccessToken" />
+ <evaluate expression="SignOIDCAccessToken" />
+ <evaluate expression="SetOAuthAccessTokenToResponseContext" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="CheckIfIDTokenNeeded" />
+ </action-state>
+
+ <!--
+ This includes OIDC use cases and all grant types but the primary audience
+ for the access token is the resource/audience. Encryption remains impossible until
+ this supports pure OAuth scenarios.
+ -->
+ <action-state id="BuildTokensForThirdPartyAccess">
+ <evaluate expression="PopulateThirdPartyAccessTokenSignatureSigningParameters" />
+ <evaluate expression="AddAttributeClaimsToAccessToken" />
+ <evaluate expression="BuildAccessToken" />
+ <evaluate expression="SignAccessToken" />
+ <evaluate expression="SetOAuthAccessTokenToResponseContext" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="CheckIfIDTokenNeeded" />
</action-state>
- <action-state id="BuildResponse">
+ <decision-state id="CheckIfIDTokenNeeded">
+ <if test="IDTokenRequested.test(opensamlProfileRequestContext)"
+ then="BuildIDToken"
+ else="PopulateClientStorageSaveContext" />
+ </decision-state>
+
+ <action-state id="BuildIDToken">
+ <evaluate expression="PopulateIDTokenSignatureSigningParameters" />
+ <evaluate expression="PopulateIDTokenEncryptionParameters" />
<evaluate expression="AddIDTokenShell" />
<evaluate expression="AddAttributeClaimsToIDToken" />
<evaluate expression="AddAuthTimeToIDToken" />
@@ -139,12 +257,12 @@
<evaluate expression="AddAuthorizationCodeHashToIDToken" />
<evaluate expression="SignIDToken" />
<evaluate expression="EncryptIDToken" />
- <evaluate expression="UpdateSessionWithSPSession" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="PopulateClientStorageSaveContext" />
</action-state>
<action-state id="PopulateClientStorageSaveContext">
+ <evaluate expression="UpdateSessionWithSPSession" />
<evaluate expression="PopulateClientStorageSaveContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="ClientStorageSave" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
index f1bba542..a2be67eb 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
@@ -85,7 +85,7 @@
<transition on="proceed" to="LookupAudienceMetadata" />
</action-state>
- <!-- For client credentials grant, need to add a second Relying Party for the primary resource/audience. -->
+ <!-- May need to add a second Relying Party for the primary resource/audience. -->
<action-state id="LookupAudienceMetadata">
<evaluate expression="AudienceOIDCMetadataLookup" />
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
index b5a6b294..be7781d1 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
@@ -243,7 +243,7 @@ public abstract class AbstractOidcFlowTest extends AbstractFlowTest {
metadata.setIDTokenJWEEnc(encMethod);
metadata.setTokenEndpointAuthMethod(tokenEndpointMethod);
metadata.setUserInfoJWSAlg(userInfoSigAlg);
- metadata.setCustomField("audience", List.of("https://rp.example.org", "https://rp2.example.org"));
+ metadata.setCustomField("audience", List.of("https://rp.example.org", "https://rp2.example.org", "https://resource.example.org"));
final OIDCClientInformation information;
if (publicKey == null) {
information = new OIDCClientInformation(new ClientID(clientId), new Date(),
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
index 62bb2070..13fb2f9d 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
@@ -18,9 +18,12 @@
package net.shibboleth.idp.plugin.oidc.op.profile.flow;
import java.io.IOException;
+import java.text.ParseException;
import java.time.Duration;
import java.time.Instant;
+import java.util.Collections;
import java.util.Date;
+import java.util.List;
import org.opensaml.storage.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -36,13 +39,13 @@ import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.SignedJWT;
-import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
import com.nimbusds.openid.connect.sdk.claims.ClaimRequirement;
import com.nimbusds.openid.connect.sdk.claims.ClaimsSetRequest;
+import net.shibboleth.idp.plugin.oidc.op.token.support.AccessTokenClaimsSet;
import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
import net.shibboleth.idp.session.SessionException;
import net.shibboleth.oidc.profile.core.OidcError;
@@ -55,6 +58,8 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
public static final String FLOW_ID = "oidc/authorize";
+ String resource = "https://resource.example.org";
+ String issuer = "https://op.example.org";
String redirectUri = "https://example.org/cb";
String clientId = "mockClientId";
String clientSecret = "mockClientSecretmockClientSecretmockClientSecretmockClientSecretmockClientSecret";
@@ -74,7 +79,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlow() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlow() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri);
@@ -92,7 +97,25 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowNoOpenid() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowAndResource() throws IOException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&resource=" + resource +
+ "&redirect_uri=" + redirectUri);
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNull(successResponse.getIDToken());
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithAuthorizationCodeFlowNoOpenid() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code&scope=profile&redirect_uri="
+ redirectUri);
@@ -105,7 +128,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithImplicitFlowNoNonce() throws IOException, ParseException, SessionException {
+ public void testWithImplicitFlowNoNonce() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile&redirect_uri="
+ redirectUri);
@@ -118,7 +141,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithImplicitFlow() throws IOException, ParseException, SessionException {
+ public void testWithImplicitFlow() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile&redirect_uri="
+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
@@ -136,7 +159,25 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithImplicitTokenFlow() throws IOException, ParseException, SessionException {
+ public void testWithImplicitFlowAndResource() throws IOException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile&resource=" + resource
+ + "&redirect_uri=" + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithImplicitTokenFlow() throws IOException, SessionException, DataSealerException, ParseException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=id_token+token&scope=openid%20profile"
+ "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
@@ -151,10 +192,37 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNotNull(successResponse.getIDToken());
Assert.assertNotNull(successResponse.getAccessToken());
Assert.assertNull(successResponse.getAuthorizationCode());
+
+ final AccessTokenClaimsSet token =
+ AccessTokenClaimsSet.parse(successResponse.getAccessToken().getValue(), getDataSealer());
+ Assert.assertEquals(token.getAudience(), Collections.singletonList(issuer));
+ Assert.assertNull(token.getClaimsSet().getStringClaim("eduPersonScopedAffiliation"));
}
@Test
- public void testWithImplicitTokenFlowNoNonce() throws IOException, ParseException, SessionException {
+ public void testWithImplicitTokenFlowAndResource() throws IOException, SessionException, ParseException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=id_token+token&scope=openid%20profile"
+ + "&resource=" + resource + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNotNull(successResponse.getAccessToken());
+ Assert.assertNull(successResponse.getAuthorizationCode());
+
+ final JWTClaimsSet token = SignedJWT.parse(successResponse.getAccessToken().getValue()).getJWTClaimsSet();
+ Assert.assertEquals(token.getAudience(), List.of(resource, issuer));
+ Assert.assertNotNull(token.getStringClaim("eduPersonScopedAffiliation"));
+ }
+
+ @Test
+ public void testWithImplicitTokenFlowNoNonce() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=id_token+token&scope=openid%20profile"
+ "&redirect_uri="+ redirectUri);
@@ -167,7 +235,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithImplicitFlowNoOpenIdScope() throws IOException, ParseException, SessionException {
+ public void testWithImplicitFlowNoOpenIdScope() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=id_token&scope=profile&redirect_uri="
+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
@@ -180,7 +248,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithHybridIdTokenFlow() throws IOException, ParseException, SessionException {
+ public void testWithHybridIdTokenFlow() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code+id_token&scope=openid%20profile"
+ "&redirect_uri=" + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
@@ -198,7 +266,25 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithHybridIdTokenFlowNoNonce() throws IOException, ParseException, SessionException {
+ public void testWithHybridIdTokenFlowAndResource() throws IOException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code+id_token&scope=openid%20profile"
+ + "&resource=" + resource + "&redirect_uri=" + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithHybridIdTokenFlowNoNonce() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code+id_token&scope=openid%20profile"
+ "&redirect_uri=" + redirectUri);
@@ -211,7 +297,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithHybridTokenFlow() throws IOException, ParseException, SessionException {
+ public void testWithHybridTokenFlow() throws IOException, SessionException, ParseException, DataSealerException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code+token&scope=openid%20profile"
+ "&redirect_uri="+ redirectUri);
@@ -227,10 +313,38 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNotNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+
+ final AccessTokenClaimsSet token =
+ AccessTokenClaimsSet.parse(successResponse.getAccessToken().getValue(), getDataSealer());
+ Assert.assertEquals(token.getAudience(), Collections.singletonList(issuer));
+ Assert.assertNull(token.getClaimsSet().getStringClaim("eduPersonScopedAffiliation"));
}
@Test
- public void testWithHybridIdTokenTokenFlow() throws IOException, ParseException, SessionException {
+ public void testWithHybridTokenFlowAndResource() throws IOException, SessionException, ParseException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code+token&scope=openid%20profile"
+ + "&resource=" + resource + "&redirect_uri="+ redirectUri);
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ // success response as id_token is not involved and thus nonce is not required
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNull(successResponse.getIDToken());
+ Assert.assertNotNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+
+ final JWTClaimsSet token = SignedJWT.parse(successResponse.getAccessToken().getValue()).getJWTClaimsSet();
+ Assert.assertEquals(token.getAudience(), List.of(resource, issuer));
+ Assert.assertNotNull(token.getStringClaim("eduPersonScopedAffiliation"));
+ }
+
+ @Test
+ public void testWithHybridIdTokenTokenFlow() throws IOException, SessionException, ParseException, DataSealerException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code+id_token+token&scope=openid%20profile"
+ "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
@@ -245,10 +359,37 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNotNull(successResponse.getIDToken());
Assert.assertNotNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+
+ final AccessTokenClaimsSet token =
+ AccessTokenClaimsSet.parse(successResponse.getAccessToken().getValue(), getDataSealer());
+ Assert.assertEquals(token.getAudience(), Collections.singletonList(issuer));
+ Assert.assertNull(token.getClaimsSet().getStringClaim("eduPersonScopedAffiliation"));
+ }
+
+ @Test
+ public void testWithHybridIdTokenTokenFlowAndResource() throws IOException, SessionException, ParseException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code+id_token+token&scope=openid%20profile"
+ + "&resource=" + resource + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNotNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+
+ final JWTClaimsSet token = SignedJWT.parse(successResponse.getAccessToken().getValue()).getJWTClaimsSet();
+ Assert.assertEquals(token.getAudience(), List.of(resource, issuer));
+ Assert.assertNotNull(token.getStringClaim("eduPersonScopedAffiliation"));
}
@Test
- public void testWithHybridIdTokenTokenFlowNoNonce() throws IOException, ParseException, SessionException {
+ public void testWithHybridIdTokenTokenFlowNoNonce() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code+id_token+token&scope=openid%20profile"
+ "&redirect_uri="+ redirectUri);
@@ -261,7 +402,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowUnforcedPKCE() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowUnforcedPKCE() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientIdPKCEPlainUnforced&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri);
@@ -279,7 +420,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowForcedPlainPKCEMissingChallenge() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowForcedPlainPKCEMissingChallenge() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri);
@@ -293,7 +434,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowForcedPlainPKCEUnknownChallenge() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowForcedPlainPKCEUnknownChallenge() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=unsupported");
@@ -307,7 +448,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowForcedPlainPKCEValidChallenge() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowForcedPlainPKCEValidChallenge() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=plain");
@@ -325,7 +466,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowForcedS256PKCEPlainChallenge() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowForcedS256PKCEPlainChallenge() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=plain");
@@ -339,7 +480,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowForcedS256PKCEUnknownChallenge() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowForcedS256PKCEUnknownChallenge() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=unknown");
@@ -353,7 +494,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowForcedS256PKCEValidChallenge() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowForcedS256PKCEValidChallenge() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=S256");
@@ -371,7 +512,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowNoScopes() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowNoScopes() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri);
@@ -387,7 +528,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowWithIDTokenClaims() throws IOException, ParseException, SessionException, java.text.ParseException, DataSealerException {
+ public void testWithAuthorizationCodeFlowWithIDTokenClaims() throws IOException, SessionException, DataSealerException, ParseException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile"
+ "&claims=%7B%22id_token%22%3A%7B%22email%22%3A%7B%22essential%22%3Atrue%7D%7D%7D"
@@ -416,7 +557,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowWithUIClaims() throws IOException, ParseException, SessionException, java.text.ParseException, DataSealerException {
+ public void testWithAuthorizationCodeFlowWithUIClaims() throws IOException, SessionException, DataSealerException, ParseException {
request.setMethod("GET");
request.setQueryString("client_id=mockClientId&response_type=code&scope=openid%20profile"
+ "&claims=%7B%22userinfo%22%3A%7B%22email%22%3A%7B%22essential%22%3Atrue%7D%7D%7D"
@@ -445,7 +586,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowUsingSAMLMetadata() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowUsingSAMLMetadata() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=mockSamlClientId&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri);
@@ -463,7 +604,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithAuthorizationCodeFlowUsingUntrustedRP() throws IOException, ParseException, SessionException {
+ public void testWithAuthorizationCodeFlowUsingUntrustedRP() throws IOException, SessionException {
request.setMethod("GET");
request.setQueryString("client_id=notTrusted&response_type=code&scope=openid%20profile&redirect_uri="
+ redirectUri);
@@ -475,7 +616,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithPlainReqObjectExpired() throws IOException, ParseException, SessionException {
+ public void testWithPlainReqObjectExpired() throws IOException, SessionException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
.expirationTime(Date.from(Instant.now().minus(Duration.ofMinutes(5))))
.build();
@@ -483,7 +624,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithPlainReqObjectNbfInFuture() throws IOException, ParseException, SessionException {
+ public void testWithPlainReqObjectNbfInFuture() throws IOException, SessionException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
.notBeforeTime(Date.from(Instant.now().plus(Duration.ofMinutes(5))))
.build();
@@ -491,7 +632,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithPlainReqObjectOverwriteRedirectUri() throws IOException, ParseException, SessionException {
+ public void testWithPlainReqObjectOverwriteRedirectUri() throws IOException, SessionException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
.claim("redirect_uri", redirectUri)
.build();
@@ -513,8 +654,8 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithPlainReqObjectClaimsRequest() throws IOException, ParseException, SessionException,
- java.text.ParseException, DataSealerException {
+ public void testWithPlainReqObjectClaimsRequest() throws IOException, SessionException,
+ DataSealerException, ParseException {
final String payload = "{\n"
+ " \"iss\": \"" + clientId + "\",\n"
+ " \"response_type\": \"code\",\n"
@@ -578,16 +719,16 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithSignedReqObjectNoIssuer() throws IOException, ParseException, SessionException,
+ public void testWithSignedReqObjectNoIssuer() throws IOException, SessionException,
JOSEException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
- .audience("https://op.example.org")
+ .audience(issuer)
.build();
assertRequestObjectError(createSecretJWT(ro, clientSecret));
}
@Test
- public void testWithSignedReqObjectNoAudience() throws IOException, ParseException, SessionException,
+ public void testWithSignedReqObjectNoAudience() throws IOException, SessionException,
JOSEException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
.issuer(clientId)
@@ -596,17 +737,17 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithSignedReqObjectWrongIssuer() throws IOException, ParseException, SessionException,
+ public void testWithSignedReqObjectWrongIssuer() throws IOException, SessionException,
JOSEException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
- .audience("https://op.example.org")
+ .audience(issuer)
.issuer("invalid")
.build();
assertRequestObjectError(createSecretJWT(ro, clientSecret));
}
@Test
- public void testWithSignedReqObjectWrongAudience() throws IOException, ParseException, SessionException,
+ public void testWithSignedReqObjectWrongAudience() throws IOException, SessionException,
JOSEException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
.audience("https://invalid.org")
@@ -619,7 +760,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
public void testWithSignedReqObjectOverwriteRedirectUri() throws IOException, ParseException,
SessionException, JOSEException {
final JWTClaimsSet ro = new JWTClaimsSet.Builder()
- .audience("https://op.example.org")
+ .audience(issuer)
.issuer(clientId)
.claim("redirect_uri", redirectUri)
.build();
@@ -641,8 +782,8 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
}
@Test
- public void testWithSignedReqObjectClaimsRequest() throws IOException, ParseException,
- SessionException, JOSEException, java.text.ParseException, DataSealerException {
+ public void testWithSignedReqObjectClaimsRequest() throws IOException,
+ SessionException, JOSEException, DataSealerException, ParseException {
final String payload = "{\n"
+ " \"iss\": \"" + clientId + "\",\n"
+ " \"response_type\": \"code\",\n"
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContextTest.java
deleted file mode 100644
index e6fa6333..00000000
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContextTest.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.idp.plugin.oidc.op.profile.impl;
-
-import net.shibboleth.idp.authn.context.SubjectContext;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseConsentContext;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseTokenClaimsContext;
-import net.shibboleth.idp.plugin.oidc.op.token.support.AccessTokenClaimsSet;
-import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
-import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
-import net.shibboleth.idp.profile.IdPEventIds;
-import net.shibboleth.idp.profile.context.RelyingPartyContext;
-import net.shibboleth.idp.profile.testing.ActionTestingSupport;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
-import net.shibboleth.utilities.java.support.security.DataSealerException;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.NoSuchAlgorithmException;
-import java.text.ParseException;
-import java.time.Instant;
-
-import org.opensaml.profile.action.EventIds;
-import org.springframework.webflow.execution.Event;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import com.nimbusds.oauth2.sdk.RefreshTokenGrant;
-import com.nimbusds.oauth2.sdk.Scope;
-import com.nimbusds.oauth2.sdk.TokenRequest;
-import com.nimbusds.oauth2.sdk.id.ClientID;
-import com.nimbusds.oauth2.sdk.token.RefreshToken;
-import com.nimbusds.openid.connect.sdk.claims.ACR;
-
-// Checkstyle: ThrowsCount OFF
-
-/** {@link SetAccessTokenToResponseContext} unit test. */
-public class SetAccessTokenToResponseContextTest extends BaseOIDCResponseActionTest {
-
- /** Action to test. */
- private SetAccessTokenToResponseContext action;
-
- private void init() throws ComponentInitializationException, NoSuchAlgorithmException, URISyntaxException {
- respCtx.setScope(new Scope());
- final TokenClaimsSet claims = new AuthorizeCodeClaimsSet.Builder()
- .setJWTID(idGenerator)
- .setClientID(new ClientID())
- .setIssuer("issuer")
- .setPrincipal("userPrin")
- .setSubject("subject")
- .setIssuedAt(Instant.now())
- .setExpiresAt(Instant.now())
- .setAuthenticationTime(Instant.now())
- .setRedirectURI(new URI("http://example.com"))
- .setScope(new Scope())
- .setACR(new ACR("0"))
- .build();
- respCtx.setSubject("subject");
- respCtx.setAuthTime(Instant.now());
- respCtx.setAuthorizationGrantClaimsSet(claims);
- respCtx.setAcr("0");
- respCtx.setRedirectURI(new URI("http://example.com"));
- action = new SetAccessTokenToResponseContext();
- action.setDataSealer(getDataSealer());
- action.initialize();
- final SubjectContext subjectCtx = profileRequestCtx.getSubcontext(SubjectContext.class, true);
- subjectCtx.setPrincipalName("userPrin");
- }
-
- /**
- * Basic success case.
- *
- * @throws ComponentInitializationException
- * @throws NoSuchAlgorithmException
- * @throws URISyntaxException
- * @throws ParseException
- * @throws DataSealerException
- */
- @Test
- public void testSuccess() throws ComponentInitializationException, NoSuchAlgorithmException, URISyntaxException,
- ParseException, DataSealerException {
- init();
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertProceedEvent(event);
- Assert.assertNotNull(respCtx.getAccessToken());
- final AccessTokenClaimsSet at =
- AccessTokenClaimsSet.parse(respCtx.getAccessToken().getValue(), getDataSealer());
- Assert.assertNotNull(at);
- }
-
- /**
- * Basic success case for non derived token.
- *
- * @throws ComponentInitializationException
- * @throws NoSuchAlgorithmException
- * @throws URISyntaxException
- * @throws ParseException
- * @throws DataSealerException
- */
- @Test
- public void testSuccess2() throws ComponentInitializationException, NoSuchAlgorithmException, URISyntaxException,
- ParseException, DataSealerException {
- init();
- respCtx.setAuthorizationGrantClaimsSet(null);
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertProceedEvent(event);
- Assert.assertNotNull(respCtx.getAccessToken());
- final AccessTokenClaimsSet at =
- AccessTokenClaimsSet.parse(respCtx.getAccessToken().getValue(), getDataSealer());
- Assert.assertNotNull(at);
- }
-
- /**
- * Basic success case for non derived token. Test for consent.
- *
- * @throws ComponentInitializationException
- * @throws NoSuchAlgorithmException
- * @throws URISyntaxException
- * @throws ParseException
- * @throws DataSealerException
- */
- @Test
- public void testSuccess2Consent() throws ComponentInitializationException, NoSuchAlgorithmException,
- URISyntaxException, ParseException, DataSealerException {
- init();
- respCtx.setAuthorizationGrantClaimsSet(null);
- final OIDCAuthenticationResponseConsentContext consCtx =
- (OIDCAuthenticationResponseConsentContext) respCtx.addSubcontext(
- new OIDCAuthenticationResponseConsentContext());
- consCtx.getConsentedAttributes().add("3");
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertProceedEvent(event);
- Assert.assertNotNull(respCtx.getAccessToken());
- final AccessTokenClaimsSet at =
- AccessTokenClaimsSet.parse(respCtx.getAccessToken().getValue(), getDataSealer());
- Assert.assertNotNull(at);
- Assert.assertEquals(at.getConsentedClaims(), consCtx.getConsentedAttributes());
- }
-
- /**
- * Basic success case with delivery claims.
- *
- * @throws ComponentInitializationException
- * @throws NoSuchAlgorithmException
- * @throws URISyntaxException
- * @throws ParseException
- * @throws DataSealerException
- */
- @Test
- public void testSuccessWithTokenDelivery() throws ComponentInitializationException, NoSuchAlgorithmException,
- URISyntaxException, ParseException, DataSealerException {
- init();
- final OIDCAuthenticationResponseTokenClaimsContext tokenCtx =
- (OIDCAuthenticationResponseTokenClaimsContext) respCtx.addSubcontext(
- new OIDCAuthenticationResponseTokenClaimsContext());
- tokenCtx.getClaims().setClaim("1", "1");
- tokenCtx.getIdtokenClaims().setClaim("2", "2");
- tokenCtx.getUserinfoClaims().setClaim("3", "3");
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertProceedEvent(event);
- Assert.assertNotNull(respCtx.getAccessToken());
- final AccessTokenClaimsSet at =
- AccessTokenClaimsSet.parse(respCtx.getAccessToken().getValue(), getDataSealer());
- Assert.assertNotNull(at);
- Assert.assertNotNull(at.getDeliveryClaims().getClaim("1"));
- Assert.assertNotNull(at.getUserinfoDeliveryClaims().getClaim("3"));
- Assert.assertNull(at.getIDTokenDeliveryClaims());
- }
-
- /**
- * fails as request is of wrong type.
- *
- * @throws NoSuchAlgorithmException
- * @throws ComponentInitializationException
- * @throws URISyntaxException
- */
- @Test
- public void testFailNoAuthnReqCase2()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException {
- init();
- respCtx.setAuthorizationGrantClaimsSet(null);
- final TokenRequest req =
- new TokenRequest(new URI("http://example.com"), new RefreshTokenGrant(new RefreshToken()), null);
- setTokenRequest(req);
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertEvent(event, EventIds.INVALID_MSG_CTX);
- }
-
- /**
- * fails as there is no subject ctx.
- *
- * @throws NoSuchAlgorithmException
- * @throws ComponentInitializationException
- * @throws URISyntaxException
- */
- @Test
- public void testFailNoSubjectCtxCase2()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException {
- init();
- respCtx.setAuthorizationGrantClaimsSet(null);
- profileRequestCtx.removeSubcontext(SubjectContext.class);
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertEvent(event, EventIds.INVALID_PROFILE_CTX);
- }
-
- /**
- * fails as there is no rp ctx.
- *
- * @throws NoSuchAlgorithmException
- * @throws ComponentInitializationException
- * @throws URISyntaxException
- */
- @Test
- public void testFailNoRPCtx()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException {
- init();
- profileRequestCtx.removeSubcontext(RelyingPartyContext.class);
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertEvent(event, IdPEventIds.INVALID_PROFILE_CONFIG);
- }
-
- /**
- * fails as there is no profile conf.
- *
- * @throws NoSuchAlgorithmException
- * @throws ComponentInitializationException
- * @throws URISyntaxException
- */
- @Test
- public void testFailNoProfileConf()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException {
- init();
- final RelyingPartyContext rpCtx = profileRequestCtx.getSubcontext(RelyingPartyContext.class, false);
- rpCtx.setProfileConfig(null);
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertEvent(event, IdPEventIds.INVALID_PROFILE_CONFIG);
- }
-
- /**
- * fails as the token is of wrong type.
- *
- * @throws NoSuchAlgorithmException
- * @throws ComponentInitializationException
- * @throws URISyntaxException
- */
- @Test
- public void testFailTokenNotCodeOrRefresh()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException {
- init();
- final TokenClaimsSet claims = new AccessTokenClaimsSet.Builder()
- .setJWTID(idGenerator)
- .setClientID(new ClientID())
- .setIssuer("issuer")
- .setPrincipal("userPrin")
- .setSubject("subject")
- .setIssuedAt(Instant.now())
- .setExpiresAt(Instant.now())
- .setAuthenticationTime(Instant.now())
- .setRedirectURI(new URI("http://example.com"))
- .setScope(new Scope())
- .build();
-
- respCtx.setAuthorizationGrantClaimsSet(claims);
- final Event event = action.execute(requestCtx);
- ActionTestingSupport.assertEvent(event, EventIds.INVALID_PROFILE_CTX);
- }
-
-}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list