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

Scott Cantor cantor.2 at osu.edu
Fri Dec 18 00:43:44 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=d5e8e5b87a38129e6e569c0bf5f557e2beacff1f

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

commit d5e8e5b87a38129e6e569c0bf5f557e2beacff1f
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Dec 17 19:43:41 2020 -0500

    JOIDC-20 - Replace token placement options on AttributeTranscoders
    
    https://issues.shibboleth.net/jira/browse/JOIDC-20
    
    Replace UserInfo denial property with profile config setting.
---
 .../transcoding/OIDCAttributeTranscoder.java       |  3 -
 .../enc/impl/BaseOIDCAttributeEncoderParser.java   |  5 --
 .../oidc/config/OIDCCoreProtocolConfiguration.java | 53 +++++++++++++++++
 .../oidc/config/OIDCUserInfoConfiguration.java     | 69 +++++++++++++++++++++-
 .../DeniedUserInfoAttributesLookupFunction.java    | 58 ++++++++++++++++++
 .../profile/impl/AddAttributesToClaimsSet.java     | 35 +++++++++--
 ...etTokenDeliveryAttributesToResponseContext.java | 41 ++++++++++---
 .../idp/service/relying-party/postconfig.xml       | 27 ++++++++-
 .../idp/plugin/oidc/op/conf/oidc.properties        |  2 +
 .../idp-oidc-extension-attribute-encoder.xsd       | 18 ------
 ...kenDeliveryAttributesToResponseContextTest.java |  4 +-
 11 files changed, 271 insertions(+), 44 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 5afadd6e..e055b80a 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
@@ -43,7 +43,4 @@ 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 deny inclusion in user_info token regardless of response type. */
-    @Nonnull @NotEmpty static final String PROP_DENY_USERINFO = "oidc.denyUserInfo";
-
 }
\ No newline at end of file
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 9f092939..76bbdcde 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
@@ -62,11 +62,6 @@ public abstract class BaseOIDCAttributeEncoderParser extends BaseAttributeEncode
             rule.put(OIDCAttributeTranscoder.PROP_STRING_DELIMITER,
                     StringSupport.trimOrNull(config.getAttributeNS(null, "stringDelimiter")));
         }
-        
-        if (config.hasAttributeNS(null, "denyUserinfo")) {
-            rule.put(OIDCAttributeTranscoder.PROP_DENY_USERINFO,
-                    StringSupport.trimOrNull(config.getAttributeNS(null, "denyUserinfo")));
-        }
     }
     
 }
\ No newline at end of file
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 e0728d5a..e4e688f2 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
@@ -109,6 +109,9 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
     /** Lookup function to supply attribute IDs to include in ID token regardless of response_type. */
     @Nonnull private Function<ProfileRequestContext,Set<String>> alwaysIncludedAttributesLookupStrategy;
 
+    /** Lookup function to supply attribute IDs to omit from UserInfo token. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> deniedUserInfoAttributesLookupStrategy;
+
     /**
      * Constructor.
      */
@@ -144,6 +147,7 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
         
         encodedAttributesLookupStrategy = FunctionSupport.constant(null);
         alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(null);
+        deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
     }
     
     /** {@inheritDoc} */
@@ -748,4 +752,53 @@ public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileC
             @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
         alwaysIncludedAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
