use of com.helger.phase4.ebms3header.Ebms3Error in project phase4 by phax.
the class AS4IncomingHandler method _parseMessage.
@Nullable
private static IAS4MessageState _parseMessage(@Nonnull final IAS4CryptoFactory aCryptoFactory, @Nonnull final IPModeResolver aPModeResolver, @Nonnull final IAS4IncomingAttachmentFactory aIAF, @Nonnull final IAS4IncomingProfileSelector aAS4ProfileSelector, @Nonnull @WillNotClose final AS4ResourceHelper aResHelper, @Nullable final IPMode aSendingPMode, @Nonnull final Locale aLocale, @Nonnull final IAS4IncomingMessageMetadata aMessageMetadata, @Nonnull final HttpResponse aHttpResponse, @Nonnull final byte[] aResponsePayload, @Nullable final IAS4IncomingDumper aIncomingDumper) throws Phase4Exception {
// This wrapper will take the result
final Wrapper<IAS4MessageState> aRetWrapper = new Wrapper<>();
// Handler for the parsed message
final IAS4ParsedMessageCallback aCallback = (aHttpHeaders, aSoapDocument, eSoapVersion, aIncomingAttachments) -> {
final ICommonsList<Ebms3Error> aErrorMessages = new CommonsArrayList<>();
// Use the sending PMode as fallback, because from the incoming
// receipt/error it is impossible to detect a PMode
final SOAPHeaderElementProcessorRegistry aRegistry = SOAPHeaderElementProcessorRegistry.createDefault(aPModeResolver, aCryptoFactory, aSendingPMode);
// Parse AS4, verify signature etc
final IAS4MessageState aState = processEbmsMessage(aResHelper, aLocale, aRegistry, aHttpHeaders, aSoapDocument, eSoapVersion, aIncomingAttachments, aAS4ProfileSelector, aErrorMessages);
if (aState.isSoapHeaderElementProcessingSuccessful()) {
// Remember the parsed signal message
aRetWrapper.set(aState);
} else {
throw new Phase4Exception("Error processing AS4 message", aState.getSoapWSS4JException());
}
};
// Create header map from response headers
final HttpHeaderMap aHttpHeaders = new HttpHeaderMap();
for (final Header aHeader : aHttpResponse.getAllHeaders()) aHttpHeaders.addHeader(aHeader.getName(), aHeader.getValue());
try (final NonBlockingByteArrayInputStream aPayloadIS = new NonBlockingByteArrayInputStream(aResponsePayload)) {
// Parse incoming message
parseAS4Message(aIAF, aResHelper, aMessageMetadata, aPayloadIS, aHttpHeaders, aCallback, aIncomingDumper);
} catch (final Phase4Exception ex) {
throw ex;
} catch (final Exception ex) {
throw new Phase4Exception("Error parsing AS4 message", ex);
}
// This one contains the result
return aRetWrapper.get();
}
use of com.helger.phase4.ebms3header.Ebms3Error in project phase4 by phax.
the class AS4IncomingHandler method processEbmsMessage.
@Nonnull
public static IAS4MessageState processEbmsMessage(@Nonnull @WillNotClose final AS4ResourceHelper aResHelper, @Nonnull final Locale aLocale, @Nonnull final SOAPHeaderElementProcessorRegistry aRegistry, @Nonnull final HttpHeaderMap aHttpHeaders, @Nonnull final Document aSoapDocument, @Nonnull final ESoapVersion eSoapVersion, @Nonnull final ICommonsList<WSS4JAttachment> aIncomingAttachments, @Nonnull final IAS4IncomingProfileSelector aAS4ProfileSelector, @Nonnull final ICommonsList<Ebms3Error> aErrorMessagesTarget) throws Phase4Exception {
ValueEnforcer.notNull(aResHelper, "ResHelper");
ValueEnforcer.notNull(aLocale, "Locale");
ValueEnforcer.notNull(aHttpHeaders, "HttpHeaders");
ValueEnforcer.notNull(aSoapDocument, "SoapDocument");
ValueEnforcer.notNull(eSoapVersion, "SoapVersion");
ValueEnforcer.notNull(aIncomingAttachments, "IncomingAttachments");
ValueEnforcer.notNull(aAS4ProfileSelector, "AS4ProfileSelector");
ValueEnforcer.notNull(aErrorMessagesTarget, "aErrorMessagesTarget");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Received the following SOAP " + eSoapVersion.getVersion() + " document:");
LOGGER.debug(AS4XMLHelper.serializeXML(aSoapDocument));
if (aIncomingAttachments.isEmpty()) {
LOGGER.debug("Without any incoming attachments");
} else {
LOGGER.debug("Including the following " + aIncomingAttachments.size() + " attachments:");
LOGGER.debug(aIncomingAttachments.toString());
}
}
// This is where all data from the SOAP headers is stored to
final AS4MessageState aState = new AS4MessageState(eSoapVersion, aResHelper, aLocale);
// Handle all headers - modifies the state
_processSoapHeaderElements(aRegistry, aSoapDocument, aIncomingAttachments, aState, aErrorMessagesTarget);
// Remember if header processing was successful or not
final boolean bSoapHeaderElementProcessingSuccess = aErrorMessagesTarget.isEmpty();
aState.setSoapHeaderElementProcessingSuccessful(bSoapHeaderElementProcessingSuccess);
if (bSoapHeaderElementProcessingSuccess) {
// Every message can only contain 1 User message or 1 pull message
// aUserMessage can be null on incoming Pull-Message!
final Ebms3UserMessage aEbmsUserMessage = aState.getEbmsUserMessage();
final Ebms3Error aEbmsError = aState.getEbmsError();
final Ebms3PullRequest aEbmsPullRequest = aState.getEbmsPullRequest();
final Ebms3Receipt aEbmsReceipt = aState.getEbmsReceipt();
// Check payload consistency
final int nCountData = (aEbmsUserMessage != null ? 1 : 0) + (aEbmsPullRequest != null ? 1 : 0) + (aEbmsReceipt != null ? 1 : 0) + (aEbmsError != null ? 1 : 0);
if (nCountData != 1) {
LOGGER.error("Expected a UserMessage(" + (aEbmsUserMessage != null ? 1 : 0) + "), a PullRequest(" + (aEbmsPullRequest != null ? 1 : 0) + "), a Receipt(" + (aEbmsReceipt != null ? 1 : 0) + ") or an Error(" + (aEbmsError != null ? 1 : 0) + ")");
// send EBMS:0001 error back
aErrorMessagesTarget.add(EEbmsError.EBMS_VALUE_NOT_RECOGNIZED.getAsEbms3Error(aLocale, aState.getMessageID()));
}
// Determine AS4 profile ID (since 0.13.0)
final String sProfileID = aAS4ProfileSelector.getAS4ProfileID(aState);
if (LOGGER.isDebugEnabled())
LOGGER.debug("Determined AS4 profile ID '" + sProfileID + "' for current message");
aState.setProfileID(sProfileID);
final IPMode aPMode = aState.getPMode();
final PModeLeg aEffectiveLeg = aState.getEffectivePModeLeg();
if (aEbmsUserMessage != null) {
// User message requires PMode
if (aPMode == null)
throw new Phase4Exception("No AS4 P-Mode configuration found for user-message!");
// Only check leg if the message is a usermessage
if (aEffectiveLeg == null)
throw new Phase4Exception("No AS4 P-Mode leg could be determined!");
// Only do profile checks if a profile is set
if (StringHelper.hasText(sProfileID)) {
// Resolve profile ID
final IAS4Profile aProfile = MetaAS4Manager.getProfileMgr().getProfileOfID(sProfileID);
if (aProfile == null)
throw new IllegalStateException("The configured AS4 profile '" + sProfileID + "' does not exist.");
// Profile Checks gets set when started with Server
final IAS4ProfileValidator aValidator = aProfile.getValidator();
if (aValidator != null) {
if (aAS4ProfileSelector.validateAgainstProfile()) {
final ErrorList aErrorList = new ErrorList();
aValidator.validatePMode(aPMode, aErrorList);
aValidator.validateUserMessage(aEbmsUserMessage, aErrorList);
if (aErrorList.isNotEmpty()) {
throw new Phase4Exception("Error validating incoming AS4 message with the profile " + aProfile.getDisplayName() + "\n Following errors are present: " + aErrorList.getAllErrors().getAllTexts(aLocale));
}
} else {
LOGGER.warn("The AS4 profile '" + sProfileID + "' has a validation configured, but the usage was disabled using the AS4ProfileSelector");
}
}
} else {
if (LOGGER.isDebugEnabled())
LOGGER.debug("AS4 state contains no AS4 profile ID - therefore no consistency checks are performed");
}
// Ensure the decrypted attachments are used
final ICommonsList<WSS4JAttachment> aDecryptedAttachments = aState.hasDecryptedAttachments() ? aState.getDecryptedAttachments() : aState.getOriginalAttachments();
// Decompress attachments (if compressed)
// Result is directly in the decrypted attachments list!
_decompressAttachments(aDecryptedAttachments, aEbmsUserMessage, aState);
} else {
// Pull-request also requires PMode
if (aEbmsPullRequest != null && aPMode == null)
throw new Phase4Exception("No AS4 P-Mode configuration found for pull-request!");
}
final boolean bUseDecryptedSOAP = aState.hasDecryptedSoapDocument();
final Document aRealSOAPDoc = bUseDecryptedSOAP ? aState.getDecryptedSoapDocument() : aSoapDocument;
assert aRealSOAPDoc != null;
// Find SOAP body (mandatory according to SOAP XSD)
final Node aBodyNode = XMLHelper.getFirstChildElementOfName(aRealSOAPDoc.getDocumentElement(), eSoapVersion.getNamespaceURI(), eSoapVersion.getBodyElementName());
if (aBodyNode == null)
throw new Phase4Exception((bUseDecryptedSOAP ? "Decrypted" : "Original") + " SOAP document is missing a Body element");
aState.setSoapBodyPayloadNode(aBodyNode.getFirstChild());
final boolean bIsPingMessage = AS4Helper.isPingMessage(aPMode);
aState.setPingMessage(bIsPingMessage);
if (bIsPingMessage)
LOGGER.info("Received an AS4 Ping message - meaning it will NOT be handled by the custom handlers.");
}
return aState;
}
use of com.helger.phase4.ebms3header.Ebms3Error in project phase4 by phax.
the class SOAPHeaderElementProcessorExtractEbms3Messaging method processHeaderElement.
@Nonnull
public ESuccess processHeaderElement(@Nonnull final Document aSOAPDoc, @Nonnull final Element aElement, @Nonnull final ICommonsList<WSS4JAttachment> aAttachments, @Nonnull final AS4MessageState aState, @Nonnull final ErrorList aErrorList) {
final IMPCManager aMPCMgr = MetaAS4Manager.getMPCMgr();
IPMode aPMode = null;
final ICommonsMap<String, EAS4CompressionMode> aCompressionAttachmentIDs = new CommonsHashMap<>();
IMPC aEffectiveMPC = null;
String sInitiatorID = null;
String sResponderID = null;
final Locale aLocale = aState.getLocale();
// Parse EBMS3 Messaging object
final CollectingValidationEventHandler aCVEH = new CollectingValidationEventHandler();
final Ebms3Messaging aMessaging = Ebms3ReaderBuilder.ebms3Messaging().setValidationEventHandler(aCVEH).read(aElement);
// wellformed
if (aMessaging == null) {
// Invalid Header == not wellformed/invalid xml
for (final IError aError : aCVEH.getErrorList()) {
LOGGER.error("Header error: " + aError.getAsString(aLocale));
aErrorList.add(SingleError.builder(aError).errorID(EEbmsError.EBMS_INVALID_HEADER.getErrorCode()).build());
}
return ESuccess.FAILURE;
}
// Remember in state
aState.setMessaging(aMessaging);
// 0 or 1 are allowed
final int nUserMessages = aMessaging.getUserMessageCount();
if (nUserMessages > 1) {
LOGGER.error("Too many UserMessage objects (" + nUserMessages + ") contained.");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
// 0 or 1 are allowed
final int nSignalMessages = aMessaging.getSignalMessageCount();
if (nSignalMessages > 1) {
LOGGER.error("Too many SignalMessage objects (" + nSignalMessages + ") contained.");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
if (nUserMessages + nSignalMessages == 0) {
// No Message was found
LOGGER.error("Neither UserMessage nor SignalMessage object contained.");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
// Check if the usermessage has a PMode in the collaboration info
final Ebms3UserMessage aUserMessage = CollectionHelper.getAtIndex(aMessaging.getUserMessage(), 0);
if (aUserMessage != null) {
final Ebms3MessageInfo aMsgInfo = aUserMessage.getMessageInfo();
if (aMsgInfo != null) {
// Set this is as early as possible, so that eventually occurring error
// messages can use the "RefToMessageId" element properly
aState.setMessageID(aMsgInfo.getMessageId());
aState.setRefToMessageID(aMsgInfo.getRefToMessageId());
aState.setMessageTimestamp(aMsgInfo.getTimestamp());
}
// PartyInfo is mandatory in UserMessage
// From is mandatory in PartyInfo
// To is mandatory in PartyInfo
final List<Ebms3PartyId> aFromPartyIdList = aUserMessage.getPartyInfo().getFrom().getPartyId();
final List<Ebms3PartyId> aToPartyIdList = aUserMessage.getPartyInfo().getTo().getPartyId();
if (aFromPartyIdList.size() > 1 || aToPartyIdList.size() > 1) {
LOGGER.error("More than one PartyId is containted in From or To Recipient please check the message.");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
// Setting Initiator and Responder id, Required values or else xsd will
// throw an error
sInitiatorID = aFromPartyIdList.get(0).getValue();
sResponderID = aToPartyIdList.get(0).getValue();
final Ebms3CollaborationInfo aCollaborationInfo = aUserMessage.getCollaborationInfo();
if (aCollaborationInfo != null) {
// Find PMode
String sPModeID = null;
String sAgreementRef = null;
if (aCollaborationInfo.getAgreementRef() != null) {
sPModeID = aCollaborationInfo.getAgreementRef().getPmode();
sAgreementRef = aCollaborationInfo.getAgreementRef().getValue();
}
// Get responder address from properties file (may be null)
final String sAddress = AS4Configuration.getThisEndpointAddress();
aPMode = m_aPModeResolver.getPModeOfID(sPModeID, aCollaborationInfo.getService().getValue(), aCollaborationInfo.getAction(), sInitiatorID, sResponderID, sAgreementRef, sAddress);
// Should be screened by the XSD conversion already
if (aPMode == null) {
LOGGER.error("Failed to resolve PMode '" + sPModeID + "' using resolver " + m_aPModeResolver);
aErrorList.add(EEbmsError.EBMS_PROCESSING_MODE_MISMATCH.getAsError(aLocale));
return ESuccess.FAILURE;
}
}
// to use the configuration for leg2
PModeLeg aPModeLeg1 = null;
PModeLeg aPModeLeg2 = null;
// Needed for the compression check: it is not allowed to have a
// compressed attachment and a SOAPBodyPayload
boolean bHasSoapBodyPayload = false;
if (aPMode != null) {
aPModeLeg1 = aPMode.getLeg1();
aPModeLeg2 = aPMode.getLeg2();
// both are present
if (aPMode.getMEPBinding().getRequiredLegs() == 2 && aPModeLeg2 == null) {
LOGGER.error("Error processing the UserMessage, PMode does not contain leg 2.");
aErrorList.add(EEbmsError.EBMS_PROCESSING_MODE_MISMATCH.getAsError(aLocale));
return ESuccess.FAILURE;
}
final boolean bUseLeg1 = _isUseLeg1(aUserMessage);
final PModeLeg aEffectiveLeg = bUseLeg1 ? aPModeLeg1 : aPModeLeg2;
final int nLegNum = bUseLeg1 ? 1 : 2;
if (aEffectiveLeg == null) {
LOGGER.error("Error processing the UserMessage, PMode does not contain effective leg " + nLegNum + ".");
aErrorList.add(EEbmsError.EBMS_PROCESSING_MODE_MISMATCH.getAsError(aLocale));
return ESuccess.FAILURE;
}
aState.setEffectivePModeLeg(nLegNum, aEffectiveLeg);
if (_checkMPCOfPMode(aEffectiveLeg, aMPCMgr, aLocale, aErrorList).isFailure())
return ESuccess.FAILURE;
bHasSoapBodyPayload = _checkSOAPBodyHasPayload(aEffectiveLeg, aSOAPDoc);
final String sEffectiveMPCID = _getMPCIDOfUserMsg(aUserMessage, aEffectiveLeg);
// PMode is valid
// Now Check if MPC valid
aEffectiveMPC = aMPCMgr.getMPCOrDefaultOfID(sEffectiveMPCID);
if (aEffectiveMPC == null) {
LOGGER.error("Error processing the UserMessage, effective MPC ID '" + sEffectiveMPCID + "' is unknown!");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
}
// Remember in state
aState.setSoapBodyPayloadPresent(bHasSoapBodyPayload);
final Ebms3PayloadInfo aEbms3PayloadInfo = aUserMessage.getPayloadInfo();
if (aEbms3PayloadInfo == null || aEbms3PayloadInfo.getPartInfo().isEmpty()) {
if (bHasSoapBodyPayload) {
LOGGER.error("No PayloadInfo/PartInfo is specified, so no SOAP body payload is allowed.");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
// attachments in the message
if (aAttachments.isNotEmpty()) {
LOGGER.error("No PayloadInfo/PartInfo is specified, so no attachments are allowed.");
aErrorList.add(EEbmsError.EBMS_EXTERNAL_PAYLOAD_ERROR.getAsError(aLocale));
return ESuccess.FAILURE;
}
} else {
// Check if there are more Attachments then specified
if (aAttachments.size() > aEbms3PayloadInfo.getPartInfoCount()) {
LOGGER.error("Error processing the UserMessage, the amount of specified attachments does not correlate with the actual attachments in the UserMessage. Expected " + aEbms3PayloadInfo.getPartInfoCount() + " but having " + aAttachments.size() + " attachments.");
aErrorList.add(EEbmsError.EBMS_EXTERNAL_PAYLOAD_ERROR.getAsError(aLocale));
return ESuccess.FAILURE;
}
int nSpecifiedAttachments = 0;
for (final Ebms3PartInfo aPartInfo : aEbms3PayloadInfo.getPartInfo()) {
// If href is null or empty there has to be a SOAP Payload
if (StringHelper.hasNoText(aPartInfo.getHref())) {
// Check if there is a BodyPayload as specified in the UserMessage
if (!bHasSoapBodyPayload) {
LOGGER.error("Error processing the UserMessage. Expected a SOAPBody Payload but there is none present.");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
} else {
// Attachment
// To check attachments which are specified in the usermessage and
// the real amount in the mime message
nSpecifiedAttachments++;
final String sAttachmentID = StringHelper.trimStart(aPartInfo.getHref(), MessageHelperMethods.PREFIX_CID);
final WSS4JAttachment aIncomingAttachment = aAttachments.findFirst(x -> EqualsHelper.equals(x.getId(), sAttachmentID));
if (aIncomingAttachment == null) {
LOGGER.warn("Failed to resolve MIME attachment '" + sAttachmentID + "' in list of " + aAttachments.getAllMapped(WSS4JAttachment::getId));
}
boolean bMimeTypePresent = false;
boolean bCompressionTypePresent = false;
if (aPartInfo.getPartProperties() != null)
for (final Ebms3Property aEbms3Property : aPartInfo.getPartProperties().getProperty()) {
final String sPropertyName = aEbms3Property.getName();
final String sPropertyValue = aEbms3Property.getValue();
if (sPropertyName.equalsIgnoreCase(MessageHelperMethods.PART_PROPERTY_MIME_TYPE)) {
bMimeTypePresent = StringHelper.hasText(sPropertyValue);
} else if (sPropertyName.equalsIgnoreCase(MessageHelperMethods.PART_PROPERTY_COMPRESSION_TYPE)) {
// Only needed check here since AS4 does not support another
// CompressionType
// http://wiki.ds.unipi.gr/display/ESENS/PR+-+AS4
final EAS4CompressionMode eCompressionMode = EAS4CompressionMode.getFromMimeTypeStringOrNull(sPropertyValue);
if (eCompressionMode == null) {
LOGGER.error("Error processing the UserMessage, CompressionType '" + sPropertyValue + "' of attachment '" + sAttachmentID + "' is not supported.");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
aCompressionAttachmentIDs.put(sAttachmentID, eCompressionMode);
bCompressionTypePresent = true;
} else if (sPropertyName.equalsIgnoreCase(MessageHelperMethods.PART_PROPERTY_CHARACTER_SET)) {
if (StringHelper.hasText(sPropertyValue)) {
final Charset aCharset = CharsetHelper.getCharsetFromNameOrNull(sPropertyValue);
if (aCharset == null) {
LOGGER.error("Value '" + sPropertyValue + "' of property '" + MessageHelperMethods.PART_PROPERTY_CHARACTER_SET + "' of attachment '" + sAttachmentID + "' is not supported");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
} else if (aIncomingAttachment != null)
aIncomingAttachment.setCharset(aCharset);
}
}
// else we don't care about the property
}
// got compressed
if (bCompressionTypePresent && !bMimeTypePresent) {
LOGGER.error("Error processing the UserMessage, MimeType for a compressed attachment ('" + sAttachmentID + "') is not present.");
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
}
}
// This may also be an indicator for "external payloads"
if (nSpecifiedAttachments != aAttachments.size()) {
LOGGER.error("Error processing the UserMessage: the amount of specified attachments does not correlate with the actual attachments in the UserMessage. Expected " + aEbms3PayloadInfo.getPartInfoCount() + " but having " + aAttachments.size() + " attachments. This is an indicator, that an external attached was provided.");
aErrorList.add(EEbmsError.EBMS_EXTERNAL_PAYLOAD_ERROR.getAsError(aLocale));
return ESuccess.FAILURE;
}
}
} else {
// Must be a SignalMessage
// all vars stay null
final Ebms3SignalMessage aSignalMessage = aMessaging.getSignalMessageAtIndex(0);
final Ebms3MessageInfo aMsgInfo = aSignalMessage.getMessageInfo();
if (aMsgInfo != null) {
// Set this is as early as possible, so that eventually occurring error
// messages can use the "RefToMessageId" element properly
aState.setMessageID(aMsgInfo.getMessageId());
aState.setRefToMessageID(aMsgInfo.getRefToMessageId());
aState.setMessageTimestamp(aMsgInfo.getTimestamp());
}
final Ebms3PullRequest aEbms3PullRequest = aSignalMessage.getPullRequest();
final Ebms3Receipt aEbms3Receipt = aSignalMessage.getReceipt();
if (aEbms3PullRequest != null) {
final String sMPC = aEbms3PullRequest.getMpc();
final IMPC aMPC = aMPCMgr.getMPCOfID(sMPC);
if (aMPC == null) {
LOGGER.error("Failed to resolve the PullRequest MPC '" + sMPC + "'");
// Return value not recognized when MPC is not currently saved
aErrorList.add(EEbmsError.EBMS_VALUE_NOT_RECOGNIZED.getAsError(aLocale));
return ESuccess.FAILURE;
}
// Create SPI which returns a PMode
for (final IAS4ServletPullRequestProcessorSPI aProcessor : AS4ServletPullRequestProcessorManager.getAllProcessors()) {
aPMode = aProcessor.findPMode(aSignalMessage);
if (aPMode != null) {
LOGGER.info("Found PMode '" + aPMode.getID() + "' for MPC '" + sMPC + "' in SignalMessage " + aSignalMessage);
break;
}
}
if (aPMode == null) {
LOGGER.error("Failed to resolve PMode for PullRequest with MPC '" + sMPC + "'");
aErrorList.add(EEbmsError.EBMS_VALUE_NOT_RECOGNIZED.getAsError(aLocale));
return ESuccess.FAILURE;
}
} else if (aEbms3Receipt != null) {
final String sRefToMessageID = aSignalMessage.getMessageInfo().getRefToMessageId();
if (StringHelper.hasNoText(sRefToMessageID)) {
LOGGER.error("The Receipt does not contain a RefToMessageId");
aErrorList.add(EEbmsError.EBMS_INVALID_RECEIPT.getAsError(aLocale));
return ESuccess.FAILURE;
}
} else {
// Error Message
if (!aSignalMessage.getError().isEmpty()) {
for (final Ebms3Error aError : aSignalMessage.getError()) {
/*
* Ebms 3 spec 6.2.6: This OPTIONAL attribute indicates the
* MessageId of the message in error, for which this error is
* raised.
*/
if (false)
if (StringHelper.hasNoText(aError.getRefToMessageInError())) {
aErrorList.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsError(aLocale));
return ESuccess.FAILURE;
}
}
}
}
}
// Remember in state
aState.setPMode(aPMode);
aState.setOriginalSoapDocument(aSOAPDoc);
aState.setOriginalAttachments(aAttachments);
aState.setCompressedAttachmentIDs(aCompressionAttachmentIDs);
aState.setMPC(aEffectiveMPC);
aState.setInitiatorID(sInitiatorID);
aState.setResponderID(sResponderID);
return ESuccess.SUCCESS;
}
use of com.helger.phase4.ebms3header.Ebms3Error in project phase4 by phax.
the class AS4DumpReader method decryptAS4In.
/**
* Utility method to decrypt dumped .as4in message late.<br>
* Note: this method was mainly created for internal use and does not win the
* prize for the most sexy piece of software in the world ;-)
*
* @param aAS4InData
* The byte array with the dumped data.
* @param aCF
* The Crypto factory to be used. This crypto factory must use use the
* private key that can be used to decrypt this particular message. May
* not be <code>null</code>.
* @param aHttpHeaderConsumer
* An optional HTTP Header map consumer. May be <code>null</code>.
* @param aDecryptedConsumer
* The consumer for the decrypted payload - whatever that is :). May
* not be <code>null</code>.
* @throws WSSecurityException
* In case of error
* @throws Phase4Exception
* In case of error
* @throws IOException
* In case of error
* @throws MessagingException
* In case of error
*/
public static void decryptAS4In(@Nonnull final byte[] aAS4InData, final IAS4CryptoFactory aCF, @Nullable final Consumer<HttpHeaderMap> aHttpHeaderConsumer, @Nonnull final Consumer<byte[]> aDecryptedConsumer) throws WSSecurityException, Phase4Exception, IOException, MessagingException {
final HttpHeaderMap hm = new HttpHeaderMap();
int nHttpStart = 0;
int nHttpEnd = -1;
boolean bLastWasCR = false;
for (int i = 0; i < aAS4InData.length; ++i) {
final byte b = aAS4InData[i];
if (b == '\n') {
if (bLastWasCR) {
nHttpEnd = i;
break;
}
bLastWasCR = true;
final String sLine = new String(aAS4InData, nHttpStart, i - nHttpStart, StandardCharsets.ISO_8859_1);
final String[] aParts = StringHelper.getExplodedArray(':', sLine, 2);
hm.addHeader(aParts[0].trim(), aParts[1].trim());
nHttpStart = i + 1;
} else {
if (b != '\r')
bLastWasCR = false;
}
}
if (aHttpHeaderConsumer != null)
aHttpHeaderConsumer.accept(hm);
LOGGER.info("Now at byte " + nHttpEnd + " having " + hm.getCount() + " HTTP headers");
WebScopeManager.onGlobalBegin(MockServletContext.create());
try (final WebScoped w = new WebScoped();
final AS4RequestHandler rh = new AS4RequestHandler(aCF, DefaultPModeResolver.DEFAULT_PMODE_RESOLVER, IAS4IncomingAttachmentFactory.DEFAULT_INSTANCE, new AS4IncomingMessageMetadata(EAS4MessageMode.REQUEST))) {
final IAS4ServletMessageProcessorSPI aSPI = new IAS4ServletMessageProcessorSPI() {
public AS4MessageProcessorResult processAS4UserMessage(final IAS4IncomingMessageMetadata aMessageMetadata, final HttpHeaderMap aHttpHeaders, final Ebms3UserMessage aUserMessage, final IPMode aPMode, final Node aPayload, final ICommonsList<WSS4JAttachment> aIncomingAttachments, final IAS4MessageState aState, final ICommonsList<Ebms3Error> aProcessingErrorMessages) {
try {
final byte[] aDecryptedBytes = StreamHelper.getAllBytes(aIncomingAttachments.getFirst().getInputStreamProvider());
aDecryptedConsumer.accept(aDecryptedBytes);
LOGGER.info("Handled decrypted payload with " + aDecryptedBytes.length + " bytes");
return AS4MessageProcessorResult.createSuccess();
} catch (final Exception ex) {
throw new IllegalStateException(ex);
}
}
public AS4SignalMessageProcessorResult processAS4SignalMessage(final IAS4IncomingMessageMetadata aMessageMetadata, final HttpHeaderMap aHttpHeaders, final Ebms3SignalMessage aSignalMessage, final IPMode aPMode, final IAS4MessageState aState, final ICommonsList<Ebms3Error> aProcessingErrorMessages) {
LOGGER.error("Unexpected signal msg");
return AS4SignalMessageProcessorResult.createSuccess();
}
};
rh.setProcessorSupplier(() -> new CommonsArrayList<>(aSPI));
rh.handleRequest(new NonBlockingByteArrayInputStream(aAS4InData, nHttpEnd, aAS4InData.length - nHttpEnd), hm, new IAS4ResponseAbstraction() {
public void setStatus(final int nStatusCode) {
}
public void setMimeType(final IMimeType aMimeType) {
}
public void setContent(final HttpHeaderMap aHeaderMap, final IHasInputStream aHasIS) {
}
public void setContent(final byte[] aResultBytes, final Charset aCharset) {
}
});
} finally {
WebScopeManager.onGlobalEnd();
}
}
use of com.helger.phase4.ebms3header.Ebms3Error in project phase4 by phax.
the class Phase4PeppolServletMessageProcessorSPI method processAS4UserMessage.
@Nonnull
public AS4MessageProcessorResult processAS4UserMessage(@Nonnull final IAS4IncomingMessageMetadata aMessageMetadata, @Nonnull final HttpHeaderMap aHttpHeaders, @Nonnull final Ebms3UserMessage aUserMessage, @Nonnull final IPMode aSrcPMode, @Nullable final Node aPayload, @Nullable final ICommonsList<WSS4JAttachment> aIncomingAttachments, @Nonnull final IAS4MessageState aState, @Nonnull final ICommonsList<Ebms3Error> aProcessingErrorMessages) {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Invoking processAS4UserMessage");
final String sMessageID = aUserMessage.getMessageInfo().getMessageId();
final String sService = aUserMessage.getCollaborationInfo().getServiceValue();
final String sAction = aUserMessage.getCollaborationInfo().getAction();
final String sConversationID = aUserMessage.getCollaborationInfo().getConversationId();
final String sLogPrefix = "[" + sMessageID + "] ";
final Locale aDisplayLocale = aState.getLocale();
// Debug log
if (LOGGER.isDebugEnabled()) {
if (aSrcPMode == null)
LOGGER.debug(sLogPrefix + " No Source PMode present");
else
LOGGER.debug(sLogPrefix + " Source PMode = " + aSrcPMode.getID());
LOGGER.debug(sLogPrefix + " AS4 Message ID = '" + sMessageID + "'");
LOGGER.debug(sLogPrefix + " AS4 Service = '" + sService + "'");
LOGGER.debug(sLogPrefix + " AS4 Action = '" + sAction + "'");
LOGGER.debug(sLogPrefix + " AS4 ConversationId = '" + sConversationID + "'");
// Log source properties
if (aUserMessage.getMessageProperties() != null && aUserMessage.getMessageProperties().hasPropertyEntries()) {
LOGGER.debug(sLogPrefix + " AS4 MessageProperties:");
for (final Ebms3Property p : aUserMessage.getMessageProperties().getProperty()) LOGGER.debug(sLogPrefix + " [" + p.getName() + "] = [" + p.getValue() + "]");
} else
LOGGER.debug(sLogPrefix + " No AS4 Mesage Properties present");
if (aPayload == null)
LOGGER.debug(sLogPrefix + " No SOAP Body Payload present");
else
LOGGER.debug(sLogPrefix + " SOAP Body Payload = " + XMLWriter.getNodeAsString(aPayload));
}
// Read all attachments
final ICommonsList<ReadAttachment> aReadAttachments = new CommonsArrayList<>();
if (aIncomingAttachments != null) {
int nAttachmentIndex = 0;
for (final IAS4Attachment aIncomingAttachment : aIncomingAttachments) {
final ReadAttachment a = new ReadAttachment();
a.m_sID = aIncomingAttachment.getId();
a.m_sMimeType = aIncomingAttachment.getMimeType();
a.m_sUncompressedMimeType = aIncomingAttachment.getUncompressedMimeType();
a.m_aCharset = aIncomingAttachment.getCharset();
a.m_eCompressionMode = aIncomingAttachment.getCompressionMode();
try (final InputStream aSIS = aIncomingAttachment.getSourceStream()) {
final NonBlockingByteArrayOutputStream aBAOS = new NonBlockingByteArrayOutputStream();
if (StreamHelper.copyInputStreamToOutputStreamAndCloseOS(aSIS, aBAOS).isSuccess()) {
a.m_aPayloadBytes = aBAOS.getBufferOrCopy();
}
} catch (final IOException | AS4DecompressException ex) {
// Fall through
}
if (a.m_aPayloadBytes == null) {
LOGGER.error(sLogPrefix + "Failed to decompress the payload");
aProcessingErrorMessages.add(EEbmsError.EBMS_DECOMPRESSION_FAILURE.getAsEbms3Error(aDisplayLocale, aState.getMessageID()));
return AS4MessageProcessorResult.createFailure(null);
}
// Read data as SBDH
// Hint for production systems: this may take a huge amount of memory,
// if the payload is large
final ErrorList aSBDHErrors = new ErrorList();
a.m_aSBDH = SBDHReader.standardBusinessDocument().setValidationEventHandler(new WrappedCollectingValidationEventHandler(aSBDHErrors)).read(a.m_aPayloadBytes);
if (a.m_aSBDH == null) {
if (aSBDHErrors.isEmpty()) {
final String sMsg = "Failed to read the provided SBDH document";
LOGGER.error(sLogPrefix + sMsg);
aProcessingErrorMessages.add(EEbmsError.EBMS_OTHER.getAsEbms3Error(aDisplayLocale, aState.getMessageID(), sMsg));
} else {
for (final IError aError : aSBDHErrors) {
final String sMsg = "Peppol SBDH Issue: " + aError.getAsString(aDisplayLocale);
LOGGER.error(sLogPrefix + sMsg);
aProcessingErrorMessages.add(EEbmsError.EBMS_OTHER.getAsEbms3Error(aDisplayLocale, aState.getMessageID(), sMsg));
}
}
return AS4MessageProcessorResult.createFailure(null);
}
aReadAttachments.add(a);
if (LOGGER.isDebugEnabled())
LOGGER.debug(sLogPrefix + "AS4 Attachment " + nAttachmentIndex + " with ID [" + a.m_sID + "] uses [" + a.m_sMimeType + (a.m_sUncompressedMimeType == null ? null : " - uncompressed " + a.m_sUncompressedMimeType) + "] and [" + StringHelper.getToString(a.m_aCharset, "no charset") + "] and length is " + (a.m_aPayloadBytes == null ? "<error>" : Integer.toString(a.m_aPayloadBytes.length)) + " bytes" + (a.m_eCompressionMode == null ? "" : " of compressed payload"));
nAttachmentIndex++;
}
}
if (aReadAttachments.size() != 1) {
// In Peppol there must be exactly one payload
final String sMsg = "In Peppol exactly one payload attachment is expected. This request has " + aReadAttachments.size() + " attachments";
LOGGER.error(sLogPrefix + sMsg);
return AS4MessageProcessorResult.createFailure(sMsg);
}
// The one and only
final ReadAttachment aReadAttachment = aReadAttachments.getFirst();
// Extract Peppol values from SBD
final PeppolSBDHDocument aPeppolSBD;
try {
if (LOGGER.isDebugEnabled())
LOGGER.debug(sLogPrefix + "Now evaluating the SBDH against Peppol rules");
final boolean bPerformValueChecks = Phase4PeppolServletConfiguration.isPerformSBDHValueChecks();
aPeppolSBD = new PeppolSBDHDocumentReader(SimpleIdentifierFactory.INSTANCE).setPerformValueChecks(bPerformValueChecks).extractData(aReadAttachment.standardBusinessDocument());
if (LOGGER.isDebugEnabled())
LOGGER.debug(sLogPrefix + "The provided SBDH is valid according to Peppol rules, with value checks being " + (bPerformValueChecks ? "enabled" : "disabled"));
} catch (final PeppolSBDHDocumentReadException ex) {
final String sMsg = "Failed to extract the Peppol data from SBDH. Technical details: " + ex.getClass().getName() + " - " + ex.getMessage();
LOGGER.error(sLogPrefix + sMsg);
return AS4MessageProcessorResult.createFailure(sMsg);
}
if (m_aHandlers.isEmpty()) {
LOGGER.error(sLogPrefix + "No SPI handler is present - the message is unhandled and discarded");
} else {
// Start consistency checks?
final Phase4PeppolReceiverCheckData aReceiverCheckData = m_aReceiverCheckData != null ? m_aReceiverCheckData : Phase4PeppolServletConfiguration.getAsReceiverCheckData();
if (aReceiverCheckData != null) {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Performing check if the provided data is registered in our SMP");
try {
// Get the endpoint information required from the recipient
// Check if an endpoint is registered
final IParticipantIdentifier aReceiverID = aPeppolSBD.getReceiverAsIdentifier();
final IDocumentTypeIdentifier aDocTypeID = aPeppolSBD.getDocumentTypeAsIdentifier();
final IProcessIdentifier aProcessID = aPeppolSBD.getProcessAsIdentifier();
final EndpointType aReceiverEndpoint = _getReceiverEndpoint(sLogPrefix, aReceiverCheckData.getSMPClient(), aReceiverID, aDocTypeID, aProcessID);
if (aReceiverEndpoint == null) {
final String sMsg = "Failed to resolve SMP endpoint for provided receiver ID (" + (aReceiverID == null ? "null" : aReceiverID.getURIEncoded()) + ")/documentType ID (" + (aDocTypeID == null ? "null" : aDocTypeID.getURIEncoded()) + ")/process ID (" + (aProcessID == null ? "null" : aProcessID.getURIEncoded()) + ")/transport profile (" + m_aTransportProfile.getID() + ") - not handling incoming AS4 document";
LOGGER.error(sLogPrefix + sMsg);
return AS4MessageProcessorResult.createFailure(sMsg);
}
// Check if the message is for us
_checkIfReceiverEndpointURLMatches(sLogPrefix, aReceiverCheckData.getAS4EndpointURL(), aReceiverEndpoint);
// Get the recipient certificate from the SMP
_checkIfEndpointCertificateMatches(sLogPrefix, aReceiverCheckData.getAPCertificate(), aReceiverEndpoint);
} catch (final Phase4Exception ex) {
final String sMsg = "The addressing data contained in the SBDH could not be verified. Technical details: " + ex.getClass().getName() + " - " + ex.getMessage();
LOGGER.error(sLogPrefix + sMsg);
return AS4MessageProcessorResult.createFailure(sMsg);
}
} else {
LOGGER.info(sLogPrefix + "Endpoint checks for incoming AS4 messages are disabled");
}
for (final IPhase4PeppolIncomingSBDHandlerSPI aHandler : m_aHandlers) {
try {
if (LOGGER.isDebugEnabled())
LOGGER.debug(sLogPrefix + "Invoking Peppol handler " + aHandler);
aHandler.handleIncomingSBD(aMessageMetadata, aHttpHeaders.getClone(), aUserMessage.clone(), aReadAttachment.payloadBytes(), aReadAttachment.standardBusinessDocument(), aPeppolSBD, aState);
} catch (final Exception ex) {
LOGGER.error(sLogPrefix + "Error invoking Peppol handler " + aHandler, ex);
if (aHandler.exceptionTranslatesToAS4Error()) {
final String sMsg = "The incoming Peppol message could not be processed. Technical details: " + ex.getClass().getName() + " - " + ex.getMessage();
LOGGER.error(sLogPrefix + sMsg);
return AS4MessageProcessorResult.createFailure(sMsg);
}
}
}
}
return AS4MessageProcessorResult.createSuccess();
}
Aggregations