[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