This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git


The following commit(s) were added to refs/heads/master by this push:
     new 7d32661c47 [ENHANCEMENT] DKIMHook - improve logging (#2702)
7d32661c47 is described below

commit 7d32661c47136c8dcf7b873dfc3fe9d447e30f4b
Author: Benoit TELLIER <btell...@linagora.com>
AuthorDate: Fri Apr 18 08:50:05 2025 +0200

    [ENHANCEMENT] DKIMHook - improve logging (#2702)
    
    * [ENHANCEMENT] DKIMHook: fix inacurate warning log when multiple signature
    
    The previous 'OR' was logging a failure if the first dtoken is not the
    expected one which is misleading.
    
    We also add a debug log upon hook
    
    * [ENHANCEMENT] DKIMHook: log messageId
    
    This ease correlation with 3rd party email system logs
    
    ---------
    
    Co-authored-by: Rene Cordier <rcord...@linagora.com>
---
 .../org/apache/james/DKIMHookIntegrationTest.java  |  2 +-
 .../java/org/apache/james/smtpserver/DKIMHook.java | 68 +++++++++++-----------
 .../org/apache/james/smtpserver/DKIMHookTest.java  | 38 ++++++------
 3 files changed, 53 insertions(+), 55 deletions(-)

diff --git 
a/server/apps/memory-app/src/test/java/org/apache/james/DKIMHookIntegrationTest.java
 
b/server/apps/memory-app/src/test/java/org/apache/james/DKIMHookIntegrationTest.java
index ac092e7aae..33bb4a3193 100644
--- 
a/server/apps/memory-app/src/test/java/org/apache/james/DKIMHookIntegrationTest.java
+++ 
b/server/apps/memory-app/src/test/java/org/apache/james/DKIMHookIntegrationTest.java
@@ -187,7 +187,7 @@ public class DKIMHookIntegrationTest {
         
server.write(ByteBuffer.wrap(("QUIT\r\n").getBytes(StandardCharsets.UTF_8)));
 
         assertThat(new String(dataResponse, StandardCharsets.UTF_8))
-            .contains("530 DKIM check failed. Wrong d token. Expecting 
avocat.fr");
+            .contains("530 DKIM check failed. Wrong d token. Expecting 
[avocat.fr]. Got [preprod-avocat.fr]");
     }
 
     @Test
diff --git 
a/server/protocols/protocols-smtp-dkim/src/main/java/org/apache/james/smtpserver/DKIMHook.java
 
b/server/protocols/protocols-smtp-dkim/src/main/java/org/apache/james/smtpserver/DKIMHook.java
index 9425ba9206..746a86ca42 100644
--- 
a/server/protocols/protocols-smtp-dkim/src/main/java/org/apache/james/smtpserver/DKIMHook.java
+++ 
b/server/protocols/protocols-smtp-dkim/src/main/java/org/apache/james/smtpserver/DKIMHook.java
@@ -146,29 +146,19 @@ public class DKIMHook implements JamesMessageHook {
     @FunctionalInterface
     interface SignatureRecordValidation {
         static SignatureRecordValidation and(SignatureRecordValidation a, 
SignatureRecordValidation b) {
-            return (sender, records) -> {
-                HookResult hookResult = a.validate(sender, records);
+            return (sender, messageId, records) -> {
+                HookResult hookResult = a.validate(sender, messageId, records);
                 if (hookResult.equals(HookResult.DECLINED)) {
-                    return b.validate(sender, records);
+                    return b.validate(sender, messageId, records);
                 }
                 return hookResult;
             };
         }
 
-        static SignatureRecordValidation or(SignatureRecordValidation a, 
SignatureRecordValidation b) {
-            return (sender, records) -> {
-                HookResult hookResult = a.validate(sender, records);
-                if (hookResult.equals(HookResult.DECLINED)) {
-                    return hookResult;
-                }
-                return b.validate(sender, records);
-            };
-        }
-
         static SignatureRecordValidation signatureRequired(boolean required) {
-            return (sender, records) -> {
+            return (sender, messageId, records) -> {
                 if (required && (records == null || records.isEmpty())) {
-                    LOGGER.warn("DKIM check failed. Expecting DKIM signatures. 
Got none.");
+                    LOGGER.warn("DKIM check failed for {}. Expecting DKIM 
signatures. Got none.", messageId);
                     return HookResult.builder()
                         .hookReturnCode(HookReturnCode.deny())
                         .smtpReturnCode(AUTH_REQUIRED)
@@ -179,24 +169,35 @@ public class DKIMHook implements JamesMessageHook {
             };
         }
 
-        static SignatureRecordValidation expectedDToken(String dToken) {
-            return (sender, records) -> {
-                if (records.stream().anyMatch(record -> 
record.getDToken().equals(dToken))) {
-                    return HookResult.DECLINED;
-                }
-                LOGGER.warn("DKIM check failed. Wrong d token. Expecting {}. 
Got {}.", dToken,
-                    
records.stream().map(SignatureRecord::getDToken).collect(ImmutableSet.toImmutableSet()));
-                return HookResult.builder()
-                    .hookReturnCode(HookReturnCode.deny())
-                    .smtpReturnCode(AUTH_REQUIRED)
-                    .smtpDescription("DKIM check failed. Wrong d token. 
Expecting " + dToken)
-                    .build();
-            };
+        SignatureRecordValidation ALLOW_ALL = (sender, messageId, records) -> 
HookResult.DECLINED;
+
+        HookResult validate(MaybeSender maybeSender, String messageId, 
List<SignatureRecord> records);
+    }
+
+    static class DTokenSignatureRecordValidation implements 
SignatureRecordValidation {
+        private final List<String> expectedDTokens;
+
+        DTokenSignatureRecordValidation(List<String> expectedDTokens) {
+            this.expectedDTokens = expectedDTokens;
         }
 
-        SignatureRecordValidation ALLOW_ALL = (sender, records) -> 
HookResult.DECLINED;
+        DTokenSignatureRecordValidation(String expectedDToken) {
+            this(ImmutableList.of(expectedDToken));
+        }
 
-        HookResult validate(MaybeSender maybeSender, List<SignatureRecord> 
records);
+        @Override
+        public HookResult validate(MaybeSender maybeSender, String messageId, 
List<SignatureRecord> records) {
+            if (records.stream().anyMatch(r -> 
expectedDTokens.stream().anyMatch(d -> r.getDToken().equals(d)))) {
+                return HookResult.DECLINED;
+            }
+            ImmutableSet<CharSequence> actualDToken = 
records.stream().map(SignatureRecord::getDToken).collect(ImmutableSet.toImmutableSet());
+            LOGGER.warn("DKIM check failed for {}. Wrong d token. Expecting 
{}. Got {}.", messageId, expectedDTokens, actualDToken);
+            return HookResult.builder()
+                .hookReturnCode(HookReturnCode.deny())
+                .smtpReturnCode(AUTH_REQUIRED)
+                .smtpDescription("DKIM check failed. Wrong d token. Expecting 
" + expectedDTokens + ". Got " + actualDToken)
+                .build();
+        }
     }
 
     public static class Config {
@@ -260,10 +261,7 @@ public class DKIMHook implements JamesMessageHook {
         SignatureRecordValidation signatureRecordValidation() {
             return SignatureRecordValidation.and(
                 SignatureRecordValidation.signatureRequired(signatureRequired),
-                expectedDToken.map(tokens -> tokens.stream()
-                    .map(SignatureRecordValidation::expectedDToken)
-                    .reduce(SignatureRecordValidation::or)
-                    .get()).orElse(SignatureRecordValidation.ALLOW_ALL));
+                
expectedDToken.<SignatureRecordValidation>map(DTokenSignatureRecordValidation::new).orElse(SignatureRecordValidation.ALLOW_ALL));
         }
 
         private ImmutableList<DKIMCheckNeeded> computeDKIMChecksNeeded(Domain 
domain) {
@@ -326,7 +324,7 @@ public class DKIMHook implements JamesMessageHook {
             return HookResult.DECLINED;
         }
         try {
-            return signatureRecordValidation.validate(mail.getMaybeSender(),
+            return signatureRecordValidation.validate(mail.getMaybeSender(), 
mail.getMessage().getMessageID(),
                 verifier.verify(mail.getMessage(), config.forceCRLF));
         } catch (MessagingException e) {
             LOGGER.warn("Error while verifying DKIM signatures", e);
diff --git 
a/server/protocols/protocols-smtp-dkim/src/test/java/org/apache/james/smtpserver/DKIMHookTest.java
 
b/server/protocols/protocols-smtp-dkim/src/test/java/org/apache/james/smtpserver/DKIMHookTest.java
index 710dc09bf5..3838c5a967 100644
--- 
a/server/protocols/protocols-smtp-dkim/src/test/java/org/apache/james/smtpserver/DKIMHookTest.java
+++ 
b/server/protocols/protocols-smtp-dkim/src/test/java/org/apache/james/smtpserver/DKIMHookTest.java
@@ -122,7 +122,7 @@ class DKIMHookTest {
         @Test
         void shouldDenyWhenNoDkimRecordsWhenTrue() {
             
assertThat(DKIMHook.SignatureRecordValidation.signatureRequired(true)
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of()))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.deny()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getSmtpDescription()).isEqualTo("DKIM check failed. 
Expecting DKIM signatures. Got none."));
         }
@@ -130,28 +130,28 @@ class DKIMHookTest {
         @Test
         void shouldDeclineWhenNoDkimRecordWhenTrue() {
             
assertThat(DKIMHook.SignatureRecordValidation.signatureRequired(false)
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of()))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.declined()));
         }
 
         @Test
         void shouldDeclineWhenDkimRecordWhenTrue() {
             
assertThat(DKIMHook.SignatureRecordValidation.signatureRequired(true)
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of(SIGNATURE_RECORD_1)))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of(SIGNATURE_RECORD_1)))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.declined()));
         }
 
         @Test
         void allShouldDeclineWhenNoDkimRecord() {
             assertThat(DKIMHook.SignatureRecordValidation.ALLOW_ALL
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of()))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.declined()));
         }
 
         @Test
         void allShouldDeclineWhenDkimRecord() {
             assertThat(DKIMHook.SignatureRecordValidation.ALLOW_ALL
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of(SIGNATURE_RECORD_1)))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of(SIGNATURE_RECORD_1)))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.declined()));
         }
 
@@ -160,7 +160,7 @@ class DKIMHookTest {
             assertThat(DKIMHook.SignatureRecordValidation.and(
                     DKIMHook.SignatureRecordValidation.ALLOW_ALL,
                     DKIMHook.SignatureRecordValidation.ALLOW_ALL)
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of()))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.declined()));
         }
 
@@ -169,7 +169,7 @@ class DKIMHookTest {
             assertThat(DKIMHook.SignatureRecordValidation.and(
                     DKIMHook.SignatureRecordValidation.signatureRequired(true),
                     DKIMHook.SignatureRecordValidation.ALLOW_ALL)
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of()))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.deny()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getSmtpDescription()).isEqualTo("DKIM check failed. 
Expecting DKIM signatures. Got none."));
         }
