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

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

commit 657749132f5a2034ee2daa402cca83af5eb47cce
Author: Quan Tran <[email protected]>
AuthorDate: Thu Jul 9 15:14:16 2026 +0700

    JAMES-4210 Add SMTP explicit LOGIN SASL integration test
    
    Add a Guice-backed SMTP integration test proving auth.saslMechanisms can 
explicitly configure LoginSaslMechanismFactory and authenticate with AUTH 
LOGIN. Extend the test SMTP configuration template to render auth.requireSSL 
and explicit SASL mechanism entries.
---
 server/mailet/integration-testing/pom.xml          |   5 +
 .../mailets/configuration/SmtpConfiguration.java   |  25 +++++
 .../src/main/resources/smtpserver.xml              |   8 +-
 .../mailets/SmtpSaslMechanismIntegrationTest.java  | 113 +++++++++++++++++++++
 4 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/server/mailet/integration-testing/pom.xml 
b/server/mailet/integration-testing/pom.xml
index 2bed7540fc..0e051cc0b4 100644
--- a/server/mailet/integration-testing/pom.xml
+++ b/server/mailet/integration-testing/pom.xml
@@ -119,6 +119,11 @@
             <groupId>com.rabbitmq</groupId>
             <artifactId>amqp-client</artifactId>
         </dependency>
+        <dependency>
+            <groupId>commons-net</groupId>
+            <artifactId>commons-net</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
diff --git 
a/server/mailet/integration-testing/src/main/java/org/apache/james/mailets/configuration/SmtpConfiguration.java
 
