[java-identity-provider] 02/02: Profile and flow support for SAML 2 authentication
Brent Putman
putmanb at georgetown.edu
Fri Jan 24 23:06:14 EST 2020
This is an automated email from the git hooks/post-receive script.
putmanb 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=df1dafeab3ce07e2f681c0001c70cb39245c9c07
commit df1dafeab3ce07e2f681c0001c70cb39245c9c07
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Tue Dec 17 15:17:29 2019 -0500
Profile and flow support for SAML 2 authentication
---
.../system/flows/authn/saml-authn-beans.xml | 68 +++++
.../system/flows/authn/saml-authn-flow.xml | 3 +
.../config/logic/CheckAddressPredicate.java | 49 ++++
.../logic/MaximumTimeSinceAuthnLookupFunction.java | 53 ++++
.../impl/ProcessAssertionsForAuthentication.java | 308 +++++++++++++++++++++
.../profile/impl/ValidateSAMLAuthentication.java | 7 -
6 files changed, 481 insertions(+), 7 deletions(-)
diff --git a/idp-conf/src/main/resources/system/flows/authn/saml-authn-beans.xml b/idp-conf/src/main/resources/system/flows/authn/saml-authn-beans.xml
index 7d5556b..89615ff 100644
--- a/idp-conf/src/main/resources/system/flows/authn/saml-authn-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/saml-authn-beans.xml
@@ -117,6 +117,12 @@
</constructor-arg>
</bean>
+ <bean id="PopulateInboundMessageContextWithSAMLSelf" parent="NestedWebFlowProfileActionAdaptor" scope="prototype">
+ <constructor-arg>
+ <bean class="net.shibboleth.idp.saml.profile.impl.PopulateInboundMessageContextWithSAMLSelf" scope="prototype" />
+ </constructor-arg>
+ </bean>
+
<util:constant id="shibboleth.EndpointType"
static-field="org.opensaml.saml.saml2.metadata.SingleSignOnService.DEFAULT_ELEMENT_NAME" />
@@ -286,6 +292,68 @@
</constructor-arg>
</bean>
+ <bean id="AssertionValidator" class="org.opensaml.saml.saml2.assertion.SAML20AssertionValidator">
+ <!-- Condition validators. -->
+ <constructor-arg index="0">
+ <util:list>
+ <bean class="org.opensaml.saml.saml2.assertion.impl.AudienceRestrictionConditionValidator" />
+ <bean class="org.opensaml.saml.saml2.assertion.impl.DelegationRestrictionConditionValidator" />
+ <bean class="org.opensaml.saml.saml2.assertion.impl.OneTimeUseConditionValidator">
+ <constructor-arg ref="shibboleth.ReplayCache" />
+ <constructor-arg value="#{null}" />
+ </bean>
+ <bean class="org.opensaml.saml.saml2.assertion.impl.ProxyRestrictionConditionValidator" />
+ </util:list>
+ </constructor-arg>
+ <!-- SubjectConfirmation validators. -->
+ <constructor-arg index="1">
+ <util:list>
+ <bean class="org.opensaml.saml.saml2.assertion.impl.BearerSubjectConfirmationValidator" />
+ <bean class="org.opensaml.saml.saml2.assertion.impl.HolderOfKeySubjectConfirmationValidator" />
+ </util:list>
+ </constructor-arg>
+ <!-- Statement validators. -->
+ <constructor-arg index="2">
+ <util:list>
+ <bean class="org.opensaml.saml.saml2.assertion.impl.AuthnStatementValidator" />
+ </util:list>
+ </constructor-arg>
+ <!-- This is null b/c in this case we use a dynamically-resolved engine in the ValidationContext -->
+ <constructor-arg index="3" value="#{null}" />
+ <constructor-arg index="4">
+ <bean class="org.opensaml.saml.security.impl.SAMLSignatureProfileValidator" />
+ </constructor-arg>
+ </bean>
+
+ <bean id="AssertionValidationContextBuilder" class="org.opensaml.saml.saml2.profile.impl.DefaultAssertionValidationContextBuilder">
+ <property name="checkAddress">
+ <bean class="net.shibboleth.idp.saml.saml2.profile.config.logic.CheckAddressPredicate" />
+ </property>
+ <property name="maximumTimeSinceAuthn">
+ <bean class="net.shibboleth.idp.saml.saml2.profile.config.logic.MaximumTimeSinceAuthnLookupFunction" />
+ </property>
+ <property name="signatureRequired">
+ <bean parent="shibboleth.Conditions.NOT">
+ <constructor-arg>
+ <bean class="org.opensaml.saml.common.profile.logic.InboundMessageSignedPredicate" />
+ </constructor-arg>
+ </bean>
+ </property>
+ </bean>
+
+ <bean id="ValidateAssertions" parent="NestedWebFlowProfileActionAdaptor" scope="prototype">
+ <constructor-arg>
+ <!-- TODO: should invalid be fatal, or let a later action decide what to do? -->
+ <bean class="org.opensaml.saml.saml2.profile.impl.ValidateAssertions" scope="prototype"
+ p:invalidFatal="true"
+ p:httpServletRequest-ref="shibboleth.HttpServletRequest"
+ p:validationContextBuilder-ref="AssertionValidationContextBuilder"
+ p:assertionValidator-ref="AssertionValidator" />
+ </constructor-arg>
+ </bean>
+
+ <bean id="ProcessAssertionsForAuthentication" class="net.shibboleth.idp.saml.saml2.profile.impl.ProcessAssertionsForAuthentication" scope="prototype" />
+
<bean id="DecryptNameIDs" parent="NestedWebFlowProfileActionAdaptor" scope="prototype">
<constructor-arg>
<bean class="org.opensaml.saml.saml2.profile.impl.DecryptNameIDs" />
diff --git a/idp-conf/src/main/resources/system/flows/authn/saml-authn-flow.xml b/idp-conf/src/main/resources/system/flows/authn/saml-authn-flow.xml
index 53d8d5e..5be18e0 100644
--- a/idp-conf/src/main/resources/system/flows/authn/saml-authn-flow.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/saml-authn-flow.xml
@@ -59,11 +59,14 @@
<evaluate expression="ContinueSAMLAuthentication" />
<evaluate expression="PopulateSignatureValidationParameters" />
<evaluate expression="PopulateClientTLSValidationParameters" />
+ <evaluate expression="PopulateInboundMessageContextWithSAMLSelf" />
<evaluate expression="HandleResponse" />
<evaluate expression="PopulateDecryptionParameters" />
<evaluate expression="DecryptAssertions" />
+ <evaluate expression="ValidateAssertions" />
<evaluate expression="DecryptNameIDs" />
<evaluate expression="DecryptAttributes" />
+ <evaluate expression="ProcessAssertionsForAuthentication" />
<evaluate expression="ValidateSAMLAuthentication" />
<evaluate expression="PostAssertionPopulateAuditContext" />
<evaluate expression="PostResponsePopulateAuditContext" />
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/logic/CheckAddressPredicate.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/logic/CheckAddressPredicate.java
new file mode 100644
index 0000000..057fae5
--- /dev/null
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/logic/CheckAddressPredicate.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.saml.saml2.profile.config.logic;
+
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.logic.AbstractRelyingPartyPredicate;
+import net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+/**
+ * A predicate that evaluates a {@link ProfileRequestContext} and extracts the effective
+ * setting of {@link BrowserSSOProfileConfiguration#isCheckAddress(ProfileRequestContext)}.
+ *
+ * <p>Defaults to true.</p>
+ *
+ * @since 4.0.0
+ */
+public class CheckAddressPredicate extends AbstractRelyingPartyPredicate {
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final ProfileRequestContext input) {
+
+ final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+ if (rpc != null && rpc.getProfileConfig() instanceof BrowserSSOProfileConfiguration) {
+ return ((BrowserSSOProfileConfiguration) rpc.getProfileConfig()).isCheckAddress(input);
+ }
+
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/logic/MaximumTimeSinceAuthnLookupFunction.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/logic/MaximumTimeSinceAuthnLookupFunction.java
new file mode 100644
index 0000000..6de2aa8
--- /dev/null
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/logic/MaximumTimeSinceAuthnLookupFunction.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.saml.saml2.profile.config.logic;
+
+import java.time.Duration;
+
+import javax.annotation.Nullable;
+
+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;
+import net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration;
+
+/**
+ * A function that returns {@link BrowserSSOProfileConfiguration#getMaximumTimeSinceAuthn(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 MaximumTimeSinceAuthnLookupFunction extends AbstractRelyingPartyLookupFunction<Duration> {
+
+ /** {@inheritDoc} */
+ @Nullable public Duration apply(@Nullable final ProfileRequestContext input) {
+ final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+ if (rpc != null) {
+ final ProfileConfiguration pc = rpc.getProfileConfig();
+ if (pc != null && pc instanceof BrowserSSOProfileConfiguration) {
+ return ((BrowserSSOProfileConfiguration) pc).getMaximumTimeSinceAuthn(input);
+ }
+ }
+
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java
new file mode 100644
index 0000000..139727e
--- /dev/null
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java
@@ -0,0 +1,308 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.saml.saml2.profile.impl;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.common.SAMLObject;
+import org.opensaml.saml.common.assertion.ValidationContext;
+import org.opensaml.saml.common.assertion.ValidationProcessingData;
+import org.opensaml.saml.common.assertion.ValidationResult;
+import org.opensaml.saml.saml2.assertion.SAML2AssertionValidationParameters;
+import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.AuthnStatement;
+import org.opensaml.saml.saml2.core.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.authn.AbstractAuthenticationAction;
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Perform processing of SAML 2 Assertions that have been validated by earlier actions
+ * for use in finalization of SAML-based authentication by later actions.
+ */
+public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAction {
+
+ /** Logger. */
+ private final Logger log = LoggerFactory.getLogger(ProcessAssertionsForAuthentication.class);
+
+ /** The resolver for the list of assertions to be processed. */
+ @Nonnull private Function<ProfileRequestContext, List<Assertion>> assertionResolver;
+
+ /** Lookup strategy to locate the SAML context. */
+ @Nonnull private Function<ProfileRequestContext,SAMLAuthnContext> samlContextLookupStrategy;
+
+ /** Selection strategy for multiple valid authn Assertions. */
+ @Nonnull private Function<List<Assertion>,Assertion> authnAssertionSelectionStrategy;
+
+ /** Selection strategy for multiple AuthnStatements. */
+ @Nonnull private Function<Assertion,AuthnStatement> authnStatementSelectionStrategy;
+
+ /** The list of initial candidate Assertions to process. */
+ private List<Assertion> candidates;
+
+ /** The SAML authentication context. */
+ private SAMLAuthnContext samlAuthnContext;
+
+ /**
+ * Constructor.
+ */
+ public ProcessAssertionsForAuthentication() {
+ super();
+
+ assertionResolver = new DefaultAssertionResolver().compose(
+ new ChildContextLookup<>(ProfileRequestContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class)));
+
+ // PRC -> AC -> SAMLAuthnContext
+ samlContextLookupStrategy = new ChildContextLookup<>(SAMLAuthnContext.class).compose(
+ new ChildContextLookup<>(AuthenticationContext.class));
+
+ //TODO replace with better default logic based on Scott review and SP behavior
+ authnAssertionSelectionStrategy = assertions -> {
+ return assertions.get(0);
+ };
+
+ //TODO replace with better default logic based on Scott review and SP behavior
+ authnStatementSelectionStrategy = assertion -> {
+ return assertion.getAuthnStatements().get(0);
+ };
+ }
+
+ /**
+ * Set the strategy function for selecting which of multiple valid Assertions to use.
+ *
+ * @param strategy the new strategy function
+ */
+ public void setAuthnAssertionSelectionStrategy(@Nonnull final Function<List<Assertion>, Assertion> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ authnAssertionSelectionStrategy = Constraint.isNotNull(strategy,
+ "The Assertion selection strategy may not be null");
+ }
+
+ /**
+ * Set the strategy function for selecting which of multiple AuthnStatements to use.
+ *
+ * @param strategy the new strategy function
+ */
+ public void setAuthnStatementSelectionStrategy(@Nonnull final Function<Assertion, AuthnStatement> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ authnStatementSelectionStrategy = Constraint.isNotNull(strategy,
+ "The AuthnStatement selection strategy may not be null");
+ }
+
+ /**
+ * Set the strategy function which resolves the list of assertions to process.
+ *
+ * @param strategy the new strategy function
+ */
+ public void setAssertionResolver(@Nonnull final Function<ProfileRequestContext, List<Assertion>> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ assertionResolver = Constraint.isNotNull(strategy, "The Assertion resolver strategy may not be null");
+ }
+
+ /**
+ * Set the lookup strategy used to locate the {@link SAMLAuthnContext}.
+ *
+ * @param strategy the new strategy function
+ */
+ public void setSAMLAuthnContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,SAMLAuthnContext> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ samlContextLookupStrategy = Constraint.isNotNull(strategy, "SAMLAuthnContext lookup strategy may not be null");
+ }
+
+ /** {@inheritDoc} */
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+ if (!super.doPreExecute(profileRequestContext, authenticationContext)) {
+ return false;
+ }
+
+ candidates = assertionResolver.apply(profileRequestContext);
+ if (candidates == null || candidates.isEmpty()) {
+ log.info("{} Profile context contained no candidate Assertions to process. Skipping further processing",
+ getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
+ return false;
+ }
+
+ samlAuthnContext = samlContextLookupStrategy.apply(profileRequestContext);
+ if (samlAuthnContext == null) {
+ log.debug("{} No SAMLAuthnContext available within authentication context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
+ return false;
+ }
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final AuthenticationContext authenticationContext) {
+
+ // Select only valid Assertions which contain at least 1 AuthnStatement and a confirmed Subject
+ final Predicate<Assertion> selector = new AssertionIsValid()
+ .and(new AssertionContainsAuthenticationStatement())
+ .and(new AssertionContainsConfirmedSubject());
+
+ final List<Assertion> assertions = candidates.stream().filter(selector).collect(Collectors.toList());
+ if (assertions.isEmpty()) {
+ log.debug("{} No valid SAML Assertions meeting the criteria for authentication were found", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
+ return;
+ }
+
+ Assertion authnAssertion = null;
+ if (assertions.size() == 1) {
+ authnAssertion = assertions.get(0);
+ log.debug("{} Saw single valid SAML Assertion, selecting for authentication", getLogPrefix());
+ } else {
+ log.debug("{} Attempting to select from multiple valid SAML Assertions for authentication", getLogPrefix());
+ authnAssertion = authnAssertionSelectionStrategy.apply(assertions);
+ }
+ if (authnAssertion == null) {
+ log.debug("{} Could not select a single valid SAML Assertion for authentication", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
+ return;
+ }
+
+ log.debug("{} Selected valid SAML Assertion for authentication: {}", getLogPrefix(), authnAssertion.getID());
+
+ AuthnStatement authnStatement = null;
+ if (authnAssertion.getAuthnStatements().size() == 1) {
+ authnStatement = authnAssertion.getAuthnStatements().get(0);
+ log.debug("{} Saw single AuthnStatement, selecting for authentication", getLogPrefix());
+ } else {
+ log.debug("{} Attempting to select from multiple AuthnStatements for authentication", getLogPrefix());
+ authnStatement = authnStatementSelectionStrategy.apply(authnAssertion);
+ if (authnStatement == null) {
+ log.debug("{} Could not select a single AuthnStatement for authentication", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
+ return;
+ }
+ }
+
+ samlAuthnContext.setAuthnStatement(authnStatement);
+ samlAuthnContext.setSubject(authnAssertion.getSubject());
+ }
+
+ /**
+ * The default assertion resolver function. NOTE: this is relative to the nested profile request context.
+ * Need to compose with other lookup function against the main/outer profile request context.
+ */
+ private class DefaultAssertionResolver implements Function<ProfileRequestContext, List<Assertion>> {
+
+ /** {@inheritDoc} */
+ public List<Assertion> apply(@Nonnull final ProfileRequestContext profileContext) {
+ final SAMLObject message = (SAMLObject) profileContext.getInboundMessageContext().getMessage();
+ if (message instanceof Response) {
+ return ((Response) message).getAssertions();
+ }
+
+ return null;
+ }
+
+ }
+
+ /**
+ * Predicate for valid assertions.
+ */
+ private class AssertionIsValid implements Predicate<Assertion> {
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final Assertion assertion) {
+ if (assertion == null) {
+ return false;
+ }
+
+ final Optional<ValidationProcessingData> validationData = assertion.getObjectMetadata()
+ .get(ValidationProcessingData.class).stream().findFirst();
+ if (validationData.isEmpty()) {
+ return false;
+ }
+
+ return validationData.get().getResult() == ValidationResult.VALID;
+ }
+
+ }
+
+ /**
+ * Predicate for assertions containing at least 1 AuthenticationStatement.
+ */
+ private class AssertionContainsAuthenticationStatement implements Predicate<Assertion> {
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final Assertion assertion) {
+ if (assertion == null) {
+ return false;
+ }
+
+ return ! assertion.getAuthnStatements().isEmpty();
+ }
+
+ }
+
+ /**
+ * Predicate for assertions which have been validated and have a confirmed Subject.
+ */
+ private class AssertionContainsConfirmedSubject implements Predicate<Assertion> {
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final Assertion assertion) {
+ if (assertion == null) {
+ return false;
+ }
+
+ final Optional<ValidationProcessingData> validationData = assertion.getObjectMetadata()
+ .get(ValidationProcessingData.class).stream().findFirst();
+ if (validationData.isEmpty()) {
+ return false;
+ }
+
+ final ValidationContext validationContext = validationData.get().getContext();
+ if (validationContext == null) {
+ return false;
+ }
+
+ return validationContext.getDynamicParameters()
+ .get(SAML2AssertionValidationParameters.CONFIRMED_SUBJECT_CONFIRMATION) != null;
+ }
+
+ }
+
+}
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 1e0f13c..b3ab4dd 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
@@ -240,13 +240,6 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
profileConfiguration = (BrowserSSOProfileConfiguration) rpContext.getProfileConfig();
- // TODO: Dummy code until we have something processing the results properly.
- final Response response = (Response) profileRequestContext.getInboundMessageContext().getMessage();
- 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));
return true;
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list