Search in sources :

Example 56 with PModeLeg

use of com.helger.phase4.model.pmode.leg.PModeLeg in project phase4 by phax.

the class AS4RequestHandler method _handleSoapMessage.

@Nullable
private IAS4ResponseFactory _handleSoapMessage(@Nonnull final HttpHeaderMap aHttpHeaders, @Nonnull final Document aSoapDocument, @Nonnull final ESoapVersion eSoapVersion, @Nonnull final ICommonsList<WSS4JAttachment> aIncomingAttachments, @Nonnull final ICommonsList<Ebms3Error> aErrorMessagesTarget) throws WSSecurityException, MessagingException, Phase4Exception {
    final SOAPHeaderElementProcessorRegistry aRegistry = SOAPHeaderElementProcessorRegistry.createDefault(m_aPModeResolver, m_aCryptoFactory, (IPMode) null);
    final IAS4MessageState aState = AS4IncomingHandler.processEbmsMessage(m_aResHelper, m_aLocale, aRegistry, aHttpHeaders, aSoapDocument, eSoapVersion, aIncomingAttachments, m_aIncomingProfileSelector, aErrorMessagesTarget);
    final IPMode aPMode = aState.getPMode();
    final PModeLeg aEffectiveLeg = aState.getEffectivePModeLeg();
    final String sMessageID = aState.getMessageID();
    final ICommonsList<WSS4JAttachment> aDecryptedAttachments = aState.hasDecryptedAttachments() ? aState.getDecryptedAttachments() : aState.getOriginalAttachments();
    final Node aPayloadNode = aState.getSoapBodyPayloadNode();
    final Ebms3UserMessage aEbmsUserMessage = aState.getEbmsUserMessage();
    final Ebms3SignalMessage aEbmsSignalMessage = aState.getEbmsSignalMessage();
    if (aState.isSoapHeaderElementProcessingSuccessful()) {
        final String sProfileID = aState.getProfileID();
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("No checking for duplicate message with message ID '" + sMessageID + "' and profile ID '" + sProfileID + "'");
        final boolean bIsDuplicate = MetaAS4Manager.getIncomingDuplicateMgr().registerAndCheck(sMessageID, sProfileID, aPMode == null ? null : aPMode.getID()).isBreak();
        if (bIsDuplicate) {
            LOGGER.error("Not invoking SPIs, because message with Message ID '" + sMessageID + "' was already handled!");
            aErrorMessagesTarget.add(EEbmsError.EBMS_OTHER.getAsEbms3Error(m_aLocale, sMessageID, "Another message with the same Message ID '" + sMessageID + "' was already received!"));
        } else {
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Message is not a duplicate");
        }
    }
    final SPIInvocationResult aSPIResult = new SPIInvocationResult();
    // Storing for two-way response messages
    final ICommonsList<WSS4JAttachment> aResponseAttachments = new CommonsArrayList<>();
    // Invoke SPIs if
    // * No errors so far (sign, encrypt, ...)
    // * Valid PMode
    // * Exactly one UserMessage or SignalMessage
    // * No ping/test message
    // * No Duplicate message ID
    final boolean bCanInvokeSPIs = aErrorMessagesTarget.isEmpty() && !aState.isPingMessage();
    if (bCanInvokeSPIs) {
        // PMode may be null for receipts
        if (aPMode == null || aPMode.getMEPBinding().isSynchronous() || aPMode.getMEPBinding().isAsynchronousInitiator() || aState.getEffectivePModeLegNumber() != 1) {
            // Call synchronous
            // Might add to aErrorMessages
            // Might add to aResponseAttachments
            // Might add to m_aPullReturnUserMsg
            _invokeSPIsForIncoming(aHttpHeaders, aEbmsUserMessage, aEbmsSignalMessage, aPayloadNode, aDecryptedAttachments, aPMode, aState, aErrorMessagesTarget, aResponseAttachments, aSPIResult);
            if (aSPIResult.isFailure())
                LOGGER.warn("Error invoking synchronous SPIs");
            else if (LOGGER.isDebugEnabled())
                LOGGER.debug("Successfully invoked synchronous SPIs");
            if (m_aSoapProcessingFinalizedCB != null)
                m_aSoapProcessingFinalizedCB.onProcessingFinalized(true);
        } else {
            // Call asynchronous
            // Only leg1 can be async!
            final IThrowingRunnable<Exception> r = () -> {
                // Start async
                final ICommonsList<Ebms3Error> aLocalErrorMessages = new CommonsArrayList<>();
                final ICommonsList<WSS4JAttachment> aLocalResponseAttachments = new CommonsArrayList<>();
                final SPIInvocationResult aAsyncSPIResult = new SPIInvocationResult();
                _invokeSPIsForIncoming(aHttpHeaders, aEbmsUserMessage, aEbmsSignalMessage, aPayloadNode, aDecryptedAttachments, aPMode, aState, aLocalErrorMessages, aLocalResponseAttachments, aAsyncSPIResult);
                final IAS4ResponseFactory aAsyncResponseFactory;
                final String sResponseMessageID;
                if (aAsyncSPIResult.isSuccess()) {
                    // SPI processing succeeded
                    assert aLocalErrorMessages.isEmpty();
                    // The response user message has no explicit payload. All data of
                    // the response user message is in the local attachments
                    sResponseMessageID = MessageHelperMethods.createRandomMessageID();
                    final AS4UserMessage aResponseUserMsg = _createReversedUserMessage(eSoapVersion, sResponseMessageID, aEbmsUserMessage, aLocalResponseAttachments);
                    // Send UserMessage
                    final AS4SigningParams aSigningParams = new AS4SigningParams().setFromPMode(aEffectiveLeg.getSecurity());
                    // Use the original receiver ID as the alias into the keystore for
                    // encrypting the response message
                    final String sEncryptionAlias = aEbmsUserMessage.getPartyInfo().getTo().getPartyIdAtIndex(0).getValue();
                    final AS4CryptParams aCryptParams = new AS4CryptParams().setFromPMode(aEffectiveLeg.getSecurity()).setAlias(sEncryptionAlias);
                    aAsyncResponseFactory = _createResponseUserMessage(aState, aEffectiveLeg.getProtocol().getSoapVersion(), aResponseUserMsg, aResponseAttachments, aSigningParams, aCryptParams);
                } else {
                    // SPI processing failed
                    // Send ErrorMessage Undefined - see
                    // https://github.com/phax/phase4/issues/4
                    final AS4ErrorMessage aResponseErrorMsg = AS4ErrorMessage.create(eSoapVersion, aState.getMessageID(), aLocalErrorMessages);
                    sResponseMessageID = aResponseErrorMsg.getEbms3SignalMessage().getMessageInfo().getMessageId();
                    // Pass error messages to the outside
                    if (m_aErrorConsumer != null && aLocalErrorMessages.isNotEmpty())
                        m_aErrorConsumer.onAS4ErrorMessage(aState, aLocalErrorMessages, aResponseErrorMsg);
                    aAsyncResponseFactory = new AS4ResponseFactoryXML(m_aMessageMetadata, aState, sResponseMessageID, aResponseErrorMsg.getAsSoapDocument(), eSoapVersion.getMimeType());
                }
                // where to send it back (must be determined by SPI!)
                final String sAsyncResponseURL = aAsyncSPIResult.getAsyncResponseURL();
                if (StringHelper.hasNoText(sAsyncResponseURL))
                    throw new IllegalStateException("No asynchronous response URL present - please check your SPI implementation");
                if (LOGGER.isDebugEnabled())
                    LOGGER.debug("Responding asynchronous to: " + sAsyncResponseURL);
                // Ensure HttpEntity is repeatable
                HttpEntity aHttpEntity = aAsyncResponseFactory.getHttpEntityForSending(eSoapVersion.getMimeType());
                aHttpEntity = m_aResHelper.createRepeatableHttpEntity(aHttpEntity);
                // Use the prebuilt entity for dumping
                _invokeSPIsForResponse(aState, aAsyncResponseFactory, aHttpEntity, eSoapVersion.getMimeType(), sResponseMessageID);
                // invoke client with new document
                final BasicHttpPoster aSender = new BasicHttpPoster();
                final Document aAsyncResponse;
                if (true) {
                    final HttpHeaderMap aResponseHttpHeaders = null;
                    // TODO make async send parameters customizable
                    final HttpRetrySettings aRetrySettings = new HttpRetrySettings();
                    aAsyncResponse = aSender.sendGenericMessageWithRetries(sAsyncResponseURL, aResponseHttpHeaders, aHttpEntity, sMessageID, aRetrySettings, new ResponseHandlerXml(), m_aOutgoingDumper, m_aRetryCallback);
                } else {
                    aAsyncResponse = aSender.sendGenericMessage(sAsyncResponseURL, null, aHttpEntity, new ResponseHandlerXml());
                }
                AS4HttpDebug.debug(() -> "SEND-RESPONSE [async sent] received: " + XMLWriter.getNodeAsString(aAsyncResponse, AS4HttpDebug.getDebugXMLWriterSettings()));
            };
            final CompletableFuture<Void> aFuture = PhotonWorkerPool.getInstance().runThrowing(CAS4.LIB_NAME + " async processing", r);
            if (m_aSoapProcessingFinalizedCB != null) {
                // Give the outside world the possibility to get notified when the
                // processing is done
                aFuture.thenRun(() -> m_aSoapProcessingFinalizedCB.onProcessingFinalized(false));
            }
        }
    }
    // Try building error message
    final String sResponseMessageID;
    final IAS4ResponseFactory ret;
    if (!aState.isSoapHeaderElementProcessingSuccessful() || aState.getEbmsError() == null) {
        // Not an incoming Ebms Error Message
        if (aErrorMessagesTarget.isNotEmpty()) {
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Creating AS4 error message with these " + aErrorMessagesTarget.size() + " errors: " + aErrorMessagesTarget.getAllMapped(Ebms3Error::getDescriptionValue));
            final AS4ErrorMessage aResponseErrorMsg = AS4ErrorMessage.create(eSoapVersion, aState.getMessageID(), aErrorMessagesTarget);
            // Call optional consumer
            if (m_aErrorConsumer != null)
                m_aErrorConsumer.onAS4ErrorMessage(aState, aErrorMessagesTarget, aResponseErrorMsg);
            // When aLeg == null, the response is true
            if (_isSendErrorAsResponse(aEffectiveLeg)) {
                sResponseMessageID = aResponseErrorMsg.getEbms3SignalMessage().getMessageInfo().getMessageId();
                ret = new AS4ResponseFactoryXML(m_aMessageMetadata, aState, sResponseMessageID, aResponseErrorMsg.getAsSoapDocument(), eSoapVersion.getMimeType());
            } else {
                LOGGER.warn("Not sending back the error, because sending error response is prohibited in PMode");
                sResponseMessageID = null;
                ret = null;
            }
        } else {
            // Do not respond to receipt (except with error message - see above)
            if (aEbmsSignalMessage == null || aEbmsSignalMessage.getReceipt() == null) {
                // So now the incoming message is a user message or a pull request
                if (aPMode.getMEP().isOneWay() || aPMode.getMEPBinding().isAsynchronous()) {
                    // the pull phase
                    if (aPMode.getMEPBinding().equals(EMEPBinding.PULL) || (aPMode.getMEPBinding().equals(EMEPBinding.PULL_PUSH) && aSPIResult.hasPullReturnUserMsg()) || (aPMode.getMEPBinding().equals(EMEPBinding.PUSH_PULL) && aSPIResult.hasPullReturnUserMsg())) {
                        // TODO would be nice to have attachments here I guess
                        final AS4UserMessage aResponseUserMsg = new AS4UserMessage(eSoapVersion, aSPIResult.getPullReturnUserMsg());
                        sResponseMessageID = aResponseUserMsg.getEbms3UserMessage().getMessageInfo().getMessageId();
                        ret = new AS4ResponseFactoryXML(m_aMessageMetadata, aState, sResponseMessageID, aResponseUserMsg.getAsSoapDocument(), eSoapVersion.getMimeType());
                    } else if (aEbmsUserMessage != null) {
                        // We received an incoming user message and no errors occurred
                        final boolean bSendReceiptAsResponse = _isSendReceiptAsResponse(aEffectiveLeg);
                        if (bSendReceiptAsResponse) {
                            sResponseMessageID = MessageHelperMethods.createRandomMessageID();
                            ret = _createResponseReceiptMessage(aState, aSoapDocument, eSoapVersion, sResponseMessageID, aEffectiveLeg, aEbmsUserMessage, aResponseAttachments);
                        } else {
                            // TODO what shall we send back here?
                            LOGGER.info("Not sending back the Receipt response, because sending Receipt response is prohibited in PMode");
                            sResponseMessageID = null;
                            ret = null;
                        }
                    } else {
                        sResponseMessageID = null;
                        ret = null;
                    }
                } else {
                    // synchronous TWO - WAY (= "SYNC")
                    final PModeLeg aLeg2 = aPMode.getLeg2();
                    if (aLeg2 == null)
                        throw new Phase4Exception("PMode has no leg2!");
                    if (MEPHelper.isValidResponseTypeLeg2(aPMode.getMEP(), aPMode.getMEPBinding(), EAS4MessageType.USER_MESSAGE)) {
                        sResponseMessageID = MessageHelperMethods.createRandomMessageID();
                        final AS4UserMessage aResponseUserMsg = _createReversedUserMessage(eSoapVersion, sResponseMessageID, aEbmsUserMessage, aResponseAttachments);
                        final AS4SigningParams aSigningParams = new AS4SigningParams().setFromPMode(aLeg2.getSecurity());
                        final String sEncryptionAlias = aEbmsUserMessage.getPartyInfo().getTo().getPartyIdAtIndex(0).getValue();
                        final AS4CryptParams aCryptParams = new AS4CryptParams().setFromPMode(aLeg2.getSecurity()).setAlias(sEncryptionAlias);
                        ret = _createResponseUserMessage(aState, aLeg2.getProtocol().getSoapVersion(), aResponseUserMsg, aResponseAttachments, aSigningParams, aCryptParams);
                    } else {
                        sResponseMessageID = null;
                        ret = null;
                    }
                }
            } else {
                sResponseMessageID = null;
                ret = null;
            }
        }
    } else {
        sResponseMessageID = null;
        ret = null;
    }
    // Create the HttpEntity on demand
    _invokeSPIsForResponse(aState, ret, null, eSoapVersion.getMimeType(), sResponseMessageID);
    return ret;
}
Also used : Ebms3SignalMessage(com.helger.phase4.ebms3header.Ebms3SignalMessage) ICommonsList(com.helger.commons.collection.impl.ICommonsList) PModeLeg(com.helger.phase4.model.pmode.leg.PModeLeg) HttpEntity(org.apache.http.HttpEntity) SOAPHeaderElementProcessorRegistry(com.helger.phase4.servlet.soap.SOAPHeaderElementProcessorRegistry) Node(org.w3c.dom.Node) Document(org.w3c.dom.Document) HttpRetrySettings(com.helger.phase4.http.HttpRetrySettings) HttpHeaderMap(com.helger.commons.http.HttpHeaderMap) Phase4Exception(com.helger.phase4.util.Phase4Exception) AS4CryptParams(com.helger.phase4.crypto.AS4CryptParams) AS4SigningParams(com.helger.phase4.crypto.AS4SigningParams) BasicHttpPoster(com.helger.phase4.http.BasicHttpPoster) AS4UserMessage(com.helger.phase4.messaging.domain.AS4UserMessage) AS4DecompressException(com.helger.phase4.attachment.AS4DecompressException) MessagingException(javax.mail.MessagingException) WSSecurityException(org.apache.wss4j.common.ext.WSSecurityException) Phase4Exception(com.helger.phase4.util.Phase4Exception) IOException(java.io.IOException) IPMode(com.helger.phase4.model.pmode.IPMode) ResponseHandlerXml(com.helger.httpclient.response.ResponseHandlerXml) Ebms3UserMessage(com.helger.phase4.ebms3header.Ebms3UserMessage) CommonsArrayList(com.helger.commons.collection.impl.CommonsArrayList) WSS4JAttachment(com.helger.phase4.attachment.WSS4JAttachment) AS4ErrorMessage(com.helger.phase4.messaging.domain.AS4ErrorMessage) Nullable(javax.annotation.Nullable)

