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

commit 22f268e65e57b61b324a8ad2c17f811aaafb7f99
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon Mar 2 16:51:37 2026 +0100

    JAMES-4183 Use PROXY protocol to inject source IP
---
 .../AllowedUnauthenticatedSenderTest.java          | 157 ++++++++++++---------
 ...r-allowed-unauthenticated-sender-allow-null.xml |   1 +
 .../smtpserver-allowed-unauthenticated-sender.xml  |   1 +
 3 files changed, 94 insertions(+), 65 deletions(-)

diff --git 
a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/AllowedUnauthenticatedSenderTest.java
 
b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/AllowedUnauthenticatedSenderTest.java
index 348b160f83..7071eeb4c1 100644
--- 
a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/AllowedUnauthenticatedSenderTest.java
+++ 
b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/AllowedUnauthenticatedSenderTest.java
@@ -23,11 +23,15 @@ import static 
org.apache.james.smtpserver.SMTPServerTestSystem.BOB;
 import static org.apache.james.smtpserver.SMTPServerTestSystem.PASSWORD;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.io.BufferedReader;
+import java.io.Closeable;
 import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.net.InetSocketAddress;
+import java.net.Socket;
 import java.util.Base64;
 
-import org.apache.commons.net.smtp.SMTPClient;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
@@ -51,73 +55,45 @@ class AllowedUnauthenticatedSenderTest {
 
         @Test
         void unauthenticatedSenderShouldBeAcceptedWhenInAllowedList() throws 
Exception {
-            SMTPClient smtpProtocol = new SMTPClient();
-            InetSocketAddress bindedAddress = testSystem.getBindedAddress();
-            smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), 
bindedAddress.getPort());
-
-            smtpProtocol.sendCommand("EHLO localhost");
-            smtpProtocol.sendCommand("MAIL FROM: <[email protected]>");
-
-            assertThat(smtpProtocol.getReplyCode()).isEqualTo(250);
+            try (SmtpClient client = 
SmtpClient.connectWithProxy(testSystem.getBindedAddress(), "127.0.0.1")) {
+                client.sendCommand("EHLO localhost");
+                assertThat(client.sendCommand("MAIL FROM: 
<[email protected]>")).isEqualTo(250);
+            }
         }
 
         @Test
         void unauthenticatedSenderShouldBeRejectedWhenNotInAllowedList() 
throws Exception {
-            SMTPClient smtpProtocol = new SMTPClient();
-            InetSocketAddress bindedAddress = testSystem.getBindedAddress();
-            smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), 
bindedAddress.getPort());
-
-            smtpProtocol.sendCommand("EHLO localhost");
-            smtpProtocol.sendCommand("MAIL FROM: <[email protected]>");
-
-            assertThat(smtpProtocol.getReplyCode()).isEqualTo(550);
+            try (SmtpClient client = 
SmtpClient.connectWithProxy(testSystem.getBindedAddress(), "127.0.0.1")) {
+                client.sendCommand("EHLO localhost");
+                assertThat(client.sendCommand("MAIL FROM: 
<[email protected]>")).isEqualTo(550);
+            }
         }
 
         @Test
         void 
unauthenticatedSenderWithIpRestrictionShouldBeRejectedFromWrongIp() throws 
Exception {
             // [email protected] is only allowed from 172.34.56.0/24
-            // but we are connecting from 127.0.0.1
-            SMTPClient smtpProtocol = new SMTPClient();
-            InetSocketAddress bindedAddress = testSystem.getBindedAddress();
-            smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), 
bindedAddress.getPort());
-
-            smtpProtocol.sendCommand("EHLO localhost");
-            smtpProtocol.sendCommand("MAIL FROM: <[email protected]>");
-
-            assertThat(smtpProtocol.getReplyCode()).isEqualTo(550);
+            // Proxy simulates connection from 127.0.0.1 which is not in that 
range
+            try (SmtpClient client = 
SmtpClient.connectWithProxy(testSystem.getBindedAddress(), "127.0.0.1")) {
+                client.sendCommand("EHLO localhost");
+                assertThat(client.sendCommand("MAIL FROM: 
<[email protected]>")).isEqualTo(550);
+            }
         }
 
         @Test
         void nullSenderShouldBeRejectedWhenAllowNullSenderIsFalse() throws 
Exception {
-            SMTPClient smtpProtocol = new SMTPClient();
-            InetSocketAddress bindedAddress = testSystem.getBindedAddress();
-            smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), 
bindedAddress.getPort());
-
-            smtpProtocol.sendCommand("EHLO localhost");
-            smtpProtocol.sendCommand("MAIL FROM: <>");
-
-            assertThat(smtpProtocol.getReplyCode()).isEqualTo(550);
+            try (SmtpClient client = 
SmtpClient.connectWithProxy(testSystem.getBindedAddress(), "127.0.0.1")) {
+                client.sendCommand("EHLO localhost");
+                assertThat(client.sendCommand("MAIL FROM: <>")).isEqualTo(550);
+            }
         }
 
         @Test
         void authenticatedUserShouldBypassAllowedSenderRestriction() throws 
