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