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 26824b5b4b5fa42d07ff11de745e594acfc183d5
Author: Quan Tran <[email protected]>
AuthorDate: Thu Aug 13 09:42:11 2026 +0700

    JAMES-4210 Drive ManageSieve AUTHENTICATE through SASL exchanges
    
    Replace the mechanism-specific ManageSieve authentication processors with a 
protocol-local SASL exchange driver.
---
 protocols/managesieve/pom.xml                      |  16 --
 .../managesieve/api/AuthenticationProcessor.java   |  34 ---
 .../org/apache/james/managesieve/api/Session.java  |  17 +-
 .../managesieve/api/UnknownSaslMechanism.java      |  28 ---
 .../managesieve/api/commands/Authenticate.java     |  48 ----
 .../managesieve/api/commands/CoreCommands.java     |   2 +-
 .../managesieve/api/commands/LineCommands.java     |   2 +-
 .../james/managesieve/core/CoreProcessor.java      |  93 ++------
 .../core/OAUTHAuthenticationProcessor.java         |  75 -------
 .../core/PlainAuthenticationProcessor.java         |  94 --------
 .../managesieve/transcode/ArgumentParser.java      |  11 -
 .../transcode/ManageSieveProcessor.java            |  93 +++-----
 .../transcode/ManageSieveSaslProcessor.java        | 248 +++++++++++++++++++++
 .../james/managesieve/util/SettableSession.java    |  30 ++-
 14 files changed, 330 insertions(+), 461 deletions(-)

diff --git a/protocols/managesieve/pom.xml b/protocols/managesieve/pom.xml
index 5522b6fa88..01c3b1a869 100644
--- a/protocols/managesieve/pom.xml
+++ b/protocols/managesieve/pom.xml
@@ -37,14 +37,6 @@
             <groupId>${james.groupId}</groupId>
             <artifactId>apache-jsieve-core</artifactId>
         </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-data-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-jwt</artifactId>
-        </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>testing-base</artifactId>
@@ -58,14 +50,6 @@
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>
-        <dependency>
-            <groupId>jakarta.annotation</groupId>
-            <artifactId>jakarta.annotation-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>jakarta.inject</groupId>
-            <artifactId>jakarta.inject-api</artifactId>
-        </dependency>
     </dependencies>
 
 </project>
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/AuthenticationProcessor.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/AuthenticationProcessor.java
deleted file mode 100644
index 50edcbb24e..0000000000
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/AuthenticationProcessor.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *   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.managesieve.api;
-
-import org.apache.james.core.Username;
-
-public interface AuthenticationProcessor {
-
-    String initialServerResponse(Session session);
-
-    /**
-     * @return Null if authentication failed, the authenticated username if 
authentication is successful
-     */
-    Username isAuthenticationSuccesfull(Session session, String 
suppliedClientData) throws SyntaxException, AuthenticationException;
-
-}
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/Session.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/Session.java
index 9f1a058f19..606ac3c3ea 100644
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/Session.java
+++ 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/Session.java
@@ -23,11 +23,13 @@ package org.apache.james.managesieve.api;
 import java.util.Optional;
 
 import org.apache.james.core.Username;
