diff --git a/phase4-profile-dbnalliance/findbugs-exclude.xml b/phase4-profile-dbnalliance/findbugs-exclude.xml new file mode 100644 index 000000000..41293edae --- /dev/null +++ b/phase4-profile-dbnalliance/findbugs-exclude.xml @@ -0,0 +1,21 @@ + + + + diff --git a/phase4-profile-dbnalliance/pom.xml b/phase4-profile-dbnalliance/pom.xml new file mode 100644 index 000000000..545992f04 --- /dev/null +++ b/phase4-profile-dbnalliance/pom.xml @@ -0,0 +1,89 @@ + + + + 4.0.0 + + com.helger.phase4 + phase4-parent-pom + 2.6.1-SNAPSHOT + + phase4-profile-dbnalliance + bundle + phase4-profile-dbnalliance + DBNAlliance AS4 profile + https://github.com/phax/phase4/phase4-profile-dbnalliance + 2023 + + + + Apache 2 + http://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + + com.helger.phase4 + phase4-lib + + + + jakarta.servlet + jakarta.servlet-api + provided + + + + junit + junit + test + + + org.slf4j + slf4j-simple + test + + + com.helger.photon + ph-oton-app + test + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + com.helger.phase4.profile.dbnalliance + com.helger.phase4.profile.dbnalliance.* + !javax.annotation.*,* + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)" + osgi.serviceloader; osgi.serviceloader=com.helger.phase4.profile.IAS4ProfileRegistrarSPI + + + + + + diff --git a/phase4-profile-dbnalliance/src/etc/javadoc.css b/phase4-profile-dbnalliance/src/etc/javadoc.css new file mode 100644 index 000000000..391139066 --- /dev/null +++ b/phase4-profile-dbnalliance/src/etc/javadoc.css @@ -0,0 +1,583 @@ +/** + * Copyright (C) 2023 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. + */ +/* + * based on phloc javadoc CSS. + * (c) 2011-2014 phloc systems. + * Derived from the original javadoc CSS from Sun JDK + */ + +body { + background-color: #FFFFFF; + color: #353833; + font-family: Arial, Helvetica, sans-serif; + font-size: 76%; + margin: 0; +} + +a:link,a:visited { + color: #880000; + text-decoration: none; +} + +a:hover,a:focus { + color: #BB2222; + text-decoration: none; +} + +a:active { + color: #4C6B87; + text-decoration: none; +} + +a[name] { + color: #353833; +} + +a[name]:hover { + color: #353833; + text-decoration: none; +} + +pre { + font-size: 1.3em; +} + +h1 { + font-size: 1.8em; +} + +h2 { + font-size: 1.5em; +} + +h3 { + font-size: 1.4em; +} + +h4 { + font-size: 1.3em; +} + +h5 { + font-size: 1.2em; +} + +h6 { + font-size: 1.1em; +} + +ul { + list-style-type: disc; +} + +code,tt { + font-size: 1.2em; +} + +dt code { + font-size: 1.2em; +} + +table tr td dt code { + font-size: 1.2em; + vertical-align: top; +} + +sup { + font-size: 0.6em; +} + +.clear { + clear: both; + height: 0; + overflow: hidden; +} + +.aboutLanguage { + float: right; + font-size: 0.8em; + margin-top: -7px; + padding: 0 21px; + z-index: 200; +} + +.legalCopy { + margin-left: 0.5em; +} + +.bar a,.bar a:link,.bar a:visited,.bar a:active { + color: #FFFFFF; + text-decoration: none; +} + +.bar a:hover,.bar a:focus { + color: #BB7A2A; +} + +.tab { + background-color: #0066FF; + background-image: url("resources/titlebar.gif"); + background-position: left top; + background-repeat: no-repeat; + color: #FFFFFF; + font-weight: bold; + padding: 8px; + width: 5em; +} + +.bar { + background-image: url("resources/background.gif"); + background-repeat: repeat-x; + color: #FFFFFF; + font-size: 1em; + height: auto; + margin: 0; + padding: 0.8em 0.5em 0.4em 0.8em; +} + +.topNav { + background-image: url("resources/background.gif"); + background-repeat: repeat-x; + clear: right; + color: #FFFFFF; + float: left; + height: 2.8em; + overflow: hidden; + padding: 10px 0 0; + width: 100%; +} + +.bottomNav { + background-image: url("resources/background.gif"); + background-repeat: repeat-x; + clear: right; + color: #FFFFFF; + float: left; + height: 2.8em; + margin-top: 10px; + overflow: hidden; + padding: 10px 0 0; + width: 100%; +} + +.subNav { + background-color: #DEE3E9; + border-bottom: 1px solid #9EADC0; + float: left; + overflow: hidden; + width: 100%; +} + +.subNav div { + clear: left; + float: left; + padding: 0 0 5px 6px; +} + +ul.navList,ul.subNavList { + float: left; + margin: 0 25px 0 0; + padding: 0; +} + +ul.navList li { + float: left; + list-style: none outside none; + padding: 3px 6px; +} + +ul.subNavList li { + float: left; + font-size: 90%; + list-style: none outside none; +} + +.topNav a:link,.topNav a:active,.topNav a:visited,.bottomNav a:link,.bottomNav a:active,.bottomNav a:visited + { + color: #FFFFFF; + text-decoration: none; +} + +.topNav a:hover,.bottomNav a:hover { + color: #BB7A2A; + text-decoration: none; +} + +.navBarCell1Rev { + background-color: #A88834; + background-image: url("resources/tab.gif"); + border: 1px solid #C9AA44; + color: #FFFFFF; + margin: auto 5px; +} + +.header,.footer { + clear: both; + margin: 0 20px; + padding: 5px 0 0; +} + +.indexHeader { + margin: 10px; + position: relative; +} + +.indexHeader h1 { + font-size: 1.3em; +} + +.title { + color: #880000; + margin: 10px 0; +} + +.subTitle { + margin: 5px 0 0; +} + +.header ul { + margin: 0 0 25px; + padding: 0; +} + +.footer ul { + margin: 20px 0 5px; +} + +.header ul li,.footer ul li { + font-size: 1.2em; + list-style: none outside none; +} + +div.details ul.blockList ul.blockList ul.blockList li.blockList h4,div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 + { + background-color: #DEE3E9; + border-bottom: 1px solid #9EADC0; + border-top: 1px solid #9EADC0; + margin: 0 0 6px -8px; + padding: 2px 5px; +} + +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color: #DEE3E9; + border-bottom: 1px solid #9EADC0; + border-top: 1px solid #9EADC0; + margin: 0 0 6px -8px; + padding: 2px 5px; +} + +ul.blockList ul.blockList li.blockList h3 { + margin: 15px 0; + padding: 0; +} + +ul.blockList li.blockList h2 { + padding: 0 0 20px; +} + +.contentContainer,.sourceContainer,.classUseContainer,.serializedFormContainer,.constantValuesContainer + { + clear: both; + padding: 10px 20px; + position: relative; +} + +.indexContainer { + font-size: 1em; + margin: 10px; + position: relative; +} + +.indexContainer h2 { + font-size: 1.1em; + padding: 0 0 3px; +} + +.indexContainer ul { + margin: 0; + padding: 0; +} + +.indexContainer ul li { + list-style: none outside none; +} + +.contentContainer .description dl dt,.contentContainer .details dl dt,.serializedFormContainer dl dt + { + color: #4E4E4E; + font-size: 1.1em; + font-weight: bold; + margin: 10px 0 0; +} + +.contentContainer .description dl dd,.contentContainer .details dl dd,.serializedFormContainer dl dd + { + margin: 10px 0 10px 20px; +} + +.serializedFormContainer dl.nameValue dt { + display: inline; + font-size: 1.1em; + font-weight: bold; + margin-left: 1px; +} + +.serializedFormContainer dl.nameValue dd { + display: inline; + font-size: 1.1em; +} + +ul.horizontal li { + display: inline; + font-size: 0.9em; +} + +ul.inheritance { + margin: 0; + padding: 0; +} + +ul.inheritance li { + display: inline; + list-style: none outside none; +} + +ul.inheritance li ul.inheritance { + margin-left: 15px; + padding-left: 15px; + padding-top: 1px; +} + +ul.blockList,ul.blockListLast { + margin: 10px 0; + padding: 0; +} + +ul.blockList li.blockList,ul.blockListLast li.blockList { + list-style: none outside none; + margin-bottom: 25px; +} + +ul.blockList ul.blockList li.blockList,ul.blockList ul.blockListLast li.blockList + { + background-color: #F9F9F9; + border: 1px solid #9EADC0; + padding: 0 20px 5px 10px; +} + +ul.blockList ul.blockList ul.blockList li.blockList,ul.blockList ul.blockList ul.blockListLast li.blockList + { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + background-color: #FFFFFF; + border-color: currentColor #9EADC0 #9EADC0; + border-image: none; + border-right: 1px solid #9EADC0; + border-style: none solid solid; + border-width: medium 1px 1px; + padding: 0 0 5px 8px; +} + +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + border-color: currentColor currentColor #9EADC0; + border-image: none; + border-style: none none solid; + border-width: medium medium 1px; + margin-left: 0; + padding-bottom: 15px; + padding-left: 0; +} + +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + border-bottom: medium none; + list-style: none outside none; + padding-bottom: 0; +} + +table tr td dl,table tr td dl dt,table tr td dl dd { + margin-bottom: 1px; + margin-top: 0; +} + +.contentContainer table,.classUseContainer table,.constantValuesContainer table + { + border-bottom: 1px solid #9EADC0; + width: 100%; +} + +.contentContainer ul li table,.classUseContainer ul li table,.constantValuesContainer ul li table + { + width: 100%; +} + +.contentContainer .description table,.contentContainer .details table { + border-bottom: medium none; +} + +.contentContainer ul li table th.colOne,.contentContainer ul li table th.colFirst,.contentContainer ul li table th.colLast,.classUseContainer ul li table th,.constantValuesContainer ul li table th,.contentContainer ul li table td.colOne,.contentContainer ul li table td.colFirst,.contentContainer ul li table td.colLast,.classUseContainer ul li table td,.constantValuesContainer ul li table td + { + padding-right: 20px; + vertical-align: top; +} + +.contentContainer ul li table th.colLast,.classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast,.contentContainer ul li table td.colLast,.classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast,.contentContainer ul li table th.colOne,.classUseContainer ul li table th.colOne,.contentContainer ul li table td.colOne,.classUseContainer ul li table td.colOne + { + padding-right: 3px; +} + +.overviewSummary caption,.packageSummary caption,.contentContainer ul.blockList li.blockList caption,.summary caption,.classUseContainer caption,.constantValuesContainer caption + { + background-repeat: no-repeat; + clear: none; + color: #FFFFFF; + font-weight: bold; + margin: 0; + overflow: hidden; + padding: 0; + position: relative; + text-align: left; +} + +caption a:link,caption a:hover,caption a:active,caption a:visited { + color: #FFFFFF; +} + +.overviewSummary caption span,.packageSummary caption span,.contentContainer ul.blockList li.blockList caption span,.summary caption span,.classUseContainer caption span,.constantValuesContainer caption span + { + background-image: url("resources/titlebar.gif"); + display: block; + float: left; + height: 18px; + padding-left: 8px; + padding-top: 8px; + white-space: nowrap; +} + +.overviewSummary .tabEnd,.packageSummary .tabEnd,.contentContainer ul.blockList li.blockList .tabEnd,.summary .tabEnd,.classUseContainer .tabEnd,.constantValuesContainer .tabEnd + { + background-image: url("resources/titlebar_end.gif"); + background-position: right top; + background-repeat: no-repeat; + float: left; + position: relative; + width: 10px; +} + +ul.blockList ul.blockList li.blockList table { + margin: 0 0 12px; + width: 100%; +} + +.tableSubHeadingColor { + background-color: #EEEEFF; +} + +.altColor { + background-color: #EEEEEF; +} + +.rowColor { + background-color: #FFFFFF; +} + +.overviewSummary td,.packageSummary td,.contentContainer ul.blockList li.blockList td,.summary td,.classUseContainer td,.constantValuesContainer td + { + padding: 3px 3px 3px 7px; + text-align: left; +} + +th.colFirst,th.colLast,th.colOne,.constantValuesContainer th { + background: none repeat scroll 0 0 #DEE3E9; + border-bottom: 1px solid #9EADC0; + border-top: 1px solid #9EADC0; + padding: 3px 3px 3px 7px; + text-align: left; +} + +td.colOne a:link,td.colOne a:active,td.colOne a:visited,td.colOne a:hover,td.colFirst a:link,td.colFirst a:active,td.colFirst a:visited,td.colFirst a:hover,td.colLast a:link,td.colLast a:active,td.colLast a:visited,td.colLast a:hover,.constantValuesContainer td a:link,.constantValuesContainer td a:active,.constantValuesContainer td a:visited,.constantValuesContainer td a:hover + { + font-weight: bold; +} + +td.colFirst,th.colFirst { + border-left: 1px solid #9EADC0; + white-space: nowrap; +} + +td.colLast,th.colLast { + border-right: 1px solid #9EADC0; +} + +td.colOne,th.colOne { + border-left: 1px solid #9EADC0; + border-right: 1px solid #9EADC0; +} + +table.overviewSummary { + margin-left: 0; + padding: 0; +} + +table.overviewSummary td.colFirst,table.overviewSummary th.colFirst,table.overviewSummary td.colOne,table.overviewSummary th.colOne + { + vertical-align: middle; + width: 25%; +} + +table.packageSummary td.colFirst,table.overviewSummary th.colFirst { + vertical-align: middle; + width: 25%; +} + +.description pre { + margin-top: 0; +} + +.deprecatedContent { + margin: 0; + padding: 10px 0; +} + +.docSummary { + padding: 0; +} + +.sourceLineNo { + color: #008000; + padding: 0 30px 0 0; +} + +h1.hidden { + font-size: 0.9em; + overflow: hidden; + visibility: hidden; +} + +.block { + display: block; + margin: 3px 0 0; +} + +.strong { + font-weight: bold; +} diff --git a/phase4-profile-dbnalliance/src/etc/license-template.txt b/phase4-profile-dbnalliance/src/etc/license-template.txt new file mode 100644 index 000000000..75720a846 --- /dev/null +++ b/phase4-profile-dbnalliance/src/etc/license-template.txt @@ -0,0 +1,14 @@ +Copyright (C) 2023 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. \ No newline at end of file diff --git a/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/AS4DBNAllianceProfileRegistarSPI.java b/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/AS4DBNAllianceProfileRegistarSPI.java new file mode 100644 index 000000000..dfa893e94 --- /dev/null +++ b/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/AS4DBNAllianceProfileRegistarSPI.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 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.profile.dbnalliance; + +import javax.annotation.Nonnull; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.helger.commons.annotation.IsSPIImplementation; +import com.helger.phase4.model.pmode.IPModeIDProvider; +import com.helger.phase4.profile.AS4Profile; +import com.helger.phase4.profile.IAS4ProfilePModeProvider; +import com.helger.phase4.profile.IAS4ProfileRegistrar; +import com.helger.phase4.profile.IAS4ProfileRegistrarSPI; + +/** + * Library specific implementation of {@link IAS4ProfileRegistrarSPI}. + * + * @author Philip Helger + * @author Michael Riviera + */ +@IsSPIImplementation +public final class AS4DBNAllianceProfileRegistarSPI implements IAS4ProfileRegistrarSPI +{ + public static final String AS4_PROFILE_ID = "dbnalliance"; + public static final String AS4_PROFILE_NAME = "DBN Alliance"; + public static final IPModeIDProvider PMODE_ID_PROVIDER = IPModeIDProvider.DEFAULT_DYNAMIC; + + private static final Logger LOGGER = LoggerFactory.getLogger (AS4DBNAllianceProfileRegistarSPI.class); + + public void registerAS4Profile (@Nonnull final IAS4ProfileRegistrar aRegistrar) + { + final IAS4ProfilePModeProvider aDefaultPModeProvider = (i, + r, + a) -> DBNAlliancePMode.createDBNAlliancePMode (i, + r, + a, + PMODE_ID_PROVIDER, + true); + + if (LOGGER.isDebugEnabled ()) + LOGGER.debug ("Registering phase4 profile '" + AS4_PROFILE_ID + "'"); + final AS4Profile aProfile = new AS4Profile (AS4_PROFILE_ID, + AS4_PROFILE_NAME, + DBNAllianceCompatibilityValidator::new, + aDefaultPModeProvider, + PMODE_ID_PROVIDER, + false, + false); + aRegistrar.registerProfile (aProfile); + aRegistrar.setDefaultProfile (aProfile); + } +} diff --git a/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/DBNAllianceCompatibilityValidator.java b/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/DBNAllianceCompatibilityValidator.java new file mode 100644 index 000000000..2cf06d3a2 --- /dev/null +++ b/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/DBNAllianceCompatibilityValidator.java @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2023 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.profile.dbnalliance; + +import javax.annotation.Nonnull; + +import com.helger.commons.ValueEnforcer; +import com.helger.commons.annotation.Nonempty; +import com.helger.commons.debug.GlobalDebug; +import com.helger.commons.error.IError; +import com.helger.commons.error.SingleError; +import com.helger.commons.error.list.ErrorList; +import com.helger.commons.string.StringHelper; +import com.helger.phase4.attachment.EAS4CompressionMode; +import com.helger.phase4.crypto.ECryptoAlgorithmCrypt; +import com.helger.phase4.crypto.ECryptoAlgorithmSign; +import com.helger.phase4.crypto.ECryptoAlgorithmSignDigest; +import com.helger.phase4.ebms3header.Ebms3AgreementRef; +import com.helger.phase4.ebms3header.Ebms3From; +import com.helger.phase4.ebms3header.Ebms3SignalMessage; +import com.helger.phase4.ebms3header.Ebms3To; +import com.helger.phase4.ebms3header.Ebms3UserMessage; +import com.helger.phase4.mgr.MetaAS4Manager; +import com.helger.phase4.model.EMEP; +import com.helger.phase4.model.EMEPBinding; +import com.helger.phase4.model.pmode.IPMode; +import com.helger.phase4.model.pmode.PModePayloadService; +import com.helger.phase4.model.pmode.PModeValidationException; +import com.helger.phase4.model.pmode.leg.EPModeSendReceiptReplyPattern; +import com.helger.phase4.model.pmode.leg.PModeLeg; +import com.helger.phase4.model.pmode.leg.PModeLegErrorHandling; +import com.helger.phase4.model.pmode.leg.PModeLegProtocol; +import com.helger.phase4.model.pmode.leg.PModeLegSecurity; +import com.helger.phase4.profile.IAS4ProfileValidator; +import com.helger.phase4.soap.ESoapVersion; +import com.helger.phase4.wss.EWSSVersion; + +/** + * Validate certain requirements imposed by the DBNAlliance. + * + * @author Philip Helger + * @author Michael Riviera + */ +public class DBNAllianceCompatibilityValidator implements IAS4ProfileValidator +{ + public DBNAllianceCompatibilityValidator () + {} + + @Nonnull + private static IError _createError (@Nonnull final String sMsg) + { + return SingleError.builderError ().errorText (sMsg).build (); + } + + @Nonnull + private static IError _createWarn (@Nonnull final String sMsg) + { + return SingleError.builderWarn ().errorText (sMsg).build (); + } + + private static void _checkIfLegIsValid (@Nonnull final ErrorList aErrorList, + @Nonnull final PModeLeg aPModeLeg, + @Nonnull @Nonempty final String sFieldPrefix) + { + final PModeLegProtocol aLegProtocol = aPModeLeg.getProtocol (); + if (aLegProtocol == null) + { + aErrorList.add (_createError (sFieldPrefix + "Protocol is missing")); + } + else + { + // PROTOCOL Address only https allowed + final String sAddressProtocol = aLegProtocol.getAddressProtocol (); + if (StringHelper.hasText (sAddressProtocol)) + { + if (sAddressProtocol.equalsIgnoreCase ("https")) + { + // Always okay + } + else + if (sAddressProtocol.equalsIgnoreCase ("http") && GlobalDebug.isDebugMode ()) + { + // Okay in debug mode only + } + else + { + // Other protocol + aErrorList.add (_createError (sFieldPrefix + "AddressProtocol '" + sAddressProtocol + "' is unsupported")); + } + } + else + { + // Empty address protocol + if (false) + aErrorList.add (_createError (sFieldPrefix + "AddressProtocol is missing")); + } + + final ESoapVersion eSOAPVersion = aLegProtocol.getSoapVersion (); + if (eSOAPVersion != ESoapVersion.SOAP_12) + { + aErrorList.add (_createError (sFieldPrefix + + "SoapVersion '" + + eSOAPVersion.getVersion () + + "' is unsupported")); + } + } + + // Only check the security features if a Security Leg is currently present + final PModeLegSecurity aPModeLegSecurity = aPModeLeg.getSecurity (); + if (aPModeLegSecurity != null) + { + // Check Certificate + // certificate is in Partner/SMP - therefore not here :) + if (false) + if (aPModeLegSecurity.getX509SignatureCertificate () == null) + { + aErrorList.add (_createError (sFieldPrefix + "Security.X509SignatureCertificate is missing")); + } + + // Check Signature Algorithm + if (aPModeLegSecurity.getX509SignatureAlgorithm () == null) + { + aErrorList.add (_createError (sFieldPrefix + "Security.X509SignatureAlgorithm is missing")); + } + else + if (!aPModeLegSecurity.getX509SignatureAlgorithm ().equals (ECryptoAlgorithmSign.RSA_SHA_256)) + { + aErrorList.add (_createError (sFieldPrefix + + "Security.X509SignatureAlgorithm must use the value '" + + ECryptoAlgorithmSign.RSA_SHA_256.getID () + + "'")); + } + + // Check Hash Function + if (aPModeLegSecurity.getX509SignatureHashFunction () == null) + { + aErrorList.add (_createError (sFieldPrefix + "Security.X509SignatureHashFunction is missing")); + } + else + if (!aPModeLegSecurity.getX509SignatureHashFunction ().equals (ECryptoAlgorithmSignDigest.DIGEST_SHA_256)) + { + aErrorList.add (_createError (sFieldPrefix + + "Security.X509SignatureHashFunction must use the value '" + + ECryptoAlgorithmSignDigest.DIGEST_SHA_256.getID () + + "'")); + } + + // Check Encrypt algorithm + if (aPModeLegSecurity.getX509EncryptionAlgorithm () == null) + { + aErrorList.add (_createError (sFieldPrefix + "Security.X509EncryptionAlgorithm is missing")); + } + else + if (!aPModeLegSecurity.getX509EncryptionAlgorithm ().equals (ECryptoAlgorithmCrypt.AES_256_GCM)) + { + aErrorList.add (_createError (sFieldPrefix + + "Security.X509EncryptionAlgorithm must use the value '" + + ECryptoAlgorithmCrypt.AES_256_GCM.getID () + + "' instead of '" + + aPModeLegSecurity.getX509EncryptionAlgorithm ().getID () + + "'")); + } + + // Check WSS Version = 1.1.1 + if (aPModeLegSecurity.getWSSVersion () != null) + { + // Check for WSS - Version if there is one present + if (!aPModeLegSecurity.getWSSVersion ().equals (EWSSVersion.WSS_111)) + aErrorList.add (_createError (sFieldPrefix + + "Security.WSSVersion must use the value " + + EWSSVersion.WSS_111 + + " instead of " + + aPModeLegSecurity.getWSSVersion ())); + } + + // PModeAuthorize + if (aPModeLegSecurity.isPModeAuthorizeDefined ()) + { + if (aPModeLegSecurity.isPModeAuthorize ()) + aErrorList.add (_createError (sFieldPrefix + "Security.PModeAuthorize must be set to 'false'")); + } + else + { + aErrorList.add (_createError (sFieldPrefix + "Security.PModeAuthorize is missing")); + } + + // SEND RECEIPT TRUE/FALSE when false don't send receipts anymore + if (aPModeLegSecurity.isSendReceiptDefined ()) + { + if (aPModeLegSecurity.isSendReceipt ()) + { + // set response required + + if (aPModeLegSecurity.getSendReceiptReplyPattern () != EPModeSendReceiptReplyPattern.RESPONSE) + aErrorList.add (_createError (sFieldPrefix + + "Security.SendReceiptReplyPattern must use the value " + + EPModeSendReceiptReplyPattern.RESPONSE + + " instead of " + + aPModeLegSecurity.getSendReceiptReplyPattern ())); + } + } + } + else + { + aErrorList.add (_createError (sFieldPrefix + "Security is missing")); + } + + // Error Handling + final PModeLegErrorHandling aErrorHandling = aPModeLeg.getErrorHandling (); + if (aErrorHandling != null) + { + if (aErrorHandling.isReportAsResponseDefined ()) + { + if (!aErrorHandling.isReportAsResponse ()) + aErrorList.add (_createError (sFieldPrefix + "ErrorHandling.Report.AsResponse must be 'true'")); + } + else + { + aErrorList.add (_createError (sFieldPrefix + "ErrorHandling.Report.AsResponse is missing")); + } + if (aErrorHandling.isReportProcessErrorNotifyConsumerDefined ()) + { + if (!aErrorHandling.isReportProcessErrorNotifyConsumer ()) + aErrorList.add (_createWarn (sFieldPrefix + + "ErrorHandling.Report.ProcessErrorNotifyConsumer should be 'true'")); + } + else + { + aErrorList.add (_createError (sFieldPrefix + "ErrorHandling.Report.ProcessErrorNotifyConsumer is missing")); + } + + if (aErrorHandling.isReportProcessErrorNotifyProducerDefined ()) + { + if (!aErrorHandling.isReportProcessErrorNotifyProducer ()) + aErrorList.add (_createWarn (sFieldPrefix + + "ErrorHandling.Report.ProcessErrorNotifyProducer should be 'true'")); + } + else + { + aErrorList.add (_createError (sFieldPrefix + "ErrorHandling.Report.ProcessErrorNotifyProducer is missing")); + } + + if (aErrorHandling.isReportDeliveryFailuresNotifyProducerDefined ()) + { + if (!aErrorHandling.isReportDeliveryFailuresNotifyProducer ()) + aErrorList.add (_createWarn (sFieldPrefix + + "ErrorHandling.Report.DeliveryFailuresNotifyProducer should be 'true'")); + } + else + { + aErrorList.add (_createError (sFieldPrefix + + "ErrorHandling.Report.DeliveryFailuresNotifyProducer is a mandatory PMode parameter")); + } + } + else + { + aErrorList.add (_createError (sFieldPrefix + "ErrorHandling is missing")); + } + } + + public void validatePMode (@Nonnull final IPMode aPMode, @Nonnull final ErrorList aErrorList) + { + ValueEnforcer.isTrue (aErrorList.isEmpty (), () -> "Errors in global PMode validation: " + aErrorList.toString ()); + + try + { + MetaAS4Manager.getPModeMgr ().validatePMode (aPMode); + } + catch (final PModeValidationException ex) + { + aErrorList.add (_createError (ex.getMessage ())); + } + + final EMEP eMEP = aPMode.getMEP (); + final EMEPBinding eMEPBinding = aPMode.getMEPBinding (); + + if (eMEP == EMEP.ONE_WAY && eMEPBinding == EMEPBinding.PUSH) + { + // Valid + } + else + { + aErrorList.add (_createError ("An invalid combination of PMode MEP (" + + eMEP + + ") and MEP binding (" + + eMEPBinding + + ") was specified, only one-way/push is valid.")); + } + + // Leg1 must be present + final PModeLeg aPModeLeg1 = aPMode.getLeg1 (); + if (aPModeLeg1 == null) + { + aErrorList.add (_createError ("PMode.Leg[1] is missing")); + } + else + { + _checkIfLegIsValid (aErrorList, aPModeLeg1, "PMode.Leg[1]."); + } + + if (aPMode.getLeg2 () != null) + { + aErrorList.add (_createError ("PMode.Leg[2] must not be present")); + } + + // Compression application/gzip ONLY + // other possible states are absent or "" (No input) + final PModePayloadService aPayloadService = aPMode.getPayloadService (); + if (aPayloadService != null) + { + final EAS4CompressionMode eCompressionMode = aPayloadService.getCompressionMode (); + if (eCompressionMode != null) + { + if (!eCompressionMode.equals (EAS4CompressionMode.GZIP)) + aErrorList.add (_createError ("PMode.PayloadService.CompressionMode must be " + + EAS4CompressionMode.GZIP + + " instead of " + + eCompressionMode)); + } + } + } + + public void validateUserMessage (@Nonnull final Ebms3UserMessage aUserMsg, @Nonnull final ErrorList aErrorList) + { + ValueEnforcer.notNull (aUserMsg, "UserMsg"); + + if (aUserMsg.getMessageInfo () == null) + { + aErrorList.add (_createError ("MessageInfo is missing")); + } + else + { + if (StringHelper.hasNoText (aUserMsg.getMessageInfo ().getMessageId ())) + aErrorList.add (_createError ("MessageInfo/MessageId is missing")); + } + + if (aUserMsg.getPartyInfo () == null) + { + aErrorList.add (_createError ("PartyInfo is missing")); + } + else + { + final Ebms3From aFrom = aUserMsg.getPartyInfo ().getFrom (); + if (aFrom != null) + { + if (aFrom.getPartyIdCount () > 1) + aErrorList.add (_createError ("PartyInfo/From must contain no more than one PartyID")); + else + if (aFrom.getPartyIdCount () == 1) + { + if (!DBNAlliancePMode.DEFAULT_PARTY_TYPE_ID.equals (aFrom.getPartyIdAtIndex (0).getType ())) + { + aErrorList.add (_createError ("PartyInfo/From[0]/@type must be '" + + DBNAlliancePMode.DEFAULT_PARTY_TYPE_ID + + "' instead of '" + + aFrom.getPartyIdAtIndex (0).getType () + + "'")); + } + } + } + + final Ebms3To aTo = aUserMsg.getPartyInfo ().getTo (); + if (aTo != null) + { + if (aTo.getPartyIdCount () > 1) + aErrorList.add (_createError ("PartyInfo/To must contain no more than one PartyID")); + else + if (aTo.getPartyIdCount () == 1) + { + if (!DBNAlliancePMode.DEFAULT_PARTY_TYPE_ID.equals (aTo.getPartyIdAtIndex (0).getType ())) + { + aErrorList.add (_createError ("PartyInfo/To[0]/@type must be '" + + DBNAlliancePMode.DEFAULT_PARTY_TYPE_ID + + "' instead of '" + + aTo.getPartyIdAtIndex (0).getType () + + "'")); + } + } + } + } + + if (aUserMsg.getCollaborationInfo () == null) + { + aErrorList.add (_createError ("CollaborationInfo is missing")); + } + else + { + final Ebms3AgreementRef aAgreementRef = aUserMsg.getCollaborationInfo ().getAgreementRef (); + if (aAgreementRef == null) + { + aErrorList.add (_createError ("CollaborationInfo/AgreementRef is missing")); + } + else + { + if (!DBNAlliancePMode.DEFAULT_AGREEMENT_ID.equals (aAgreementRef.getValue ())) + aErrorList.add (_createError ("CollaborationInfo/AgreementRef must be '" + + DBNAlliancePMode.DEFAULT_AGREEMENT_ID + + "' instead of '" + + aAgreementRef.getValue () + + "'")); + + if (StringHelper.hasText (aAgreementRef.getType ())) + aErrorList.add (_createError ("CollaborationInfo/AgreementRef/@type must not be set")); + } + } + } + + public void validateSignalMessage (@Nonnull final Ebms3SignalMessage aSignalMsg, @Nonnull final ErrorList aErrorList) + { + ValueEnforcer.notNull (aSignalMsg, "SignalMsg"); + + if (aSignalMsg.getMessageInfo () == null) + { + aErrorList.add (_createError ("MessageInfo is missing")); + } + else + { + if (StringHelper.hasNoText (aSignalMsg.getMessageInfo ().getMessageId ())) + aErrorList.add (_createError ("MessageID is missing but is mandatory!")); + } + } +} diff --git a/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/DBNAlliancePMode.java b/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/DBNAlliancePMode.java new file mode 100644 index 000000000..550d20ae7 --- /dev/null +++ b/phase4-profile-dbnalliance/src/main/java/com/helger/phase4/profile/dbnalliance/DBNAlliancePMode.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2023 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.profile.dbnalliance; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +import com.helger.commons.CGlobal; +import com.helger.commons.annotation.Nonempty; +import com.helger.commons.state.ETriState; +import com.helger.phase4.CAS4; +import com.helger.phase4.crypto.ECryptoAlgorithmCrypt; +import com.helger.phase4.crypto.ECryptoAlgorithmSign; +import com.helger.phase4.crypto.ECryptoAlgorithmSignDigest; +import com.helger.phase4.mgr.MetaAS4Manager; +import com.helger.phase4.model.EMEP; +import com.helger.phase4.model.EMEPBinding; +import com.helger.phase4.model.pmode.IPModeIDProvider; +import com.helger.phase4.model.pmode.PMode; +import com.helger.phase4.model.pmode.PModeParty; +import com.helger.phase4.model.pmode.PModePayloadService; +import com.helger.phase4.model.pmode.PModeReceptionAwareness; +import com.helger.phase4.model.pmode.leg.EPModeSendReceiptReplyPattern; +import com.helger.phase4.model.pmode.leg.PModeAddressList; +import com.helger.phase4.model.pmode.leg.PModeLeg; +import com.helger.phase4.model.pmode.leg.PModeLegBusinessInformation; +import com.helger.phase4.model.pmode.leg.PModeLegErrorHandling; +import com.helger.phase4.model.pmode.leg.PModeLegProtocol; +import com.helger.phase4.model.pmode.leg.PModeLegReliability; +import com.helger.phase4.model.pmode.leg.PModeLegSecurity; +import com.helger.phase4.soap.ESoapVersion; +import com.helger.phase4.wss.EWSSVersion; + +/** + * DBNAlliance PMode creation code. + * + * @author Philip Helger + * @author Michael Riviera + */ +@Immutable +public final class DBNAlliancePMode +{ + public static final String DEFAULT_AGREEMENT_ID = "https://dbnalliance.org/agreements/access_point.html"; + public static final String DEFAULT_PARTY_TYPE_ID = "http://docs.oasis-open.org/bdxr/AS4/1"; + + private DBNAlliancePMode () + {} + + @Nonnull + public static PModeLegProtocol generatePModeLegProtocol (@Nullable final String sAddress) + { + // Set the endpoint URL + return new PModeLegProtocol (sAddress, ESoapVersion.SOAP_12); + } + + @Nonnull + public static PModeLegBusinessInformation generatePModeLegBusinessInformation () + { + // dynamic + final String sService = null; + // dynamic + final String sAction = null; + final Long nPayloadProfileMaxKB = null; + final String sMPCID = CAS4.DEFAULT_MPC_ID; + return PModeLegBusinessInformation.create (sService, sAction, nPayloadProfileMaxKB, sMPCID); + } + + @Nonnull + public static PModeLegErrorHandling generatePModeLegErrorHandling () + { + final PModeAddressList aReportSenderErrorsTo = null; + final PModeAddressList aReportReceiverErrorsTo = null; + final ETriState eReportAsResponse = ETriState.TRUE; + final ETriState eReportProcessErrorNotifyConsumer = ETriState.TRUE; + final ETriState eReportProcessErrorNotifyProducer = ETriState.TRUE; + // Called Report.MissingReceiptNotifyProducer in DBNAlliance + final ETriState eReportDeliveryFailuresNotifyProducer = ETriState.TRUE; + return new PModeLegErrorHandling (aReportSenderErrorsTo, + aReportReceiverErrorsTo, + eReportAsResponse, + eReportProcessErrorNotifyConsumer, + eReportProcessErrorNotifyProducer, + eReportDeliveryFailuresNotifyProducer); + } + + @Nonnull + public static PModeLegSecurity generatePModeLegSecurity () + { + final PModeLegSecurity aPModeLegSecurity = new PModeLegSecurity (); + aPModeLegSecurity.setWSSVersion (EWSSVersion.WSS_111); + aPModeLegSecurity.setX509SignatureAlgorithm (ECryptoAlgorithmSign.RSA_SHA_256); + aPModeLegSecurity.setX509SignatureHashFunction (ECryptoAlgorithmSignDigest.DIGEST_SHA_256); + aPModeLegSecurity.setX509EncryptionAlgorithm (ECryptoAlgorithmCrypt.AES_256_GCM); + // Minimum Strength is not used + aPModeLegSecurity.setPModeAuthorize (false); + aPModeLegSecurity.setSendReceipt (true); + aPModeLegSecurity.setSendReceiptNonRepudiation (true); + aPModeLegSecurity.setSendReceiptReplyPattern (EPModeSendReceiptReplyPattern.RESPONSE); + return aPModeLegSecurity; + } + + @Nonnull + public static PModeLeg generatePModeLeg (@Nullable final String sAddress) + { + return new PModeLeg (generatePModeLegProtocol (sAddress), + generatePModeLegBusinessInformation (), + generatePModeLegErrorHandling (), + (PModeLegReliability) null, + generatePModeLegSecurity ()); + } + + @Nonnull + public static PModeReceptionAwareness generatePModeReceptionAwareness () + { + final ETriState eReceptionAwareness = ETriState.TRUE; + final ETriState eRetry = ETriState.TRUE; + final int nMaxRetries = 5; + final long nRetryIntervalMS = (CGlobal.SECONDS_PER_HOUR * 6 / nMaxRetries) * CGlobal.MILLISECONDS_PER_SECOND; + final ETriState eDuplicateDetection = ETriState.TRUE; + return new PModeReceptionAwareness (eReceptionAwareness, + eRetry, + nMaxRetries, + nRetryIntervalMS, + eDuplicateDetection); + } + + @Nonnull + public static PModeParty createParty (@Nonnull @Nonempty final String sPartyID, @Nonnull @Nonempty final String sRole) + { + // Party type is needed for DBNAlliance + return new PModeParty (DEFAULT_PARTY_TYPE_ID, sPartyID, sRole, null, null); + } + + /** + * One-Way Version of the DBNAlliance pmode uses one-way push + * + * @param sInitiatorID + * Initiator ID. May neither be null nor empty. + * @param sResponderID + * Responder ID. May neither be null nor empty. + * @param sAddress + * Endpoint address URL. May be null. + * @param aPModeIDProvider + * PMode ID provider. May not be null. + * @param bPersist + * true to persist the PMode in the PModeManager, + * false to have it only in memory. + * @return New PMode + */ + @Nonnull + public static PMode createDBNAlliancePMode (@Nonnull @Nonempty final String sInitiatorID, + @Nonnull @Nonempty final String sResponderID, + @Nullable final String sAddress, + @Nonnull final IPModeIDProvider aPModeIDProvider, + final boolean bPersist) + { + final PModeParty aInitiator = createParty (sInitiatorID, CAS4.DEFAULT_INITIATOR_URL); + final PModeParty aResponder = createParty (sResponderID, CAS4.DEFAULT_RESPONDER_URL); + + final PMode aPMode = new PMode (aPModeIDProvider.getPModeID (aInitiator, aResponder), + aInitiator, + aResponder, + DEFAULT_AGREEMENT_ID, + EMEP.ONE_WAY, + EMEPBinding.PUSH, + generatePModeLeg (sAddress), + (PModeLeg) null, + (PModePayloadService) null, + generatePModeReceptionAwareness ()); + // Leg 2 stays null, because we only use one-way + // By default no compression active + + if (bPersist) + { + // Ensure it is stored + MetaAS4Manager.getPModeMgr ().createOrUpdatePMode (aPMode); + } + return aPMode; + } +} diff --git a/phase4-profile-dbnalliance/src/main/resources/LICENSE b/phase4-profile-dbnalliance/src/main/resources/LICENSE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/phase4-profile-dbnalliance/src/main/resources/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + diff --git a/phase4-profile-dbnalliance/src/main/resources/META-INF/services/com.helger.phase4.profile.IAS4ProfileRegistrarSPI b/phase4-profile-dbnalliance/src/main/resources/META-INF/services/com.helger.phase4.profile.IAS4ProfileRegistrarSPI new file mode 100644 index 000000000..3d8a45817 --- /dev/null +++ b/phase4-profile-dbnalliance/src/main/resources/META-INF/services/com.helger.phase4.profile.IAS4ProfileRegistrarSPI @@ -0,0 +1 @@ +com.helger.phase4.profile.dbnalliance.AS4DBNAllianceProfileRegistarSPI diff --git a/phase4-profile-dbnalliance/src/main/resources/NOTICE b/phase4-profile-dbnalliance/src/main/resources/NOTICE new file mode 100644 index 000000000..6b30bbfce --- /dev/null +++ b/phase4-profile-dbnalliance/src/main/resources/NOTICE @@ -0,0 +1,5 @@ +============================================================================= += NOTICE file corresponding to section 4d of the Apache License Version 2.0 = +============================================================================= +This product includes Open Source Software developed by +Philip Helger - https://www.helger.com/ diff --git a/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/DBNAllianceCompatibilityValidatorTest.java b/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/DBNAllianceCompatibilityValidatorTest.java new file mode 100644 index 000000000..735dcd7cd --- /dev/null +++ b/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/DBNAllianceCompatibilityValidatorTest.java @@ -0,0 +1,462 @@ +/* + * Copyright (C) 2023 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.profile.dbnalliance; + +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertTrue; + +import java.util.Locale; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; + +import com.helger.commons.error.list.ErrorList; +import com.helger.commons.state.ETriState; +import com.helger.phase4.crypto.ECryptoAlgorithmCrypt; +import com.helger.phase4.crypto.ECryptoAlgorithmSign; +import com.helger.phase4.crypto.ECryptoAlgorithmSignDigest; +import com.helger.phase4.ebms3header.Ebms3From; +import com.helger.phase4.ebms3header.Ebms3MessageInfo; +import com.helger.phase4.ebms3header.Ebms3PartyId; +import com.helger.phase4.ebms3header.Ebms3PartyInfo; +import com.helger.phase4.ebms3header.Ebms3SignalMessage; +import com.helger.phase4.ebms3header.Ebms3To; +import com.helger.phase4.ebms3header.Ebms3UserMessage; +import com.helger.phase4.messaging.domain.MessageHelperMethods; +import com.helger.phase4.model.EMEP; +import com.helger.phase4.model.EMEPBinding; +import com.helger.phase4.model.pmode.IPModeIDProvider; +import com.helger.phase4.model.pmode.PMode; +import com.helger.phase4.model.pmode.leg.EPModeSendReceiptReplyPattern; +import com.helger.phase4.model.pmode.leg.PModeLeg; +import com.helger.phase4.model.pmode.leg.PModeLegErrorHandling; +import com.helger.phase4.model.pmode.leg.PModeLegProtocol; +import com.helger.phase4.model.pmode.leg.PModeLegSecurity; +import com.helger.phase4.soap.ESoapVersion; +import com.helger.phase4.wss.EWSSVersion; +import com.helger.photon.app.mock.PhotonAppWebTestRule; + +/** + * All essentials need to be set and need to be not null since they are getting + * checked, when a PMode is introduced into the system and these null checks + * would be redundant in the profiles. + * + * @author Philip Helger + */ +public final class DBNAllianceCompatibilityValidatorTest +{ + @ClassRule + public static final PhotonAppWebTestRule RULE = new PhotonAppWebTestRule (); + + private static final Locale LOCALE = Locale.US; + private static final DBNAllianceCompatibilityValidator VALIDATOR = new DBNAllianceCompatibilityValidator (); + + private PMode m_aPMode; + private ErrorList m_aErrorList; + + @Before + public void before () + { + m_aErrorList = new ErrorList (); + m_aPMode = DBNAlliancePMode.createDBNAlliancePMode ("TestInitiator", + "TestResponder", + "http://localhost:8080", + IPModeIDProvider.DEFAULT_DYNAMIC, + true); + } + + @Test + public void testValidatePModeWrongMEP () + { + m_aPMode.setMEP (EMEP.TWO_WAY); + // Only 2-way push-push allowed + m_aPMode.setMEPBinding (EMEPBinding.PULL); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("MEP"))); + } + + @Test + public void testValidatePModeWrongMEPBinding () + { + // SYNC not allowed + m_aPMode.setMEPBinding (EMEPBinding.SYNC); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("MEP binding"))); + } + + @Test + public void testValidatePModeNoLeg () + { + m_aPMode.setLeg1 (null); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("PMode.Leg[1] is missing"))); + } + + @Test + public void testValidatePModeNoProtocol () + { + m_aPMode.setLeg1 (new PModeLeg (null, null, null, null, null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("Protocol is missing"))); + } + + @Test + @Ignore ("The response address is most of the time not set") + public void testValidatePModeNoProtocolAddress () + { + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion (null), null, null, null, null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("AddressProtocol is missing"))); + } + + @Test + public void testValidatePModeProtocolAddressIsNotHttp () + { + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("ftp://test.com"), + null, + null, + null, + null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("AddressProtocol 'ftp' is unsupported"))); + } + + @Test + public void testValidatePModeProtocolSOAP11NotAllowed () + { + m_aPMode.setLeg1 (new PModeLeg (new PModeLegProtocol ("https://test.com", + ESoapVersion.SOAP_11), + null, + null, + null, + null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("SoapVersion '1.1' is unsupported"))); + } + + @Test + @Ignore ("The X509 certificate is always null, as it is received from the SMP") + public void testValidatePModeSecurityNoX509SignatureCertificate () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setX509SignatureCertificate (null); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + PModeLegErrorHandling.createUndefined (), + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("X509SignatureCertificate is missing"))); + } + + @Test + public void testValidatePModeSecurityNoX509SignatureAlgorithm () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setX509SignatureAlgorithm (null); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + PModeLegErrorHandling.createUndefined (), + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("X509SignatureAlgorithm is missing"))); + } + + @Test + public void testValidatePModeSecurityWrongX509SignatureAlgorithm () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setX509SignatureAlgorithm (ECryptoAlgorithmSign.RSA_SHA_384); + assertNotSame (ECryptoAlgorithmSign.RSA_SHA_256, aSecurityLeg.getX509SignatureAlgorithm ()); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains (ECryptoAlgorithmSign.RSA_SHA_256.getID ()))); + } + + @Test + public void testValidatePModeSecurityNoX509SignatureHashFunction () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setX509SignatureHashFunction (null); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("X509SignatureHashFunction is missing"))); + } + + @Test + public void testValidatePModeSecurityWrongX509SignatureHashFunction () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setX509SignatureHashFunction (ECryptoAlgorithmSignDigest.DIGEST_SHA_512); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains (ECryptoAlgorithmSignDigest.DIGEST_SHA_256.getID ()))); + } + + @Test + public void testValidatePModeSecurityNoX509EncryptionAlgorithm () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setX509EncryptionAlgorithm (null); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("X509EncryptionAlgorithm is missing"))); + } + + @Test + public void testValidatePModeSecurityWrongX509EncryptionAlgorithm () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setX509EncryptionAlgorithm (ECryptoAlgorithmCrypt.AES_192_CBC); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains (ECryptoAlgorithmCrypt.AES_256_GCM.getID ()))); + } + + @SuppressWarnings ("deprecation") + @Test + public void testValidatePModeSecurityWrongWSSVersion () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setWSSVersion (EWSSVersion.WSS_10); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("Security.WSSVersion must use the value WSS_111 instead of WSS_10"))); + } + + @Test + public void testValidatePModeSecurityPModeAuthorizeMandatory () + { + m_aPMode.getLeg1 ().getSecurity ().setPModeAuthorize (ETriState.UNDEFINED); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue ("Errors: " + m_aErrorList.toString (), + m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("Security.PModeAuthorize is missing"))); + } + + @Test + public void testValidatePModeSecurityPModeAuthorizeTrue () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setPModeAuthorize (true); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("false"))); + } + + @Test + public void testValidatePModeSecurityResponsePatternWrongBoolean () + { + final PModeLegSecurity aSecurityLeg = m_aPMode.getLeg1 ().getSecurity (); + aSecurityLeg.setSendReceipt (true); + aSecurityLeg.setSendReceiptReplyPattern (EPModeSendReceiptReplyPattern.CALLBACK); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + aSecurityLeg)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("Security.SendReceiptReplyPattern must use the value RESPONSE instead of CALLBACK"))); + } + + // Error Handling + + @Test + public void testValidatePModeErrorHandlingMandatory () + { + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + null, + null, + null)); + + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("PMode.Leg[1].ErrorHandling is missing"))); + } + + @Test + public void testValidatePModeErrorHandlingReportAsResponseMandatory () + { + final PModeLegErrorHandling aErrorHandler = PModeLegErrorHandling.createUndefined (); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + aErrorHandler, + null, + null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("ErrorHandling.Report.AsResponse is missing"))); + } + + @Test + public void testValidatePModeErrorHandlingReportAsResponseWrongValue () + { + final PModeLegErrorHandling aErrorHandler = PModeLegErrorHandling.createUndefined (); + aErrorHandler.setReportAsResponse (false); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + aErrorHandler, + null, + null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("ErrorHandling.Report.AsResponse must be 'true'"))); + } + + @Test + public void testValidatePModeErrorHandlingReportProcessErrorNotifyConsumerMandatory () + { + final PModeLegErrorHandling aErrorHandler = PModeLegErrorHandling.createUndefined (); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + aErrorHandler, + null, + null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("ErrorHandling.Report.ProcessErrorNotifyConsumer is missing"))); + } + + @Test + public void testValidatePModeErrorHandlingReportProcessErrorNotifyConsumerWrongValue () + { + final PModeLegErrorHandling aErrorHandler = PModeLegErrorHandling.createUndefined (); + aErrorHandler.setReportProcessErrorNotifyConsumer (false); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + aErrorHandler, + null, + null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("ErrorHandling.Report.ProcessErrorNotifyConsumer should be 'true'"))); + } + + @Test + public void testValidatePModeErrorHandlingReportDeliveryFailuresNotifyProducerMandatory () + { + final PModeLegErrorHandling aErrorHandler = PModeLegErrorHandling.createUndefined (); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + aErrorHandler, + null, + null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("ErrorHandling.Report.ProcessErrorNotifyProducer is missing"))); + } + + @Test + public void testValidatePModeErrorHandlingReportDeliveryFailuresNotifyProducerWrongValue () + { + final PModeLegErrorHandling aErrorHandler = PModeLegErrorHandling.createUndefined (); + aErrorHandler.setReportProcessErrorNotifyProducer (false); + m_aPMode.setLeg1 (new PModeLeg (PModeLegProtocol.createForDefaultSoapVersion ("http://test.example.org"), + null, + aErrorHandler, + null, + null)); + VALIDATOR.validatePMode (m_aPMode, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("ErrorHandling.Report.ProcessErrorNotifyProducer should be 'true'"))); + } + + @Test + public void testValidateUserMessageNoMessageID () + { + final Ebms3UserMessage aUserMessage = new Ebms3UserMessage (); + aUserMessage.setMessageInfo (new Ebms3MessageInfo ()); + VALIDATOR.validateUserMessage (aUserMessage, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("MessageInfo/MessageId is missing"))); + } + + @Test + public void testValidateUserMessageMoreThanOnePartyID () + { + final Ebms3PartyId aFirstId = MessageHelperMethods.createEbms3PartyId ("type", "value"); + final Ebms3PartyId aSecondId = MessageHelperMethods.createEbms3PartyId ("type2", "value2"); + + final Ebms3From aFromPart = new Ebms3From (); + aFromPart.addPartyId (aFirstId); + aFromPart.addPartyId (aSecondId); + final Ebms3To aToPart = new Ebms3To (); + aToPart.addPartyId (aFirstId); + aToPart.addPartyId (aSecondId); + final Ebms3PartyInfo aPartyInfo = new Ebms3PartyInfo (); + aPartyInfo.setFrom (aFromPart); + aPartyInfo.setTo (aToPart); + + final Ebms3UserMessage aUserMessage = new Ebms3UserMessage (); + aUserMessage.setPartyInfo (aPartyInfo); + + VALIDATOR.validateUserMessage (aUserMessage, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE) + .contains ("must contain no more than one PartyID"))); + } + + @Test + public void testValidateSignalMessageNoMessageID () + { + final Ebms3SignalMessage aSignalMessage = new Ebms3SignalMessage (); + aSignalMessage.setMessageInfo (new Ebms3MessageInfo ()); + VALIDATOR.validateSignalMessage (aSignalMessage, m_aErrorList); + assertTrue (m_aErrorList.containsAny (x -> x.getErrorText (LOCALE).contains ("MessageID is missing"))); + } +} diff --git a/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/DBNAlliancePModeTest.java b/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/DBNAlliancePModeTest.java new file mode 100644 index 000000000..6e8b2daf3 --- /dev/null +++ b/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/DBNAlliancePModeTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 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.profile.dbnalliance; + +import static org.junit.Assert.assertNotNull; + +import org.junit.ClassRule; +import org.junit.Test; + +import com.helger.phase4.model.pmode.IPModeIDProvider; +import com.helger.phase4.model.pmode.PMode; +import com.helger.photon.app.mock.PhotonAppWebTestRule; + +/** + * Test class for class {@link DBNAlliancePMode}. + * + * @author Philip Helger + */ +public final class DBNAlliancePModeTest +{ + @ClassRule + public static final PhotonAppWebTestRule RULE = new PhotonAppWebTestRule (); + + @Test + public void testDBNAlliancePMode () + { + final PMode aPMode = DBNAlliancePMode.createDBNAlliancePMode ("TestInitiator", + "TestResponder", + "https://test.example.org", + IPModeIDProvider.DEFAULT_DYNAMIC, + false); + assertNotNull (aPMode); + } +} diff --git a/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/SPITest.java b/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/SPITest.java new file mode 100644 index 000000000..8a7cf96ab --- /dev/null +++ b/phase4-profile-dbnalliance/src/test/java/com/helger/phase4/profile/dbnalliance/SPITest.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 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.profile.dbnalliance; + +import org.junit.Test; + +import com.helger.commons.mock.SPITestHelper; + +/** + * Test SPI definitions + * + * @author Pavel Rotek + */ +public final class SPITest +{ + @Test + public void testBasic () throws Exception + { + SPITestHelper.testIfAllSPIImplementationsAreValid (); + } +} diff --git a/pom.xml b/pom.xml index 2ebba0316..26f749a61 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ Base POM to build the phase4 projects https://github.com/phax/phase4 2015 - + Apache 2 @@ -240,6 +240,11 @@ phase4-profile-cef ${project.version} + + com.helger.phase4 + phase4-profile-dbnalliance + ${project.version} + com.helger.phase4 phase4-profile-eespa @@ -309,6 +314,7 @@ phase4-profile-bdew phase4-profile-bpc phase4-profile-cef + phase4-profile-dbnalliance phase4-profile-eespa phase4-profile-entsog phase4-profile-peppol @@ -335,6 +341,7 @@ phase4-profile-bdew phase4-profile-bpc phase4-profile-cef + phase4-profile-dbnalliance phase4-profile-eespa phase4-profile-entsog phase4-profile-peppol