Exception {
-            SMTPClient smtpProtocol = new SMTPClient();
-            InetSocketAddress bindedAddress = testSystem.getBindedAddress();
-            smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), 
bindedAddress.getPort());
-            authenticate(smtpProtocol);
-
-            smtpProtocol.sendCommand("EHLO localhost");
-            smtpProtocol.sendCommand("MAIL FROM: <[email protected]>");
-
-            assertThat(smtpProtocol.getReplyCode()).isEqualTo(250);
-        }
-
-        private void authenticate(SMTPClient smtpProtocol) throws IOException {
-            smtpProtocol.sendCommand("AUTH PLAIN");
-            smtpProtocol.sendCommand(Base64.getEncoder().encodeToString(("\0" 
+ BOB.asString() + "\0" + PASSWORD + "\0").getBytes(UTF_8)));
-            assertThat(smtpProtocol.getReplyCode())
-                .as("authenticated")
-                .isEqualTo(235);
+            try (SmtpClient client = 
SmtpClient.connectWithProxy(testSystem.getBindedAddress(), "127.0.0.1")) {
+                client.authenticate();
+                client.sendCommand("EHLO localhost");
+                assertThat(client.sendCommand("MAIL FROM: 
<[email protected]>")).isEqualTo(250);
+            }
         }
     }
 
@@ -137,26 +113,77 @@ class AllowedUnauthenticatedSenderTest {
 
         @Test
         void nullSenderShouldBeAcceptedWhenAllowNullSenderIsTrue() throws 
Exception {
-            SMTPClient smtpProtocol = new SMTPClient();
-            InetSocketAddress bindedAddress = testSystem.getBindedAddress();
-            smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), 
bindedAddress.getPort());
-
-            smtpProtocol.sendCommand("EHLO localhost");
-            smtpProtocol.sendCommand("MAIL FROM: <>");
-
-            assertThat(smtpProtocol.getReplyCode()).isEqualTo(250);
+            try (SmtpClient client = 
SmtpClient.connectWithProxy(testSystem.getBindedAddress(), "127.0.0.1")) {
+                client.sendCommand("EHLO localhost");
+                assertThat(client.sendCommand("MAIL FROM: <>")).isEqualTo(250);
+            }
         }
 
         @Test
         void nonNullSenderShouldStillBeCheckedAgainstAllowedList() throws 
