[java-shib-metadata] branch main updated: OSJ-439 - Add options for removal to Algorithm metadata filter

Codeberg noreply at shibboleth.net
Wed Jan 21 18:17:04 UTC 2026


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

codeberg pushed a commit to branch main
in repository java-shib-metadata.

View the commit online:
https://codeberg.org/Shibboleth/java-shib-metadata/commit/8b7d844c0cd75a3af804e81ed615df01543393f3

The following commit(s) were added to refs/heads/main by this push:
     new 8b7d844c OSJ-439 - Add options for removal to Algorithm metadata filter
8b7d844c is described below

commit 8b7d844c0cd75a3af804e81ed615df01543393f3
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Jan 21 13:16:52 2026 -0500

    OSJ-439 - Add options for removal to Algorithm metadata filter
    
    https://shibboleth.atlassian.net/browse/OSJ-439
    
    Add removal support to schema and Spring parser.
    Add unit test.
---
 .../metadata/filter/AlgorithmFilterParser.java     |  20 +++-
 .../main/resources/schema/shibboleth-metadata.xsd  |  21 ++++
 .../metadata/filter/AlgorithmFilterParserTest.java | 111 +++++++++++++--------
 .../metadata/filter/algorithmRemovalOnly.xml       |  83 +++++++++++++++
 4 files changed, 195 insertions(+), 40 deletions(-)

diff --git a/shib-metadata-spring/src/main/java/net/shibboleth/spring/metadata/filter/AlgorithmFilterParser.java b/shib-metadata-spring/src/main/java/net/shibboleth/spring/metadata/filter/AlgorithmFilterParser.java
index 76d62d06..82bb8990 100644
--- a/shib-metadata-spring/src/main/java/net/shibboleth/spring/metadata/filter/AlgorithmFilterParser.java
+++ b/shib-metadata-spring/src/main/java/net/shibboleth/spring/metadata/filter/AlgorithmFilterParser.java
@@ -42,6 +42,7 @@ import org.w3c.dom.Element;
 
 import net.shibboleth.shared.logic.ScriptedPredicate;
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.spring.util.SpringSupport;
 import net.shibboleth.shared.xml.ElementSupport;
 import net.shibboleth.spring.ScriptTypeBeanParser;
 import net.shibboleth.spring.metadata.AbstractMetadataProviderParser;