Example 57 with PModeLeg

use of com.helger.phase4.model.pmode.leg.PModeLeg 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;
}
Also used : Ebms3Receipt(com.helger.phase4.ebms3header.Ebms3Receipt) IAS4Profile(com.helger.phase4.profile.IAS4Profile) PModeLeg(com.helger.phase4.model.pmode.leg.PModeLeg) Node(org.w3c.dom.Node) Ebms3Error(com.helger.phase4.ebms3header.Ebms3Error) Document(org.w3c.dom.Document) Phase4Exception(com.helger.phase4.util.Phase4Exception) ErrorList(com.helger.commons.error.list.ErrorList) Ebms3PullRequest(com.helger.phase4.ebms3header.Ebms3PullRequest) IPMode(com.helger.phase4.model.pmode.IPMode) Ebms3UserMessage(com.helger.phase4.ebms3header.Ebms3UserMessage) IAS4ProfileValidator(com.helger.phase4.profile.IAS4ProfileValidator) WSS4JAttachment(com.helger.phase4.attachment.WSS4JAttachment) Nonnull(javax.annotation.Nonnull)

Example 58 with PModeLeg

use of com.helger.phase4.model.pmode.leg.PModeLeg in project phase4 by phax.

the class PModeMicroTypeConverter method convertToNative.

