[java-idp-oidc] branch main updated: JOIDC-20 - Replace token placement options on AttributeTranscoders

Scott Cantor cantor.2 at osu.edu
Thu Dec 17 21:06:21 UTC 2020


This is an automated email from the git hooks/post-receive script.

scantor 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=bcfd77406d519a0378e1b21b818e0ee0238e662c

The following commit(s) were added to refs/heads/main by this push:
       new  bcfd7740  JOIDC-20 - Replace token placement options on AttributeTranscoders
bcfd7740 is described below

commit bcfd77406d519a0378e1b21b818e0ee0238e662c
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Dec 17 16:06:18 2020 -0500

    JOIDC-20 - Replace token placement options on AttributeTranscoders
    
    https://issues.shibboleth.net/jira/browse/JOIDC-20
    
    Move forced ID token placement to alwaysIncluded profile setting.
---
 .../transcoding/OIDCAttributeTranscoder.java       |  3 --
 .../enc/impl/BaseOIDCAttributeEncoderParser.java   |  5 --
 .../oidc/config/OIDCCoreProtocolConfiguration.java | 54 ++++++++++++++++++++++
 .../AlwaysIncludedAttributesLookupFunction.java    | 54 ++++++++++++++++++++++
 .../profile/impl/AddAttributesToClaimsSet.java     | 44 ++++++++++++++----
 ...etTokenDeliveryAttributesToResponseContext.java | 37 +++++++++++++--
 .../idp/service/relying-party/postconfig.xml       | 12 ++++-
 .../idp/plugin/oidc/op/conf/oidc.properties        |  3 ++
 .../profile/impl/AddAttributesToClaimsSetTest.java |  8 ++--
 ...kenDeliveryAttributesToResponseContextTest.java |  7 +--
 ...tributeResolutionSubjectLookupFunctionTest.java |  1 -
 11 files changed, 197 insertions(+), 31 deletions(-)

diff --git a/idp-oidc-extension-api/src/main/java/org/geant/idpextension/oidc/attribute/transcoding/OIDCAttributeTranscoder.java b/idp-oidc-extension-api/src/main/java/org/geant/idpextension/oidc/attribute/transcoding/OIDCAttributeTranscoder.java
index 1f61c49c..5afadd6e 100644
--- a/idp-oidc-extension-api/src/main/java/org/geant/idpextension/oidc/attribute/transcoding/OIDCAttributeTranscoder.java
+++ b/idp-oidc-extension-api/src/main/java/org/geant/idpextension/oidc/attribute/transcoding/OIDCAttributeTranscoder.java
@@ -42,9 +42,6 @@ public interface OIDCAttributeTranscoder extends AttributeTranscoder<JSONObject>
 
     /** Separator to use when not encoding multiple values to array. */
     @Nonnull @NotEmpty static final String PROP_STRING_DELIMITER = "oidc.stringDelimiter";
-    
-    /** Whether to forcibly include data in ID token regardless of response type. */
-    @Nonnull @NotEmpty static final String PROP_FORCE_ID_TOKEN = "oidc.forceIDToken";
 
     /** Whether to deny inclusion in user_info token regardless of response type. */
     @Nonnull @NotEmpty static final String PROP_DENY_USERINFO = "oidc.denyUserInfo";
diff --git a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/attribute/resolver/spring/enc/impl/BaseOIDCAttributeEncoderParser.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/attribute/resolver/spring/enc/impl/BaseOIDCAttributeEncoderParser.java
index 373265cb..9f092939 100644
--- a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/attribute/resolver/spring/enc/impl/BaseOIDCAttributeEncoderParser.java
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/attribute/resolver/spring/enc/impl/BaseOIDCAttributeEncoderParser.java
@@ -63,11 +63,6 @@ public abstract class BaseOIDCAttributeEncoderParser extends BaseAttributeEncode
                     StringSupport.trimOrNull(config.getAttributeNS(null, "stringDelimiter")));
         }
         
