[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