/// <summary> /// Execute the step for a given <paramref name="messagingContext" />. /// </summary> /// <param name="messagingContext">Message used during the step execution.</param> /// <returns></returns> public Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext == null) { throw new ArgumentNullException(nameof(messagingContext)); } if (messagingContext.AS4Message == null) { throw new InvalidOperationException( $"{nameof(VerifyPullRequestAuthorizationStep)} requires a MessagingContext with a AS4Message to verify the PullRequest"); } AS4Message as4Message = messagingContext.AS4Message; var authorizationMap = new PullAuthorizationMapService(_pullAuthorizationMapProvider); if (authorizationMap.IsPullRequestAuthorized(as4Message)) { return(StepResult.SuccessAsync(messagingContext)); } string mpc = (as4Message.FirstSignalMessage as PullRequest)?.Mpc ?? string.Empty; throw new SecurityException( $"{messagingContext.LogTag} PullRequest for MPC {mpc} is not authorized. " + "Either change the PullRequest MPC or add the MPC value to the authorization map"); }
/// <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 Task <StepResult> HandleResponse(IAS4Response response) { response.OriginalRequest.ModifyContext(response.ReceivedStream, response.OriginalRequest.Mode); response.OriginalRequest.ModifyContext(response.ReceivedAS4Message); return(StepResult.SuccessAsync(response.OriginalRequest)); }
/// <summary> /// Start creating a <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.AS4Message == null) { throw new InvalidOperationException( $"{nameof(CreateDefaultAS4MessageStep)} requires an AS4Message to assign the default UserMessage to but no AS4Message is present in the MessagingContext"); } SendingProcessingMode pmode = _config.GetSendingPMode(DefaultPmode); IEnumerable <PartInfo> parts = messagingContext.AS4Message.Attachments.Select(PartInfo.CreateFor); UserMessage userMessage = SendingPModeMap.CreateUserMessage(pmode, parts.ToArray()); messagingContext.AS4Message.AddMessageUnit(userMessage); messagingContext.SendingPMode = pmode; Logger.Info($"{messagingContext.LogTag} Default AS4Message is created using SendingPMode {pmode.Id}"); return(await StepResult.SuccessAsync(messagingContext)); }
/// <summary> /// Execute the step for a given <paramref name="messagingContext"/>. /// </summary> /// <param name="messagingContext">The Message used during the step execution.</param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext?.AS4Message == null) { throw new InvalidOperationException( $"{nameof(StoreAS4MessageStep)} requires an AS4Message to save but no AS4Message is present in the MessagingContext"); } Logger.Trace("Storing the AS4Message with Operation=ToBeProcessed..."); using (DatastoreContext context = _createContext()) { var repository = new DatastoreRepository(context); var service = new OutMessageService(_config, repository, _messageBodyStore); service.InsertAS4Message( messagingContext.AS4Message, messagingContext.SendingPMode, messagingContext.ReceivingPMode); try { await context.SaveChangesAsync().ConfigureAwait(false); } catch { messagingContext.ErrorResult = new ErrorResult( "Unable to store the received message due to an exception occured during the saving operation", ErrorAlias.Other); throw; } } Logger.Trace("Stored the AS4Message with Operation=ToBeProcesed"); return(await StepResult.SuccessAsync(messagingContext)); }
/// <summary> /// Sign 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.AS4Message == null) { throw new InvalidOperationException( $"{nameof(SignAS4MessageStep)} requires an AS4Message to sign but no AS4Message is present in the MessagingContext"); } if (messagingContext.AS4Message.IsEmpty) { Logger.Debug("No signing will be performed on the message because it's empty"); return(await StepResult.SuccessAsync(messagingContext)); } Signing signInfo = RetrieveSigningInformation( messagingContext.AS4Message, messagingContext.SendingPMode, messagingContext.ReceivingPMode); if (signInfo == null) { Logger.Trace("No signing will be performend on the message because no signing information was found in either Sending or Receiving PMode"); return(await StepResult.SuccessAsync(messagingContext)); } if (signInfo.IsEnabled == false) { Logger.Trace("No signing will be performend on the message because the PMode siging information is disabled"); return(await StepResult.SuccessAsync(messagingContext)); } Logger.Info($"(Outbound)[{messagingContext.AS4Message.GetPrimaryMessageId()}] Sign AS4Message with given signing information of the PMode"); X509Certificate2 certificate = RetrieveCertificate(signInfo); var settings = new CalculateSignatureConfig( signingCertificate: certificate, referenceTokenType: signInfo.KeyReferenceMethod, signingAlgorithm: signInfo.Algorithm, hashFunction: signInfo.HashFunction); SignAS4Message(settings, messagingContext.AS4Message); JournalLogEntry logEntry = JournalLogEntry.CreateFrom( messagingContext.AS4Message, $"Signed with certificate {settings.SigningCertificate.FriendlyName} and reference {settings.ReferenceTokenType} " + $"using algorithm {settings.SigningAlgorithm} and hash {settings.HashFunction}"); return(await StepResult .Success(messagingContext) .WithJournalAsync(logEntry)); }
/// <summary> /// Start Encrypting AS4 Message /// </summary> /// <param name="messagingContext"></param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext == null) { throw new ArgumentNullException(nameof(messagingContext)); } if (messagingContext.AS4Message == null) { throw new InvalidOperationException( $"{nameof(EncryptAS4MessageStep)} requires an AS4Message to encrypt but no AS4Message is present in the MessagingContext"); } if (messagingContext.SendingPMode == null) { throw new InvalidOperationException( $"{nameof(EncryptAS4MessageStep)} requires a SendingPMode to encrypt the AS4Message but no SendingPMode is present in the MessagingContext"); } if (messagingContext.SendingPMode.Security?.Encryption == null || messagingContext.SendingPMode.Security.Encryption.IsEnabled == false) { Logger.Trace( "No encryption of the AS4Message will happen because the " + $"SendingPMode {messagingContext.SendingPMode?.Id} Security.Encryption.IsEnabled is disabled"); return(await StepResult.SuccessAsync(messagingContext)); } Logger.Info( $"(Outbound)[{messagingContext.AS4Message.GetPrimaryMessageId()}] Encrypt AS4Message with given encryption information " + $"configured in the SendingPMode: {messagingContext.SendingPMode.Id}"); KeyEncryptionConfiguration keyEncryptionConfig = RetrieveKeyEncryptionConfig(messagingContext.SendingPMode); Encryption encryptionSettings = messagingContext.SendingPMode.Security.Encryption; var dataEncryptionConfig = new DataEncryptionConfiguration( encryptionMethod: encryptionSettings.Algorithm, algorithmKeySize: encryptionSettings.AlgorithmKeySize); EncryptAS4Message( messagingContext.AS4Message, keyEncryptionConfig, dataEncryptionConfig); var journal = JournalLogEntry.CreateFrom( messagingContext.AS4Message, $"Encrypted using certificate {keyEncryptionConfig.EncryptionCertificate.FriendlyName} and " + $"key encryption method: {keyEncryptionConfig.EncryptionMethod}, key digest method: {keyEncryptionConfig.DigestMethod}, " + $"key mgf: {keyEncryptionConfig.Mgf} and Data encryption method: {dataEncryptionConfig.EncryptionMethod}, " + $" data encryption type: {dataEncryptionConfig.EncryptionType}, data transport algorithm: {dataEncryptionConfig.TransformAlgorithm}"); return(await StepResult .Success(messagingContext) .WithJournalAsync(journal)); }
/// <summary> /// Validates whether the configured Sending PMode is valid and can be used. /// </summary> /// <param name="messagingContext">Message used during the step execution.</param> /// <returns></returns> public Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { var result = SendingProcessingModeValidator.Instance.Validate(messagingContext.SendingPMode); if (result.IsValid) { return(StepResult.SuccessAsync(messagingContext)); } string description = result.AppendValidationErrorsToErrorMessage($"Sending PMode {messagingContext.SendingPMode.Id} was invalid:"); return(StepResult.FailedAsync(new MessagingContext(new ConfigurationErrorsException(description)))); }
/// <summary> /// Execute the step for a given <paramref name="messagingContext"/>. /// </summary> /// <param name="messagingContext">Message used during the step execution.</param> /// <returns></returns> public Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext == null) { throw new ArgumentNullException(nameof(messagingContext)); } if (messagingContext.ReceivedMessage == null) { throw new NotSupportedException( "DetermineRoutingStep requires a 'ReceivedMessage'"); } if (messagingContext.ReceivingPMode == null) { throw new InvalidOperationException( "No ReceivingPMode available is set." + "The ReceivingPMode is used to correctly forward the message with the provided configured values inside this PMode."); } if (messagingContext.ReceivingPMode.MessageHandling?.ForwardInformation == null) { throw new ConfigurationErrorsException( "The ReceivingPMode does not contain a MessageHandling.Forward element." + "This element is required in a Forwarding scenario."); } string sendingPModeId = messagingContext.ReceivingPMode.MessageHandling.ForwardInformation.SendingPMode; Logger.Trace($"SendingPMode {sendingPModeId} must be used to forward Message with Id {messagingContext.EbmsMessageId}"); if (String.IsNullOrWhiteSpace(sendingPModeId)) { throw new ConfigurationErrorsException( "The ReceivingPMode does not contain a SendingPMode-Id in the MessageHandling.Forward element." + "This SendingPMode-Id is required in a Forwarding scenario and will be used to forward the message to the next MSH."); } SendingProcessingMode sendingPMode = _configuration.GetSendingPMode(sendingPModeId); if (sendingPMode == null) { throw new ConfigurationErrorsException( $"No Sending Processing Mode found for {sendingPModeId}." + "Please provide a valid Id that points to a configured Sending PMode." + @"SendingPModes are configured in the .\config\send-pmodes\ folder."); } messagingContext.SendingPMode = sendingPMode; return(StepResult.SuccessAsync(messagingContext)); }
/// <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> /// Retrieve the PMode that must be used to send the SubmitMessage that is in the current Messagingcontext /> /// </summary> /// <param name="messagingContext"></param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext == null) { throw new ArgumentNullException(nameof(messagingContext)); } if (messagingContext.SubmitMessage == null) { throw new InvalidOperationException( $"{nameof(RetrieveSendingPModeStep)} requires an SubmitMessage to retrieve the SendingPMode from but no SubmitMessage is present in the MessagingContext"); } messagingContext.SubmitMessage.PMode = RetrieveSendPMode(messagingContext); messagingContext.SendingPMode = messagingContext.SubmitMessage.PMode; return(await StepResult.SuccessAsync(messagingContext)); }
/// <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> /// Execute the step for a given <paramref name="messagingContext" />. /// </summary> /// <param name="messagingContext">Message used during the step execution.</param> /// <returns></returns> public Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { return(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 Task <StepResult> HandleResponse(IAS4Response response) { IsCalled = true; return(StepResult.SuccessAsync(new MessagingContext(response.ReceivedStream, MessagingContextMode.Send))); }
public Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { return(StepResult.SuccessAsync(new MessagingContext(AS4Message.Empty, MessagingContextMode.Submit))); }
/// <summary> /// Execute the step for a given <paramref name="context"/>. /// </summary> /// <param name="context">Message used during the step execution.</param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.AS4Message == null) { throw new InvalidOperationException( $"{nameof(ValidateAS4MessageStep)} requires an AS4Message to validate but no AS4Message is present in the MessagingContext"); } Logger.Trace("Validating the received AS4Message ..."); if (SoapBodyIsNotEmpty(context.AS4Message)) { context.ErrorResult = SoapBodyAttachmentsNotSupported(); return(ValidationFailure(context)); } IEnumerable <PartInfo> notSupportedPartInfos = context.AS4Message.UserMessages.SelectMany( message => message.PayloadInfo.Where(payload => payload.Href.StartsWith("cid:") == false)); if (notSupportedPartInfos.Any()) { context.ErrorResult = ExternalPayloadError(notSupportedPartInfos); return(ValidationFailure(context)); } if (context.AS4Message.IsUserMessage) { AS4Message message = context.AS4Message; IEnumerable <PartInfo> unreferencedPartInfos = message.UserMessages .SelectMany(u => u.PayloadInfo) .Where(p => message.Attachments.FirstOrDefault(a => a.Matches(p)) == null); if (unreferencedPartInfos.Any()) { context.ErrorResult = AttachmentNotFoundInvalidHeaderError(unreferencedPartInfos); return(ValidationFailure(context)); } IEnumerable <IGrouping <string, PartInfo> > duplicatePartInfos = message.UserMessages .SelectMany(u => u.PayloadInfo) .GroupBy(p => p.Href) .Where(g => g.Count() != 1); if (duplicatePartInfos.Any()) { context.ErrorResult = DuplicateAttachmentInvalidHeaderError(duplicatePartInfos); return(ValidationFailure(context)); } } Logger.Trace($"{context.LogTag} Received AS4Message is valid"); return(await StepResult.SuccessAsync(context)); }