This is an automated email from the ASF dual-hosted git repository.
Arsnael 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 412078bf29 JAMES-4210 [POP3] Pass command shall rely on
PlainSaslMechanism logic (#3089)
412078bf29 is described below
commit 412078bf29e51db727f581aa1a2a25619aad689a
Author: Trần Hồng Quân <[email protected]>
AuthorDate: Thu Jul 16 08:53:05 2026 +0700
JAMES-4210 [POP3] Pass command shall rely on PlainSaslMechanism logic
(#3089)
---
.../protocols/sasl/plain/PlainSaslMechanism.java | 2 +
server/protocols/protocols-pop3/pom.xml | 4 ++
.../james/pop3server/core/PassCmdHandler.java | 44 +++++++++++++++++-----
3 files changed, 41 insertions(+), 9 deletions(-)
diff --git
a/protocols/sasl/src/main/java/org/apache/james/protocols/sasl/plain/PlainSaslMechanism.java
b/protocols/sasl/src/main/java/org/apache/james/protocols/sasl/plain/PlainSaslMechanism.java
index 641171f9e5..6a6abeb9e3 100644
---
a/protocols/sasl/src/main/java/org/apache/james/protocols/sasl/plain/PlainSaslMechanism.java
+++
b/protocols/sasl/src/main/java/org/apache/james/protocols/sasl/plain/PlainSaslMechanism.java
@@ -39,6 +39,8 @@ import com.google.common.collect.ImmutableList;
public class PlainSaslMechanism implements SaslMechanism {
public static final String NAME = SaslMechanismNames.PLAIN;
+ public static final boolean ENABLED = true;
+ public static final boolean REQUIRE_SSL = true;
protected record PlainCredentials(Optional<Username> authorizationId,
Username authenticationId, String password) {
}
diff --git a/server/protocols/protocols-pop3/pom.xml
b/server/protocols/protocols-pop3/pom.xml
index 0906ff19f6..849ce07669 100644
--- a/server/protocols/protocols-pop3/pom.xml
+++ b/server/protocols/protocols-pop3/pom.xml
@@ -133,6 +133,10 @@
<groupId>${james.protocols.groupId}</groupId>
<artifactId>protocols-pop3</artifactId>
</dependency>
+ <dependency>
+ <groupId>${james.protocols.groupId}</groupId>
+ <artifactId>protocols-sasl</artifactId>
+ </dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
diff --git
a/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/core/PassCmdHandler.java
b/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/core/PassCmdHandler.java
index 7eeff22175..93ea6a573d 100644
---
a/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/core/PassCmdHandler.java
+++
b/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/core/PassCmdHandler.java
@@ -18,6 +18,9 @@
****************************************************************/
package org.apache.james.pop3server.core;
+import static org.apache.james.protocols.sasl.plain.PlainSaslMechanism.ENABLED;
+import static
org.apache.james.protocols.sasl.plain.PlainSaslMechanism.REQUIRE_SSL;
+
import java.io.IOException;
import java.util.Optional;
@@ -28,7 +31,6 @@ import org.apache.james.core.Username;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageManager;
-import org.apache.james.mailbox.exception.BadCredentialsException;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
@@ -36,11 +38,16 @@ import org.apache.james.metrics.api.MetricFactory;
import org.apache.james.pop3server.mailbox.MailboxAdapterFactory;
import org.apache.james.protocols.api.Request;
import org.apache.james.protocols.api.Response;
+import org.apache.james.protocols.api.sasl.SaslAuthenticator;
+import org.apache.james.protocols.api.sasl.SaslFailure;
+import org.apache.james.protocols.api.sasl.SaslStep;
import org.apache.james.protocols.lib.POP3BeforeSMTPHelper;
import org.apache.james.protocols.pop3.POP3Response;
import org.apache.james.protocols.pop3.POP3Session;
import org.apache.james.protocols.pop3.core.AbstractPassCmdHandler;
import org.apache.james.protocols.pop3.mailbox.Mailbox;
+import org.apache.james.protocols.sasl.JamesSaslAuthenticator;
+import org.apache.james.protocols.sasl.plain.PlainSaslMechanism;
import org.apache.james.util.MDCBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,15 +62,18 @@ import reactor.core.publisher.Mono;
*/
public class PassCmdHandler extends AbstractPassCmdHandler {
private static final Logger LOGGER =
LoggerFactory.getLogger(PassCmdHandler.class);
+ private static final PlainSaslMechanism PLAIN_SASL_MECHANISM = new
PlainSaslMechanism(ENABLED, !REQUIRE_SSL);
private final MailboxManager manager;
private final MailboxAdapterFactory mailboxAdapterFactory;
+ private final SaslAuthenticator saslAuthenticator;
@Inject
public PassCmdHandler(@Named("mailboxmanager") MailboxManager manager,
MailboxAdapterFactory mailboxAdapterFactory, MetricFactory metricFactory) {
super(metricFactory);
this.manager = manager;
this.mailboxAdapterFactory = mailboxAdapterFactory;
+ this.saslAuthenticator =
JamesSaslAuthenticator.jamesSaslAuthenticator(manager);
}
@Override
@@ -81,13 +91,34 @@ public class PassCmdHandler extends AbstractPassCmdHandler
{
return MDCBuilder.withMdc(
MDCBuilder.create()
.addToContext(MDCBuilder.USER, username.asString()),
- Throwing.supplier(() -> auth(session, password)).sneakyThrow());
+ Throwing.supplier(() -> authenticate(session, username,
password)).sneakyThrow());
+ }
+
+ private Mailbox authenticate(POP3Session session, Username username,
String password) throws IOException {
+ return switch (PLAIN_SASL_MECHANISM.authenticate(username, password,
saslAuthenticator)) {
+ case SaslStep.Success success -> openMailbox(session,
success.identity().authorizationId());
+ case SaslStep.Failure failure ->
handleAuthenticationFailure(session, failure.failure());
+ case SaslStep.Challenge ignored -> throw new
IllegalStateException("Direct PLAIN authentication must be terminal");
+ };
+ }
+
+ private Mailbox handleAuthenticationFailure(POP3Session session,
SaslFailure failure) throws IOException {
+ if (failure.type() == SaslFailure.Type.SERVER_ERROR) {
+ throw failure.cause()
+ .map(cause -> new IOException("Unable to authenticate POP3
user " + session.getUsername().asString(), cause))
+ .orElseGet(() -> new IOException("Unable to authenticate POP3
user " + session.getUsername().asString()));
+ }
+
+ LOGGER.info("Bad credential supplied for {} with remote address {}",
+ session.getUsername().asString(),
+ session.getRemoteAddress().getAddress().getHostAddress());
+ return null;
}
- private Mailbox auth(POP3Session session, String password) throws
IOException {
+ private Mailbox openMailbox(POP3Session session, Username username) throws
IOException {
MailboxSession mSession = null;
try {
- mSession = manager.authenticate(session.getUsername(),
password).withoutDelegation();
+ mSession = manager.authenticate(username).withoutDelegation();
session.stopDetectingCommandInjection();
manager.startProcessingRequest(mSession);
MailboxPath inbox = MailboxPath.inbox(mSession);
@@ -103,11 +134,6 @@ public class PassCmdHandler extends AbstractPassCmdHandler
{
mailbox.getMailboxPath().asString(),
mSession.getSessionId().getValue());
return mailboxAdapterFactory.create(mailbox, mSession);
- } catch (BadCredentialsException e) {
- LOGGER.info("Bad credential supplied for {} with remote address
{}",
- session.getUsername().asString(),
- session.getRemoteAddress().getAddress().getHostAddress());
- return null;
} catch (MailboxException e) {
throw new IOException("Unable to access mailbox for user " +
session.getUsername().asString(), e);
} finally {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]