[java-idp-oidc] 02/02: JOIDC-127 - Include sid claim in id_token
Henri Mikkonen
henri.mikkonen at iki.fi
Tue Sep 20 12:33:53 UTC 2022
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=d5964bb9e04bc3ae993a27710c96bb194a121f7b
commit d5964bb9e04bc3ae993a27710c96bb194a121f7b
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Tue Sep 20 15:31:55 2022 +0300
JOIDC-127 - Include sid claim in id_token
https://shibboleth.atlassian.net/browse/JOIDC-127
The sid value is generated by the authorize endpoint for end-user flows, and by the token
endpoint for the client_credentials grant. The value is stored to OIDCAuthenticationResponseContext and
encoded to the token claims sets (authz code, accesa and refresh tokens).
The generation strategy can be configured with idp.oidc.SessionIdentifierGenerationStrategy -property, it defaults to
shibboleth.DefaultIdentifierGenerationStrategy.
---
.../context/OIDCAuthenticationResponseContext.java | 30 ++++-
.../TokenRequestSessionIdLookupFunction.java | 41 +++++++
.../op/token/support/AccessTokenClaimsSet.java | 1 +
.../op/token/support/RefreshTokenClaimsSet.java | 1 +
.../oidc/op/token/support/TokenClaimsSet.java | 38 +++++-
.../op/oauth2/profile/impl/BuildAccessToken.java | 4 +-
.../oidc/op/profile/impl/AddIDTokenShell.java | 6 +
.../SetAuthorizationCodeToResponseContext.java | 1 +
.../impl/SetSessionIdToResponseContext.java | 75 ++++++++++++
.../flows/oidc/abstract/oidc-abstract-beans.xml | 13 +-
.../idp/flows/oidc/authorize/authorize-beans.xml | 4 +
.../idp/flows/oidc/authorize/authorize-flow.xml | 1 +
.../idp/flows/oidc/token/token-beans.xml | 7 ++
.../shibboleth/idp/flows/oidc/token/token-flow.xml | 2 +
.../idp/plugin/oidc/op/conf/oidc.properties | 3 +
.../oauth2/profile/impl/BuildAccessTokenTest.java | 75 ++++++++++++
.../oidc/op/profile/flow/AuthorizeFlowTest.java | 112 ++++++++++++++++-
.../plugin/oidc/op/profile/flow/TokenFlowTest.java | 128 +++++++++++++++++++-
.../oidc/op/profile/impl/AddIDTokenShellTest.java | 17 +++
.../SetAuthorizationCodeToResponseContextTest.java | 24 ++++
.../impl/SetSessionIdToResponseContextTest.java | 133 +++++++++++++++++++++
21 files changed, 708 insertions(+), 8 deletions(-)
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContext.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContext.java
index 94e54224..83744498 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContext.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContext.java
@@ -127,7 +127,10 @@ public class OIDCAuthenticationResponseContext extends BaseContext {
/** Mapped requested claims from the Userinfo set. */
@Nullable private AttributesMapContainer mappedUserinfoRequestedClaims;
-
+
+ /** Session identifier. */
+ @Nullable private String sessionId;
+
/** Constructor. */
public OIDCAuthenticationResponseContext() {
validatedAudience = new ArrayList<>();
@@ -556,5 +559,28 @@ public class OIDCAuthenticationResponseContext extends BaseContext {
public void setRequestObject(@Nullable final JWT obj) {
requestObject = obj;
}
-
+
+ /**
+ * Get the session identifier.
+ *
+ * @return session identifier
+ *
+ * @since 3.3.0
+ */
+ @Nullable
+ public String getSessionId() {
+ return sessionId;
+ }
+
+ /**
+ * Set the session identifier.
+ *
+ * @param sid session identifier
+ *
+ * @since 3.3.0
+ */
+ public void setSessionId(@Nullable final String sid) {
+ sessionId = sid;
+ }
+
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestSessionIdLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestSessionIdLookupFunction.java
new file mode 100644
index 00000000..fa5871d1
--- /dev/null
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestSessionIdLookupFunction.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.profile.context.navigate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
+
+/**
+ * For Token and UserInfo end points.
+ *
+ * A function that returns session id claim via a lookup function. This lookup locates id from token (Authorization
+ * Code / Access Token) for token request handling. If id is not available, null is returned.
+ *
+ * @since 3.3.0
+ */
+public class TokenRequestSessionIdLookupFunction extends AbstractTokenClaimsLookupFunction<String> {
+
+ /** {@inheritDoc} */
+ @Override @Nullable
+ String doLookup(@Nonnull final TokenClaimsSet tokenClaims) {
+ return tokenClaims.getSessionIdentifier();
+ }
+
+}
\ No newline at end of file
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 f39f75da..9aefa336 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
@@ -231,6 +231,7 @@ public final class AccessTokenClaimsSet extends TokenClaimsSet {
setConsentedClaims(existing.getConsentedClaims());
setConsentEnabled(existing.isConsentEnabled());
setRootTokenIdentifier(existing.getRootTokenIdentifier());
+ setSessionIdentifier(existing.getSessionIdentifier());
}
/**
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 b060659b..fe151743 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
@@ -146,6 +146,7 @@ public final class RefreshTokenClaimsSet extends TokenClaimsSet {
setDlClaimsUI(existing.getUserinfoDeliveryClaims());
setConsentedClaims(existing.getConsentedClaims());
setConsentEnabled(existing.isConsentEnabled());
+ setSessionIdentifier(existing.getSessionIdentifier());
}
/**
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/TokenClaimsSet.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/TokenClaimsSet.java
index ad63c0f1..f1cd8073 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/TokenClaimsSet.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/TokenClaimsSet.java
@@ -136,6 +136,9 @@ public class TokenClaimsSet {
/** Identifier for the root token in the chain. */
@Nonnull @NotEmpty public static final String KEY_ROOT_JTI = "root_jti";
+ /** Identifier for the session id. */
+ @Nonnull @NotEmpty public static final String KEY_SESSION_ID = "sid";
+
/** Claims set for the claim. */
@Nullable private JWTClaimsSet tokenClaimsSet;
@@ -642,6 +645,21 @@ public class TokenClaimsSet {
return (String) tokenClaimsSet.getClaim(KEY_ROOT_JTI);
}
+ /**
+ * Get the session identifier.
+ *
+ * @return the session identifier.
+ *
+ * @since 3.3.0
+ */
+ @Nullable public String getSessionIdentifier() {
+ Constraint.isNotNull(tokenClaimsSet, "JWTClaimsSet cannot be null");
+ if (tokenClaimsSet.getClaim(KEY_SESSION_ID) == null) {
+ return null;
+ }
+ return (String) tokenClaimsSet.getClaim(KEY_SESSION_ID);
+ }
+
/**
* Abstract builder to extend builders from that are instantiating claims sets extending TokenClaimsSet.
*
@@ -720,6 +738,9 @@ public class TokenClaimsSet {
/** Root token identifier. */
@Nullable protected String rootTokenId;
+ /** Session identifier. */
+ @Nullable protected String sessionId;
+
/** Default constructor. */
protected Builder() {
audience = Collections.emptyList();
@@ -769,7 +790,8 @@ public class TokenClaimsSet {
.claim(KEY_CONSENTED_CLAIMS, consentedClaims)
.claim(KEY_CODE_CHALLENGE, codeChallenge)
.claim(KEY_CONSENT_ENABLED, consentEnabled)
- .claim(KEY_ROOT_JTI, rootTokenId);
+ .claim(KEY_ROOT_JTI, rootTokenId)
+ .claim(KEY_SESSION_ID, sessionId);
customClaims.forEach((n,v) -> {
if (n != null) {
@@ -1143,6 +1165,20 @@ public class TokenClaimsSet {
return this;
}
+ /**
+ * Set session identifier.
+ *
+ * @param id session identifier
+ *
+ * @return the builder
+ *
+ * @since 3.3.0
+ */
+ public Builder<T> setSessionIdentifier(@Nullable final String id) {
+ sessionId = id;
+ return this;
+ }
+
/**
* Builds claims set.
*
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 ea65d84f..ad82eb9e 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
@@ -459,6 +459,7 @@ public class BuildAccessToken extends AbstractOIDCResponseAction {
// Add additional bits.
builder.setAudience(responseCtx.getAudience());
builder.setJWTID(idGenerator);
+ builder.setSessionIdentifier(responseCtx.getSessionId());
// Set root token identifier to contain jit from the claims set used for building the new token
if (StringSupport.trimOrNull(tokenClaimsSet.getRootTokenIdentifier()) == null) {
builder.setRootTokenIdentifier(tokenClaimsSet.getID());
@@ -483,7 +484,8 @@ public class BuildAccessToken extends AbstractOIDCResponseAction {
.setDlClaims(claims)
.setDlClaimsUI(claimsUI)
.setConsentedClaims(consented)
- .setConsentEnabled(consentEnabledPredicate.test(profileRequestContext));
+ .setConsentEnabled(consentEnabledPredicate.test(profileRequestContext))
+ .setSessionIdentifier(responseCtx.getSessionId());
if (authenticationRequest != null) {
builder
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddIDTokenShell.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddIDTokenShell.java
index ab4950e8..8e7672c2 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddIDTokenShell.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddIDTokenShell.java
@@ -36,6 +36,7 @@ import net.shibboleth.oidc.profile.config.navigate.AudienceRestrictionsLookupFun
import net.shibboleth.oidc.profile.config.navigate.IDTokenLifetimeLookupFunction;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.context.ProfileRequestContext;
@@ -46,6 +47,7 @@ import com.nimbusds.oauth2.sdk.id.Audience;
import com.nimbusds.oauth2.sdk.id.Issuer;
import com.nimbusds.oauth2.sdk.id.Subject;
import com.nimbusds.openid.connect.sdk.claims.IDTokenClaimsSet;
+import com.nimbusds.openid.connect.sdk.claims.SessionID;
/**
* Action that creates a {@link IDTokenClaimsSet} object shell, and sets it to work context
@@ -162,6 +164,10 @@ public class AddIDTokenShell extends AbstractOIDCResponseAction {
final Date exp = Date.from(Instant.now().plus(lifetime));
final IDTokenClaimsSet idToken = new IDTokenClaimsSet(new Issuer(issuerId),
new Subject(getOidcResponseContext().getSubject()), aud, exp, new Date());
+ final String sid = getOidcResponseContext().getSessionId();
+ if (StringSupport.trimOrNull(sid) != null) {
+ idToken.setSessionID(new SessionID(sid));
+ }
log.debug("{} Setting ID token shell to response context {}", getLogPrefix(),
idToken.toJSONObject().toJSONString());
getOidcResponseContext().setIDToken(idToken);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContext.java
index 15400a08..dbd9fb0c 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContext.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContext.java
@@ -360,6 +360,7 @@ public class SetAuthorizationCodeToResponseContext extends AbstractOIDCAuthentic
.setDlClaimsUI(claimsUI)
.setConsentedClaims(consented)
.setConsentEnabled(consentEnabledPredicate.test(profileRequestContext))
+ .setSessionIdentifier(responseCtx.getSessionId())
.build();
if (manipulationStrategy != null) {
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSessionIdToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSessionIdToResponseContext.java
new file mode 100644
index 00000000..913c4e40
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSessionIdToResponseContext.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.profile.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestSessionIdLookupFunction;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Action that locates session id using configurable lookup strategy. Located session id is set to
+ * {@link OIDCAuthenticationResponseContext}.
+ **/
+public class SetSessionIdToResponseContext extends AbstractOIDCResponseAction {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(SetSessionIdToResponseContext.class);
+
+ /** Strategy used to obtain the session identifier. */
+ @Nonnull private Function<ProfileRequestContext, String> sessionIdLookupStrategy;
+
+ /**
+ * Constructor.
+ */
+ public SetSessionIdToResponseContext() {
+ sessionIdLookupStrategy = new TokenRequestSessionIdLookupFunction();
+ }
+
+ /**
+ * Set the strategy used to locate session identifier.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setSessionIdLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ sessionIdLookupStrategy = Constraint.isNotNull(strategy, "Session ID lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ final String sessionId = sessionIdLookupStrategy.apply(profileRequestContext);
+ if (StringSupport.trimOrNull(sessionId) == null) {
+ log.debug("{} Session id value did not exist", getLogPrefix());
+ } else {
+ log.debug("{} Setting session id value to {}", getLogPrefix(), sessionId);
+ getOidcResponseContext().setSessionId(sessionId);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml
index f2b30adc..5ad5361f 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml
@@ -100,5 +100,16 @@
<bean id="FlowStartPopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
p:fieldExtractors="#{getObject('shibboleth.FlowStartAuditExtractors') ?: getObject('shibboleth.DefaultFlowStartAuditExtractors')}" />
-
+
+ <bean id="SessionIdGenerationStrategy" parent="shibboleth.Functions.Scripted"
+ p:customObject="#{getObject('%{idp.oidc.SessionIdentifierGenerationStrategy:shibboleth.DefaultIdentifierGenerationStrategy}'.trim())}">
+ <constructor-arg>
+ <value>
+ <![CDATA[
+ custom.generateIdentifier();
+ ]]>
+ </value>
+ </constructor-arg>
+ </bean>
+
</beans>
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 a686307d..20f96972 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
@@ -41,6 +41,10 @@
<bean id="SetRequestedSubjectToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestedSubjectToResponseContext" scope="prototype" />
+ <bean id="SetSessionIdToResponseContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSessionIdToResponseContext" scope="prototype"
+ p:sessionIdLookupStrategy-ref="SessionIdGenerationStrategy" />
+
<bean id="SetRequestedClaimsToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestedClaimsToResponseContext" scope="prototype"
p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
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 db319735..51f782e3 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
@@ -51,6 +51,7 @@
<evaluate expression="ValidateCodeChallenge" />
<evaluate expression="SetRequestedClaimsToResponseContext" />
<evaluate expression="SetRequestedSubjectToResponseContext" />
+ <evaluate expression="SetSessionIdToResponseContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="PopulateClientStorageLoadContext" />
</action-state>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
index b6e1fd2b..1ce78d1b 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
@@ -134,6 +134,13 @@
</property>
</bean>
+ <bean id="SetSessionIdToResponseContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSessionIdToResponseContext" scope="prototype"
+ p:sessionIdLookupStrategy-ref="SessionIdGenerationStrategy" />
+
+ <bean id="SetSessionIdFromAuthzCodeToResponseContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSessionIdToResponseContext" scope="prototype" />
+
<!-- Common grant handling. -->
<bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateScope" scope="prototype"
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 c14e9c4b..fb4f16c0 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
@@ -60,6 +60,7 @@
<evaluate expression="SetSubjectFromAuthzCodeToResponseContext" />
<evaluate expression="ValidateScope" />
<evaluate expression="ValidateAudience" />
+ <evaluate expression="SetSessionIdFromAuthzCodeToResponseContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="CheckTraditionalGrantForAudience" />
@@ -79,6 +80,7 @@
<evaluate expression="SetSubjectFromSubjectContextToResponseContext" />
<evaluate expression="ValidateScope" />
<evaluate expression="ValidateAudience" />
+ <evaluate expression="SetSessionIdToResponseContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="LookupAudienceMetadata" />
diff --git a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
index 1df268c2..776e5ab0 100644
--- a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
+++ b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
@@ -96,6 +96,9 @@ idp.oidc.subject.salt = this_too_should_be_ch4ng3d
# Bean used for extracting login_hint from the authentication request. The default function parses login_hint as is.
#idp.oidc.LoginHintLookupStrategy = DefaultRequestLoginHintLookupFunction
+# Bean used for generating session identifiers, stored as sid claim in the id_token and claims sets.
+#idp.oidc.SessionIdentifierGenerationStrategy = shibboleth.DefaultIdentifierGenerationStrategy
+
# Bean used for creating SPSessions needed for SLO. By default builds protocol-independent BasicSPSession, as SLO is not yet supported.
#idp.oidc.SPSessionCreationStrategy = DefaultSPSessionCreationStrategy
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/BuildAccessTokenTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/BuildAccessTokenTest.java
index e888d10e..1f67c907 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/BuildAccessTokenTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/BuildAccessTokenTest.java
@@ -117,6 +117,28 @@ public class BuildAccessTokenTest extends BaseOIDCResponseActionTest {
Collections.singletonList("https://rp.example.org"), null);
}
+ /**
+ * Basic success case.
+ *
+ * @throws ParseException
+ * @throws DataSealerException
+ * @throws ComponentInitializationException
+ * @throws NoSuchAlgorithmException
+ */
+ @Test
+ public void testOpaqueSuccessSid() throws ParseException, DataSealerException, ComponentInitializationException,
+ NoSuchAlgorithmException {
+
+ initAction(null, null);
+ respCtx.setSessionId("mockSid");
+
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ verifyClaims(respCtx.getSubcontext(AccessTokenContext.class), new Scope(),
+ Collections.singletonList("https://rp.example.org"), null, "mockSid");
+ }
+
/**
* Basic success case with custom claims.
*
@@ -159,6 +181,28 @@ public class BuildAccessTokenTest extends BaseOIDCResponseActionTest {
Collections.singletonList("https://rp.example.org"), null);
}
+ /**
+ * Basic success case, direct reuse of requested scope/audience.
+ *
+ * @throws ParseException
+ * @throws ComponentInitializationException
+ * @throws NoSuchAlgorithmException
+ * @throws DataSealerException
+ */
+ @Test
+ public void testJWTSuccessSid() throws ParseException, ComponentInitializationException, NoSuchAlgorithmException,
+ DataSealerException {
+
+ initAction("JWT", null);
+
+ respCtx.setSessionId("mockSid");
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ verifyClaims(respCtx.getSubcontext(AccessTokenContext.class), new Scope(),
+ Collections.singletonList("https://rp.example.org"), null, "mockSid");
+ }
+
/**
* Basic success case, direct reuse of requested scope/audience.
*
@@ -219,6 +263,27 @@ public class BuildAccessTokenTest extends BaseOIDCResponseActionTest {
private void verifyClaims(@Nonnull final AccessTokenContext ctx, @Nonnull final Scope scope,
@Nonnull @NonnullElements final Collection<String> audiences, final Map<String, Object> customClaims)
throws NoSuchAlgorithmException, ParseException, DataSealerException, ComponentInitializationException {
+ verifyClaims(ctx, scope, audiences, customClaims, null);
+ }
+
+ /**
+ * Verify access token's claims.
+ *
+ * @param ctx access token context
+ * @param scope scope to check for
+ * @param audiences audiences to check for
+ * @param customClaims custom claims to check for, may be null
+ * @param sid session id to check for, may be null
+ *
+ * @throws ComponentInitializationException
+ * @throws DataSealerException
+ * @throws ParseException
+ * @throws NoSuchAlgorithmException
+ */
+ private void verifyClaims(@Nonnull final AccessTokenContext ctx, @Nonnull final Scope scope,
+ @Nonnull @NonnullElements final Collection<String> audiences, final Map<String, Object> customClaims,
+ @Nullable final String sid)
+ throws NoSuchAlgorithmException, ParseException, DataSealerException, ComponentInitializationException {
assertEquals(ctx.getLifetime(), Duration.ofMinutes(10));
@@ -236,6 +301,11 @@ public class BuildAccessTokenTest extends BaseOIDCResponseActionTest {
assertEquals(at.getSubject(), clientId);
assertEquals(at.getPrincipal(), "jdoe");
verifyCustomClaims(at.getClaimsSet(), customClaims);
+ if (sid == null) {
+ Assert.assertNull(at.getSessionIdentifier());
+ } else {
+ Assert.assertEquals(at.getSessionIdentifier(), sid);
+ }
} else if (ctx.getJWT() != null) {
final JWTClaimsSet claims = ctx.getJWT().getJWTClaimsSet();
assertNotNull(claims);
@@ -252,6 +322,11 @@ public class BuildAccessTokenTest extends BaseOIDCResponseActionTest {
JWTClaimsSet.parse(getDataSealer().unwrap(claims.getStringClaim(TokenClaimsSet.KEY_SEALED_FOR_OP)));
assertEquals(unsealedClaims.getStringClaim(TokenClaimsSet.KEY_USER_PRINCIPAL), "jdoe");
verifyCustomClaims(claims, customClaims);
+ if (sid == null) {
+ Assert.assertNull(claims.getStringClaim("sid"));
+ } else {
+ Assert.assertEquals(claims.getStringClaim("sid"), sid);
+ }
} else {
throw new RuntimeException("No token found");
}
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 32e41a43..16c84fa4 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
@@ -99,6 +99,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
}
@@ -118,6 +119,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
}
@@ -137,6 +139,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNotNull(successResponse.getIssuer());
Assert.assertEquals(successResponse.getIssuer().getValue(), issuer);
}
@@ -193,6 +196,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNotNull(getSidFromIDToken(successResponse));
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNull(successResponse.getAuthorizationCode());
Assert.assertNull(successResponse.getIssuer());
@@ -212,6 +216,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNotNull(getSidFromIDToken(successResponse));
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNull(successResponse.getAuthorizationCode());
Assert.assertNotNull(successResponse.getIssuer());
@@ -232,6 +237,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNotNull(getSidFromIDToken(successResponse));
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNull(successResponse.getAuthorizationCode());
Assert.assertNull(successResponse.getIssuer());
@@ -251,7 +257,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
Assert.assertNotNull(successResponse.getIDToken());
+ final String sid1 = getSidFromIDToken(successResponse);
+ Assert.assertNotNull(sid1);
Assert.assertNotNull(successResponse.getAccessToken());
+ final String sid2 = getSidFromOpaqueAccessTokenClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
Assert.assertNull(successResponse.getAuthorizationCode());
final AccessTokenClaimsSet token =
@@ -275,7 +285,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
Assert.assertNotNull(successResponse.getIDToken());
+ final String sid1 = getSidFromIDToken(successResponse);
+ Assert.assertNotNull(sid1);
Assert.assertNotNull(successResponse.getAccessToken());
+ final String sid2 = getSidFromOpaqueAccessTokenClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
Assert.assertNull(successResponse.getAuthorizationCode());
final AccessTokenClaimsSet token =
@@ -300,7 +314,11 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
Assert.assertNotNull(successResponse.getIDToken());
+ final String sid1 = getSidFromIDToken(successResponse);
+ Assert.assertNotNull(sid1);
Assert.assertNotNull(successResponse.getAccessToken());
+ final String sid2 = getSidFromJWTAccessTokenClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
Assert.assertNull(successResponse.getAuthorizationCode());
Assert.assertNull(successResponse.getIssuer());
@@ -361,8 +379,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
Assert.assertNotNull(successResponse.getIDToken());
+ final String sid1 = getSidFromIDToken(successResponse);
+ Assert.assertNotNull(sid1);
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ final String sid2 = getSidFromAuthorizeCodeClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
Assert.assertNull(successResponse.getIssuer());
}
@@ -380,8 +402,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
Assert.assertNotNull(successResponse.getIDToken());
+ final String sid1 = getSidFromIDToken(successResponse);
+ Assert.assertNotNull(sid1);
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ final String sid2 = getSidFromAuthorizeCodeClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
Assert.assertNotNull(successResponse.getIssuer());
Assert.assertEquals(successResponse.getIssuer().getValue(), issuer);
}
@@ -399,9 +425,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
- Assert.assertNotNull(successResponse.getIDToken());
+ final String sid1 = getSidFromIDToken(successResponse);
+ Assert.assertNotNull(sid1);
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ final String sid2 = getSidFromAuthorizeCodeClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
Assert.assertNull(successResponse.getIssuer());
}
@@ -435,6 +464,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNotNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+
+ final String sid1 = getSidFromOpaqueAccessTokenClaimsSet(successResponse);
+ final String sid2 = getSidFromAuthorizeCodeClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
final AccessTokenClaimsSet token =
AccessTokenClaimsSet.parse(successResponse.getAccessToken().getValue(), getDataSealer());
@@ -462,6 +495,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNotNull(successResponse.getAuthorizationCode());
Assert.assertNull(successResponse.getIssuer());
+ final String sid1 = getSidFromJWTAccessTokenClaimsSet(successResponse);
+ final String sid2 = getSidFromAuthorizeCodeClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
+
final JWTClaimsSet token = SignedJWT.parse(successResponse.getAccessToken().getValue()).getJWTClaimsSet();
Assert.assertEquals(token.getAudience(), List.of(resource, issuer));
Assert.assertNotNull(token.getStringClaim("eduPersonScopedAffiliation"));
@@ -485,6 +522,10 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNotNull(successResponse.getAuthorizationCode());
Assert.assertNull(successResponse.getIssuer());
+ final String sid1 = getSidFromOpaqueAccessTokenClaimsSet(successResponse);
+ final String sid2 = getSidFromAuthorizeCodeClaimsSet(successResponse);
+ Assert.assertEquals(sid1, sid2);
+
final AccessTokenClaimsSet token =
AccessTokenClaimsSet.parse(successResponse.getAccessToken().getValue(), getDataSealer());
Assert.assertEquals(token.getAudience(), Collections.singletonList(issuer));
@@ -510,6 +551,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNotNull(successResponse.getAuthorizationCode());
Assert.assertNull(successResponse.getIssuer());
+ final String sid1 = getSidFromOpaqueAccessTokenClaimsSet(successResponse);
+ final String sid2 = getSidFromAuthorizeCodeClaimsSet(successResponse);
+ final String sid3 = getSidFromIDToken(successResponse);
+ Assert.assertEquals(sid1, sid2);
+ Assert.assertEquals(sid2, sid3);
+
final IDTokenClaimsSet idToken = new IDTokenClaimsSet(successResponse.getIDToken().getJWTClaimsSet());
Assert.assertNotNull(idToken);
Assert.assertNotNull(idToken.getStringClaim("custom_id_token_claim"));
@@ -542,6 +589,12 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNotNull(successResponse.getAuthorizationCode());
Assert.assertNull(successResponse.getIssuer());
+ final String sid1 = getSidFromJWTAccessTokenClaimsSet(successResponse);
+ final String sid2 = getSidFromAuthorizeCodeClaimsSet(successResponse);
+ final String sid3 = getSidFromIDToken(successResponse);
+ Assert.assertEquals(sid1, sid2);
+ Assert.assertEquals(sid2, sid3);
+
final JWTClaimsSet token = SignedJWT.parse(successResponse.getAccessToken().getValue()).getJWTClaimsSet();
Assert.assertEquals(token.getAudience(), List.of(resource, issuer));
Assert.assertNotNull(token.getStringClaim("eduPersonScopedAffiliation"));
@@ -576,6 +629,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
}
@Test
@@ -622,6 +676,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
}
@Test
@@ -668,6 +723,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
}
@Test
@@ -721,6 +777,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
final AuthorizeCodeClaimsSet code =
@@ -751,6 +808,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
final AuthorizeCodeClaimsSet code =
@@ -781,6 +839,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
final AuthorizeCodeClaimsSet code =
@@ -806,6 +865,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
}
@@ -857,6 +917,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
}
@@ -905,6 +966,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
final AuthorizeCodeClaimsSet code =
@@ -987,6 +1049,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
}
@@ -1034,6 +1097,7 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getIDToken());
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
+ Assert.assertNotNull(getSidFromAuthorizeCodeClaimsSet(successResponse));
Assert.assertNull(successResponse.getIssuer());
final AuthorizeCodeClaimsSet code =
@@ -1085,6 +1149,52 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertEquals(errorResponse.getIssuer().getValue(), issuer);
}
+ protected String getSidFromAuthorizeCodeClaimsSet(final AuthenticationSuccessResponse successResponse) {
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ final AuthorizeCodeClaimsSet claims;
+ try {
+ claims = AuthorizeCodeClaimsSet.parse(successResponse.getAuthorizationCode().getValue(), getDataSealer());
+ Assert.assertNotNull(claims.getSessionIdentifier());
+ return claims.getSessionIdentifier();
+ } catch (ParseException | DataSealerException e) {
+ return null;
+ }
+ }
+
+ protected String getSidFromOpaqueAccessTokenClaimsSet(final AuthenticationSuccessResponse successResponse) {
+ Assert.assertNotNull(successResponse.getAccessToken());
+ final AccessTokenClaimsSet claims;
+ try {
+ claims = AccessTokenClaimsSet.parse(successResponse.getAccessToken().getValue(), getDataSealer());
+ Assert.assertNotNull(claims.getSessionIdentifier());
+ return claims.getSessionIdentifier();
+ } catch (ParseException | DataSealerException e) {
+ return null;
+ }
+ }
+
+ protected String getSidFromJWTAccessTokenClaimsSet(final AuthenticationSuccessResponse successResponse) {
+ Assert.assertNotNull(successResponse.getAccessToken());
+ try {
+ final JWT jwt = SignedJWT.parse(successResponse.getAccessToken().getValue());
+ final JWTClaimsSet claims = jwt.getJWTClaimsSet();
+ Assert.assertNotNull(claims.getStringClaim("sid"));
+ return claims.getStringClaim("sid");
+ } catch (ParseException e) {
+ return null;
+ }
+ }
+
+ protected String getSidFromIDToken(final AuthenticationSuccessResponse successResponse) {
+ final JWT idToken = successResponse.getIDToken();
+ Assert.assertNotNull(idToken);
+ try {
+ return idToken.getJWTClaimsSet().getStringClaim("sid");
+ } catch (ParseException e) {
+ return null;
+ }
+ }
+
@AfterMethod
public void removeMetadata() throws IOException {
removeMetadata(storageService, clientId);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
index 8e53ef2e..277a9c30 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
@@ -18,6 +18,7 @@
package net.shibboleth.idp.plugin.oidc.op.profile.flow;
import java.io.IOException;
+import java.net.URI;
import java.text.ParseException;
import java.time.Duration;
import java.time.Instant;
@@ -45,6 +46,7 @@ import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
import com.nimbusds.oauth2.sdk.auth.ClientSecretJWT;
import com.nimbusds.oauth2.sdk.auth.JWTAuthentication;
+import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.pkce.CodeChallenge;
import com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod;
import com.nimbusds.oauth2.sdk.pkce.CodeVerifier;
@@ -58,10 +60,12 @@ import net.minidev.json.JSONObject;
import net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateGrantTest;
import net.shibboleth.idp.plugin.oidc.op.storage.RevocationCacheContexts;
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.utilities.java.support.collection.Pair;
import net.shibboleth.utilities.java.support.security.DataSealerException;
+import net.shibboleth.utilities.java.support.security.impl.SecureRandomIdentifierGenerationStrategy;
/**
* Unit tests for the token flow.
@@ -191,8 +195,26 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
Assert.assertNotNull(response.getTokens().getAccessToken());
Assert.assertNotNull(response.getTokens().getRefreshToken());
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
+ Assert.assertNull(getSidFromAccessToken(response.getTokens().getAccessToken()));
+ Assert.assertNull(getSidFromRefreshToken(response.getTokens().getRefreshToken()));
+ Assert.assertNull(getSidFromJWT(response.getOIDCTokens().getIDToken()));
}
+ @Test
+ public void testValidGrantWithSid() throws Exception {
+ final String sid = idGenerator.generateIdentifier();
+ initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
+ buildAuthorizationCodeWithSid(clientId, sid), clientId));
+ storeConsent(storageService, "jdoe", clientId, "mail");
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ Assert.assertNotNull(response.getTokens().getAccessToken());
+ Assert.assertNotNull(response.getTokens().getRefreshToken());
+ Assert.assertNotNull(response.getOIDCTokens().getIDToken());
+ Assert.assertEquals(getSidFromAccessToken(response.getTokens().getAccessToken()), sid);
+ Assert.assertEquals(getSidFromRefreshToken(response.getTokens().getRefreshToken()), sid);
+ Assert.assertEquals(getSidFromJWT(response.getOIDCTokens().getIDToken()), sid);
+ }
@Test
public void testValidGrantNonMatchingRedirectURI() throws Exception {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri + "wrong", "authorization_code",
@@ -345,6 +367,8 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
final AccessToken accessToken = response.getTokens().getAccessToken();
Assert.assertNotNull(accessToken);
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
+ Assert.assertNull(getSidFromAccessToken(accessToken));
+ Assert.assertNull(getSidFromJWT(response.getOIDCTokens().getIDToken()));
validateConsentFromAccessToken(response, false);
}
@@ -357,6 +381,8 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
final AccessToken accessToken = response.getTokens().getAccessToken();
Assert.assertNotNull(accessToken);
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
+ Assert.assertNull(getSidFromAccessToken(accessToken));
+ Assert.assertNull(getSidFromJWT(response.getOIDCTokens().getIDToken()));
validateConsentFromAccessToken(response, true);
}
@@ -387,7 +413,11 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
protected String buildAuthorizationCode(final String clientId) throws Exception {
return buildAuthorizationCode(clientId, null);
}
-
+
+ protected String buildAuthorizationCodeWithSid(final String clientId, final String sid) throws Exception {
+ return buildAuthorizationCodeWithSid(clientId, null, null, null, null, sid);
+ }
+
protected String buildAuthorizationCode(final String clientId, final String verifier) throws Exception {
return buildAuthorizationCode(clientId, verifier, null, null, null);
}
@@ -399,7 +429,36 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
redirectUri, verifier, deliveryClaims, deliveryClaimsIDToken, deliveryClaimsUserInfo,
"openid profile email offline_access").toString();
}
-
+
+ protected String buildAuthorizationCodeWithSid(final String clientId, final String verifier,
+ final JSONObject deliveryClaims, final JSONObject deliveryClaimsIDToken,
+ final JSONObject deliveryClaimsUserInfo, final String sid) throws Exception {
+ final AuthorizeCodeClaimsSet.Builder builder = new AuthorizeCodeClaimsSet.Builder();
+ builder.setJWTID(new SecureRandomIdentifierGenerationStrategy())
+ .setClientID(new ClientID(clientId))
+ .setIssuer("https://op.example.org")
+ .setPrincipal("jdoe")
+ .setSubject("mock")
+ .setIssuedAt(Instant.now())
+ .setExpiresAt(Instant.now().plusSeconds(100))
+ .setAuthenticationTime(Instant.now())
+ .setRedirectURI(new URI(redirectUri))
+ .setScope(scope)
+ .setSessionIdentifier(sid);
+
+ if (deliveryClaims != null) {
+ builder.setDlClaims(new ClaimsSet(deliveryClaims));
+ }
+ if (deliveryClaimsIDToken != null) {
+ builder.setDlClaimsID(new ClaimsSet(deliveryClaimsIDToken));
+ }
+ if (deliveryClaimsUserInfo != null) {
+ builder.setDlClaimsUI(new ClaimsSet(deliveryClaimsUserInfo));
+ }
+
+ return builder.build().serialize(getDataSealer());
+ }
+
protected String buildLegacyAuthorizationCode(final String clientId, final String... consentedClaims)
throws Exception {
final String json = buildJsonForLegacyToken("jdoe", clientId, Scope.parse("openid email"), "ac",
@@ -426,6 +485,19 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
return new RefreshToken(rtClaims.serialize(new ValidateGrantTest().getDataSealer())).getValue();
}
+ protected String buildRefreshTokenWithSid(final String clientId, final String id, final String rootId,
+ final Collection<String> aud, final String sid, final String... consentedClaims) throws Exception {
+ final TokenClaimsSet acClaims = ValidateGrantTest.buildTokenClaimsSet(clientId, "https://op.example.org", "jdoe", "mock", redirectUri,
+ null, null, null, null, scope.toString(), aud);
+ final RefreshTokenClaimsSet rtClaims = new RefreshTokenClaimsSet.Builder(acClaims, Instant.now(),
+ Instant.now().plus(Duration.ofHours(1)))
+ .setRootTokenIdentifier(rootId)
+ .setJWTID(id)
+ .setSessionIdentifier(sid)
+ .build();
+ return new RefreshToken(rtClaims.serialize(new ValidateGrantTest().getDataSealer())).getValue();
+ }
+
@Test
public void testValidSecretJWT() throws Exception {
final ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret);
@@ -654,6 +726,27 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
final AccessToken accessToken = response.getTokens().getAccessToken();
Assert.assertNotNull(accessToken);
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
+ Assert.assertNull(getSidFromAccessToken(accessToken));
+ Assert.assertNull(getSidFromJWT(response.getOIDCTokens().getIDToken()));
+ validateConsentFromAccessToken(response, false);
+ Assert.assertFalse(revocationCache.isRevoked(RevocationCacheContexts.SINGLE_ACCESS_OR_REFRESH_TOKENS, id));
+ Assert.assertFalse(revocationCache.isRevoked(RevocationCacheContexts.AUTHORIZATION_CODE, rootId));
+ }
+
+ @Test
+ public void testValidRefreshTokenGrantWithSid() throws Exception {
+ final String id = idGenerator.generateIdentifier();
+ final String rootId = idGenerator.generateIdentifier();
+ final String sid = idGenerator.generateIdentifier();
+ initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "refresh_token",
+ buildRefreshTokenWithSid(clientId, id, rootId, null, sid), clientId));
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final AccessToken accessToken = response.getTokens().getAccessToken();
+ Assert.assertNotNull(accessToken);
+ Assert.assertNotNull(response.getOIDCTokens().getIDToken());
+ Assert.assertEquals(getSidFromAccessToken(accessToken), sid);
+ Assert.assertEquals(getSidFromJWT(response.getOIDCTokens().getIDToken()), sid);
validateConsentFromAccessToken(response, false);
Assert.assertFalse(revocationCache.isRevoked(RevocationCacheContexts.SINGLE_ACCESS_OR_REFRESH_TOKENS, id));
Assert.assertFalse(revocationCache.isRevoked(RevocationCacheContexts.AUTHORIZATION_CODE, rootId));
@@ -825,4 +918,35 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
}
+ protected String getSidFromAccessToken(final AccessToken accessToken) {
+ Assert.assertNotNull(accessToken.getValue());
+ final AccessTokenClaimsSet claims;
+ try {
+ claims = AccessTokenClaimsSet.parse(accessToken.getValue(), getDataSealer());
+ return claims.getSessionIdentifier();
+ } catch (ParseException | DataSealerException e) {
+ return null;
+ }
+ }
+
+ protected String getSidFromRefreshToken(final RefreshToken refreshToken) {
+ Assert.assertNotNull(refreshToken.getValue());
+ final RefreshTokenClaimsSet claims;
+ try {
+ claims = RefreshTokenClaimsSet.parse(refreshToken.getValue(), getDataSealer());
+ return claims.getSessionIdentifier();
+ } catch (ParseException | DataSealerException e) {
+ return null;
+ }
+ }
+
+ protected String getSidFromJWT(final JWT jwt) {
+ Assert.assertNotNull(jwt);
+ try {
+ return jwt.getJWTClaimsSet().getStringClaim("sid");
+ } catch (ParseException e) {
+ return null;
+ }
+ }
+
}
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddIDTokenShellTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddIDTokenShellTest.java
index 283399e5..91129692 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddIDTokenShellTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddIDTokenShellTest.java
@@ -26,6 +26,7 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.nimbusds.oauth2.sdk.id.Audience;
+import com.nimbusds.openid.connect.sdk.claims.SessionID;
/** {@link AddIDTokenShell} unit test. */
public class AddIDTokenShellTest extends BaseOIDCResponseActionTest {
@@ -52,6 +53,22 @@ public class AddIDTokenShellTest extends BaseOIDCResponseActionTest {
ActionTestingSupport.assertProceedEvent(event);
Assert.assertTrue(respCtx.getIDToken().getAudience().contains(new Audience(request.getClientID())));
Assert.assertEquals(respCtx.getIDToken().getSubject().getValue(), subject);
+ Assert.assertNull(respCtx.getIDToken().getSessionID());
+ }
+ /**
+ * Test that id token shell is generate with sid.
+ *
+ * @throws ComponentInitializationException
+ */
+ @Test
+ public void testSuccessWithSid() throws ComponentInitializationException {
+ respCtx.setSessionId("mockSid");
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ Assert.assertTrue(respCtx.getIDToken().getAudience().contains(new Audience(request.getClientID())));
+ Assert.assertEquals(respCtx.getIDToken().getSubject().getValue(), subject);
+ Assert.assertEquals(respCtx.getIDToken().getSessionID(), new SessionID("mockSid"));
}
+
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContextTest.java
index a206fe4b..3441dad6 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContextTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAuthorizationCodeToResponseContextTest.java
@@ -91,6 +91,30 @@ public class SetAuthorizationCodeToResponseContextTest extends BaseOIDCResponseA
final AuthorizeCodeClaimsSet ac =
AuthorizeCodeClaimsSet.parse(respCtx.getAuthorizationCode().getValue(), getDataSealer());
Assert.assertNotNull(ac);
+ Assert.assertNull(ac.getSessionIdentifier());
+ }
+
+ /**
+ * Basic success case with session identifier.
+ *
+ * @throws ComponentInitializationException
+ * @throws NoSuchAlgorithmException
+ * @throws URISyntaxException
+ * @throws ParseException
+ * @throws DataSealerException
+ */
+ @Test
+ public void testSuccessWithSid() throws ComponentInitializationException, NoSuchAlgorithmException,
+ URISyntaxException, ParseException, DataSealerException {
+ init();
+ respCtx.setSessionId("mockSid");
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ Assert.assertNotNull(respCtx.getAuthorizationCode());
+ final AuthorizeCodeClaimsSet ac =
+ AuthorizeCodeClaimsSet.parse(respCtx.getAuthorizationCode().getValue(), getDataSealer());
+ Assert.assertNotNull(ac);
+ Assert.assertEquals(ac.getSessionIdentifier(), "mockSid");
}
@Test
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSessionIdToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSessionIdToResponseContextTest.java
new file mode 100644
index 00000000..525138fe
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSessionIdToResponseContextTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.plugin.oidc.op.profile.context.navigate.TokenRequestSessionIdLookupFunction;
+import net.shibboleth.idp.plugin.oidc.op.token.support.AccessTokenClaimsSet;
+import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.UnmodifiableComponentException;
+import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.NoSuchAlgorithmException;
+import java.time.Instant;
+import java.util.function.Function;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.springframework.webflow.execution.Event;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+
+/** {@link SetSessionIdToResponseContext} unit test. */
+public class SetSessionIdToResponseContextTest extends BaseOIDCResponseActionTest {
+
+ /** Action. */
+ private SetSessionIdToResponseContext action;
+
+ private void init() throws ComponentInitializationException {
+ init(new TokenRequestSessionIdLookupFunction());
+ }
+
+ private void init(final Function<ProfileRequestContext, String> strategy)
+ throws ComponentInitializationException {
+ action = new SetSessionIdToResponseContext();
+ action.setSessionIdLookupStrategy(strategy);
+ action.initialize();
+ }
+
+ /**
+ * Test that action throws error when null strategy is set.
+ */
+ @Test(expectedExceptions = ConstraintViolationException.class)
+ public void testNoStrategy() {
+ action = new SetSessionIdToResponseContext();
+ action.setSessionIdLookupStrategy(null);
+ }
+
+ /**
+ * Test that action throws error when strategy is being set when already initialized.
+ *
+ * @throws NoSuchAlgorithmException
+ * @throws ComponentInitializationException
+ */
+ @Test(expectedExceptions = UnmodifiableComponentException.class)
+ public void testInitialized() throws NoSuchAlgorithmException, ComponentInitializationException {
+ init();
+ action.setSessionIdLookupStrategy(new TokenRequestSessionIdLookupFunction());
+ }
+
+ /**
+ * Test that action copies session id to response ctx.
+ *
+ * @throws ComponentInitializationException
+ * @throws URISyntaxException
+ */
+ @Test
+ public void testSuccessWithoutValue() throws 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.assertProceedEvent(event);
+ Assert.assertNull(respCtx.getSessionId());
+ }
+
+ /**
+ * Test that action copies session id to response ctx.
+ *
+ * @throws ComponentInitializationException
+ * @throws URISyntaxException
+ */
+ @Test
+ public void testSuccessWithValue() throws 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())
+ .setSessionIdentifier("mockSid")
+ .build();
+ respCtx.setAuthorizationGrantClaimsSet(claims);
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ Assert.assertEquals(respCtx.getSessionId(), "mockSid");
+ }
+
+}
\ 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