-import org.apache.james.jwt.OidcSASLConfiguration;
-import org.apache.james.managesieve.api.commands.Authenticate;
+import org.apache.james.protocols.api.sasl.SaslExchange;
 
 public interface Session {
 
+    record ActiveSaslExchange(String mechanismName, SaslExchange exchange) {
+    }
+
     enum State {
         UNAUTHENTICATED,
         AUTHENTICATION_IN_PROGRESS,
@@ -46,15 +48,18 @@ public interface Session {
 
     void setState(State state);
 
-    Authenticate.SupportedMechanism getChoosedAuthenticationMechanism();
+    Optional<ActiveSaslExchange> getActiveSaslExchange();
 
-    void setChoosedAuthenticationMechanism(Authenticate.SupportedMechanism 
choosedAuthenticationMechanism);
+    void setActiveSaslExchange(ActiveSaslExchange activeSaslExchange);
+
+    Optional<ActiveSaslExchange> clearActiveSaslExchange();
 
     void setSslEnabled(boolean sslEnabled);
 
     boolean isSslEnabled();
 
-    Optional<OidcSASLConfiguration> getOidcSASLConfiguration();
+    void setStartTlsSupported(boolean startTlsSupported);
+
+    boolean supportStartTLS();
 
-    void setOidcSASLConfiguration(Optional<OidcSASLConfiguration> 
configuration);
 }
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/UnknownSaslMechanism.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/UnknownSaslMechanism.java
deleted file mode 100644
index ebef4a4c25..0000000000
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/UnknownSaslMechanism.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *   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.managesieve.api;
-
-public class UnknownSaslMechanism extends ManageSieveException {
-
-    public UnknownSaslMechanism(String unknownMechanism) {
-        super("Unknown SASL mechanism " + unknownMechanism);
-    }
-}
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/Authenticate.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/Authenticate.java
deleted file mode 100644
index 4e4820cd90..0000000000
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/Authenticate.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *   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.managesieve.api.commands;
-
-import org.apache.james.managesieve.api.Session;
-import org.apache.james.managesieve.api.UnknownSaslMechanism;
-
-
-/**
- * @see <a href=http://tools.ietf.org/html/rfc5804#section-2.1>RFC 5804 
AUTHENTICATE Command</a>
- */
-public interface Authenticate {
-
-    enum SupportedMechanism {
-        PLAIN, XOAUTH2, OAUTHBEARER;
-
-        public static SupportedMechanism retrieveMechanism(String 
serializedData) throws UnknownSaslMechanism {
-            for (SupportedMechanism supportedMechanism : 
SupportedMechanism.values()) {
-                if 
(supportedMechanism.toString().equalsIgnoreCase(serializedData)) {
-                    return supportedMechanism;
-                }
-            }
-            throw new UnknownSaslMechanism(serializedData);
-        }
-    }
-    
-    String chooseMechanism(Session session, String mechanism);
-    
-    String authenticate(Session session, String suppliedData);
-}
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/CoreCommands.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/CoreCommands.java
index 6016b9c192..7f5a6ed98e 100644
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/CoreCommands.java
+++ 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/CoreCommands.java
@@ -26,6 +26,6 @@ package org.apache.james.managesieve.api.commands;
  * @see <a href=http://tools.ietf.org/html/rfc5804#section-2>RFC 5804 
Commands</a>
  */
 public interface CoreCommands extends Capability, CheckScript, DeleteScript, 
GetScript, HaveSpace,
-        ListScripts, PutScript, RenameScript, SetActive, Noop, Unauthenticate, 
Logout, Authenticate, StartTLS {
+        ListScripts, PutScript, RenameScript, SetActive, Noop, Unauthenticate, 
Logout, StartTLS {
 
 }
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/LineCommands.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/LineCommands.java
index 01cc9b3388..d2bc97eade 100644
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/LineCommands.java
+++ 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/api/commands/LineCommands.java
@@ -25,6 +25,6 @@ package org.apache.james.managesieve.api.commands;
  * 
  *  @see <a href=http://tools.ietf.org/html/rfc5804#section-1.8>RFC 5804 
Transport</a>
  */
-public interface LineCommands extends Authenticate, Unauthenticate, Logout, 
Noop {
+public interface LineCommands extends Unauthenticate, Logout, Noop {
 
 }
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/CoreProcessor.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/CoreProcessor.java
index 0224dac400..4b6186e910 100644
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/CoreProcessor.java
+++ 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/CoreProcessor.java
@@ -27,21 +27,17 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-import jakarta.inject.Inject;
-
 import org.apache.commons.io.IOUtils;
-import org.apache.james.core.Username;
 import org.apache.james.managesieve.api.AuthenticationException;
-import org.apache.james.managesieve.api.AuthenticationProcessor;
 import org.apache.james.managesieve.api.AuthenticationRequiredException;
 import org.apache.james.managesieve.api.ManageSieveException;
 import org.apache.james.managesieve.api.Session;
 import org.apache.james.managesieve.api.SessionTerminatedException;
 import org.apache.james.managesieve.api.SieveParser;
 import org.apache.james.managesieve.api.SyntaxException;
-import org.apache.james.managesieve.api.UnknownSaslMechanism;
 import org.apache.james.managesieve.api.commands.CoreCommands;
 import org.apache.james.managesieve.util.ParserUtils;
+import org.apache.james.protocols.api.sasl.SaslMechanism;
 import org.apache.james.sieverepository.api.ScriptContent;
 import org.apache.james.sieverepository.api.ScriptName;
 import org.apache.james.sieverepository.api.SieveRepository;
@@ -51,11 +47,11 @@ import 
org.apache.james.sieverepository.api.exception.QuotaExceededException;
 import org.apache.james.sieverepository.api.exception.ScriptNotFoundException;
 import org.apache.james.sieverepository.api.exception.SieveRepositoryException;
 import org.apache.james.sieverepository.api.exception.StorageException;
-import org.apache.james.user.api.UsersRepository;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
 
 public class CoreProcessor implements CoreCommands {
@@ -70,15 +66,13 @@ public class CoreProcessor implements CoreCommands {
     private final SieveRepository sieveRepository;
     private final SieveParser parser;
     private final Map<Capabilities, String> capabilitiesBase;
-    private final Map<SupportedMechanism, AuthenticationProcessor> 
authenticationProcessorMap;
+    private final ImmutableList<SaslMechanism> saslMechanisms;
 
-    @Inject
-    public CoreProcessor(SieveRepository repository, UsersRepository 
usersRepository, SieveParser parser) {
+    public CoreProcessor(SieveRepository repository, SieveParser parser, 
ImmutableList<SaslMechanism> saslMechanisms) {
         this.sieveRepository = repository;
         this.parser = parser;
         this.capabilitiesBase = precomputedCapabilitiesBase(parser);
-        this.authenticationProcessorMap = new HashMap<>();
-        this.authenticationProcessorMap.put(SupportedMechanism.PLAIN, new 
PlainAuthenticationProcessor(usersRepository));
+        this.saslMechanisms = saslMechanisms;
     }
 
     @Override
@@ -96,17 +90,17 @@ public class CoreProcessor implements CoreCommands {
 
     private Map<Capabilities, String> computeCapabilityMap(Session session) {
         Map<Capabilities, String> capabilities = 
Maps.newHashMap(capabilitiesBase);
-        if (!session.isSslEnabled()) {
+        if (!session.isSslEnabled() && session.supportStartTLS()) {
             capabilities.put(Capabilities.STARTTLS, null);
         }
         if (session.isAuthenticated()) {
             capabilities.put(Capabilities.OWNER, session.getUser().asString());
         }
-        session.getOidcSASLConfiguration().ifPresent(oidcConfiguration -> {
-            
this.authenticationProcessorMap.putIfAbsent(SupportedMechanism.XOAUTH2, new 
OAUTHAuthenticationProcessor(oidcConfiguration));
-            
this.authenticationProcessorMap.putIfAbsent(SupportedMechanism.OAUTHBEARER, new 
OAUTHAuthenticationProcessor(oidcConfiguration));
-        });
-        capabilities.put(Capabilities.SASL, 
constructSaslSupportedAuthenticationMechanisms());
+        String saslMechanisms = 
constructSaslSupportedAuthenticationMechanisms(session);
+        // RFC 5804 section 1.7 allows an empty SASL list only when STARTTLS 
is also advertised.
+        if (!saslMechanisms.isEmpty() || 
capabilities.containsKey(Capabilities.STARTTLS)) {
+            capabilities.put(Capabilities.SASL, saslMechanisms);
+        }
         return capabilities;
     }
 
@@ -211,60 +205,6 @@ public class CoreProcessor implements CoreCommands {
         return "OK " + taggify(tag) + " \"DONE\"";
     }
 
-    @Override
-    public String chooseMechanism(Session session, String mechanism) {
-        try {
-            if (Strings.isNullOrEmpty(mechanism)) {
-                throw new SyntaxException("quoted SASL mechanism must be 
supplied");
-            }
-
-            SupportedMechanism supportedMechanism = 
SupportedMechanism.retrieveMechanism(mechanism);
-            if 
(!this.authenticationProcessorMap.containsKey(supportedMechanism)) {
-                throw new UnknownSaslMechanism("SASL mechanism disabled: " + 
mechanism);
-            }
-
-            session.setChoosedAuthenticationMechanism(supportedMechanism);
-            session.setState(Session.State.AUTHENTICATION_IN_PROGRESS);
-            AuthenticationProcessor authenticationProcessor = 
authenticationProcessorMap.get(supportedMechanism);
-            return authenticationProcessor.initialServerResponse(session);
-        } catch (UnknownSaslMechanism e) {
-            resetSession(session);
-            return "NO \"" + e.getMessage() + "\"";
-        } catch (SyntaxException e) {
-            resetSession(session);
-            return "NO \"ManageSieve syntax is incorrect: " + e.getMessage() + 
"\"";
-        }
-    }
-
-    @Override
-    public String authenticate(Session session, String suppliedData) {
-        try {
-            SupportedMechanism currentAuthenticationMechanism = 
session.getChoosedAuthenticationMechanism();
-            AuthenticationProcessor authenticationProcessor = 
authenticationProcessorMap.get(currentAuthenticationMechanism);
-            if (Strings.isNullOrEmpty(suppliedData)) {
-                throw new SyntaxException("authentication data must be 
supplied");
-            }
-            if (suppliedData.equals("*")) {
-                throw new AuthenticationException("authentication aborted by 
client");
-            }
-            Username authenticatedUsername = 
authenticationProcessor.isAuthenticationSuccesfull(session, suppliedData);
-            if (authenticatedUsername != null) {
-                session.setUser(authenticatedUsername);
-                session.setState(Session.State.AUTHENTICATED);
-                return "OK";
-            } else {
-                resetSession(session);
-                return "NO \"authentication failed\"";
-            }
-        } catch (AuthenticationException e) {
-            resetSession(session);
-            return "NO \"Authentication failed with: " + e.getMessage() + "\"";
-        } catch (SyntaxException e) {
-            resetSession(session);
-            return "NO \"ManageSieve syntax is incorrect: " + e.getMessage() + 
"\"";
-        }
-    }
-
     @Override
     public String unauthenticate(Session session) {
         if (session.isAuthenticated()) {
@@ -278,7 +218,6 @@ public class CoreProcessor implements CoreCommands {
     private static void resetSession(Session session) {
         session.setState(Session.State.UNAUTHENTICATED);
         session.setUser(null);
-        session.setChoosedAuthenticationMechanism(null);
     }
 
     @Override
@@ -354,11 +293,11 @@ public class CoreProcessor implements CoreCommands {
         return capabilitiesBase;
     }
 
-    private String constructSaslSupportedAuthenticationMechanisms() {
-        return Joiner.on(' ').join(this.authenticationProcessorMap
-            .keySet()
+    private String constructSaslSupportedAuthenticationMechanisms(Session 
session) {
+        return Joiner.on(' ').join(this.saslMechanisms
             .stream()
-            .map(Enum::toString)
+            .filter(mechanism -> 
mechanism.isAvailableOnTransport(session.isSslEnabled()))
+            .map(SaslMechanism::name)
             .iterator()
         );
     }
@@ -366,4 +305,4 @@ public class CoreProcessor implements CoreCommands {
     private String sanitizeString(String message) {
         return Joiner.on("\r\n").join(Splitter.on('\n').split(message));
     }
-}
\ No newline at end of file
+}
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/OAUTHAuthenticationProcessor.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/OAUTHAuthenticationProcessor.java
deleted file mode 100644
index ebdfe25c33..0000000000
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/OAUTHAuthenticationProcessor.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *   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.managesieve.core;
-
-import java.util.Optional;
-
-import org.apache.james.core.Username;
-import org.apache.james.jwt.OidcJwtTokenVerifier;
-import org.apache.james.jwt.OidcSASLConfiguration;
-import org.apache.james.managesieve.api.AuthenticationException;
-import org.apache.james.managesieve.api.AuthenticationProcessor;
-import org.apache.james.managesieve.api.Session;
-import org.apache.james.managesieve.api.SyntaxException;
-import org.apache.james.protocols.api.OIDCSASLParser;
-import org.apache.james.protocols.api.OIDCSASLParser.OIDCInitialResponse;
-
-public class OAUTHAuthenticationProcessor implements AuthenticationProcessor {
-
-    private final OidcSASLConfiguration oidcConfiguration;
-
-    public OAUTHAuthenticationProcessor(OidcSASLConfiguration 
oidcConfiguration) {
-        this.oidcConfiguration = oidcConfiguration;
-    }
-
-    @Override
-    public String initialServerResponse(Session session) {
-        return "+ \"\"";
-    }
-
-    @Override
-    public Username isAuthenticationSuccesfull(Session session, String 
suppliedClientData) throws SyntaxException, AuthenticationException {
-        Optional<OIDCInitialResponse> oidcInitialResponseResult = 
OIDCSASLParser.parse(suppliedClientData);
-        if (oidcInitialResponseResult.isEmpty()) {
-            throw new SyntaxException("Could not parse the given JWT");
-        }
-        OIDCInitialResponse oidcInitialResponse = 
oidcInitialResponseResult.get();
-
-        Optional<Username> authenticatedUserResult = Optional.empty();
-        try {
-            authenticatedUserResult = new 
OidcJwtTokenVerifier(this.oidcConfiguration).validateToken(oidcInitialResponse.getToken());
-        } catch (Exception e) {
-            throw new AuthenticationException("Could not validate the JWT");
-        }
-        if (authenticatedUserResult.isEmpty()) {
-            throw new AuthenticationException("Could not validate the JWT");
-        }
-        Username authenticatedUser = authenticatedUserResult.get();
-
-        // The user from the managesieve AUTHENTICATE command must match the 
username in the token.
-        Username associatedUser = 
Username.of(oidcInitialResponse.getAssociatedUser());
-        if (!authenticatedUser.equals(associatedUser)) {
-            throw new AuthenticationException("Mismatch between user from 
command and JWT");
-        }
-
-        return authenticatedUser;
-    }
-}
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/PlainAuthenticationProcessor.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/PlainAuthenticationProcessor.java
deleted file mode 100644
index 1e9e659638..0000000000
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/core/PlainAuthenticationProcessor.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- *   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.managesieve.core;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import java.util.Iterator;
-
-import org.apache.james.core.Username;
-import org.apache.james.managesieve.api.AuthenticationException;
-import org.apache.james.managesieve.api.AuthenticationProcessor;
-import org.apache.james.managesieve.api.Session;
-import org.apache.james.managesieve.api.SyntaxException;
-import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.api.UsersRepositoryException;
-import org.apache.james.user.api.model.User;
-
-import com.google.common.base.Splitter;
-
-/**
- * See RFC-4616 : https://tools.ietf.org/html/rfc4616
- *
- * Only differences is that ManageSieve does not handle tags. See 
https://tools.ietf.org/html/rfc5804#section-2.1 for details
- */
-public class PlainAuthenticationProcessor implements AuthenticationProcessor {
-
-    private final UsersRepository usersRepository;
-
-    public PlainAuthenticationProcessor(UsersRepository usersRepository) {
-        this.usersRepository = usersRepository;
-    }
-
-    @Override
-    public String initialServerResponse(Session session) {
-        return "+ \"\"";
-    }
-
-
-    @Override
-    public Username isAuthenticationSuccesfull(Session session, String 
suppliedClientData) throws SyntaxException, AuthenticationException {
-        try {
-            byte[] decoded = 
Base64.getDecoder().decode(suppliedClientData.getBytes());
-            String decodedString = new String(decoded, 
StandardCharsets.US_ASCII);
-            return authenticateWithSeparator(session, decodedString, '\u0000');
-        } catch (Exception e) {
-            if (suppliedClientData.contains("\u0000")) {
-                return authenticateWithSeparator(session, suppliedClientData, 
'\u0000');
-            } else {
-                return authenticateWithSeparator(session, suppliedClientData, 
' ');
-            }
-        }
-    }
-
-    private Username authenticateWithSeparator(Session session, String 
suppliedClientData, char c) throws SyntaxException, AuthenticationException {
-        Iterator<String> it = 
Splitter.on(c).omitEmptyStrings().split(suppliedClientData).iterator();
-        if (!it.hasNext()) {
-            throw new SyntaxException("You must supply a username for the 
authentication mechanism. Formal syntax: <NULL>username<NULL>password");
-        }
-        Username userName = Username.of(it.next());
-        if (!it.hasNext()) {
-            throw new SyntaxException("You must supply a password for the 
authentication mechanism. Formal syntax: <NULL>username<NULL>password");
-        }
-        String password = it.next();
-        session.setUser(userName);
-        try {
-            User user = usersRepository.getUserByName(userName);
-            if (user != null && user.verifyPassword(password)) {
-                return user.getUserName();
-            } else {
-                throw new AuthenticationException("Verification of credentials 
failed");
-            }
-        } catch (UsersRepositoryException e) {
-            throw new AuthenticationException(e.getMessage());
-        }
-    }
-}
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ArgumentParser.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ArgumentParser.java
index c6d2cb16f6..5132191b5d 100644
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ArgumentParser.java
+++ 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ArgumentParser.java
@@ -22,8 +22,6 @@ package org.apache.james.managesieve.transcode;
 
 import java.util.Iterator;
 
-import jakarta.inject.Inject;
-
 import org.apache.james.managesieve.api.ArgumentException;
 import org.apache.james.managesieve.api.Session;
 import org.apache.james.managesieve.api.SessionTerminatedException;
@@ -42,7 +40,6 @@ public class ArgumentParser {
     private final CoreCommands core;
     private final boolean validatePutSize;
 
-    @Inject
     public ArgumentParser(CoreCommands core) {
         this.core = core;
         this.validatePutSize = true;
@@ -76,14 +73,6 @@ public class ArgumentParser {
         core.logout();
     }
 
-    public String chooseMechanism(Session session, String mechanism) {
-        return core.chooseMechanism(session, mechanism);
-    }
-
-    public String authenticate(Session session, String suppliedData) {
-        return core.authenticate(session, suppliedData);
-    }
-    
     public String deleteScript(Session session, String args) {
         Iterator<String> argumentIterator = Splitter.on(' 
').omitEmptyStrings().split(args).iterator();
         if (!argumentIterator.hasNext()) {
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ManageSieveProcessor.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ManageSieveProcessor.java
index 391e9203b9..bfa2f1d608 100644
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ManageSieveProcessor.java
+++ 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ManageSieveProcessor.java
@@ -20,16 +20,16 @@
 
 package org.apache.james.managesieve.transcode;
 
-import jakarta.inject.Inject;
-
 import org.apache.james.managesieve.api.ManageSieveException;
 import org.apache.james.managesieve.api.Session;
 import org.apache.james.managesieve.api.SessionTerminatedException;
-import org.apache.james.managesieve.util.ParserUtils;
+import org.apache.james.protocols.api.sasl.SaslAuthenticator;
+import org.apache.james.protocols.api.sasl.SaslMechanism;
 import org.apache.james.sieverepository.api.exception.SieveRepositoryException;
 
-public class ManageSieveProcessor {
+import com.google.common.collect.ImmutableList;
 
+public class ManageSieveProcessor {
     public static final String AUTHENTICATE = "AUTHENTICATE";
     public static final String CAPABILITY = "CAPABILITY";
     public static final String CHECKSCRIPT = "CHECKSCRIPT";
@@ -47,80 +47,58 @@ public class ManageSieveProcessor {
     public static final String UNAUTHENTICATE = "UNAUTHENTICATE";
 
     private final ArgumentParser argumentParser;
+    private final ManageSieveSaslProcessor saslProcessor;
 
-    @Inject
-    public ManageSieveProcessor(ArgumentParser argumentParser) {
+    public ManageSieveProcessor(ArgumentParser argumentParser,
+                                ImmutableList<SaslMechanism> saslMechanisms,
+                                SaslAuthenticator saslAuthenticator) {
         this.argumentParser = argumentParser;
+        this.saslProcessor = new ManageSieveSaslProcessor(saslMechanisms, 
saslAuthenticator);
     }
 
     public String handleRequest(Session session, String request) throws 
ManageSieveException, SieveRepositoryException {
-        if (request.endsWith("\n")) {
-            request = request.substring(0, request.length() - 1);
-        }
-        if (request.endsWith("\r")) {
-            request = request.substring(0, request.length() - 1);
-        }
-
+        String requestWithoutLineEnding = removeLineEnding(request);
         if (session.getState() == Session.State.AUTHENTICATION_IN_PROGRESS) {
-            return matchCommandWithImplementation(session, request.trim(), 
AUTHENTICATE) + "\r\n";
+            return saslProcessor.handleContinuation(session, 
requestWithoutLineEnding) + "\r\n";
         }
 
-        int firstWordEndIndex = request.indexOf(' ');
-        String arguments = parseArguments(request, firstWordEndIndex);
-        String command = parseCommand(request, firstWordEndIndex);
+        int firstWordEndIndex = requestWithoutLineEnding.indexOf(' ');
+        String arguments = parseArguments(requestWithoutLineEnding, 
firstWordEndIndex);
+        String command = parseCommand(requestWithoutLineEnding, 
firstWordEndIndex);
         return matchCommandWithImplementation(session, arguments, command) + 
"\r\n";
     }
 
+    public void close(Session session) {
+        saslProcessor.close(session);
+    }
+
+    private String removeLineEnding(String request) {
+        if (request.endsWith("\r\n")) {
+            return request.substring(0, request.length() - 2);
+        }
+        if (request.endsWith("\n") || request.endsWith("\r")) {
+            return request.substring(0, request.length() - 1);
+        }
+        return request;
+    }
+
     private String parseCommand(String request, int firstWordEndIndex) {
-        String command;
-        if (request.contains(" ")) {
-            command = request.substring(0, firstWordEndIndex);
-        } else {
-            command = request;
+        if (firstWordEndIndex >= 0) {
+            return request.substring(0, firstWordEndIndex);
         }
-        return command;
+        return request;
     }
 
     private String parseArguments(String request, int firstWordEndIndex) {
-        if (request.contains(" ")) {
-            return request.substring(firstWordEndIndex).trim();
-        } else {
-            return "";
+        if (firstWordEndIndex >= 0) {
+            return request.substring(firstWordEndIndex + 1).trim();
         }
+        return "";
     }
 
     private String matchCommandWithImplementation(Session session, String 
arguments, String command) throws SessionTerminatedException {
         if (command.equalsIgnoreCase(AUTHENTICATE)) {
-            // The RFC forbids the AUTHENTICATE command if the session is 
already authenticated.
-            if (session.isAuthenticated()) {
-                return "NO \"already authenticated\"";
-            }
-
-            // If no authentication is in progress, the authentication 
mechanism needs to be chosen.
-            if (session.getState() != 
Session.State.AUTHENTICATION_IN_PROGRESS) {
-                String mechanism = ParserUtils.unquoteFirst(arguments);
-                String result = argumentParser.chooseMechanism(session, 
mechanism);
-                // If the authentication is not in progress, return the result 
(error) because choosing the mechanism has failed.
-                if (session.getState() != 
Session.State.AUTHENTICATION_IN_PROGRESS) {
-                    return result;
-                }
-
-                // Skips the whole mechanism, the closing quote, and the space 
if present.
-                // If the request is well-formatted, the arguments are now 
empty or contain the client's initial response.
-                arguments = arguments.substring(arguments.indexOf(mechanism) + 
mechanism.length() + 1);
-                if (arguments.startsWith(" ")) {
-                    arguments = arguments.substring(1);
-                }
-                // If there are is no initial client response left, return the 
result (initial server response).
-                if (arguments.isEmpty()) {
-                    return result;
-                }
-                // Unquote the argument in this case because continuation is 
not used.
-                arguments = ParserUtils.unquoteFirst(arguments);
-            }
-
-            // The authentication is in progress, the mechanism has been 
chosen, and the arguments contain an initial client response.
-            return argumentParser.authenticate(session, arguments);
+            return saslProcessor.startAuthentication(session, arguments);
         } else if (command.equalsIgnoreCase(CAPABILITY)) {
             return argumentParser.capability(session, arguments);
         } else if (command.equalsIgnoreCase(CHECKSCRIPT)) {
@@ -154,5 +132,4 @@ public class ManageSieveProcessor {
     public String getAdvertisedCapabilities(Session session) {
         return argumentParser.capability(session, "") + "\r\n";
     }
-
 }
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ManageSieveSaslProcessor.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ManageSieveSaslProcessor.java
new file mode 100644
index 0000000000..287b1a0c24
--- /dev/null
+++ 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/transcode/ManageSieveSaslProcessor.java
@@ -0,0 +1,248 @@
+/****************************************************************
+ * 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.managesieve.transcode;
+
+import java.util.Optional;
+
+import org.apache.james.managesieve.api.Session;
+import org.apache.james.managesieve.api.Session.ActiveSaslExchange;
+import org.apache.james.managesieve.api.SyntaxException;
+import org.apache.james.managesieve.sasl.ManageSieveSaslCodec;
+import org.apache.james.protocols.api.sasl.SaslAuthenticator;
+import org.apache.james.protocols.api.sasl.SaslExchange;
+import org.apache.james.protocols.api.sasl.SaslFailure;
+import org.apache.james.protocols.api.sasl.SaslMechanism;
+import org.apache.james.protocols.api.sasl.SaslStep;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+class ManageSieveSaslProcessor {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(ManageSieveSaslProcessor.class);
+
+    private final ImmutableList<SaslMechanism> saslMechanisms;
+    private final SaslAuthenticator saslAuthenticator;
+
+    ManageSieveSaslProcessor(ImmutableList<SaslMechanism> saslMechanisms, 
SaslAuthenticator saslAuthenticator) {
+        this.saslMechanisms = saslMechanisms;
+        this.saslAuthenticator = saslAuthenticator;
+    }
+
+    String startAuthentication(Session session, String arguments) {
+        if (session.isAuthenticated()) {
+            return "NO \"already authenticated\"";
+        }
+        try {
+            ManageSieveSaslCodec.InitialRequest request = 
ManageSieveSaslCodec.parseInitialRequest(arguments);
+            Optional<SaslMechanism> mechanism = 
findMechanism(request.mechanismName());
+            if (mechanism.isEmpty()) {
+                return "NO \"Unknown SASL mechanism\"";
+            }
+            SaslMechanism selectedMechanism = mechanism.get();
+            if 
(!selectedMechanism.isAvailableOnTransport(session.isSslEnabled())) {
+                if (!session.isSslEnabled() && 
selectedMechanism.isAvailableOnTransport(true)) {
+                    return "NO (ENCRYPT-NEEDED) \"Authentication requires an 
encrypted channel\"";
+                }
+                return "NO \"Unknown SASL mechanism\"";
+            }
+            return startExchange(session, request, selectedMechanism);
+        } catch (NotEnoughDataException e) {
+            // RFC 5804 section 2.1 permits an initial SASL response as a 
literal spanning multiple network frames.
+            throw e;
+        } catch (SyntaxException e) {
+            resetAuthentication(session);
+            return syntaxFailure(e);
+        } catch (RuntimeException e) {
+            closeAndReset(session);
+            return unexpectedAuthenticationFailure(e);
+        }
+    }
+
+    String handleContinuation(Session session, String suppliedData) {
+        ActiveSaslExchange active = session.getActiveSaslExchange()
+            .orElseThrow(() -> new IllegalStateException("Missing active SASL 
exchange"));
+        if (ManageSieveSaslCodec.isAbort(suppliedData)) {
+            try {
+                return "NO \"Authentication failed with: authentication 
aborted by client\"";
+            } finally {
+                closeAndReset(session);
+            }
+        }
+        try {
+            byte[] clientResponse = parseClientResponse(session, active, 
suppliedData);
+            return handleSaslStep(session, onResponse(session, 
active.exchange(), clientResponse));
+        } catch (NotEnoughDataException e) {
+            // Keep both the channel cumulation and the active exchange until 
the complete literal arrives.
+            throw e;
+        } catch (SyntaxException e) {
+            closeAndReset(session);
+            return syntaxFailure(e);
+        } catch (RuntimeException e) {
+            closeAndReset(session);
+            return unexpectedAuthenticationFailure(e);
+        }
+    }
+
+    void close(Session session) {
+        try {
+            closeActiveSaslExchange(session);
+        } finally {
+            resetAuthentication(session);
+        }
+    }
+
+    private String startExchange(Session session, 
ManageSieveSaslCodec.InitialRequest request, SaslMechanism mechanism) {
+        ActiveSaslExchange active = new 
ActiveSaslExchange(request.mechanismName(), 
mechanism.start(request.saslInitialRequest(), saslAuthenticator));
+        registerActiveSaslExchange(session, active);
+        return handleSaslStep(session, firstStep(session, active.exchange()));
+    }
+
+    private void registerActiveSaslExchange(Session session, 
ActiveSaslExchange active) {
+        if (session.getActiveSaslExchange().isPresent()) {
+            active.exchange().close();
+            throw new IllegalStateException("A SASL exchange is already 
active");
+        }
+        try {
+            session.setActiveSaslExchange(active);
+        } catch (RuntimeException e) {
+            active.exchange().close();
+            throw e;
+        }
+    }
+
+    private SaslStep firstStep(Session session, SaslExchange exchange) {
+        try {
+            return exchange.firstStep();
+        } catch (RuntimeException e) {
+            closeAndReset(session);
+            throw e;
+        }
+    }
+
+    private byte[] parseClientResponse(Session session, ActiveSaslExchange 
active, String suppliedData) throws SyntaxException {
+        try {
+            return 
ManageSieveSaslCodec.parseClientResponse(active.mechanismName(), suppliedData);
+        } catch (NotEnoughDataException | SyntaxException e) {
+            throw e;
+        } catch (RuntimeException e) {
+            closeAndReset(session);
+            throw e;
+        }
+    }
+
+    private SaslStep onResponse(Session session, SaslExchange exchange, byte[] 
clientResponse) {
+        try {
+            return exchange.onResponse(clientResponse);
+        } catch (RuntimeException e) {
+            closeAndReset(session);
+            throw e;
+        }
+    }
+
+    private String handleSaslStep(Session session, SaslStep step) {
+        return switch (step) {
+            case SaslStep.Challenge challenge -> handleChallenge(session, 
challenge);
+            case SaslStep.Success success -> handleSuccess(session, success);
+            case SaslStep.Failure failure -> handleFailure(session, failure);
+        };
+    }
+
+    private String handleChallenge(Session session, SaslStep.Challenge 
challenge) {
+        try {
+            String response = ManageSieveSaslCodec.challenge(challenge);
+            session.setState(Session.State.AUTHENTICATION_IN_PROGRESS);
+            return response;
+        } catch (RuntimeException e) {
+            closeAndReset(session);
+            throw e;
+        }
+    }
+
+    private String handleSuccess(Session session, SaslStep.Success success) {
+        try {
+            String response = ManageSieveSaslCodec.success(success);
+            session.setUser(success.identity().authorizationId());
+            session.setState(Session.State.AUTHENTICATED);
+            return response;
+        } catch (RuntimeException e) {
+            resetAuthentication(session);
+            throw e;
+        } finally {
+            closeActiveSaslExchange(session);
+        }
+    }
+
+    private String handleFailure(Session session, SaslStep.Failure failure) {
+        try {
+            return authenticationFailure(failure.failure());
+        } finally {
+            closeAndReset(session);
+        }
+    }
+
+    private Optional<SaslMechanism> findMechanism(String mechanismName) {
+        return saslMechanisms.stream()
+            .filter(mechanism -> 
mechanism.name().equalsIgnoreCase(mechanismName))
+            .findFirst();
+    }
+
+    private String authenticationFailure(SaslFailure failure) {
+        if (failure.type() == SaslFailure.Type.SERVER_ERROR) {
+            failure.cause().ifPresentOrElse(
+                cause -> LOGGER.error("ManageSieve SASL authentication 
failed", cause),
+                () -> LOGGER.error("ManageSieve SASL authentication failed: 
{}", failure.reason()));
+        }
+        if (failure.type() == SaslFailure.Type.MALFORMED) {
+            return "NO \"ManageSieve syntax is incorrect: authentication data 
is malformed\"";
+        }
+        if (failure.type() == SaslFailure.Type.INVALID_CREDENTIALS) {
+            return "NO \"Authentication failed with: Verification of 
credentials failed\"";
+        }
+        return "NO \"authentication failed\"";
+    }
+
+    private String unexpectedAuthenticationFailure(RuntimeException exception) 
{
+        LOGGER.error("ManageSieve SASL authentication failed", exception);
+        return "NO \"authentication failed\"";
+    }
+
+    private String syntaxFailure(SyntaxException e) {
+        return "NO \"ManageSieve syntax is incorrect: " + e.getMessage() + 
"\"";
+    }
+
+    private void resetAuthentication(Session session) {
+        session.setState(Session.State.UNAUTHENTICATED);
+        session.setUser(null);
+    }
+
+    private void closeAndReset(Session session) {
+        try {
+            closeActiveSaslExchange(session);
+        } finally {
+            resetAuthentication(session);
+        }
+    }
+
+    private void closeActiveSaslExchange(Session session) {
+        session.clearActiveSaslExchange()
+            .ifPresent(active -> active.exchange().close());
+    }
+}
diff --git 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/util/SettableSession.java
 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/util/SettableSession.java
index 204a39e688..16e741a78d 100644
--- 
a/protocols/managesieve/src/main/java/org/apache/james/managesieve/util/SettableSession.java
+++ 
b/protocols/managesieve/src/main/java/org/apache/james/managesieve/util/SettableSession.java
@@ -23,17 +23,15 @@ package org.apache.james.managesieve.util;
 import java.util.Optional;
 
 import org.apache.james.core.Username;
-import org.apache.james.jwt.OidcSASLConfiguration;
 import org.apache.james.managesieve.api.Session;
-import org.apache.james.managesieve.api.commands.Authenticate;
 
 public class SettableSession implements Session {
 
     private Username user;
     private State state;
-    private Authenticate.SupportedMechanism choosedAuthenticationMechanism;
+    private Optional<ActiveSaslExchange> activeSaslExchange = Optional.empty();
     private boolean sslEnabled;
-    private Optional<OidcSASLConfiguration> oidcSASLConfiguration = 
Optional.empty();
+    private boolean startTlsSupported;
 
     public SettableSession() {
         this.state = State.UNAUTHENTICATED;
@@ -66,13 +64,20 @@ public class SettableSession implements Session {
     }
 
     @Override
-    public Authenticate.SupportedMechanism getChoosedAuthenticationMechanism() 
{
-        return choosedAuthenticationMechanism;
+    public Optional<ActiveSaslExchange> getActiveSaslExchange() {
+        return activeSaslExchange;
     }
 
     @Override
-    public void 
setChoosedAuthenticationMechanism(Authenticate.SupportedMechanism 
choosedAuthenticationMechanism) {
-        this.choosedAuthenticationMechanism = choosedAuthenticationMechanism;
+    public void setActiveSaslExchange(ActiveSaslExchange activeSaslExchange) {
+        this.activeSaslExchange = Optional.of(activeSaslExchange);
+    }
+
+    @Override
+    public Optional<ActiveSaslExchange> clearActiveSaslExchange() {
+        Optional<ActiveSaslExchange> previousExchange = activeSaslExchange;
+        this.activeSaslExchange = Optional.empty();
+        return previousExchange;
     }
 
     @Override
@@ -86,12 +91,13 @@ public class SettableSession implements Session {
     }
 
     @Override
-    public Optional<OidcSASLConfiguration> getOidcSASLConfiguration() {
-        return this.oidcSASLConfiguration;
+    public void setStartTlsSupported(boolean startTlsSupported) {
+        this.startTlsSupported = startTlsSupported;
     }
 
     @Override
-    public void setOidcSASLConfiguration(Optional<OidcSASLConfiguration> 
configuration) {
-        this.oidcSASLConfiguration = configuration;
+    public boolean supportStartTLS() {
+        return startTlsSupported;
     }
+
 }


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

Reply via email to