-        if (config.hasAttributeNS(null, "placeToIDToken")) {
-            rule.put(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN,
-                    StringSupport.trimOrNull(config.getAttributeNS(null, "placeToIDToken")));
-        }
-        
         if (config.hasAttributeNS(null, "denyUserinfo")) {
             rule.put(OIDCAttributeTranscoder.PROP_DENY_USERINFO,
                     StringSupport.trimOrNull(config.getAttributeNS(null, "denyUserinfo")));
diff --git a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/OIDCCoreProtocolConfiguration.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/OIDCCoreProtocolConfiguration.java
index adf436a6..e0728d5a 100644
--- a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/OIDCCoreProtocolConfiguration.java
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/OIDCCoreProtocolConfiguration.java
@@ -106,6 +106,9 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
     /** Lookup function to supply attribute IDs to embed in authorization code or access token. */
     @Nonnull private Function<ProfileRequestContext,Set<String>> encodedAttributesLookupStrategy;
 
+    /** Lookup function to supply attribute IDs to include in ID token regardless of response_type. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> alwaysIncludedAttributesLookupStrategy;
+
     /**
      * Constructor.
      */
@@ -140,6 +143,7 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
         postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         
         encodedAttributesLookupStrategy = FunctionSupport.constant(null);
+        alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(null);
     }
     
     /** {@inheritDoc} */
@@ -694,4 +698,54 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
         encodedAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
