Hello

First time writing, so a quick introduction - for many years I was working
(among others) on Hawtio console (since it was based on Angular.js 1.2) and
after I implemented its OIDC Login module and after it was used in Artemis
Console I was more and more involved with Artemis.

1. == Bringing Hawtio's OIDC Login module to Artemis

in Hawtio, the JAAS LoginModule implementation depends on few Hawtio
classes and the configuration is in special hawtio-oidc.properties (as we
need browser-related configuration there as well).
For Artemis, I've implemented the login module fully configurable using
etc/login.config

2. == Artemis OIDC LoginModule features

ARTEMIS-5200 is implemented and PR is green
https://github.com/apache/artemis/pull/6304 and here's a quick list of
features:
 - handling signed JWT tokens using one library -
com.nimbusds:nimbus-jose-jwt
 - handling claim verification (mandatory claims, expiration, required
audience)
 - caching public keys from OIDC Provider key endpoints (EC and RSA, no
Hmac support)
 - configurable token "paths" to retrieve user "identities" (like "sub" or
"preferred_username") and "roles" (like "realm_access.roles" from Keycloak)
 - cnf/x5t#256 certificate "proof of possession" from RFC 8705

I've also added quite extensive test suite.

Note: ActiveMQ "classic" has similar feature:
https://github.com/apache/activemq/issues/1737 but with less flexible
configuration.

3. == Passing JWT in messaging protocols

AMQP has SASL frames (but limited to 512 bytes in spec - has to be
explicitly configured to support larger "initial frames") where a token can
be passed and there are two SASL mechanisms dedicated for this:
 - XOAUTH2 - marked as OBSOLETE at
https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml,
originated from gmail, but supported
by org.apache.qpid.jms.sasl.XOauth2MechanismFactory
 - OAUTHBEARER - RFC 7628, handled by Kafka for example, but not used in
qpid-jms or proton-j2

I've added XOAUTH2 and OAUTHBEARER as implementations
of org.apache.activemq.artemis.protocol.amqp.sasl.ServerSASL and checked
some simple qpid-jms example which gets a token and sends as JMS password.

MQTT mentions (5.x: "4.12 Enhanced authentication"):
> While these fields are named for a simple password authentication, they
can be used to carry other forms of authentication such as passing a token
as the Password.
but I didn't touch MQTT yet

4. == Now the high-level aspect of "JWT Authentication"

I don't think there's anything to do at JMS API side - I assume that
"username" and "password" arguments to
`jakarta.jms.ConnectionFactory#createConnection()` needs to bend to
password=token interpretation.

But things get interesting in two places and related to short (whether 5
minutes or few days) validity of JWT tokens) - and I didn't implement
anything final:

4.1. === JMS Connection pool handling at client side

When creating a connection pool with underlying factory
(like org.apache.qpid.jms.JmsConnectionFactory which has "passowrd override
extension") the pooled object (JMS Connection) should be "associated" with
the JWT token (its credentials).
commons-pool2 (used in pooled-jms) should be configured to
set org.messaginghub.pooled.jms.pool.PooledConnection#hasExpired when the
related token has expired.
I'm just experimenting on that.

4.2. === AMQP connection expiration at server side

Even if the client-side pool can expire connections, there should be a
server side expiration too
(org.apache.qpid.proton.amqp.messaging.TerminusExpiryPolicy?) I still don't
know how to approach this and I'd appreciate any comments.

5. == Summary

I keep working on ARTEMIS-5200, but please check if I'm not going too far
with that.

kind regards
Grzegorz Grzybek

Reply via email to