b/server/mailet/integration-testing/src/main/java/org/apache/james/mailets/configuration/SmtpConfiguration.java
index 3640af9d2a..66f8e82bf0 100644
--- 
a/server/mailet/integration-testing/src/main/java/org/apache/james/mailets/configuration/SmtpConfiguration.java
+++ 
b/server/mailet/integration-testing/src/main/java/org/apache/james/mailets/configuration/SmtpConfiguration.java
@@ -76,6 +76,8 @@ public class SmtpConfiguration implements SerializableAsXml {
         private Optional<Boolean> allowUnauthenticatedSender;
         private Optional<Boolean> bracketEnforcement;
         private Optional<String> authorizedAddresses;
+        private Optional<Boolean> authRequireSSL;
+        private Optional<String> saslMechanisms;
         private final ImmutableList.Builder<HookConfigurationEntry> 
additionalHooks;
 
         public Builder() {
@@ -86,6 +88,8 @@ public class SmtpConfiguration implements SerializableAsXml {
             maxMessageSize = Optional.empty();
             bracketEnforcement = Optional.empty();
             allowUnauthenticatedSender = Optional.empty();
+            authRequireSSL = Optional.empty();
+            saslMechanisms = Optional.empty();
             additionalHooks = ImmutableList.builder();
         }
 
@@ -135,6 +139,16 @@ public class SmtpConfiguration implements 
SerializableAsXml {
             return this;
         }
 
+        public Builder requireSSLForAuth(boolean requireSSL) {
+            this.authRequireSSL = Optional.of(requireSSL);
+            return this;
+        }
+
+        public Builder withSaslMechanisms(String saslMechanisms) {
+            this.saslMechanisms = Optional.of(saslMechanisms);
+            return this;
+        }
+
         public Builder relaxedIdentityVerification() {
             this.verifyIndentity = 
Optional.of(SMTPConfiguration.SenderVerificationMode.RELAXED);
             return this;
@@ -158,6 +172,8 @@ public class SmtpConfiguration implements SerializableAsXml 
{
                     allowUnauthenticatedSender.orElse(true),
                     
verifyIndentity.orElse(SMTPConfiguration.SenderVerificationMode.DISABLED),
                     maxMessageSize.orElse(DEFAULT_DISABLED),
+                    authRequireSSL.orElse(false),
+                    saslMechanisms,
                     additionalHooks.build());
         }
     }
@@ -173,6 +189,8 @@ public class SmtpConfiguration implements SerializableAsXml 
{
     private final boolean allowUnauthenticatedSenders;
     private final SMTPConfiguration.SenderVerificationMode verifyIndentity;
     private final String maxMessageSize;
+    private final boolean authRequireSSL;
+    private final Optional<String> saslMechanisms;
     private final ImmutableList<HookConfigurationEntry> additionalHooks;
 
     private SmtpConfiguration(Optional<String> authorizedAddresses,
@@ -182,6 +200,8 @@ public class SmtpConfiguration implements SerializableAsXml 
{
                               boolean allowUnauthenticatedSenders,
                               SMTPConfiguration.SenderVerificationMode 
verifyIndentity,
                               String maxMessageSize,
+                              boolean authRequireSSL,
+                              Optional<String> saslMechanisms,
                               ImmutableList<HookConfigurationEntry> 
additionalHooks) {
         this.authorizedAddresses = authorizedAddresses;
         this.authRequired = authRequired;
@@ -189,6 +209,8 @@ public class SmtpConfiguration implements SerializableAsXml 
{
         this.verifyIndentity = verifyIndentity;
         this.allowUnauthenticatedSenders = allowUnauthenticatedSenders;
         this.maxMessageSize = maxMessageSize;
+        this.authRequireSSL = authRequireSSL;
+        this.saslMechanisms = saslMechanisms;
         this.startTls = startTls;
         this.additionalHooks = additionalHooks;
     }
@@ -202,6 +224,9 @@ public class SmtpConfiguration implements SerializableAsXml 
{
         scopes.put("verifyIdentity", verifyIndentity.toString());
         scopes.put("forbidUnauthenticatedSenders", 
Boolean.toString(!allowUnauthenticatedSenders));
         scopes.put("maxmessagesize", maxMessageSize);
+        scopes.put("authRequireSSL", authRequireSSL);
+        scopes.put("hasSaslMechanisms", saslMechanisms.isPresent());
+        saslMechanisms.ifPresent(value -> scopes.put("saslMechanisms", value));
         scopes.put("bracketEnforcement", bracketEnforcement);
         scopes.put("startTls", startTls);
 
diff --git 
a/server/mailet/integration-testing/src/main/resources/smtpserver.xml 
b/server/mailet/integration-testing/src/main/resources/smtpserver.xml
index e2a2c719fb..4cea11c9a0 100644
--- a/server/mailet/integration-testing/src/main/resources/smtpserver.xml
+++ b/server/mailet/integration-testing/src/main/resources/smtpserver.xml
@@ -39,8 +39,11 @@
 {{/hasAuthorizedAddresses}}
         <auth>
             <required>{{forbidUnauthenticatedSenders}}</required>
-            <requireSSL>false</requireSSL>
+            <requireSSL>{{authRequireSSL}}</requireSSL>
             <plainAuthEnabled>true</plainAuthEnabled>
+{{#hasSaslMechanisms}}
+            <saslMechanisms>{{saslMechanisms}}</saslMechanisms>
+{{/hasSaslMechanisms}}
         </auth>
         <verifyIdentity>{{verifyIdentity}}</verifyIdentity>
         <maxmessagesize>{{maxmessagesize}}</maxmessagesize>
@@ -83,6 +86,9 @@
             <required>{{forbidUnauthenticatedSenders}}</required>
             <requireSSL>true</requireSSL>
             <plainAuthEnabled>true</plainAuthEnabled>
+{{#hasSaslMechanisms}}
+            <saslMechanisms>{{saslMechanisms}}</saslMechanisms>
+{{/hasSaslMechanisms}}
         </auth>
         <!-- Trust authenticated users -->
         <verifyIdentity>false</verifyIdentity>
diff --git 
a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SmtpSaslMechanismIntegrationTest.java
 
b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SmtpSaslMechanismIntegrationTest.java
new file mode 100644
index 0000000000..3cd5188c12
--- /dev/null
+++ 
b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SmtpSaslMechanismIntegrationTest.java
@@ -0,0 +1,113 @@
+/****************************************************************
+ * 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.mailets;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.james.mailets.configuration.Constants.DEFAULT_DOMAIN;
+import static org.apache.james.mailets.configuration.Constants.LOCALHOST_IP;
+import static org.apache.james.mailets.configuration.Constants.PASSWORD;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.util.Base64;
+
+import org.apache.commons.net.smtp.SMTPClient;
+import org.apache.james.MemoryJamesServerMain;
+import org.apache.james.mailets.configuration.CommonProcessors;
+import org.apache.james.mailets.configuration.MailetConfiguration;
+import org.apache.james.mailets.configuration.MailetContainer;
+import org.apache.james.mailets.configuration.ProcessorConfiguration;
+import org.apache.james.mailets.configuration.SmtpConfiguration;
+import org.apache.james.modules.protocols.SmtpGuiceProbe;
+import org.apache.james.probe.DataProbe;
+import org.apache.james.utils.DataProbeImpl;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class SmtpSaslMechanismIntegrationTest {
+    private static final String USER = "fromuser@" + DEFAULT_DOMAIN;
+
+    private static String base64(String value) {
+        return Base64.getEncoder().encodeToString(value.getBytes(UTF_8));
+    }
+
+    private TemporaryJamesServer jamesServer;
+
+    @BeforeEach
+    void setup(@TempDir File temporaryFolder) throws Exception {
+        jamesServer = TemporaryJamesServer.builder()
+            .withBase(MemoryJamesServerMain.SMTP_ONLY_MODULE)
+            .withMailetContainer(minimalMailetContainer())
+            .withSmtpConfiguration(SmtpConfiguration.builder()
+                .doNotVerifyIdentity()
+                .requireSSLForAuth(true)
+                .withSaslMechanisms("LoginSaslMechanismFactory")
+                .build())
+            .build(temporaryFolder);
+        jamesServer.start();
+
+        DataProbe dataProbe = jamesServer.getProbe(DataProbeImpl.class);
+        dataProbe.addDomain(DEFAULT_DOMAIN);
+        dataProbe.addUser(USER, PASSWORD);
+    }
+
+    private MailetContainer.Builder minimalMailetContainer() {
+        return MailetContainer.builder()
+            .putProcessor(CommonProcessors.simpleRoot())
+            .putProcessor(CommonProcessors.error())
+            .putProcessor(CommonProcessors.rrtError())
+            .putProcessor(ProcessorConfiguration.transport()
+                .addMailet(MailetConfiguration.BCC_STRIPPER)
+                .addMailet(MailetConfiguration.TO_BOUNCE))
+            .putProcessor(CommonProcessors.bounces());
+    }
+
+    @AfterEach
+    void tearDown() {
+        jamesServer.shutdown();
+    }
+
+    @Test
+    void explicitlyConfiguredLoginSaslMechanismShouldAuthenticate() throws 
Exception {
+        SMTPClient smtpClient = new SMTPClient();
+        try {
+            smtpClient.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+
+            smtpClient.sendCommand("EHLO", "localhost");
+            assertThat(smtpClient.getReplyCode()).isEqualTo(250);
+
+            smtpClient.sendCommand("AUTH LOGIN");
+            assertThat(smtpClient.getReplyCode()).isEqualTo(334);
+
+            smtpClient.sendCommand(base64(USER));
+            assertThat(smtpClient.getReplyCode()).isEqualTo(334);
+
+            smtpClient.sendCommand(base64(PASSWORD));
+            assertThat(smtpClient.getReplyCode()).isEqualTo(235);
+        } finally {
+            if (smtpClient.isConnected()) {
+                smtpClient.disconnect();
+            }
+        }
+    }
+
+}


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

Reply via email to