/// <summary> /// Receives an AS2 Message in the form of a map of headers together with the payload, /// which is made available in an input stream /// <p>If persisting message to the Message Repository fails, we have to return negative MDN.</p> /// </summary> /// <param name="httpHeaders">the http headers received</param> /// <param name="mimeMessage">supplies the MIME message</param> /// <returns>MDN object to signal if everything is ok or if some error occurred while receiving</returns> public MimeMessage Receive(IHeaderDictionary httpHeaders, MimeMessage mimeMessage) { Logger.Debug("Receiving message .."); SMimeReader sMimeReader = new SMimeReader(mimeMessage); // Get timestamp using signature as input Timestamp t2 = this.timestampProvider.Generate(sMimeReader.GetSignature(), Direction.IN); // Initiate MDN MdnBuilder mdnBuilder = MdnBuilder.NewInstance(mimeMessage); mdnBuilder.AddHeader(MdnHeader.Date, t2.GetDate()); // Extract Message-ID TransmissionIdentifier transmissionIdentifier = TransmissionIdentifier.FromHeader(httpHeaders[As2Header.MessageId]); mdnBuilder.AddHeader(MdnHeader.OriginalMessageId, httpHeaders[As2Header.MessageId]); // Extract signed digest and digest algorithm SMimeDigestMethod digestMethod = sMimeReader.GetDigestMethod(); // Extract content headers byte[] headerBytes = sMimeReader.GetBodyHeader(); Stream bodyStream = sMimeReader.GetBodyInputStream(); byte[] bodyBytes = bodyStream.ToBuffer(); mdnBuilder.AddHeader(MdnHeader.OriginalContentHeader, headerBytes); // Extract SBDH Mx.Peppol.Common.Model.Header header; bodyStream.Seek(0, SeekOrigin.Begin); using (var sbdReader = SbdReader.NewInstance(bodyStream)) { header = sbdReader.Header; // Perform validation of SBDH this.transmissionVerifier.Verify(header, Direction.IN); // Extract "fresh" InputStream using (Stream payloadInputStream = sMimeReader.GetBodyInputStream()) { // Persist content this.persisterHandler.Persist( transmissionIdentifier, header, new UnclosableInputStream(payloadInputStream)); } // Fetch calculated digest var s = SHA1.Create(); var hash = s.ComputeHash(headerBytes.Concat(bodyBytes).ToArray()); Digest calculatedDigest = Digest.Of(DigestMethod.Sha1, hash); mdnBuilder.AddHeader(MdnHeader.ReceivedContentMic, new Mic(calculatedDigest)); var check = this.VerifySignature(mimeMessage.Body as MultipartSigned, out var signatures); if (!check || signatures.Count != 1) { throw new NotSupportedException("Firma non valida"); } var signature = signatures[0]; var certificate = signature.SignerCertificate as SecureMimeDigitalCertificate; Debug.Assert(certificate != null, nameof(certificate) + " != null"); this.certificateValidator.Validate(Service.Ap, certificate.Certificate); // Create receipt (MDN) mdnBuilder.AddHeader(MdnHeader.Disposition, Disposition.Processed); MimeMessage mdn = this.sMimeMessageFactory.CreateSignedMimeMessage(mdnBuilder.Build(), digestMethod); mdn.Headers.Add(As2Header.As2Version, As2Header.Version); mdn.Headers.Add(As2Header.As2From, httpHeaders[As2Header.As2To]); mdn.Headers.Add(As2Header.As2To, httpHeaders[As2Header.As2From]); return(mdn); } }
public void DoPost() { var headers = this.httpContext.Request.Headers; var messageId = headers["message-id"]; if (string.IsNullOrWhiteSpace(messageId)) { var errorResult = new ContentResult(); errorResult.StatusCode = StatusCodes.Status400BadRequest; errorResult.Content = "Header field 'Message-ID' not found."; throw new NotSupportedException("error management"); // return errorResult; } Trace root = Trace.Create(); root.Record(Annotations.ServiceName("as2servlet.post")); root.Record(Annotations.ServerRecv()); root.Record(Annotations.Tag("message-id", messageId)); Logger.Debug("Receiving HTTP POST request"); try { // Read MIME message var bodyStream = this.httpContext.Request.Body; var bodyData = bodyStream.ToBuffer(); MimeMessage mimeMessage = MimeMessageHelper.CreateMimeMessageAssistedByHeaders(bodyData.ToStream(), headers); try { Trace span = root.Child(); span.Record(Annotations.ServiceName("as2message")); span.Record(Annotations.ServerRecv()); MimeMessage mdn = this.inboundHandlerProvider().Receive(headers, mimeMessage); span.Record(Annotations.ServerSend()); span = root.Child(); span.Record(Annotations.ServiceName("mdn")); span.Record(Annotations.ServerRecv()); this.WriteMdn(this.httpContext.Response, mdn, (int)HttpStatusCode.OK); span.Record(Annotations.ServerSend()); } catch (HyperwayAs2InboundException e) { String identifier = Guid.NewGuid().ToString(); Logger.ErrorFormat("Error [{0}] {1}", identifier, e); // Open message for reading SMimeReader sMimeReader = new SMimeReader(mimeMessage); // Begin builder MdnBuilder mdnBuilder = MdnBuilder.NewInstance(mimeMessage); // Original Message-Id mdnBuilder.AddHeader(MdnHeader.OriginalMessageId, headers[As2Header.MessageId]); // Disposition from exception mdnBuilder.AddHeader(MdnHeader.Disposition, e.Disposition); mdnBuilder.AddText(String.Format("Error [{0}]", identifier), e.Message); // Build and add headers MimeMessage mdn = this.sMimeMessageFactory.CreateSignedMimeMessage( mdnBuilder.Build(), sMimeReader.GetDigestMethod()); mdn.Headers.Add(As2Header.As2Version, As2Header.Version); mdn.Headers.Add(As2Header.As2From, headers[As2Header.As2To]); mdn.Headers.Add(As2Header.As2To, headers[As2Header.As2From]); this.WriteMdn(this.httpContext.Response, mdn, (int)HttpStatusCode.BadRequest); } } catch (Exception e) { root.Record(Annotations.Tag("exception", e.Message)); // Unexpected internal error, cannot proceed, return HTTP 500 and partly MDN to indicating the problem Logger.ErrorFormat("Internal error occured: {0}", e.Message); Logger.Error("Attempting to return MDN with explanatory message and HTTP 500 status"); // TODO: manage failure this.WriteFailureWithExplanation(this.httpContext.Request, this.httpContext.Response, e); } // MDC.clear(); root.Record(Annotations.ServerSend()); }