User storage provider implementation in Keycloak
Table of Contents
This project showcases a Keycloak User Storage SPI that connects with external relational databases.
By default, Keycloak relies on its internal database to handle user creation, updates, lookups, and credential validation. Developers can implement the User Storage SPI to connect external user databases with Keycloak’s internal user management system.
When Keycloak needs to locate a user, for instance, during a login attempt, it follows a specific process. It first checks the user cache; if the user is found there, it uses that in-memory data. If not, Keycloak searches its local database. If the user is still not located, Keycloak then queries the User Storage SPI provider implementations in sequence until one returns the desired user.
This project will implement the User Storage SPI to connect to an external, pre-populated database. The user model in the external store is composed of the below attributes:
- ID
- Username
- Password
- User Role
- First Name
- Last Name
- Created Date
The provider will read only those attributes; it will be able to look up users by ID, username, role, as well as validate users' passwords. Also, the provider will map the user's role from the external store into a realm role based on the mappings, if any, defined when creating the provider.
Since the external storage cannot accommodate all Keycloak features, such as additional user attributes, group management,
and various credential types, this provider lets you extend your external storage by saving extra information in Keycloak’s
database. For instance, if a user is assigned to a group and the external store does not support group relationships,
Keycloak will store this group assignment in its own federated database relations while maintaining a reference to the
external user ID. Later, if the provider was deleted from the realm, all information related to external users coming
from the provider will be deleted too. This is achieved by overriding methods from AbstractUserAdapterFederatedStorage
that are supported in the external store. Non-overridden methods will be managed in Keycloak's federated database relations,
such as groups assignment, required actions, etc.
When configuring a Keycloak User Storage SPI with an external datasource, you need to specify datasource properties in the quarkus.properties file.
This file is then copied to the conf
directory of the server.
-
quarkus.datasource.user-store.db-kind
: Defines the type of database. -
quarkus.datasource.user-store.username
: Specifies the username for connecting to the external datasource. -
quarkus.datasource.user-store.password
: Specifies the password for connecting to the external datasource. -
quarkus.datasource.user-store.jdbc.url
: Sets the JDBC URL for the external datasource.
A persistence unit defines the configurations that are required when acquiring an entity manager.
The persistence.xml file, which defines the required configurations,
should be located in the META-INF
directory of your provider.
name
: Assign a unique name to your persistence unit.transaction-type
: Set to JTA (Java Transaction API) to use container-managed transactions. You can also set this to RESOURCE_LOCAL if you want to manage transactions manually.<class>
: Define the entity classes that are part of this persistence unit. List all entity classes that should be managed.hibernate.dialect
: Specify the Hibernate dialect for your database. This ensures Hibernate generates SQL compatible with your database.hibernate.connection.datasource
: Provide the name of the datasource. This name should match the datasource configured in quarkus.properties.jakarta.persistence.transactionType
: The transaction type.hibernate.hbm2ddl.auto
: Determines how Hibernate manages schema creation. Common values are none (no automatic schema management), update (update the schema), create (create schema), and create-drop (create and drop schema).hibernate.show_sql
: Set to true to enable SQL logging for debugging purposes. Set to false to disable SQL logging.
Note: You can configure multiple persistence units in the same file. Each persistence unit should have a unique name and can have different settings depending on your needs.
System Requirements:
- JDK 21+
- Apache Maven 3+
- Docker
To package the sources, build the image, and deploy the services:
./start.sh
UI display name
: A name to the provider to be shown in the UI.Persistence Unit Name
: Specifies the name of the persistence unit. The persistence.xml file should already contain the unit name.Role Mappings
: Define role mappings, if any, between external user roles and realm roles. For example, if external users with roleexternal_admin
should have therealm_admin
realm role, then addexternal_admin
:realm_admin
. As a result, when users with roleexternal_admin
from this provider log in, they would have therealm_admin
role.Cache Policy
: Defines the cache policy for this provider. For example, if you expect external users to be changed on a daily basis in the external store, you can consider setting it toEVICT_DAILY
.
- https://www.keycloak.org/docs/latest/server_development/#_user-storage-spi
- https://quarkus.io/guides/hibernate-orm