Esempio n. 1
0
  public void handle(final AbstractActiveNetModule aOwner, @Nonnull final Socket aSocket) {
    final String sClientInfo = getClientInfo(aSocket);
    s_aLogger.info("Incoming connection " + sClientInfo);

    final AS2Message aMsg = createMessage(aSocket);

    final IAS2HttpResponseHandler aResponseHandler = new AS2HttpResponseHandlerSocket(aSocket);

    // Time the transmission
    final StopWatch aSW = StopWatch.createdStarted();
    byte[] aMsgData = null;
    try {
      // Read in the message request, headers, and data
      aMsgData =
          readAndDecodeHttpRequest(
              new AS2InputStreamProviderSocket(aSocket), aResponseHandler, aMsg);
    } catch (final Exception ex) {
      final NetException ne = new NetException(aSocket.getInetAddress(), aSocket.getPort(), ex);
      ne.terminate();
    }

    aSW.stop();

    if (aMsgData != null) {
      s_aLogger.info(
          "received "
              + IOHelper.getTransferRate(aMsgData.length, aSW)
              + " from "
              + sClientInfo
              + aMsg.getLoggingText());

      handleIncomingMessage(sClientInfo, aMsgData, aMsg, aResponseHandler);
    }
  }
Esempio n. 2
0
 /**
  * Create a new message and record the source ip and port
  *
  * @param aSocket The socket through which the message will be read.
  * @return The {@link AS2Message} to use and never <code>null</code>.
  */
 @Nonnull
 protected AS2Message createMessage(@Nonnull final Socket aSocket) {
   final AS2Message aMsg = new AS2Message();
   aMsg.setAttribute(CNetAttribute.MA_SOURCE_IP, aSocket.getInetAddress().toString());
   aMsg.setAttribute(CNetAttribute.MA_SOURCE_PORT, Integer.toString(aSocket.getPort()));
   aMsg.setAttribute(CNetAttribute.MA_DESTINATION_IP, aSocket.getLocalAddress().toString());
   aMsg.setAttribute(CNetAttribute.MA_DESTINATION_PORT, Integer.toString(aSocket.getLocalPort()));
   aMsg.setAttribute(AS2Message.ATTRIBUTE_RECEIVED, Boolean.TRUE.toString());
   return aMsg;
 }
  private void _sendAsyncMDN(@Nonnull final AS2Message aMsg) throws OpenAS2Exception {
    s_aLogger.info("Async MDN submitted" + aMsg.getLoggingText());
    final DispositionType aDisposition = DispositionType.createSuccess();

    try {
      final IMessageMDN aMdn = aMsg.getMDN();

      // Create a HTTP connection
      final String sUrl = aMsg.getAsyncMDNurl();
      final boolean bOutput = true;
      final boolean bInput = true;
      final boolean bUseCaches = false;
      final HttpURLConnection aConn =
          getConnection(sUrl, bOutput, bInput, bUseCaches, "POST", getSession().getHttpProxy());

      try {
        s_aLogger.info("connected to " + sUrl + aMsg.getLoggingText());

        aConn.setRequestProperty(CAS2Header.HEADER_CONNECTION, CAS2Header.DEFAULT_CONNECTION);
        aConn.setRequestProperty(CAS2Header.HEADER_USER_AGENT, CAS2Header.DEFAULT_USER_AGENT);
        // Copy all the header from mdn to the RequestProperties of conn
        final Enumeration<?> aHeaders = aMdn.getHeaders().getAllHeaders();
        while (aHeaders.hasMoreElements()) {
          final Header aHeader = (Header) aHeaders.nextElement();
          final String sHeaderValue =
              aHeader.getValue().replace('\t', ' ').replace('\n', ' ').replace('\r', ' ');
          aConn.setRequestProperty(aHeader.getName(), sHeaderValue);
        }

        // Note: closing this stream causes connection abort errors on some AS2
        // servers
        final OutputStream aMessageOS = aConn.getOutputStream();

        // Transfer the data
        final InputStream aMessageIS = aMdn.getData().getInputStream();
        final StopWatch aSW = StopWatch.createdStarted();
        final long nBytes = IOHelper.copy(aMessageIS, aMessageOS);
        aSW.stop();
        s_aLogger.info(
            "transferred " + IOHelper.getTransferRate(nBytes, aSW) + aMsg.getLoggingText());

        // Check the HTTP Response code
        final int nResponseCode = aConn.getResponseCode();
        if (nResponseCode != HttpURLConnection.HTTP_OK
            && nResponseCode != HttpURLConnection.HTTP_CREATED
            && nResponseCode != HttpURLConnection.HTTP_ACCEPTED
            && nResponseCode != HttpURLConnection.HTTP_PARTIAL
            && nResponseCode != HttpURLConnection.HTTP_NO_CONTENT) {
          s_aLogger.error(
              "sent AsyncMDN [" + aDisposition.getAsString() + "] Fail " + aMsg.getLoggingText());
          throw new HttpResponseException(sUrl, nResponseCode, aConn.getResponseMessage());
        }

        s_aLogger.info(
            "sent AsyncMDN [" + aDisposition.getAsString() + "] OK " + aMsg.getLoggingText());

        // log & store mdn into backup folder.
        try {
          getSession()
              .getMessageProcessor()
              .handle(IProcessorStorageModule.DO_STOREMDN, aMsg, null);
        } catch (final ComponentNotFoundException ex) {
          // May be
        }
      } finally {
        aConn.disconnect();
      }
    } catch (final HttpResponseException ex) {
      // Resend if the HTTP Response has an error code
      ex.terminate();
      _resend(aMsg, ex);
    } catch (final IOException ex) {
      // Resend if a network error occurs during transmission
      final OpenAS2Exception wioe = WrappedOpenAS2Exception.wrap(ex);
      wioe.addSource(OpenAS2Exception.SOURCE_MESSAGE, aMsg);
      wioe.terminate();

      _resend(aMsg, wioe);
    } catch (final Exception ex) {
      // Propagate error if it can't be handled by a resend
      throw WrappedOpenAS2Exception.wrap(ex);
    }
  }