@Nonnull
public PMode convertToNative(@Nonnull final IMicroElement aElement) {
    final PModeParty aInitiator = MicroTypeConverter.convertToNative(aElement.getFirstChildElement(ELEMENT_INITIATOR), PModeParty.class);
    final PModeParty aResponder = MicroTypeConverter.convertToNative(aElement.getFirstChildElement(ELEMENT_RESPONDER), PModeParty.class);
    final String sAgreement = aElement.getAttributeValue(ATTR_AGREEMENT);
    final String sMEP = aElement.getAttributeValue(ATTR_MEP);
    final EMEP eMEP = EMEP.getFromIDOrNull(sMEP);
    if (eMEP == null)
        throw new IllegalStateException("Failed to resolve MEP '" + sMEP + "'");
    final String sMEPBinding = aElement.getAttributeValue(ATTR_MEP_BINDING);
    final EMEPBinding eMEPBinding = EMEPBinding.getFromIDOrNull(sMEPBinding);
    if (eMEPBinding == null)
        throw new IllegalStateException("Failed to resolve MEPBinding '" + sMEPBinding + "'");
    final PModeLeg aLeg1 = MicroTypeConverter.convertToNative(aElement.getFirstChildElement(ELEMENT_LEG1), PModeLeg.class);
    final PModeLeg aLeg2 = MicroTypeConverter.convertToNative(aElement.getFirstChildElement(ELEMENT_LEG2), PModeLeg.class);
    final PModePayloadService aPayloadService = MicroTypeConverter.convertToNative(aElement.getFirstChildElement(ELEMENT_PAYLOADSERVICE), PModePayloadService.class);
    final PModeReceptionAwareness aReceptionAwareness = MicroTypeConverter.convertToNative(aElement.getFirstChildElement(ELEMENT_RECEPETIONAWARENESS), PModeReceptionAwareness.class);
    return new PMode(getStubObject(aElement), aInitiator, aResponder, sAgreement, eMEP, eMEPBinding, aLeg1, aLeg2, aPayloadService, aReceptionAwareness);
}
Also used : EMEPBinding(com.helger.phase4.model.EMEPBinding) EMEP(com.helger.phase4.model.EMEP) PModeLeg(com.helger.phase4.model.pmode.leg.PModeLeg) Nonnull(javax.annotation.Nonnull)

