[java-opensaml] branch master updated: IDP-1494: Login flow for proxied SAML authentication
Brent Putman
putmanb at georgetown.edu
Sun Mar 8 01:18: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-opensaml.
View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=dc92eed3945ae4431a942e42a3494b37de047949
The following commit(s) were added to refs/heads/master by this push:
new dc92eed IDP-1494: Login flow for proxied SAML authentication
dc92eed is described below
commit dc92eed3945ae4431a942e42a3494b37de047949
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Fri Mar 6 22:56:58 2020 -0500
IDP-1494: Login flow for proxied SAML authentication
Unit tests.
---
.../saml2/profile/impl/ValidateAssertions.java | 16 +-
.../assertion/BaseAssertionValidationTest.java | 36 +++
.../saml2/assertion/MockAssertionValidator.java | 82 ++++++
.../impl/AuthnStatementValidatorTest.java | 198 +++++++++++++
.../MockAssertionValidationContextBuilder.java | 49 ++++
.../saml2/profile/impl/ValidateAssertionsTest.java | 326 +++++++++++++++++++++
6 files changed, 702 insertions(+), 5 deletions(-)
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/ValidateAssertions.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/ValidateAssertions.java
index 6f2ccf8..80b79cb 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/ValidateAssertions.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/ValidateAssertions.java
@@ -107,7 +107,9 @@ public class ValidateAssertions extends AbstractProfileAction {
* @param function the new assertion resolver function
*/
public void setAssertionResolver(@Nonnull final Function<ProfileRequestContext, List<Assertion>> function) {
- assertionResolver = Constraint.isNotNull(function, "The Assertion resolver function may not be null");
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+ assertionResolver = function;
}
/**
@@ -139,7 +141,7 @@ public class ValidateAssertions extends AbstractProfileAction {
@Nonnull final Function<AssertionValidationInput, ValidationContext> builder) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
- validationContextBuilder = Constraint.isNotNull(builder, "Validation context builder may not be null");
+ validationContextBuilder = builder;
}
/**
@@ -159,7 +161,7 @@ public class ValidateAssertions extends AbstractProfileAction {
public void setHttpServletRequest(@Nonnull final HttpServletRequest request) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
- httpServletRequest = Constraint.isNotNull(request, "HttpServletRequest cannot be null");
+ httpServletRequest = request;
}
/**
@@ -236,6 +238,10 @@ public class ValidateAssertions extends AbstractProfileAction {
protected void doInitialize() throws ComponentInitializationException {
super.doInitialize();
+ if (getAssertionResolver() == null) {
+ throw new ComponentInitializationException("Assertion resolver function cannot be null");
+ }
+
if (getValidationContextBuilder() == null) {
throw new ComponentInitializationException("ValidationContext builder cannot be null");
}
@@ -294,8 +300,8 @@ public class ValidateAssertions extends AbstractProfileAction {
sawNonValid = true;
}
processResult(validationContext, validationResult, assertion, profileContext);
- } catch (final AssertionValidationException e) {
- log.warn("{} There was a problem determining Assertion validity: {}", getLogPrefix(), e.getMessage());
+ } catch (final Throwable t) {
+ log.warn("{} There was a problem determining Assertion validity", getLogPrefix(), t);
ActionSupport.buildEvent(profileContext, SAMLEventIds.UNABLE_VALIDATE_ASSERTION);
return;
}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/BaseAssertionValidationTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/BaseAssertionValidationTest.java
index 6fa4d87..1b54f38 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/BaseAssertionValidationTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/BaseAssertionValidationTest.java
@@ -40,9 +40,13 @@ import org.opensaml.core.xml.XMLObjectBaseTestCase;
import org.opensaml.core.xml.XMLObjectBuilder;
import org.opensaml.core.xml.io.MarshallingException;
import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.AuthnContext;
+import org.opensaml.saml.saml2.core.AuthnContextClassRef;
+import org.opensaml.saml.saml2.core.AuthnStatement;
import org.opensaml.saml.saml2.core.Conditions;
import org.opensaml.saml.saml2.core.SubjectConfirmation;
import org.opensaml.saml.saml2.core.SubjectConfirmationData;
+import org.opensaml.saml.saml2.core.SubjectLocality;
import org.opensaml.saml.saml2.profile.SAML2ActionTestingSupport;
import org.opensaml.security.SecurityException;
import org.opensaml.security.credential.BasicCredential;
@@ -72,6 +76,9 @@ public class BaseAssertionValidationTest extends XMLObjectBaseTestCase {
public static final String SUBJECT_CONFIRMATION_IN_RESPONSE_TO = "id-123";
+ public static final String AUTHN_STATEMENT_ADDRESS = "10.1.2.3";
+
+
private Assertion assertion;
protected Assertion getAssertion() {
@@ -123,6 +130,25 @@ public class BaseAssertionValidationTest extends XMLObjectBaseTestCase {
return scd;
}
+ protected AuthnStatement buildBasicAuthnStatement() {
+ AuthnStatement authnStatement = buildXMLObject(AuthnStatement.DEFAULT_ELEMENT_NAME);
+
+ Instant now = Instant.now();
+ authnStatement.setAuthnInstant(now.minusSeconds(5));
+
+ SubjectLocality sl = buildXMLObject(SubjectLocality.DEFAULT_ELEMENT_NAME);
+ sl.setAddress(AUTHN_STATEMENT_ADDRESS);
+ authnStatement.setSubjectLocality(sl);
+
+ AuthnContextClassRef accr = buildXMLObject(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
+ accr.setURI(AuthnContext.PASSWORD_AUTHN_CTX);
+ AuthnContext ac = buildXMLObject(AuthnContext.DEFAULT_ELEMENT_NAME);
+ ac.setAuthnContextClassRef(accr);
+ authnStatement.setAuthnContext(ac);
+
+ return authnStatement;
+ }
+
protected Map<String,Object> buildBasicStaticParameters() {
HashMap<String,Object> params = new HashMap<>();
@@ -140,6 +166,16 @@ public class BaseAssertionValidationTest extends XMLObjectBaseTestCase {
} catch(UnknownHostException e) {
Assert.fail("Invalid address: " + SUBJECT_CONFIRMATION_ADDRESS);
}
+
+ params.put(SAML2AssertionValidationParameters.STMT_AUTHN_MAX_TIME, Duration.ofMinutes(5));
+
+ try {
+ params.put(SAML2AssertionValidationParameters.STMT_AUTHN_VALID_ADDRESSES,
+ Collections.singleton(InetAddress.getByName(AUTHN_STATEMENT_ADDRESS)));
+ } catch(UnknownHostException e) {
+ Assert.fail("Invalid address: " + AUTHN_STATEMENT_ADDRESS);
+ }
+
return params;
}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/MockAssertionValidator.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/MockAssertionValidator.java
new file mode 100644
index 0000000..58cd0c0
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/MockAssertionValidator.java
@@ -0,0 +1,82 @@
+/*
+ * 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 org.opensaml.saml.saml2.assertion;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.opensaml.saml.common.assertion.AssertionValidationException;
+import org.opensaml.saml.common.assertion.ValidationContext;
+import org.opensaml.saml.common.assertion.ValidationResult;
+import org.opensaml.saml.saml2.core.Assertion;
+
+import net.shibboleth.utilities.java.support.collection.Pair;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+public class MockAssertionValidator extends SAML20AssertionValidator {
+
+ private Map<Assertion, Object> resultsMap;
+
+ public MockAssertionValidator(Map<Assertion, Object> results) {
+ super(Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), null, null);
+ resultsMap = Constraint.isNotNull(results, "Results map was null");
+ }
+
+ /** {@inheritDoc} */
+ public ValidationResult validate(Assertion assertion, ValidationContext context) throws AssertionValidationException {
+ Object result = resultsMap.get(assertion);
+
+ if (Throwable.class.isInstance(result)) {
+ Throwable throwable = Throwable.class.cast(result);
+
+ if (AssertionValidationException.class.isInstance(throwable)) {
+ throw AssertionValidationException.class.cast(throwable);
+ }
+ if (RuntimeException.class.isInstance(throwable)) {
+ throw RuntimeException.class.cast(throwable);
+ }
+ if (Error.class.isInstance(throwable)) {
+ throw Error.class.cast(throwable);
+ }
+ if (Exception.class.isInstance(throwable)) {
+ throw new AssertionValidationException(Exception.class.cast(throwable));
+ }
+ throw new RuntimeException(throwable);
+ }
+
+ if (ValidationResult.class.isInstance(result)) {
+ ValidationResult vr = ValidationResult.class.cast(result);
+ if (!ValidationResult.VALID.equals(vr)) {
+ context.setValidationFailureMessage("Mock validation was not valid");
+ }
+ return vr;
+ }
+
+ if (Pair.class.isInstance(result)) {
+ Pair<ValidationResult,String> pair = Pair.class.cast(result);
+ if (!ValidationResult.VALID.equals(pair.getFirst())) {
+ context.setValidationFailureMessage(pair.getSecond());
+ }
+ return pair.getFirst();
+ }
+
+ throw new IllegalArgumentException(String.format("Invalid result type supplied in mock results map for Assertion '%s': %s",
+ assertion, result));
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AuthnStatementValidatorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AuthnStatementValidatorTest.java
new file mode 100644
index 0000000..4b37e39
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AuthnStatementValidatorTest.java
@@ -0,0 +1,198 @@
+/*
+ * 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 org.opensaml.saml.saml2.assertion.impl;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Map;
+
+import org.opensaml.saml.common.assertion.AssertionValidationException;
+import org.opensaml.saml.common.assertion.ValidationContext;
+import org.opensaml.saml.common.assertion.ValidationResult;
+import org.opensaml.saml.saml2.assertion.BaseAssertionValidationTest;
+import org.opensaml.saml.saml2.assertion.SAML2AssertionValidationParameters;
+import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.AttributeStatement;
+import org.opensaml.saml.saml2.core.AuthnContext;
+import org.opensaml.saml.saml2.core.AuthnStatement;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class AuthnStatementValidatorTest extends BaseAssertionValidationTest {
+
+ private AuthnStatementValidator validator;
+
+ private AuthnStatement authnStatement;
+
+ @BeforeMethod(dependsOnMethods="setUpBasicAssertion")
+ public void setUp() {
+ validator = new AuthnStatementValidator();
+ authnStatement = buildBasicAuthnStatement();
+ getAssertion().getAuthnStatements().add(authnStatement);
+ }
+
+ @Test
+ public void testValid() throws AssertionValidationException {
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.VALID);
+ }
+
+ @Test
+ void testMaxTimeSinceAuthnExceeded() throws AssertionValidationException {
+ authnStatement.setAuthnInstant(Instant.now().minus(Duration.ofHours(1)));
+
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.INVALID);
+ }
+
+ @Test
+ void testNoAuthnInstant() throws AssertionValidationException {
+ authnStatement.setAuthnInstant(null);
+
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.INVALID);
+ }
+
+ @Test
+ void testNoMaxTimeSinceAuthnParam() throws AssertionValidationException {
+ authnStatement.setAuthnInstant(Instant.now().minus(Duration.ofHours(1)));
+
+ Map<String,Object> staticParams = buildBasicStaticParameters();
+ staticParams.remove(SAML2AssertionValidationParameters.STMT_AUTHN_MAX_TIME);
+ ValidationContext validationContext = new ValidationContext(staticParams);
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.VALID);
+ }
+
+ @Test
+ public void testInvalidAddress() throws AssertionValidationException {
+ authnStatement.getSubjectLocality().setAddress("1.2.3.4");
+
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.INVALID);
+ }
+
+ @Test
+ public void testInvalidAddressWithAddressCheckDisabled() throws AssertionValidationException {
+ authnStatement.getSubjectLocality().setAddress("1.2.3.4");
+
+ Map<String,Object> staticParams = buildBasicStaticParameters();
+ staticParams.put(SAML2AssertionValidationParameters.STMT_AUTHN_CHECK_ADDRESS, Boolean.FALSE);
+ ValidationContext validationContext = new ValidationContext(staticParams);
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.VALID);
+ }
+
+ @Test
+ public void testInvalidAddressParamType() throws AssertionValidationException {
+ Map<String,Object> staticParams = buildBasicStaticParameters();
+ // It should be a Set<String>, not a String
+ staticParams.put(SAML2AssertionValidationParameters.STMT_AUTHN_VALID_ADDRESSES, AUTHN_STATEMENT_ADDRESS);
+
+ ValidationContext validationContext = new ValidationContext(staticParams);
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.INDETERMINATE);
+ }
+
+ @Test
+ public void testMissingAddressParam() throws AssertionValidationException {
+ Map<String,Object> staticParams = buildBasicStaticParameters();
+ staticParams.remove(SAML2AssertionValidationParameters.STMT_AUTHN_VALID_ADDRESSES);
+
+ ValidationContext validationContext = new ValidationContext(staticParams);
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.INDETERMINATE);
+ }
+
+ @Test
+ public void testNoAddress() throws AssertionValidationException {
+ authnStatement.getSubjectLocality().setAddress(null);
+
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.VALID);
+ }
+
+ @Test
+ public void testNoSubjectLocality() throws AssertionValidationException {
+ authnStatement.setSubjectLocality(null);
+
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.VALID);
+ }
+
+ @Test
+ public void testAuthnContextEval() throws AssertionValidationException {
+ // Just testing that if a subclass overrides this method, it gets processed.
+ validator = new AuthnStatementValidator() {
+ /** {@inheritDoc} */
+ protected ValidationResult validateAuthnContext(AuthnStatement statement, Assertion assertion,
+ ValidationContext context) throws AssertionValidationException {
+ return AuthnContext.SMARTCARD_AUTHN_CTX.equals(statement.getAuthnContext().getAuthnContextClassRef().getURI())
+ ? ValidationResult.VALID : ValidationResult.INVALID;
+ }
+ };
+
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.INVALID);
+ }
+
+ @Test
+ public void testValidationThrows() throws AssertionValidationException {
+ validator = new AuthnStatementValidator() {
+ /** {@inheritDoc} */
+ protected ValidationResult validateAuthnInstant(AuthnStatement statement, Assertion assertion,
+ ValidationContext context) throws AssertionValidationException {
+ throw new RuntimeException();
+ }
+ };
+
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(authnStatement, getAssertion(), validationContext),
+ ValidationResult.INDETERMINATE);
+ }
+
+ @Test
+ public void testWrongStatementType() throws AssertionValidationException {
+ ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
+
+ Assert.assertEquals(validator.validate(buildXMLObject(AttributeStatement.DEFAULT_ELEMENT_NAME), getAssertion(), validationContext),
+ ValidationResult.INDETERMINATE);
+ }
+
+
+}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/profile/impl/MockAssertionValidationContextBuilder.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/profile/impl/MockAssertionValidationContextBuilder.java
new file mode 100644
index 0000000..888f470
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/profile/impl/MockAssertionValidationContextBuilder.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 org.opensaml.saml.saml2.profile.impl;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.function.Function;
+
+import org.opensaml.saml.common.assertion.ValidationContext;
+import org.opensaml.saml.saml2.profile.impl.ValidateAssertions.AssertionValidationInput;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ *
+ */
+public class MockAssertionValidationContextBuilder implements Function<AssertionValidationInput, ValidationContext> {
+
+ private Map<String,Object> staticParams;
+
+ public MockAssertionValidationContextBuilder() {
+ staticParams = Collections.emptyMap();
+ }
+
+ public MockAssertionValidationContextBuilder(Map<String,Object> statics) {
+ staticParams = Constraint.isNotNull(statics, "Static params were null");
+ }
+
+ /** {@inheritDoc} */
+ public ValidationContext apply(AssertionValidationInput t) {
+ return new ValidationContext(staticParams);
+ }
+
+}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/profile/impl/ValidateAssertionsTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/profile/impl/ValidateAssertionsTest.java
new file mode 100644
index 0000000..856cee5
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/profile/impl/ValidateAssertionsTest.java
@@ -0,0 +1,326 @@
+/*
+ * 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 org.opensaml.saml.saml2.profile.impl;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.opensaml.core.OpenSAMLInitBaseTestCase;
+import org.opensaml.profile.RequestContextBuilder;
+import org.opensaml.profile.action.ActionTestingSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.common.assertion.AssertionValidationException;
+import org.opensaml.saml.common.assertion.ValidationProcessingData;
+import org.opensaml.saml.common.assertion.ValidationResult;
+import org.opensaml.saml.common.profile.SAMLEventIds;
+import org.opensaml.saml.saml2.assertion.MockAssertionValidator;
+import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.Response;
+import org.opensaml.saml.saml2.profile.SAML2ActionTestingSupport;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Lists;
+
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+public class ValidateAssertionsTest extends OpenSAMLInitBaseTestCase {
+
+ private ValidateAssertions action;
+
+ private ProfileRequestContext prc;
+
+ private Response samlResponse;
+
+ private Map<Assertion,Object> resultsMap;
+
+ private MockHttpServletRequest httpRequest;
+ private MockHttpServletResponse httpResponse;
+
+ @BeforeMethod
+ public void beforeMethod() {
+ httpRequest = new MockHttpServletRequest();
+ httpResponse = new MockHttpServletResponse();
+
+ resultsMap = new HashMap<>();
+
+ action = new ValidateAssertions();
+ action.setHttpServletRequest(httpRequest);
+ action.setHttpServletResponse(httpResponse);
+ action.setValidationContextBuilder(new MockAssertionValidationContextBuilder());
+ action.setAssertionValidator(new MockAssertionValidator(resultsMap));
+
+ samlResponse = SAML2ActionTestingSupport.buildResponse();
+ samlResponse.getAssertions().add(SAML2ActionTestingSupport.buildAssertion());
+ prc = new RequestContextBuilder().setInboundMessage(samlResponse).buildProfileRequestContext();
+
+ }
+
+ @Test
+ public void testValid() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertProceedEvent(prc);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+ }
+
+ @Test
+ public void testInvalid() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.INVALID);
+
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertEvent(prc, SAMLEventIds.ASSERTION_INVALID);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.INVALID);
+ }
+
+ @Test
+ public void testIndeterminate() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.INDETERMINATE);
+
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertEvent(prc, SAMLEventIds.ASSERTION_INVALID);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.INDETERMINATE);
+ }
+
+ @Test
+ public void testInvalidNonFatal() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.INVALID);
+
+ action.setInvalidFatal(false);
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertProceedEvent(prc);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.INVALID);
+ }
+
+ @Test
+ public void testIndeterminateNonFatal() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.INDETERMINATE);
+
+ action.setInvalidFatal(false);
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertProceedEvent(prc);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.INDETERMINATE);
+ }
+
+ @Test
+ public void testMultipleValid() throws ComponentInitializationException {
+ samlResponse.getAssertions().add(SAML2ActionTestingSupport.buildAssertion());
+
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+ resultsMap.put(samlResponse.getAssertions().get(1), ValidationResult.VALID);
+
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertProceedEvent(prc);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+ checkObjectMetadata(samlResponse.getAssertions().get(1), ValidationResult.VALID);
+ }
+
+ @Test
+ public void testMultipleMixed() throws ComponentInitializationException {
+ samlResponse.getAssertions().add(SAML2ActionTestingSupport.buildAssertion());
+
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.INVALID);
+ resultsMap.put(samlResponse.getAssertions().get(1), ValidationResult.VALID);
+
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertEvent(prc, SAMLEventIds.ASSERTION_INVALID);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.INVALID);
+ checkObjectMetadata(samlResponse.getAssertions().get(1), ValidationResult.VALID);
+ }
+
+ @Test
+ public void testMultipleMixedNonFatal() throws ComponentInitializationException {
+ samlResponse.getAssertions().add(SAML2ActionTestingSupport.buildAssertion());
+
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.INVALID);
+ resultsMap.put(samlResponse.getAssertions().get(1), ValidationResult.VALID);
+
+ action.setInvalidFatal(false);
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertProceedEvent(prc);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.INVALID);
+ checkObjectMetadata(samlResponse.getAssertions().get(1), ValidationResult.VALID);
+ }
+
+ @Test
+ public void testValidatorLookup() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+
+ action.setAssertionValidator(null);
+ action.setAssertionValidatorLookup(input -> {return new MockAssertionValidator(resultsMap);});
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertProceedEvent(prc);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+ }
+
+ @Test
+ public void testValidatorLookupFails() throws ComponentInitializationException {
+ action.setAssertionValidator(null);
+ action.setAssertionValidatorLookup(input -> {return null;});
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertEvent(prc, SAMLEventIds.UNABLE_VALIDATE_ASSERTION);
+ }
+
+ @Test
+ public void testCustomAssertionResolution() throws ComponentInitializationException {
+ Assertion assertion1 = SAML2ActionTestingSupport.buildAssertion();
+ resultsMap.put(assertion1, ValidationResult.VALID);
+
+ action.setAssertionResolver(input -> {return Lists.newArrayList(assertion1);});
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertProceedEvent(prc);
+ checkObjectMetadata(assertion1, ValidationResult.VALID);
+ checkObjectMetadataEmpty(samlResponse.getAssertions().get(0));
+ }
+
+ @Test
+ public void testNoAssertions() throws ComponentInitializationException {
+ action.setAssertionResolver(input -> {return Collections.emptyList();});
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertProceedEvent(prc);
+ }
+
+ @Test
+ public void testValidationThrows() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), new AssertionValidationException());
+
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertEvent(prc, SAMLEventIds.UNABLE_VALIDATE_ASSERTION);
+ checkObjectMetadataEmpty(samlResponse.getAssertions().get(0));
+ }
+
+ @Test
+ public void testValidationThrowsUnchecked() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), new RuntimeException());
+
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertEvent(prc, SAMLEventIds.UNABLE_VALIDATE_ASSERTION);
+ checkObjectMetadataEmpty(samlResponse.getAssertions().get(0));
+ }
+
+ @Test
+ public void testValidationThrowsMultiple() throws ComponentInitializationException {
+ samlResponse.getAssertions().add(SAML2ActionTestingSupport.buildAssertion());
+ samlResponse.getAssertions().add(SAML2ActionTestingSupport.buildAssertion());
+
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+ resultsMap.put(samlResponse.getAssertions().get(1), new AssertionValidationException());
+ resultsMap.put(samlResponse.getAssertions().get(2), ValidationResult.VALID);
+
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertEvent(prc, SAMLEventIds.UNABLE_VALIDATE_ASSERTION);
+ checkObjectMetadata(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+ checkObjectMetadataEmpty(samlResponse.getAssertions().get(1));
+ checkObjectMetadataEmpty(samlResponse.getAssertions().get(2));
+ }
+
+ @Test
+ public void testUnableToBuildValidationContext() throws ComponentInitializationException {
+ resultsMap.put(samlResponse.getAssertions().get(0), ValidationResult.VALID);
+
+ action.setValidationContextBuilder(input -> {return null;});
+ action.initialize();
+
+ action.execute(prc);
+ ActionTestingSupport.assertEvent(prc, SAMLEventIds.UNABLE_VALIDATE_ASSERTION);
+ checkObjectMetadataEmpty(samlResponse.getAssertions().get(0));
+ }
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testNoAssertionResolver() throws ComponentInitializationException {
+ action.setAssertionResolver(null);
+
+ action.initialize();
+ }
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testNoValidators() throws ComponentInitializationException {
+ action.setAssertionValidator(null);
+ action.setAssertionValidatorLookup(null);
+
+ action.initialize();
+ }
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testNoHttpRequest() throws ComponentInitializationException {
+ action.setHttpServletRequest(null);
+
+ action.initialize();
+ }
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testNoContextBuilder() throws ComponentInitializationException {
+ action.setValidationContextBuilder(null);
+
+ action.initialize();
+ }
+
+
+
+ // Helpers
+
+ public void checkObjectMetadata(Assertion assertion, ValidationResult result) {
+ List<ValidationProcessingData> dataItems = assertion.getObjectMetadata().get(ValidationProcessingData.class);
+ Assert.assertNotNull(dataItems);
+ Assert.assertEquals(dataItems.size(), 1);
+ ValidationProcessingData data = dataItems.get(0);
+ Assert.assertEquals(data.getResult(), result);
+ Assert.assertNotNull(data.getContext());
+ }
+
+ public void checkObjectMetadataEmpty(Assertion assertion) {
+ Assert.assertTrue(assertion.getObjectMetadata().get(ValidationProcessingData.class).isEmpty());
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list