[java-plugin-shibd-saml] branch main updated: Add internal attribute resolution to end of SAML consumer flow.

Scott Cantor cantor.2 at osu.edu
Thu Oct 10 19:03:09 UTC 2024


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

scantor pushed a commit to branch main
in repository java-plugin-shibd-saml.

View the commit online:
http://git.shibboleth.net/view/?p=java-plugin-shibd-saml.git;a=commit;h=51822c2956a00f3b935208d2f8df5c49af945e58

The following commit(s) were added to refs/heads/main by this push:
     new 51822c2  Add internal attribute resolution to end of SAML consumer flow.
51822c2 is described below

commit 51822c2956a00f3b935208d2f8df5c49af945e58
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Oct 10 15:03:05 2024 -0400

    Add internal attribute resolution to end of SAML consumer flow.
---
 .../config/BrowserSSOProfileConfiguration.java     |  9 ++++
 sp-saml-impl/pom.xml                               |  7 ++-
 .../impl/BrowserSSOProfileConfiguration.java       | 58 ++++++++++++++++++++++
 .../saml2/profile/impl/ExtractSAMLAttributes.java  | 46 ++++++++++++++++-
 4 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
index 83a4466..d38b311 100644
--- a/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
@@ -95,4 +95,13 @@ public interface BrowserSSOProfileConfiguration extends SAMLArtifactConsumerProf
     @Nullable Function<ProfileRequestContext,Collection<IdPAttribute>> getAttributeExtractionStrategy(
             @Nullable final ProfileRequestContext profileRequestContext);
 
+    /**
+     * Get a principal name to feed into attribute resolution if {@link #isResolveAttributes(ProfileRequestContext)} is true.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return principal name to use during resolution
+     */
+    @Nullable String getAttributeResolutionPrincipal(@Nullable final ProfileRequestContext profileRequestContext);
+
 }
\ No newline at end of file
diff --git a/sp-saml-impl/pom.xml b/sp-saml-impl/pom.xml
index b908724..c679775 100644
--- a/sp-saml-impl/pom.xml
+++ b/sp-saml-impl/pom.xml
@@ -63,7 +63,7 @@
         </dependency>
         <dependency>
             <groupId>${shib-attribute.groupId}</groupId>
-            <artifactId>shib-saml-attribute-api</artifactId>
+            <artifactId>shib-attribute-resolver-api</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -71,6 +71,11 @@
             <artifactId>shib-attribute-filter-api</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>${shib-attribute.groupId}</groupId>
+            <artifactId>shib-saml-attribute-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
         
         <dependency>
             <groupId>${shib-metadata.groupId}</groupId>
