Uses Apache Cassandra to store and retrieve entities of all storage areas except authorization and events. Requires Keycloak >= 26.4.0 (older versions may be supported by older versions of this extension).
- Download the JAR from Maven Central: https://repo1.maven.org/maven2/de/arbeitsagentur/opdt/keycloak-cassandra-extension/xxx/keycloak-cassandra-extension-xxx.jar
- Put the JAR in Keycloak's providers folder
- Set
KC_COMMUNITY_DATASTORE_CASSANDRA_ENABLED=true(kc.community.datastore.cassandra.enabled=trueas system property) orKC_COMMUNITY_DATASTORE_CASSANDRA_CACHE_ENABLED=true(kc.community.datastore.cassandra.cache.enabled=trueas system property) to enable the extension - Set the necessary configuration options like cassandra endpoints (see the overview below)
⚠️ 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 ownDatastoreProvider. 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,admin-fine-grained-authz,organization | Disable unsupported features |
| --spi-connections-jpa-legacy-enabled=false | Deactivate automatic JPA schema migration |
| 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 |
Keycloak Organizations are currently not supported and have to be turned off.
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:
keycloak.session.realm.users.query.searchfor a case insensitive username searchkeycloak.session.realm.users.query.include_service_accountto include service accountsemailfor an email search
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
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.
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)
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.
Keycloak creates a service account user for each client with serviceAccountEnabled set to true.
This extension allows to dynamically assign roles to this service account. This needs to be enabled per role by setting an attribute unattendedServiceAccountAssignment.enabled to true.
It can further be restricted by setting the role attribute unattendedServiceAccountAssignment.clientIdPattern to a regex matching all client-ids where this role can be dynamically assigned.
To assign a role to a service account, a client attribute initialServiceAccountRoles needs to contain a comma-separated list of all role ids to set (which need to have the aforementioned attributes set).
Before contributing to Keycloak Cassandra, please read our contributing guidelines.
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 can be enabled via mvn -Dmaven.surefire.debug verify (Port 5005).
If you want to use an external cassandra instance on localhost (Port 9042) you can
use mvn -Dkeycloak.testsuite.start-cassandra-container=false verify
The official Keycloak implementation now executes a dependsOn() for each provider. Even if it has a lower priority.
This will implicitly initialize the default JPA-Provider.
To circumvent this problem you may want to define a "NullProvider" which overrides the default JPA-Provider.
The Integration Tests require a container runtime. If you encounter the error "Could not find a valid Docker environment", this typically occurs when:
- Docker is not running
- You're using Podman instead of Docker
- The container socket is not accessible
For Podman users: To run the tests with Podman, configure the Docker compatibility socket:
export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/podman/podman.sock
mvn clean verify