Les sources d'utilisateurs et la reprise des comptes

Fédération LDAP et Active Directory, User Storage SPI, migration au fil de l'eau, import d'empreintes de mots de passe, identity brokering et doublons : choisir une stratégie par source de vérité.

Keycloak essentiel Cours 7 sur 17 de Keycloak Academy 40 min 5 questions de quiz Cours suivant : Les parcours d'authentification et le MFA

Sur cette page
  1. Cinq façons d’avoir des utilisateurs dans un realm
  2. Fédération LDAP et Active Directory
  3. User Storage SPI et migration au fil de l’eau
  4. Importer des comptes avec leurs empreintes
  5. Identity brokering
  6. Doublons et rapprochement de comptes
  7. Le tableau des sources de vérité
  8. Natif, extension ou hébergeur
  9. Quiz

Avant de choisir un parcours d’authentification, il faut savoir d’où viennent les comptes. Keycloak peut être lui-même la base des comptes, s’appuyer sur un annuaire existant, lire une base applicative ou déléguer l’authentification à un fournisseur d’identité externe. Chaque option a un coût et des limites, et une même architecture combine souvent plusieurs d’entre elles. Ce cours vous donne de quoi remplir, pour chaque population et chaque application, la colonne « source de vérité ».

Cinq façons d’avoir des utilisateurs dans un realm

StratégieOù vit le compteOù est vérifié le mot de passeNativeCas typique
Comptes locauxbase KeycloakKeycloakouiusagers en auto-inscription
Fédération LDAP / ADannuaire (copie locale si import)annuaireouiagents d’un annuaire d’entreprise
User Storage SPIbase applicativeselon le providerextensionbase existante qu’on ne peut pas migrer
Reprise (import ou migration au fil de l’eau)base Keycloak après repriseKeycloakimport natif, migration au fil de l’eau en extensiondécommissionnement d’une authentification applicative
Identity brokeringfournisseur externe, compte lié en localfournisseur externeouipartenaires, fédération d’identité nationale

Keycloak cherche toujours un utilisateur d’abord dans sa base locale, puis dans les providers de fédération par ordre de priorité. Si un provider de priorité haute est en panne, la recherche échoue sans basculer sur le suivant. La documentation recommande donc de garder un compte d’administration local, utilisable si l’annuaire est injoignable.

Fédération LDAP et Active Directory

Le provider LDAP se déclare dans User Federation. Trois choix structurent son comportement.

Avec ou sans import. Avec Import Users activé, Keycloak crée une copie locale de chaque utilisateur à sa première apparition (connexion ou recherche). Il peut alors stocker ses propres données : credentials OTP ou WebAuthn, required actions, attributs non mappés. Sans import, l’annuaire est la seule source, et la documentation précise qu’on ne peut plus enregistrer côté Keycloak que les données mappées vers l’annuaire. Les fonctions qui demandent un stockage local peuvent alors ne pas fonctionner : vérifiez en particulier le comportement des facteurs MFA avant de retenir ce mode.

Dans les deux cas, Keycloak n’importe jamais les mots de passe : la vérification se fait toujours par un bind sur l’annuaire.

Le mode d’édition.

ModeModification des attributs mappésChangement de mot de passeUsage
READ_ONLYrefuséerefusél’annuaire reste maître, Keycloak consomme
WRITABLEécrite dans l’annuaireécrit dans l’annuaireKeycloak devient un point de gestion de l’annuaire
UNSYNCEDstockée en local seulementstocké en localannuaire en lecture seule, mais besoin de modifier côté Keycloak

Le mode se choisit à la création : les mappers par défaut sont générés selon lui et ne sont pas recalculés si on le change ensuite.

La synchronisation. Les utilisateurs importés se synchronisent à la demande ou par tâche périodique, complète (tous les utilisateurs) ou différentielle (modifiés depuis la dernière synchronisation). La pratique recommandée : une synchronisation complète à la création, puis une synchronisation périodique des changements.

kcadm.sh create "user-storage/$LDAP_ID/sync?action=triggerFullSync" -r academy
kcadm.sh create "user-storage/$LDAP_ID/sync?action=triggerChangedUsersSync" -r academy

Les mappers traduisent l’annuaire vers le modèle Keycloak : attribut utilisateur (mail vers email), nom complet, valeur fixe, group-ldap-mapper (groupes de l’annuaire vers groupes Keycloak), role-ldap-mapper (groupes vers rôles), et pour Active Directory le mapper qui lit userAccountControl (compte désactivé, mot de passe expiré).

Deux nouveautés récentes de la branche 26 concernent Active Directory et les politiques de mots de passe de l’annuaire : les utilisateurs créés dans AD par Keycloak sont activés par défaut (26.1), et une option permet de forcer le changement de mot de passe quand l’annuaire l’exige (26.6). La version déployée détermine donc ce qui est disponible.

