diff --git a/phase4-lib/src/main/java/com/helger/phase4/incoming/AS4IncomingHandler.java b/phase4-lib/src/main/java/com/helger/phase4/incoming/AS4IncomingHandler.java
index c0c0ff14c..b6731d0eb 100644
--- a/phase4-lib/src/main/java/com/helger/phase4/incoming/AS4IncomingHandler.java
+++ b/phase4-lib/src/main/java/com/helger/phase4/incoming/AS4IncomingHandler.java
@@ -1072,6 +1072,7 @@ public static IAS4IncomingMessageState processEbmsMessage (@NonNull @WillNotClos
{
final ErrorList aErrorList = new ErrorList ();
aValidator.validatePMode (aPMode, aErrorList, EAS4ProfileValidationMode.USER_MESSAGE);
+ aValidator.validateSoapMessage (aSoapDocument, aIncomingState.getSoapVersion(), aErrorList);
aValidator.validateUserMessage (aEbmsUserMessage, aErrorList);
aValidator.validateInitiatorIdentity (aEbmsUserMessage,
aIncomingState.getSigningCertificate (),
diff --git a/phase4-lib/src/main/java/com/helger/phase4/profile/IAS4ProfileValidator.java b/phase4-lib/src/main/java/com/helger/phase4/profile/IAS4ProfileValidator.java
index eaef47e37..85e3d7375 100644
--- a/phase4-lib/src/main/java/com/helger/phase4/profile/IAS4ProfileValidator.java
+++ b/phase4-lib/src/main/java/com/helger/phase4/profile/IAS4ProfileValidator.java
@@ -19,6 +19,7 @@
import java.security.cert.X509Certificate;
import java.util.EnumSet;
+import com.helger.phase4.model.ESoapVersion;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
@@ -29,6 +30,7 @@
import com.helger.phase4.ebms3header.Ebms3UserMessage;
import com.helger.phase4.incoming.IAS4IncomingMessageMetadata;
import com.helger.phase4.model.pmode.IPMode;
+import org.w3c.dom.Document;
/**
* Generic AS4 profile validator
@@ -137,7 +139,20 @@ default void validateInitiatorIdentity (@NonNull final Ebms3UserMessage aUserMsg
{}
/**
- * Validation a UserMessage
+ * Validation of a SoapDocument
+ *
+ * @param aSoapDocument
+ * The SOAP document to be validated. May not be null.
+ * @param eSoapVersion
+ * The SOAP version of the document to be validated.
+ * @param aErrorList
+ * The error list to be filled. May not be null.
+ */
+ default void validateSoapMessage (@NonNull final Document aSoapDocument, @NonNull ESoapVersion eSoapVersion, @NonNull final ErrorList aErrorList)
+ {}
+
+ /**
+ * Validation of a UserMessage
*
* @param aUserMsg
* The message to be validated. May not be null.
@@ -148,7 +163,7 @@ default void validateUserMessage (@NonNull final Ebms3UserMessage aUserMsg, @Non
{}
/**
- * Validation a SignalMessage
+ * Validation of a SignalMessage
*
* @param aSignalMsg
* The message to be validated. May not be null.
diff --git a/phase4-profile-bdew/src/main/java/com/helger/phase4/profile/bdew/BDEWCompatibilityValidator.java b/phase4-profile-bdew/src/main/java/com/helger/phase4/profile/bdew/BDEWCompatibilityValidator.java
index c6fafc364..ff1d6168e 100644
--- a/phase4-profile-bdew/src/main/java/com/helger/phase4/profile/bdew/BDEWCompatibilityValidator.java
+++ b/phase4-profile-bdew/src/main/java/com/helger/phase4/profile/bdew/BDEWCompatibilityValidator.java
@@ -17,7 +17,9 @@
package com.helger.phase4.profile.bdew;
import java.security.cert.X509Certificate;
+import java.util.EnumSet;
+import com.helger.xml.XMLHelper;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
@@ -63,6 +65,9 @@
import com.helger.phase4.model.pmode.leg.PModeLegSecurity;
import com.helger.phase4.profile.IAS4ProfileValidator;
import com.helger.phase4.wss.EWSSVersion;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
/**
* Validate certain requirements imposed by the BDEW project.
@@ -518,10 +523,58 @@ public void validateInitiatorIdentity (@NonNull final Ebms3UserMessage aUserMsg,
}
}
+ @Override
+ public void validateSoapMessage(@NonNull Document aSoapDocument, @NonNull ESoapVersion eSoapVersion, @NonNull ErrorList aErrorList)
+ {
+ ValueEnforcer.notNull (aSoapDocument, "SoapDocument");
+ ValueEnforcer.notNull (aErrorList, "SoapVersion");
+ ValueEnforcer.notNull (aErrorList, "ErrorList");
+
+ final Element aEnvelope = aSoapDocument.getDocumentElement ();
+ if (aEnvelope == null)
+ {
+ aErrorList.add (_createError ("SOAP Envelope is missing"));
+ return;
+ }
+
+ Element aBodyElement = XMLHelper.getFirstChildElementOfName (aEnvelope,
+ eSoapVersion.getNamespaceURI (),
+ eSoapVersion.getBodyElementName ());
+
+ if (aBodyElement == null)
+ {
+ aErrorList.add (_createError ("SOAP Body is missing"));
+ return;
+ }
+
+ if (!_isSoapBodyEmpty (aBodyElement))
+ aErrorList.add (_createError ("SOAP Body must be empty"));
+ }
+
+ private static boolean _isSoapBodyEmpty (@NonNull final Element aBodyElement)
+ {
+ for (Node aChild = aBodyElement.getFirstChild (); aChild != null; aChild = aChild.getNextSibling ())
+ switch (aChild.getNodeType ())
+ {
+ case Node.ELEMENT_NODE:
+ return false;
+ case Node.TEXT_NODE, Node.CDATA_SECTION_NODE:
+ final String sNodeValue = aChild.getNodeValue ();
+ if (sNodeValue != null && !sNodeValue.trim ().isEmpty ())
+ return false;
+ break;
+ default:
+ // Ignore comments and processing instructions
+ break;
+ }
+ return true;
+ }
+
@Override
public void validateUserMessage (@NonNull final Ebms3UserMessage aUserMsg, @NonNull final ErrorList aErrorList)
{
ValueEnforcer.notNull (aUserMsg, "UserMsg");
+ ValueEnforcer.notNull (aErrorList, "ErrorList");
if (aUserMsg.getMessageInfo () == null)
{
@@ -637,6 +690,7 @@ public void validateUserMessage (@NonNull final Ebms3UserMessage aUserMsg, @NonN
public void validateSignalMessage (@NonNull final Ebms3SignalMessage aSignalMsg, @NonNull final ErrorList aErrorList)
{
ValueEnforcer.notNull (aSignalMsg, "SignalMsg");
+ ValueEnforcer.notNull (aErrorList, "ErrorList");
if (aSignalMsg.getMessageInfo () == null)
{
@@ -648,4 +702,9 @@ public void validateSignalMessage (@NonNull final Ebms3SignalMessage aSignalMsg,
aErrorList.add (_createError ("MessageInfo/MessageId is missing"));
}
}
+
+ @Override
+ public @NonNull EnumSet getRequiredSignedParts(boolean bMessageHasAttachments) {
+ return EnumSet.of(ESignedPart.EBMS_MESSAGING, ESignedPart.ATTACHMENTS);
+ }
}
diff --git a/phase4-profile-bdew/src/test/java/com/helger/phase4/profile/bdew/BDEWCompatibilityValidatorTest.java b/phase4-profile-bdew/src/test/java/com/helger/phase4/profile/bdew/BDEWCompatibilityValidatorTest.java
index 6c86eafb6..4c8f5e74f 100644
--- a/phase4-profile-bdew/src/test/java/com/helger/phase4/profile/bdew/BDEWCompatibilityValidatorTest.java
+++ b/phase4-profile-bdew/src/test/java/com/helger/phase4/profile/bdew/BDEWCompatibilityValidatorTest.java
@@ -16,6 +16,7 @@
*/
package com.helger.phase4.profile.bdew;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
@@ -29,6 +30,7 @@
import java.util.Locale;
import java.util.UUID;
+import com.helger.xml.serialize.read.DOMReader;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -69,6 +71,7 @@
import com.helger.phase4.profile.IAS4ProfileValidator.EAS4ProfileValidationMode;
import com.helger.phase4.wss.EWSSVersion;
import com.helger.photon.app.mock.PhotonAppWebTestRule;
+import org.w3c.dom.Document;
/**
* All essentials need to be set and need to be not null since they are getting
@@ -632,6 +635,35 @@ public void testValidatePModeCorrect ()
assertTrue (m_aErrorList.isEmpty ());
}
+ @Test
+ public void testValidateSoapDocumentHasEmptyBody ()
+ {
+ final Document aSoapDoc = DOMReader.readXMLDOM ("""
+
+
+
+ """);
+ assertNotNull (aSoapDoc);
+
+ VALIDATOR.validateSoapMessage (aSoapDoc, ESoapVersion.SOAP_12, m_aErrorList);
+ assertTrue (m_aErrorList.isEmpty ());
+ }
+
+ @Test
+ public void testValidateSoapDocumentHasPayloadInBody ()
+ {
+ final Document aSoapDoc = DOMReader.readXMLDOM ("""
+
+
+
+ """);
+ assertNotNull (aSoapDoc);
+
+ VALIDATOR.validateSoapMessage (aSoapDoc, ESoapVersion.SOAP_12, m_aErrorList);
+ assertFalse (m_aErrorList.isEmpty ());
+ assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("SOAP Body must be empty")));
+ }
+
@Test
public void testValidateUserMessageNoMessageInfo ()
{