[java-metadata-aggregator] branch master updated: MDA-138 add SAMLStringElementCheckingStage

Ian Young ian at iay.org.uk
Mon May 25 13:39:03 UTC 2020


This is an automated email from the git hooks/post-receive script.

iay pushed a commit to branch master
in repository java-metadata-aggregator.

View the commit online:
http://git.shibboleth.net/view/?p=java-metadata-aggregator.git;a=commit;h=ab2b46038f59d4c8e0b61ad060396e81745fe7ca

The following commit(s) were added to refs/heads/master by this push:
       new  ab2b460   MDA-138 add SAMLStringElementCheckingStage
ab2b460 is described below

commit ab2b46038f59d4c8e0b61ad060396e81745fe7ca
Author: Ian Young <ian at iay.org.uk>
AuthorDate: Mon May 25 14:38:59 2020 +0100

    MDA-138 add SAMLStringElementCheckingStage
    
    https://issues.shibboleth.net/jira/browse/MDA-138
---
 .../dom/saml/SAMLStringElementCheckingStage.java   | 85 ++++++++++++++++++++++
 .../resources/net/shibboleth/metadata/beans.xml    |  3 +
 .../saml/SAMLStringElementCheckingStageTest.java   | 65 +++++++++++++++++
 .../saml/SAMLStringElementCheckingStage-fail.xml   | 49 +++++++++++++
 .../dom/saml/SAMLStringElementCheckingStage-ok.xml | 46 ++++++++++++
 5 files changed, 248 insertions(+)

diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage.java
new file mode 100644
index 0000000..715dd06
--- /dev/null
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage.java
@@ -0,0 +1,85 @@
+/*
+ * 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.metadata.dom.saml;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.metadata.dom.AbstractElementVisitingStage;
+import net.shibboleth.metadata.dom.DOMTraversalContext;
+import net.shibboleth.utilities.java.support.xml.QNameSupport;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * A Stage which checks the text content of the named elements to verify that
+ * they meet the constraints of SAML string values.
+ */
+public class SAMLStringElementCheckingStage extends AbstractElementVisitingStage {
+
+    /** Regular expression matching a string which contains no non-whitespace characters. */
+    private static final Pattern ALL_WHITE_SPACE_PATTERN = Pattern.compile("^[ \\t\\r\\n\\x85\\u2028]*$");
+
+    /**
+     * Returns the {@link Element} representing the EntityDescriptor which is the
+     * closest-containing ancestor of the given element.
+     * 
+     * @param element {@link Element} to locate the ancestor Entity of.
+     * @return ancestor EntityDescriptor {@link Element}, or null.
+     */
+    private Element ancestorEntity(@Nonnull final Element element) {
+        assert element != null;
+        for (Element e = element; e != null; e = (Element) e.getParentNode()) {
+            if (SAMLMetadataSupport.isEntityDescriptor(e)) {
+                return e;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Check that the string value is appropriate.
+     * 
+     * This is done using a regular expression because Java's {@link String#trim} method does not
+     * use XML's definition of white space.
+     * 
+     * @param visited DOM {@link Node} being checked
+     * @return <code>true</code> if the {@link Node}'s value matches
+     */
+    private static boolean match(@Nonnull final Node visited) {
+        assert visited != null;
+        final String textContent = visited.getTextContent();
+        final Matcher matcher = ALL_WHITE_SPACE_PATTERN.matcher(textContent);
+        return matcher.matches();
+    }
+
+    @Override
+    protected void visit(@Nonnull final Element e, @Nonnull final DOMTraversalContext context) {
+        if (match(e)) {
+            final StringBuilder b = new StringBuilder("element ");
+            b.append(QNameSupport.getNodeQName(e));
+            b.append(" must contain at least one non-whitespace character");
+            final Element entity = ancestorEntity(e);
+            addError(context.getItem(), entity, b.toString());
+        }
+    }
+
+}
diff --git a/aggregator-pipeline/src/main/resources/net/shibboleth/metadata/beans.xml b/aggregator-pipeline/src/main/resources/net/shibboleth/metadata/beans.xml
index c2f5afb..8f25643 100644
--- a/aggregator-pipeline/src/main/resources/net/shibboleth/metadata/beans.xml
+++ b/aggregator-pipeline/src/main/resources/net/shibboleth/metadata/beans.xml
@@ -147,6 +147,9 @@
     <bean id="mda.RemoveOrganizationStage" abstract="true" parent="mda.stage_parent"
         class="net.shibboleth.metadata.dom.saml.RemoveOrganizationStage"/>
 
+    <bean id="mda.SAMLStringElementCheckingStage" abstract="true" parent="mda.stage_parent"
+        class="net.shibboleth.metadata.dom.saml.SAMLStringElementCheckingStage"/>
+    
     <bean id="mda.SetCacheDurationStage" abstract="true" parent="mda.stage_parent"
         class="net.shibboleth.metadata.dom.saml.SetCacheDurationStage"/>
 
diff --git a/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStageTest.java b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStageTest.java
new file mode 100644
index 0000000..dfeface
--- /dev/null
+++ b/aggregator-pipeline/src/test/java/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStageTest.java
@@ -0,0 +1,65 @@
+
+package net.shibboleth.metadata.dom.saml;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.w3c.dom.Element;
+
+import net.shibboleth.metadata.ErrorStatus;
+import net.shibboleth.metadata.Item;
+import net.shibboleth.metadata.dom.BaseDOMTest;
+import net.shibboleth.metadata.dom.DOMElementItem;
+
+public class SAMLStringElementCheckingStageTest extends BaseDOMTest {
+
+    /** Constructor sets class under test. */
+    public SAMLStringElementCheckingStageTest() {
+        super(SAMLStringElementCheckingStage.class);
+    }
+    
+    @Test
+    public void testOK() throws Exception {
+        final Item<Element> item = new DOMElementItem(readXMLData("ok.xml"));
+        final List<Item<Element>> items = new ArrayList<>();
+        items.add(item);
+        
+        final SAMLStringElementCheckingStage stage = new SAMLStringElementCheckingStage();
+        stage.setId("test");
+        stage.setElementNames(Set.of(SAMLMetadataSupport.ORGANIZATIONNAME_NAME));
+        stage.initialize();
+        
+        stage.execute(items);
+        
+        final Item<Element> outItem = items.get(0);
+        Assert.assertSame(outItem, item);
+        final List<ErrorStatus> errors = item.getItemMetadata().get(ErrorStatus.class);
+        Assert.assertEquals(errors.size(), 0);
+    }
+    
+    @Test
+    public void testFail() throws Exception {
+        final Item<Element> item = new DOMElementItem(readXMLData("fail.xml"));
+        final List<Item<Element>> items = new ArrayList<>();
+        items.add(item);
+        
+        final SAMLStringElementCheckingStage stage = new SAMLStringElementCheckingStage();
+        stage.setId("test");
+        stage.setElementNames(Set.of(SAMLMetadataSupport.ORGANIZATIONNAME_NAME,
+                SAMLMetadataSupport.ORGANIZATIONDISPLAYNAME_NAME));
+        stage.initialize();
+        
+        stage.execute(items);
+        
+        final Item<Element> outItem = items.get(0);
+        Assert.assertSame(outItem, item);
+        final List<ErrorStatus> errors = item.getItemMetadata().get(ErrorStatus.class);
+        for (final ErrorStatus error : errors) {
+            System.out.println(error.getComponentId() + ": " + error.getStatusMessage());
+        }
+        Assert.assertEquals(errors.size(), 3);
+    }
+}
diff --git a/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage-fail.xml b/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage-fail.xml
new file mode 100644
index 0000000..4ef0c39
--- /dev/null
+++ b/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage-fail.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<md:EntityDescriptor ID="uk123456" entityID="https://idp5.example.org/idp/shibboleth"
+    xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+    xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi"
+    xmlns:shibmd="urn:mace:shibboleth:metadata:1.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <IDPSSODescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+        protocolSupportEnumeration="urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
+        <Extensions>
+            <mdui:UIInfo xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui">
+                <mdui:DisplayName xml:lang="en">Example Organization</mdui:DisplayName>
+            </mdui:UIInfo>
+        </Extensions>
+        <ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding"
+            Location="https://idp5.example.org:8443/idp/profile/SAML1/SOAP/ArtifactResolution"
+            index="1"/>
+        <ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+            Location="https://idp5.example.org:8443/idp/profile/SAML2/SOAP/ArtifactResolution"
+            index="2"/>
+        <NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
+        <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
+        <SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest"
+            Location="https://idp5.example.org/idp/profile/Shibboleth/SSO"/>
+        <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+            Location="https://idp5.example.org/idp/profile/SAML2/POST/SSO"/>
+        <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
+            Location="https://idp5.example.org/idp/profile/SAML2/POST-SimpleSign/SSO"/>
+        <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+            Location="https://idp5.example.org/idp/profile/SAML2/Redirect/SSO"/>
+    </IDPSSODescriptor>
+    <AttributeAuthorityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+        protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
+        <AttributeService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding"
+            Location="https://idp5.example.org:8443/idp/profile/SAML1/SOAP/AttributeQuery"/>
+        <AttributeService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+            Location="https://idp5.example.org:8443/idp/profile/SAML2/SOAP/AttributeQuery"/>
+        <NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
+        <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
+    </AttributeAuthorityDescriptor>
+    <Organization xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
+        <OrganizationName xml:lang="en"></OrganizationName>
+        <OrganizationDisplayName xml:lang="sv">     </OrganizationDisplayName>
+        <!-- space, tab, carriage return, line feed, NEL and LINE SEPARATOR -->
+        <OrganizationDisplayName xml:lang="en">   	   
   
   &#x85;   &#x2028;   </OrganizationDisplayName>
+        <!-- but a single character in there is fine. -->
+        <OrganizationDisplayName xml:lang="en">   	   
 x  
   &#x85;   &#x2028;   </OrganizationDisplayName>
+        <OrganizationURL xml:lang="en">http://www.bth.se</OrganizationURL>
+    </Organization>
+</md:EntityDescriptor>
diff --git a/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage-ok.xml b/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage-ok.xml
new file mode 100644
index 0000000..1b0d9b5
--- /dev/null
+++ b/aggregator-pipeline/src/test/resources/net/shibboleth/metadata/dom/saml/SAMLStringElementCheckingStage-ok.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<md:EntityDescriptor ID="uk123456" entityID="https://idp5.example.org/idp/shibboleth"
+    xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+    xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi"
+    xmlns:shibmd="urn:mace:shibboleth:metadata:1.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <IDPSSODescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+        protocolSupportEnumeration="urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
+        <Extensions>
+            <mdui:UIInfo xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui">
+                <mdui:DisplayName xml:lang="en">Example Organization</mdui:DisplayName>
+            </mdui:UIInfo>
+        </Extensions>
+        <ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding"
+            Location="https://idp5.example.org:8443/idp/profile/SAML1/SOAP/ArtifactResolution"
+            index="1"/>
+        <ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+            Location="https://idp5.example.org:8443/idp/profile/SAML2/SOAP/ArtifactResolution"
+            index="2"/>
+        <NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
+        <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
+        <SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest"
+            Location="https://idp5.example.org/idp/profile/Shibboleth/SSO"/>
+        <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+            Location="https://idp5.example.org/idp/profile/SAML2/POST/SSO"/>
+        <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
+            Location="https://idp5.example.org/idp/profile/SAML2/POST-SimpleSign/SSO"/>
+        <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+            Location="https://idp5.example.org/idp/profile/SAML2/Redirect/SSO"/>
+    </IDPSSODescriptor>
+    <AttributeAuthorityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+        protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
+        <AttributeService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding"
+            Location="https://idp5.example.org:8443/idp/profile/SAML1/SOAP/AttributeQuery"/>
+        <AttributeService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+            Location="https://idp5.example.org:8443/idp/profile/SAML2/SOAP/AttributeQuery"/>
+        <NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
+        <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
+    </AttributeAuthorityDescriptor>
+    <Organization xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
+        <OrganizationName xml:lang="en">STUDENTS</OrganizationName>
+        <OrganizationDisplayName xml:lang="sv">Second Organization</OrganizationDisplayName>
+        <OrganizationDisplayName xml:lang="en">Second Organization</OrganizationDisplayName>
+        <OrganizationURL xml:lang="en">http://www.bth.se</OrganizationURL>
+    </Organization>
+</md:EntityDescriptor>

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list