User Storage SPI et migration au fil de l’eau

Le User Storage SPI permet d’écrire un provider Java qui présente une base existante (souvent la table des comptes d’une application) comme une source d’utilisateurs. Le provider implémente la recherche d’utilisateurs, la validation des credentials et, s’il le faut, l’écriture. Il peut fonctionner avec ou sans import local, comme le provider LDAP.

La migration au fil de l’eau est un usage particulier de ce SPI :

  1. l’usager se connecte, Keycloak ne le trouve pas en local ;
  2. le provider le cherche dans l’ancien système et valide le mot de passe saisi (par lecture de l’empreinte ou par appel d’une API de l’ancien système) ;
  3. en cas de succès, le provider crée le compte local avec le mot de passe saisi, haché par Keycloak, et coupe le lien avec l’ancien système ;
  4. les connexions suivantes ne sollicitent plus l’ancien système.

Ce mécanisme évite de connaître le format des empreintes et d’imposer une réinitialisation. Ses contreparties : du code à maintenir, un ancien système qui doit rester joignable pendant toute la période, et des comptes inactifs qui ne migrent jamais. Il faut donc prévoir une date de fin et le sort des comptes restants (import, réinitialisation, suppression).

Importer des comptes avec leurs empreintes

Keycloak 26 lit nativement ces algorithmes : argon2 (défaut hors FIPS depuis la 25), pbkdf2-sha512 (défaut en mode FIPS), pbkdf2-sha256 et pbkdf2 (SHA-1, déprécié). Un compte importé avec une empreinte dans l’un de ces formats peut se connecter immédiatement. À la connexion suivante, si l’algorithme ou le nombre d’itérations diffère de la politique du realm, Keycloak recalcule l’empreinte.

Le credential est décrit par deux chaînes JSON. Exemple pour PBKDF2-SHA256 :

{
  "username": "lucie",
  "email": "lucie@example.org",
  "enabled": true,
  "emailVerified": true,
  "credentials": [
    {
      "type": "password",
      "secretData": "{\"value\":\"Gq8Z...base64...==\",\"salt\":\"q1w2e3...base64==\",\"additionalParameters\":{}}",
      "credentialData": "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
    }
  ]
}

Pour Argon2, credentialData porte en plus les paramètres de l’algorithme dans additionalParameters (type, version, mémoire, parallélisme, longueur). Le plus sûr est de copier la structure d’un credential Argon2 créé par Keycloak lui-même, visible avec kcadm.sh get users/ID/credentials.

L’import se fait par l’API d’import partiel (pour quelques milliers de comptes), par kc.sh import au démarrage pour de gros volumes, ou par la création d’utilisateurs via l’API d’administration.

Tout autre format (bcrypt, scrypt, MD5 ou SHA salé, hachage maison) demande un PasswordHashProvider spécifique. C’est une extension simple, mais elle doit rester déployée tant qu’il reste des empreintes dans ce format.

Identity brokering

Un identity provider déclaré dans le realm délègue l’authentification à un fournisseur externe : OIDC, SAML 2.0, ou réseaux sociaux. Keycloak reste le fournisseur des applications : elles ne voient que les jetons de Keycloak.

À la première connexion via un fournisseur, le flux first broker login s’exécute. Par défaut :

  1. Review Profile affiche les informations reçues, si elles sont incomplètes ou si le réglage l’impose ;
  2. Create User If Unique crée le compte local s’il n’existe aucun compte avec le même e-mail ou nom d’utilisateur ;
  3. sinon, Confirm Link Existing Account propose de lier, puis Verify Existing Account by Email ou by Re-authentication demande la preuve que l’usager possède le compte existant.

Le compte local est ensuite lié au compte externe. L’usager voit ses liaisons dans la console de compte (Comptes liés) et l’administrateur peut en créer par l’API. Les mappers d’IdP importent des claims en attributs, rôles ou groupes, et le sync mode décide si ces données sont mises à jour à chaque connexion (force) ou seulement à la création (import).

D’autres réglages pèsent en architecture : Trust Email (considérer l’e-mail reçu comme vérifié), le flux Post Login (par exemple exiger un facteur supplémentaire après le fournisseur externe), et le paramètre kc_idp_hint qui permet à une application d’envoyer directement l’usager vers un fournisseur.

Doublons et rapprochement de comptes

L’e-mail sert souvent d’identifiant. Trois réglages du realm (onglet Login) l’encadrent :

  • Email as username : l’e-mail devient le nom d’utilisateur ;
  • Login with email : l’usager peut saisir son e-mail ou son nom d’utilisateur ;
  • Duplicate emails : autorise plusieurs comptes avec le même e-mail. Ce réglage est incompatible avec la connexion par e-mail et rend le rapprochement par e-mail du brokering ambigu.

