Re: [DISCUSS] Generic SASL mechanism extension model for James protocols

Benoit TELLIER <[email protected]> Mon, 22 Jun 2026 10:16:53 +0000
Newsgroups gmane.comp.jakarta.james.devel
Message-ID <[email protected]>
---=Part.595.6aa5647b1a752c3e.19eeed5419e.eefae479d3e859ed=-
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Accept-Language: fr-FR, en-US, vi-VN, ru-RU, ar-TN, it-IT, de-DE
Content-Language: en-US

Hello Quan

Here are my thoughts=2E

I think AuthHook encompasses two thing=
s:

=C2=A0- A bad implementation of SASL (no advertized capability) which i=
s Ok dropping=2E

We could potentially even propose a SaslAuthHookAdapter t=
hat plugs in the SASL flow and delegates to the given AuthHook thus easing =
migration?
It would then be mostly conf to adapt ones axtension=2E=2E=2E

=
=C2=A0- Decorate login eg to push a notif somewhere=2E=C2=A0

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:
=C2=A0- Deprecate=
=C2=A0AuthHook
=C2=A0- Introduce a=C2=A0SaslAuthHookAdapter that one can ex=
tend to record existing AuthHook=2E The=C2=A0SaslAuthHookAdapter should be =
flexible enough to allow override the PLAIN mechanism=2E
=C2=A0- Have a new=
 hook:=C2=A0SaslAuthResultHook
=C2=A0- Write an upgrade-instructions regard=
ing this=2E

Would this make sense ?--=C2=A0


Best regards,

Benoit TELLIE=
R

General manager of Linagora VIETNAM=2E
Product owner for Twake-Mail prod=
uct=2E
Chairman of the Apache James project=2E

Mail: btellier@linagora=2Ec=
om
Tel: (0033) 6 77 26 04 58 (WhatsApp, Signal)



On Jun 22, 2026 12:08 PM=
, from Quan Tran Hong <quan=2Etranhong1999@gmail=2Ecom>Hello folks,

