Open ErrorCode-404 opened 7 months ago
@ErrorCode-404 I hope you previously had a look at https://github.com/phax/phase4/wiki/Profile-BDEW and saw that phase4 does not work with BDEW out of the box and that you need implement a custom key exchange (which is kind of a pain in the a...).
For the client it is recommended to use ther phase4-bdew-client
submodule that ships with a decent Phase4BDEWSender.builder()
to assemble and send the message in a decent way. I assume you need to fill .action()
and .service()
manually. Via sendMessageAndCheckForReceipt
of the builder you can send the AS4 user message and check the returned AS4 SignalMessage.
Unfortunately I am myself not involved in the BDEW implementations, so I cannot give other then general advice
Thank you for your response. I already have checked the docu and also brought the basic communication between a sender and a receiver to work. I used the Phase4BDEWSender.builder()
like below:
Phase4BDEWSender.builder()
//Communication Configs
.endpointURL("http://localhost:8080/as4")
.encryptionKeyIdentifierType(ECryptoKeyIdentifierType.X509_KEY_IDENTIFIER)
.signingKeyIdentifierType(ECryptoKeyIdentifierType.BST_DIRECT_REFERENCE)
//----MessageInfo----
.messageID(UUID.randomUUID().toString())
//----PartyInfo----
.fromPartyIDType("urn:oasis:names:tc:ebcore:partyid-type:iso6523:0088")
.fromPartyID("myCompany")
.fromRole(CAS4.DEFAULT_INITIATOR_URL)
.toPartyIDType("urn:oasis:names:tc:ebcore:partyid-type:iso6523:0088")
.toPartyID("otherCompany")
.toRole(CAS4.DEFAULT_RESPONDER_URL)
//----PartyInfo----
//----CollaborationInfo----
.agreementRef("https://www.bdew.de/as4/communication/agreement")
.service("https://www.bdew.de/as4/communication/services/MP")
.action("http://docs.oasis-open.org/ebxml-msg/as4/200902/action")
//----CollaborationInfo----
//----PayloadInfo----
.payload(AS4OutgoingAttachment.builder()
.data(aPayloadBytes)
.compressionGZIP()
.mimeTypeXML()
.charset(StandardCharsets.UTF_8),
new BDEWPayloadParams()
.setDocumentType("MSCONS")
.setDocumentDate(PDTFactory.getCurrentLocalDate())
.setDocumentNumber("28198611A")
.setFulfillmentDate(PDTFactory.getCurrentLocalDate().minusMonths(2))
.setSubjectPartyId("123456")
.setSubjectPartyRole("MSCONS-AS4-Receiver"))
.sendMessageAndCheckForReceipt(e -> {
LOGGER.error("Error sending BDEW message via AS4", e);
});
After some more debugger investigations I saw that the UserMessage will be parsed and processed correctly with all the information I send.
So the problem lies in the pmode which will be created with default values (mostly constants which must be set according to the as4 profile) but not all fields will replaced with the values the sender sent.
With #187 there were added some validations for the pmode like the m_sServiceValue
in PModeLegBusinessInformation
.
Here the service is checked but is never set which leads to the problem above if a real client-receiver-communication happens.
Okay, that indeed is a tricky thing to comment without the actual code. My assumption is, that you have more then one AS4 profile in your build path (peppol and bdew) and therefore the automatic PMode detection fails. By removing "phase4-profile-peppol" from your build path may resolve the issue....
@ErrorCode-404 were you able to resolve the issue?
I only have this both dependencies in my project:
<dependency>
<groupId>com.helger.phase4</groupId>
<artifactId>phase4-lib</artifactId>
</dependency>
<dependency>
<groupId>com.helger.phase4</groupId>
<artifactId>phase4-profile-bdew</artifactId>
</dependency>
So there is only one profile at the same time. But I think I have found a kind of a workaround.
Okay, on the receiver side, when debugging, all the AS4 profiles should be contained in the manager class AS4ProfileManager
. If you could run a getAllProfiles()
you should get exactly 1 profile back. If you get anything else then 1, please let me know
Okay I can confirm that exactly one profile (bdew) will be registered.
The problem is indeed the validation of the determined PMode and not of the UserMessage, The PMode is resolved based on the incoming message. There is a way to circumvent the PMode validation, but it is a bit tedious:
AS4RequestHandler.setIncomingProfileSelector (...)
IHandlerCustomizer
that you need to pass into the AS4XServletHandler
So in the SpringBoot example code, class ServletConfig
add this snippet and the validation should be offline:
hdl.setHandlerCustomizer (new IHandlerCustomizer ()
{
public void customizeBeforeHandling (@Nonnull final IRequestWebScopeWithoutResponse aRequestScope,
@Nonnull final AS4UnifiedResponse aUnifiedResponse,
@Nonnull final AS4RequestHandler aHandler)
{
aHandler.setIncomingProfileSelector (new AS4IncomingProfileSelectorFromGlobal ()
{
public boolean validateAgainstProfile ()
{
// override;
return false;
}
});
}
});
Edit: with final AS4XServletHandler hdl = new AS4XServletHandler ();
Without looking at your code I don't know how to resolve this, as PModeResolution can be quite tricky, also depending on the PModeManager you chose/implemented
Hi I have posted my code below:
@Configuration
public class ServletConfig {
@Bean
public ServletRegistrationBean<AS4BDEWServlet> registerAS4BDWEWServlet(final ServletContext servletContext) {
init(servletContext);
final AS4BDEWServlet servlet = new AS4BDEWServlet();
ServletRegistrationBean<AS4BDEWServlet> bean = new ServletRegistrationBean<>(servlet, true, "as4");
bean.setLoadOnStartup(1);
return bean;
}
private void init(final ServletContext servletContext) {
// Do it only once
if (!WebScopeManager.isGlobalScopePresent()) {
WebScopeManager.onGlobalBegin(servletContext);
initGlobalSettings(servletContext);
initAS4();
}
}
/**
* This method is used to initialize the global settings for the application.
*
* @param servletContext The servlet context of the application.
*/
private void initGlobalSettings(@Nonnull final ServletContext servletContext) {
// Logging: JUL to SLF4J
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
if (GlobalDebug.isDebugMode()) {
RequestTrackerSettings.setLongRunningRequestsCheckEnabled(false);
RequestTrackerSettings.setParallelRunningRequestsCheckEnabled(false);
HttpDebugger.setEnabled(false);
}
// Sanity check
if (CommandMap.getDefaultCommandMap().createDataContentHandler(CMimeType.MULTIPART_RELATED.getAsString()) ==
null) {
throw new IllegalStateException("No DataContentHandler for MIME Type '" +
CMimeType.MULTIPART_RELATED.getAsString() +
"' is available. There seems to be a problem with the dependencies/packaging");
}
// Init the data path
{
// Get the ServletContext base path
final String sServletContextPath = ServletHelper.getServletContextBasePath (servletContext);
// Get the data path
final String sDataPath = AS4Configuration.getDataPath ();
if (StringHelper.hasNoText (sDataPath))
throw new InitializationException ("No data path was provided!");
final boolean bFileAccessCheck = false;
// Init the IO layer
WebFileIO.initPaths (new File (sDataPath).getAbsoluteFile (), sServletContextPath, bFileAccessCheck);
}
}
private void initAS4() {
AS4ProfileSelector.setCustomAS4ProfileID(AS4BDEWProfileRegistarSPI.AS4_PROFILE_ID);
AS4ServerInitializer.initAS4Server();
}
public static IAS4CryptoFactory getCryptoFactoryToUse() {
// If you have a custom crypto factory, build/return it here
return AS4CryptoFactoryProperties.getDefaultInstance();
}
}
public class AS4BDEWServlet extends AbstractXServlet {
public AS4BDEWServlet() {
AS4DumpManager.setIncomingDumper(new AS4IncomingDumperFileBased());
AS4DumpManager.setOutgoingDumper(new AS4OutgoingDumperFileBased());
// Multipart is handled specifically inside
settings().setMultipartEnabled(false);
final AS4XServletHandler as4ServletHandler = new AS4XServletHandler();
as4ServletHandler.setHandlerCustomizer((aRequestScope, aUnifiedResponse, aHandler)->{
aHandler.setIncomingProfileSelector(new AS4IncomingProfileSelectorFromGlobal(){
@Override
public boolean validateAgainstProfile() {
return false;
}
});
});
as4ServletHandler.setCryptoFactorySupplier(ServletConfig::getCryptoFactoryToUse);
handlerRegistry().registerHandler(EHttpMethod.POST, as4ServletHandler);
}
}
Thats my current setup and I also added your suggestion. And indeed I can confirm that I now can receive messages without any error and the sender gets back a response. But If I see it right your code means that validation against the profile will be disabled entirely. Correct?
Yes, that is correct :-/ And I don't see an obvious flaw in your code....
Well unfortunately the deactivation of the validation against the profile doesn't solves the problem.
I still think that the error will be caused through the validator of the bdew profile. There the PModeLegBusinessInformation
or more precisely the service and action will be checked against the constants given in the BDEWPMode
.
But the PModeLegBusinessInformation
was not filled with all PMode relevant data when a user message is received.
On the other side the received Ebms3UserMessage
has all the data set in the Ebms3CollaborationInfo
like service and action. So maybe the data which should be validated are more likely to find in the user message and not in the PMode.
Hmm, this is really a pitty. I am really curious what's going and would like to ask, if you are willing for a quick screensharing session, so that we can "pair debug" :) If that sounds interesting for you, you find my email address in the pom.xml of this project - just let me know your timezone and we will figure something out....
@ErrorCode-404 were you able to resolve the issue in the meantime?
Hello guys thank you for this awesome as4 library.
I maybe have encountered an problem which I don't know how to handle it. First of all I am using this library to implement an as4 receiver with the bdew profile. Therefore i have created an simple springboot project according to the given springboot peppol example but with bdew support. On the other side I am using the bdew client project in this repo which sends messages to the spring boot as4 receiver.
After some required configs (keystore, message content) the client can send as4 messages to the receiver. But the receiver checks the parsed message and pmode and I get the following error:
PMode.Leg[1].BusinessInfo.Service 'null' is unsupported This comes from the BDEWCompatibilityValidator which does some validation.
After an inspection with the debugger it seems that the property serviceValue in the businessInfo is null which may be the cause of the error.
After further inspection of the code I saw that there will be created a default pmode (BDEWPMode in this case)
If you compare these defaults with the debugger output you can see that the values in the debugger are still the same. I have expected that the values like serviceValue will be exactly that what the client has send (e.g. "https://www.bdew.de/as4/communication/services/MP") but that is not the case.
Does the library does not extract those information or do I have an error in my thinking?