Example #1
0
        /// <summary>
        /// Execute the step for a given <paramref name="messagingContext" />.
        /// </summary>
        /// <param name="messagingContext">Message used during the step execution.</param>
        /// <returns></returns>
        public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext)
        {
            var pullRequest = messagingContext?.AS4Message?.FirstSignalMessage as PullRequest;

            if (pullRequest == null)
            {
                throw new InvalidMessageException(
                          "The received message is not a PullRequest message, " +
                          "therefore no UserMessage can be selected to return to the sender");
            }

            (bool hasMatch, OutMessage match) = RetrieveUserMessageForPullRequest(pullRequest);
            if (hasMatch)
            {
                // Retrieve the existing MessageBody and put that stream in the MessagingContext.
                // The HttpReceiver processor will make sure that it gets serialized to the http response stream.
                Stream messageBody = await match.RetrieveMessageBody(_messageBodyStore).ConfigureAwait(false);

                messagingContext.ModifyContext(
                    new ReceivedMessage(messageBody, match.ContentType),
                    MessagingContextMode.Send);

                messagingContext.SendingPMode = AS4XmlSerializer.FromString <SendingProcessingMode>(match.PMode);

                return(StepResult.Success(messagingContext));
            }

            AS4Message pullRequestWarning = AS4Message.Create(Error.CreatePullRequestWarning(IdentifierFactory.Instance.Create()));

            messagingContext.ModifyContext(pullRequestWarning);

            return(StepResult.Success(messagingContext).AndStopExecution());
        }
Example #2
0
        /// <summary>
        /// Transform a given <see cref="ReceivedMessage"/> to a Canonical <see cref="MessagingContext"/> instance.
        /// </summary>
        /// <param name="message">Given message to transform.</param>
        ///
        /// <returns></returns>
        public async Task <MessagingContext> TransformAsync(ReceivedMessage message)
        {
            if (!(message is ReceivedEntityMessage))
            {
                throw new NotSupportedException(
                          $"Minder Deliver Transformer only supports transforming instances of type {typeof(ReceivedEntityMessage)}");
            }

            var as4Transformer       = new AS4MessageTransformer();
            MessagingContext context = await as4Transformer.TransformAsync(message);

            var includeAttachments = true;
            CollaborationInfo collaborationInfo = context.ReceivingPMode?.MessagePackaging?.CollaborationInfo;

            if (collaborationInfo != null &&
                (collaborationInfo.Action?.Equals("ACT_SIMPLE_ONEWAY_SIZE", StringComparison.OrdinalIgnoreCase) ?? false) &&
                (collaborationInfo.Service?.Value?.Equals("SRV_SIMPLE_ONEWAY_SIZE", StringComparison.OrdinalIgnoreCase) ?? false))
            {
                includeAttachments = false;
            }

            DeliverMessageEnvelope deliverMessage = CreateDeliverMessageEnvelope(context.AS4Message, includeAttachments);

            context.ModifyContext(deliverMessage);

            return(context);
        }
        private async Task <MessagingContext> InsertReceivedAS4MessageAsync(MessagingContext messagingContext)
        {
            using (DatastoreContext context = _createDatastoreContext())
            {
                MessageExchangePattern messageExchangePattern =
                    messagingContext.Mode == MessagingContextMode.PullReceive
                        ? MessageExchangePattern.Pull
                        : MessageExchangePattern.Push;

                try
                {
                    var        service    = new InMessageService(_config, new DatastoreRepository(context));
                    AS4Message as4Message = await service
                                            .InsertAS4MessageAsync(
                        messagingContext.AS4Message,
                        messagingContext.ReceivedMessage,
                        messagingContext.SendingPMode,
                        messageExchangePattern,
                        _messageBodyStore)
                                            .ConfigureAwait(false);

                    messagingContext.ModifyContext(as4Message);
                    await context.SaveChangesAsync().ConfigureAwait(false);

                    return(messagingContext);
                }
                catch (Exception ex)
                {
                    return(new MessagingContext(ex));
                }
            }
        }
        /// <summary>
        /// Send the <see cref="AS4Message" />
        /// </summary>
        /// <param name="messagingContext"></param>
        /// <returns></returns>
        public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext)
        {
            if (messagingContext == null)
            {
                throw new ArgumentNullException(nameof(messagingContext));
            }

            if (messagingContext.ReceivedMessage == null && messagingContext.AS4Message == null)
            {
                throw new InvalidOperationException(
                          $"{nameof(SendAS4MessageStep)} requires a MessagingContext with a ReceivedStream or an AS4Message to correctly send the message");
            }

            if (messagingContext.ReceivedMessage == null && messagingContext.AS4Message.IsPullRequest == false)
            {
                throw new InvalidOperationException(
                          $"{nameof(SendAS4MessageStep)} expects a PullRequest AS4Message when the MessagingContext does not contain a ReceivedStream");
            }

            PushConfiguration pushConfig = GetPushConfiguration(messagingContext.SendingPMode, messagingContext.ReceivingPMode);

            if (pushConfig?.Protocol?.Url == null)
            {
                throw new ConfigurationErrorsException(
                          "Message cannot be send because neither the Sending or Receiving PMode has a Protocol.Url child in a <PushConfiguration/> or <ResponseConfiguration/> element");
            }

            AS4Message as4Message = await DeserializeUnderlyingStreamIfPresentAsync(
                messagingContext.ReceivedMessage,
                otherwise : messagingContext.AS4Message);

            try
            {
                string         contentType = messagingContext.ReceivedMessage?.ContentType ?? messagingContext.AS4Message.ContentType;
                HttpWebRequest request     = CreateWebRequest(pushConfig, contentType.Replace("charset=\"utf-8\"", ""));

                await WriteToHttpRequestStreamAsync(request, messagingContext).ConfigureAwait(false);

                messagingContext.ModifyContext(as4Message);

                return(await HandleHttpResponseAsync(request, messagingContext).ConfigureAwait(false));
            }
            catch
            {
                await UpdateRetryStatusForMessageAsync(messagingContext, SendResult.RetryableFail);

                return(StepResult.Failed(messagingContext).AndStopExecution());
            }
        }
