diff --git a/README.md b/README.md index 40f07a40..9949b1ab 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ The subproject `as2-demo-webapp` is licensed under the Apache 2 license. * Added support for deprecated signing algorithms `rsa-md5` and `rsa-sha1` * Updated to new Mendelson test certificates (key3 and key4 - see http://mendelson-e-c.com/node/3211) * The `Content-Transfer-Encoding` value `base64` now works correctly (see [#71](https://github.com/phax/as2-lib/pull/71)) + * Added a custom `IMICMatchingHandler` interface to `AS2SenderModule` and `AS2MDNReceiverHandler` (see [#59](https://github.com/phax/as2-lib/pull/59)) * Updated to ph-commons 9.3.4 * v4.3.0 - 2019-05-17 * Moved interface `IRefreshablePartnershipFactory` from project as2-server to this project diff --git a/as2-lib/src/main/java/com/helger/as2lib/crypto/IMICMatchingHandler.java b/as2-lib/src/main/java/com/helger/as2lib/crypto/IMICMatchingHandler.java new file mode 100644 index 00000000..fed8e11f --- /dev/null +++ b/as2-lib/src/main/java/com/helger/as2lib/crypto/IMICMatchingHandler.java @@ -0,0 +1,46 @@ +package com.helger.as2lib.crypto; + +import java.io.Serializable; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.helger.as2lib.exception.OpenAS2Exception; +import com.helger.as2lib.message.IMessage; + +/** + * A special handler if MIC is not matched. + * + * @author Philip Helger + * @since 4.4.0 + */ +public interface IMICMatchingHandler extends Serializable +{ + /** + * Invoked upon MIC match + * + * @param aMsg + * The message it is all about. Never null + * @param sMIC + * The MIC calculated and received. May not be null. + * @throws OpenAS2Exception + * In case of error + */ + void onMICMatch (@Nonnull IMessage aMsg, @Nonnull String sMIC) throws OpenAS2Exception; + + /** + * Invoked upon MIC mismatch + * + * @param aMsg + * The message it is all about. Never null + * @param sOriginalMIC + * The MIC calculated here. May be null. + * @param sReceivedMIC + * The MIC received from the other side. May be null. + * @throws OpenAS2Exception + * In case of error + */ + void onMICMismatch (@Nonnull IMessage aMsg, + @Nullable String sOriginalMIC, + @Nullable String sReceivedMIC) throws OpenAS2Exception; +} diff --git a/as2-lib/src/main/java/com/helger/as2lib/crypto/LoggingMICMatchingHandler.java b/as2-lib/src/main/java/com/helger/as2lib/crypto/LoggingMICMatchingHandler.java new file mode 100644 index 00000000..12e614d8 --- /dev/null +++ b/as2-lib/src/main/java/com/helger/as2lib/crypto/LoggingMICMatchingHandler.java @@ -0,0 +1,35 @@ +package com.helger.as2lib.crypto; + +import javax.annotation.Nonnull; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.helger.as2lib.message.IMessage; + +/** + * Logging implementation of {@link IMICMatchingHandler} + * + * @author Philip Helger + * @since 4.40 + */ +public class LoggingMICMatchingHandler implements IMICMatchingHandler +{ + private static final Logger LOGGER = LoggerFactory.getLogger (LoggingMICMatchingHandler.class); + + public void onMICMatch (@Nonnull final IMessage aMsg, @Nonnull final String sMIC) + { + if (LOGGER.isInfoEnabled ()) + LOGGER.info ("MIC is matched, MIC: " + sMIC + aMsg.getLoggingText ()); + } + + public void onMICMismatch (final IMessage aMsg, final String sOriginalMIC, final String sReceivedMIC) + { + if (LOGGER.isInfoEnabled ()) + LOGGER.info ("MIC IS NOT MATCHED; original MIC: " + + sOriginalMIC + + " received MIC: " + + sReceivedMIC + + aMsg.getLoggingText ()); + } +} diff --git a/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2MDNReceiverHandler.java b/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2MDNReceiverHandler.java index e1e9a158..f49bccd3 100644 --- a/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2MDNReceiverHandler.java +++ b/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2MDNReceiverHandler.java @@ -49,6 +49,8 @@ import com.helger.as2lib.cert.ECertificatePartnershipType; import com.helger.as2lib.cert.ICertificateFactory; +import com.helger.as2lib.crypto.IMICMatchingHandler; +import com.helger.as2lib.crypto.LoggingMICMatchingHandler; import com.helger.as2lib.crypto.MIC; import com.helger.as2lib.disposition.DispositionException; import com.helger.as2lib.disposition.DispositionType; @@ -90,6 +92,7 @@ public class AS2MDNReceiverHandler extends AbstractReceiverHandler private static final Logger LOGGER = LoggerFactory.getLogger (AS2MDNReceiverHandler.class); private final AS2MDNReceiverModule m_aModule; + private IMICMatchingHandler m_aMICMatchingHandler = new LoggingMICMatchingHandler (); public AS2MDNReceiverHandler (@Nonnull final AS2MDNReceiverModule aModule) { @@ -97,11 +100,34 @@ public AS2MDNReceiverHandler (@Nonnull final AS2MDNReceiverModule aModule) } @Nonnull - public AS2MDNReceiverModule getModule () + public final AS2MDNReceiverModule getModule () { return m_aModule; } + /** + * @return The current MIC matching handler. Never null. + * @since 4.4.0 + */ + @Nonnull + public final IMICMatchingHandler getMICMatchingHandler () + { + return m_aMICMatchingHandler; + } + + /** + * Set the MIC matching handler to used. + * + * @param aMICMatchingHandler + * The new handler. May not be null. + * @since 4.4.0 + */ + public final void setMICMatchingHandler (@Nonnull final IMICMatchingHandler aMICMatchingHandler) + { + ValueEnforcer.notNull (aMICMatchingHandler, "MICMatchingHandler"); + m_aMICMatchingHandler = aMICMatchingHandler; + } + public void handle (@Nonnull final AbstractActiveNetModule aOwner, @Nonnull final Socket aSocket) { final String sClientInfo = getClientInfo (aSocket); @@ -273,8 +299,10 @@ protected final void receiveMDN (@Nonnull final AS2Message aMsg, * @param aMsg * Message * @return true if mdn processed + * @throws OpenAS2Exception + * In case of error; e.g. MIC mismatch */ - public boolean checkAsyncMDN (final AS2Message aMsg) + public boolean checkAsyncMDN (@Nonnull final AS2Message aMsg) throws OpenAS2Exception { try { @@ -315,18 +343,13 @@ public boolean checkAsyncMDN (final AS2Message aMsg) if (aOriginalMIC == null || aReturnMIC == null || !aReturnMIC.equals (aOriginalMIC)) { - if (LOGGER.isInfoEnabled ()) - LOGGER.info ("MIC IS NOT MATCHED, original mic: " + - sOriginalMIC + - " return mic: " + - sReturnMIC + - aMsg.getLoggingText ()); + m_aMICMatchingHandler.onMICMismatch (aMsg, sOriginalMIC, sReturnMIC); return false; } + m_aMICMatchingHandler.onMICMatch (aMsg, sReturnMIC); + // delete the pendinginfo & pending file if mic is matched - if (LOGGER.isInfoEnabled ()) - LOGGER.info ("mic is matched, mic: " + sReturnMIC + aMsg.getLoggingText ()); final File aPendingInfoFile = new File (sPendingInfoFile); if (LOGGER.isInfoEnabled ()) diff --git a/as2-lib/src/main/java/com/helger/as2lib/processor/sender/AS2SenderModule.java b/as2-lib/src/main/java/com/helger/as2lib/processor/sender/AS2SenderModule.java index 433cc487..f3f6b0ca 100644 --- a/as2-lib/src/main/java/com/helger/as2lib/processor/sender/AS2SenderModule.java +++ b/as2-lib/src/main/java/com/helger/as2lib/processor/sender/AS2SenderModule.java @@ -57,6 +57,8 @@ import com.helger.as2lib.crypto.ECompressionType; import com.helger.as2lib.crypto.ECryptoAlgorithmCrypt; import com.helger.as2lib.crypto.ECryptoAlgorithmSign; +import com.helger.as2lib.crypto.IMICMatchingHandler; +import com.helger.as2lib.crypto.LoggingMICMatchingHandler; import com.helger.as2lib.crypto.MIC; import com.helger.as2lib.disposition.DispositionException; import com.helger.as2lib.disposition.DispositionType; @@ -111,9 +113,34 @@ public class AS2SenderModule extends AbstractHttpSenderModule private static final String ATTR_PENDINGMDN = "pendingmdn"; private static final Logger LOGGER = LoggerFactory.getLogger (AS2SenderModule.class); + private IMICMatchingHandler m_aMICMatchingHandler = new LoggingMICMatchingHandler (); + public AS2SenderModule () {} + /** + * @return The current MIC matching handler. Never null. + * @since 4.4.0 + */ + @Nonnull + public final IMICMatchingHandler getMICMatchingHandler () + { + return m_aMICMatchingHandler; + } + + /** + * Set the MIC matching handler to used. + * + * @param aMICMatchingHandler + * The new handler. May not be null. + * @since 4.4.0 + */ + public final void setMICMatchingHandler (@Nonnull final IMICMatchingHandler aMICMatchingHandler) + { + ValueEnforcer.notNull (aMICMatchingHandler, "MICMatchingHandler"); + m_aMICMatchingHandler = aMICMatchingHandler; + } + public boolean canHandle (@Nonnull final String sAction, @Nonnull final IMessage aMsg, @Nullable final Map aOptions) @@ -682,20 +709,13 @@ protected void receiveSyncMDN (@Nonnull final AS2Message aMsg, if (aOriginalMIC == null || aReturnMIC == null || !aReturnMIC.equals (aOriginalMIC)) { // file was sent completely but the returned mic was not matched, - // don't know it needs or needs not to be resent ? it's depended on - // what! anyway, just log the warning message here. - if (LOGGER.isInfoEnabled ()) - LOGGER.info ("MIC IS NOT MATCHED, original mic: '" + - aOriginalMIC.getAsAS2String () + - "' return mic: '" + - sReturnMIC + - "'" + - aMsg.getLoggingText ()); + m_aMICMatchingHandler.onMICMismatch (aMsg, + aOriginalMIC == null ? null : aOriginalMIC.getAsAS2String (), + sReturnMIC); } else { - if (LOGGER.isInfoEnabled ()) - LOGGER.info ("MIC is matched, MIC: " + sReturnMIC + aMsg.getLoggingText ()); + m_aMICMatchingHandler.onMICMatch (aMsg, sReturnMIC); } try