[java-idp-oidc] branch main updated: JOIDC-37 Refactor user consent logic
Henri Mikkonen
henri.mikkonen at iki.fi
Sun Mar 7 13:33:52 UTC 2021
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=cdb63d84b623acb7e16a1a07c48eefefe2d96962
The following commit(s) were added to refs/heads/main by this push:
new cdb63d84 JOIDC-37 Refactor user consent logic
cdb63d84 is described below
commit cdb63d84b623acb7e16a1a07c48eefefe2d96962
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Sun Mar 7 15:29:15 2021 +0200
JOIDC-37 Refactor user consent logic
https://issues.shibboleth.net/jira/browse/JOIDC-37
- By default, exploit attribute-release-query instead of direct ctx access
- Added property 'idp.oidc.encodeConsentInTokens' to enable storing consent inside tokens
- Got rid of consentable claim -concept inside the tokens & authz code
Initial testing done successfully, more still needed.
---
.../OIDCAuthenticationResponseConsentContext.java | 15 ---
.../op/token/support/AccessTokenClaimsSet.java | 14 +--
.../op/token/support/AuthorizeCodeClaimsSet.java | 14 +--
.../op/token/support/RefreshTokenClaimsSet.java | 4 +-
.../oidc/op/token/support/TokenClaimsSet.java | 68 +++++-----
...DCAuthenticationResponseConsentContextTest.java | 3 -
.../BaseTokenRequestLookupFunctionTest.java | 6 +-
...estConsentableAttributesLookupFunctionTest.java | 37 ------
.../oidc/op/token/support/TokenClaimsSetTest.java | 11 +-
.../support/testing/BaseTokenClaimsSetTest.java | 3 +-
.../op/config/OIDCCoreProtocolConfiguration.java | 34 +++++
...uteConsentEnabledInTokenClaimsSetPredicate.java | 49 ++++++++
.../AttributeConsentFlowEnabledPredicate.java | 29 ++---
.../op/profile/impl/AddAttributesToClaimsSet.java | 3 +-
.../impl/SetAccessTokenToResponseContext.java | 31 +++--
.../SetAuthorizationCodeToResponseContext.java | 32 +++--
.../impl/SetConsentFromTokenToResponseContext.java | 22 +---
.../profile/impl/SetConsentToResponseContext.java | 139 ++++++++++++++-------
.../oidc/consent-lookup/consent-lookup-beans.xml | 21 ++++
.../oidc/consent-lookup/consent-lookup-flow.xml | 29 +++++
.../shibboleth/idp/flows/oidc/token/token-flow.xml | 6 +-
.../idp/flows/oidc/userinfo/token-flow.xml | 6 +-
.../idp/service/relying-party/postconfig.xml | 9 ++
.../idp/plugin/oidc/op/conf/oidc.properties | 5 +-
.../oidc/op/profile/flow/AbstractOidcFlowTest.java | 10 ++
.../plugin/oidc/op/profile/flow/TokenFlowTest.java | 12 +-
.../plugin/oidc/op/profile/flow/UserInfoTest.java | 1 +
.../profile/impl/AddAttributesToClaimsSetTest.java | 4 +-
.../impl/SetAccessTokenToResponseContextTest.java | 4 -
.../SetAuthorizationCodeToResponseContextTest.java | 4 -
.../SetConsentFromTokenToResponseContextTest.java | 7 +-
.../impl/SetConsentToResponseContextTest.java | 86 ++++++-------
.../impl/SetSubjectToResponseContextTest.java | 3 -
.../oidc/op/profile/impl/ValidateGrantTest.java | 14 ++-
.../src/test/resources/conf/idp.properties | 1 +
.../EntityDescriptor-with-oidcmd-clientsecret.xml | 10 +-
36 files changed, 445 insertions(+), 301 deletions(-)
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseConsentContext.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseConsentContext.java
index e46bf667..dd74113f 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseConsentContext.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseConsentContext.java
@@ -33,16 +33,11 @@ public class OIDCAuthenticationResponseConsentContext extends BaseContext {
@Nullable
private JSONArray consentedAttributes;
- /** Attributes requiring consent. */
- @Nullable
- private JSONArray consentableAttributes;
-
/**
* Constructor.
*/
public OIDCAuthenticationResponseConsentContext() {
consentedAttributes = new JSONArray();
- consentableAttributes = new JSONArray();
}
/**
@@ -55,14 +50,4 @@ public class OIDCAuthenticationResponseConsentContext extends BaseContext {
return consentedAttributes;
}
- /**
- * Get consentable attributes.
- *
- * @return consentable attributes.
- */
- @Nonnull
- public JSONArray getConsentableAttributes() {
- return consentableAttributes;
- }
-
}
\ 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 2b9743ed..de4adee0 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
@@ -68,8 +68,8 @@ public final class AccessTokenClaimsSet extends TokenClaimsSet {
tokenClaimSet.getClaimsSet().getSubject(),
tokenClaimSet.getACR() == null ? null : new ACR(tokenClaimSet.getACR()), iat, exp,
tokenClaimSet.getNonce(), tokenClaimSet.getAuthenticationTime(), tokenClaimSet.getRedirectURI(), scope,
- tokenClaimSet.getClaimsRequest(), dlClaims, null, dlClaimsUI, tokenClaimSet.getConsentableClaims(),
- tokenClaimSet.getConsentedClaims(), null);
+ tokenClaimSet.getClaimsRequest(), dlClaims, null, dlClaimsUI, tokenClaimSet.getConsentedClaims(),
+ null, tokenClaimSet.isConsentEnabled());
}
/**
@@ -90,8 +90,8 @@ public final class AccessTokenClaimsSet extends TokenClaimsSet {
* @param claims Claims request of the authentication request. May be NULL.
* @param dlClaims token delivery claims delivered both for id token and userinfo response. May be NULL.
* @param dlClaimsUI token delivery claims delivered for userinfo response. May be NULL.
- * @param consentableClaims consentable claims. May be NULL.
* @param consentedClaims consented claims. May be NULL.
+ * @param consentEnabled Whether consent has been enabled.
* @throws RuntimeException if called with nonallowed null parameters
*/
private AccessTokenClaimsSet(@Nonnull final IdentifierGenerationStrategy idGenerator,
@@ -100,10 +100,10 @@ public final class AccessTokenClaimsSet extends TokenClaimsSet {
@Nonnull final Instant exp, @Nullable final Nonce nonce, @Nonnull final Instant authTime,
@Nonnull final URI redirectURI, @Nonnull final Scope scope, @Nullable final OIDCClaimsRequest claims,
@Nullable final ClaimsSet dlClaims, @Nullable final ClaimsSet dlClaimsUI,
- @Nullable final List<Object> consentableClaims, @Nullable final List<Object> consentedClaims) {
+ @Nullable final List<Object> consentedClaims, final boolean consentEnabled) {
super(VALUE_TYPE_AT, idGenerator.generateIdentifier(), clientID, issuer, userPrincipal, subject, acr, iat, exp,
- nonce, authTime, redirectURI, scope, claims, dlClaims, null, dlClaimsUI, consentableClaims,
- consentedClaims, null);
+ nonce, authTime, redirectURI, scope, claims, dlClaims, null, dlClaimsUI, consentedClaims, null,
+ consentEnabled);
}
/**
@@ -175,7 +175,7 @@ public final class AccessTokenClaimsSet extends TokenClaimsSet {
*/
public AccessTokenClaimsSet build() {
return new AccessTokenClaimsSet(idGen, rpId, iss, usrPrincipal, sub, acr, iat, exp, nonce, authTime,
- redirect, reqScope, claims, dlClaims, dlClaimsUI, cnsntlClaims, cnsntdClaims);
+ redirect, reqScope, claims, dlClaims, dlClaimsUI, cnsntdClaims, cnsntEnabled);
}
}
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/AuthorizeCodeClaimsSet.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/AuthorizeCodeClaimsSet.java
index 1a888742..f081a17a 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/AuthorizeCodeClaimsSet.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/token/support/AuthorizeCodeClaimsSet.java
@@ -61,9 +61,9 @@ public final class AuthorizeCodeClaimsSet extends TokenClaimsSet {
* @param dlClaims Token delivery claims delivered both for id token and userinfo response. May be NULL.
* @param dlClaimsID Token delivery claims delivered for id token. May be NULL.
* @param dlClaimsUI Token delivery claims delivered for userinfo response. May be NULL.
- * @param consentableClaims consentable claims. May be NULL.
* @param consentedClaims consented claims. May be NULL.
* @param codeChallenge Code Challenge. May be NULL.
+ * @param consentEnabled Whether consent has been enabled.
* @throws RuntimeException if called with nonallowed null parameters
*/
private AuthorizeCodeClaimsSet(@Nonnull final IdentifierGenerationStrategy idGenerator,
@@ -72,11 +72,11 @@ public final class AuthorizeCodeClaimsSet extends TokenClaimsSet {
@Nonnull final Instant exp, @Nullable final Nonce nonce, @Nonnull final Instant authTime,
@Nonnull final URI redirectURI, @Nonnull final Scope scope, @Nullable final OIDCClaimsRequest claims,
@Nullable final ClaimsSet dlClaims, @Nullable final ClaimsSet dlClaimsID,
- @Nullable final ClaimsSet dlClaimsUI, @Nullable final List<Object> consentableClaims,
- @Nullable final List<Object> consentedClaims, @Nullable final String codeChallenge) {
+ @Nullable final ClaimsSet dlClaimsUI, @Nullable final List<Object> consentedClaims,
+ @Nullable final String codeChallenge, final boolean consentEnabled) {
super(VALUE_TYPE_AC, idGenerator.generateIdentifier(), clientID, issuer, userPrincipal, subject, acr, iat, exp,
- nonce, authTime, redirectURI, scope, claims, dlClaims, dlClaimsID, dlClaimsUI, consentableClaims,
- consentedClaims, codeChallenge);
+ nonce, authTime, redirectURI, scope, claims, dlClaims, dlClaimsID, dlClaimsUI, consentedClaims,
+ codeChallenge, consentEnabled);
}
/**
@@ -148,8 +148,8 @@ public final class AuthorizeCodeClaimsSet extends TokenClaimsSet {
*/
public AuthorizeCodeClaimsSet build() {
return new AuthorizeCodeClaimsSet(idGen, rpId, iss, usrPrincipal, sub, acr, iat, exp, nonce, authTime,
- redirect, reqScope, claims, dlClaims, dlClaimsID, dlClaimsUI, cnsntlClaims, cnsntdClaims,
- codeChallenge);
+ redirect, reqScope, claims, dlClaims, dlClaimsID, dlClaimsUI, cnsntdClaims,
+ codeChallenge, cnsntEnabled);
}
}
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 26e4f191..8518241d 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
@@ -54,8 +54,8 @@ public final class RefreshTokenClaimsSet extends TokenClaimsSet {
tokenClaimsSet.getACR() == null ? null : new ACR(tokenClaimsSet.getACR()), iat, exp,
tokenClaimsSet.getNonce(), tokenClaimsSet.getAuthenticationTime(), tokenClaimsSet.getRedirectURI(),
tokenClaimsSet.getScope(), tokenClaimsSet.getClaimsRequest(), tokenClaimsSet.getDeliveryClaims(), null,
- tokenClaimsSet.getUserinfoDeliveryClaims(), tokenClaimsSet.getConsentableClaims(),
- tokenClaimsSet.getConsentedClaims(), null);
+ tokenClaimsSet.getUserinfoDeliveryClaims(), tokenClaimsSet.getConsentedClaims(), null,
+ tokenClaimsSet.isConsentEnabled());
}
/**
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 f04629f0..15e2345c 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
@@ -102,11 +102,11 @@ public class TokenClaimsSet {
/** Claims set for token delivery, user info only. */
public static final String KEY_DELIVERY_CLAIMS_USERINFO = "dl_claims_ui";
- /** Claims/Attributes requiring consent. */
- public static final String KEY_CONSENTABLE_CLAIMS = "cnsntbl_claims";
-
/** Claims/Attributes having consent. */
public static final String KEY_CONSENTED_CLAIMS = "cnsntd_claims";
+
+ /** Whether consent has been enabled. */
+ public static final String KEY_CONSENT_ENABLED = "cnsnt";
/** Code Challenge. */
public static final String KEY_CODE_CHALLENGE = "cc";
@@ -144,9 +144,9 @@ public class TokenClaimsSet {
* @param dlClaims token delivery claims delivered both for id token and userinfo response. May be NULL.
* @param dlClaimsID token delivery claims delivered for id token. May be NULL.
* @param dlClaimsUI token delivery claims delivered for userinfo response. May be NULL.
- * @param consentableClaims consentable claims. May be NULL.
* @param consentedClaims consented claims. May be NULL.
* @param codeChallenge Code Challenge. May be NULL.
+ * @param consentEnabled Whether consent has been enabled.
* @throws RuntimeException if called with not allowed null parameters
*/
// Checkstyle: CyclomaticComplexity OFF
@@ -156,8 +156,8 @@ public class TokenClaimsSet {
@Nullable final Nonce nonce, @Nonnull final Instant authTime, @Nonnull final URI redirectURI,
@Nonnull final Scope scope, @Nullable final OIDCClaimsRequest claims, @Nullable final ClaimsSet dlClaims,
@Nullable final ClaimsSet dlClaimsID, @Nullable final ClaimsSet dlClaimsUI,
- @Nullable final List<Object> consentableClaims, @Nullable final List<Object> consentedClaims,
- @Nullable final String codeChallenge) {
+ @Nullable final List<Object> consentedClaims, @Nullable final String codeChallenge,
+ final boolean consentEnabled) {
if (tokenType == null || tokenID == null || clientID == null || issuer == null || userPrincipal == null
|| iat == null || exp == null || authTime == null || redirectURI == null || scope == null
|| subject == null) {
@@ -173,8 +173,8 @@ public class TokenClaimsSet {
.claim(KEY_DELIVERY_CLAIMS, dlClaims == null ? null : dlClaims.toJSONObject())
.claim(KEY_DELIVERY_CLAIMS_IDTOKEN, dlClaimsID == null ? null : dlClaimsID.toJSONObject())
.claim(KEY_DELIVERY_CLAIMS_USERINFO, dlClaimsUI == null ? null : dlClaimsUI.toJSONObject())
- .claim(KEY_CONSENTABLE_CLAIMS, consentableClaims).claim(KEY_CONSENTED_CLAIMS, consentedClaims)
- .claim(KEY_CODE_CHALLENGE, codeChallenge).build();
+ .claim(KEY_CONSENTED_CLAIMS, consentedClaims).claim(KEY_CODE_CHALLENGE, codeChallenge)
+ .claim(KEY_CONSENT_ENABLED, consentEnabled).build();
}
@@ -228,14 +228,13 @@ public class TokenClaimsSet {
if (tokenClaimsSet.getClaims().containsKey(KEY_ACR)) {
tokenClaimsSet.getStringClaim(KEY_ACR);
}
- if (tokenClaimsSet.getClaims().containsKey(KEY_CONSENTABLE_CLAIMS)
- && !(tokenClaimsSet.getClaim(KEY_CONSENTABLE_CLAIMS) instanceof List)) {
- throw new ParseException("consentable claims is of wrong type", 0);
- }
if (tokenClaimsSet.getClaims().containsKey(KEY_CONSENTED_CLAIMS)
&& !(tokenClaimsSet.getClaim(KEY_CONSENTED_CLAIMS) instanceof List)) {
throw new ParseException("consented claims is of wrong type", 0);
}
+ if (tokenClaimsSet.getClaims().containsKey(KEY_CONSENT_ENABLED)) {
+ tokenClaimsSet.getBooleanClaim(KEY_CONSENT_ENABLED);
+ }
if (tokenClaimsSet.getClaims().containsKey(KEY_CLAIMS)) {
tokenClaimsSet.getJSONObjectClaim(KEY_CLAIMS);
}
@@ -463,21 +462,27 @@ public class TokenClaimsSet {
}
/**
- * Get consentable claims.
+ * Get consented claims.
*
- * @return consentable claims
+ * @return consented claims
*/
- public List<Object> getConsentableClaims() {
- return (List<Object>) tokenClaimsSet.getClaim(KEY_CONSENTABLE_CLAIMS);
+ public List<Object> getConsentedClaims() {
+ return (List<Object>) tokenClaimsSet.getClaim(KEY_CONSENTED_CLAIMS);
}
/**
- * Get consented claims.
+ * Get whether consent has been enabled.
*
- * @return consented claims
+ * @return whether consent has been enabled
*/
- public List<Object> getConsentedClaims() {
- return (List<Object>) tokenClaimsSet.getClaim(KEY_CONSENTED_CLAIMS);
+ public boolean isConsentEnabled() {
+ try {
+ return tokenClaimsSet.getBooleanClaim(KEY_CONSENT_ENABLED).booleanValue();
+ } catch (final ParseException e) {
+ log.error("Error parsing scope in request {}", tokenClaimsSet.getClaim(KEY_CONSENT_ENABLED));
+ // should never happen, programming error.
+ return false;
+ }
}
/**
@@ -600,13 +605,12 @@ public class TokenClaimsSet {
@Nullable
protected ClaimsSet dlClaimsUI;
- /** Consentable claims. */
- @Nullable
- protected List<Object> cnsntlClaims;
-
/** consented claims. */
@Nullable
protected List<Object> cnsntdClaims;
+
+ /** Has consent been asked from the end-user. */
+ protected boolean cnsntEnabled;
/** Code challenge. */
@Nullable
@@ -717,26 +721,26 @@ public class TokenClaimsSet {
}
/**
- * Set consentable claims.
+ * Set consented claims.
*
- * @param consentableClaims consentable claims
+ * @param consentedClaims consented claims
*
* @return the builder
*/
- public Builder<T> setConsentableClaims(@Nullable final List<Object> consentableClaims) {
- cnsntlClaims = consentableClaims;
+ public Builder<T> setConsentedClaims(@Nullable final List<Object> consentedClaims) {
+ cnsntdClaims = consentedClaims;
return this;
}
/**
- * Set consented claims.
+ * Set whether consent has been enabled.
*
- * @param consentedClaims consented claims
+ * @param consentEnabled whether consent has been enabled.
*
* @return the builder
*/
- public Builder<T> setConsentedClaims(@Nullable final List<Object> consentedClaims) {
- cnsntdClaims = consentedClaims;
+ public Builder<T> setConsentEnabled(final boolean consentEnabled) {
+ cnsntEnabled = consentEnabled;
return this;
}
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseConsentContextTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseConsentContextTest.java
index f0446c58..28b76cb0 100644
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseConsentContextTest.java
+++ b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseConsentContextTest.java
@@ -21,8 +21,6 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseConsentContext;
-
/** Tests for {@link OIDCAuthenticationResponseConsentContext}. */
public class OIDCAuthenticationResponseConsentContextTest {
@@ -35,7 +33,6 @@ public class OIDCAuthenticationResponseConsentContextTest {
@Test
public void testInitialState() {
- Assert.assertNotNull(ctx.getConsentableAttributes());
Assert.assertNotNull(ctx.getConsentedAttributes());
}
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/BaseTokenRequestLookupFunctionTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/BaseTokenRequestLookupFunctionTest.java
index cb72e4ac..d62c916a 100644
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/BaseTokenRequestLookupFunctionTest.java
+++ b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/BaseTokenRequestLookupFunctionTest.java
@@ -19,7 +19,6 @@ package net.shibboleth.idp.plugin.oidc.op.profile.context.navigate;
import net.minidev.json.JSONArray;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
-import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.AbstractTokenRequestLookupFunction;
import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
import net.shibboleth.idp.plugin.oidc.op.token.support.TokenDeliveryClaimsClaimsSet;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
@@ -84,8 +83,6 @@ public class BaseTokenRequestLookupFunctionTest {
protected ClaimsSet tokenToUserInfoTokenDeliveryClaims = new TokenDeliveryClaimsClaimsSet();
- protected JSONArray consentableClaims = new JSONArray();
-
protected JSONArray consentedClaims = new JSONArray();
BaseTokenRequestLookupFunctionTest() {
@@ -100,7 +97,6 @@ public class BaseTokenRequestLookupFunctionTest {
tokenDeliveryClaims.setClaim("tokenDelivery", "value");
tokenToIdTokenDeliveryClaims.setClaim("tokenToIdtokenDelivery", "value");
tokenToUserInfoTokenDeliveryClaims.setClaim("tokenToUserInfotokenDeliveryClaim", "value");
- consentableClaims.add("consentableClaim");
consentedClaims.add("consentedClaim");
}
@@ -115,7 +111,7 @@ public class BaseTokenRequestLookupFunctionTest {
cliendID, issuer, userPrin, subject, iat, exp, authTime, redirectUri, scope).setACR(acr).setNonce(nonce)
.setClaims(claimsRequest).setDlClaims(tokenDeliveryClaims)
.setDlClaimsID(tokenToIdTokenDeliveryClaims).setDlClaimsUI(tokenToUserInfoTokenDeliveryClaims)
- .setConsentableClaims(consentableClaims).setConsentedClaims(consentedClaims).build());
+ .setConsentedClaims(consentedClaims).build());
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestConsentableAttributesLookupFunctionTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestConsentableAttributesLookupFunctionTest.java
deleted file mode 100644
index eb06e4a3..00000000
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestConsentableAttributesLookupFunctionTest.java
+++ /dev/null
@@ -1,37 +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.context.navigate;
-
-import org.testng.annotations.Test;
-
-import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestConsentableAttributesLookupFunction;
-
-import org.testng.Assert;
-
-/** Test for {@link TokenRequestConsentableAttributesLookupFunction}. */
-public class TokenRequestConsentableAttributesLookupFunctionTest extends BaseTokenRequestLookupFunctionTest {
-
- private TokenRequestConsentableAttributesLookupFunction lookup =
- new TokenRequestConsentableAttributesLookupFunction();
-
- @Test
- public void testLookup() {
- Assert.assertTrue(lookup.apply(prc).contains("consentableClaim"));
- }
-
-}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/token/support/TokenClaimsSetTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/token/support/TokenClaimsSetTest.java
index 126bb516..f76ec979 100644
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/token/support/TokenClaimsSetTest.java
+++ b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/token/support/TokenClaimsSetTest.java
@@ -19,7 +19,6 @@ package net.shibboleth.idp.plugin.oidc.op.token.support;
import org.testng.annotations.Test;
-import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
import net.shibboleth.idp.plugin.oidc.op.token.support.testing.BaseTokenClaimsSetTest;
import java.time.temporal.ChronoUnit;
@@ -39,8 +38,8 @@ public class TokenClaimsSetTest extends BaseTokenClaimsSetTest {
protected void init() {
tokenClaimsSet = new TokenClaimsSet(tokenType, tokenID, clientID, issuer, userPrincipal, subject, acr, iat, exp,
- nonce, authTime, redirectURI, scope, claims, dlClaims, dlClaimsID, dlClaimsUI, consentableClaims,
- consentedClaims, codeChallenge);
+ nonce, authTime, redirectURI, scope, claims, dlClaims, dlClaimsID, dlClaimsUI, consentedClaims,
+ codeChallenge, consentEnabled);
}
@Test
@@ -58,27 +57,27 @@ public class TokenClaimsSetTest extends BaseTokenClaimsSetTest {
Assert.assertEquals(tokenClaimsSet.getUserinfoDeliveryClaims().getClaim("tokenToUserInfotokenDeliveryClaim"),
"value");
Assert.assertEquals(tokenClaimsSet.getClientID(), clientID);
- Assert.assertTrue(tokenClaimsSet.getConsentableClaims().contains("consentableClaim"));
Assert.assertTrue(tokenClaimsSet.getConsentedClaims().contains("consentedClaim"));
Assert.assertEquals(tokenClaimsSet.getExp(), exp.truncatedTo(ChronoUnit.MILLIS));
Assert.assertEquals(tokenClaimsSet.getNonce(), nonce);
Assert.assertEquals(tokenClaimsSet.getRedirectURI(), redirectURI);
Assert.assertEquals(tokenClaimsSet.getScope(), scope);
Assert.assertEquals(tokenClaimsSet.getCodeChallenge(), codeChallenge);
+ Assert.assertEquals(tokenClaimsSet.isConsentEnabled(), consentEnabled);
}
@Test
public void testNullGetters() {
tokenClaimsSet = new TokenClaimsSet(tokenType, tokenID, clientID, issuer, userPrincipal, subject, null, iat,
- exp, null, authTime, redirectURI, scope, null, null, null, null, null, null, null);
+ exp, null, authTime, redirectURI, scope, null, null, null, null, null, null, false);
Assert.assertNull(tokenClaimsSet.getACR());
Assert.assertNull(tokenClaimsSet.getClaimsRequest());
Assert.assertNull(tokenClaimsSet.getDeliveryClaims());
Assert.assertNull(tokenClaimsSet.getIDTokenDeliveryClaims());
Assert.assertNull(tokenClaimsSet.getUserinfoDeliveryClaims());
- Assert.assertNull(tokenClaimsSet.getConsentableClaims());
Assert.assertNull(tokenClaimsSet.getConsentedClaims());
Assert.assertNull(tokenClaimsSet.getNonce());
+ Assert.assertFalse(tokenClaimsSet.isConsentEnabled());
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/token/support/testing/BaseTokenClaimsSetTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/token/support/testing/BaseTokenClaimsSetTest.java
index 7673c86d..bd54167a 100644
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/token/support/testing/BaseTokenClaimsSetTest.java
+++ b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/token/support/testing/BaseTokenClaimsSetTest.java
@@ -76,7 +76,7 @@ public class BaseTokenClaimsSetTest {
protected Instant authTime = Instant.now();
- protected JSONArray consentableClaims = new JSONArray();;
+ protected boolean consentEnabled = false;
protected ClaimsSet dlClaimsID = new TokenDeliveryClaimsClaimsSet();
@@ -109,7 +109,6 @@ public class BaseTokenClaimsSetTest {
dlClaims.setClaim("tokenDelivery", "value");
dlClaimsID.setClaim("tokenToIdtokenDeliveryClaim", "value");
dlClaimsUI.setClaim("tokenToUserInfotokenDeliveryClaim", "value");
- consentableClaims.add("consentableClaim");
consentedClaims.add("consentedClaim");
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/OIDCCoreProtocolConfiguration.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/OIDCCoreProtocolConfiguration.java
index 028be678..d863f72d 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/OIDCCoreProtocolConfiguration.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/OIDCCoreProtocolConfiguration.java
@@ -73,6 +73,9 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
/** Whether client is allowed to use PKCE code challenge method plain. */
@Nonnull private Predicate<ProfileRequestContext> allowPKCEPlainPredicate;
+ /** Whether to encode consent in authorization code and access/refresh tokens. */
+ @Nonnull private Predicate<ProfileRequestContext> encodeConsentInTokensPredicate;
+
/** Lookup function to override issuer value. */
@Nonnull private Function<ProfileRequestContext,String> issuerLookupStrategy;
@@ -141,6 +144,7 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
acrRequestAlwaysEssentialPredicate = Predicates.alwaysFalse();
forcePKCEPredicate = Predicates.alwaysFalse();
allowPKCEPlainPredicate = Predicates.alwaysFalse();
+ encodeConsentInTokensPredicate = Predicates.alwaysFalse();
defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
@@ -657,6 +661,36 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
public void setAllowPKCEPlainPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
allowPKCEPlainPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
}
+
+
+ /**
+ * Get whether to encode consent in authorization code and access/refresh tokens.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether to encode consent in authorization code and access/refresh tokens
+ */
+ public boolean isEncodeConsentInTokens(@Nullable final ProfileRequestContext profileRequestContext) {
+ return encodeConsentInTokensPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether to encode consent in authorization code and access/refresh tokens.
+ *
+ * @param flag flag to set
+ */
+ public void setEncodeConsentInTokens(final boolean flag) {
+ encodeConsentInTokensPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition for whether to encode consent in authorization code and access/refresh tokens.
+ *
+ * @param condition condition to set
+ */
+ public void setEncodeConsentInTokensPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ encodeConsentInTokensPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+ }
/**
* Get the set of attribute IDs which should be encoded in encrypted form into the authorization code
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/logic/AttributeConsentEnabledInTokenClaimsSetPredicate.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/logic/AttributeConsentEnabledInTokenClaimsSetPredicate.java
new file mode 100644
index 00000000..884d6cfc
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/logic/AttributeConsentEnabledInTokenClaimsSetPredicate.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.config.logic;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
+import net.shibboleth.idp.profile.logic.AbstractRelyingPartyPredicate;
+
+/**
+ * A predicate implementation that checks if attribute consent flag is enabled. The value is fetched from
+ * {@link TokenClaimsSet#isConsentEnabled()} via #{@link OIDCAuthenticationResponseContext#getTokenClaimsSet()}
+ * under outbound message context. Default value is false, if any of the objects in the chain is null.
+ */
+public class AttributeConsentEnabledInTokenClaimsSetPredicate extends AbstractRelyingPartyPredicate {
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final ProfileRequestContext input) {
+ final MessageContext outboundMessageCtx = input.getOutboundMessageContext();
+ if (outboundMessageCtx != null) {
+ final OIDCAuthenticationResponseContext oidcResponseContext =
+ outboundMessageCtx.getSubcontext(OIDCAuthenticationResponseContext.class, false);
+ if (oidcResponseContext != null && oidcResponseContext.getTokenClaimsSet() != null) {
+ return oidcResponseContext.getTokenClaimsSet().isConsentEnabled();
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestConsentableAttributesLookupFunction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/logic/AttributeConsentFlowEnabledPredicate.java
similarity index 50%
rename from idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestConsentableAttributesLookupFunction.java
rename to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/logic/AttributeConsentFlowEnabledPredicate.java
index ac12c60f..0c0a796a 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestConsentableAttributesLookupFunction.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/config/logic/AttributeConsentFlowEnabledPredicate.java
@@ -15,27 +15,24 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.context.navigate;
+package net.shibboleth.idp.plugin.oidc.op.config.logic;
-import java.util.List;
+import javax.annotation.Nullable;
-import javax.annotation.Nonnull;
+import org.opensaml.profile.context.ProfileRequestContext;
-import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
+import net.shibboleth.idp.authn.config.navigate.PostAuthenticationFlowsLookupFunction;
+import net.shibboleth.idp.profile.logic.AbstractRelyingPartyPredicate;
/**
- * For Token and UserInfo end points.
- *
- * A function that returns consentable claims via a lookup function. This lookup locates consentable claims from token
- * (Authorization Code / Access Token) for token request handling. If consentable claims are not available, null is
- * returned.
+ * A predicate implementation that checks if attribute-release is included in the list of post authentication flows
+ * returned by {@link PostAuthenticationFlowsLookupFunction}.
*/
-public class TokenRequestConsentableAttributesLookupFunction extends AbstractTokenClaimsLookupFunction<List<Object>> {
-
+public class AttributeConsentFlowEnabledPredicate extends AbstractRelyingPartyPredicate {
+
/** {@inheritDoc} */
- @Override
- List<Object> doLookup(@Nonnull final TokenClaimsSet tokenClaims) {
- return tokenClaims.getConsentableClaims();
+ public boolean test(@Nullable final ProfileRequestContext input) {
+ final PostAuthenticationFlowsLookupFunction postAuthnFlowsLookup = new PostAuthenticationFlowsLookupFunction();
+ return postAuthnFlowsLookup.apply(input).contains("attribute-release");
}
-
-}
\ No newline at end of file
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddAttributesToClaimsSet.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddAttributesToClaimsSet.java
index d10e68c2..c3b05180 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddAttributesToClaimsSet.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddAttributesToClaimsSet.java
@@ -341,8 +341,7 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
continue;
}
- if (consentCtx != null && consentCtx.getConsentableAttributes().contains(name)
- && !consentCtx.getConsentedAttributes().contains(name)) {
+ if (consentCtx != null && !consentCtx.getConsentedAttributes().contains(name)) {
log.debug("{} Consentable attribute {} has no consent. Not added to claims set",
getLogPrefix(), name);
continue;
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
index 9e0e7ae0..2eb9ca2b 100644
--- 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
@@ -20,6 +20,7 @@ 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;
@@ -35,6 +36,7 @@ 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.config.OIDCCoreProtocolConfiguration;
+import net.shibboleth.idp.plugin.oidc.op.config.logic.AttributeConsentFlowEnabledPredicate;
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;
@@ -84,6 +86,10 @@ public class SetAccessTokenToResponseContext extends AbstractOIDCResponseAction
/** Strategy used to obtain the response issuer value. */
@Nonnull private Function<ProfileRequestContext, String> issuerLookupStrategy;
+ /** 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;
@@ -121,6 +127,7 @@ public class SetAccessTokenToResponseContext extends AbstractOIDCResponseAction
new ChildContextLookup<>(OIDCAuthenticationResponseConsentContext.class).compose(
new OIDCAuthenticationResponseContextLookupFunction());
relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+ consentEnabledPredicate = new AttributeConsentFlowEnabledPredicate();
dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
issuerLookupStrategy = new ResponderIdLookupFunction();
idGeneratorLookupStrategy = FunctionSupport.constant(new SecureRandomIdentifierGenerationStrategy());
@@ -190,6 +197,18 @@ public class SetAccessTokenToResponseContext extends AbstractOIDCResponseAction
issuerLookupStrategy = Constraint.isNotNull(strategy, "IssuerLookupStrategy 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");
+ }
+
// Checkstyle: CyclomaticComplexity OFF
/** {@inheritDoc} */
@Override
@@ -268,14 +287,9 @@ public class SetAccessTokenToResponseContext extends AbstractOIDCResponseAction
claimsSet = new AccessTokenClaimsSet(tokenClaimsSet, getOidcResponseContext().getScope(), claims, claimsUI,
Instant.now(), dateExp);
} else {
- JSONArray consentable = null;
- JSONArray consented = null;
final OIDCAuthenticationResponseConsentContext consentCtx =
consentContextLookupStrategy.apply(profileRequestContext);
- if (consentCtx != null) {
- consentable = consentCtx.getConsentableAttributes();
- consented = consentCtx.getConsentedAttributes();
- }
+ 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(idGenerator, authenticationRequest.getClientID(),
issuerLookupStrategy.apply(profileRequestContext), subjectCtx.getPrincipalName(),
@@ -283,8 +297,9 @@ public class SetAccessTokenToResponseContext extends AbstractOIDCResponseAction
getOidcResponseContext().getAuthTime(), getOidcResponseContext().getRedirectURI(),
getOidcResponseContext().getScope())
.setACR(getOidcResponseContext().getAcr()).setClaims(authenticationRequest.getOIDCClaims())
- .setConsentableClaims(consentable).setConsentedClaims(consented).setDlClaims(claims)
- .setDlClaimsUI(claimsUI).setNonce(authenticationRequest.getNonce()).build();
+ .setConsentedClaims(consented).setDlClaims(claims)
+ .setDlClaimsUI(claimsUI).setNonce(authenticationRequest.getNonce())
+ .setConsentEnabled(consentEnabledPredicate.test(profileRequestContext)).build();
}
try {
getOidcResponseContext().setAccessToken(claimsSet.serialize(dataSealer), accessTokenLifetime);
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 8dc62e3a..2a7b3a8a 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
@@ -20,6 +20,7 @@ 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;
@@ -32,6 +33,7 @@ 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.config.OIDCCoreProtocolConfiguration;
+import net.shibboleth.idp.plugin.oidc.op.config.logic.AttributeConsentFlowEnabledPredicate;
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;
@@ -94,6 +96,10 @@ public class SetAuthorizationCodeToResponseContext extends AbstractOIDCAuthentic
@Nonnull
private Function<ProfileRequestContext, OIDCAuthenticationResponseConsentContext> consentContextLookupStrategy;
+ /** Predicate used to check if consent is enabled with a given {@link ProfileRequestContext}. */
+ @Nonnull
+ private Predicate<ProfileRequestContext> consentEnabledPredicate;
+
/** Strategy used to locate the code challenge. */
@Nonnull private Function<ProfileRequestContext, String> codeChallengeLookupStrategy;
@@ -125,6 +131,7 @@ public class SetAuthorizationCodeToResponseContext extends AbstractOIDCAuthentic
new OIDCAuthenticationResponseContextLookupFunction());
relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
issuerLookupStrategy = new ResponderIdLookupFunction();
+ consentEnabledPredicate = new AttributeConsentFlowEnabledPredicate();
dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
idGeneratorLookupStrategy = FunctionSupport.constant(new SecureRandomIdentifierGenerationStrategy());
}
@@ -215,6 +222,18 @@ public class SetAuthorizationCodeToResponseContext extends AbstractOIDCAuthentic
issuerLookupStrategy = Constraint.isNotNull(strategy, "IssuerLookupStrategy 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 boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
@@ -264,14 +283,9 @@ public class SetAuthorizationCodeToResponseContext extends AbstractOIDCAuthentic
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- JSONArray consentable = null;
- JSONArray consented = null;
final OIDCAuthenticationResponseConsentContext consentCtx =
consentContextLookupStrategy.apply(profileRequestContext);
- if (consentCtx != null) {
- consentable = consentCtx.getConsentableAttributes();
- consented = consentCtx.getConsentedAttributes();
- }
+ final JSONArray consented = consentCtx != null ? consentCtx.getConsentedAttributes() : null;
ClaimsSet claims = null;
ClaimsSet claimsID = null;
ClaimsSet claimsUI = null;
@@ -290,9 +304,9 @@ public class SetAuthorizationCodeToResponseContext extends AbstractOIDCAuthentic
getOidcResponseContext().getScope()).setACR(getOidcResponseContext().getAcr())
.setNonce(new DefaultRequestNonceLookupFunction().apply(profileRequestContext))
.setClaims(getOidcResponseContext().getRequestedClaims()).setDlClaims(claims)
- .setDlClaimsID(claimsID).setDlClaimsUI(claimsUI).setConsentableClaims(consentable)
- .setConsentedClaims(consented)
- .setCodeChallenge(codeChallenge).build();
+ .setDlClaimsID(claimsID).setDlClaimsUI(claimsUI).setConsentedClaims(consented)
+ .setCodeChallenge(codeChallenge)
+ .setConsentEnabled(consentEnabledPredicate.test(profileRequestContext)).build();
// We set token claims set to response context for possible access token generation.
getOidcResponseContext().setTokenClaimsSet(claimsSet);
try {
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentFromTokenToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentFromTokenToResponseContext.java
index f304e931..579a33e4 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentFromTokenToResponseContext.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentFromTokenToResponseContext.java
@@ -23,7 +23,6 @@ import java.util.function.Function;
import javax.annotation.Nonnull;
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.profile.context.navigate.TokenRequestConsentableAttributesLookupFunction;
import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestConsentedAttributesLookupFunction;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -45,15 +44,11 @@ public class SetConsentFromTokenToResponseContext extends AbstractOIDCResponseAc
/** Strategy used to obtain the consented attributes. */
@Nonnull private Function<ProfileRequestContext, List<Object>> consentedAttributesLookupStrategy;
- /** Strategy used to obtain the consentable attributes. */
- @Nonnull private Function<ProfileRequestContext, List<Object>> consentableAttributesLookupStrategy;
-
/**
* Constructor.
*/
public SetConsentFromTokenToResponseContext() {
consentedAttributesLookupStrategy = new TokenRequestConsentedAttributesLookupFunction();
- consentableAttributesLookupStrategy = new TokenRequestConsentableAttributesLookupFunction();
}
/**
@@ -69,28 +64,13 @@ public class SetConsentFromTokenToResponseContext extends AbstractOIDCResponseAc
Constraint.isNotNull(strategy, "ConsentedAttributesLookupStrategy lookup strategy cannot be null");
}
- /**
- * Set the strategy used to locate the consentable attributes.
- *
- * @param strategy lookup strategy
- */
- public void
- setConsentableAttributesLookupStrategy(@Nonnull final Function<ProfileRequestContext,
- List<Object>> strategy) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- consentableAttributesLookupStrategy =
- Constraint.isNotNull(strategy, "ConsentableAttributesLookupStrategy lookup strategy cannot be null");
- }
-
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final List<Object> consentedAttributes = consentedAttributesLookupStrategy.apply(profileRequestContext);
- final List<Object> consentableAttributes = consentableAttributesLookupStrategy.apply(profileRequestContext);
- if (consentedAttributes != null || consentableAttributes != null) {
+ if (consentedAttributes != null) {
final OIDCAuthenticationResponseConsentContext consentClaimsCtx =
getOidcResponseContext().getSubcontext(OIDCAuthenticationResponseConsentContext.class, true);
- consentClaimsCtx.getConsentableAttributes().addAll(consentableAttributes);
consentClaimsCtx.getConsentedAttributes().addAll(consentedAttributes);
}
}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentToResponseContext.java
index 33a9e4b4..7fcb23be 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentToResponseContext.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentToResponseContext.java
@@ -19,6 +19,7 @@ package net.shibboleth.idp.plugin.oidc.op.profile.impl;
import java.util.Map;
import java.util.function.Function;
+import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -30,16 +31,22 @@ import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import net.shibboleth.idp.consent.context.AttributeReleaseContext;
-import net.shibboleth.idp.consent.context.ConsentContext;
+import net.shibboleth.idp.plugin.oidc.op.config.OIDCCoreProtocolConfiguration;
+import net.shibboleth.idp.plugin.oidc.op.config.logic.AttributeConsentFlowEnabledPredicate;
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.consent.Consent;
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.idp.profile.config.ProfileConfiguration;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * Action that checks for any existing consent information for token delivery. Consent information is stored to
+ * Action that checks for adds the currently existing attributes from {@link AttributeContext} for token delivery. They
+ * are assumed to be consented, if they exist in the context. The (consent) information is stored to
* {@link OIDCAuthenticationResponseTokenClaimsContext} that is created under {@link OIDCAuthenticationResponseContext}.
**/
public class SetConsentToResponseContext extends AbstractOIDCResponseAction {
@@ -47,47 +54,72 @@ public class SetConsentToResponseContext extends AbstractOIDCResponseAction {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(SetConsentToResponseContext.class);
- /** Consent context. */
- @Nullable private ConsentContext consentContext;
-
/**
- * Strategy used to find the {@link ConsentContext} from the {@link ProfileRequestContext}.
+ * Strategy used to locate the {@link RelyingPartyContext} associated with a given {@link ProfileRequestContext}.
*/
- @Nonnull private Function<ProfileRequestContext, ConsentContext> consentContextLookupStrategy;
-
- /** The {@link AttributeReleaseContext} to operate on. */
- @Nullable private AttributeReleaseContext attributeReleaseContext;
+ @Nonnull private Function<ProfileRequestContext, RelyingPartyContext> relyingPartyContextLookupStrategy;
/**
- * Strategy used to find the {@link AttributeReleaseContext} from the {@link ProfileRequestContext}.
+ * Strategy used to locate the {@link AttributeContext} associated with a given {@link ProfileRequestContext}.
+ */
+ @Nonnull private Function<ProfileRequestContext,AttributeContext> attributeContextLookupStrategy;
+
+ /**
+ * Predicate used to check if consent is enabled with a given {@link ProfileRequestContext}.
*/
- @Nonnull private Function<ProfileRequestContext, AttributeReleaseContext> attributeReleaseContextLookupStrategy;
+ @Nonnull private Predicate<ProfileRequestContext> consentEnabledPredicate;
+
+ /** AttributeContext to use. */
+ @Nullable private AttributeContext attributeCtx;
/** Constructor. */
SetConsentToResponseContext() {
- consentContextLookupStrategy = new ChildContextLookup<>(ConsentContext.class, false);
- attributeReleaseContextLookupStrategy = new ChildContextLookup<>(AttributeReleaseContext.class, false);
+ relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+ attributeContextLookupStrategy = new ChildContextLookup<>(AttributeContext.class).compose(
+ new ChildContextLookup<>(RelyingPartyContext.class));
+ consentEnabledPredicate = new AttributeConsentFlowEnabledPredicate();
}
/**
- * Set the consent context lookup strategy.
+ * Set the strategy used to locate the {@link RelyingPartyContext} associated with a given
+ * {@link ProfileRequestContext}.
*
- * @param strategy the consent context lookup strategy
+ * @param strategy strategy used to locate the {@link RelyingPartyContext} associated with a given
+ * {@link ProfileRequestContext}
*/
- public void
- setConsentContextLookupStrategy(@Nonnull final Function<ProfileRequestContext, ConsentContext> strategy) {
- consentContextLookupStrategy = Constraint.isNotNull(strategy, "Consent context lookup strategy cannot be null");
+ public void setRelyingPartyContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, RelyingPartyContext> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ relyingPartyContextLookupStrategy =
+ Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
}
/**
- * Set the attribute release context lookup strategy.
+ * Set the strategy used to locate the {@link AttributeContext} associated with a given
+ * {@link ProfileRequestContext}.
*
- * @param strategy the attribute release context lookup strategy
+ * @param strategy strategy used to locate the {@link AttributeContext} associated with a given
+ * {@link ProfileRequestContext}
*/
- public void setAttributeReleaseContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, AttributeReleaseContext> strategy) {
- attributeReleaseContextLookupStrategy =
- Constraint.isNotNull(strategy, "Attribute release context lookup strategy cannot be null");
+ public void setAttributeContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, AttributeContext> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ attributeContextLookupStrategy =
+ Constraint.isNotNull(strategy, "AttributeContext 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} */
@@ -97,18 +129,40 @@ public class SetConsentToResponseContext extends AbstractOIDCResponseAction {
return false;
}
- consentContext = consentContextLookupStrategy.apply(profileRequestContext);
- if (consentContext == null) {
- log.debug("{} Unable to locate consent context within profile request context, nothing to do",
- getLogPrefix());
+ final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+ if (rpCtx == null) {
+ log.error("{} No relying party context associated with this profile request", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
return false;
}
- attributeReleaseContext = attributeReleaseContextLookupStrategy.apply(profileRequestContext);
- if (attributeReleaseContext == null) {
- log.debug("{} Unable to locate attribute release context within profile request context", getLogPrefix());
+
+ if (!consentEnabledPredicate.test(profileRequestContext)) {
+ log.debug("{} The attribute consent has not been enabled, nothing to do", getLogPrefix());
+ return false;
+ }
+
+ final ProfileConfiguration pc = rpCtx.getProfileConfig();
+ if (pc != null && pc instanceof OIDCCoreProtocolConfiguration) {
+ log.debug("{} TODO Returning {}", ((OIDCCoreProtocolConfiguration) pc).isEncodeConsentInTokens(profileRequestContext));
+ if (!((OIDCCoreProtocolConfiguration) pc).isEncodeConsentInTokens(profileRequestContext)) {
+ log.debug("{} The consent encoding to token has not been enabled, nothing to do",
+ getLogPrefix());
+ return false;
+ }
+ } else {
+ log.error("{} No oidc profile configuration associated with this profile request", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+ return false;
+ }
+
+ attributeCtx = attributeContextLookupStrategy.apply(profileRequestContext);
+ if (attributeCtx == null) {
+ log.debug("{} No AttributeSubcontext available, nothing to do", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
return false;
+
}
+
return true;
}
@@ -118,20 +172,11 @@ public class SetConsentToResponseContext extends AbstractOIDCResponseAction {
final OIDCAuthenticationResponseConsentContext oidcConsentCtx =
getOidcResponseContext().getSubcontext(OIDCAuthenticationResponseConsentContext.class, true);
- final Map<String, Consent> consents = consentContext.getCurrentConsents().isEmpty()
- ? consentContext.getPreviousConsents() : consentContext.getCurrentConsents();
- for (final String key : consents.keySet()) {
- if (consents.get(key) != null && consents.get(key).isApproved()) {
- oidcConsentCtx.getConsentedAttributes().add(key);
- }
- }
- if (attributeReleaseContext.getConsentableAttributes() != null) {
- oidcConsentCtx.getConsentableAttributes()
- .addAll(attributeReleaseContext.getConsentableAttributes().keySet());
- }
+
+ final Map<String, IdPAttribute> consented = attributeCtx.getIdPAttributes();
+ oidcConsentCtx.getConsentedAttributes().addAll(consented.keySet());
log.debug("{} Set to response context consented attributes {} and consentable attributes {}", getLogPrefix(),
- oidcConsentCtx.getConsentedAttributes().toJSONString(),
- oidcConsentCtx.getConsentableAttributes().toJSONString());
+ oidcConsentCtx.getConsentedAttributes().toJSONString());
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/consent-lookup/consent-lookup-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/consent-lookup/consent-lookup-beans.xml
new file mode 100644
index 00000000..ab93d5af
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/consent-lookup/consent-lookup-beans.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+ default-init-method="initialize" default-destroy-method="destroy">
+
+ <bean id="ConsentEnabledPredicate"
+ class="net.shibboleth.idp.plugin.oidc.op.config.logic.AttributeConsentEnabledInTokenClaimsSetPredicate" />
+
+ <bean id="PopulateConsentInterceptContext"
+ class="net.shibboleth.idp.profile.interceptor.impl.PopulateProfileInterceptorContext" scope="prototype"
+ p:availableFlows="#{@'shibboleth.ProfileInterceptorFlowDescriptorManager'.getComponents()}">
+ <property name="activeFlowsLookupStrategy">
+ <bean parent="shibboleth.Functions.Constant" c:target="#{ {'attribute-release-query' } }" />
+ </property>
+ </bean>
+
+</beans>
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/consent-lookup/consent-lookup-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/consent-lookup/consent-lookup-flow.xml
new file mode 100644
index 00000000..ecfb9fcf
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/consent-lookup/consent-lookup-flow.xml
@@ -0,0 +1,29 @@
+<flow xmlns="http://www.springframework.org/schema/webflow"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
+ abstract="true">
+
+ <decision-state id="DoConsentLookup">
+ <if test="ConsentEnabledPredicate.test(opensamlProfileRequestContext)"
+ then="CheckConsentSetup" else="BuildResponse" />
+ </decision-state>
+
+ <decision-state id="CheckConsentSetup">
+ <if test="opensamlProfileRequestContext.getOutboundMessageContext().getSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).containsSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseConsentContext))"
+ then="BuildResponse" else="ConsentFlowSetup" />
+ </decision-state>
+
+ <action-state id="ConsentFlowSetup">
+ <evaluate expression="PopulateConsentInterceptContext" />
+ <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.profile.context.ProfileInterceptorContext)).setAttemptedFlow(flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.ProfileInterceptorFlowDescriptorManager').getComponents().?[id matches 'intercept/attribute-release-query'])" />
+ <transition on="success" to="ConsentFlow" />
+ </action-state>
+
+ <subflow-state id="ConsentFlow" subflow="intercept/attribute-release-query">
+ <input name="calledAsSubflow" value="true" />
+ <transition on="proceed" to="BuildResponse"/>
+ </subflow-state>
+
+ <bean-import resource="../../oidc/consent-lookup/consent-lookup-beans.xml" />
+
+</flow>
\ No newline at end of file
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 a032b6d6..4ce1d038 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
@@ -1,6 +1,6 @@
<flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
- parent="oidc/abstract-api, oidc/metadata-lookup">
+ parent="oidc/abstract-api, oidc/metadata-lookup, oidc/consent-lookup">
<action-state id="InitializeMandatoryContexts">
<evaluate expression="InitializeProfileRequestContext" />
@@ -56,9 +56,9 @@
<evaluate expression="ResolveAttributes" />
<evaluate expression="FilterAttributes" />
<evaluate expression="'proceed'" />
- <transition on="proceed" to="BuildResponse" />
+ <transition on="proceed" to="DoConsentLookup" />
</action-state>
-
+
<action-state id="BuildResponse">
<evaluate expression="SetAccessTokenToResponseContext" />
<evaluate expression="SetRefreshTokenToResponseContext" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/token-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/token-flow.xml
index ee8226ee..e86fda70 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/token-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/token-flow.xml
@@ -1,7 +1,7 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
- parent="oidc/abstract-api, oidc/metadata-lookup">
+ parent="oidc/abstract-api, oidc/metadata-lookup, oidc/consent-lookup">
<action-state id="InitializeMandatoryContexts">
<evaluate expression="InitializeProfileRequestContext" />
@@ -49,9 +49,9 @@
<evaluate expression="ResolveAttributes" />
<evaluate expression="FilterAttributes" />
<evaluate expression="'proceed'" />
- <transition on="proceed" to="BuildResponse" />
+ <transition on="proceed" to="DoConsentLookup" />
</action-state>
-
+
<action-state id="BuildResponse">
<evaluate expression="AddUserInfoShell" />
<evaluate expression="AddAttributeClaimsToUserInfo" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index 6ff09290..a7b41064 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -28,6 +28,7 @@
p:tokenEndpointAuthMethods="%{idp.oidc.tokenEndpointAuthMethods:client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt}"
p:forcePKCE="%{idp.oidc.forcePKCE:false}"
p:allowPKCEPlain="%{idp.oidc.allowPKCEPlain:false}"
+ p:encodeConsentInTokens="%{idp.oidc.encodeConsentInTokens:false}"
p:encodedAttributes="%{idp.oidc.encodedAttributes:}"
p:alwaysIncludedAttributes="%{idp.oidc.alwaysIncludedAttributes:}"
p:deniedUserInfoAttributes="%{idp.oidc.deniedUserInfoAttributes:}" />
@@ -146,6 +147,14 @@
<constructor-arg value="false" />
</bean>
</property>
+ <property name="encodeConsentInTokensPredicate">
+ <bean class="net.shibboleth.utilities.java.support.logic.PredicateSupport" factory-method="fromFunction">
+ <constructor-arg>
+ <bean parent="shibboleth.MDDrivenBoolProperty" p:propertyName="encodeConsentInTokens" />
+ </constructor-arg>
+ <constructor-arg value="%{idp.oidc.encodeConsentInTokens:false}" />
+ </bean>
+ </property>
<property name="issuerLookupStrategy">
<bean parent="shibboleth.MDDrivenStringProperty" p:propertyName="issuer" p:defaultValue-ref="issuer" />
</property>
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 da44fdbc..cbdd8f32 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
@@ -43,6 +43,9 @@ idp.signing.oidc.rsa.enc.key = %{idp.home}/credentials/idp-encryption-rsa.jwk
#idp.oidc.forcePKCE = false
#idp.oidc.allowPKCEPlain = false
+# Store user consent to authorization code & access/refresh tokens instead of exploiting consent storage
+#idp.oidc.encodeConsentInTokens = false
+
# shibboleth.ClientInformationResolverService properties
#idp.service.clientinfo.failFast = false
#idp.service.clientinfo.checkInterval = PT0S
@@ -68,4 +71,4 @@ idp.oidc.subject.sourceAttribute = uid
idp.oidc.subject.salt = this_too_should_be_ch4ng3d
# Bean to determine whether SAML metadata should be exploited for trusted OIDC RP resolution
-#idp.oidc.metadata.saml = shibboleth.Conditions.TRUE
\ No newline at end of file
+#idp.oidc.metadata.saml = shibboleth.Conditions.TRUE
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 6629ada7..3148919f 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
@@ -184,5 +184,15 @@ public abstract class AbstractOidcFlowTest extends AbstractFlowTest {
protected void removeMetadata(final StorageService storageService, final String clientId) throws IOException {
storageService.delete(BaseStorageServiceClientInformationComponent.CONTEXT_NAME, clientId);
}
+
+ protected void storeConsent(final StorageService storageService, final String uid, final String clientId,
+ final String... ids) throws IOException {
+ final StringBuilder consented = new StringBuilder("[{\"id\":\"subject-public\"}");
+ for (final String id : ids) {
+ consented.append(",{\"id\":\"" + id + "\"}");
+ }
+ storageService.create("intercept/attribute-release", uid + ":" + clientId,
+ consented.append("]").toString(), System.currentTimeMillis() + (60 * 60 * 1000));
+ }
}
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 28169209..2b48da9e 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
@@ -34,6 +34,7 @@ import org.testng.annotations.Test;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jwt.JWT;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
import com.nimbusds.oauth2.sdk.auth.ClientSecretJWT;
@@ -141,20 +142,26 @@ public class TokenFlowTest extends AbstractOidcFlowTest {
DataSealerException, ComponentInitializationException {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientId), clientId));
+ storeConsent(storageService, "jdoe", clientId, "mail");
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
+ Assert.assertNotNull(response.getOIDCTokens().getIDToken());
}
@Test
public void testValidGrantSaml() throws ParseException, IOException, NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException {
+ DataSealerException, ComponentInitializationException, java.text.ParseException {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdSaml), clientIdSaml));
setBasicAuth(clientIdSaml, clientSecret);
+ storeConsent(storageService, "jdoe", clientIdSaml, "mail");
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
+ final JWT idToken = response.getOIDCTokens().getIDToken();
+ Assert.assertNotNull(idToken);
+ Assert.assertEquals(idToken.getJWTClaimsSet().getClaim("email"), "jdoe at example.org");
}
protected String buildAuthorizationCode(String clientId) throws NoSuchAlgorithmException, URISyntaxException,
@@ -171,7 +178,8 @@ public class TokenFlowTest extends AbstractOidcFlowTest {
JSONObject deliveryClaimsIDToken, JSONObject deliveryClaimsUserInfo) throws NoSuchAlgorithmException,
URISyntaxException, DataSealerException, ComponentInitializationException {
return ValidateGrantTest.buildAuthorizationCode(clientId, "https://op.example.org", "jdoe", "mock",
- redirectUri, verifier, deliveryClaims, deliveryClaimsIDToken, deliveryClaimsUserInfo).toString();
+ redirectUri, verifier, deliveryClaims, deliveryClaimsIDToken, deliveryClaimsUserInfo,
+ "openid profile email").toString();
}
@Test
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/UserInfoTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/UserInfoTest.java
index 5cccc347..b9ea3416 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/UserInfoTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/UserInfoTest.java
@@ -123,6 +123,7 @@ public class UserInfoTest extends AbstractOidcApiFlowTest {
ComponentInitializationException, IOException {
BearerAccessToken token = buildToken(clientId, subject, new Scope("openid", "email", "profile"));
storeMetadata(storageService, clientId, "mockSecret");
+ storeConsent(storageService, "jdoe", clientId, "mail");
request.addHeader("Authorization", token.toAuthorizationHeader());
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
UserInfoSuccessResponse response = parseSuccessResponse(result, UserInfoSuccessResponse.class);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddAttributesToClaimsSetTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddAttributesToClaimsSetTest.java
index 9efa67ef..b8fd96eb 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddAttributesToClaimsSetTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AddAttributesToClaimsSetTest.java
@@ -37,7 +37,6 @@ import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
import net.shibboleth.idp.attribute.transcoding.impl.AttributeTranscoderRegistryImpl;
import net.shibboleth.idp.plugin.oidc.op.config.OIDCCoreProtocolConfiguration;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseConsentContext;
-import net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAttributesToClaimsSet;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
@@ -221,9 +220,8 @@ public class AddAttributesToClaimsSetTest extends BaseOIDCResponseActionTest {
setAttributeContext();
final OIDCAuthenticationResponseConsentContext ctx = (OIDCAuthenticationResponseConsentContext) respCtx
.addSubcontext(new OIDCAuthenticationResponseConsentContext());
- ctx.getConsentableAttributes().add("test1");
- ctx.getConsentableAttributes().add("test3");
ctx.getConsentedAttributes().add("test1");
+ ctx.getConsentedAttributes().add("test4");
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
Assert.assertTrue(respCtx.getIDToken().getClaim("test1").equals("value1 value2"));
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
index f06187c2..f50632ff 100644
--- 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
@@ -20,7 +20,6 @@ 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.profile.impl.SetAccessTokenToResponseContext;
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;
@@ -110,15 +109,12 @@ public class SetAccessTokenToResponseContextTest extends BaseOIDCResponseActionT
respCtx.setTokenClaimsSet(null);
OIDCAuthenticationResponseConsentContext consCtx = (OIDCAuthenticationResponseConsentContext) respCtx
.addSubcontext(new OIDCAuthenticationResponseConsentContext());
- consCtx.getConsentableAttributes().add("1");
- consCtx.getConsentableAttributes().add("2");
consCtx.getConsentedAttributes().add("3");
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
Assert.assertNotNull(respCtx.getAccessToken());
AccessTokenClaimsSet at = AccessTokenClaimsSet.parse(respCtx.getAccessToken().getValue(), getDataSealer());
Assert.assertNotNull(at);
- Assert.assertEquals(at.getConsentableClaims(), consCtx.getConsentableAttributes());
Assert.assertEquals(at.getConsentedClaims(), consCtx.getConsentedAttributes());
}
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 35dad681..3a313e2b 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
@@ -20,7 +20,6 @@ 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.profile.impl.SetAuthorizationCodeToResponseContext;
import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
@@ -81,8 +80,6 @@ public class SetAuthorizationCodeToResponseContextTest extends BaseOIDCResponseA
init();
final OIDCAuthenticationResponseConsentContext consCtx = (OIDCAuthenticationResponseConsentContext) respCtx
.addSubcontext(new OIDCAuthenticationResponseConsentContext());
- consCtx.getConsentableAttributes().add("1");
- consCtx.getConsentableAttributes().add("2");
consCtx.getConsentedAttributes().add("3");
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
@@ -90,7 +87,6 @@ public class SetAuthorizationCodeToResponseContextTest extends BaseOIDCResponseA
final AuthorizeCodeClaimsSet ac =
AuthorizeCodeClaimsSet.parse(respCtx.getAuthorizationCode().getValue(), getDataSealer());
Assert.assertNotNull(ac);
- Assert.assertEquals(ac.getConsentableClaims(), consCtx.getConsentableAttributes());
Assert.assertEquals(ac.getConsentedClaims(), consCtx.getConsentedAttributes());
}
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentFromTokenToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentFromTokenToResponseContextTest.java
index 2eaf861c..1cb32427 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentFromTokenToResponseContextTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentFromTokenToResponseContextTest.java
@@ -19,7 +19,6 @@ package net.shibboleth.idp.plugin.oidc.op.profile.impl;
import net.minidev.json.JSONArray;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseConsentContext;
-import net.shibboleth.idp.plugin.oidc.op.profile.impl.SetConsentFromTokenToResponseContext;
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.testing.ActionTestingSupport;
@@ -63,21 +62,17 @@ public class SetConsentFromTokenToResponseContextTest extends BaseOIDCResponseAc
*/
@Test
public void testSuccess() throws ComponentInitializationException, URISyntaxException {
- final JSONArray consentableClaims = new JSONArray();
- consentableClaims.add("1");
- consentableClaims.add("2");
final JSONArray consentedClaims = new JSONArray();
consentedClaims.add("1");
final TokenClaimsSet claims = new AuthorizeCodeClaimsSet.Builder(idGenerator, new ClientID(), "issuer", "userPrin",
"subject", Instant.now(), Instant.now(), Instant.now(), new URI("http://example.com"), new Scope())
- .setConsentableClaims(consentableClaims).setConsentedClaims(consentedClaims).build();
+ .setConsentedClaims(consentedClaims).build();
respCtx.setTokenClaimsSet(claims);
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
final OIDCAuthenticationResponseConsentContext ctx =
respCtx.getSubcontext(OIDCAuthenticationResponseConsentContext.class, false);
Assert.assertNotNull(ctx);
- Assert.assertEquals(ctx.getConsentableAttributes(), consentableClaims);
Assert.assertEquals(ctx.getConsentedAttributes(), consentedClaims);
}
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentToResponseContextTest.java
index 54543b45..3e31a9e0 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentToResponseContextTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetConsentToResponseContextTest.java
@@ -17,111 +17,101 @@
package net.shibboleth.idp.plugin.oidc.op.profile.impl;
-import net.shibboleth.idp.consent.context.AttributeReleaseContext;
-import net.shibboleth.idp.consent.context.ConsentContext;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.plugin.oidc.op.config.OIDCCoreProtocolConfiguration;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseConsentContext;
-import net.shibboleth.idp.plugin.oidc.op.profile.impl.SetConsentToResponseContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
-import net.shibboleth.idp.consent.Consent;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import java.util.HashSet;
+import java.util.Set;
+
import org.opensaml.profile.action.EventIds;
import org.springframework.webflow.execution.Event;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.base.Predicates;
+
/** {@link SetConsentToResponseContext} unit test. */
public class SetConsentToResponseContextTest extends BaseOIDCResponseActionTest {
private SetConsentToResponseContext action;
- private AttributeReleaseContext attrRelCtx;
+ private AttributeContext attributeCtx;
- private ConsentContext consCtx;
-
- private void init() throws ComponentInitializationException {
- attrRelCtx = (AttributeReleaseContext) profileRequestCtx.addSubcontext(new AttributeReleaseContext());
- attrRelCtx.getConsentableAttributes().put("1", null);
- attrRelCtx.getConsentableAttributes().put("2", null);
- consCtx = (ConsentContext) profileRequestCtx.addSubcontext(new ConsentContext());
- Consent yes = new Consent();
- yes.setApproved(true);
- Consent no = new Consent();
- no.setApproved(false);
- consCtx.getPreviousConsents().put("1", yes);
- consCtx.getPreviousConsents().put("2", no);
- consCtx.getCurrentConsents().put("3", yes);
+ private void init(boolean encodeConsent, boolean consentEnabled) throws ComponentInitializationException {
+ attributeCtx = new AttributeContext();
+ final Set<IdPAttribute> attributes = new HashSet<>();
+ attributes.add(new IdPAttribute("1"));
+ attributes.add(new IdPAttribute("2"));
+ attributeCtx.setIdPAttributes(attributes);
+ rpCtx.addSubcontext(attributeCtx);
+ ((OIDCCoreProtocolConfiguration) rpCtx.getProfileConfig()).setEncodeConsentInTokens(encodeConsent);
action = new SetConsentToResponseContext();
+ action.setConsentEnabledPredicate(consentEnabled ? Predicates.alwaysTrue() : Predicates.alwaysFalse());
+
action.initialize();
}
-
+
/**
- * Test that action handles no consent being available.
+ * Test that action doesn't create context when consent encoding flag in profile config is disabled.
*
* @throws ComponentInitializationException
*/
@Test
- public void testSuccessNoConsent() throws ComponentInitializationException {
- init();
- profileRequestCtx.removeSubcontext(ConsentContext.class);
- respCtx.removeSubcontext(OIDCAuthenticationResponseConsentContext.class);
+ public void testWithEncodingDisabled() throws ComponentInitializationException {
+ init(false, false);
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
Assert.assertNull(respCtx.getSubcontext(OIDCAuthenticationResponseConsentContext.class, false));
}
/**
- * Test that action handles consent but not attrib release context being available.
+ * Test that action handles missing attribute context.
*
* @throws ComponentInitializationException
*/
@Test
- public void testFailNoAttribRelConsent() throws ComponentInitializationException {
- init();
- profileRequestCtx.removeSubcontext(AttributeReleaseContext.class);
+ public void testFailNoAttributeContext() throws ComponentInitializationException {
+ init(true, true);
+ profileRequestCtx.getSubcontext(RelyingPartyContext.class).removeSubcontext(AttributeContext.class);
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertEvent(event, EventIds.INVALID_PROFILE_CTX);
+ Assert.assertNull(respCtx.getSubcontext(OIDCAuthenticationResponseConsentContext.class, false));
}
/**
- * Test that action handles basic success case.
+ * Test that action doesn't create context when attribute-release flow is not returned by the lookup function.
*
* @throws ComponentInitializationException
*/
@Test
- public void testSuccess() throws ComponentInitializationException {
- init();
+ public void testNoAttributeReleaseFlow() throws ComponentInitializationException {
+ init(true, false);
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
- OIDCAuthenticationResponseConsentContext ctx =
- respCtx.getSubcontext(OIDCAuthenticationResponseConsentContext.class, false);
- Assert.assertNotNull(ctx);
- Assert.assertTrue(ctx.getConsentableAttributes().contains("1"));
- Assert.assertTrue(ctx.getConsentableAttributes().contains("2"));
- Assert.assertTrue(ctx.getConsentableAttributes().size() == 2);
- Assert.assertTrue(ctx.getConsentedAttributes().contains("3"));
- Assert.assertTrue(ctx.getConsentedAttributes().size() == 1);
+ Assert.assertNull(respCtx.getSubcontext(OIDCAuthenticationResponseConsentContext.class, false));
}
/**
- * Test that action handles basic success case of having only previous consent.
+ * Test that action handles basic success case.
*
* @throws ComponentInitializationException
*/
@Test
- public void testSuccessPrev() throws ComponentInitializationException {
- init();
- consCtx.getCurrentConsents().clear();
+ public void testSuccess() throws ComponentInitializationException {
+ init(true, true);
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
OIDCAuthenticationResponseConsentContext ctx =
respCtx.getSubcontext(OIDCAuthenticationResponseConsentContext.class, false);
Assert.assertNotNull(ctx);
- Assert.assertTrue(ctx.getConsentableAttributes().contains("1"));
- Assert.assertTrue(ctx.getConsentableAttributes().contains("2"));
- Assert.assertTrue(ctx.getConsentableAttributes().size() == 2);
Assert.assertTrue(ctx.getConsentedAttributes().contains("1"));
- Assert.assertTrue(ctx.getConsentedAttributes().size() == 1);
+ Assert.assertTrue(ctx.getConsentedAttributes().contains("2"));
+ Assert.assertTrue(ctx.getConsentedAttributes().size() == 2);
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSubjectToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSubjectToResponseContextTest.java
index eb5c0059..4cdef58e 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSubjectToResponseContextTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetSubjectToResponseContextTest.java
@@ -17,9 +17,7 @@
package net.shibboleth.idp.plugin.oidc.op.profile.impl;
-import net.shibboleth.idp.consent.context.ConsentContext;
import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestSubjectLookupFunction;
-import net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSubjectToResponseContext;
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;
@@ -86,7 +84,6 @@ public class SetSubjectToResponseContextTest extends BaseOIDCResponseActionTest
"issuer", "userPrin", "subject", Instant.now(), Instant.now(), Instant.now(),
new URI("http://example.com"), new Scope()).build();
respCtx.setTokenClaimsSet(claims);
- profileRequestCtx.removeSubcontext(ConsentContext.class);
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
Assert.assertEquals(respCtx.getSubject(), "subject");
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrantTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrantTest.java
index 635f7dbf..6c997f42 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrantTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrantTest.java
@@ -95,20 +95,26 @@ public class ValidateGrantTest extends BaseOIDCResponseActionTest {
}
public static AuthorizationCode buildAuthorizationCode(String clientId, String issuer, String userPrincipal,
- String sub, String callbackUrl, String codeChallenge)
+ String sub, String callbackUrl, String scope)
throws URISyntaxException, NoSuchAlgorithmException, DataSealerException, ComponentInitializationException {
- return buildAuthorizationCode(clientId, issuer, userPrincipal, sub, callbackUrl, codeChallenge, null, null, null);
+ return buildAuthorizationCode(clientId, issuer, userPrincipal, sub, callbackUrl, null, null);
+ }
+
+ public static AuthorizationCode buildAuthorizationCode(String clientId, String issuer, String userPrincipal,
+ String sub, String callbackUrl, String codeChallenge, String scope)
+ throws URISyntaxException, NoSuchAlgorithmException, DataSealerException, ComponentInitializationException {
+ return buildAuthorizationCode(clientId, issuer, userPrincipal, sub, callbackUrl, codeChallenge, null, null, null, null);
}
public static AuthorizationCode buildAuthorizationCode(String clientId, String issuer, String userPrincipal,
String sub, String callbackUrl, String codeChallenge, JSONObject deliveryClaims,
- JSONObject deliveryClaimsIDToken, JSONObject deliveryClaimsUserInfo)
+ JSONObject deliveryClaimsIDToken, JSONObject deliveryClaimsUserInfo, String scope)
throws URISyntaxException, NoSuchAlgorithmException, DataSealerException, ComponentInitializationException {
final Instant now = Instant.now();
final ValidateGrantTest test = new ValidateGrantTest();
final AuthorizeCodeClaimsSet.Builder builder = new AuthorizeCodeClaimsSet.Builder(
new SecureRandomIdentifierGenerationStrategy(), new ClientID(clientId), issuer, userPrincipal, sub,
- now, now.plusSeconds(100), now, new URI(callbackUrl), new Scope());
+ now, now.plusSeconds(100), now, new URI(callbackUrl), scope == null ? new Scope() : Scope.parse(scope));
if (codeChallenge != null) {
builder.setCodeChallenge(codeChallenge);
}
diff --git a/idp-oidc-extension-impl/src/test/resources/conf/idp.properties b/idp-oidc-extension-impl/src/test/resources/conf/idp.properties
index cd09a526..b4137101 100644
--- a/idp-oidc-extension-impl/src/test/resources/conf/idp.properties
+++ b/idp-oidc-extension-impl/src/test/resources/conf/idp.properties
@@ -125,6 +125,7 @@ idp.session.secondaryServiceIndex = true
# Set to "shibboleth.StorageService" or custom bean for alternate storage of consent
#idp.consent.StorageService = shibboleth.ClientPersistentStorageService
+idp.consent.StorageService = shibboleth.StorageService
# Set to "shibboleth.consent.AttributeConsentStorageKey" to use an attribute
# to key user consent storage records (and set the attribute name)
diff --git a/idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/oidc/metadata/impl/EntityDescriptor-with-oidcmd-clientsecret.xml b/idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/oidc/metadata/impl/EntityDescriptor-with-oidcmd-clientsecret.xml
index 7a35ea85..1630118b 100644
--- a/idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/oidc/metadata/impl/EntityDescriptor-with-oidcmd-clientsecret.xml
+++ b/idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/oidc/metadata/impl/EntityDescriptor-with-oidcmd-clientsecret.xml
@@ -1,5 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="mockSamlClientId">
+ <md:Extensions xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute">
+ <mdattr:EntityAttributes xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
+ <saml:Attribute Name="http://shibboleth.net/ns/profiles/oidc/sso/browser/alwaysIncludedAttributes"
+ NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
+ <saml:AttributeValue>mail</saml:AttributeValue>
+ </saml:Attribute>
+ </mdattr:EntityAttributes>
+ </md:Extensions>
<md:SPSSODescriptor xmlns:oidcmd="urn:mace:shibboleth:metadata:oidc:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" protocolSupportEnumeration="http://openid.net/specs/openid-connect-core-1_0.html">
<md:KeyDescriptor>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
@@ -16,7 +24,7 @@
response_types="code"
application_type="web"
token_endpoint_auth_method="client_secret_basic"
- scopes="openid profile" />
+ scopes="openid profile email" />
</md:Extensions>
<md:AssertionConsumerService
Binding="https://tools.ietf.org/html/rfc6749#section-3.1.2"
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list