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]