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 e8eae26051 [FIX] Support RFC-3848 service types in Received headers 
(#2536)
e8eae26051 is described below

commit e8eae26051b55e4aa19f34bf3fab55ac9dc471d2
Author: Benoit TELLIER <[email protected]>
AuthorDate: Wed Dec 4 23:27:34 2024 +0100

    [FIX] Support RFC-3848 service types in Received headers (#2536)
    
    Co-authored-by: Rene Cordier <[email protected]>
---
 .../lmtp/core/ReceivedDataLineFilter.java          |  40 ++++--
 .../smtp/core/ReceivedDataLineFilter.java          | 134 ++++-----------------
 .../smtp/core/ReceivedHeaderGenerator.java         | 126 +++++++++++++++++++
 3 files changed, 182 insertions(+), 118 deletions(-)

diff --git 
a/protocols/lmtp/src/main/java/org/apache/james/protocols/lmtp/core/ReceivedDataLineFilter.java
 
b/protocols/lmtp/src/main/java/org/apache/james/protocols/lmtp/core/ReceivedDataLineFilter.java
index a7fe568bdd..38265993cf 100644
--- 
a/protocols/lmtp/src/main/java/org/apache/james/protocols/lmtp/core/ReceivedDataLineFilter.java
+++ 
b/protocols/lmtp/src/main/java/org/apache/james/protocols/lmtp/core/ReceivedDataLineFilter.java
@@ -19,6 +19,7 @@
 package org.apache.james.protocols.lmtp.core;
 
 import org.apache.james.protocols.smtp.SMTPSession;
+import org.apache.james.protocols.smtp.core.ReceivedHeaderGenerator;
 
 /**
  * {@link ReceivedDataLineFilter} which will add the Received header to the 
message
@@ -26,12 +27,37 @@ import org.apache.james.protocols.smtp.SMTPSession;
 public class ReceivedDataLineFilter extends 
org.apache.james.protocols.smtp.core.ReceivedDataLineFilter {
 
     private static final String SERVICE_TYPE = "LMTP";
-    
-    /**
-     * Always returns <code>LMTP</code>
-     */
-    @Override
-    protected String getServiceType(SMTPSession session, String heloMode) {
-        return SERVICE_TYPE;
+    private static final String SERVICE_TYPE_AUTH = "LMTPA";
+    private static final String SERVICE_TYPE_SSL = "LMTPS";
+    private static final String SERVICE_TYPE_SSL_AUTH = "LMTPSA";
+
+    public ReceivedDataLineFilter() {
+        super(new ReceivedHeaderGenerator() {
+
+            /**
+             * Always returns <code>LMTP</code>
+             */
+            @Override
+            protected String getServiceType(SMTPSession session, String 
heloMode) {
+                // Not successful auth
+                if (session.getUsername() == null) {
+                    if (session.isTLSStarted()) {
+                        return SERVICE_TYPE_SSL;
+                    } else {
+                        return SERVICE_TYPE;
+                    }
+                } else {
+                    // See RFC3848:
+                    // The new keyword "ESMTPA" indicates the use of ESMTP 
when the SMTP
+                    // AUTH [3] extension is also used and authentication is 
successfully achieved.
+                    if (session.isTLSStarted()) {
+                        return SERVICE_TYPE_SSL_AUTH;
+                    } else {
+                        return SERVICE_TYPE_AUTH;
+                    }
+                }
+            }
+        });
     }
+
 }
diff --git 
a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java
 
b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java
index e524aa92c9..b0a4e045d7 100644
--- 
a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java
+++ 
b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java
@@ -18,65 +18,34 @@
  ****************************************************************/
 package org.apache.james.protocols.smtp.core;
 
-import java.io.UnsupportedEncodingException;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Locale;
-import java.util.Optional;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.apache.james.core.MailAddress;
 import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.LineHandler;
 import org.apache.james.protocols.smtp.SMTPSession;
 
-import com.google.common.collect.ImmutableList;
-
 /**
  * {@link SeparatingDataLineFilter} which adds the Received header for the 
message.
  */
 public class ReceivedDataLineFilter extends SeparatingDataLineFilter {
-
-    private static final String EHLO = "EHLO";
-    private static final String SMTP = "SMTP";
-    private static final String ESMTPA = "ESMTPA";
-    private static final String ESMTP = "ESMTP";
-
-    private static final DateTimeFormatter DATEFORMAT = 
DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss Z (zzz)", Locale.US);
-
     private static final AtomicInteger COUNTER = new AtomicInteger(0);
     private final ProtocolSession.AttachmentKey<Boolean> headersPrefixAdded = 
ProtocolSession.AttachmentKey.of("HEADERS_PREFIX_ADDED" + 
COUNTER.incrementAndGet(), Boolean.class);
     private final ProtocolSession.AttachmentKey<Boolean> headersSuffixAdded = 
ProtocolSession.AttachmentKey.of("HEADERS_SUFFIX_ADDED" + 
COUNTER.incrementAndGet(), Boolean.class);
-    private final ProtocolSession.AttachmentKey<Integer> mtPriority = 
ProtocolSession.AttachmentKey.of("MT-PRIORITY", Integer.class);
+    protected final ReceivedHeaderGenerator receivedHeaderGenerator;
 
-    /**
-     * Return the service type which will be used in the Received headers.
-     */
-    protected String getServiceType(SMTPSession session, String heloMode) {
-        // Check if EHLO was used
-        if (EHLO.equals(heloMode)) {
-            // Not successful auth
-            if (session.getUsername() == null) {
-                return ESMTP;
-            } else {
-                // See RFC3848
-                // The new keyword "ESMTPA" indicates the use of ESMTP when
-                // the
-                // SMTP
-                // AUTH [3] extension is also used and authentication is
-                // successfully
-                // achieved.
-                return ESMTPA;
-            }
-        } else {
-            return SMTP;
-        }
+    public ReceivedDataLineFilter(ReceivedHeaderGenerator 
receivedHeaderGenerator) {
+        this.receivedHeaderGenerator = receivedHeaderGenerator;
+    }
+
+    public ReceivedDataLineFilter() {
+        this(new ReceivedHeaderGenerator());
     }
 
     /**
@@ -90,60 +59,7 @@ public class ReceivedDataLineFilter extends 
SeparatingDataLineFilter {
      * Returns the Received header for the message.
      */
     protected Collection<Header> headers(SMTPSession session) {
-
-        StringBuilder headerLineBuffer = new StringBuilder();
-
-        Optional<String> heloMode = 
session.getAttachment(SMTPSession.CURRENT_HELO_MODE, State.Connection);
-        Optional<String> heloName = 
session.getAttachment(SMTPSession.CURRENT_HELO_NAME, State.Connection);
-
-        // Put our Received header first
-        headerLineBuffer.append("from 
").append(session.getRemoteAddress().getHostName());
-
-        if (heloName.isPresent() && heloMode.isPresent()) {
-            headerLineBuffer.append(" (").append(heloMode.get()).append(" 
").append(heloName.get()).append(")");
-        }
-        headerLineBuffer.append(" 
([").append(session.getRemoteAddress().getAddress().getHostAddress()).append("])");
-        Header header = new Header("Received", headerLineBuffer.toString());
-        
-        headerLineBuffer = new StringBuilder();
-
-        session.getSSLSession()
-            .map(sslSession -> String.format("(using %s with cipher %s)",
-                sslSession.getProtocol(),
-                Optional.ofNullable(sslSession.getCipherSuite())
-                    .orElse("")))
-            .ifPresent(header::add);
-
-        headerLineBuffer.append("by 
").append(session.getConfiguration().getHelloName()).append(" 
(").append(session.getConfiguration().getSoftwareName()).append(") with 
").append(getServiceType(session, heloMode.orElse("NOT-DEFINED")));
-        headerLineBuffer.append(" ID ").append(session.getSessionID());
-
-        List<MailAddress> rcptList = 
session.getAttachment(SMTPSession.RCPT_LIST, 
State.Transaction).orElse(ImmutableList.of());
-
-        String priorityValue = session.getAttachment(mtPriority, 
State.Transaction)
-            .map(p -> " (PRIORITY " + p + ")").orElse("");
-
-        if (rcptList.size() == 1) {
-            // Only indicate a recipient if they're the only recipient
-            // (prevents email address harvesting and large headers in
-            // bulk email)
-            header.add(headerLineBuffer.toString());
-
-            headerLineBuffer = new StringBuilder();
-            headerLineBuffer.append("for 
<").append(rcptList.getFirst().toString()).append(">");
-            headerLineBuffer.append(priorityValue).append(";");
-        } else {
-            // Put the ; on the end of the 'by' line
-            headerLineBuffer.append(priorityValue).append(";");
-        }
-        header.add(headerLineBuffer.toString());
-        headerLineBuffer = new StringBuilder();
-
-        headerLineBuffer.append(DATEFORMAT.format(ZonedDateTime.now()));
-
-        header.add(headerLineBuffer.toString());
-        
-        return Collections.singletonList(header);
-    
+        return 
Collections.singletonList(receivedHeaderGenerator.generateReceivedHeader(session));
     }
 
     @Override
@@ -214,26 +130,22 @@ public class ReceivedDataLineFilter extends 
SeparatingDataLineFilter {
          * @return response
          */
         public Response transferTo(SMTPSession session, 
LineHandler<SMTPSession> handler) {
-            String charset = session.getCharset().name();
-
-            try {
-                Response response = null;
-                for (int i = 0; i < values.size(); i++) {
-                    String line;
-                    if (i == 0) {
-                        line = name + ": " + values.get(i);
-                    } else {
-                        line = MULTI_LINE_PREFIX + values.get(i);
-                    }
-                    response = handler.onLine(session, (line + 
session.getLineDelimiter()).getBytes(charset));
-                    if (response != null) {
-                        break;
-                    }
+            Charset charset = session.getCharset();
+
+            Response response = null;
+            for (int i = 0; i < values.size(); i++) {
+                String line;
+                if (i == 0) {
+                    line = name + ": " + values.get(i);
+                } else {
+                    line = MULTI_LINE_PREFIX + values.get(i);
+                }
+                response = handler.onLine(session, (line + 
session.getLineDelimiter()).getBytes(charset));
+                if (response != null) {
+                    break;
                 }
-                return response;
-            } catch (UnsupportedEncodingException e) {
-                throw new RuntimeException("NO " + charset + " support ?", e);
             }
+            return response;
         }
     }
 }
diff --git 
a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedHeaderGenerator.java
 
b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedHeaderGenerator.java
new file mode 100644
index 0000000000..614fb5e96e
--- /dev/null
+++ 
b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedHeaderGenerator.java
@@ -0,0 +1,126 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.protocols.smtp.core;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.protocols.api.ProtocolSession;
+import org.apache.james.protocols.smtp.SMTPSession;
+
+import com.google.common.collect.ImmutableList;
+
+public class ReceivedHeaderGenerator {
+    private static final DateTimeFormatter DATEFORMAT = 
DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss Z (zzz)", Locale.US);
+
+    private static final String EHLO = "EHLO";
+    private static final String SMTP = "SMTP";
+    private static final String ESMTPA = "ESMTPA";
+    private static final String ESMTPSA = "ESMTPSA";
+    private static final String ESMTP = "ESMTP";
+    private static final String ESMTPS = "ESMTPS";
+    private final ProtocolSession.AttachmentKey<Integer> mtPriority = 
ProtocolSession.AttachmentKey.of("MT-PRIORITY", Integer.class);
+
+    /**
+     * Return the service type which will be used in the Received headers.
+     */
+    protected String getServiceType(SMTPSession session, String heloMode) {
+        // Check if EHLO was used
+        if (EHLO.equals(heloMode)) {
+            // Not successful auth
+            if (session.getUsername() == null) {
+                if (session.isTLSStarted()) {
+                    return ESMTPS;
+                } else {
+                    return ESMTP;
+                }
+            } else {
+                // See RFC3848:
+                // The new keyword "ESMTPA" indicates the use of ESMTP when 
the SMTP
+                // AUTH [3] extension is also used and authentication is 
successfully achieved.
+                if (session.isTLSStarted()) {
+                    return ESMTPSA;
+                } else {
+                    return ESMTPA;
+                }
+            }
+        } else {
+            return SMTP;
+        }
+    }
+
+    public ReceivedDataLineFilter.Header generateReceivedHeader(SMTPSession 
session) {
+        StringBuilder headerLineBuffer = new StringBuilder();
+
+        Optional<String> heloMode = 
session.getAttachment(SMTPSession.CURRENT_HELO_MODE, 
ProtocolSession.State.Connection);
+        Optional<String> heloName = 
session.getAttachment(SMTPSession.CURRENT_HELO_NAME, 
ProtocolSession.State.Connection);
+
+        // Put our Received header first
+        headerLineBuffer.append("from 
").append(session.getRemoteAddress().getHostName());
+
+        if (heloName.isPresent() && heloMode.isPresent()) {
+            headerLineBuffer.append(" (").append(heloMode.get()).append(" 
").append(heloName.get()).append(")");
+        }
+        headerLineBuffer.append(" 
([").append(session.getRemoteAddress().getAddress().getHostAddress()).append("])");
+        ReceivedDataLineFilter.Header header = new 
ReceivedDataLineFilter.Header("Received", headerLineBuffer.toString());
+
+        headerLineBuffer = new StringBuilder();
+
+        session.getSSLSession()
+            .map(sslSession -> String.format("(using %s with cipher %s)",
+                sslSession.getProtocol(),
+                Optional.ofNullable(sslSession.getCipherSuite())
+                    .orElse("")))
+            .ifPresent(header::add);
+
+        headerLineBuffer.append("by 
").append(session.getConfiguration().getHelloName()).append(" 
(").append(session.getConfiguration().getSoftwareName()).append(") with 
").append(getServiceType(session, heloMode.orElse("NOT-DEFINED")));
+        headerLineBuffer.append(" ID ").append(session.getSessionID());
+
+        List<MailAddress> rcptList = 
session.getAttachment(SMTPSession.RCPT_LIST, 
ProtocolSession.State.Transaction).orElse(ImmutableList.of());
+
+        String priorityValue = session.getAttachment(mtPriority, 
ProtocolSession.State.Transaction)
+            .map(p -> " (PRIORITY " + p + ")").orElse("");
+
+        if (rcptList.size() == 1) {
+            // Only indicate a recipient if they're the only recipient
+            // (prevents email address harvesting and large headers in
+            // bulk email)
+            header.add(headerLineBuffer.toString());
+
+            headerLineBuffer = new StringBuilder();
+            headerLineBuffer.append("for 
<").append(rcptList.getFirst().toString()).append(">");
+            headerLineBuffer.append(priorityValue).append(";");
+        } else {
+            // Put the ; on the end of the 'by' line
+            headerLineBuffer.append(priorityValue).append(";");
+        }
+        header.add(headerLineBuffer.toString());
+        headerLineBuffer = new StringBuilder();
+
+        headerLineBuffer.append(DATEFORMAT.format(ZonedDateTime.now()));
+
+        header.add(headerLineBuffer.toString());
+        return header;
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to