Example #5
0
        /// <summary>
        /// It is only executed when the external message (received) is an AS4 UserMessage
        /// </summary>
        /// <param name="messagingContext"></param>
        public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext)
        {
            if (messagingContext == null)
            {
                throw new ArgumentNullException(nameof(messagingContext));
            }

            if (messagingContext.AS4Message == null)
            {
                throw new InvalidOperationException(
                          $"{nameof(CreateAS4ReceiptStep)} requires an AS4Message to create ebMS Receipts but no AS4Message is present in the MessagingContext");
            }

            bool receiptSigning = messagingContext.ReceivingPMode?.ReplyHandling?.ResponseSigning?.IsEnabled ?? false;
            bool useNRRFormat   = messagingContext.ReceivingPMode?.ReplyHandling?.ReceiptHandling?.UseNRRFormat ?? false;

            if (!receiptSigning && useNRRFormat)
            {
                Logger.Error(
                    "Cannot create Non-Repudiation Receipts that aren\'t signed, please change either the "
                    + $"ReceivingPMode {messagingContext.ReceivingPMode.Id} ReplyHandling.ReceiptHandling.UseNRRFormat or the ReplyHandling.ResponseSigning");

                messagingContext.ErrorResult = new ErrorResult(
                    "Cannot create Non-Repudiation Receipts that aren't signed",
                    ErrorAlias.InvalidReceipt);

                return(StepResult.Failed(messagingContext));
            }

            AS4Message receivedMessage = messagingContext.AS4Message;
            AS4Message receiptMessage  = AS4Message.Empty;

            receiptMessage.SigningId = receivedMessage.SigningId;

            foreach (UserMessage userMessage in receivedMessage.UserMessages)
            {
                Receipt receipt = CreateReferencedReceipt(userMessage, receivedMessage, messagingContext.ReceivingPMode);
                receiptMessage.AddMessageUnit(receipt);
            }

            if (Logger.IsInfoEnabled && receiptMessage.MessageUnits.Any())
            {
                Logger.Info($"{messagingContext.LogTag} {receiptMessage.MessageUnits.Count()} Receipt message(s) has been created for received AS4 UserMessages");
            }

            messagingContext.ModifyContext(receiptMessage);
            return(await StepResult.SuccessAsync(messagingContext));
        }
        /// <summary>
        /// Transform a given <see cref="ReceivedMessage" /> to a Canonical <see cref="MessagingContext" /> instance.
        /// </summary>
        /// <param name="message">Given message to transform.</param>
        /// <returns></returns>
        public async Task <MessagingContext> TransformAsync(ReceivedMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            if (!(message is ReceivedEntityMessage entityMessage) ||
                !(entityMessage.Entity is MessageEntity me))
            {
                throw new InvalidDataException(
                          $"The message that must be transformed should be of type {nameof(ReceivedEntityMessage)} with a {nameof(MessageEntity)} as Entity");
            }

            MessagingContext context = await AS4MessageTransformer.TransformAsync(entityMessage);

            AS4Message as4Message = context.AS4Message;

            UserMessage toBeDeliveredUserMessage =
                as4Message.UserMessages.FirstOrDefault(u => u.MessageId == me.EbmsMessageId);

            if (toBeDeliveredUserMessage == null)
            {
                throw new InvalidOperationException(
                          $"No UserMessage {me.EbmsMessageId} can be found in stored record for delivering");
            }

            IEnumerable <Attachment> toBeUploadedAttachments =
                as4Message.Attachments
                .Where(a => a.MatchesAny(toBeDeliveredUserMessage.PayloadInfo))
                .ToArray();

            DeliverMessage deliverMessage =
                CreateDeliverMessage(
                    toBeDeliveredUserMessage,
                    toBeUploadedAttachments,
                    context.ReceivingPMode);

            Logger.Info($"(Deliver) Created DeliverMessage from (first) UserMessage {as4Message.FirstUserMessage.MessageId}");
            var envelope = new DeliverMessageEnvelope(
                message: deliverMessage,
                contentType: "application/xml",
                attachments: toBeUploadedAttachments);

            context.ModifyContext(envelope);
            return(context);
        }
