use of com.helger.as2lib.disposition.AS2DispositionException in project as2-lib by phax.
the class AS2SenderModule method _sendViaHTTP.
private void _sendViaHTTP(@Nonnull final AS2Message aMsg, @Nonnull final MimeBodyPart aSecuredMimePart, @Nullable final MIC aMIC, @Nullable final EContentTransferEncoding eCTE, @Nullable final IHTTPOutgoingDumper aOutgoingDumper, @Nullable final IHTTPIncomingDumper aIncomingDumper, @Nonnull final AS2ResourceHelper aResHelper) throws AS2Exception, IOException, MessagingException {
final Partnership aPartnership = aMsg.partnership();
// Create the HTTP connection
final String sUrl = aPartnership.getAS2URL();
final EHttpMethod eRequestMethod = EHttpMethod.POST;
// decide on the connection type to use according to the MimeBodyPart:
// If it contains the data, (and no DataHandler), then use HttpUrlClient,
// otherwise, use HttpClient
final AS2HttpClient aConn = getHttpClient(sUrl, eRequestMethod, getSession().getHttpProxy());
try {
if (aOutgoingDumper != null)
aOutgoingDumper.start(sUrl, aMsg);
if (LOGGER.isInfoEnabled())
LOGGER.info("Connecting to " + sUrl + aMsg.getLoggingText());
final boolean bQuoteHeaderValues = isQuoteHeaderValues();
updateHttpHeaders(new AS2HttpHeaderSetter(aConn, aOutgoingDumper, bQuoteHeaderValues), aMsg);
if (aOutgoingDumper != null)
aOutgoingDumper.finishedHeaders();
aMsg.attrs().putIn(CNetAttribute.MA_DESTINATION_IP, aConn.getURL().getHost());
aMsg.attrs().putIn(CNetAttribute.MA_DESTINATION_PORT, aConn.getURL().getPort());
final InputStream aMsgIS = aSecuredMimePart.getInputStream();
// Transfer the data
final StopWatch aSW = StopWatch.createdStarted();
final long nBytes = aConn.send(aMsgIS, eCTE, aOutgoingDumper, aResHelper);
aSW.stop();
if (LOGGER.isInfoEnabled())
LOGGER.info("AS2 Message transferred " + AS2IOHelper.getTransferRate(nBytes, aSW) + aMsg.getLoggingText());
if (aOutgoingDumper != null)
aOutgoingDumper.finishedPayload();
final int nHttpResponseCode = aConn.getResponseCode();
if (getOutgoingHttpCallback() != null)
getOutgoingHttpCallback().onOutgoingHttpMessage(true, aMsg.getAS2From(), aMsg.getAS2To(), aMsg.getMessageID(), aMIC == null ? null : aMIC.getClone(), eCTE, sUrl, nHttpResponseCode);
// Check the HTTP Response code
if (AS2HttpClient.isErrorResponseCode(nHttpResponseCode)) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Error URL '" + sUrl + "' - HTTP " + nHttpResponseCode + " " + aConn.getResponseMessage() + " " + aMsg.getLoggingText());
throw new AS2HttpResponseException(sUrl, nHttpResponseCode, aConn.getResponseMessage());
}
// Receive an MDN
try {
// Receive an MDN
if (aMsg.isRequestingMDN()) {
// Check if the AsyncMDN is required
if (aPartnership.getAS2ReceiptDeliveryOption() == null) {
// Note: If an MDN is requested, a MIC is present
assert aMIC != null;
receiveSyncMDN(aMsg, aConn, aMIC, aIncomingDumper, aResHelper);
if (LOGGER.isInfoEnabled())
LOGGER.info("message sent" + aMsg.getLoggingText());
}
}
} catch (final AS2DispositionException ex) {
// was not successful
throw ex;
} catch (final AS2Exception ex) {
// Don't re-send or fail, just log an error if one occurs while
// receiving the MDN
onReceivedMDNError(aMsg, ex);
}
} finally {
// Closes all resources
aConn.disconnect();
}
}
use of com.helger.as2lib.disposition.AS2DispositionException in project as2-lib by phax.
the class MessageFileModule method handle.
public void handle(@Nonnull final String sAction, @Nonnull final IMessage aMsg, @Nullable final Map<String, Object> aOptions) throws AS2Exception {
// store message content
try {
final File aMsgFile = getFile(aMsg, getAttributeAsStringRequired(ATTR_FILENAME));
try (final InputStream aIS = aMsg.getData().getInputStream()) {
store(aMsgFile, aIS);
}
aMsg.attrs().put(MessageParameters.ATTR_STORED_FILE_NAME, aMsgFile.getAbsolutePath());
LOGGER.info("stored message to " + aMsgFile.getAbsolutePath() + aMsg.getLoggingText());
} catch (final AS2DispositionException ex) {
// Re-throw "as is"
throw ex;
} catch (final Exception ex) {
throw AS2DispositionException.wrap(ex, () -> DispositionType.createError("error-storing-transaction"), () -> AbstractActiveNetModule.DISP_STORAGE_FAILED);
}
// Store message headers and attributes
final String sHeaderFilename = getHeaderFilename();
if (sHeaderFilename != null) {
try {
final File aHeaderFile = getFile(aMsg, sHeaderFilename);
try (final InputStream aIS = getHeaderStream(aMsg, getCharset())) {
store(aHeaderFile, aIS);
}
LOGGER.info("stored headers to " + aHeaderFile.getAbsolutePath() + aMsg.getLoggingText());
} catch (final IOException ex) {
throw WrappedAS2Exception.wrap(ex);
}
}
}
use of com.helger.as2lib.disposition.AS2DispositionException in project as2-lib by phax.
the class AS2ReceiverHandler method handleIncomingMessage.
/**
* This method can be used to handle an incoming HTTP message AFTER the
* headers where extracted.
*
* @param sClientInfo
* Client connection info
* @param aMsgData
* The message body
* @param aMsg
* The AS2 message that will be filled by this method
* @param aResponseHandler
* The response handler which handles HTTP error messages as well as
* synchronous MDN.
*/
public void handleIncomingMessage(@Nonnull final String sClientInfo, @Nonnull final DataSource aMsgData, @Nonnull final AS2Message aMsg, @Nonnull final IAS2HttpResponseHandler aResponseHandler) {
// handler, to avoid the decrypted content gets removed (see issue #135)
try (final AS2ResourceHelper aResHelper = new AS2ResourceHelper()) {
try {
final IAS2Session aSession = m_aReceiverModule.getSession();
try {
// Put received data in a MIME body part
final String sReceivedContentType = AS2HttpHelper.getCleanContentType(aMsg.getHeader(CHttpHeader.CONTENT_TYPE));
final MimeBodyPart aReceivedPart = new MimeBodyPart();
aReceivedPart.setDataHandler(new DataHandler(aMsgData));
// Header must be set AFTER the DataHandler!
aReceivedPart.setHeader(CHttpHeader.CONTENT_TYPE, sReceivedContentType);
aMsg.setData(aReceivedPart);
} catch (final Exception ex) {
throw new AS2DispositionException(DispositionType.createError("unexpected-processing-error"), AbstractActiveNetModule.DISP_PARSING_MIME_FAILED, ex);
}
// update the message
try {
final String sAS2From = aMsg.getAS2From();
aMsg.partnership().setSenderAS2ID(sAS2From);
final String sAS2To = aMsg.getAS2To();
aMsg.partnership().setReceiverAS2ID(sAS2To);
// Fill all partnership attributes etc.
aSession.getPartnershipFactory().updatePartnership(aMsg, false);
} catch (final AS2Exception ex) {
throw AS2DispositionException.wrap(ex, () -> DispositionType.createError("authentication-failed"), () -> AbstractActiveNetModule.DISP_PARTNERSHIP_NOT_FOUND);
}
// Per RFC5402 compression is always before encryption but can be before
// or after signing of message but only in one place
final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper();
boolean bIsDecompressed = false;
// Decrypt and verify signature of the data, and attach data to the
// message
decrypt(aMsg, aResHelper);
if (aCryptoHelper.isCompressed(aMsg.getContentType())) {
if (LOGGER.isTraceEnabled())
LOGGER.trace("Decompressing received message before checking signature...");
decompress(aMsg);
bIsDecompressed = true;
}
verify(aMsg, aResHelper);
if (aCryptoHelper.isCompressed(aMsg.getContentType())) {
// or after signing of message but only in one place
if (bIsDecompressed) {
throw new AS2DispositionException(DispositionType.createError("decompression-failed"), AbstractActiveNetModule.DISP_DECOMPRESSION_ERROR, new Exception("Message has already been decompressed. Per RFC5402 it cannot occur twice."));
}
if (LOGGER.isTraceEnabled())
if (aMsg.attrs().containsKey(AS2Message.ATTRIBUTE_RECEIVED_SIGNED))
LOGGER.trace("Decompressing received message after verifying signature...");
else
LOGGER.trace("Decompressing received message after decryption...");
decompress(aMsg);
bIsDecompressed = true;
}
if (LOGGER.isTraceEnabled())
try {
LOGGER.trace("SMIME Decrypted Content-Disposition: " + aMsg.getContentDisposition() + "\n Content-Type received: " + aMsg.getContentType() + "\n HEADERS after decryption: " + aMsg.getData().getAllHeaders() + "\n Content-Disposition in MSG detData() MIMEPART after decryption: " + aMsg.getData().getContentType());
} catch (final MessagingException ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Failed to trace message: " + aMsg, ex);
}
// Validate the received message before storing
try {
aSession.getMessageProcessor().handle(IProcessorStorageModule.DO_VALIDATE_BEFORE_STORE, aMsg, null);
} catch (final AS2NoModuleException ex) {
// No module installed - ignore
} catch (final AS2Exception ex) {
// Issue 90 - use CRLF as separator
throw AS2DispositionException.wrap(ex, () -> DispositionType.createError("unexpected-processing-error"), () -> StringHelper.getConcatenatedOnDemand(AbstractActiveNetModule.DISP_VALIDATION_FAILED, CHttp.EOL, _getDispositionText(ex)));
}
// Store the received message
try {
aSession.getMessageProcessor().handle(IProcessorStorageModule.DO_STORE, aMsg, null);
} catch (final AS2NoModuleException ex) {
// No module installed - ignore
} catch (final AS2Exception ex) {
// Issue 90 - use CRLF as separator
throw AS2DispositionException.wrap(ex, () -> DispositionType.createError("unexpected-processing-error"), () -> StringHelper.getConcatenatedOnDemand(AbstractActiveNetModule.DISP_STORAGE_FAILED, CHttp.EOL, _getDispositionText(ex)));
}
// Validate the received message after storing
try {
aSession.getMessageProcessor().handle(IProcessorStorageModule.DO_VALIDATE_AFTER_STORE, aMsg, null);
} catch (final AS2NoModuleException ex) {
// No module installed - ignore
} catch (final AS2Exception ex) {
// Issue 90 - use CRLF as separator
throw AS2DispositionException.wrap(ex, () -> DispositionType.createError("unexpected-processing-error"), () -> StringHelper.getConcatenatedOnDemand(AbstractActiveNetModule.DISP_VALIDATION_FAILED, CHttp.EOL, _getDispositionText(ex)));
}
try {
if (aMsg.isRequestingMDN()) {
if (LOGGER.isTraceEnabled())
LOGGER.trace("AS2 message is requesting an MDN");
// Transmit a success MDN if requested
sendMDN(sClientInfo, aResponseHandler, aMsg, DispositionType.createSuccess(), AbstractActiveNetModule.DISP_SUCCESS, ESuccess.SUCCESS);
} else {
if (LOGGER.isTraceEnabled())
LOGGER.trace("AS2 message is not requesting an MDN - just sending HTTP 200 (OK)");
// Just send a HTTP OK
HTTPHelper.sendSimpleHTTPResponse(aResponseHandler, CHttp.HTTP_OK);
if (LOGGER.isInfoEnabled())
LOGGER.info("sent HTTP OK " + sClientInfo + aMsg.getLoggingText());
}
} catch (final Exception ex) {
throw new AS2Exception("Error creating and returning MDN, message was stilled processed", ex);
}
} catch (final AS2DispositionException ex) {
sendMDN(sClientInfo, aResponseHandler, aMsg, ex.getDisposition(), ex.getText(), ESuccess.FAILURE);
m_aReceiverModule.handleError(aMsg, ex);
} catch (final AS2Exception ex) {
m_aReceiverModule.handleError(aMsg, ex);
} finally {
// close the temporary shared stream if it exists
final TempSharedFileInputStream sis = aMsg.getTempSharedFileInputStream();
if (null != sis) {
try {
sis.closeAll();
} catch (final IOException e) {
LOGGER.error("Exception while closing TempSharedFileInputStream", e);
}
}
}
}
}
use of com.helger.as2lib.disposition.AS2DispositionException in project as2-lib by phax.
the class AS2ReceiverHandler method decrypt.
protected void decrypt(@Nonnull final IMessage aMsg, @Nonnull final AS2ResourceHelper aResHelper) throws AS2Exception {
final ICertificateFactory aCertFactory = m_aReceiverModule.getSession().getCertificateFactory();
final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper();
try {
final boolean bDisableDecrypt = aMsg.partnership().isDisableDecrypt();
final boolean bMsgIsEncrypted = aCryptoHelper.isEncrypted(aMsg.getData());
final boolean bForceDecrypt = aMsg.partnership().isForceDecrypt();
if (bMsgIsEncrypted && bDisableDecrypt) {
if (LOGGER.isInfoEnabled())
LOGGER.info("Message claims to be encrypted but decryption is disabled" + aMsg.getLoggingText());
} else if (bMsgIsEncrypted || bForceDecrypt) {
// Decrypt
if (bForceDecrypt && !bMsgIsEncrypted) {
if (LOGGER.isInfoEnabled())
LOGGER.info("Forced decrypting" + aMsg.getLoggingText());
} else if (LOGGER.isDebugEnabled())
LOGGER.debug("Decrypting" + aMsg.getLoggingText());
final X509Certificate aReceiverCert = aCertFactory.getCertificate(aMsg, ECertificatePartnershipType.RECEIVER);
final PrivateKey aReceiverKey = aCertFactory.getPrivateKey(aReceiverCert);
final MimeBodyPart aDecryptedData = aCryptoHelper.decrypt(aMsg.getData(), aReceiverCert, aReceiverKey, bForceDecrypt, aResHelper);
aMsg.setData(aDecryptedData);
// Remember that message was encrypted
aMsg.attrs().putIn(AS2Message.ATTRIBUTE_RECEIVED_ENCRYPTED, true);
if (LOGGER.isInfoEnabled())
LOGGER.info("Successfully decrypted incoming AS2 message" + aMsg.getLoggingText());
}
} catch (final AS2DispositionException ex) {
// Re-throw "as is"
throw ex;
} catch (final Exception ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Error decrypting " + aMsg.getLoggingText() + ": " + ex.getMessage());
throw new AS2DispositionException(DispositionType.createError("decryption-failed"), AbstractActiveNetModule.DISP_DECRYPTION_ERROR, ex);
}
}
use of com.helger.as2lib.disposition.AS2DispositionException in project as2-lib by phax.
the class AS2ReceiverHandler method decompress.
protected void decompress(@Nonnull final IMessage aMsg) throws AS2DispositionException {
try {
if (aMsg.partnership().isDisableDecompress()) {
if (LOGGER.isInfoEnabled())
LOGGER.info("Message claims to be compressed but decompression is disabled" + aMsg.getLoggingText());
} else {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Decompressing a compressed AS2 message");
MimeBodyPart aDecompressedPart;
final ZlibExpanderProvider aExpander = new ZlibExpanderProvider();
// Compress using stream
if (LOGGER.isDebugEnabled()) {
final StringBuilder aSB = new StringBuilder();
aSB.append("Headers before uncompress\n");
final MimeBodyPart part = aMsg.getData();
final Enumeration<String> aHeaderLines = part.getAllHeaderLines();
while (aHeaderLines.hasMoreElements()) {
aSB.append(aHeaderLines.nextElement()).append('\n');
}
aSB.append("done");
LOGGER.debug(aSB.toString());
}
// The default buffer size in BufferedInputStream is 8192
final SMIMECompressedParser aCompressedParser = new SMIMECompressedParser(aMsg.getData());
// TODO: get buffer from configuration
aDecompressedPart = SMIMEUtil.toMimeBodyPart(aCompressedParser.getContent(aExpander));
// Update the message object
aMsg.setData(aDecompressedPart);
// Remember that message was decompressed
aMsg.attrs().putIn(AS2Message.ATTRIBUTE_RECEIVED_COMPRESSED, true);
if (LOGGER.isInfoEnabled())
LOGGER.info("Successfully decompressed incoming AS2 message" + aMsg.getLoggingText());
}
} catch (final SMIMEException | CMSException | MessagingException ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Error decompressing received message", ex);
throw new AS2DispositionException(DispositionType.createError("unexpected-processing-error"), AbstractActiveNetModule.DISP_DECOMPRESSION_ERROR, ex);
}
}
Aggregations