Example 59 with PModeLeg

use of com.helger.phase4.model.pmode.leg.PModeLeg in project phase4 by phax.

the class DefaultPMode method _generatePModeLeg.

@Nonnull
private static PModeLeg _generatePModeLeg(@Nullable final String sAddress) {
    final PModeLegErrorHandling aErrorHandling = PModeLegErrorHandling.createUndefined();
    aErrorHandling.setReportAsResponse(true);
    final PModeLegReliability aReliability = null;
    final PModeLegSecurity aSecurity = new PModeLegSecurity();
    aSecurity.setSendReceipt(true);
    aSecurity.setSendReceiptReplyPattern(EPModeSendReceiptReplyPattern.RESPONSE);
    return new PModeLeg(_generatePModeLegProtocol(sAddress), _generatePModeLegBusinessInformation(), aErrorHandling, aReliability, aSecurity);
}
Also used : PModeLegReliability(com.helger.phase4.model.pmode.leg.PModeLegReliability) PModeLeg(com.helger.phase4.model.pmode.leg.PModeLeg) PModeLegErrorHandling(com.helger.phase4.model.pmode.leg.PModeLegErrorHandling) PModeLegSecurity(com.helger.phase4.model.pmode.leg.PModeLegSecurity) Nonnull(javax.annotation.Nonnull)

