[java-identity-provider] branch master updated: IDP-1511 - Support referencing of non-inline MetadataFilters

Scott Cantor cantor.2 at osu.edu
Tue Oct 22 11:05:51 EDT 2019


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

scantor pushed a commit to branch master
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=3c9ba87764042eb16fb767c04f70b2c896ce33a5

The following commit(s) were added to refs/heads/master by this push:
       new  3c9ba87   IDP-1511 - Support referencing of non-inline MetadataFilters
3c9ba87 is described below

commit 3c9ba87764042eb16fb767c04f70b2c896ce33a5
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Oct 22 11:05:47 2019 -0400

    IDP-1511 - Support referencing of non-inline MetadataFilters
    
    https://issues.shibboleth.net/jira/browse/IDP-1511
    
    Implementation through a bridging component installed
    with a BeanPostProcessor.
---
 .../system/conf/metadata-providers-system.xml      |  7 +-
 .../main/resources/system/conf/services-system.xml | 10 +--
 ...stEnvironmentApplicationContextInitializer.java |  2 +
 idp-conf/src/test/resources/conf/global.xml        |  6 ++
 ...metadata-providers.xml => metadata-filters.xml} | 41 ++-------
 .../src/test/resources/conf/metadata-providers.xml | 24 ++----
 .../metadata/AbstractMetadataProviderParser.java   | 13 ++-
 .../metadata/filter/impl/ByReferenceParser.java    | 94 +++++++++++++++++++++
 .../impl/ByReferenceFilterBeanPostProcessor.java   | 97 ++++++++++++++++++++++
 .../metadata/impl/MetadataNamespaceHandler.java    |  2 +
 .../NodeProcessingAttachingBeanPostProcessor.java  |  8 +-
 .../impl/ByReferenceMetadataFilterBridge.java      | 89 ++++++++++++++++++++
 .../main/resources/schema/shibboleth-metadata.xsd  | 26 ++++++
 13 files changed, 351 insertions(+), 68 deletions(-)

diff --git a/idp-conf/src/main/resources/system/conf/metadata-providers-system.xml b/idp-conf/src/main/resources/system/conf/metadata-providers-system.xml
index 55775cb..c54996a 100644
--- a/idp-conf/src/main/resources/system/conf/metadata-providers-system.xml
+++ b/idp-conf/src/main/resources/system/conf/metadata-providers-system.xml
@@ -12,7 +12,12 @@
        default-init-method="initialize"
        default-destroy-method="destroy">
 
-    <!-- Beans internal to metadata configuration but not for user manipulation. -->
+    <!-- BeanPostProcessors that auto-install MetadataFilters for internal use. -->
+    
+    <bean class="net.shibboleth.idp.profile.spring.relyingparty.metadata.impl.ByReferenceFilterBeanPostProcessor" />
+    
+    <bean class="net.shibboleth.idp.profile.spring.relyingparty.metadata.impl.NodeProcessingAttachingBeanPostProcessor"
+        c:service-ref="shibboleth.AttributeRegistryService" />
     
     <!-- Signature Validation Criteria  -->
     
diff --git a/idp-conf/src/main/resources/system/conf/services-system.xml b/idp-conf/src/main/resources/system/conf/services-system.xml
index 3950fcb..1cc2546 100644
--- a/idp-conf/src/main/resources/system/conf/services-system.xml
+++ b/idp-conf/src/main/resources/system/conf/services-system.xml
@@ -101,18 +101,12 @@
             p:serviceConfigurations-ref="#{'%{idp.service.metadata.resources:shibboleth.MetadataResolverResources}'.trim()}"
             p:failFast="%{idp.service.metadata.failFast:%{idp.service.failFast:false}}"
             p:reloadCheckDelay="%{idp.service.metadata.checkInterval:PT0S}"