Sources de doublons à anticiper : un agent présent dans l’annuaire et dans une base applicative, un usager qui a créé deux comptes avec deux e-mails, un partenaire qui arrive par un fournisseur externe alors qu’il avait un compte local. Le rapprochement natif se fait sur l’e-mail ou le nom d’utilisateur. Un rapprochement sur une autre clé (matricule, numéro de dossier) demande un authenticator spécifique dans le flux first broker login, ou un traitement en amont de la reprise.

Le tableau des sources de vérité

Pour chaque population, et pour chaque application qui porte ses propres comptes, remplissez une ligne :

QuestionFédérationImport d’empreintesMigration au fil de l’eauBrokering
La source reste-t-elle maître ?ouinon, Keycloak devient maîtrenon, à termeoui, pour l’authentification
Format d’empreinte à connaître ?nonouinonnon
Ancien système requis ensuite ?oui, en permanencenonoui, pendant la périodeoui, en permanence
Développementaucunaucun si PBKDF2 ou Argon2provider Javaaucun en général
RéseauKeycloak doit joindre l’annuaireaucunKeycloak doit joindre l’ancien systèmenavigateur et Keycloak joignent le fournisseur

Restent les cas non prévus, à recenser explicitement : comptes partagés ou génériques, comptes de service applicatifs, applications qui créent elles-mêmes leurs comptes (via l’API d’administration ou, dans les versions récentes de la branche 26, l’API SCIM), comptes sans e-mail.

Fédérer l'OpenLDAP de test et importer des empreintes

35 min

Installer le lab
  1. Depuis keycloak-academy-lab/, préparez kcadm et créez le realm academy s’il n’existe pas.
kcadm() { docker compose exec -T keycloak /opt/keycloak/bin/kcadm.sh "$@"; }
kcadm config credentials --server http://localhost:8080 --realm master --user admin --password admin
kcadm create realms -s realm=academy -s enabled=true
  1. Déclarez le provider LDAP en lecture seule avec import. L’URL est celle vue depuis le conteneur Keycloak (service openldap), pas localhost.
LDAP_ID=$(kcadm create components -r academy -s name=annuaire-academy -s providerId=ldap \
  -s providerType=org.keycloak.storage.UserStorageProvider \
  -s 'config.enabled=["true"]' -s 'config.vendor=["other"]' \
  -s 'config.connectionUrl=["ldap://openldap:389"]' \
  -s 'config.bindDn=["cn=admin,dc=academy,dc=local"]' -s 'config.bindCredential=["admin"]' \
  -s 'config.usersDn=["ou=people,dc=academy,dc=local"]' \
  -s 'config.usernameLDAPAttribute=["uid"]' -s 'config.rdnLDAPAttribute=["uid"]' \
  -s 'config.uuidLDAPAttribute=["entryUUID"]' -s 'config.userObjectClasses=["inetOrgPerson"]' \
  -s 'config.editMode=["READ_ONLY"]' -s 'config.importEnabled=["true"]' \
  -s 'config.searchScope=["1"]' -s 'config.authType=["simple"]' -i)
kcadm get components -r academy -q parent=$LDAP_ID --fields name,providerId
  1. Ajoutez un mapper de groupes vers ou=groups (groupes groupOfNames, appartenance par l’attribut member).
MAPPER_ID=$(kcadm create components -r academy -s name=groupes-ldap -s providerId=group-ldap-mapper \
  -s providerType=org.keycloak.storage.ldap.mappers.LDAPStorageMapper -s parentId=$LDAP_ID \
  -s 'config."groups.dn"=["ou=groups,dc=academy,dc=local"]' \
  -s 'config."group.name.ldap.attribute"=["cn"]' -s 'config."group.object.classes"=["groupOfNames"]' \
  -s 'config."membership.ldap.attribute"=["member"]' -s 'config."membership.attribute.type"=["DN"]' \
  -s 'config."membership.user.ldap.attribute"=["uid"]' -s 'config.mode=["READ_ONLY"]' \
  -s 'config."user.roles.retrieve.strategy"=["LOAD_GROUPS_BY_MEMBER_ATTRIBUTE"]' \
  -s 'config."preserve.group.inheritance"=["false"]' -i)
  1. Lancez les synchronisations et vérifiez : cinq utilisateurs importés (alice à emma) avec un federationLink, et les groupes agents et administrateurs.
kcadm create "user-storage/$LDAP_ID/sync?action=triggerFullSync" -r academy -o
kcadm create "user-storage/$LDAP_ID/mappers/$MAPPER_ID/sync?direction=fedToKeycloak" -r academy -o
kcadm get users -r academy --fields username,federationLink
kcadm get groups -r academy --fields name
  1. Constatez le mode READ_ONLY : la modification est refusée avec error-user-attribute-read-only.