Example 60 with PModeLeg

use of com.helger.phase4.model.pmode.leg.PModeLeg 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;
}
Also used : Locale(java.util.Locale) Ebms3SignalMessage(com.helger.phase4.ebms3header.Ebms3SignalMessage) PModeLeg(com.helger.phase4.model.pmode.leg.PModeLeg) EAS4CompressionMode(com.helger.phase4.attachment.EAS4CompressionMode) Ebms3PartyId(com.helger.phase4.ebms3header.Ebms3PartyId) Ebms3PayloadInfo(com.helger.phase4.ebms3header.Ebms3PayloadInfo) Ebms3PullRequest(com.helger.phase4.ebms3header.Ebms3PullRequest) CommonsHashMap(com.helger.commons.collection.impl.CommonsHashMap) Ebms3MessageInfo(com.helger.phase4.ebms3header.Ebms3MessageInfo) Ebms3Property(com.helger.phase4.ebms3header.Ebms3Property) Ebms3Receipt(com.helger.phase4.ebms3header.Ebms3Receipt) CollectingValidationEventHandler(com.helger.jaxb.validation.CollectingValidationEventHandler) Charset(java.nio.charset.Charset) Ebms3PartInfo(com.helger.phase4.ebms3header.Ebms3PartInfo) Ebms3Error(com.helger.phase4.ebms3header.Ebms3Error) IError(com.helger.commons.error.IError) IAS4ServletPullRequestProcessorSPI(com.helger.phase4.servlet.spi.IAS4ServletPullRequestProcessorSPI) IMPC(com.helger.phase4.model.mpc.IMPC) Ebms3CollaborationInfo(com.helger.phase4.ebms3header.Ebms3CollaborationInfo) IMPCManager(com.helger.phase4.model.mpc.IMPCManager) IPMode(com.helger.phase4.model.pmode.IPMode) Ebms3UserMessage(com.helger.phase4.ebms3header.Ebms3UserMessage) Ebms3Messaging(com.helger.phase4.ebms3header.Ebms3Messaging) WSS4JAttachment(com.helger.phase4.attachment.WSS4JAttachment) Nonnull(javax.annotation.Nonnull)

