[java-opensaml] branch master updated: Extend EntityAttributesFilter with pre-validation feature and add test.
Scott Cantor
cantor.2 at osu.edu
Tue May 2 14:12:27 EDT 2017
This is an automated email from the git hooks/post-receive script.
scantor 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=80c3f5aa5db3122286386dd2d070173d580b9ee8
The following commit(s) were added to refs/heads/master by this push:
new 80c3f5a Extend EntityAttributesFilter with pre-validation feature and add test.
80c3f5a is described below
commit 80c3f5aa5db3122286386dd2d070173d580b9ee8
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue May 2 14:12:19 2017 -0400
Extend EntityAttributesFilter with pre-validation feature and add test.
---
.../saml/ext/saml2mdattr/EntityAttributes.java | 4 +
.../ext/saml2mdattr/impl/EntityAttributesImpl.java | 18 ++-
.../filter/impl/EntityAttributesFilter.java | 73 +++++++++-
.../filter/impl/EntityAttributesFilterTest.java | 155 +++++++++++++++++++++
4 files changed, 244 insertions(+), 6 deletions(-)
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdattr/EntityAttributes.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdattr/EntityAttributes.java
index 45e807a..784bce9 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdattr/EntityAttributes.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdattr/EntityAttributes.java
@@ -43,6 +43,10 @@ public interface EntityAttributes extends SAMLObject {
public static final QName TYPE_NAME =
new QName(SAMLConstants.SAML20MDATTR_NS, TYPE_LOCAL_NAME, SAMLConstants.SAML20MDATTR_PREFIX);
+ /* TODO: add a modifiable accessor of the child collection in 4.0
+ public List<? extends SAMLObject> getEntityAttributesChildren();
+ */
+
/**
* Gets the attributes about the entity.
*
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdattr/impl/EntityAttributesImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdattr/impl/EntityAttributesImpl.java
index e6466e5..f8dd630 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdattr/impl/EntityAttributesImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdattr/impl/EntityAttributesImpl.java
@@ -28,12 +28,11 @@ import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.ext.saml2mdattr.EntityAttributes;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute;
-import org.opensaml.saml.saml2.core.Evidentiary;
/** Concrete implementation of {@link EntityAttributes}. */
public class EntityAttributesImpl extends AbstractSAMLObject implements EntityAttributes {
- /** Assertion of the Evidence. */
+ /** Extension data. */
private final IndexedXMLObjectChildrenList<? extends SAMLObject> attributeInfo;
/**
@@ -45,7 +44,7 @@ public class EntityAttributesImpl extends AbstractSAMLObject implements EntityAt
*/
protected EntityAttributesImpl(String namespaceURI, String elementLocalName, String namespacePrefix) {
super(namespaceURI, elementLocalName, namespacePrefix);
- attributeInfo = new IndexedXMLObjectChildrenList<Evidentiary>(this);
+ attributeInfo = new IndexedXMLObjectChildrenList<>(this);
}
/** {@inheritDoc} */
@@ -57,6 +56,19 @@ public class EntityAttributesImpl extends AbstractSAMLObject implements EntityAt
public List<Assertion> getAssertions() {
return (List<Assertion>) attributeInfo.subList(Assertion.DEFAULT_ELEMENT_NAME);
}
+
+ /**
+ * Get the list of {@link Attribute} and {@link Assertion} content.
+ *
+ * TODO: this is implementation only until 4.0 when we can promote this to the API
+ *
+ * @return a modifiable list of the children
+ *
+ * @since 3.4.0
+ */
+ public List<? extends SAMLObject> getEntityAttributesChildren() {
+ return attributeInfo;
+ }
/** {@inheritDoc} */
public List<XMLObject> getOrderedChildren() {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/filter/impl/EntityAttributesFilter.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/filter/impl/EntityAttributesFilter.java
index 41458a2..947a723 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/filter/impl/EntityAttributesFilter.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/filter/impl/EntityAttributesFilter.java
@@ -19,12 +19,16 @@ package org.opensaml.saml.metadata.resolver.filter.impl;
import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
import org.opensaml.core.xml.XMLObject;
@@ -32,8 +36,10 @@ import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.core.xml.io.MarshallingException;
import org.opensaml.core.xml.io.UnmarshallingException;
import org.opensaml.core.xml.util.XMLObjectSupport;
+import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.SAMLObjectBuilder;
import org.opensaml.saml.ext.saml2mdattr.EntityAttributes;
+import org.opensaml.saml.ext.saml2mdattr.impl.EntityAttributesImpl;
import org.opensaml.saml.metadata.resolver.filter.FilterException;
import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
import org.opensaml.saml.saml2.core.Attribute;
@@ -53,10 +59,13 @@ import com.google.common.collect.Multimap;
* A filter that adds {@link EntityAttributes} extension content to entities in order to drive software
* behavior based on them.
*
- * The entities to annotate are identified with a {@link Predicate}, and multiple attributes can be
- * associated with each.
+ * <p>The entities to annotate are identified with a {@link Predicate}, and multiple attributes can be
+ * associated with each.</p>
+ *
+ * <p>As of 3.4.0, another predicate can be set to validate pre-existing extension content to better
+ * protect use cases of this component.</p>
*/
-public class EntityAttributesFilter implements MetadataFilter {
+public class EntityAttributesFilter extends AbstractInitializableComponent implements MetadataFilter {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(EntityAttributesFilter.class);
@@ -64,6 +73,9 @@ public class EntityAttributesFilter implements MetadataFilter {
/** Rules for adding attributes. */
@Nonnull @NonnullElements private Multimap<Predicate<EntityDescriptor>,Attribute> applyMap;
+ /** A condition to apply to pre-existing tags to determine their legitimacy. */
+ @Nullable private Predicate<Attribute> attributeFilter;
+
/** Builder for {@link Extensions}. */
@Nonnull private final SAMLObjectBuilder<Extensions> extBuilder;
@@ -78,6 +90,7 @@ public class EntityAttributesFilter implements MetadataFilter {
entityAttributesBuilder = (SAMLObjectBuilder<EntityAttributes>)
XMLObjectProviderRegistrySupport.getBuilderFactory().<EntityAttributes>getBuilderOrThrow(
EntityAttributes.DEFAULT_ELEMENT_NAME);
+ applyMap = ArrayListMultimap.create();
}
/**
@@ -86,6 +99,7 @@ public class EntityAttributesFilter implements MetadataFilter {
* @param rules rules to apply
*/
public void setRules(@Nonnull @NonnullElements final Map<Predicate<EntityDescriptor>,Collection<Attribute>> rules) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
Constraint.isNotNull(rules, "Rules map cannot be null");
applyMap = ArrayListMultimap.create(rules.size(), 1);
@@ -96,6 +110,22 @@ public class EntityAttributesFilter implements MetadataFilter {
}
}
+ /**
+ * Set a condition to apply to any pre-existing extension attributes, such that failure
+ * causes their removal.
+ *
+ * <p>If not set, then anything is allowed.</p>
+ *
+ * @param condition condition to apply
+ *
+ * @since 3.4.0
+ */
+ public void setAttributeFilter(@Nullable final Predicate<Attribute> condition) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ attributeFilter = condition;
+ }
+
/** {@inheritDoc} */
@Override
@Nullable public XMLObject filter(@Nullable final XMLObject metadata) throws FilterException {
@@ -118,6 +148,10 @@ public class EntityAttributesFilter implements MetadataFilter {
* @param descriptor entity descriptor to filter
*/
protected void filterEntityDescriptor(@Nonnull final EntityDescriptor descriptor) {
+ if (attributeFilter != null) {
+ applyFilter(descriptor);
+ }
+
for (final Map.Entry<Predicate<EntityDescriptor>,Collection<Attribute>> entry : applyMap.asMap().entrySet()) {
if (!entry.getValue().isEmpty() && entry.getKey().apply(descriptor)) {
@@ -167,4 +201,37 @@ public class EntityAttributesFilter implements MetadataFilter {
}
}
+ /**
+ * Apply whitelist to metadata on input.
+ *
+ * @param descriptor input to evaluate
+ */
+ @Nullable private void applyFilter(@Nonnull final EntityDescriptor descriptor) {
+ final Extensions ext = descriptor.getExtensions();
+ if (ext != null) {
+ final Collection<XMLObject> entityAttributesCollection =
+ ext.getUnknownXMLObjects(EntityAttributes.DEFAULT_ELEMENT_NAME);
+ if (!entityAttributesCollection.isEmpty()) {
+ final EntityAttributes entityAttributes =
+ (EntityAttributes) entityAttributesCollection.iterator().next();
+ if (entityAttributes instanceof EntityAttributesImpl) {
+ // TODO: bug in original interface requires that we dive into the impl layer
+ final List<? extends SAMLObject> attributes =
+ ((EntityAttributesImpl) entityAttributes).getEntityAttributesChildren();
+ final Iterator<? extends SAMLObject> iter = attributes.iterator();
+ while (iter.hasNext()) {
+ final SAMLObject attribute = iter.next();
+ if (attribute instanceof Attribute) {
+ if (!attributeFilter.apply((Attribute) attribute)) {
+ log.warn("Filtering pre-existing attribute '{}' from entity '{}'",
+ ((Attribute) attribute).getName(), descriptor.getEntityID());
+ iter.remove();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/filter/impl/EntityAttributesFilterTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/filter/impl/EntityAttributesFilterTest.java
new file mode 100644
index 0000000..077d047
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/filter/impl/EntityAttributesFilterTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.metadata.resolver.filter.impl;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.core.xml.XMLObject;
+import org.opensaml.core.xml.XMLObjectBaseTestCase;
+import org.opensaml.core.xml.XMLObjectBuilder;
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.core.xml.schema.XSString;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.ext.saml2mdattr.EntityAttributes;
+import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver;
+import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolverTest;
+import org.opensaml.saml.saml2.core.Attribute;
+import org.opensaml.saml.saml2.core.AttributeValue;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml.saml2.metadata.Extensions;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+
+public class EntityAttributesFilterTest extends XMLObjectBaseTestCase implements Predicate<EntityDescriptor> {
+
+ private SAMLObjectBuilder<Attribute> tagBuilder;
+
+ private XMLObjectBuilder<XSString> valueBuilder;
+
+ private FilesystemMetadataResolver metadataProvider;
+
+ private File mdFile;
+
+ @BeforeMethod
+ protected void setUp() throws Exception {
+
+ tagBuilder = (SAMLObjectBuilder<Attribute>)
+ XMLObjectProviderRegistrySupport.getBuilderFactory().<Attribute>getBuilderOrThrow(
+ Attribute.DEFAULT_ELEMENT_NAME);
+ valueBuilder = XMLObjectProviderRegistrySupport.getBuilderFactory().<XSString>getBuilderOrThrow(
+ XSString.TYPE_NAME);
+
+ URL mdURL = FilesystemMetadataResolverTest.class
+ .getResource("/org/opensaml/saml/saml2/metadata/InCommon-metadata.xml");
+ mdFile = new File(mdURL.toURI());
+
+ metadataProvider = new FilesystemMetadataResolver(mdFile);
+ metadataProvider.setParserPool(parserPool);
+ }
+
+ @Test
+ public void test() throws ComponentInitializationException, ResolverException {
+
+ final Attribute tag = tagBuilder.buildObject();
+ tag.setName("foo");
+ final XSString value = valueBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
+ value.setValue("bar");
+ tag.getAttributeValues().add(value);
+ final Collection<Attribute> tags = Collections.singletonList(tag);
+
+ final EntityAttributesFilter filter = new EntityAttributesFilter();
+ filter.setRules(Collections.<Predicate<EntityDescriptor>,Collection<Attribute>>singletonMap(this, tags));
+ filter.initialize();
+
+ metadataProvider.setMetadataFilter(filter);
+ metadataProvider.setId("test");
+ metadataProvider.initialize();
+
+ EntityIdCriterion key = new EntityIdCriterion("https://carmenwiki.osu.edu/shibboleth");
+ EntityDescriptor entity = metadataProvider.resolveSingle(new CriteriaSet(key));
+ Assert.assertNotNull(entity);
+ Extensions exts = entity.getExtensions();
+ Assert.assertNotNull(exts);
+ Collection<XMLObject> extElements = exts.getUnknownXMLObjects(EntityAttributes.DEFAULT_ELEMENT_NAME);
+ Assert.assertFalse(extElements.isEmpty());
+ EntityAttributes extTags = (EntityAttributes) extElements.iterator().next();
+ Assert.assertNotNull(extTags);
+ Assert.assertEquals(extTags.getAttributes().size(), 2);
+ Assert.assertEquals(extTags.getAttributes().get(0).getName(), "http://macedir.org/entity-category");
+ Assert.assertEquals(extTags.getAttributes().get(1).getName(), "foo");
+
+ key = new EntityIdCriterion("https://cms.psu.edu/Shibboleth");
+ entity = metadataProvider.resolveSingle(new CriteriaSet(key));
+ Assert.assertNotNull(entity);
+ exts = entity.getExtensions();
+ Assert.assertNull(exts);
+ }
+
+ @Test
+ public void testWithWhitelist() throws ComponentInitializationException, ResolverException {
+
+ final Attribute tag = tagBuilder.buildObject();
+ tag.setName("foo");
+ final XSString value = valueBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
+ value.setValue("bar");
+ tag.getAttributeValues().add(value);
+ final Collection<Attribute> tags = Collections.singletonList(tag);
+
+ final EntityAttributesFilter filter = new EntityAttributesFilter();
+ filter.setRules(Collections.<Predicate<EntityDescriptor>,Collection<Attribute>>singletonMap(this, tags));
+ filter.setAttributeFilter(new Predicate<Attribute>() {
+ public boolean apply(Attribute input) {
+ return "foo".equals(input.getName());
+ }
+ });
+ filter.initialize();
+
+ metadataProvider.setMetadataFilter(filter);
+ metadataProvider.setId("test");
+ metadataProvider.initialize();
+
+ EntityIdCriterion key = new EntityIdCriterion("https://carmenwiki.osu.edu/shibboleth");
+ EntityDescriptor entity = metadataProvider.resolveSingle(new CriteriaSet(key));
+ Assert.assertNotNull(entity);
+ Extensions exts = entity.getExtensions();
+ Assert.assertNotNull(exts);
+ Collection<XMLObject> extElements = exts.getUnknownXMLObjects(EntityAttributes.DEFAULT_ELEMENT_NAME);
+ Assert.assertFalse(extElements.isEmpty());
+ EntityAttributes extTags = (EntityAttributes) extElements.iterator().next();
+ Assert.assertNotNull(extTags);
+ Assert.assertEquals(extTags.getAttributes().size(), 1);
+ Assert.assertEquals(extTags.getAttributes().get(0).getName(), "foo");
+ }
+
+ /** {@inheritDoc} */
+ public boolean apply(final EntityDescriptor input) {
+ return input.getEntityID().equals("https://carmenwiki.osu.edu/shibboleth");
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list