dasniko / keycloak-cassandra-extension

Keycloak-DatastoreProvider storing data in an Apache Cassandra NoSQL-database.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CI Maven Central Known Vulnerabilities Sonarcloud

Cassandra storage extension for Keycloak

Uses Apache Cassandra to store and retrieve entities of all storage areas except authorization and events. Requires Keycloak 22.0.x with enabled Map-Storage feature.

How to use

Use for caching only (Replace Infinispan)

This extensions enables users to get rid of Infinispan for caching and use Cassandra instead! The benefits are much easier operations and a proven way for multi-site setups, where Cassandra handles all the Cross-DC Synchronizations.

Set KC_SPI_DATASTORE_CASSANDRA_MAP_CACHE_MODE=true (or equivalent keycloak configuration mechanisms) and configure the default map-storage (for example via KC_STORAGE=file) to use this extension for cache areas (authSession, userSession, singleUseObject) only.

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-passwort 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:

  • keycloak.session.realm.users.query.search for a case insensitive username search
  • keycloak.session.realm.users.query.include_service_account to include service accounts
  • email for 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

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)

Development

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

About

Keycloak-DatastoreProvider storing data in an Apache Cassandra NoSQL-database.

License:Apache License 2.0


Languages

Language:Java 99.8%Language:Shell 0.2%