RAMPART-44 / RAMPART-252: add a dedicated algorithm-downgrade test

Follow-up to the Gemini review: add a focused, deterministic test for the new
inbound algorithm-suite enforcement, rather than relying only on the incidental
coverage from RampartTest case 34.

PolicyAssertionsTest.testAlgorithmSuiteDowngradeRejected builds a signed request
with a Basic128 (SHA-1) policy, then validates it as the server against a
Basic128Sha256 (SHA-256) policy and asserts the message is rejected - a peer must
not be able to downgrade the digest algorithm below what the policy requires.

Confirmed the test guards the fix: with applyAlgorithmSuite disabled the SHA-1
signature verifies and the message is accepted, failing the test. Adds the
rampart-asymm-binding-1-sha256.xml policy (a Basic128Sha256 copy of
rampart-asymm-binding-1.xml). Verified with a full clean -Papache-release verify
across all modules including the nine policy samples on JDK 25.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
diff --git a/modules/rampart-tests/src/test/java/org/apache/rampart/PolicyAssertionsTest.java b/modules/rampart-tests/src/test/java/org/apache/rampart/PolicyAssertionsTest.java
index 9ea4c74..ae7fcfd 100644
--- a/modules/rampart-tests/src/test/java/org/apache/rampart/PolicyAssertionsTest.java
+++ b/modules/rampart-tests/src/test/java/org/apache/rampart/PolicyAssertionsTest.java
@@ -159,4 +159,41 @@
         }
 
     }
+
+    public void testAlgorithmSuiteDowngradeRejected() throws Exception {
+        // RAMPART-44 / RAMPART-252: a message signed with a weaker algorithm suite
+        // (Basic128, SHA-1) must be rejected when the service policy requires a stronger
+        // suite (Basic128Sha256, SHA-256), so a peer cannot downgrade the digest
+        // algorithm. Without algorithm-suite enforcement the SHA-1 signature would verify
+        // and the message would be accepted.
+        MessageContext ctx = getMsgCtx();
+
+        // Build the request with the SHA-1 (Basic128) policy.
+        Policy buildPolicy = loadPolicy("test-resources/policy/rampart-asymm-binding-1.xml");
+        ctx.setProperty(RampartMessageData.KEY_RAMPART_POLICY, buildPolicy);
+        MessageBuilder builder = new MessageBuilder();
+        builder.build(ctx);
+
+        SOAPBuilder soapBuilder = new SOAPBuilder();
+        SOAPEnvelope env = ctx.getEnvelope();
+        ByteArrayInputStream inStream = new ByteArrayInputStream(env.toString().getBytes());
+        env = (SOAPEnvelope) soapBuilder.processDocument(inStream, "text/xml", ctx);
+        ctx.setEnvelope(env);
+
+        // Validate as the server with the SHA-256 (Basic128Sha256) policy.
+        ctx.setServerSide(true);
+        AxisService axisService = ctx.getAxisService();
+        axisService.removeParameter(axisService.getParameter(RampartMessageData.PARAM_CLIENT_SIDE));
+
+        Policy verifyPolicy = loadPolicy("test-resources/policy/rampart-asymm-binding-1-sha256.xml");
+        ctx.setProperty(RampartMessageData.KEY_RAMPART_POLICY, verifyPolicy);
+
+        RampartEngine engine = new RampartEngine();
+        try {
+            engine.process(ctx);
+            fail("A message signed with SHA-1 must be rejected when the policy requires SHA-256");
+        } catch (Exception expected) {
+            // Expected: algorithm-suite enforcement rejects the weaker digest algorithm.
+        }
+    }
 }
diff --git a/modules/rampart-tests/test-resources/policy/rampart-asymm-binding-1-sha256.xml b/modules/rampart-tests/test-resources/policy/rampart-asymm-binding-1-sha256.xml
new file mode 100644
index 0000000..d0fc48e
--- /dev/null
+++ b/modules/rampart-tests/test-resources/policy/rampart-asymm-binding-1-sha256.xml
@@ -0,0 +1,75 @@
+<wsp:Policy  wsu:Id="6-sha256" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">

+	<wsp:ExactlyOne>

+		<wsp:All>

+			<sp:AsymmetricBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">

+				<wsp:Policy>

+					<sp:InitiatorToken>

+						<wsp:Policy>

+							<sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">

+								<wsp:Policy>

+									<sp:WssX509V3Token10/>

+								</wsp:Policy>

+							</sp:X509Token>

+						</wsp:Policy>

+					</sp:InitiatorToken>

+					<sp:RecipientToken>

+						<wsp:Policy>

+							<sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Never">

+								<wsp:Policy>

+									<sp:WssX509V3Token10/>

+								</wsp:Policy>

+							</sp:X509Token>

+						</wsp:Policy>

+					</sp:RecipientToken>

+					<sp:AlgorithmSuite>

+						<wsp:Policy>

+							<sp:Basic128Sha256/>

+						</wsp:Policy>

+					</sp:AlgorithmSuite>

+					<sp:Layout>

+						<wsp:Policy>

+							<sp:Lax/>

+						</wsp:Policy>

+					</sp:Layout>

+					<sp:IncludeTimestamp/>

+					<sp:OnlySignEntireHeadersAndBody/>

+				</wsp:Policy>

+			</sp:AsymmetricBinding>

+			<sp:Wss10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">

+				<wsp:Policy>

+					<sp:MustSupportRefKeyIdentifier/>

+					<sp:MustSupportRefIssuerSerial/>

+				</wsp:Policy>

+			</sp:Wss10>

+			<sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">

+				<wsp:Policy>

+					<sp:MustSupportIssuedTokens/>

+					<sp:RequireClientEntropy/>

+					<sp:RequireServerEntropy/>

+				</wsp:Policy>

+			</sp:Trust10>

+			

+			<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy"> 

+				<ramp:user>alice</ramp:user>

+				<ramp:encryptionUser>bob</ramp:encryptionUser>

+				<ramp:passwordCallbackClass>org.apache.rampart.TestCBHandler</ramp:passwordCallbackClass>

+				

+				<ramp:signatureCrypto>

+					<ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">

+						<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type">pkcs12</ramp:property>

+						<ramp:property name="org.apache.ws.security.crypto.merlin.file">test-resources/keys/interop2024.pkcs12</ramp:property>

+						<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.password">password</ramp:property>

+					</ramp:crypto>

+				</ramp:signatureCrypto>

+				<ramp:encryptionCypto>

+					<ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">

+						<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type">pkcs12</ramp:property>

+						<ramp:property name="org.apache.ws.security.crypto.merlin.file">test-resources/keys/interop2024.pkcs12</ramp:property>

+						<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.password">password</ramp:property>

+					</ramp:crypto>

+				</ramp:encryptionCypto>

+			</ramp:RampartConfig>

+	

+		</wsp:All>

+	</wsp:ExactlyOne>

+</wsp:Policy>