Example #7
0
            public void OverrideMessageWithAS4Message()
            {
                // Arrange
                var context = new MessagingContext(AS4MessageWithEbmsMessageId(), MessagingContextMode.Unknown)
                {
                    ReceivingPMode = new ReceivingProcessingMode(),
                    SendingPMode   = new SendingProcessingMode()
                };

                // Act
                context.ModifyContext(AS4MessageWithoutEbmsMessageId());

                // Assert
                Assert.Equal(AS4MessageWithoutEbmsMessageId(), context.AS4Message);
                Assert.NotNull(context.SendingPMode);
                Assert.NotNull(context.ReceivingPMode);
            }
Example #8
0
        /// <summary>
        /// Transform a given <see cref="ReceivedMessage"/> to a Canonical <see cref="MessagingContext"/> instance.
        /// </summary>
        /// <param name="message">Given message to transform.</param>
        /// <returns></returns>
        public async Task <MessagingContext> TransformAsync(ReceivedMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            if (!(message is ReceivedEntityMessage receivedMessage))
            {
                throw new NotSupportedException(
                          $"Incoming message stream from {message.Origin} that must be transformed should be of type {nameof(ReceivedEntityMessage)}");
            }

            if (receivedMessage.Entity is ExceptionEntity ex)
            {
                string ebmsMessageId = IdentifierFactory.Instance.Create();
                Error  error         = Error.FromErrorResult(
                    ebmsMessageId,
                    ex.EbmsRefToMessageId,
                    new ErrorResult(ex.Exception, ErrorAlias.Other));

                NotifyMessageEnvelope notifyEnvelope =
                    await CreateNotifyMessageEnvelopeAsync(AS4Message.Create(error), ebmsMessageId, ex.GetType());

                return(new MessagingContext(notifyEnvelope, receivedMessage));
            }

            if (receivedMessage.Entity is MessageEntity me)
            {
                var as4Transformer   = new AS4MessageTransformer();
                MessagingContext ctx = await as4Transformer.TransformAsync(receivedMessage);

                // Normally the message shouldn't have any attachments
                // but to be sure we should dispose them since we don't need attachments for notifying.
                ctx.AS4Message.CloseAttachments();

                NotifyMessageEnvelope notifyEnvelope =
                    await CreateNotifyMessageEnvelopeAsync(ctx.AS4Message, me.EbmsMessageId, me.GetType());

                ctx.ModifyContext(notifyEnvelope, receivedMessage.Entity.Id);

                return(ctx);
            }

            throw new InvalidOperationException();
        }