-            p:beanFactoryPostProcessors-ref="shibboleth.PropertySourcesPlaceholderConfigurer">
+            p:beanFactoryPostProcessors-ref="shibboleth.PropertySourcesPlaceholderConfigurer"
+            p:beanPostProcessors-ref="shibboleth.IdentifiableBeanPostProcessor">
         <constructor-arg name="claz" value="org.opensaml.saml.metadata.resolver.MetadataResolver" />
         <constructor-arg name="strategy">
             <bean class="net.shibboleth.idp.profile.spring.relyingparty.metadata.impl.MetadataResolverServiceStrategy" />
         </constructor-arg>
-        <property name="beanPostProcessors">
-            <list>
-                <ref bean="shibboleth.IdentifiableBeanPostProcessor" />
-                <bean class="net.shibboleth.idp.profile.spring.relyingparty.metadata.impl.NodeProcessingAttachingBeanPostProcessor"
-                    c:service-ref="shibboleth.AttributeRegistryService" />
-            </list>
-        </property>
     </bean>
 
     <bean id="shibboleth.ReloadableAccessControlService" class="net.shibboleth.ext.spring.service.ReloadableSpringService"
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/TestEnvironmentApplicationContextInitializer.java b/idp-conf/src/test/java/net/shibboleth/idp/test/TestEnvironmentApplicationContextInitializer.java
index e57637d..44fa18e 100644
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/TestEnvironmentApplicationContextInitializer.java
+++ b/idp-conf/src/test/java/net/shibboleth/idp/test/TestEnvironmentApplicationContextInitializer.java
@@ -51,7 +51,9 @@ public class TestEnvironmentApplicationContextInitializer
         mock.setProperty("idp.storage.htmlLocalStorage", "false");
         mock.setProperty("idp.session.trackSPSessions", "false");
         mock.setProperty("idp.session.secondaryServiceIndex", "false");
+        mock.setProperty("idp.service.metadata.resources", "testbed.MetadataResolverResources");
         applicationContext.getEnvironment().getPropertySources().addFirst(mock);
         log.info("Prepending properties '{}'", mock.getSource());
     }
+    
 }
\ No newline at end of file
diff --git a/idp-conf/src/test/resources/conf/global.xml b/idp-conf/src/test/resources/conf/global.xml
index dcbc143..7b79f7a 100644
--- a/idp-conf/src/test/resources/conf/global.xml
+++ b/idp-conf/src/test/resources/conf/global.xml
@@ -68,4 +68,10 @@
         <constructor-arg value="/metadata/example-sp123-metadata.xml"/>
     </bean>
       
+    <util:list id="testbed.MetadataResolverResources">
+        <value>%{idp.home}/conf/metadata-providers.xml</value>
+        <value>%{idp.home}/conf/metadata-filters.xml</value>
+        <value>%{idp.home}/system/conf/metadata-providers-system.xml</value>
+    </util:list>
+    
 </beans>
diff --git a/idp-conf/src/test/resources/conf/metadata-providers.xml b/idp-conf/src/test/resources/conf/metadata-filters.xml
similarity index 54%
copy from idp-conf/src/test/resources/conf/metadata-providers.xml
copy to idp-conf/src/test/resources/conf/metadata-filters.xml
index 3e687ba..9a16b61 100644
--- a/idp-conf/src/test/resources/conf/metadata-providers.xml
+++ b/idp-conf/src/test/resources/conf/metadata-filters.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<MetadataProvider id="ShibbolethMetadata" xsi:type="ChainingMetadataProvider"
+<MetadataFilter xsi:type="ByReference"
     xmlns="urn:mace:shibboleth:2.0:metadata"
     xmlns:security="urn:mace:shibboleth:2.0:security"
     xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
@@ -19,30 +19,9 @@
                         http://www.w3.org/2009/xmldsig11# http://www.w3.org/TR/2013/REC-xmldsig-core1-20130411/xmldsig11-schema.xsd
                         http://www.w3.org/2001/04/xmlenc# http://www.w3.org/TR/xmlenc-core/xenc-schema.xsd
                         http://www.w3.org/2009/xmlenc11# http://www.w3.org/TR/2013/REC-xmlenc-core1-20130411/xenc-schema-11.xsd">