@@ -179,7 +179,7 @@ class DKIMHookTest {
             assertThat(DKIMHook.SignatureRecordValidation.and(
                     DKIMHook.SignatureRecordValidation.ALLOW_ALL,
                     DKIMHook.SignatureRecordValidation.signatureRequired(true))
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of()))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.deny()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getSmtpDescription()).isEqualTo("DKIM check failed. 
Expecting DKIM signatures. Got none."));
         }
@@ -188,38 +188,38 @@ class DKIMHookTest {
         void andShouldKeepOnlyTheFirstSMTPDescription() {
             assertThat(DKIMHook.SignatureRecordValidation.and(
                     DKIMHook.SignatureRecordValidation.signatureRequired(true),
-                    
DKIMHook.SignatureRecordValidation.expectedDToken("wrong.com"))
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of()))
+                    new DKIMHook.DTokenSignatureRecordValidation("wrong.com"))
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.deny()))
                 .satisfies(hookResult -> 
assertThat(hookResult.getSmtpDescription()).isEqualTo("DKIM check failed. 
Expecting DKIM signatures. Got none."));
         }
 
         @Test
         void expectedDTokenShouldDenyWhenWrongDToken() {
-            
assertThat(DKIMHook.SignatureRecordValidation.expectedDToken("wrong.com")
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of(SIGNATURE_RECORD_1)))
+            assertThat(new 
DKIMHook.DTokenSignatureRecordValidation("wrong.com")
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of(SIGNATURE_RECORD_1)))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.deny()))
-                .satisfies(hookResult -> 
assertThat(hookResult.getSmtpDescription()).isEqualTo("DKIM check failed. Wrong 
d token. Expecting wrong.com"));
+                .satisfies(hookResult -> 
assertThat(hookResult.getSmtpDescription()).isEqualTo("DKIM check failed. Wrong 
d token. Expecting [wrong.com]. Got [linagora.com]"));
         }
 
         @Test
         void expectedDTokenShouldDeclineWhenGoodDToken() {
-            
assertThat(DKIMHook.SignatureRecordValidation.expectedDToken("linagora.com")
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of(SIGNATURE_RECORD_1)))
+            assertThat(new 
DKIMHook.DTokenSignatureRecordValidation("linagora.com")
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of(SIGNATURE_RECORD_1)))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.declined()));
         }
 
         @Test
         void expectedDTokenShouldDeclineWhenGoodFirstDToken() {
-            
assertThat(DKIMHook.SignatureRecordValidation.expectedDToken("linagora.com")
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of(SIGNATURE_RECORD_1, SIGNATURE_RECORD_2)))
+            assertThat(new 
DKIMHook.DTokenSignatureRecordValidation("linagora.com")
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of(SIGNATURE_RECORD_1, SIGNATURE_RECORD_2)))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.declined()));
         }
 
         @Test
         void expectedDTokenShouldDeclineWhenGoodSecondDToken() {
-            
assertThat(DKIMHook.SignatureRecordValidation.expectedDToken("linagora.com")
-                .validate(MaybeSender.getMailSender("bob@localhost"), 
ImmutableList.of(SIGNATURE_RECORD_2, SIGNATURE_RECORD_1)))
+            assertThat(new 
DKIMHook.DTokenSignatureRecordValidation("linagora.com")
+                .validate(MaybeSender.getMailSender("bob@localhost"), 
"messageId", ImmutableList.of(SIGNATURE_RECORD_2, SIGNATURE_RECORD_1)))
                 .satisfies(hookResult -> 
assertThat(hookResult.getResult()).isEqualTo(HookReturnCode.declined()));
         }
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org
For additional commands, e-mail: notifications-h...@james.apache.org

Reply via email to