Example #9
0
        /// <summary>
        /// Start creating <see cref="Error"/>
        /// </summary>
        /// <param name="messagingContext"></param>
        /// <returns></returns>
        /// <exception cref="System.Exception">A delegate callback throws an exception.</exception>
        public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext)
        {
            if (messagingContext == null)
            {
                throw new ArgumentNullException(nameof(messagingContext));
            }

            if (messagingContext.AS4Message == null)
            {
                throw new InvalidOperationException(
                          $"{nameof(CreateAS4ErrorStep)} requires an AS4Message to create an Error but no AS4Message is present in the MessagingContext");
            }

            if (messagingContext.AS4Message.IsEmpty && messagingContext?.ErrorResult == null)
            {
                Logger.Warn("Skip creating AS4 Error because AS4Message and ErrorResult is empty in the MessagingContext");
                return(await StepResult.SuccessAsync(messagingContext));
            }

            ErrorResult errorResult = messagingContext.ErrorResult;

            AS4Message errorMessage = CreateAS4ErrorWithPossibleMultihop(received: messagingContext.AS4Message,
                                                                         occurredError: errorResult);

            if (errorResult != null)
            {
                Logger.Error($"AS4 Error(s) created with {errorResult.Code.GetString()} {errorResult.Alias}, {errorResult.Description}");

                await InsertInExceptionsForNowExceptionedInMessageAsync(
                    messagingContext.AS4Message.SignalMessages,
                    messagingContext.ErrorResult,
                    messagingContext.ReceivingPMode);
            }

            messagingContext.ModifyContext(errorMessage);

            if (Logger.IsInfoEnabled && errorMessage.MessageUnits.Any())
            {
                Logger.Info(
                    $"{messagingContext.LogTag} {errorMessage.MessageUnits.Count()} Error(s) has been created for received AS4 UserMessages");
            }

            return(await StepResult.SuccessAsync(messagingContext));
        }
        /// <summary>
        /// Handle the given <paramref name="response" />, but delegate to the next handler if you can't.
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        public async Task <StepResult> HandleResponse(IAS4Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            MessagingContext request = response.OriginalRequest;

            if (request?.AS4Message?.IsPullRequest == true)
            {
                bool pullRequestWasPiggyBacked =
                    request.AS4Message.SignalMessages.Any(s => !(s is PullRequest));

                if (pullRequestWasPiggyBacked)
                {
                    using (DatastoreContext ctx = _createContext())
                    {
                        SendResult result =
                            response.StatusCode == HttpStatusCode.Accepted ||
                            response.StatusCode == HttpStatusCode.OK
                                ? SendResult.Success
                                : SendResult.RetryableFail;

                        var service = new PiggyBackingService(ctx);
                        service.ResetSignalMessagesToBePiggyBacked(request.AS4Message.SignalMessages, result);

                        await ctx.SaveChangesAsync().ConfigureAwait(false);
                    }
                }

                bool isEmptyChannelWarning =
                    (response.ReceivedAS4Message?.FirstSignalMessage as Error)?.IsPullRequestWarning == true;

                if (isEmptyChannelWarning)
                {
                    request.ModifyContext(response.ReceivedAS4Message, MessagingContextMode.Send);
                    return(StepResult.Success(response.OriginalRequest).AndStopExecution());
                }
            }

            return(await _nextHandler.HandleResponse(response));
        }
