opdt / keycloak-cassandra-extension

Keycloak-DatastoreProvider storing data in an Apache Cassandra NoSQL-database.
Apache License 2.0
17 stars 5 forks source link
keycloak keycloak-spi storage

CI Maven Central Sonarcloud

Cassandra storage extension for Keycloak

Uses Apache Cassandra to store and retrieve entities of all storage areas except authorization and events. Requires Keycloak >= 25.0.0 (older versions may be supported by older versions of this extension).

How to use

:warning: Important information: Since map storage has been removed from Keycloak, using different storage providers for different storage areas (like users, roles) requires you to implement your own DatastoreProvider. If "cache mode" is active (KC_COMMUNITY_DATASTORE_CASSANDRA_CACHE_ENABLED=true), default providers (jpa) are used for non-cache areas.

The following parameters might be needed in addition to the configuration options of this extension (see below):

CLI-Parameter Description
--features-disabled=authorization Disable authorization (this is essential as otherwise Keycloak tries to use InfinispanStoreFactory at a lot of places)
--spi-connections-jpa-legacy-enabled=false Deactivate automatic JPA schema migration

Configuration options

CLI-Parameter Description
--spi-cassandra-connection-default-port Cassandra CQL-Port
--spi-cassandra-connection-default-contact-points Comma-separated list of cassandra node-endpoints
--spi-cassandra-connection-default-local-datacenter Local datacenter name
--spi-cassandra-connection-default-username Username
--spi-cassandra-connection-default-password Password
--spi-cassandra-connection-default-keyspace Keyspace-name (will be generated by the extension if it does not exist at startup-time)
--spi-cassandra-connection-default-replication-factor Replication factor used if the extension creates the keyspace with simple strategy

Deviations from standard storage providers

User Lookup

Due to Cassandras query first nature, users can only be looked up by specific fields. UserProvider::searchForUserStream supports the following subset of Keycloaks standard search attributes:

UserProvider::searchForUserByUserAttributeStream by default iterates all users in the entire database to filter for the requested attribute in-memory. For efficient searches, attributes can be defined as indexed attributes by prefixing their name with indexed., e.g. indexed.businessKey

Conditional updates / optimistic locking

All write-queries are done conditionally via Cassandra Lightweight Transactions. Therefore we store a version column in each of the tables. To be able to use this to get notified if a conflicting change occured after data was read, the entityVersion is exposed via a readonly attribute readonly.entityVersion. In order to pass a version in update operations, one can use the corresponding attribute internal.entityVersion.

Uniqueness across username and password

This extension supports additional checks to prevent setting username to a value that is already as email of another user and setting email to a value used as username.

To enable these checks for a realm, set its attribute enableCheckForDuplicatesAcrossUsernameAndEmail to true (default when not set: false)

Multi-Tab Refresh Token Rotation

This extension adds support for a grace period when checking for reuses. It can be set via refreshTokenReuseInterval realm attribute. Refresh token reuses during this grace period are allowed, which can be useful in case of retries / network problems.

Contributing

Before contributing to Keycloak Cassandra, please read our contributing guidelines.

Private image registries

If you use a private image registry, you can use the .testcontainers file in your user directory to override all image-registries used by the tests. See https://www.testcontainers.org/features/image_name_substitution/

Example:

docker.client.strategy=org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy
hub.image.name.prefix=private-registry/3rd-party/

Debugging

Debugging can be enabled via mvn -Dmaven.surefire.debug verify (Port 5005).

Using an external cassandra instance

If you want to use an external cassandra instance on localhost (Port 9042) you can use mvn -Dkeycloak.testsuite.start-cassandra-container=false verify