Repository navigation
Conversation
15c6f4b to
de32ac9
Compare
de32ac9 to
65c1988
Compare
65c1988 to
d86be1d
Compare
Lets a device authenticate with its client certificate instead of a username and password. ActiveMQORSecurityManager takes the leaf of the chain presented on the connection - the only certificate the handshake proves the client holds the key for - requires it to carry the Client Authentication extended key usage, and derives the identity from its subject: CN is the service user, OU is the realm. An explicit username still wins over the OU when it names an existing realm, which is how a device whose certificate carries no OU says where it belongs. The service user is then looked up within that realm, since service user names are only unique within one, trying the auto-provisioning prefix before the bare CN so that both provisioned devices and hand-made service users can present a certificate. Its secret completes the normal token exchange, so authorisation is unchanged downstream. A connection presenting no certificate, or one whose CN matches no service user, is left anonymous rather than rejected, preserving existing behaviour for plain MQTT clients. A certificate that is not a client certificate at all is refused. getSubjectOU joins getSubjectCN in ProvisioningUtil since certificate-derived identity is now needed outside provisioning; both parse the subject as an RFC 2253 LDAP name rather than by string splitting.
d86be1d to
018677f
Compare
|
richturner
left a comment
There was a problem hiding this comment.
Two concerns with how a certificate is mapped to an identity in ActiveMQORSecurityManager.authenticate:
1. The connect username can override the authenticated OU
if (!TextUtil.isNullOrEmpty(originalUsername)
&& identityProvider.realmExists(originalUsername)) {
realm = originalUsername;
}The OU was verified in the handshake, but the username field is unauthenticated client input. A device whose certificate says CN=device1, OU=realmA can connect with username realmB and log in as the service user device1 in realmB, if one exists. I'd only use the username when the certificate has no OU. Better still, don't let the client pick the realm at all (see 2).
2. The realm isn't tied to the CA that issued the certificate
Login trusts any certificate that chains to the acceptor's single, broker-wide truststore, then maps its CN to any service user in the claimed realm. That includes hand-made service users through the bare-CN fallback. So a CA trusted to issue certificates for one realm's devices can authenticate as service users in any realm, including ones that were never provisioned from a certificate. #3204 checks the OU against the config realm, but only during provisioning, not at login.
Suggestions:
- Scope login the same way provisioning is scoped: find the provisioning config whose CA signed the leaf (
getMatchingX509ProvisioningConfigalready does this), and take the realm from that config instead of the OU or username. Reject the connection when the two disagree. - Only map to
PROVISIONING_USER_PREFIXservice users, or make the bare-CN fallback something each realm opts into. That way certificate login can't reach accounts that were created for password or secret auth.



Description
Lets a device authenticate with its client certificate instead of a username and password.
Artemis has already validated the chain against the truststore by the time
ActiveMQORSecurityManagerruns, so nothing is verified here — the job is mapping an accepted certificate onto a Keycloak service user. Identity comes from the first certificate in the chain, the only one the handshake proves the client holds the key for: CN is the service user, OU is the realm, and an explicit connect username wins over the OU when it names an existing realm.The service user is looked up within that realm (names are only unique within one), trying the auto-provisioning prefix before the bare CN so both provisioned devices and hand-made service users work. Its secret completes the normal token exchange, so authorisation downstream is unchanged.
Connections with no certificate are untouched; one whose CN matches no service user stays anonymous rather than being rejected, which is what lets an unprovisioned device reach the provisioning topic in the next PR.
How to verify
MqttBrokerTest."Mqtt broker mTLS test"covers a certificate belonging to an existing service user, one not signed by the CA, and a signed one with no service user.Checklist