Example #11
0
        private static MessagingContext CreateNotifyMessage <T>(string ebmsMessageId, Entity entity)
        {
            var envelope = new NotifyMessageEnvelope(
                new MessageInfo
            {
                MessageId      = ebmsMessageId,
                RefToMessageId = ebmsMessageId
            },
                Status.Delivered,
                new byte[0],
                "content-type",
                typeof(T));

            var ctx = new MessagingContext(
                new ReceivedEntityMessage(entity),
                MessagingContextMode.Notify)
            {
                SendingPMode = new SendingProcessingMode
                {
                    ReceiptHandling =
                    {
                        NotifyMethod = new Method {
                            Type     = "FILE"
                        }
                    },
                    ErrorHandling =
                    {
                        NotifyMethod = new Method {
                            Type     = "FILE"
                        }
                    },
                    ExceptionHandling =
                    {
                        NotifyMethod = new Method {
                            Type     = "FILE"
                        }
                    }
                }
            };

            ctx.ModifyContext(envelope);
            return(ctx);
        }
Example #12
0
            public void OverrideMessageWithDeliverMessage()
            {
                // Arrange
                var filledNotify = new DeliverMessageEnvelope(new MessageInfo(), new byte[0], "type");
                var context      = new MessagingContext(filledNotify)
                {
                    SendingPMode   = new SendingProcessingMode(),
                    ReceivingPMode = new ReceivingProcessingMode()
                };

                var anonymousDeliver = new DeliverMessageEnvelope(new MessageInfo(), new byte[0], "type");

                // Act
                context.ModifyContext(anonymousDeliver);

                // Assert
                Assert.Equal(anonymousDeliver, context.DeliverMessage);
                Assert.NotNull(context.SendingPMode);
                Assert.NotNull(context.ReceivingPMode);
            }
Example #13
0
            public void OverrideMessageWithNotifyMessage()
            {
                // Arrange
                var filledNotify = new NotifyMessageEnvelope(new AS4.Model.Notify.MessageInfo(), Status.Delivered, new byte[0], "type", typeof(InMessage));

                var context = new MessagingContext(filledNotify)
                {
                    SendingPMode   = new SendingProcessingMode(),
                    ReceivingPMode = new ReceivingProcessingMode()
                };

                var anonymousNotify = new NotifyMessageEnvelope(null, default(Status), null, null, typeof(InMessage));

                // Act
                context.ModifyContext(anonymousNotify);

                // Assert
                Assert.Equal(anonymousNotify, context.NotifyMessage);
                Assert.NotNull(context.SendingPMode);
                Assert.NotNull(context.ReceivingPMode);
            }
Example #14
0
        protected MessagingContext CreateReceivedMessagingContext(AS4Message as4Message, ReceivingProcessingMode receivingPMode)
        {
            var stream = new MemoryStream();

            SerializerProvider
            .Default
            .Get(as4Message.ContentType)
            .Serialize(as4Message, stream);

            stream.Position = 0;

            var ctx = new MessagingContext(
                new ReceivedMessage(stream, as4Message.ContentType),
                MessagingContextMode.Receive)
            {
                ReceivingPMode = receivingPMode
            };

            ctx.ModifyContext(as4Message);
            return(ctx);
        }