Follow=
ing the Generic SASL modularization and adoption for IMAP at
github=2Ecom/a=
pache/james-project/pull/3059, I am working further on
the adoption for SMT=
P (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=2E

Reg=
arding SMTP adoption, I am not sure if we should drop the `AuthHook`
interf=
ace (and its extension capability)=2E

*If we drop `AuthHook` for SMTP*, th=
en we would rely purely on the SASL
layer for the authentication logic, whi=
ch should reduce the code
complexity=2E However, community `AuthHook` exten=
sion implementors would then
need to be rewritten under a custom `SaslMecha=
nism` implementation instead=2E
Example of what we proposed for IMAP custom=
 SASL:
github=2Ecom/apache/james-project/pull/3059/changes/3f0a554e4c3b3914=
daecbd41b75a6aa21ae9c8cf
=2E
Also, please note that it may not be straightf=
orward to just replace
`AuthHook` with the `SaslMechanism` extension: AuthH=
ook can extend the
*PLAIN* auth capability, while SaslMechanism would likel=
y be distinct by
the mechanism name (PLAIN) and only override is possible=
=2E

*If we keep `AuthHook` for SMTP,* we would mix the legacy `AuthHook` c=
ode
and the modular SASL layer for SMTP authentication, which may introduce=

extra complexity for SMTP authentication=2E Also, having 2 mechanisms to
c=
onfigure authentication for SMTP (`AuthHook` and `SaslMechanism`) feels
odd=
=2E However, keeping the `AuthHook` would be less invasive for community
ex=
tension usage, if any=2E

I am not sure about the `AuthHook` extension usag=
e in our community, and
the best way to go for SMTP adoption here=2E Maybe =
I would go the defensive
way to try to keep the `AuthHook` mechanism, to av=
oid invasion=2E Or do you
think the code complexity and the limited adoptio=
n of `AuthHook` are not
worth keeping?

Feedback and opinion are very welco=
me!

Quan


On Wed, Jun 3, 2026 at 12:30=E2=80=AFPM Benoit TELLIER <btellie=
r@linagora=2Ecom>
wrote:

> This looks really reasonable to me=2E
> Other m=
ail servers achieve sasl code mutualisation and expose it as
> extension=2E=

> 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 mo=
re
> descriptive approach leads us to!
> --
>
>
> Best regards,
>
> Benoit =
TELLIER
>
> General manager of Linagora VIETNAM=2E
> Product owner for Twak=
e-Mail product=2E
> Chairman of the Apache James project=2E
>
> Mail: btell=
ier@linagora=2Ecom
> Tel: (0033) 6 77 26 04 58 (WhatsApp, Signal)
>
>
>
> O=
n Jun 3, 2026 5:22 AM, from Quan Tran Hong <quan=2Etranhong1999@gmail=2Ecom=
>Hi
> all,
>
> I would like to propose a generic SASL mechanism extension m=
odel for James
> protocols=2E
>
> Today, when adding a new authentication m=
echanism for IMAP or SMTP, we need
> to modify core protocol code, such as =
IMAP *AuthenticateProcessor* or SMTP
> *AuthCmdHandler*=2E This makes the p=
rotocol handlers accumulate
> mechanism-specific branches, and would make f=
uture mechanisms such as
> GSSAPI / Kerberos harder to add cleanly=2E
>
> T=
he 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 se=
mantics and exchange state;
>  - existing IMAP/SMTP behavior should remain =
unchanged when no new
> configuration is provided=2E
>
> This takes inspira=
tion from JMAP authentication strategies configuration
> and Guice loading=
=2E
>
>
> *Configuration shape*
> -------------------
>
> Each protocol wou=
ld keep an operator-visible *auth=2EsaslMechanisms* list=2E
>
> Example for=
 IMAP:
>
>
>
> *    <auth>
>
> <saslMechanisms>PlainSaslMechanism,OauthBear=
erSaslMechanism,XOauth2SaslMechanism,com=2Eexample=2Ejames=2Ekerberos=2EGss=
apiSaslMechanism</saslMechanisms>
>   </auth>*
>
> Example for SMTP:
>
>
>
=
> *    <auth>
>
> <saslMechanisms>LoginSaslMechanism,PlainSaslMechanism,Oau=
thBearerSaslMechanism,XOauth2SaslMechanism,com=2Eexample=2Ejames=2Ekerberos=
=2EGssapiSaslMechanism</saslMechanisms>
>   </auth>*
>
> Expected semantics=
:
>
>  - if *auth=2EsaslMechanisms* is absent, load current protocol defaul=
ts;
>  - IMAP defaults remain PLAIN, OAUTHBEARER, XOAUTH2;
>  - SMTP defaul=
ts remain LOGIN, PLAIN, OAUTHBEARER, XOAUTH2;
>  - if configured, load the =
configured list in the configured order;
>  - simple class names resolve ag=
ainst James default SASL packages;
>  - fully qualified class names allow e=
xternal/community extensions;
>
> Existing protocol settings still decide a=
vailability=2E For example, plain
> auth restrictions still decide whether =
PLAIN is advertised, OIDC
> configuration still decides whether OAuth mecha=
nisms are advertised, and
> SMTP *auth=2Eannounce* still controls whether S=
MTP advertises AUTH=2E
>
>
> *Proposed SPI shape*
> ------------------
>
> =
I propose introducing protocol-neutral SASL types in *protocols/api*, for
>=
 example under *org=2Eapache=2Ejames=2Eprotocols=2Eapi=2Esasl*=2E
>
> The c=
ore idea is a stateful SaslExchange: each SASL mechanism creates one
> exch=
ange per authentication attempt, and that exchange owns mechanism state
> a=
cross the initial request and continuation responses=2E
>
> Core structure:=

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
=
>
>
> *    interface SaslMechanism {        String name();        boolean
>=
 supports(SaslProtocol protocol);        boolean
> isAvailable(SaslSessionC=
ontext context);        SaslExchange
> start(SaslInitialRequest request, Sa=
slSessionContext context);    }    enum
> SaslProtocol {        IMAP, SMTP,=
 MANAGESIEVE, POP3    }    record
> SaslInitialRequest(SaslProtocol protoco=
l, String mechanismName,
> Optional<byte[]> initialResponse) {    }    reco=
rd 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[]
> clientR=
esponse);        void abort();        @Override        void
> close();    }=
    interface SaslStep {        record
> Challenge(Optional<byte[]> payload=
) implements SaslStep {        }
> record Success(SaslIdentity identity, Op=
tional<byte[]> serverData, String
> log) implements SaslStep {        }    =
    record Failure(String log)
> implements SaslStep {        }    }*
>
> T=
he intended split is:
>
>  - SASL mechanisms own payload parsing, challenge=
 generation, response
