Hello Benoit,

Thanks for your suggestions! That sounds reasonable to me.

I will attempt to apply the suggestions for SMTP.

Regards,

Quan

On Mon, Jun 22, 2026 at 5:17 PM Benoit TELLIER <[email protected]>
wrote:

> Hello Quan
>
> Here are my thoughts.
>
> I think AuthHook encompasses two things:
>
>  - A bad implementation of SASL (no advertized capability) which is Ok
> dropping.
>
> We could potentially even propose a SaslAuthHookAdapter that plugs in the
> SASL flow and delegates to the given AuthHook thus easing migration?
> It would then be mostly conf to adapt ones axtension...
>
>  - Decorate login eg to push a notif somewhere.
>
> Maybe we culd have a new hook (SaslAuthResultHook ?) for being able to
> decorate this and allow adding side effect effectively?
>
>
> So I'd go with:
>  - Deprecate AuthHook
>  - Introduce a SaslAuthHookAdapter that one can extend to record existing
> AuthHook. The SaslAuthHookAdapter should be flexible enough to allow
> override the PLAIN mechanism.
>  - Have a new hook: SaslAuthResultHook
>  - Write an upgrade-instructions regarding this.
>
> Would this make sense ?--
>
>
> Best regards,
>
> Benoit TELLIER
>
> General manager of Linagora VIETNAM.
> Product owner for Twake-Mail product.
> Chairman of the Apache James project.
>
> Mail: [email protected]
> Tel: (0033) 6 77 26 04 58 (WhatsApp, Signal)
>
>
>
> On Jun 22, 2026 12:08 PM, from Quan Tran Hong 
> <[email protected]>Hello
> folks,
>
> Following the Generic SASL modularization and adoption for IMAP at
> github.com/apache/james-project/pull/3059, I am working further on
> the adoption for SMTP (based on the IMAP PR) to see how it goes, before we
> can decide if it is good to merge the IMAP PR and go forward with this SASL
> refactoring.
>
> Regarding SMTP adoption, I am not sure if we should drop the `AuthHook`
> interface (and its extension capability).
>
> *If we drop `AuthHook` for SMTP*, then we would rely purely on the SASL
> layer for the authentication logic, which should reduce the code
> complexity. However, community `AuthHook` extension implementors would then
> need to be rewritten under a custom `SaslMechanism` implementation instead.
> Example of what we proposed for IMAP custom SASL:
>
> github.com/apache/james-project/pull/3059/changes/3f0a554e4c3b3914daecbd41b75a6aa21ae9c8cf
> .
> Also, please note that it may not be straightforward to just replace
> `AuthHook` with the `SaslMechanism` extension: AuthHook can extend the
> *PLAIN* auth capability, while SaslMechanism would likely be distinct by
> the mechanism name (PLAIN) and only override is possible.
>
> *If we keep `AuthHook` for SMTP,* we would mix the legacy `AuthHook` code
> and the modular SASL layer for SMTP authentication, which may introduce
> extra complexity for SMTP authentication. Also, having 2 mechanisms to
> configure authentication for SMTP (`AuthHook` and `SaslMechanism`) feels
> odd. However, keeping the `AuthHook` would be less invasive for community
> extension usage, if any.
>
> I am not sure about the `AuthHook` extension usage in our community, and
> the best way to go for SMTP adoption here. Maybe I would go the defensive
> way to try to keep the `AuthHook` mechanism, to avoid invasion. Or do you
> think the code complexity and the limited adoption of `AuthHook` are not
> worth keeping?
>
> Feedback and opinion are very welcome!
>
> Quan
>
>
> On Wed, Jun 3, 2026 at 12:30 PM Benoit TELLIER <[email protected]>
> wrote:
>
> > This looks really reasonable to me.
> > Other mail servers achieve sasl code mutualisation and expose it as
> > extension.
> > I'd have naturaly bundled the side effects behind the sasl API to mimic
> > current authentication code but I am actually curious to see where the
> more
> > descriptive approach leads us to!
> > --
> >
> >
> > Best regards,
> >
> > Benoit TELLIER
> >
> > General manager of Linagora VIETNAM.
> > Product owner for Twake-Mail product.
> > Chairman of the Apache James project.
> >
> > Mail: [email protected]
> > Tel: (0033) 6 77 26 04 58 (WhatsApp, Signal)
> >
> >
> >
> > On Jun 3, 2026 5:22 AM, from Quan Tran Hong <[email protected]
> >Hi
> > all,
> >
> > I would like to propose a generic SASL mechanism extension model for
> James
> > protocols.
> >
> > Today, when adding a new authentication mechanism for IMAP or SMTP, we
> need
> > to modify core protocol code, such as IMAP *AuthenticateProcessor* or
> SMTP
> > *AuthCmdHandler*. This makes the protocol handlers accumulate
> > mechanism-specific branches, and would make future mechanisms such as
> > GSSAPI / Kerberos harder to add cleanly.
> >
> > The goal is:
> >
> >  - adding a new SASL mechanism should not require modifying core
> IMAP/SMTP
> > command handlers;
> >  - protocol code should keep protocol framing and side effects;
> >  - SASL mechanism code should own mechanism semantics and exchange state;
> >  - existing IMAP/SMTP behavior should remain unchanged when no new
> > configuration is provided.
> >
> > This takes inspiration from JMAP authentication strategies configuration
> > and Guice loading.
> >
> >
> > *Configuration shape*
> > -------------------
> >
> > Each protocol would keep an operator-visible *auth.saslMechanisms* list.
> >
> > Example for IMAP:
> >
> >
> >
> > *    <auth>
> >
> >
> <saslMechanisms>PlainSaslMechanism,OauthBearerSaslMechanism,XOauth2SaslMechanism,com.example.james.kerberos.GssapiSaslMechanism</saslMechanisms>
> >   </auth>*
> >
> > Example for SMTP:
> >
> >
> >
> > *    <auth>
> >
> >
> <saslMechanisms>LoginSaslMechanism,PlainSaslMechanism,OauthBearerSaslMechanism,XOauth2SaslMechanism,com.example.james.kerberos.GssapiSaslMechanism</saslMechanisms>
> >   </auth>*
> >
> > Expected semantics:
> >
> >  - if *auth.saslMechanisms* is absent, load current protocol defaults;
> >  - IMAP defaults remain PLAIN, OAUTHBEARER, XOAUTH2;
> >  - SMTP defaults remain LOGIN, PLAIN, OAUTHBEARER, XOAUTH2;
> >  - if configured, load the configured list in the configured order;
> >  - simple class names resolve against James default SASL packages;
> >  - fully qualified class names allow external/community extensions;
> >
> > Existing protocol settings still decide availability. For example, plain
> > auth restrictions still decide whether PLAIN is advertised, OIDC
> > configuration still decides whether OAuth mechanisms are advertised, and
> > SMTP *auth.announce* still controls whether SMTP advertises AUTH.
> >
> >
> > *Proposed SPI shape*
> > ------------------
> >
> > I propose introducing protocol-neutral SASL types in *protocols/api*, for
> > example under *org.apache.james.protocols.api.sasl*.
> >
> > The core idea is a stateful SaslExchange: each SASL mechanism creates one
> > exchange per authentication attempt, and that exchange owns mechanism
> state
> > across the initial request and continuation responses.
> >
> > Core structure:
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> > *    interface SaslMechanism {        String name();        boolean
> > supports(SaslProtocol protocol);        boolean
> > isAvailable(SaslSessionContext context);        SaslExchange
> > start(SaslInitialRequest request, SaslSessionContext context);    }
> enum
> > SaslProtocol {        IMAP, SMTP, MANAGESIEVE, POP3    }    record
> > SaslInitialRequest(SaslProtocol protocol, String mechanismName,
> > Optional<byte[]> initialResponse) {    }    record SaslIdentity(Username
> > authenticationId, Username authorizationId) {    }    interface
> > SaslSessionContext {        SaslProtocol protocol();        boolean
> > isTlsStarted();        <T> Optional<T> configuration(Class<T>
> > configurationType);    }    interface SaslExchange extends AutoCloseable
> {
> >       SaslStep firstStep();        SaslStep onResponse(byte[]
> > clientResponse);        void abort();        @Override        void
> > close();    }    interface SaslStep {        record
> > Challenge(Optional<byte[]> payload) implements SaslStep {        }
> > record Success(SaslIdentity identity, Optional<byte[]> serverData, String
> > log) implements SaslStep {        }        record Failure(String log)
> > implements SaslStep {        }    }*
> >
> > The intended split is:
> >
> >  - SASL mechanisms own payload parsing, challenge generation, response
> > validation, final SASL identity extraction, and exchange state.
> >  - IMAP/SMTP bridges own base64/wire framing, continuation responses,
> > success/failure session side effects, audit logs, hooks, and
> > protocol-specific error responses.
> >
> > For example, PLAIN and OAUTHBEARER can complete from *firstStep()*, while
> > GSSAPI can return Challenge first and complete later from
> > *onResponse(...)*.
> >
> > SaslIdentity carries both the authentication identity and the
> authorization
> > identity. This keeps delegation expressible by the SPI without granting
> it
> > automatically. IMAP/SMTP bridges still decide whether delegation is
> allowed
> > and how to build their protocol session state.
> >
> >
> > *Loading and registry*
> > --------------------
> >
> > Mechanism loading would follow the same spirit as JMAP authentication
> > strategies:
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> > *    interface SaslMechanismLoader {        ImmutableList<SaslMechanism>
> > load(Collection<String> classNames);    }    class SaslMechanismRegistry
> {
> >       Optional<SaslMechanism> find(String mechanismName, SaslProtocol
> > protocol) {            // match by mechanism name and supports(protocol)
> >     }        Stream<SaslMechanism> availableFor(SaslProtocol protocol,
> > SaslSessionContext context) {            // filter supports(protocol) and
> > isAvailable(context)        }    }*
> >
> > Then implement a GuiceSaslMechanismLoader to actually load the SASL
> > mechanisms.
> >
> >
> > *Incremental implementation plan*
> > -------------------------------
> >
> > I suggest doing this step by step:
> >
> > - *Step 1*: Start with a POC introducing the shared SaslMechanism SPI and
> > adapting IMAP.
> >   This must not introduce breaking changes to existing authentication
> > configs. The SASL SPI can be adopted gradually, protocol by protocol,
> > without changing behavior for protocols that have not adopted it yet.
> > - *Step 2*: Adapt SASL modularization for SMTP.
> > - *Step 3*: Leverage the SASL modularization to implement GSSAPI /
> Kerberos
> > mechanism support.
> >
> > ManageSieve and POP3 are not part of the immediate scope, but the SPI
> > should make later adoption possible.
> >
> > *Testing expectations*
> > --------------------
> >
> > At minimum, I think we should prove:
> >
> >  - no breaking change: absent auth.saslMechanisms keeps existing
> IMAP/SMTP
> > SASL methods;
> >  - configured custom SASL mechanism loads and authenticates through real
> or
> > near-real protocol wiring;
> >  - authentication / authorization identity handling preserves existing
> > delegation behavior (we should already have tests for these);
> >  - fake multi-step mechanism works for continuation;
> >  - exchange cleanup is covered.
> >
> > *Feedback requested*
> > ------------------
> >
> > Does this refactoring direction look reasonable to you? Feedback and
> > discussion are welcome!
> > Meanwhile, I would start POC work on my side to see how this design
> goes...
> >
> > Regards,
> > Quan
> >
> >
>

Reply via email to