-                        
-	<!-- ========================================== -->
-	<!-- Metadata Configuration -->
-	<!-- ========================================== -->
 
-	<!-- Example metadata provider. -->
-
-    <MetadataProvider id="URLMD" xsi:type="ResourceBackedMetadataProvider" maxRefreshDelay="PT5M" indexesRef="testbed.MetadataIndexes" resourceRef="exampleMetadata">
-        <MetadataFilter xsi:type="SignatureValidation" requireSignedRoot="false"> <!-- TODO -->
-            <PublicKey>
-                MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxg0TyQAP/tIvOH89EtaX
-                uRRn8SYzTj7W1TbNY4VvBmobjkRmSkki4hH9x4sQpi635wn6WtXTN/FNNmkTK3N/
-                LspmBWxfZS+n+cc7I82E5yvCAPX67QsZgqgglp2W5dvK/FsMMCS6X6SVqzBLMP88
-                NenXKxY+HMxMs0sT0UKYh1cAEqadrHRBO65aDBcm5a0sBVYt9K6pgaOHrp/zSIbh
-                nR5tFFLjBbtFktDpHL3AdGBH3OYidNGKBO3tJ3Ms7LeKXsM0+0Y4P+9fHZINL2X3
-                E2N6GVnKs5PZTg9sP0FtIpAbYm/+zCx7Yj1ET/Er8mDd6tNVGSQsn9s5xUBwGqn1
-                4wIDAQAB
-            </PublicKey>
-        </MetadataFilter>
-        <MetadataFilter xsi:type="SchemaValidation"/>
-        <MetadataFilter xsi:type="EntityRoleWhiteList">
-            <RetainedRole>md:SPSSODescriptor</RetainedRole>
-        </MetadataFilter>
-        
+    <MetadataFilters providerRef="URLMD">
+    
         <MetadataFilter xsi:type="EntityAttributes">
             <saml:Attribute Name="https://sp.example.org/tagname">
                 <saml:AttributeValue>foo</saml:AttributeValue>
@@ -58,16 +37,6 @@
             <Entity>https://sp.example.org</Entity>
         </MetadataFilter>
         
-        <MetadataFilter xsi:type="Algorithm">
-            <md:EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#rsa-oaep">
-                <MGF xmlns="http://www.w3.org/2009/xmlenc11#"
-                    Algorithm="http://www.w3.org/2009/xmlenc11#mgf1sha256" />
-                <DigestMethod xmlns="http://www.w3.org/2000/09/xmldsig#"
-                    Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
-            </md:EncryptionMethod>
-            <Entity>https://sp.example.org</Entity>
-        </MetadataFilter>
-    </MetadataProvider>
+    </MetadataFilters>
 
-    <MetadataProvider id="SP123MD" xsi:type="ResourceBackedMetadataProvider" maxRefreshDelay="PT5M" indexesRef="testbed.MetadataIndexes" resourceRef="exampleMetadata-sp123"/>
-</MetadataProvider>
+</MetadataFilter>
diff --git a/idp-conf/src/test/resources/conf/metadata-providers.xml b/idp-conf/src/test/resources/conf/metadata-providers.xml
index 3e687ba..2df93e0 100644
--- a/idp-conf/src/test/resources/conf/metadata-providers.xml
+++ b/idp-conf/src/test/resources/conf/metadata-providers.xml
@@ -43,21 +43,6 @@
             <RetainedRole>md:SPSSODescriptor</RetainedRole>
         </MetadataFilter>
         
-        <MetadataFilter xsi:type="EntityAttributes">
-            <saml:Attribute Name="https://sp.example.org/tagname">
-                <saml:AttributeValue>foo</saml:AttributeValue>
-            </saml:Attribute>
-            <saml:Attribute Name="https://sp.example.org/tagname2">
-                <saml:AttributeValue>foo</saml:AttributeValue>
-                <saml:AttributeValue>bar</saml:AttributeValue>
-            </saml:Attribute>
-            <saml:Attribute Name="http://shibboleth.net/ns/profiles/saml1/sso/browser/includeAttributeStatement"
-                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
-                <saml:AttributeValue>1</saml:AttributeValue>
-            </saml:Attribute>
-            <Entity>https://sp.example.org</Entity>
-        </MetadataFilter>
-        
         <MetadataFilter xsi:type="Algorithm">
             <md:EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#rsa-oaep">
                 <MGF xmlns="http://www.w3.org/2009/xmlenc11#"
