[
https://issues.apache.org/jira/browse/JAMES-4210?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Benoit Tellier closed JAMES-4210.
---------------------------------
Resolution: Fixed
> Generic SASL mechanism extension model for James protocols
> ----------------------------------------------------------
>
> Key: JAMES-4210
> URL: https://issues.apache.org/jira/browse/JAMES-4210
> Project: James Server
> Issue Type: Improvement
> Components: IMAPServer, POP3Server, sieve, SMTPServer
> Affects Versions: 3.10
> Reporter: Tran Hong Quan
> Priority: Major
> Time Spent: 17h 10m
> Remaining Estimate: 0h
>
> 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
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]