ALICE=$(kcadm get users -r academy -q username=alice -q exact=true --fields id --format csv --noquotes)
kcadm update users/$ALICE -r academy -s lastName=Autre
  1. Connectez-vous à http://localhost:8080/realms/academy/account avec alice et le mot de passe de l’annuaire (password). Le mot de passe est vérifié par l’annuaire. Dans Informations personnelles, essayez de modifier votre nom : en READ_ONLY, la modification ne doit pas être possible.
  2. Générez un fichier de reprise avec deux comptes et des empreintes PBKDF2-SHA256 (27 500 itérations), comme les produirait un ancien système.
python3 - <<'EOF'
import base64, hashlib, json, os
def compte(nom):
    sel = os.urandom(16)
    h = hashlib.pbkdf2_hmac("sha256", b"Reprise2026!", sel, 27500, 64)
    secret = {"value": base64.b64encode(h).decode(), "salt": base64.b64encode(sel).decode(), "additionalParameters": {}}
    data = {"hashIterations": 27500, "algorithm": "pbkdf2-sha256", "additionalParameters": {}}
    return {"username": nom, "email": f"{nom}@example.org", "firstName": nom.capitalize(), "lastName": "Reprise",
            "enabled": True, "emailVerified": True,
            "credentials": [{"type": "password", "secretData": json.dumps(secret), "credentialData": json.dumps(data)}]}
json.dump({"ifResourceExists": "SKIP", "users": [compte("lucie"), compte("marc")]}, open("reprise.json", "w"), indent=2)
EOF
kcadm create partialImport -r academy -f - -o < reprise.json
  1. Connectez-vous à la console de compte avec lucie / Reprise2026! : la connexion réussit sans réinitialisation.
  2. Relisez le credential de lucie : l’empreinte a été recalculée en argon2 à la connexion, selon l’algorithme par défaut du realm.
LUCIE=$(kcadm get users -r academy -q username=lucie --fields id --format csv --noquotes)
kcadm get users/$LUCIE/credentials -r academy --fields credentialData

Natif, extension ou hébergeur

Natif : fourni par Keycloak, à configurer. Extension : demande du code à maintenir (un SPI, le mécanisme de plugin de Keycloak). Hébergeur : dépend de la plateforme qui héberge Keycloak, à vérifier avec elle.

CapacitéVerdictPrécision
Fédération LDAP et Active Directory (import, modes d'édition, synchronisation, mappers)NatifProvider LDAP fourni, avec mappers d'attributs, de groupes, de rôles et spécifiques à Active Directory.
Annuaire joignable uniquement depuis un réseau interneHébergeurKeycloak doit ouvrir la connexion LDAP. Chez un hébergeur, cela suppose un tunnel ou un agent : modalités à vérifier avec lui.
Base de données applicative comme source d'utilisateursExtensionUser Storage SPI : un provider Java qui lit (et éventuellement écrit) les comptes dans la base existante.
Migration au fil de l'eau (reprise du compte à la première connexion réussie)ExtensionConstruite sur le User Storage SPI : valider le mot de passe auprès de l'ancien système puis créer le compte local.
Import d'empreintes PBKDF2 (SHA-1, SHA-256, SHA-512) et Argon2NatifFormats lus nativement à l'import ; l'empreinte est recalculée avec l'algorithme du realm à la connexion suivante.
Import d'empreintes bcrypt, scrypt, SHA salé ou hachage maisonExtensionDemande un PasswordHashProvider spécifique (des implémentations communautaires existent pour bcrypt).
Identity brokering OIDC et SAML, first broker login, liaison de comptesNatifFlux first broker login configurable par fournisseur, mappers d'IdP, liaison depuis la console de compte.
Rapprochement automatique de comptes selon une règle métier (matricule, date de naissance)ExtensionLe rapprochement natif se fait sur l'e-mail ou le nom d'utilisateur ; une autre clé demande un authenticator spécifique.

Vérifier ce que vous avez retenu

5 questions

  1. L'annuaire des agents est la source de vérité et ne doit jamais être modifié par Keycloak, mais vous voulez stocker l'OTP des agents. Quelle configuration retenir ?

  2. Une application historique stocke ses mots de passe en bcrypt. L'objectif est de ne pas imposer de réinitialisation. Quelles options sont réalistes ?

  3. Un fournisseur d'identité externe renvoie un e-mail qui existe déjà dans le realm. Que fait le flux first broker login par défaut ?

  4. Vous fédérez deux annuaires dans le même realm et un identifiant existe dans les deux. Quel est le risque ?

  5. Quelle question du questionnaire applicatif départage le mieux import d'empreintes et migration au fil de l'eau ?