@@ -70,4 +55,13 @@
     </MetadataProvider>
 
     <MetadataProvider id="SP123MD" xsi:type="ResourceBackedMetadataProvider" maxRefreshDelay="PT5M" indexesRef="testbed.MetadataIndexes" resourceRef="exampleMetadata-sp123"/>
+
+    <!--
+    <MetadataProvider id="ICMDQ" xsi:type="DynamicHTTPMetadataProvider"
+            minCacheDuration="PT5M" maxCacheDuration="PT24H" maxIdleEntityData="PT1H">
+        <MetadataFilter xsi:type="RequiredValidUntil" maxValidityInterval="P14D" />
+        <MetadataQueryProtocol>https://mdq.incommon.org/</MetadataQueryProtocol>
+    </MetadataProvider>
+    -->
+
 </MetadataProvider>
diff --git a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/AbstractMetadataProviderParser.java b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/AbstractMetadataProviderParser.java
index f93eff9..8801368 100644
--- a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/AbstractMetadataProviderParser.java
+++ b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/AbstractMetadataProviderParser.java
@@ -187,11 +187,10 @@ public abstract class AbstractMetadataProviderParser extends AbstractSingleBeanD
 
         processPredicateOptions(element, parserContext, builder);
 
-        if (!isChaining(element)) {
-            final List<Element> filters =
-                    ElementSupport.getChildElements(element, METADATA_FILTER_ELEMENT_NAME);
-    
-            if (null != filters) {
+        final List<Element> filters =
+                ElementSupport.getChildElements(element, METADATA_FILTER_ELEMENT_NAME);
+        if (null != filters && !filters.isEmpty()) {
+            if (!isChaining(element)) {
                 if (filters.size() == 1) {
                     // Install directly.
                     builder.addPropertyValue("metadataFilter",
@@ -204,9 +203,9 @@ public abstract class AbstractMetadataProviderParser extends AbstractSingleBeanD
                             chainBuilder));
                     builder.addPropertyValue("metadataFilter", chainBuilder.getBeanDefinition());
                 }
+            } else {
+                log.warn("MetadataFilter is not valid for {}", CHAINING_PROVIDER_ELEMENT_NAME.getLocalPart());
             }
-        } else {
-            log.warn("MetadataFilter is not valid for {}", CHAINING_PROVIDER_ELEMENT_NAME.getLocalPart());
         }
     }
 