+
+    /**
+     * Get the set of attribute IDs which should be omitted from the UserInfo token.
+     * 
+     * <p>Default behavior is to include all claims, but omiited claims also affect the set that
+     * may need to be embedded for recovery into the access/refresh tokens.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the attribute IDs to omit from UserInfo token
+     */
+    @Nonnull @NonnullElements @NotLive public Set<String> getDeniedUserInfoAttributes(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Set<String> attributes = deniedUserInfoAttributesLookupStrategy.apply(profileRequestContext);
+        if (attributes != null) {
+            return Set.copyOf(attributes);
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Set the set of attribute IDs which should be omitted from the UserInfo token.
+     * 
+     * <p>Default behavior is to include all claims, but omiited claims also affect the set that
+     * may need to be embedded for recovery into the access/refresh tokens.</p>
+     * 
+     * @param attributes the attribute IDs to omit from UserInfo token
+     */
+    public void setDeniedUserInfoAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+        if (attributes == null || attributes.isEmpty()) {
+            deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
+        } else {
+            deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(
+                    Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the set of attribute IDs which should be omitted from the UserInfo token.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setDeniedUserInfoAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        deniedUserInfoAttributesLookupStrategy = 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/OIDCUserInfoConfiguration.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/OIDCUserInfoConfiguration.java
index defbff43..365b20b1 100644
--- a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/OIDCUserInfoConfiguration.java
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/OIDCUserInfoConfiguration.java
@@ -16,12 +16,24 @@
 
 package org.geant.idpextension.oidc.config;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.function.Function;
+
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.geant.idpextension.oidc.profile.config.OIDCProfileConfiguration;
+import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.profile.config.AbstractConditionalProfileConfiguration;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 /**
  * Profile configuration for the OpenID Connect core protocol userinfo endpoint.
@@ -30,11 +42,14 @@ public class OIDCUserInfoConfiguration extends AbstractConditionalProfileConfigu
         implements OIDCProfileConfiguration {
 
     /** OIDC base protocol URI. */
-    public static final String PROTOCOL_URI = "http://openid.net/specs/openid-connect-core-1_0.html";
+    @Nonnull @NotEmpty public static final String PROTOCOL_URI = "http://openid.net/specs/openid-connect-core-1_0.html";
 
     /** ID for this profile configuration. */
-    public static final String PROFILE_ID = "http://csc.fi/ns/profiles/oidc/userinfo";
+    @Nonnull @NotEmpty public static final String PROFILE_ID = "http://csc.fi/ns/profiles/oidc/userinfo";
 
+    /** Lookup function to supply attribute IDs to omit from UserInfo token. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> deniedUserInfoAttributesLookupStrategy;
+    
     /**
      * Constructor.
      */
@@ -49,6 +64,56 @@ public class OIDCUserInfoConfiguration extends AbstractConditionalProfileConfigu
      */
     public OIDCUserInfoConfiguration(@Nonnull @NotEmpty final String profileId) {
         super(profileId);
+        
+        deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
+    }
+
+    /**
+     * Get the set of attribute IDs which should be omitted from the UserInfo token.
+     * 
+     * <p>Default behavior is to include all claims, but omiited claims also affect the set that
+     * may need to be embedded for recovery into the access/refresh tokens.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the attribute IDs to omit from UserInfo token
+     */
+    @Nonnull @NonnullElements @NotLive public Set<String> getDeniedUserInfoAttributes(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Set<String> attributes = deniedUserInfoAttributesLookupStrategy.apply(profileRequestContext);
+        if (attributes != null) {
+            return Set.copyOf(attributes);
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Set the set of attribute IDs which should be omitted from the UserInfo token.
+     * 
+     * <p>Default behavior is to include all claims, but omiited claims also affect the set that
+     * may need to be embedded for recovery into the access/refresh tokens.</p>
+     * 
+     * @param attributes the attribute IDs to omit from UserInfo token
+     */
+    public void setDeniedUserInfoAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+        if (attributes == null || attributes.isEmpty()) {
+            deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
+        } else {
+            deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(
+                    Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the set of attribute IDs which should be omitted from the UserInfo token.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setDeniedUserInfoAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        deniedUserInfoAttributesLookupStrategy = 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/DeniedUserInfoAttributesLookupFunction.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/navigate/DeniedUserInfoAttributesLookupFunction.java
new file mode 100644
index 00000000..5f4fa949
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/config/navigate/DeniedUserInfoAttributesLookupFunction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.geant.idpextension.oidc.config.OIDCUserInfoConfiguration;
+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#getDeniedUserInfoAttributes(ProfileRequestContext)} or
+ * {@link OIDCUserInfoConfiguration#getDeniedUserInfoAttributes(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 DeniedUserInfoAttributesLookupFunction 
+    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 instanceof OIDCCoreProtocolConfiguration) {
+                return ((OIDCCoreProtocolConfiguration)pc).getDeniedUserInfoAttributes(input);
+            } else if (pc instanceof OIDCUserInfoConfiguration) {
+                return ((OIDCUserInfoConfiguration) pc).getDeniedUserInfoAttributes(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 1b65cd39..b2ee1a65 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
@@ -45,8 +45,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 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.DeniedUserInfoAttributesLookupFunction;
 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;
@@ -88,7 +88,10 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
     
     /** 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;
-    
+
+    /** Strategy used to obtain the set of attribute IDs to omit from the UserInfo token. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> deniedUserInfoAttributesLookupStrategy;
+
     /** Transcoder registry service object. */
     @NonnullAfterInit private ReloadableService<AttributeTranscoderRegistry> transcoderRegistry;
 
@@ -118,6 +121,9 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
     /** Attributes to include in ID token no matter what. */
     @Nullable @NonnullElements private Set<String> alwaysIncludedAttributes;
 
+    /** Attributes to omit from UserInfo token. */
+    @Nullable @NonnullElements private Set<String> deniedUserInfoAttributes;
+
     /** Constructor. */
     AddAttributesToClaimsSet() {
         attributeContextLookupStrategy = new ChildContextLookup<>(AttributeContext.class).compose(
@@ -128,6 +134,7 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
                         new OIDCAuthenticationResponseContextLookupFunction());
         
         alwaysIncludedAttributesLookupStrategy = new AlwaysIncludedAttributesLookupFunction();
+        deniedUserInfoAttributesLookupStrategy = new DeniedUserInfoAttributesLookupFunction();
         
         ignoringUnencodableAttributes = true;
     }
@@ -230,6 +237,19 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
                 "Always included attributes lookup strategy cannot be null");
     }
 
+    /**
+     * Set the strategy used to obtain the set of attribute IDs to omit from UserInfo tokens.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setDeniedUserInfoAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        deniedUserInfoAttributesLookupStrategy = Constraint.isNotNull(strategy,
+                "Denied UserInfo attributes lookup strategy cannot be null");
+    }
+    
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -271,6 +291,13 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
             if (alwaysIncludedAttributes == null) {
                 alwaysIncludedAttributes = Collections.emptySet();
             }
+            deniedUserInfoAttributes = Collections.emptySet();
+        } else {
+            deniedUserInfoAttributes = deniedUserInfoAttributesLookupStrategy.apply(profileRequestContext);
+            if (deniedUserInfoAttributes == null) {
+                deniedUserInfoAttributes = Collections.emptySet();
+            }
+            alwaysIncludedAttributes = Collections.emptySet();
         }
         return true;
     }
@@ -357,8 +384,8 @@ public class AddAttributesToClaimsSet extends AbstractOIDCResponseAction {
                         log.debug("{} Attribute {} not targeted for ID Token", getLogPrefix(), attribute.getId());
                         continue;
                     }
-                } else if (rule.getOrDefault(OIDCAttributeTranscoder.PROP_DENY_USERINFO, Boolean.class, false)) {
-                    log.debug("{} Attribute {} not targeted for Userinfo response", getLogPrefix(), attribute.getId());
+                } else if (deniedUserInfoAttributes.contains(attribute.getId())) {
+                    log.debug("{} Attribute {} not targeted for Userinfo 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 5c79ec67..b93c4417 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
@@ -42,8 +42,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 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.DeniedUserInfoAttributesLookupFunction;
 import org.geant.idpextension.oidc.config.navigate.EncodedAttributesLookupFunction;
 import org.geant.idpextension.oidc.messaging.context.OIDCAuthenticationResponseContext;
 import org.geant.idpextension.oidc.messaging.context.OIDCAuthenticationResponseTokenClaimsContext;
@@ -74,6 +74,9 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
     /** 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;
 
+    /** Strategy used to obtain the set of attribute IDs to omit from the UserInfo token. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> deniedUserInfoAttributesLookupStrategy;
+
     /** Transcoder registry service object. */
     @NonnullAfterInit private ReloadableService<AttributeTranscoderRegistry> transcoderRegistry;
 
@@ -92,6 +95,9 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
 
     /** Attributes to include in ID token no matter what. */
     @Nullable @NonnullElements private Set<String> alwaysIncludedAttributes;
+    
+    /** Attributes to omit from UserInfo token. */
+    @Nullable @NonnullElements private Set<String> deniedUserInfoAttributes;
 
     /** Constructor. */
     SetTokenDeliveryAttributesToResponseContext() {
@@ -99,6 +105,7 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
                 new ChildContextLookup<>(RelyingPartyContext.class));
         encodedAttributesLookupStrategy = new EncodedAttributesLookupFunction();
         alwaysIncludedAttributesLookupStrategy = new AlwaysIncludedAttributesLookupFunction();
+        deniedUserInfoAttributesLookupStrategy = new DeniedUserInfoAttributesLookupFunction();
         
         ignoringUnencodableAttributes = true;
     }
@@ -164,9 +171,22 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         
         alwaysIncludedAttributesLookupStrategy = Constraint.isNotNull(strategy,
-                "Always included attributes lookup strategy cannot be null");
+                "Always included ID token attributes lookup strategy cannot be null");
     }
 
+    /**
+     * Set the strategy used to obtain the set of attribute IDs to omit from UserInfo tokens.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setDeniedUserInfoAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        deniedUserInfoAttributesLookupStrategy = Constraint.isNotNull(strategy,
+                "Denied UserInfo attributes lookup strategy cannot be null");
+    }
+    
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -200,6 +220,11 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
         if (alwaysIncludedAttributes == null) {
             alwaysIncludedAttributes = Collections.emptySet();
         }
+        
+        deniedUserInfoAttributes = deniedUserInfoAttributesLookupStrategy.apply(profileRequestContext);
+        if (deniedUserInfoAttributes == null) {
+            deniedUserInfoAttributes = Collections.emptySet();
+        }
 
         return true;
     }
@@ -260,9 +285,9 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
             try {
                 final AttributeTranscoder<JSONObject> transcoder = TranscoderSupport.<JSONObject>getTranscoder(rule);
                 
-                if (alwaysIncludedAttributes.contains(attribute.getId())
-                        && !rule.getOrDefault(OIDCAttributeTranscoder.PROP_DENY_USERINFO, Boolean.class, false)) {
-                    // Deliver for userinfo and id token
+                if (alwaysIncludedAttributes.contains(attribute.getId()) &&
+                        !deniedUserInfoAttributes.contains(attribute.getId())) {
+                    // Deliver for UserInfo and ID token
                     final JSONObject encodedAttribute =
                             transcoder.encode(profileRequestContext, attribute, JSONObject.class, rule);
                     if (encodedAttribute != null) {
@@ -270,15 +295,15 @@ public class SetTokenDeliveryAttributesToResponseContext extends AbstractOIDCRes
                                 k -> tokenClaimsCtx.getClaims().setClaim(k, encodedAttribute.get(k)));
                     }
                 } else if (alwaysIncludedAttributes.contains(attribute.getId())) {
-                    // Deliver only for idtoken
+                    // Deliver only for ID token
                     final JSONObject encodedAttribute =
                             transcoder.encode(profileRequestContext, attribute, JSONObject.class, rule);
                     if (encodedAttribute != null) {
                         encodedAttribute.keySet().forEach(
                                 k -> tokenClaimsCtx.getIdtokenClaims().setClaim(k, encodedAttribute.get(k)));
                     }
-                } else if (!rule.getOrDefault(OIDCAttributeTranscoder.PROP_DENY_USERINFO, Boolean.class, false)) {
-                    // Deliver only for userinfo
+                } else if (!deniedUserInfoAttributes.contains(attribute.getId())) {
+                    // Deliver only for UserInfo token
                     final JSONObject encodedAttribute =
                             transcoder.encode(profileRequestContext, attribute, JSONObject.class, rule);
                     if (encodedAttribute != null) {
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 fc3e6e3c..91278320 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
@@ -29,10 +29,12 @@
         p:forcePKCE="%{idp.oidc.forcePKCE:false}"
         p:allowPKCEPlain="%{idp.oidc.allowPKCEPlain:false}"
         p:encodedAttributes="%{idp.oidc.encodedAttributes:}"
-        p:alwaysIncludedAttributes="%{idp.oidc.alwaysIncludedAttributes:}" />
+        p:alwaysIncludedAttributes="%{idp.oidc.alwaysIncludedAttributes:}"
+        p:deniedUserInfoAttributes="%{idp.oidc.deniedUserInfoAttributes:}" />
         
     <bean id="OIDC.UserInfo" parent="AbstractOIDCProfile" lazy-init="true"
-        class="org.geant.idpextension.oidc.config.OIDCUserInfoConfiguration" />
+        class="org.geant.idpextension.oidc.config.OIDCUserInfoConfiguration"
+        p:deniedUserInfoAttributes="%{idp.oidc.deniedUserInfoAttributes:}" />
         
     <bean id="OIDC.Registration" parent="AbstractOIDCProfile" lazy-init="true"
         class="org.geant.idpextension.oidc.config.OIDCDynamicRegistrationConfiguration"
@@ -202,10 +204,29 @@
                 </property>
             </bean>
         </property>
+        <property name="deniedUserInfoAttributesLookupStrategy">
+            <bean parent="shibboleth.MDDrivenSetProperty" p:propertyName="encodedAttributes">
+                <property name="defaultValue">
+                    <bean parent="shibboleth.CommaDelimStringArray">
+                        <constructor-arg type="java.lang.String" value="%{idp.oidc.deniedUserInfoAttributes:}" />
+                    </bean>
+                </property>
+            </bean>
+        </property>
     </bean>
     
     <bean id="OIDC.UserInfo.MDDriven" parent="AbstractMDDrivenOIDCProfile" lazy-init="true"
-            class="org.geant.idpextension.oidc.config.OIDCUserInfoConfiguration" />
+            class="org.geant.idpextension.oidc.config.OIDCUserInfoConfiguration">
+        <property name="deniedUserInfoAttributesLookupStrategy">
+            <bean parent="shibboleth.MDDrivenSetProperty" p:propertyName="encodedAttributes">
+                <property name="defaultValue">
+                    <bean parent="shibboleth.CommaDelimStringArray">
+                        <constructor-arg type="java.lang.String" value="%{idp.oidc.deniedUserInfoAttributes:}" />
+                    </bean>
+                </property>
+            </bean>
+        </property>
+    </bean>
         
     <bean id="OIDC.Registration.MDDriven" parent="AbstractMDDrivenOIDCFlowAwareProfile" lazy-init="true"
             class="org.geant.idpextension.oidc.config.OIDCDynamicRegistrationConfiguration">
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 ce7c740c..be179f3f 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
@@ -51,6 +51,8 @@ idp.signing.oidc.rsa.enc.key = %{idp.home}/credentials/idp-encryption-rsa.jwk
 #idp.oidc.embeddedAttributes =
 # "Always included" attributes are forced into ID tokens for all response_types
 #idp.oidc.alwaysIncludedAttributes =
+# "Denied" attributes are omitted from the UserInfo token
+#idp.oidc.deniedUserInfoAttributes =
 
 # The source attribute used in generating the sub claim
 idp.oidc.subject.sourceAttribute = uid
diff --git a/idp-oidc-extension-impl/src/main/resources/schema/idp-oidc-extension-attribute-encoder.xsd b/idp-oidc-extension-impl/src/main/resources/schema/idp-oidc-extension-attribute-encoder.xsd
index b2496572..264fdf0e 100644
--- a/idp-oidc-extension-impl/src/main/resources/schema/idp-oidc-extension-attribute-encoder.xsd
+++ b/idp-oidc-extension-impl/src/main/resources/schema/idp-oidc-extension-attribute-encoder.xsd
@@ -97,24 +97,6 @@
                         </documentation>
                     </annotation>
                 </attribute>
-                <attribute name="placeToIDToken" type="string" use="optional">
-                    <annotation>
-                        <documentation>
-                            By default attributes are delivered in userinfo response unless response type is
-                            id_token. This flag is false by default and setting it true will include it in id token
-                            regardless of response type.
-                        </documentation>
-                    </annotation>
-                </attribute>
-                <attribute name="denyUserinfo" type="string" use="optional">
-                    <annotation>
-                        <documentation>
-                            By default attributes are delivered in userinfo response unless response type is
-                            id_token. This flag is false by default and setting it true excludes it from userinfo
-                            response.
-                        </documentation>
-                    </annotation>
-                </attribute>
             </extension>
         </complexContent>
     </complexType>
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 ede7ae24..3b8e85a9 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
@@ -64,6 +64,9 @@ public class SetTokenDeliveryAttributesToResponseContextTest extends BaseOIDCRes
         ((OIDCCoreProtocolConfiguration) rpCtx.getProfileConfig()).setAlwaysIncludedAttributes(
                 Set.of("test2", "test3"));
 
+        ((OIDCCoreProtocolConfiguration) rpCtx.getProfileConfig()).setDeniedUserInfoAttributes(
+                Collections.singleton("test2"));
+
         registry = new AttributeTranscoderRegistryImpl();
         registry.setId("test");
                 
@@ -79,7 +82,6 @@ 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_DENY_USERINFO, true);
 
         final Map<String,Object> rule3 = new HashMap<>();
         rule3.put(AttributeTranscoderRegistry.PROP_ID, "test3");

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


More information about the commits mailing list