Aggregations

PModeLeg (com.helger.phase4.model.pmode.leg.PModeLeg)99 PMode (com.helger.phase4.model.pmode.PMode)91 PModeLegSecurity (com.helger.phase4.model.pmode.leg.PModeLegSecurity)89 EMEP (com.helger.phase4.model.EMEP)88 EMEPBinding (com.helger.phase4.model.EMEPBinding)88 Ebms3UserMessage (com.helger.phase4.ebms3header.Ebms3UserMessage)87 PModeLegErrorHandling (com.helger.phase4.model.pmode.leg.PModeLegErrorHandling)87 PModeLegProtocol (com.helger.phase4.model.pmode.leg.PModeLegProtocol)86 ESoapVersion (com.helger.phase4.soap.ESoapVersion)86 Before (org.junit.Before)86 Ebms3SignalMessage (com.helger.phase4.ebms3header.Ebms3SignalMessage)85 Locale (java.util.Locale)85 ErrorList (com.helger.commons.error.list.ErrorList)84 ECryptoAlgorithmSign (com.helger.phase4.crypto.ECryptoAlgorithmSign)84 ECryptoAlgorithmSignDigest (com.helger.phase4.crypto.ECryptoAlgorithmSignDigest)84 Ebms3MessageInfo (com.helger.phase4.ebms3header.Ebms3MessageInfo)84 Ebms3PartyId (com.helger.phase4.ebms3header.Ebms3PartyId)84 Ignore (org.junit.Ignore)84 Test (org.junit.Test)84 ETriState (com.helger.commons.state.ETriState)83