@@ -70,8 +71,25 @@ public class AlgorithmFilterParser extends AbstractMetadataFilterParser {
     /** {@inheritDoc} */
     @Override protected void doParse(@Nonnull final Element element, @Nonnull final ParserContext parserContext,
             @Nonnull final BeanDefinitionBuilder builder) {
-
         super.doParse(element, parserContext, builder);
+
+        if (element.hasAttributeNS(null, "removeExistingDigestMethods")) {
+            builder.addPropertyValue("removeExistingDigestMethods", 
+                    SpringSupport.getStringValueAsBoolean(element.getAttributeNS(null,
+                            "removeExistingDigestMethods")));
+        }
+
+        if (element.hasAttributeNS(null, "removeExistingSigningMethods")) {
+            builder.addPropertyValue("removeExistingSigningMethods", 
+                    SpringSupport.getStringValueAsBoolean(element.getAttributeNS(null,
+                            "removeExistingSigningMethods")));
+        }
+
+        if (element.hasAttributeNS(null, "removeExistingEncryptionMethods")) {
+            builder.addPropertyValue("removeExistingEncryptionMethods", 
+                    SpringSupport.getStringValueAsBoolean(element.getAttributeNS(null,
+                            "removeExistingEncryptionMethods")));
+        }
         
         final Unmarshaller digestUnmarshaller = XMLObjectSupport.getUnmarshaller(DigestMethod.DEFAULT_ELEMENT_NAME);
         final Unmarshaller signingUnmarshaller =XMLObjectSupport.getUnmarshaller(SigningMethod.DEFAULT_ELEMENT_NAME);
diff --git a/shib-metadata-spring/src/main/resources/schema/shibboleth-metadata.xsd b/shib-metadata-spring/src/main/resources/schema/shibboleth-metadata.xsd
index cbee4b70..5bb023c5 100644
--- a/shib-metadata-spring/src/main/resources/schema/shibboleth-metadata.xsd
+++ b/shib-metadata-spring/src/main/resources/schema/shibboleth-metadata.xsd
@@ -1399,6 +1399,27 @@
                         </element>
                     </choice>
                 </sequence>
+                <attribute name="removeExistingDigestMethods" type="boolean">
+                    <annotation>
+                        <documentation>
+                            Whether to remove any existing DigestMethods when adding new ones (default is false).
+                        </documentation>
+                    </annotation>
+                </attribute>
+                <attribute name="removeExistingSigningMethods" type="boolean">
+                    <annotation>
+                        <documentation>
+                            Whether to remove any existing SigningMethods when adding new ones (default is false).
+                        </documentation>
+                    </annotation>
+                </attribute>
+                <attribute name="removeExistingEncryptionMethods" type="boolean">
+                    <annotation>
+                        <documentation>
+                            Whether to remove any existing EncryptionMethods when adding new ones (default is false).
+                        </documentation>
+                    </annotation>
+                </attribute>
             </extension>
         </complexContent>
     </complexType>
diff --git a/shib-metadata-spring/src/test/java/net/shibboleth/spring/metadata/filter/AlgorithmFilterParserTest.java b/shib-metadata-spring/src/test/java/net/shibboleth/spring/metadata/filter/AlgorithmFilterParserTest.java
index 04043d7c..b3f3f0a6 100644
--- a/shib-metadata-spring/src/test/java/net/shibboleth/spring/metadata/filter/AlgorithmFilterParserTest.java
+++ b/shib-metadata-spring/src/test/java/net/shibboleth/spring/metadata/filter/AlgorithmFilterParserTest.java
@@ -46,25 +46,30 @@ public class AlgorithmFilterParserTest extends AbstractMetadataParserTest {
     
     @Test
     public void test() throws ResolverException, IOException {
-        doTest("filter/algorithm.xml");
+        doTest(false, "filter/algorithm.xml");
     }
 
+    @Test
+    public void testRemovalOnly() throws ResolverException, IOException {
+        doTest(true, "filter/algorithmRemovalOnly.xml");
+    }
+    
     @Test
     public void testRegex() throws ResolverException, IOException {
-        doTest("filter/algorithmRegex.xml");
+        doTest(false, "filter/algorithmRegex.xml");
     }
 
     @Test
     public void testFilterScript() throws ResolverException, IOException {
-        doTest("filter/algorithmWithScript.xml");
+        doTest(false, "filter/algorithmWithScript.xml");
     }
 
     @Test
     public void testFilterScriptResource() throws ResolverException, IOException {
-        doTest("filter/algorithmWithScriptResource.xml");
+        doTest(false, "filter/algorithmWithScriptResource.xml");
     }
 
-    private void doTest(final String... files) throws ResolverException, IOException {
+    private void doTest(boolean removal, final String... files) throws ResolverException, IOException {
 
         final MetadataResolver resolver = getBean(MetadataResolver.class, files);
 
@@ -73,12 +78,12 @@ public class AlgorithmFilterParserTest extends AbstractMetadataParserTest {
         
         EntityIdCriterion crit = new EntityIdCriterion("https://sp.example.org/sp/shibboleth");
         EntityDescriptor entity = resolver.resolveSingle(new CriteriaSet(crit));
-        validate(entity);
+        validate(entity, removal);
 
         crit = new EntityIdCriterion("https://sp4.example.org/sp/shibboleth");
         entity = resolver.resolveSingle(new CriteriaSet(crit));
         if (entity != null) {
-            validate(entity);
+            validate(entity, removal);
         }
 
         crit = new EntityIdCriterion("https://sp2.example.org/sp/shibboleth");
@@ -86,45 +91,73 @@ public class AlgorithmFilterParserTest extends AbstractMetadataParserTest {
         Assert.assertNotNull(entity);
         assert entity != null;
         final Extensions exts = entity.getExtensions();
-        if (exts != null) {
-            Assert.assertTrue(exts.getUnknownXMLObjects(DigestMethod.DEFAULT_ELEMENT_NAME).isEmpty());
-            Assert.assertTrue(exts.getUnknownXMLObjects(SigningMethod.DEFAULT_ELEMENT_NAME).isEmpty());
+        // This test looks backwards because normally they're not added but when testing
+        // removal they're left in place.
+        if (removal) {
+            assert exts != null;
+            Assert.assertEquals(exts.getUnknownXMLObjects(DigestMethod.DEFAULT_ELEMENT_NAME).size(), 2);
+            Assert.assertEquals(exts.getUnknownXMLObjects(SigningMethod.DEFAULT_ELEMENT_NAME).size(), 2);
+        } else {
+            if (exts != null) {
+                Assert.assertTrue(exts.getUnknownXMLObjects(DigestMethod.DEFAULT_ELEMENT_NAME).isEmpty());
+                Assert.assertTrue(exts.getUnknownXMLObjects(SigningMethod.DEFAULT_ELEMENT_NAME).isEmpty());
+            }
         }
     }
     
-    private void validate(final EntityDescriptor entity) {
-        final Extensions exts = entity.getExtensions();
-        assert exts != null;
-        
-        List<XMLObject> extElements = exts.getUnknownXMLObjects(DigestMethod.DEFAULT_ELEMENT_NAME);
-        assertEquals(extElements.size(), 2);
+    private void validate(final EntityDescriptor entity, boolean removal) {
+        Extensions exts = entity.getExtensions();
         
-        Iterator<XMLObject> digests = extElements.iterator();
-        assertEquals(((DigestMethod) digests.next()).getAlgorithm(), SignatureConstants.ALGO_ID_DIGEST_SHA256);
-        assertEquals(((DigestMethod) digests.next()).getAlgorithm(), SignatureConstants.ALGO_ID_DIGEST_SHA512);
-
-        extElements = exts.getUnknownXMLObjects(SigningMethod.DEFAULT_ELEMENT_NAME);
-        assertEquals(extElements.size(), 2);
+        if (removal ) {
+            if (exts != null) {
+                Assert.assertTrue(exts.getUnknownXMLObjects(DigestMethod.DEFAULT_ELEMENT_NAME).isEmpty());
+                Assert.assertTrue(exts.getUnknownXMLObjects(SigningMethod.DEFAULT_ELEMENT_NAME).isEmpty());
+            }
+        } else {
+            assert exts != null;
+            List<XMLObject> extElements = exts.getUnknownXMLObjects(DigestMethod.DEFAULT_ELEMENT_NAME);
+            assertEquals(extElements.size(), 2);
+            
+            Iterator<XMLObject> digests = extElements.iterator();
+            assertEquals(((DigestMethod) digests.next()).getAlgorithm(), SignatureConstants.ALGO_ID_DIGEST_SHA256);
+            assertEquals(((DigestMethod) digests.next()).getAlgorithm(), SignatureConstants.ALGO_ID_DIGEST_SHA512);
+    
+            extElements = exts.getUnknownXMLObjects(SigningMethod.DEFAULT_ELEMENT_NAME);
+            assertEquals(extElements.size(), 2);
+            
+            Iterator<XMLObject> signings = extElements.iterator();
+            assertEquals(((SigningMethod) signings.next()).getAlgorithm(), SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
+            assertEquals(((SigningMethod) signings.next()).getAlgorithm(), SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512);
+        }
         
-        Iterator<XMLObject> signings = extElements.iterator();
-        assertEquals(((SigningMethod) signings.next()).getAlgorithm(), SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
-        assertEquals(((SigningMethod) signings.next()).getAlgorithm(), SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512);
-
         for (final RoleDescriptor role : entity.getRoleDescriptors()) {
+            
+            if (removal) {
+                exts = role.getExtensions();
+                if (exts != null) {
+                    Assert.assertTrue(exts.getUnknownXMLObjects(DigestMethod.DEFAULT_ELEMENT_NAME).isEmpty());
+                    Assert.assertTrue(exts.getUnknownXMLObjects(SigningMethod.DEFAULT_ELEMENT_NAME).isEmpty());
+                }
+            }
+            
             for (final KeyDescriptor key : role.getKeyDescriptors()) {
-                final List<EncryptionMethod> methods = key.getEncryptionMethods();
-                assertEquals(methods.size(), 1);
-                assertEquals(methods.get(0).getAlgorithm(), EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP11);
-                
-                final List<XMLObject> encDigests = methods.get(0).getUnknownXMLObjects(
-                        org.opensaml.xmlsec.signature.DigestMethod.DEFAULT_ELEMENT_NAME);
-                assertEquals(encDigests.size(), 1);
-                assertEquals(((org.opensaml.xmlsec.signature.DigestMethod) encDigests.get(0)).getAlgorithm(),
-                        SignatureConstants.ALGO_ID_DIGEST_SHA256);
-
-                final List<XMLObject> mgfs = methods.get(0).getUnknownXMLObjects(MGF.DEFAULT_ELEMENT_NAME);
-                assertEquals(mgfs.size(), 1);
-                assertEquals(((MGF) mgfs.get(0)).getAlgorithm(), EncryptionConstants.ALGO_ID_MGF1_SHA256);
+                if (removal) {
+                    Assert.assertTrue(key.getEncryptionMethods().isEmpty());
+                } else {
+                    final List<EncryptionMethod> methods = key.getEncryptionMethods();
+                    assertEquals(methods.size(), 1);
+                    assertEquals(methods.get(0).getAlgorithm(), EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP11);
+                    
+                    final List<XMLObject> encDigests = methods.get(0).getUnknownXMLObjects(
+                            org.opensaml.xmlsec.signature.DigestMethod.DEFAULT_ELEMENT_NAME);
+                    assertEquals(encDigests.size(), 1);
+                    assertEquals(((org.opensaml.xmlsec.signature.DigestMethod) encDigests.get(0)).getAlgorithm(),
+                            SignatureConstants.ALGO_ID_DIGEST_SHA256);
+
+                    final List<XMLObject> mgfs = methods.get(0).getUnknownXMLObjects(MGF.DEFAULT_ELEMENT_NAME);
+                    assertEquals(mgfs.size(), 1);
+                    assertEquals(((MGF) mgfs.get(0)).getAlgorithm(), EncryptionConstants.ALGO_ID_MGF1_SHA256);
+                }
             }
         }        
     }
diff --git a/shib-metadata-spring/src/test/resources/net/shibboleth/spring/metadata/filter/algorithmRemovalOnly.xml b/shib-metadata-spring/src/test/resources/net/shibboleth/spring/metadata/filter/algorithmRemovalOnly.xml
new file mode 100644
index 00000000..54169e33
--- /dev/null
+++ b/shib-metadata-spring/src/test/resources/net/shibboleth/spring/metadata/filter/algorithmRemovalOnly.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata:MetadataProvider xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+	xmlns:metadata="urn:mace:shibboleth:2.0:metadata"
+    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+    xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd
+                       urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd
+                       urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd
+                       urn:oasis:names:tc:SAML:metadata:algsupport http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-algsupport-v1.0.xsd
+                       http://www.w3.org/2009/xmlenc11# http://www.w3.org/TR/2013/REC-xmlenc-core1-20130411/xenc-schema-11.xsd"
+    
+	failFastInitialization="false" requireValidMetadata="false"
+
+	id="algorithms" xsi:type="metadata:InlineMetadataProvider">
+    
+	<metadata:MetadataFilter xsi:type="metadata:Algorithm"
+            removeExistingDigestMethods="true"
+            removeExistingSigningMethods="true">
+        <metadata:Entity>https://sp.example.org/sp/shibboleth</metadata:Entity>
+        <metadata:Entity>https://sp3.example.org/sp/shibboleth</metadata:Entity>
+        <metadata:Entity>https://sp4.example.org/sp/shibboleth</metadata:Entity>
+        <metadata:ConditionScript language="javascript">
+            <metadata:Script>input.getEntityID().equals("https://sp3.example.org/sp/shibboleth");</metadata:Script>
+        </metadata:ConditionScript>
+    </metadata:MetadataFilter>
+
+    <EntitiesDescriptor Name="ukgroup">
+    	<EntityDescriptor
+    		entityID="https://sp.example.org/sp/shibboleth">
+            <Extensions>
+                <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
+                <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512" />
+                <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
+                <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" />
+            </Extensions>
+    		<SPSSODescriptor
+    			protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
+    
+    			<AssertionConsumerService
+    				Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
+    				Location="https://sp.example.org/Shibboleth.sso/SAML2/POST-SimpleSign"
+    				index="5" />
+    		</SPSSODescriptor>
+    	</EntityDescriptor>
+
+        <EntityDescriptor
+            entityID="https://sp2.example.org/sp/shibboleth">
+            <Extensions>
+                <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
+                <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512" />
+                <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
+                <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" />
+            </Extensions>
+            <SPSSODescriptor
+                protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
+    
+                <AssertionConsumerService
+                    Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
+                    Location="https://sp2.example.org/Shibboleth.sso/SAML2/POST-SimpleSign"
+                    index="5" />
+            </SPSSODescriptor>
+        </EntityDescriptor>
+
+        <EntityDescriptor
+            entityID="https://sp4.example.org/sp/shibboleth">
+            <Extensions>
+                <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
+                <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512" />
+                <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
+                <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" />
+            </Extensions>
+            <SPSSODescriptor
+                protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
+    
+                <AssertionConsumerService
+                    Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
+                    Location="https://sp4.example.org/Shibboleth.sso/SAML2/POST-SimpleSign"
+                    index="5" />
+            </SPSSODescriptor>
+        </EntityDescriptor>
+    </EntitiesDescriptor>
+</metadata:MetadataProvider>

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


More information about the commits mailing list