[java-identity-provider] branch master updated: IDP-1494 - Login flow for proxied authentication
Scott Cantor
cantor.2 at osu.edu
Wed Oct 30 13:27:08 EDT 2019
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch master
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=b8a0d1b11fa31ede9d108eba70309698fcb2365d
The following commit(s) were added to refs/heads/master by this push:
new b8a0d1b IDP-1494 - Login flow for proxied authentication
b8a0d1b is described below
commit b8a0d1b11fa31ede9d108eba70309698fcb2365d
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Oct 30 13:25:16 2019 -0400
IDP-1494 - Login flow for proxied authentication
https://issues.shibboleth.net/jira/browse/IDP-1494
Start to flesh out result end of SAML flow.
---
.../system/flows/authn/proxy/saml-proxy-beans.xml | 12 +-
.../system/flows/authn/proxy/saml-proxy-flow.xml | 1 +
idp-saml-impl/pom.xml | 5 +
.../saml/saml2/profile/impl/AddAuthnRequest.java | 2 +-
...cation.java => ContinueSAMLAuthentication.java} | 18 +-
.../saml/saml2/profile/impl/SAMLAuthnContext.java | 55 +++-
.../profile/impl/ValidateSAMLAuthentication.java | 338 +++++++++++++++++++--
7 files changed, 397 insertions(+), 34 deletions(-)
diff --git a/idp-conf/src/main/resources/system/flows/authn/proxy/saml-proxy-beans.xml b/idp-conf/src/main/resources/system/flows/authn/proxy/saml-proxy-beans.xml
index 547120c..6c81b89 100644
--- a/idp-conf/src/main/resources/system/flows/authn/proxy/saml-proxy-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/proxy/saml-proxy-beans.xml
@@ -213,9 +213,19 @@
p:httpServletRequest-ref="shibboleth.HttpServletRequest"
p:bindingDescriptor-ref="shibboleth.Binding.SAML2POST" />
+ <bean id="ContinueSAMLAuthentication"
+ class="net.shibboleth.idp.saml.saml2.profile.impl.ContinueSAMLAuthentication" scope="prototype"
+ p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
+
<bean id="ValidateSAMLAuthentication"
class="net.shibboleth.idp.saml.saml2.profile.impl.ValidateSAMLAuthentication" scope="prototype"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
- p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:responderLookupStrategy-ref="shibboleth.RelyingPartyIdLookup.Simple"
+ p:requesterLookupStrategy-ref="shibboleth.ResponderIdLookup.Simple"
+ p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
+ p:attributeFilter-ref="shibboleth.AttributeFilterService"
+ p:metadataResolver-ref="shibboleth.MetadataResolver" />
</beans>
diff --git a/idp-conf/src/main/resources/system/flows/authn/proxy/saml-proxy-flow.xml b/idp-conf/src/main/resources/system/flows/authn/proxy/saml-proxy-flow.xml
index 9991204..4803cba 100644
--- a/idp-conf/src/main/resources/system/flows/authn/proxy/saml-proxy-flow.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/proxy/saml-proxy-flow.xml
@@ -45,6 +45,7 @@
</view-state>
<action-state id="ProcessResponse">
+ <evaluate expression="ContinueSAMLAuthentication" />
<evaluate expression="ValidateSAMLAuthentication" />
<evaluate expression="'proceed'" />
diff --git a/idp-saml-impl/pom.xml b/idp-saml-impl/pom.xml
index 673dba1..45298bb 100644
--- a/idp-saml-impl/pom.xml
+++ b/idp-saml-impl/pom.xml
@@ -56,6 +56,11 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
+ <artifactId>idp-attribute-filter-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
<artifactId>idp-attribute-resolver-api</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
index b50a733..7201449 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
@@ -80,7 +80,7 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
/** Strategy used to obtain the relay state token to provide. */
@Nonnull private Function<ProfileRequestContext,String> relayStateLookupStrategy;
- /** Strategy used to obtain the response issuer value. */
+ /** Strategy used to obtain the request issuer value. */
@Nullable private Function<ProfileRequestContext,String> issuerLookupStrategy;
/** The generator to use. */
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ContinueSAMLAuthentication.java
similarity index 79%
copy from idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
copy to idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ContinueSAMLAuthentication.java
index a89ca72..08e21c7 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ContinueSAMLAuthentication.java
@@ -24,11 +24,13 @@ import net.shibboleth.idp.authn.AbstractAuthenticationAction;
import net.shibboleth.idp.authn.AuthnEventIds;
import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.authn.context.ExternalAuthenticationContext;
+import net.shibboleth.utilities.java.support.logic.Constraint;
import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.saml2.core.Response;
+import org.opensaml.saml.saml2.core.StatusCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,10 +48,10 @@ import org.slf4j.LoggerFactory;
* @event {@link AuthnEventIds#NO_CREDENTIALS}
* @event various
*/
-public class ValidateSAMLAuthentication extends AbstractAuthenticationAction {
+public class ContinueSAMLAuthentication extends AbstractAuthenticationAction {
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(ValidateSAMLAuthentication.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(ContinueSAMLAuthentication.class);
/** Context containing the result to examine. */
@Nullable private ExternalAuthenticationContext extContext;
@@ -89,6 +91,18 @@ public class ValidateSAMLAuthentication extends AbstractAuthenticationAction {
log.info("{} Inbound message was not a SAML Response", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.MESSAGE_PROC_ERROR);
}
+
+ // TODO: this is dummy code to be removed once we have legitimate processing in place.
+ final Response response = (Response) profileRequestContext.getInboundMessageContext().getMessage();
+ if (StatusCode.SUCCESS.equals(response.getStatus().getStatusCode().getValue())) {
+ Constraint.isTrue(response.getAssertions().size() == 1, "Wrong assertion count");
+ Constraint.isTrue(response.getAssertions().get(0).getAuthnStatements().size() == 1, "Wrong statement count");
+ authenticationContext.getSubcontext(SAMLAuthnContext.class)
+ .setSubject(response.getAssertions().get(0).getSubject())
+ .setAuthnStatement(response.getAssertions().get(0).getAuthnStatements().get(0));
+ } else {
+ authenticationContext.removeSubcontext(SAMLAuthnContext.class);
+ }
}
}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/SAMLAuthnContext.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/SAMLAuthnContext.java
index 9ee5dc1..4083060 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/SAMLAuthnContext.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/SAMLAuthnContext.java
@@ -26,12 +26,13 @@ import org.opensaml.messaging.context.BaseContext;
import org.opensaml.messaging.decoder.MessageDecoder;
import org.opensaml.messaging.handler.MessageHandler;
import org.opensaml.profile.action.ProfileAction;
+import org.opensaml.saml.saml2.core.AuthnStatement;
+import org.opensaml.saml.saml2.core.Subject;
import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * Manages state for the webflow -> external -> webflow transitions
- * during proxied SAML authentication.
+ * Manages state during proxied SAML authentication.
*
* @since 4.0.0
*/
@@ -46,6 +47,12 @@ public class SAMLAuthnContext extends BaseContext {
/** The function to use to obtain a decoder. */
@Nonnull private Function<String,MessageDecoder> decoderFactory;
+ /** Subject of assertion used to authenticate. */
+ @Nullable private Subject subject;
+
+ /** Authentication statement. */
+ @Nullable private AuthnStatement authnStatement;
+
/**
* Constructor.
*
@@ -98,4 +105,48 @@ public class SAMLAuthnContext extends BaseContext {
return this;
}
+ /**
+ * Get the SAML {@link Subject} from the authentication.
+ *
+ * @return SAML {@link Subject}
+ */
+ @Nullable public Subject getSubject() {
+ return subject;
+ }
+
+ /**
+ * Set the SAML {@link Subject} from the authentication.
+ *
+ * @param sub the SAML {@link Subject}
+ *
+ * @return this context
+ */
+ @Nonnull public SAMLAuthnContext setSubject(@Nullable final Subject sub) {
+ subject = sub;
+
+ return this;
+ }
+
+ /**
+ * Get the SAML {@link AuthnStatement} from the authentication.
+ *
+ * @return SAML {@link AuthnStatement}
+ */
+ @Nullable public AuthnStatement getAuthnStatement() {
+ return authnStatement;
+ }
+
+ /**
+ * Set the SAML {@link AuthnStatement} from the authentication.
+ *
+ * @param statement the SAML {@link AuthnStatement}
+ *
+ * @return this context
+ */
+ @Nonnull public SAMLAuthnContext setAuthnStatement(@Nullable final AuthnStatement statement) {
+ authnStatement = statement;
+
+ return this;
+ }
+
}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
index a89ca72..67e008d 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
@@ -17,42 +17,146 @@
package net.shibboleth.idp.saml.saml2.profile.impl;
+import java.util.Collection;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.security.auth.Subject;
-import net.shibboleth.idp.authn.AbstractAuthenticationAction;
+import net.shibboleth.idp.attribute.AttributeDecodingException;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.context.AttributeContext;
+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.transcoding.AttributeTranscoder;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
+import net.shibboleth.idp.attribute.transcoding.TranscoderSupport;
+import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
+import net.shibboleth.idp.authn.AbstractValidationAction;
import net.shibboleth.idp.authn.AuthnEventIds;
import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.idp.authn.context.ExternalAuthenticationContext;
+import net.shibboleth.idp.authn.principal.IdPAttributePrincipal;
+import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
+import net.shibboleth.idp.profile.context.navigate.ResponderIdLookupFunction;
+import net.shibboleth.idp.saml.profile.context.navigate.SAMLMetadataContextLookupFunction;
+import net.shibboleth.utilities.java.support.annotation.constraint.Live;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.service.ReloadableService;
+import net.shibboleth.utilities.java.support.service.ServiceableComponent;
+import org.opensaml.messaging.context.navigate.RecursiveTypedParentContextLookup;
import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.metadata.resolver.MetadataResolver;
+import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.Attribute;
+import org.opensaml.saml.saml2.core.AttributeStatement;
+import org.opensaml.saml.saml2.core.AuthenticatingAuthority;
import org.opensaml.saml.saml2.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Strings;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
/**
- * An action that checks for an {@link ExternalAuthenticationContext} for a signaled event via the
- * {@link ExternalAuthenticationContext#getAuthnError()} method, and otherwise enforces the presence
- * of an inbound SAML Response to process.
+ * An action that produces an {@link net.shibboleth.idp.authn.AuthenticationResult} based on an inbound
+ * SAML 2.0 SSO response.
*
- * <p>This is a bridge from the external portion of the SAML proxy implementation to transition
- * back into the flow and pick up any signaled errors if necessary.</p>
+ * <p>A {@link SAMLAuthnContext} is used as the basis of the result and the lack of a context is a signal
+ * to record a failure. Actual validation is all upstream of this action, but the use of the ValidationAction
+ * subclass is a convenience for auditing and handling the result.</p>
*
* @event {@link EventIds#PROCEED_EVENT_ID}
- * @event {@Link EventIds#MESSAGE_PROC_ERROR}
- * @event {@link AuthnEventIds#INVALID_AUTHN_CTX}
- * @event {@link AuthnEventIds#NO_CREDENTIALS}
- * @event various
+ * @event {@link EventIds#INVALID_PROFILE_CTX}
+ * @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class).getAttemptedFlow() != null</pre>
+ * @post If AuthenticationContext.getSubcontext(SAMLAuthnContext.class) != null, then
+ * an {@link net.shibboleth.idp.authn.AuthenticationResult} is saved to the {@link AuthenticationContext}.
*/
-public class ValidateSAMLAuthentication extends AbstractAuthenticationAction {
+public class ValidateSAMLAuthentication extends AbstractValidationAction {
+
+ /** Default prefix for metrics. */
+ @Nonnull @NotEmpty private static final String DEFAULT_METRIC_NAME = "net.shibboleth.idp.authn.saml";
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(ValidateSAMLAuthentication.class);
- /** Context containing the result to examine. */
- @Nullable private ExternalAuthenticationContext extContext;
+ /** Transcoder registry service object. */
+ @Nullable private ReloadableService<AttributeTranscoderRegistry> transcoderRegistry;
+
+ /** Service used to get the engine used to filter attributes. */
+ @Nullable private ReloadableService<AttributeFilter> attributeFilterService;
+
+ /** Strategy used to obtain our identity. */
+ @Nullable private Function<ProfileRequestContext,String> recipientIdLookupStrategy;
+
+ /** Optional supplemental metadata source for filtering. */
+ @Nullable private MetadataResolver metadataResolver;
+
+ /** Context containing the result to validate. */
+ @Nullable private SAMLAuthnContext samlAuthnContext;
+
+ /** Free-standing context for externally supplied inbound attributes. */
+ @Nullable private AttributeContext attributeContext;
+
+ /** Constructor. */
+ public ValidateSAMLAuthentication() {
+ setMetricName(DEFAULT_METRIC_NAME);
+ recipientIdLookupStrategy = new ResponderIdLookupFunction();
+ }
+
+ /**
+ * Sets the registry of transcoding rules to apply to encode attributes.
+ *
+ * @param registry registry service interface
+ */
+ public void setTranscoderRegistry(@Nullable final ReloadableService<AttributeTranscoderRegistry> registry) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ transcoderRegistry = registry;
+ }
+
+
+ /**
+ * Sets the filter service to use for inbound attributes.
+ *
+ * @param filterService optional filter service for inbound attributes
+ */
+ public void setAttributeFilter(@Nullable final ReloadableService<AttributeFilter> filterService) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ attributeFilterService = filterService;
+ }
+
+ /**
+ * Set a metadata source to use during filtering.
+ *
+ * @param resolver metadata resolver
+ */
+ public void setMetadataResolver(@Nullable final MetadataResolver resolver) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ metadataResolver = resolver;
+ }
+
+ /**
+ * Set the strategy used to locate the attribute recipient value to use.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setRecipientIdLookupStrategy(@Nullable final Function<ProfileRequestContext,String> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ recipientIdLookupStrategy = strategy;
+ }
/** {@inheritDoc} */
@Override
@@ -63,10 +167,18 @@ public class ValidateSAMLAuthentication extends AbstractAuthenticationAction {
return false;
}
- extContext = authenticationContext.getSubcontext(ExternalAuthenticationContext.class);
- if (extContext == null) {
- log.debug("{} No ExternalAuthenticationContext available within authentication context", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX);
+ if (authenticationContext.getAttemptedFlow() == null) {
+ log.debug("{} No attempted flow within authentication context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+ recordFailure();
+ return false;
+ }
+
+ samlAuthnContext = authenticationContext.getSubcontext(SAMLAuthnContext.class);
+ if (samlAuthnContext == null) {
+ log.debug("{} No SAMLAuthnContext available within authentication context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
+ recordFailure();
return false;
}
@@ -78,17 +190,187 @@ public class ValidateSAMLAuthentication extends AbstractAuthenticationAction {
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@Nonnull final AuthenticationContext authenticationContext) {
- if (extContext.getAuthnError() != null) {
- log.info("{} SAML authentication attempt signaled an error: {}", getLogPrefix(),
- extContext.getAuthnError());
- ActionSupport.buildEvent(profileRequestContext, extContext.getAuthnError());
- } else if (profileRequestContext.getInboundMessageContext() == null) {
- log.info("{} No inbound SAML Response found", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_CREDENTIALS);
- } else if (!(profileRequestContext.getInboundMessageContext().getMessage() instanceof Response)) {
- log.info("{} Inbound message was not a SAML Response", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.MESSAGE_PROC_ERROR);
+ recordSuccess();
+
+ if (transcoderRegistry != null) {
+ processAttributes(profileRequestContext);
+ }
+
+ buildAuthenticationResult(profileRequestContext, authenticationContext);
+
+ if (authenticationContext.getAuthenticationResult() != null) {
+ if (samlAuthnContext.getAuthnStatement().getAuthnInstant() != null) {
+ authenticationContext.getAuthenticationResult().setAuthenticationInstant(
+ samlAuthnContext.getAuthnStatement().getAuthnInstant());
+ }
}
}
+ /** {@inheritDoc} */
+ @Override
+ @Nonnull protected Subject populateSubject(@Nonnull final Subject subject) {
+
+ final Collection<AuthenticatingAuthority> authorities =
+ samlAuthnContext.getAuthnStatement().getAuthnContext().getAuthenticatingAuthorities();
+ if (!authorities.isEmpty()) {
+ final ProxyAuthenticationPrincipal proxied = new ProxyAuthenticationPrincipal(
+ authorities
+ .stream()
+ .filter(aa -> !Strings.isNullOrEmpty(aa.getURI()))
+ .map(AuthenticatingAuthority::getURI)
+ .collect(Collectors.toUnmodifiableList()));
+ subject.getPrincipals().add(proxied);
+ }
+
+ if (attributeContext != null && !attributeContext.getIdPAttributes().isEmpty()) {
+ log.debug("{} Adding filtered inbound attributes to Subject", getLogPrefix());
+ subject.getPrincipals().addAll(
+ attributeContext.getIdPAttributes().values()
+ .stream()
+ .map(a -> new IdPAttributePrincipal(a))
+ .collect(Collectors.toUnmodifiableList()));
+ }
+
+ return subject;
+ }
+
+ /**
+ * Process the inbound SAML Attributes.
+ *
+ * @param profileRequestContext current profile request context
+ */
+ private void processAttributes(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ log.debug("{} Decoding incoming SAML Attributes", getLogPrefix());
+
+ final Multimap<String,IdPAttribute> mapped = HashMultimap.create();
+
+ ServiceableComponent<AttributeTranscoderRegistry> component = null;
+ try {
+ component = transcoderRegistry.getServiceableComponent();
+ if (component == null) {
+ log.error("Attribute transcoder service unavailable");
+ return;
+ }
+
+ final Response response = (Response) profileRequestContext.getInboundMessageContext().getMessage();
+ for (final Assertion assertion : response.getAssertions()) {
+ for (final AttributeStatement statement : assertion.getAttributeStatements()) {
+ for (final Attribute designator : statement.getAttributes()) {
+ try {
+ decodeAttribute(component.getComponent(), profileRequestContext, designator, mapped);
+ } catch (final AttributeDecodingException e) {
+ log.error("{} Error decoding inbound Attribute", getLogPrefix(), e);
+ }
+ }
+ }
+ }
+ } finally {
+ if (component != null) {
+ component.unpinComponent();
+ }
+ }
+
+ log.debug("{} Incoming SAML Attributes mapped to attribute IDs: {}", getLogPrefix(), mapped.keySet());
+
+ if (!mapped.isEmpty()) {
+ attributeContext = new AttributeContext();
+ attributeContext.setUnfilteredIdPAttributes(mapped.values());
+ filterAttributes(profileRequestContext);
+ }
+ }
+
+ /**
+ * Access the registry of transcoding rules to decode the input {@link Attribute}.
+ *
+ * @param registry registry of transcoding rules
+ * @param profileRequestContext current profile request context
+ * @param input input object
+ * @param results collection to add results to
+ *
+ * @throws AttributeDecodingException if an error occurs or no results were obtained
+ */
+ private void decodeAttribute(@Nonnull final AttributeTranscoderRegistry registry,
+ @Nonnull final ProfileRequestContext profileRequestContext, @Nonnull final Attribute input,
+ @Nonnull @NonnullElements @Live final Multimap<String,IdPAttribute> results)
+ throws AttributeDecodingException {
+
+ final Collection<TranscodingRule> transcodingRules = registry.getTranscodingRules(input);
+ if (transcodingRules.isEmpty()) {
+ log.info("{} No transcoding rule for Attribute '{}'", getLogPrefix(), input.getName());
+ return;
+ }
+
+ for (final TranscodingRule rules : transcodingRules) {
+ final AttributeTranscoder<Attribute> transcoder = TranscoderSupport.getTranscoder(rules);
+ final IdPAttribute decodedAttribute = transcoder.decode(profileRequestContext, input, rules);
+ if (decodedAttribute != null) {
+ results.put(decodedAttribute.getId(), decodedAttribute);
+ }
+ }
+ }
+
+ /**
+ * Check for inbound attributes and apply filtering.
+ *
+ * @param profileRequestContext current profile request context
+ */
+ private void filterAttributes(@Nonnull final ProfileRequestContext profileRequestContext) {
+ if (attributeFilterService == null) {
+ log.warn("{} No AttributeFilter service provided", getLogPrefix());
+ attributeContext.setIdPAttributes(null);
+ return;
+ }
+
+
+ final AttributeFilterContext filterContext = samlAuthnContext.getSubcontext(AttributeFilterContext.class, true);
+
+ populateFilterContext(profileRequestContext, filterContext);
+
+ ServiceableComponent<AttributeFilter> component = null;
+
+ try {
+ component = attributeFilterService.getServiceableComponent();
+ if (null == component) {
+ log.error("{} Error while filtering inbound attributes: Invalid Attribute Filter configuration",
+ getLogPrefix());
+ attributeContext.setIdPAttributes(null);
+ } else {
+ final AttributeFilter filter = component.getComponent();
+ filter.filterAttributes(filterContext);
+ filterContext.getParent().removeSubcontext(filterContext);
+ attributeContext.setIdPAttributes(filterContext.getFilteredIdPAttributes().values());
+ }
+ } catch (final AttributeFilterException e) {
+ log.error("{} Error while filtering inbound attributes", getLogPrefix(), e);
+ attributeContext.setIdPAttributes(null);
+ } finally {
+ if (null != component) {
+ component.unpinComponent();
+ }
+ }
+ }
+
+ /**
+ * Fill in the filter context data.
+ *
+ * @param profileRequestContext current profile request context
+ * @param filterContext context to populate
+ */
+ private void populateFilterContext(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AttributeFilterContext filterContext) {
+
+ filterContext.setDirection(Direction.INBOUND)
+ .setPrefilteredIdPAttributes(attributeContext.getUnfilteredIdPAttributes().values())
+ .setMetadataResolver(metadataResolver)
+ .setRequesterMetadataContextLookupStrategy(null)
+ .setIssuerMetadataContextLookupStrategy(
+ new SAMLMetadataContextLookupFunction().compose(
+ new RecursiveTypedParentContextLookup<>(ProfileRequestContext.class)))
+ .setProxiedRequesterContextLookupStrategy(null)
+ .setAttributeIssuerID(
+ ((Assertion) samlAuthnContext.getAuthnStatement().getParent()).getIssuer().getValue())
+ .setAttributeRecipientID(recipientIdLookupStrategy.apply(profileRequestContext));
+ }
+
}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list