diff --git a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/impl/BrowserSSOProfileConfiguration.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/impl/BrowserSSOProfileConfiguration.java
index 0a65837..a7c40fe 100644
--- a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/impl/BrowserSSOProfileConfiguration.java
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/impl/BrowserSSOProfileConfiguration.java
@@ -47,6 +47,9 @@ import org.opensaml.saml.saml2.metadata.RequestedAttribute;
 public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionConsumerProfileConfiguration
         implements SAMLArtifactConsumerProfileConfiguration, net.shibboleth.sp.saml.saml2.profile.config.BrowserSSOProfileConfiguration {
 
+    /** Whether attributes should be resolved in the course of the profile. */
+    @Nonnull private Predicate<ProfileRequestContext> resolveAttributesPredicate;
+
     /** Whether to mandate forced authentication for the request. */
     @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
 
@@ -87,6 +90,9 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionConsum
     @Nonnull Function<ProfileRequestContext,Function<ProfileRequestContext,Collection<IdPAttribute>>>
     attributeExtractionStrategyLookupStrategy;
     
+    /** Lookup function for attribute resolution principal. */
+    @Nonnull Function<ProfileRequestContext,String> attributeResolutionPrincipalLookupStrategy;
+    
     /** Constructor. */
     public BrowserSSOProfileConfiguration() {
         this(PROFILE_ID);
@@ -100,6 +106,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionConsum
     protected BrowserSSOProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
         super(profileId);
         setEncryptNameIDs(true);
+        resolveAttributesPredicate = PredicateSupport.alwaysFalse();
         forceAuthnPredicate = PredicateSupport.alwaysFalse();
         checkAddressPredicate = PredicateSupport.alwaysTrue();
         maximumTimeSinceAuthnLookupStrategy = FunctionSupport.constant(null);
@@ -113,8 +120,32 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionConsum
         responseBindingLookupStrategy = FunctionSupport.constant(SAMLConstants.SAML2_POST_BINDING_URI);
         extractStandardAttributesPredicate = PredicateSupport.alwaysTrue();
         attributeExtractionStrategyLookupStrategy = FunctionSupport.constant(null);
+        attributeResolutionPrincipalLookupStrategy = FunctionSupport.constant(null);
     }
 
+    /** {@inheritDoc} */
+    public boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext) {
+        return resolveAttributesPredicate.test(profileRequestContext);
+    }
+    
+    /**
+     * Set whether attributes should be resolved during the profile.
+     * 
+     * @param flag flag to set
+     */
+    public void setResolveAttributes(final boolean flag) {
+        resolveAttributesPredicate = PredicateSupport.constant(flag);
+    }
+    
+    /**
+     * Set a condition to determine whether attributes should be resolved during the profile.
+     * 
+     * @param condition condition to set
+     */
+    public void setResolveAttributesPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        resolveAttributesPredicate = Constraint.isNotNull(condition, "Resolve attributes predicate cannot be null");
+    }
+    
     /** {@inheritDoc} */
     public boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext) {
         return forceAuthnPredicate.test(profileRequestContext);
@@ -475,4 +506,31 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionConsum
                 "Attribute extraction strategy lookup strategy cannot be null");
     }
     