> validation, final SASL identity extraction, and exc=
hange state=2E
>  - IMAP/SMTP bridges own base64/wire framing, continuation=
 responses,
> success/failure session side effects, audit logs, hooks, and
=
> protocol-specific error responses=2E
>
> For example, PLAIN and OAUTHBEAR=
ER can complete from *firstStep()*, while
> GSSAPI can return Challenge fir=
st and complete later from
> *onResponse(=2E=2E=2E)*=2E
>
> SaslIdentity ca=
rries both the authentication identity and the authorization
> identity=2E =
This keeps delegation expressible by the SPI without granting it
> automati=
cally=2E IMAP/SMTP bridges still decide whether delegation is allowed
> and=
 how to build their protocol session state=2E
>
>
> *Loading and registry*
=
> --------------------
>
> Mechanism loading would follow the same spirit a=
s JMAP authentication
> strategies:
>
>
>
>
>
>
>
>
>
>
>
>
>
> *    interf=
ace SaslMechanismLoader {        ImmutableList<SaslMechanism>
> load(Collec=
tion<String> classNames);    }    class SaslMechanismRegistry {
>       Opt=
ional<SaslMechanism> find(String mechanismName, SaslProtocol
> protocol) { =
           // match by mechanism name and supports(protocol)
>     }       =
 Stream<SaslMechanism> availableFor(SaslProtocol protocol,
> SaslSessionCon=
text context) {            // filter supports(protocol) and
> isAvailable(c=
ontext)        }    }*
>
> Then implement a GuiceSaslMechanismLoader to act=
ually load the SASL
> mechanisms=2E
>
>
> *Incremental implementation plan*=

> -------------------------------
>
> I suggest doing this step by step:
>=

> - *Step 1*: Start with a POC introducing the shared SaslMechanism SPI an=
d
> adapting IMAP=2E
>   This must not introduce breaking changes to existi=
ng authentication
> configs=2E The SASL SPI can be adopted gradually, proto=
col by protocol,
> without changing behavior for protocols that have not ad=
opted it yet=2E
> - *Step 2*: Adapt SASL modularization for SMTP=2E
> - *St=
ep 3*: Leverage the SASL modularization to implement GSSAPI / Kerberos
> me=
chanism support=2E
>
> ManageSieve and POP3 are not part of the immediate s=
cope, but the SPI
> should make later adoption possible=2E
>
> *Testing exp=
ectations*
> --------------------
>
> At minimum, I think we should prove:
=
>
>  - no breaking change: absent auth=2EsaslMechanisms keeps existing IMAP=
/SMTP
> SASL methods;
>  - configured custom SASL mechanism loads and authe=
nticates 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 wor=
ks for continuation;
>  - exchange cleanup is covered=2E
>
> *Feedback requ=
ested*
> ------------------
>
> Does this refactoring direction look reason=
able to you? Feedback and
> discussion are welcome!
> Meanwhile, I would st=
art POC work on my side to see how this design goes=2E=2E=2E
>
> Regards,
>=
 Quan
>
>

---=Part.595.6aa5647b1a752c3e.19eeed5419e.eefae479d3e859ed=---