diff --git a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/filter/impl/ByReferenceParser.java b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/filter/impl/ByReferenceParser.java
new file mode 100644
index 0000000..b863b20
--- /dev/null
+++ b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/filter/impl/ByReferenceParser.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.profile.spring.relyingparty.metadata.filter.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.xml.namespace.QName;
+
+import net.shibboleth.ext.spring.util.SpringSupport;
+import net.shibboleth.idp.profile.spring.relyingparty.metadata.AbstractMetadataProviderParser;
+import net.shibboleth.utilities.java.support.xml.ElementSupport;
+
+import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain;
+import org.opensaml.saml.metadata.resolver.filter.impl.ByReferenceMetadataFilter;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedList;
+import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.w3c.dom.Element;
+
+/**
+ * Parser for a <ByReference> filter.
+ */
+public class ByReferenceParser extends AbstractSingleBeanDefinitionParser {
+
+    /** Element name. */
+    @Nonnull public static final QName TYPE_NAME =
+            new QName(AbstractMetadataProviderParser.METADATA_NAMESPACE, "ByReference");
+
+    /** {@inheritDoc} */
+    @Override protected Class<?> getBeanClass(final Element element) {
+        return ByReferenceMetadataFilter.class;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void doParse(final Element element, final ParserContext parserContext,
+            final BeanDefinitionBuilder builder) {
+        builder.setLazyInit(false);
+
+        final List<Element> children = ElementSupport.getChildElements(element,
+                new QName(AbstractMetadataProviderParser.METADATA_NAMESPACE, "MetadataFilters"));
+
+        if (null != children && !children.isEmpty()) {
+            
+            final ManagedMap<Object,BeanDefinition> mappings = new ManagedMap<>();
+            
+            for (final Element child : children) {
+                final List<Element> filters = ElementSupport.getChildElements(child,
+                        new QName(AbstractMetadataProviderParser.METADATA_NAMESPACE, "MetadataFilter"));
+                if (filters != null && !filters.isEmpty()) {
+                    final String providerRef = child.getAttributeNS(null, "providerRef");
+                    final ManagedList<BeanDefinition> filterBeans =
+                            SpringSupport.parseCustomElements(filters, parserContext, builder);
+                    if (filterBeans != null) {
+                        if (filterBeans.size() == 1) {
+                            mappings.put(providerRef, filterBeans.get(0));
+                        } else {
+                            final BeanDefinitionBuilder chain =
+                                    BeanDefinitionBuilder.genericBeanDefinition(MetadataFilterChain.class);
+                            chain.addPropertyValue("filters", filterBeans);
+                            mappings.put(providerRef, chain.getBeanDefinition());
+                        }
+                    }
+                }
+            }
+            
+            builder.addPropertyValue("filterMappings", mappings);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override protected boolean shouldGenerateId() {
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/ByReferenceFilterBeanPostProcessor.java b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/ByReferenceFilterBeanPostProcessor.java
new file mode 100644
index 0000000..f2e6aa2
--- /dev/null
+++ b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/ByReferenceFilterBeanPostProcessor.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.profile.spring.relyingparty.metadata.impl;
+
+import java.util.Arrays;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver;
+import org.opensaml.saml.metadata.resolver.MetadataResolver;
+import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
+import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.Ordered;
+
+import net.shibboleth.idp.saml.metadata.impl.ByReferenceMetadataFilterBridge;
+
+/**
+ * A {@link BeanPostProcessor} for {@link MetadataResolver} beans that ensures a {@link ByReferenceMetadataFilterBridge}
+ * is attached.
+ */
+public class ByReferenceFilterBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware, Ordered {
+
+    /** Spring context. */
+    @Nullable private ApplicationContext applicationContext;
+
+    /** {@inheritDoc} */
+    public int getOrder() {
+        return HIGHEST_PRECEDENCE;
+    }
+
+    /** {@inheritDoc} */
+    public void setApplicationContext(@Nullable final ApplicationContext context) throws BeansException {
+        applicationContext = context;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object postProcessBeforeInitialization(final Object bean, final String beanName) {
+        if (!(bean instanceof MetadataResolver) || bean instanceof ChainingMetadataResolver) {
+            // Do not attach to beans which just include other ones.
+            return bean;
+        }
+
+        final MetadataResolver resolver = (MetadataResolver) bean;
+
+        boolean filterAttached = false;
+
+        final MetadataFilter filter = resolver.getMetadataFilter();
+        if (filter instanceof ByReferenceMetadataFilterBridge) {
+            filterAttached = true;
+        } else if (filter instanceof MetadataFilterChain) {
+            filterAttached = ((MetadataFilterChain) filter).getFilters().stream().anyMatch(
+                    f -> f instanceof ByReferenceMetadataFilterBridge);
+        }
+
+        if (!filterAttached) {
+            final ByReferenceMetadataFilterBridge filterToAttach = new ByReferenceMetadataFilterBridge();
+            filterToAttach.setApplicationContext(applicationContext);
+
+            if (filter == null) {
+                resolver.setMetadataFilter(filterToAttach);
+            } else if (filter instanceof MetadataFilterChain) {
+                ((MetadataFilterChain) filter).getFilters().add(filterToAttach);
+            } else {
+                final MetadataFilterChain chain = new MetadataFilterChain();
+                chain.setFilters(Arrays.asList(filter, filterToAttach));
+                resolver.setMetadataFilter(chain);
+            }
+        }
+
+        return resolver;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object postProcessAfterInitialization(final Object bean, final String beanName) {
+        return bean;
+    }
+
+}
\ No newline at end of file
diff --git a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/MetadataNamespaceHandler.java b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/MetadataNamespaceHandler.java
index 00cefbe..09ce2f1 100644
--- a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/MetadataNamespaceHandler.java
+++ b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/MetadataNamespaceHandler.java
@@ -22,6 +22,7 @@ import javax.xml.namespace.QName;
 import net.shibboleth.ext.spring.util.BaseSpringNamespaceHandler;
 import net.shibboleth.idp.profile.spring.relyingparty.metadata.AbstractMetadataProviderParser;
 import net.shibboleth.idp.profile.spring.relyingparty.metadata.filter.impl.AlgorithmFilterParser;
+import net.shibboleth.idp.profile.spring.relyingparty.metadata.filter.impl.ByReferenceParser;
 import net.shibboleth.idp.profile.spring.relyingparty.metadata.filter.impl.EntitiesDescriptorNameParser;
 import net.shibboleth.idp.profile.spring.relyingparty.metadata.filter.impl.EntityAttributesFilterParser;
 import net.shibboleth.idp.profile.spring.relyingparty.metadata.filter.impl.EntityRoleFilterParser;
@@ -71,6 +72,7 @@ public class MetadataNamespaceHandler extends BaseSpringNamespaceHandler {
         registerBeanDefinitionParser(SchemaValidationParser.TYPE_NAME, new SchemaValidationParser());
         registerBeanDefinitionParser(SignatureValidationParser.TYPE_NAME, new SignatureValidationParser());
         registerBeanDefinitionParser(NodeProcessingParser.TYPE_NAME, new NodeProcessingParser());
+        registerBeanDefinitionParser(ByReferenceParser.TYPE_NAME, new ByReferenceParser());
 
         // Node Processors
         registerBeanDefinitionParser(EntitiesDescriptorNameParser.TYPE_NAME, new EntitiesDescriptorNameParser());
diff --git a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/NodeProcessingAttachingBeanPostProcessor.java b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/NodeProcessingAttachingBeanPostProcessor.java
index 9cbf430..833318c 100644
--- a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/NodeProcessingAttachingBeanPostProcessor.java
+++ b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/NodeProcessingAttachingBeanPostProcessor.java
@@ -32,6 +32,7 @@ import org.opensaml.saml.metadata.resolver.filter.impl.EntitiesDescriptorNamePro
 import org.opensaml.saml.metadata.resolver.filter.impl.NodeProcessingMetadataFilter;
 import org.springframework.beans.factory.BeanCreationException;
 import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.core.Ordered;
 
 import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
 import net.shibboleth.idp.saml.metadata.impl.AttributeMappingNodeProcessor;
@@ -51,7 +52,7 @@ import net.shibboleth.utilities.java.support.service.ReloadableService;
  * depend on group information.
  * </p>
  */
-public class NodeProcessingAttachingBeanPostProcessor implements BeanPostProcessor {
+public class NodeProcessingAttachingBeanPostProcessor implements BeanPostProcessor, Ordered {
 
     /** The registry of decoding rules. */
     @Nullable private final ReloadableService<AttributeTranscoderRegistry> transcoderRegistry;
@@ -66,6 +67,11 @@ public class NodeProcessingAttachingBeanPostProcessor implements BeanPostProcess
         transcoderRegistry = service;
     }
 
+    /** {@inheritDoc} */
+    public int getOrder() {
+        return LOWEST_PRECEDENCE;
+    }
+    
     // Checkstyle: CyclomaticComplexity OFF
     /** {@inheritDoc} */
     @Override public Object postProcessBeforeInitialization(final Object bean, final String beanName) {
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/metadata/impl/ByReferenceMetadataFilterBridge.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/metadata/impl/ByReferenceMetadataFilterBridge.java
new file mode 100644
index 0000000..8f0034d
--- /dev/null
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/metadata/impl/ByReferenceMetadataFilterBridge.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.saml.metadata.impl;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.XMLObject;
+import org.opensaml.saml.metadata.resolver.filter.FilterException;
+import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
+import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain;
+import org.opensaml.saml.metadata.resolver.filter.MetadataFilterContext;
+import org.opensaml.saml.metadata.resolver.filter.impl.ByReferenceMetadataFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * This is a bridge filter that uses Spring to locate extant {@link ByReferenceMetadataFilter}
+ * objects to run.
+ */
+public class ByReferenceMetadataFilterBridge implements MetadataFilter {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ByReferenceMetadataFilterBridge.class);
+
+    /** Application context. */
+    @Nullable private ApplicationContext applicationContext;
+    
+    /** Chain to wrap the beans obtained from the context. */
+    @Nullable private MetadataFilterChain filterChain;
+    
+    /**
+     * Set the containing {@link ApplicationContext}.
+     * 
+     * @param context the context
+     */
+    public void setApplicationContext(@Nullable final ApplicationContext context) {
+        applicationContext = context;
+    }
+    
+    /** {@inheritDoc} */
+    public XMLObject filter(@Nullable final XMLObject metadata, @Nonnull final MetadataFilterContext context)
+            throws FilterException {
+
+        MetadataFilterChain chain = null;
+        
+        synchronized(this) {
+            if (filterChain != null) {
+                chain = filterChain;
+            } else if (applicationContext != null) {
+                try {
+                    final Map<String,ByReferenceMetadataFilter> beans =
+                            applicationContext.getBeansOfType(ByReferenceMetadataFilter.class);
+                    log.debug("Bridging to {} ByReference filters in Spring context", beans.size());
+                    filterChain = new MetadataFilterChain();
+                    filterChain.setFilters(List.copyOf(beans.values()));
+                    chain = filterChain;
+                } catch (final BeansException e) {
+                    throw new FilterException(e);
+                }
+            } else {
+                throw new FilterException("ApplicationContext is not set");
+            }
+        }
+        
+        return chain != null ? chain.filter(metadata, context) : metadata;
+    }
+
+}
\ No newline at end of file
diff --git a/idp-schema/src/main/resources/schema/shibboleth-metadata.xsd b/idp-schema/src/main/resources/schema/shibboleth-metadata.xsd
index 7e47a90..082fc59 100644
--- a/idp-schema/src/main/resources/schema/shibboleth-metadata.xsd
+++ b/idp-schema/src/main/resources/schema/shibboleth-metadata.xsd
@@ -1254,6 +1254,32 @@
         </complexContent>
     </complexType>
 
+    <complexType name="ByReference">
+        <annotation>
+            <documentation>
+                A metadata filter that associates filters declared "out of band" with specific
+                MetadataProvider instances.
+            </documentation>
+        </annotation>
+        <complexContent>
+            <extension base="shibmd:MetadataFilterType">
+                <sequence>
+                    <element name="MetadataFilters" minOccurs="0" maxOccurs="unbounded">
+                        <annotation>
+                            <documentation>A set of filters applied to a specific provider by name.</documentation>
+                        </annotation>
+                        <complexType>
+                            <sequence>
+                                <element ref="shibmd:MetadataFilter" minOccurs="0" maxOccurs="unbounded" />
+                            </sequence>
+                            <attribute name="providerRef" type="shibmd:string" use="required" />
+                        </complexType>
+                    </element>
+                </sequence>
+            </extension>
+        </complexContent>
+    </complexType>
+
     <complexType name="MetadataFilterType" abstract="true"/>
     
     <element name="MetadataNodeProcessor" type="shibmd:MetadataNodeProcessorType">

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


More information about the commits mailing list