+    /** {@inheritDoc} */
+    @Nullable public String getAttributeResolutionPrincipal(@Nullable final ProfileRequestContext profileRequestContext) {
+        return attributeResolutionPrincipalLookupStrategy.apply(profileRequestContext);
+    }
+
+    /**
+     * Set a principal name to feed into attribute resolution if {@link #isResolveAttributes(ProfileRequestContext)}
+     * is true.
+     * 
+     * @param principal principal name to set
+     */
+    public void setAttributeResolutionPrincipal(@Nullable final String principal) {
+        attributeResolutionPrincipalLookupStrategy = FunctionSupport.constant(principal);
+    }
+    
+    /**
+     * Set a lookup strategy for the principal name to feed into attribute resolution if
+     * {@link #isResolveAttributes(ProfileRequestContext)} is true
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setAttributeResolutionPrincipalLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,String> strategy) {
+        attributeResolutionPrincipalLookupStrategy =
+                Constraint.isNotNull(strategy, "Resolution principal lookup strategy cannot be null");
+    }
+    
 }
\ No newline at end of file
diff --git a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ExtractSAMLAttributes.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ExtractSAMLAttributes.java
index cd6df43..c15a778 100644
--- a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ExtractSAMLAttributes.java
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ExtractSAMLAttributes.java
@@ -61,6 +61,8 @@ import net.shibboleth.idp.attribute.filter.AttributeFilter;
 import net.shibboleth.idp.attribute.filter.AttributeFilterException;
 import net.shibboleth.idp.attribute.filter.context.AttributeFilterContext;
 import net.shibboleth.idp.attribute.filter.context.AttributeFilterContext.Direction;
+import net.shibboleth.idp.attribute.resolver.AttributeResolver;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
 import net.shibboleth.idp.attribute.transcoding.AttributeTranscoder;
 import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
 import net.shibboleth.idp.attribute.transcoding.TranscoderSupport;
@@ -79,6 +81,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 import net.shibboleth.shared.service.ServiceException;
 import net.shibboleth.shared.service.ServiceableComponent;
+import net.shibboleth.sp.Application;
 import net.shibboleth.sp.profile.AbstractApplicationAction;
 import net.shibboleth.sp.saml.saml2.context.SAMLTokenContext;
 import net.shibboleth.sp.saml.saml2.profile.config.BrowserSSOProfileConfiguration;
@@ -88,6 +91,10 @@ import net.shibboleth.sp.saml.saml2.profile.config.BrowserSSOProfileConfiguratio
  *
  * <p>Attributes decoded from the assertion(s) are in an unfiltered state and subject to the filtering
  * service. Any other data extracted is stored directly in the filtered set.</p>
+ * 
+ * <p>There are three supplemental sets: the optional "standard" set extracted from the message,
+ * an optional profile config-supplied strategy function, and an optional use of the {@link AttributeResolver}
+ * associated with the {@link Application}.</p>
  *  
  * @event {@link EventIds#PROCEED_EVENT_ID}
  * @event {@link EventIds#INVALID_PROFILE_CTX}
@@ -280,13 +287,27 @@ public class ExtractSAMLAttributes extends AbstractApplicationAction {
                 profileConfiguration.getAttributeExtractionStrategy(profileRequestContext);
         if (aes != null) {
             log.debug("{} Applying custom attribute extraction strategy", getLogPrefix());
-            final Collection<IdPAttribute> attributes = new ArrayList<>(attributeContext.getIdPAttributes().values());
             final Collection<IdPAttribute> newAttributes = aes.apply(profileRequestContext);
             if (newAttributes != null && !newAttributes.isEmpty()) {
                 if (log.isDebugEnabled()) {
                     log.debug("{} Extracted attributes with custom strategy: {}", getLogPrefix(),
                             newAttributes.stream().map(IdPAttribute::getId).collect(Collectors.toUnmodifiableList()));
                 }
+                final Collection<IdPAttribute> attributes = new ArrayList<>(attributeContext.getIdPAttributes().values());
+                attributes.addAll(newAttributes);
+                attributeContext.setIdPAttributes(attributes);
+            }
+        }
+        
+        if (profileConfiguration.isResolveAttributes(profileRequestContext)) {
+            log.debug("{} Performing internal attribute resolution", getLogPrefix());
+            final Collection<IdPAttribute> newAttributes = resolveAttributes(profileRequestContext);
+            if (newAttributes != null && !newAttributes.isEmpty()) {
+                if (log.isDebugEnabled()) {
+                    log.debug("{} Resolved attributes internally: {}", getLogPrefix(),
+                            newAttributes.stream().map(IdPAttribute::getId).collect(Collectors.toUnmodifiableList()));
+                }
+                final Collection<IdPAttribute> attributes = new ArrayList<>(attributeContext.getIdPAttributes().values());
                 attributes.addAll(newAttributes);
                 attributeContext.setIdPAttributes(attributes);
             }
@@ -474,6 +495,29 @@ public class ExtractSAMLAttributes extends AbstractApplicationAction {
             .setAttributeRecipientID(requesterLookupStrategy.apply(profileRequestContext));
     }
     
+    /**
+     * Perform internal attribute resolution using the {@link Application}-associated
+     * {@link AttributeResolver} service.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return resolved attributes
+     */
+    @Nullable private Collection<IdPAttribute> resolveAttributes(
+            @Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        final AttributeResolutionContext resolutionContext = new AttributeResolutionContext();
+
+        resolutionContext.setResolutionLabel("sp/consumer/saml2")
+            .setPrincipal(profileConfiguration.getAttributeResolutionPrincipal(profileRequestContext))
+            .setAttributeIssuerID(issuerLookupStrategy.apply(profileRequestContext))
+            .setAttributeRecipientID(requesterLookupStrategy.apply(profileRequestContext));
+        
+        profileRequestContext.addSubcontext(resolutionContext, true);
+        resolutionContext.resolveAttributes(ensureApplication().getAttributeResolver());
+        return resolutionContext.getResolvedIdPAttributes().values();
+    }
+    
     /**
      * Built-in function to perform "standard" extraction of data into attributes.
      */

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


More information about the commits mailing list