/** * Read headers and payload from the passed input stream provider. * * @param aISP The abstract input stream provider to use. May not be <code>null</code>. * @param aResponseHandler The HTTP response handler to be used. May not be <code>null</code>. * @param aMsg The Message to be filled. May not be <code>null</code>. * @return The payload of the HTTP request. * @throws IOException In case of error reading from the InputStream * @throws MessagingException In case header line parsing fails */ @Nonnull public static byte[] readHttpRequest( @Nonnull final IAS2InputStreamProvider aISP, @Nonnull final IAS2HttpResponseHandler aResponseHandler, @Nonnull final IMessage aMsg) throws IOException, MessagingException { // Get the stream to read from final InputStream aIS = aISP.getInputStream(); if (aIS == null) throw new IllegalStateException("Failed to open InputStream from " + aISP); // Read the HTTP meta data final String[] aRequest = _readRequestInfo(aIS); // Request method (e.g. "POST") aMsg.setAttribute(MA_HTTP_REQ_TYPE, aRequest[0]); // Request URL (e.g. "/as2") aMsg.setAttribute(MA_HTTP_REQ_URL, aRequest[1]); // HTTP version (e.g. "HTTP/1.1") aMsg.setAttribute(MA_HTTP_REQ_VERSION, aRequest[2]); // Parse all HTTP headers from stream final InternetHeaders aHeaders = new InternetHeaders(aIS); aMsg.setHeaders(aHeaders); // Read the message body - no Content-Transfer-Encoding handling final byte[] aPayload = readHttpPayload(aIS, aResponseHandler, aMsg); // Dump on demand if (isHTTPIncomingDumpEnabled()) dumpIncomingHttpRequest(getAllHTTPHeaderLines(aHeaders), aPayload, aMsg); return aPayload; // Don't close the IS here! }
@Nonnull public X509Certificate getCertificate( @Nonnull final IMessage aMsg, @Nullable final ECertificatePartnershipType ePartnershipType) throws OpenAS2Exception { final String sAlias = getAlias(aMsg.getPartnership(), ePartnershipType); return internalGetCertificate(sAlias, ePartnershipType); }
protected void decompress(@Nonnull final IMessage aMsg) throws DispositionException { try { if (aMsg.getPartnership().isDisableDecompress()) { s_aLogger.info( "Message claims to be compressed but decompression is disabled" + aMsg.getLoggingText()); } else { if (s_aLogger.isDebugEnabled()) s_aLogger.debug("Decompressing a compressed AS2 message"); final SMIMECompressed aCompressed = new SMIMECompressed(aMsg.getData()); // decompression step MimeBodyPart final MimeBodyPart aDecompressedPart = SMIMEUtil.toMimeBodyPart(aCompressed.getContent(new ZlibExpanderProvider())); // Update the message object aMsg.setData(aDecompressedPart); // Remember that message was decompressed aMsg.setAttribute(AS2Message.ATTRIBUTE_RECEIVED_COMPRESSED, Boolean.TRUE.toString()); s_aLogger.info("Successfully decompressed incoming AS2 message" + aMsg.getLoggingText()); } } catch (final Exception ex) { s_aLogger.error("Error decompressing received message", ex); throw new DispositionException( DispositionType.createError("unexpected-processing-error"), AbstractActiveNetModule.DISP_DECOMPRESSION_ERROR, ex); } }
@Nonnull public static byte[] readHttpPayload( @Nonnull final InputStream aIS, @Nonnull final IAS2HttpResponseHandler aResponseHandler, @Nonnull final IMessage aMsg) throws IOException { ValueEnforcer.notNull(aIS, "InputStream"); ValueEnforcer.notNull(aResponseHandler, "ResponseHandler"); ValueEnforcer.notNull(aMsg, "Msg"); final DataInputStream aDataIS = new DataInputStream(aIS); // Retrieve the message content byte[] aData = null; final String sContentLength = aMsg.getHeader(CAS2Header.HEADER_CONTENT_LENGTH); if (sContentLength == null) { // No "Content-Length" header present final String sTransferEncoding = aMsg.getHeader(CAS2Header.HEADER_TRANSFER_ENCODING); if (sTransferEncoding != null) { // Remove all whitespaces in the value if (sTransferEncoding.replaceAll("\\s+", "").equalsIgnoreCase("chunked")) { // chunked encoding int nLength = 0; for (; ; ) { // First get hex chunk length; followed by CRLF int nBlocklen = 0; for (; ; ) { int ch = aDataIS.readByte(); if (ch == '\n') break; if (ch >= 'a' && ch <= 'f') ch -= ('a' - 10); else if (ch >= 'A' && ch <= 'F') ch -= ('A' - 10); else if (ch >= '0' && ch <= '9') ch -= '0'; else continue; nBlocklen = (nBlocklen * 16) + ch; } // Zero length is end of chunks if (nBlocklen == 0) break; // Ok, now read new chunk final int nNewlen = nLength + nBlocklen; final byte[] aNewData = new byte[nNewlen]; if (nLength > 0) System.arraycopy(aData, 0, aNewData, 0, nLength); aDataIS.readFully(aNewData, nLength, nBlocklen); aData = aNewData; nLength = nNewlen; // And now the CRLF after the chunk; while (true) { final int n = aDataIS.readByte(); if (n == '\n') break; } } aMsg.setHeader(CAS2Header.HEADER_CONTENT_LENGTH, Integer.toString(nLength)); } else { // No "Content-Length" and unsupported "Transfer-Encoding" sendSimpleHTTPResponse(aResponseHandler, HttpURLConnection.HTTP_LENGTH_REQUIRED); throw new IOException("Transfer-Encoding unimplemented: " + sTransferEncoding); } } else { // No "Content-Length" and no "Transfer-Encoding" sendSimpleHTTPResponse(aResponseHandler, HttpURLConnection.HTTP_LENGTH_REQUIRED); throw new IOException("Content-Length missing"); } } else { // "Content-Length" is present // Receive the transmission's data // XX if a value > 2GB comes in, this will fail!! final int nContentSize = Integer.parseInt(sContentLength); aData = new byte[nContentSize]; aDataIS.readFully(aData); } return aData; }
protected void verify(@Nonnull final IMessage aMsg) throws OpenAS2Exception { final ICertificateFactory aCertFactory = m_aReceiverModule.getSession().getCertificateFactory(); final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper(); try { final boolean bDisableVerify = aMsg.getPartnership().isDisableVerify(); final boolean bMsgIsSigned = aCryptoHelper.isSigned(aMsg.getData()); final boolean bForceVerify = aMsg.getPartnership().isForceVerify(); if (bMsgIsSigned && bDisableVerify) { s_aLogger.info( "Message claims to be signed but signature validation is disabled" + aMsg.getLoggingText()); } else if (bMsgIsSigned || bForceVerify) { if (bForceVerify && !bMsgIsSigned) s_aLogger.info("Forced verify signature" + aMsg.getLoggingText()); else if (s_aLogger.isDebugEnabled()) s_aLogger.debug("Verifying signature" + aMsg.getLoggingText()); final X509Certificate aSenderCert = aCertFactory.getCertificateOrNull(aMsg, ECertificatePartnershipType.SENDER); boolean bUseCertificateInBodyPart; final ETriState eUseCertificateInBodyPart = aMsg.getPartnership().getVerifyUseCertificateInBodyPart(); if (eUseCertificateInBodyPart.isDefined()) { // Use per partnership bUseCertificateInBodyPart = eUseCertificateInBodyPart.getAsBooleanValue(); } else { // Use global value bUseCertificateInBodyPart = m_aReceiverModule.getSession().isCryptoVerifyUseCertificateInBodyPart(); } final MimeBodyPart aVerifiedData = aCryptoHelper.verify( aMsg.getData(), aSenderCert, bUseCertificateInBodyPart, bForceVerify); aMsg.setData(aVerifiedData); // Remember that message was signed and verified aMsg.setAttribute(AS2Message.ATTRIBUTE_RECEIVED_SIGNED, Boolean.TRUE.toString()); s_aLogger.info( "Successfully verified signature of incoming AS2 message" + aMsg.getLoggingText()); } } catch (final Exception ex) { s_aLogger.error( "Error verifying signature " + aMsg.getLoggingText() + ": " + ex.getMessage()); throw new DispositionException( DispositionType.createError("integrity-check-failed"), AbstractActiveNetModule.DISP_VERIFY_SIGNATURE_FAILED, ex); } }
protected void decrypt(@Nonnull final IMessage aMsg) throws OpenAS2Exception { final ICertificateFactory aCertFactory = m_aReceiverModule.getSession().getCertificateFactory(); final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper(); try { final boolean bDisableDecrypt = aMsg.getPartnership().isDisableDecrypt(); final boolean bMsgIsEncrypted = aCryptoHelper.isEncrypted(aMsg.getData()); final boolean bForceDecrypt = aMsg.getPartnership().isForceDecrypt(); if (bMsgIsEncrypted && bDisableDecrypt) { s_aLogger.info( "Message claims to be encrypted but decryption is disabled" + aMsg.getLoggingText()); } else if (bMsgIsEncrypted || bForceDecrypt) { // Decrypt if (bForceDecrypt && !bMsgIsEncrypted) s_aLogger.info("Forced decrypting" + aMsg.getLoggingText()); else if (s_aLogger.isDebugEnabled()) s_aLogger.debug("Decrypting" + aMsg.getLoggingText()); final X509Certificate aReceiverCert = aCertFactory.getCertificate(aMsg, ECertificatePartnershipType.RECEIVER); final PrivateKey aReceiverKey = aCertFactory.getPrivateKey(aMsg, aReceiverCert); final MimeBodyPart aDecryptedData = aCryptoHelper.decrypt(aMsg.getData(), aReceiverCert, aReceiverKey, bForceDecrypt); aMsg.setData(aDecryptedData); // Remember that message was encrypted aMsg.setAttribute(AS2Message.ATTRIBUTE_RECEIVED_ENCRYPTED, Boolean.TRUE.toString()); s_aLogger.info("Successfully decrypted incoming AS2 message" + aMsg.getLoggingText()); } } catch (final Exception ex) { s_aLogger.error("Error decrypting " + aMsg.getLoggingText() + ": " + ex.getMessage()); throw new DispositionException( DispositionType.createError("decryption-failed"), AbstractActiveNetModule.DISP_DECRYPTION_ERROR, ex); } }