+    /**
+     * Get the set of attribute IDs which should be included in the ID token regardless of response_type.
+     * 
+     * <p>Default behavior is to include claims only with the implicit id_token type only, while any use
+     * of a back-channel relies on the user_info endpoint to get the claims. This setting forces certain
+     * attributes to be added to the ID token regardless of flow.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the attribute IDs to include in all cases
+     */
+    @Nonnull @NonnullElements @NotLive public Set<String> getAlwaysIncludedAttributes(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Set<String> attributes = alwaysIncludedAttributesLookupStrategy.apply(profileRequestContext);
+        if (attributes != null) {
+            return Set.copyOf(attributes);
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Set the set of attribute IDs which should be included in the ID token regardless of response_type.
+     * 
+     * <p>Default behavior is to include claims only with the implicit id_token type only, while any use
+     * of a back-channel relies on the user_info endpoint to get the claims. This setting forces certain
+     * attributes to be added to the ID token regardless of flow.</p>
+     * 
+     * @param attributes the attribute IDs to include in all cases
+     */
+    public void setAlwaysIncludedAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+        if (attributes == null || attributes.isEmpty()) {
+            alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(null);
+        } else {
+            alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(
+                    Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the attribute IDs which should be included in the ID token regardless of
+     * response_type.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setAlwaysIncludedAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        alwaysIncludedAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
 }
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/navigate/AlwaysIncludedAttributesLookupFunction.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/navigate/AlwaysIncludedAttributesLookupFunction.java
new file mode 100644
index 00000000..365ac4bb
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/navigate/AlwaysIncludedAttributesLookupFunction.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 - 2020, GÉANT
+ *
+ * Licensed 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 org.geant.idpextension.oidc.config.navigate;
+
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+import org.geant.idpextension.oidc.config.OIDCCoreProtocolConfiguration;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.profile.config.ProfileConfiguration;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.AbstractRelyingPartyLookupFunction;
+
+/**
+ * A function that obtains
+ * {@link OIDCCoreProtocolConfiguration#getAlwaysIncludedAttributes(ProfileRequestContext)}
+ * if such a profile is available from a {@link RelyingPartyContext} obtained via a lookup function,
+ * by default a child of the {@link ProfileRequestContext}.
+ * 
+ * <p>If a specific setting is unavailable, a null value is returned.</p>
+ */
+public class AlwaysIncludedAttributesLookupFunction 
+    extends AbstractRelyingPartyLookupFunction<Set<String>> {
+
+    /** {@inheritDoc} */
+    @Nullable public Set<String> apply(@Nullable final ProfileRequestContext input) {
+        final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+        if (rpc != null) {
+            final ProfileConfiguration pc = rpc.getProfileConfig();
+            if (pc != null && pc instanceof OIDCCoreProtocolConfiguration) {
+                return ((OIDCCoreProtocolConfiguration)pc).getAlwaysIncludedAttributes(input);
+            }
+        }
+        
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/profile/impl/AddAttributesToClaimsSet.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/profile/impl/AddAttributesToClaimsSet.java
index 36b3b896..1b65cd39 100644
--- a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/profile/impl/AddAttributesToClaimsSet.java
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/profile/impl/AddAttributesToClaimsSet.java
@@ -18,7 +18,9 @@ package org.geant.idpextension.oidc.profile.impl;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -44,6 +46,7 @@ import net.shibboleth.utilities.java.support.service.ReloadableService;
 import net.shibboleth.utilities.java.support.service.ServiceableComponent;
 
 import org.geant.idpextension.oidc.attribute.transcoding.OIDCAttributeTranscoder;
+import org.geant.idpextension.oidc.config.navigate.AlwaysIncludedAttributesLookupFunction;
 import org.geant.idpextension.oidc.messaging.context.OIDCAuthenticationResponseConsentContext;
 import org.geant.idpextension.oidc.messaging.context.OIDCAuthenticationResponseTokenClaimsContext;
 import org.geant.idpextension.oidc.profile.context.navigate.DefaultResponseClaimsSetLookupFunction;
@@ -83,6 +86,9 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
     @Nonnull
     private Function<ProfileRequestContext, OIDCAuthenticationResponseConsentContext> consentContextLookupStrategy;
     
+    /** Strategy used to obtain the set of attribute IDs to include in the ID token in all cases. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> alwaysIncludedAttributesLookupStrategy;
+    
     /** Transcoder registry service object. */
     @NonnullAfterInit private ReloadableService<AttributeTranscoderRegistry> transcoderRegistry;
 
@@ -94,24 +100,23 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
     private boolean ignoringUnencodableAttributes;
     
     /** AttributeContext to use. */
-    @Nullable
-    private AttributeContext attributeCtx;
+    @Nullable private AttributeContext attributeCtx;
 
     /** Claims Set to use. */
-    @Nullable
-    private ClaimsSet claimsSet;
+    @Nullable private ClaimsSet claimsSet;
 
     /** Whether we are adding claims to ID Token. */
-    @Nonnull
     private boolean targetIDToken;
 
     /** Whether we can add claims to IDToken by default i.e. response type is "id_token". */
-    @Nonnull
     private boolean addToIDTokenByDefault;
 
     /** List of claim names that will not be added. */
-    @Nullable
-    private List<String> reservedClaimNames;
+    @Nullable @NonnullElements private List<String> reservedClaimNames;
+
+
+    /** Attributes to include in ID token no matter what. */
+    @Nullable @NonnullElements private Set<String> alwaysIncludedAttributes;
 
     /** Constructor. */
     AddAttributesToClaimsSet() {
@@ -122,6 +127,8 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
                 new ChildContextLookup<>(OIDCAuthenticationResponseConsentContext.class).compose(
                         new OIDCAuthenticationResponseContextLookupFunction());
         
+        alwaysIncludedAttributesLookupStrategy = new AlwaysIncludedAttributesLookupFunction();
+        
         ignoringUnencodableAttributes = true;
     }
 
@@ -210,6 +217,19 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
                 "OIDCAuthenticationResponseConsentContext lookup strategy cannot be null");
     }
 
+    /**
+     * Set the strategy used to obtain the set of attribute IDs always included in ID tokens.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setAlwaysIncludedAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        alwaysIncludedAttributesLookupStrategy = Constraint.isNotNull(strategy,
+                "Always included attributes lookup strategy cannot be null");
+    }
+
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -246,6 +266,11 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
                 addToIDTokenByDefault =
                         !((AuthenticationRequest) msg).getResponseType().contains(ResponseType.Value.TOKEN);
             }
+
+            alwaysIncludedAttributes = alwaysIncludedAttributesLookupStrategy.apply(profileRequestContext);
+            if (alwaysIncludedAttributes == null) {
+                alwaysIncludedAttributes = Collections.emptySet();
+            }
         }
         return true;
     }
@@ -328,8 +353,7 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
         for (final TranscodingRule rule : transcodingRules) {
             try {
                 if (targetIDToken) {
-                    if (!addToIDTokenByDefault
-                            && !rule.getOrDefault(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, Boolean.class, false)) {
+                    if (!addToIDTokenByDefault && !alwaysIncludedAttributes.contains(attribute.getId())) {
                         log.debug("{} Attribute {} not targeted for ID Token", getLogPrefix(), attribute.getId());
                         continue;
                     }
diff --git a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/profile/impl/SetTokenDeliveryAttributesToResponseContext.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/profile/impl/SetTokenDeliveryAttributesToResponseContext.java
index 5b912bea..5c79ec67 100644
--- a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/profile/impl/SetTokenDeliveryAttributesToResponseContext.java
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/profile/impl/SetTokenDeliveryAttributesToResponseContext.java
@@ -35,6 +35,7 @@ import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -42,6 +43,7 @@ import net.shibboleth.utilities.java.support.service.ReloadableService;
 import net.shibboleth.utilities.java.support.service.ServiceableComponent;
 
 import org.geant.idpextension.oidc.attribute.transcoding.OIDCAttributeTranscoder;
+import org.geant.idpextension.oidc.config.navigate.AlwaysIncludedAttributesLookupFunction;
 import org.geant.idpextension.oidc.config.navigate.EncodedAttributesLookupFunction;
 import org.geant.idpextension.oidc.messaging.context.OIDCAuthenticationResponseContext;
 import org.geant.idpextension.oidc.messaging.context.OIDCAuthenticationResponseTokenClaimsContext;
@@ -68,7 +70,10 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
 
     /** Strategy used to obtain the set of attribute IDs to encode for back-channel recovery. */
     @Nonnull private Function<ProfileRequestContext,Set<String>> encodedAttributesLookupStrategy;
-    
+
+    /** Strategy used to obtain the set of attribute IDs to include in the ID token in all cases. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> alwaysIncludedAttributesLookupStrategy;
+
     /** Transcoder registry service object. */
     @NonnullAfterInit private ReloadableService<AttributeTranscoderRegistry> transcoderRegistry;
 
@@ -83,13 +88,17 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
     @Nullable private AttributeContext attributeCtx;
     
     /** Attributes to encode for recovery. */
-    @Nullable private Set<String> encodedAttributes;
+    @Nullable @NonnullElements private Set<String> encodedAttributes;
+
+    /** Attributes to include in ID token no matter what. */
+    @Nullable @NonnullElements private Set<String> alwaysIncludedAttributes;
 
     /** Constructor. */
     SetTokenDeliveryAttributesToResponseContext() {
         attributeContextLookupStrategy = new ChildContextLookup<>(AttributeContext.class).compose(
                 new ChildContextLookup<>(RelyingPartyContext.class));
         encodedAttributesLookupStrategy = new EncodedAttributesLookupFunction();
+        alwaysIncludedAttributesLookupStrategy = new AlwaysIncludedAttributesLookupFunction();
         
         ignoringUnencodableAttributes = true;
     }
@@ -145,6 +154,19 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
                 "Encoded attributes lookup strategy cannot be null");
     }
 
+    /**
+     * Set the strategy used to obtain the set of attribute IDs always included in ID tokens.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setAlwaysIncludedAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        alwaysIncludedAttributesLookupStrategy = Constraint.isNotNull(strategy,
+                "Always included attributes lookup strategy cannot be null");
+    }
+
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -173,7 +195,12 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
         if (encodedAttributes == null) {
             encodedAttributes = Collections.emptySet();
         }
-        
+
+        alwaysIncludedAttributes = alwaysIncludedAttributesLookupStrategy.apply(profileRequestContext);
+        if (alwaysIncludedAttributes == null) {
+            alwaysIncludedAttributes = Collections.emptySet();
+        }
+
         return true;
     }
 
@@ -233,7 +260,7 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
             try {
                 final AttributeTranscoder<JSONObject> transcoder = TranscoderSupport.<JSONObject>getTranscoder(rule);
                 
-                if (rule.getOrDefault(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, Boolean.class, false)
+                if (alwaysIncludedAttributes.contains(attribute.getId())
                         && !rule.getOrDefault(OIDCAttributeTranscoder.PROP_DENY_USERINFO, Boolean.class, false)) {
                     // Deliver for userinfo and id token
                     final JSONObject encodedAttribute =
@@ -242,7 +269,7 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
                         encodedAttribute.keySet().forEach(
                                 k -> tokenClaimsCtx.getClaims().setClaim(k, encodedAttribute.get(k)));
                     }
-                } else if (rule.getOrDefault(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, Boolean.class, false)) {
+                } else if (alwaysIncludedAttributes.contains(attribute.getId())) {
                     // Deliver only for idtoken
                     final JSONObject encodedAttribute =
                             transcoder.encode(profileRequestContext, attribute, JSONObject.class, rule);
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 95ef9b52..fc3e6e3c 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,7 +28,8 @@
         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:encodedAttributes="%{idp.oidc.encodedAttributes:}" />
+        p:encodedAttributes="%{idp.oidc.encodedAttributes:}"
+        p:alwaysIncludedAttributes="%{idp.oidc.alwaysIncludedAttributes:}" />
         
     <bean id="OIDC.UserInfo" parent="AbstractOIDCProfile" lazy-init="true"
         class="org.geant.idpextension.oidc.config.OIDCUserInfoConfiguration" />
@@ -192,6 +193,15 @@
                 </property>
             </bean>
         </property>
+        <property name="alwaysIncludedAttributesLookupStrategy">
+            <bean parent="shibboleth.MDDrivenSetProperty" p:propertyName="encodedAttributes">
+                <property name="defaultValue">
+                    <bean parent="shibboleth.CommaDelimStringArray">
+                        <constructor-arg type="java.lang.String" value="%{idp.oidc.alwaysIncludedAttributes:}" />
+                    </bean>
+                </property>
+            </bean>
+        </property>
     </bean>
     
     <bean id="OIDC.UserInfo.MDDriven" parent="AbstractMDDrivenOIDCProfile" lazy-init="true"
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 24d42776..ce7c740c 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
@@ -47,7 +47,10 @@ idp.signing.oidc.rsa.enc.key = %{idp.home}/credentials/idp-encryption-rsa.jwk
 #idp.oidc.discovery.resolver = shibboleth.oidc.DefaultOpenIdConfigurationResolver
 
 # Special claim handling rules
+# "Embedded" attributes are encoded and encrypted into the access token
 #idp.oidc.embeddedAttributes =
+# "Always included" attributes are forced into ID tokens for all response_types
+#idp.oidc.alwaysIncludedAttributes =
 
 # The source attribute used in generating the sub claim
 idp.oidc.subject.sourceAttribute = uid
diff --git a/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/impl/AddAttributesToClaimsSetTest.java b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/impl/AddAttributesToClaimsSetTest.java
index f49314fc..ae9a6ccb 100644
--- a/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/impl/AddAttributesToClaimsSetTest.java
+++ b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/impl/AddAttributesToClaimsSetTest.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import net.shibboleth.ext.spring.testing.MockApplicationContext;
 import net.shibboleth.idp.attribute.IdPAttribute;
@@ -42,6 +43,7 @@ import net.shibboleth.utilities.java.support.test.service.MockReloadableService;
 import org.geant.idpextension.oidc.attribute.transcoding.AbstractOIDCAttributeTranscoder;
 import org.geant.idpextension.oidc.attribute.transcoding.OIDCAttributeTranscoder;
 import org.geant.idpextension.oidc.attribute.transcoding.impl.OIDCStringAttributeTranscoder;
+import org.geant.idpextension.oidc.config.OIDCCoreProtocolConfiguration;
 import org.geant.idpextension.oidc.messaging.context.OIDCAuthenticationResponseConsentContext;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
@@ -63,6 +65,9 @@ public class AddAttributesToClaimsSetTest extends BaseOIDCResponseActionTest {
     @BeforeMethod
     public void setup() throws ComponentInitializationException {
         
+        ((OIDCCoreProtocolConfiguration) rpCtx.getProfileConfig()).setAlwaysIncludedAttributes(
+                Set.of("test1", "test3", "test4"));
+        
         registry = new AttributeTranscoderRegistryImpl();
         registry.setId("test");
                 
@@ -73,7 +78,6 @@ public class AddAttributesToClaimsSetTest extends BaseOIDCResponseActionTest {
         rule1.put(AttributeTranscoderRegistry.PROP_ID, "test1");
         rule1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         rule1.put(OIDCAttributeTranscoder.PROP_NAME, "test1");
-        rule1.put(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, true);
         
         final Map<String,Object> rule2 = new HashMap<>();
         rule2.put(AttributeTranscoderRegistry.PROP_ID, "test2");
@@ -84,13 +88,11 @@ public class AddAttributesToClaimsSetTest extends BaseOIDCResponseActionTest {
         rule3.put(AttributeTranscoderRegistry.PROP_ID, "test3");
         rule3.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         rule3.put(OIDCAttributeTranscoder.PROP_NAME, "test3");
-        rule3.put(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, true);
 
         final Map<String,Object> rule4 = new HashMap<>();
         rule4.put(AttributeTranscoderRegistry.PROP_ID, "test4");
         rule4.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         rule4.put(OIDCAttributeTranscoder.PROP_NAME, "test4");
-        rule4.put(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, true);
         
         registry.setNamingRegistry(Collections.singletonList(
                 new BasicNamingFunction<>(transcoder.getEncodedType(),
diff --git a/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/impl/SetTokenDeliveryAttributesToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/impl/SetTokenDeliveryAttributesToResponseContextTest.java
index 6950b5b4..ede7ae24 100644
--- a/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/impl/SetTokenDeliveryAttributesToResponseContextTest.java
+++ b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/impl/SetTokenDeliveryAttributesToResponseContextTest.java
@@ -60,7 +60,10 @@ public class SetTokenDeliveryAttributesToResponseContextTest extends BaseOIDCRes
         
         ((OIDCCoreProtocolConfiguration) rpCtx.getProfileConfig()).setEncodedAttributes(
                 Set.of("test1", "test2", "test3"));
-        
+
+        ((OIDCCoreProtocolConfiguration) rpCtx.getProfileConfig()).setAlwaysIncludedAttributes(
+                Set.of("test2", "test3"));
+
         registry = new AttributeTranscoderRegistryImpl();
         registry.setId("test");
                 
@@ -76,14 +79,12 @@ public class SetTokenDeliveryAttributesToResponseContextTest extends BaseOIDCRes
         rule2.put(AttributeTranscoderRegistry.PROP_ID, "test2");
         rule2.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         rule2.put(OIDCAttributeTranscoder.PROP_NAME, "test2");
-        rule2.put(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, true);
         rule2.put(OIDCAttributeTranscoder.PROP_DENY_USERINFO, true);
 
         final Map<String,Object> rule3 = new HashMap<>();
         rule3.put(AttributeTranscoderRegistry.PROP_ID, "test3");
         rule3.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         rule3.put(OIDCAttributeTranscoder.PROP_NAME, "test3");
-        rule3.put(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, true);
 
         final Map<String,Object> rule4 = new HashMap<>();
         rule4.put(AttributeTranscoderRegistry.PROP_ID, "test4");
diff --git a/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/logic/AttributeResolutionSubjectLookupFunctionTest.java b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/logic/AttributeResolutionSubjectLookupFunctionTest.java
index 64c5a1be..1506a7ca 100644
--- a/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/logic/AttributeResolutionSubjectLookupFunctionTest.java
+++ b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/profile/logic/AttributeResolutionSubjectLookupFunctionTest.java
@@ -76,7 +76,6 @@ public class AttributeResolutionSubjectLookupFunctionTest extends OpenSAMLInitBa
         rule1.put(AttributeTranscoderRegistry.PROP_ID, "test1");
         rule1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         rule1.put(OIDCAttributeTranscoder.PROP_NAME, "test1");
-        rule1.put(OIDCAttributeTranscoder.PROP_FORCE_ID_TOKEN, true);
         
         final Map<String,Object> rule2 = new HashMap<>();
         rule2.put(AttributeTranscoderRegistry.PROP_ID, "test2");

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list