Esempio n. 4
0
  /**
   * 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 byte[] aMsgData,
      @Nonnull final AS2Message aMsg,
      @Nonnull final IAS2HttpResponseHandler aResponseHandler) {
    // TODO store HTTP request, headers, and data to file in Received folder
    // -> use message-id for filename?
    try {
      final IAS2Session aSession = m_aReceiverModule.getSession();

      try {
        // Put received data in a MIME body part
        final ContentType aReceivedContentType =
            new ContentType(aMsg.getHeader(CAS2Header.HEADER_CONTENT_TYPE));
        final String sReceivedContentType = aReceivedContentType.toString();

        final MimeBodyPart aReceivedPart = new MimeBodyPart();
        aReceivedPart.setDataHandler(
            new DataHandler(new ByteArrayDataSource(aMsgData, sReceivedContentType, null)));

        // Header must be set AFTER the DataHandler!
        aReceivedPart.setHeader(CAS2Header.HEADER_CONTENT_TYPE, sReceivedContentType);
        aMsg.setData(aReceivedPart);
      } catch (final Exception ex) {
        throw new DispositionException(
            DispositionType.createError("unexpected-processing-error"),
            AbstractActiveNetModule.DISP_PARSING_MIME_FAILED,
            ex);
      }

      // Extract AS2 ID's from header, find the message's partnership and
      // update the message
      try {
        final String sAS2From = aMsg.getAS2From();
        aMsg.getPartnership().setSenderAS2ID(sAS2From);

        final String sAS2To = aMsg.getAS2To();
        aMsg.getPartnership().setReceiverAS2ID(sAS2To);

        // Fill all partnership attributes etc.
        aSession.getPartnershipFactory().updatePartnership(aMsg, false);
      } catch (final OpenAS2Exception ex) {
        throw new DispositionException(
            DispositionType.createError("authentication-failed"),
            AbstractActiveNetModule.DISP_PARTNERSHIP_NOT_FOUND,
            ex);
      }

      // 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);

      if (aCryptoHelper.isCompressed(aMsg.getContentType())) {
        if (s_aLogger.isTraceEnabled())
          s_aLogger.trace("Decompressing received message before checking signature...");
        decompress(aMsg);
        bIsDecompressed = true;
      }

      verify(aMsg);

      if (aCryptoHelper.isCompressed(aMsg.getContentType())) {
        // Per RFC5402 compression is always before encryption but can be before
        // or after signing of message but only in one place
        if (bIsDecompressed) {
          throw new DispositionException(
              DispositionType.createError("decompression-failed"),
              AbstractActiveNetModule.DISP_DECOMPRESSION_ERROR,
              new Exception(
                  "Message has already been decompressed. Per RFC5402 it cannot occur twice."));
        }

        if (s_aLogger.isTraceEnabled())
          if (aMsg.containsAttribute(AS2Message.ATTRIBUTE_RECEIVED_SIGNED))
            s_aLogger.trace("Decompressing received message after verifying signature...");
          else s_aLogger.trace("Decompressing received message after decryption...");
        decompress(aMsg);
        bIsDecompressed = true;
      }

      if (s_aLogger.isTraceEnabled())
        try {
          s_aLogger.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) {
          s_aLogger.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 NoModuleException ex) {
        // No module installed - ignore
      } catch (final OpenAS2Exception ex) {
        throw new DispositionException(
            DispositionType.createError("unexpected-processing-error"),
            AbstractActiveNetModule.DISP_VALIDATION_FAILED
                + "\n"
                + StackTraceHelper.getStackAsString(ex),
            ex);
      }

      // Store the received message
      try {
        aSession.getMessageProcessor().handle(IProcessorStorageModule.DO_STORE, aMsg, null);
      } catch (final NoModuleException ex) {
        // No module installed - ignore
      } catch (final OpenAS2Exception ex) {
        throw new DispositionException(
            DispositionType.createError("unexpected-processing-error"),
            AbstractActiveNetModule.DISP_STORAGE_FAILED + "\n" + ex.getMessage(),
            ex);
      }

      // Validate the received message after storing
      try {
        aSession
            .getMessageProcessor()
            .handle(IProcessorStorageModule.DO_VALIDATE_AFTER_STORE, aMsg, null);
      } catch (final NoModuleException ex) {
        // No module installed - ignore
      } catch (final OpenAS2Exception ex) {
        throw new DispositionException(
            DispositionType.createError("unexpected-processing-error"),
            AbstractActiveNetModule.DISP_VALIDATION_FAILED
                + "\n"
                + StackTraceHelper.getStackAsString(ex),
            ex);
      }

      try {
        if (aMsg.isRequestingMDN()) {
          // Transmit a success MDN if requested
          sendSyncMDN(
              sClientInfo,
              aResponseHandler,
              aMsg,
              DispositionType.createSuccess(),
              AbstractActiveNetModule.DISP_SUCCESS);
        } else {
          // Just send a HTTP OK
          HTTPHelper.sendSimpleHTTPResponse(aResponseHandler, HttpURLConnection.HTTP_OK);
          s_aLogger.info("sent HTTP OK " + sClientInfo + aMsg.getLoggingText());
        }
      } catch (final Exception ex) {
        throw new WrappedOpenAS2Exception(
            "Error creating and returning MDN, message was stilled processed", ex);
      }
    } catch (final DispositionException ex) {
      sendSyncMDN(sClientInfo, aResponseHandler, aMsg, ex.getDisposition(), ex.getText());
      m_aReceiverModule.handleError(aMsg, ex);
    } catch (final OpenAS2Exception ex) {
      m_aReceiverModule.handleError(aMsg, ex);
    }
  }
Esempio n. 5
0
  protected void sendSyncMDN(
      @Nonnull final String sClientInfo,
      @Nonnull final IAS2HttpResponseHandler aResponseHandler,
      @Nonnull final AS2Message aMsg,
      @Nonnull final DispositionType aDisposition,
      @Nonnull final String sText) {
    final boolean bMDNBlocked = aMsg.getPartnership().isBlockErrorMDN();
    if (!bMDNBlocked) {
      try {
        final IAS2Session aSession = m_aReceiverModule.getSession();
        final IMessageMDN aMdn = AS2Helper.createMDN(aSession, aMsg, aDisposition, sText);

        if (aMsg.isRequestingAsynchMDN()) {
          // if asyncMDN requested, close connection and initiate separate MDN
          // send
          final InternetHeaders aHeaders = new InternetHeaders();
          aHeaders.setHeader(CAS2Header.HEADER_CONTENT_LENGTH, Integer.toString(0));
          // Empty data
          final NonBlockingByteArrayOutputStream aData = new NonBlockingByteArrayOutputStream();
          aResponseHandler.sendHttpResponse(HttpURLConnection.HTTP_OK, aHeaders, aData);

          s_aLogger.info(
              "Setup to send asynch MDN ["
                  + aDisposition.getAsString()
                  + "] "
                  + sClientInfo
                  + aMsg.getLoggingText());

          // trigger explicit sending
          aSession.getMessageProcessor().handle(IProcessorSenderModule.DO_SENDMDN, aMsg, null);
        } else {
          // otherwise, send sync MDN back on same connection
          s_aLogger.info(
              "Sending back sync MDN ["
                  + aDisposition.getAsString()
                  + "] "
                  + sClientInfo
                  + aMsg.getLoggingText());

          // Get data and therefore content length for sync MDN
          final NonBlockingByteArrayOutputStream aData = new NonBlockingByteArrayOutputStream();
          final MimeBodyPart aPart = aMdn.getData();
          StreamHelper.copyInputStreamToOutputStream(aPart.getInputStream(), aData);
          aMdn.setHeader(CAS2Header.HEADER_CONTENT_LENGTH, Integer.toString(aData.getSize()));

          // start HTTP response
          aResponseHandler.sendHttpResponse(HttpURLConnection.HTTP_OK, aMdn.getHeaders(), aData);

          // Save sent MDN for later examination
          try {
            aSession.getMessageProcessor().handle(IProcessorStorageModule.DO_STOREMDN, aMsg, null);
          } catch (final ComponentNotFoundException ex) {
            // No message processor found
          } catch (final NoModuleException ex) {
            // No module found in message processor
          }
          s_aLogger.info(
              "sent MDN ["
                  + aDisposition.getAsString()
                  + "] "
                  + sClientInfo
                  + aMsg.getLoggingText());
        }
      } catch (final Exception ex) {
        final OpenAS2Exception we = WrappedOpenAS2Exception.wrap(ex);
        we.addSource(OpenAS2Exception.SOURCE_MESSAGE, aMsg);
        we.terminate();
      }
    }
  }