Example #15
0
        /// <summary>
        /// Execute the step for a given <paramref name="messagingContext"/>.
        /// </summary>
        /// <param name="messagingContext">Message used during the step execution.</param>
        /// <returns></returns>
        public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext)
        {
            if (messagingContext?.AS4Message == null)
            {
                throw new InvalidOperationException(
                          $"{nameof(UpdateReceivedAS4MessageBodyStep)} requires an AS4Message to update but no AS4Message is present in the MessagingContext");
            }

            Logger.Trace("Updating the received message body...");
            using (DatastoreContext datastoreContext = _createDatastoreContext())
            {
                var repository = new DatastoreRepository(datastoreContext);
                var service    = new InMessageService(_configuration, repository);

                service.UpdateAS4MessageForMessageHandling(
                    messagingContext.AS4Message,
                    messagingContext.SendingPMode,
                    messagingContext.ReceivingPMode,
                    _messageBodyStore);

                await datastoreContext.SaveChangesAsync().ConfigureAwait(false);
            }

            if (messagingContext.ReceivedMessageMustBeForwarded)
            {
                // When the Message has to be forwarded, the remaining Steps must not be executed.
                // The MSH must answer with a HTTP Accepted status-code, so an empty context must be returned.
                messagingContext.ModifyContext(AS4Message.Empty);

                Logger.Info(
                    "Stops execution to return empty SOAP envelope to the orignal sender. " +
                    "This happens when the message must be forwarded");

                return(StepResult.Success(messagingContext).AndStopExecution());
            }

            return(StepResult.Success(messagingContext));
        }
        /// <summary>
        /// Transform a given <see cref="ReceivedMessage"/> to a Canonical <see cref="MessagingContext"/> instance.
        /// </summary>
        /// <param name="message">Given message to transform.</param>
        /// <returns></returns>
        public async Task <MessagingContext> TransformAsync(ReceivedMessage message)
        {
            var receivedEntityMessage = message as ReceivedEntityMessage;

            if (receivedEntityMessage == null)
            {
                throw new NotSupportedException(
                          $"Minder Notify Transformer only supports transforming instances of type {typeof(ReceivedEntityMessage)}");
            }

            var as4Transformer       = new AS4MessageTransformer();
            MessagingContext context = await as4Transformer.TransformAsync(message);

            NotifyMessageEnvelope notifyMessage =
                await CreateNotifyMessageEnvelope(
                    context.AS4Message,
                    context.AS4Message.GetPrimaryMessageId(),
                    receivedEntityMessage.Entity.GetType());

            context.ModifyContext(notifyMessage);

            return(context);
        }
Example #17
0
        /// <summary>
        /// Start Mapping from a <see cref="SubmitMessage"/>
        /// to an <see cref="AS4Message"/>
        /// </summary>
        /// <param name="messagingContext"></param>
        /// <returns></returns>
        public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext)
        {
            if (messagingContext == null)
            {
                throw new ArgumentNullException(nameof(messagingContext));
            }

            SubmitMessage submitMessage = messagingContext.SubmitMessage;

            if (submitMessage == null)
            {
                throw new InvalidOperationException(
                          $"{nameof(CreateAS4MessageStep)} requires a SubmitMessage to create an AS4Message from but no AS4Message is present in the MessagingContext");
            }

            if (messagingContext.SendingPMode == null)
            {
                Logger.Debug("No SendingPMode was found, only use information from SubmitMessage to create AS4 UserMessage");
            }

            ValidateSubmitMessage(submitMessage);

            Logger.Trace("Create UserMessage for SubmitMessage");
            UserMessage userMessage = SubmitMessageMap.CreateUserMessage(submitMessage, submitMessage.PMode);

            Logger.Info($"{messagingContext.LogTag} UserMessage with Id \"{userMessage.MessageId}\" created from SubmitMessage");
            AS4Message as4Message = AS4Message.Create(userMessage, messagingContext.SendingPMode);

            IEnumerable <Attachment> attachments =
                await RetrieveAttachmentsForAS4MessageAsync(submitMessage.Payloads)
                .ConfigureAwait(false);

            as4Message.AddAttachments(attachments);

            messagingContext.ModifyContext(as4Message);
            return(StepResult.Success(messagingContext));
        }