Exception {
-            SMTPClient smtpProtocol = new SMTPClient();
-            InetSocketAddress bindedAddress = testSystem.getBindedAddress();
-            smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), 
bindedAddress.getPort());
+            try (SmtpClient client = 
SmtpClient.connectWithProxy(testSystem.getBindedAddress(), "127.0.0.1")) {
+                client.sendCommand("EHLO localhost");
+                assertThat(client.sendCommand("MAIL FROM: 
<[email protected]>")).isEqualTo(550);
+            }
+        }
+    }
+
+    private static class SmtpClient implements Closeable {
+        private final Socket socket;
+        private final BufferedReader reader;
+        private final OutputStream out;
+
+        private SmtpClient(Socket socket) throws IOException {
+            this.socket = socket;
+            this.reader = new BufferedReader(new 
InputStreamReader(socket.getInputStream(), UTF_8));
+            this.out = socket.getOutputStream();
+        }
+
+        static SmtpClient connectWithProxy(InetSocketAddress serverAddress, 
String sourceIp) throws IOException {
+            Socket socket = new Socket(serverAddress.getAddress(), 
serverAddress.getPort());
+            socket.setSoTimeout(5000);
+            SmtpClient client = new SmtpClient(socket);
+            client.readResponse(); // consume greeting
+            client.sendRaw("PROXY TCP4 " + sourceIp + " 127.0.0.1 12345 25");
+            return client;
+        }
 
-            smtpProtocol.sendCommand("EHLO localhost");
-            smtpProtocol.sendCommand("MAIL FROM: <[email protected]>");
+        int sendCommand(String command) throws IOException {
+            sendRaw(command);
+            return Integer.parseInt(readResponse().substring(0, 3));
+        }
+
+        void authenticate() throws IOException {
+            sendCommand("AUTH PLAIN");
+            int code = sendCommand(Base64.getEncoder().encodeToString(("\0" + 
BOB.asString() + "\0" + PASSWORD + "\0").getBytes(UTF_8)));
+            assertThat(code).as("authenticated").isEqualTo(235);
+        }
+
+        private void sendRaw(String line) throws IOException {
+            out.write((line + "\r\n").getBytes(UTF_8));
+            out.flush();
+        }
+
+        private String readResponse() throws IOException {
+            StringBuilder sb = new StringBuilder();
+            String line;
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+                // A final response line has a space after the 3-digit code 
(not a dash)
+                if (line.length() >= 4
+                        && Character.isDigit(line.charAt(0))
+                        && Character.isDigit(line.charAt(1))
+                        && Character.isDigit(line.charAt(2))
+                        && line.charAt(3) == ' ') {
+                    break;
+                }
+            }
+            return sb.toString();
+        }
 
-            assertThat(smtpProtocol.getReplyCode()).isEqualTo(550);
+        @Override
+        public void close() throws IOException {
+            socket.close();
         }
     }
 }
diff --git 
a/server/protocols/protocols-smtp/src/test/resources/smtpserver-allowed-unauthenticated-sender-allow-null.xml
 
b/server/protocols/protocols-smtp/src/test/resources/smtpserver-allowed-unauthenticated-sender-allow-null.xml
index bb3b5ce0cc..51843c10d8 100644
--- 
a/server/protocols/protocols-smtp/src/test/resources/smtpserver-allowed-unauthenticated-sender-allow-null.xml
+++ 
b/server/protocols/protocols-smtp/src/test/resources/smtpserver-allowed-unauthenticated-sender-allow-null.xml
@@ -52,4 +52,5 @@
         <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
     </handlerchain>
     <gracefulShutdown>false</gracefulShutdown>
+    <proxyRequired>true</proxyRequired>
 </smtpserver>
diff --git 
a/server/protocols/protocols-smtp/src/test/resources/smtpserver-allowed-unauthenticated-sender.xml
 
b/server/protocols/protocols-smtp/src/test/resources/smtpserver-allowed-unauthenticated-sender.xml
index d90d20e8ef..1d96dea0fa 100644
--- 
a/server/protocols/protocols-smtp/src/test/resources/smtpserver-allowed-unauthenticated-sender.xml
+++ 
b/server/protocols/protocols-smtp/src/test/resources/smtpserver-allowed-unauthenticated-sender.xml
@@ -53,4 +53,5 @@
         <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
     </handlerchain>
     <gracefulShutdown>false</gracefulShutdown>
+    <proxyRequired>true</proxyRequired>
 </smtpserver>


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

Reply via email to