From 4b2a66a6436f58d3f99843e7e271c143e69b21cc Mon Sep 17 00:00:00 2001 From: GT Date: Tue, 25 Aug 2026 09:39:59 +0200 Subject: [PATCH] Exclude unused Cryptacular from phase4 runtime --- .../wss/AS4SignatureWithoutBCProbe.java | 89 +++++++++++++++++++ .../phase4/wss/AS4SignatureWithoutBCTest.java | 74 +++++++++++++++ pom.xml | 6 ++ 3 files changed, 169 insertions(+) create mode 100644 phase4-test/src/test/java/com/helger/phase4/wss/AS4SignatureWithoutBCProbe.java create mode 100644 phase4-test/src/test/java/com/helger/phase4/wss/AS4SignatureWithoutBCTest.java diff --git a/phase4-test/src/test/java/com/helger/phase4/wss/AS4SignatureWithoutBCProbe.java b/phase4-test/src/test/java/com/helger/phase4/wss/AS4SignatureWithoutBCProbe.java new file mode 100644 index 000000000..7c2c158c1 --- /dev/null +++ b/phase4-test/src/test/java/com/helger/phase4/wss/AS4SignatureWithoutBCProbe.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015-2026 Philip Helger (www.helger.com) + * philip[at]helger[dot]com + * + * Licensed 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 com.helger.phase4.wss; + +import java.util.List; + +import org.apache.wss4j.dom.WSConstants; +import org.apache.wss4j.dom.engine.WSSecurityEngine; +import org.apache.wss4j.dom.engine.WSSecurityEngineResult; +import org.apache.wss4j.dom.handler.WSHandlerResult; +import org.apache.wss4j.dom.message.WSSecHeader; +import org.apache.wss4j.dom.message.WSSecSignature; +import org.apache.wss4j.dom.str.STRParser; +import org.w3c.dom.Document; + +import com.helger.io.resource.ClassPathResource; +import com.helger.phase4.crypto.AS4CryptoFactoryConfiguration; +import com.helger.phase4.crypto.ECryptoAlgorithmSign; +import com.helger.phase4.crypto.ECryptoAlgorithmSignDigest; +import com.helger.phase4.crypto.ECryptoKeyIdentifierType; +import com.helger.phase4.crypto.ECryptoMode; +import com.helger.phase4.crypto.IAS4CryptoFactory; +import com.helger.scope.mock.ScopeTestRule; +import com.helger.xml.serialize.read.DOMReader; + +/** Invoked through an isolated class loader by {@link AS4SignatureWithoutBCTest}. */ +public final class AS4SignatureWithoutBCProbe +{ + private AS4SignatureWithoutBCProbe () + {} + + public static String verify () throws Exception + { + final ScopeTestRule aScopeRule = new ScopeTestRule (); + aScopeRule.before (); + try + { + final IAS4CryptoFactory aCryptoFactory = AS4CryptoFactoryConfiguration.getDefaultInstance (); + final Document aDoc = DOMReader.readXMLDOM (new ClassPathResource ("UserMessageWithoutWSSE.xml")); + if (aDoc == null) + throw new IllegalStateException ("Failed to read the test SOAP envelope"); + + final WSSecHeader aSecHeader = new WSSecHeader (aDoc); + aSecHeader.insertSecurityHeader (); + + final WSSecSignature aBuilder = new WSSecSignature (aSecHeader); + aBuilder.setUserInfo (aCryptoFactory.getKeyAlias (), + aCryptoFactory.getKeyPasswordPerAlias (aCryptoFactory.getKeyAlias ())); + aBuilder.setKeyIdentifierType (ECryptoKeyIdentifierType.BST_DIRECT_REFERENCE.getTypeID ()); + aBuilder.setSignatureAlgorithm (ECryptoAlgorithmSign.RSA_SHA_256.getAlgorithmURI ()); + aBuilder.setDigestAlgo (ECryptoAlgorithmSignDigest.DIGEST_SHA_256.getAlgorithmURI ()); + final Document aSignedDoc = aBuilder.build (aCryptoFactory.getCrypto (ECryptoMode.ENCRYPT_SIGN)); + + final WSSecurityEngine aSecEngine = new WSSecurityEngine (); + aSecEngine.setWssConfig (WSSConfigManager.getInstance ().createWSSConfig ()); + final WSHandlerResult aResults = aSecEngine.processSecurityHeader (aSignedDoc, + null, + null, + aCryptoFactory.getCrypto (ECryptoMode.ENCRYPT_SIGN)); + + final List aSignResults = aResults.getActionResults () + .get (Integer.valueOf (WSConstants.SIGN)); + if (aSignResults == null || aSignResults.size () != 1) + throw new IllegalStateException ("Expected exactly one verified signature result"); + + final STRParser.REFERENCE_TYPE eReferenceType = (STRParser.REFERENCE_TYPE) aSignResults.get (0) + .get (WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE); + return eReferenceType.name (); + } + finally + { + aScopeRule.after (); + } + } +} diff --git a/phase4-test/src/test/java/com/helger/phase4/wss/AS4SignatureWithoutBCTest.java b/phase4-test/src/test/java/com/helger/phase4/wss/AS4SignatureWithoutBCTest.java new file mode 100644 index 000000000..7ada474b6 --- /dev/null +++ b/phase4-test/src/test/java/com/helger/phase4/wss/AS4SignatureWithoutBCTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015-2026 Philip Helger (www.helger.com) + * philip[at]helger[dot]com + * + * Licensed 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 com.helger.phase4.wss; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.regex.Pattern; + +import org.junit.Test; + +/** Verifies a complete AS4 sign/verify cycle without BC, ph-bc, or Cryptacular. */ +public final class AS4SignatureWithoutBCTest +{ + private static final String PROBE_CLASS = AS4SignatureWithoutBCProbe.class.getName (); + + @Test + public void testSignAndVerifyWithoutBC () throws Exception + { + final String sTestClasspath = System.getProperty ("surefire.test.class.path"); + if (sTestClasspath == null) + throw new IllegalStateException ("The Surefire test classpath is unavailable"); + + final String [] aClasspathEntries = sTestClasspath.split (Pattern.quote (File.pathSeparator)); + final URL [] aURLs = new URL [aClasspathEntries.length]; + for (int i = 0; i < aClasspathEntries.length; ++i) + aURLs[i] = new File (aClasspathEntries[i]).toURI ().toURL (); + + final ClassLoader aOldContextClassLoader = Thread.currentThread ().getContextClassLoader (); + try (final URLClassLoader aCL = new URLClassLoader (aURLs, ClassLoader.getPlatformClassLoader ()) + { + @Override + protected Class loadClass (final String sName, final boolean bResolve) throws ClassNotFoundException + { + if (sName.startsWith ("org.bouncycastle.") || + sName.startsWith ("com.helger.bc.") || + sName.startsWith ("org.cryptacular.")) + throw new ClassNotFoundException ("Optional crypto/SAML dependency deliberately hidden from test class loader"); + return super.loadClass (sName, bResolve); + } + }) + { + Thread.currentThread ().setContextClassLoader (aCL); + assertThrows (ClassNotFoundException.class, + () -> aCL.loadClass ("org.bouncycastle.asn1.ASN1Primitive")); + assertThrows (ClassNotFoundException.class, () -> aCL.loadClass ("com.helger.bc.PBCProvider")); + assertThrows (ClassNotFoundException.class, () -> aCL.loadClass ("org.cryptacular.util.CipherUtil")); + + final Class aProbeClass = Class.forName (PROBE_CLASS, true, aCL); + assertEquals ("DIRECT_REF", aProbeClass.getMethod ("verify").invoke (null)); + } + finally + { + Thread.currentThread ().setContextClassLoader (aOldContextClassLoader); + } + } +} diff --git a/pom.xml b/pom.xml index 7a57d6337..0f73ad8a3 100644 --- a/pom.xml +++ b/pom.xml @@ -169,6 +169,12 @@ org.opensaml opensaml-xacml-saml-impl + + + org.cryptacular + cryptacular + com.google.guava