keycloak : federation LDAP en WRITABLE, et reconciliee
Le changement de mot de passe imposé echouait sur « Federated storage is not writable » : `editMode=READ_ONLY` etait code en dur. Keycloak lisait l'annuaire sans pouvoir y ecrire — `pwdReset` devenait un cul-de-sac, LDAP exigeant un changement que Keycloak ne pouvait pas faire. Trois modes, un seul tient avec la doctrine. `UNSYNCED` ferait ecrire Keycloak dans SA base : Dovecot et Postfix, qui se lient directement a LDAP (D-39), valideraient encore l'ancien mot de passe. Ca aurait « marche » a l'ecran en cassant le courriel en silence. `WRITABLE` ecrit A TRAVERS : l'annuaire reste la source unique, Keycloak n'en est qu'un client. Le mode devient une variable et il est RECONCILIE : un provider cree en READ_ONLY le serait reste a vie. Deux fautes de ma part au passage : extraction ancree sur `$` alors que la ligne finit par un guillemet, et pas de `|| true` — sous `pipefail`, un grep vide tue le script. Masque par `no_log`, pour la troisieme fois aujourd'hui. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
c21ed62237
commit
71ed179b0c
3 changed files with 54 additions and 3 deletions
27
CHANGELOG.md
27
CHANGELOG.md
|
|
@ -2,6 +2,33 @@
|
||||||
|
|
||||||
## 2026-08-06 — le chemin nord-sud devient dérivable
|
## 2026-08-06 — le chemin nord-sud devient dérivable
|
||||||
|
|
||||||
|
### « Federated storage is not writable » — la fédération était en lecture seule
|
||||||
|
|
||||||
|
Le changement de mot de passe imposé échouait : `editMode=READ_ONLY` était **codé en dur**
|
||||||
|
dans `federation-ldap.yml`. Keycloak lisait l'annuaire sans jamais pouvoir y écrire — donc
|
||||||
|
`pwdReset` était un cul-de-sac : LDAP *exige* le changement, et Keycloak *ne peut pas* le
|
||||||
|
faire.
|
||||||
|
|
||||||
|
**Trois modes, un seul tient avec la doctrine :**
|
||||||
|
|
||||||
|
| Mode | Effet | Verdict |
|
||||||
|
|---|---|---|
|
||||||
|
| `READ_ONLY` | Keycloak n'écrit jamais | le changement de mot de passe est impossible |
|
||||||
|
| `UNSYNCED` | Keycloak écrit dans **sa** base | Dovecot et Postfix, qui se lient directement à LDAP (D-39), valideraient encore l'ancien — une identité, deux mots de passe |
|
||||||
|
| `WRITABLE` | Keycloak écrit **à travers** vers LDAP | l'annuaire reste la source unique ; Keycloak n'en est qu'un client |
|
||||||
|
|
||||||
|
`UNSYNCED` aurait « marché » à l'écran tout en cassant le courriel en silence. C'est le piège
|
||||||
|
qu'il fallait éviter.
|
||||||
|
|
||||||
|
Le mode devient une variable, et il est **réconcilié** — comme l'URL depuis hier. Un provider
|
||||||
|
créé en `READ_ONLY` le serait resté à vie.
|
||||||
|
|
||||||
|
**Deux fautes de ma part dans le même correctif.** Mon extraction du mode actuel s'ancrait sur
|
||||||
|
`$` alors que la ligne finit par un guillemet : elle ne correspondait jamais. Et sans `|| true`,
|
||||||
|
un `grep` sans correspondance tue le script entier sous `pipefail`. La tâche échouait — masquée
|
||||||
|
par `no_log`, pour la troisième fois aujourd'hui.
|
||||||
|
|
||||||
|
|
||||||
### « invalid username or password » — c'était la porte, pas le mot de passe
|
### « invalid username or password » — c'était la porte, pas le mot de passe
|
||||||
|
|
||||||
Première tentative de connexion du sysadmin : refusée. Ni le jeton ni le compte n'étaient en
|
Première tentative de connexion du sysadmin : refusée. Ni le jeton ni le compte n'étaient en
|
||||||
|
|
|
||||||
|
|
@ -95,3 +95,20 @@ serveur_keycloak_groupes_roles: []
|
||||||
# jamais les services : Forgejo et Nextcloud liraient un claim vide.
|
# jamais les services : Forgejo et Nextcloud liraient un claim vide.
|
||||||
serveur_keycloak_groupes_claim: "groups"
|
serveur_keycloak_groupes_claim: "groups"
|
||||||
serveur_keycloak_groupes_mapper_clients: []
|
serveur_keycloak_groupes_mapper_clients: []
|
||||||
|
|
||||||
|
# Mode d'ecriture de la federation LDAP. TROIS valeurs possibles, et une seule tient
|
||||||
|
# avec la doctrine :
|
||||||
|
#
|
||||||
|
# READ_ONLY Keycloak lit, n'ecrit jamais. Un changement de mot de passe echoue sur
|
||||||
|
# « Federated storage is not writable » — donc `pwdReset` est un cul-de-sac :
|
||||||
|
# l'annuaire EXIGE le changement, et Keycloak ne peut pas le faire.
|
||||||
|
# UNSYNCED Keycloak ecrit dans SA base. Le mot de passe ne serait plus dans LDAP :
|
||||||
|
# Dovecot et Postfix, qui s'y lient DIRECTEMENT (D-39), continueraient de
|
||||||
|
# valider l'ancien. Une identite, deux mots de passe — exactement ce que la
|
||||||
|
# doctrine interdit.
|
||||||
|
# WRITABLE Keycloak ecrit A TRAVERS vers LDAP. L'annuaire reste la source unique ;
|
||||||
|
# Keycloak n'en est qu'un client. C'est le seul mode coherent.
|
||||||
|
#
|
||||||
|
# Constate le 2026-08-07 : READ_ONLY etait code en dur, et la premiere reprise du
|
||||||
|
# sysadmin butait dessus.
|
||||||
|
serveur_keycloak_ldap_edit_mode: "WRITABLE"
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,18 @@
|
||||||
if [ -n "$FEDID" ]; then
|
if [ -n "$FEDID" ]; then
|
||||||
URL_ACTUELLE=$("$KC" get components/"$FEDID" -r {{ serveur_keycloak_realm }} 2>/dev/null \
|
URL_ACTUELLE=$("$KC" get components/"$FEDID" -r {{ serveur_keycloak_realm }} 2>/dev/null \
|
||||||
| grep -o '"connectionUrl" : \[ "[^"]*"' | grep -o 'ldaps\?://[^"]*' | head -1)
|
| grep -o '"connectionUrl" : \[ "[^"]*"' | grep -o 'ldaps\?://[^"]*' | head -1)
|
||||||
if [ "$URL_ACTUELLE" != "{{ serveur_keycloak_ldap_url }}" ]; then
|
# `|| true` en fin de chaine : avec `pipefail`, un grep sans correspondance
|
||||||
|
# tuerait le script entier. Et l'extraction ne s'ancre pas sur `$` — la ligne
|
||||||
|
# se termine par un guillemet, pas par la valeur.
|
||||||
|
MODE_ACTUEL=$("$KC" get components/"$FEDID" -r {{ serveur_keycloak_realm }} 2>/dev/null \
|
||||||
|
| sed -n 's/.*"editMode" : \[ "\([A-Z_]*\)".*/\1/p' | head -1 || true)
|
||||||
|
if [ "$URL_ACTUELLE" != "{{ serveur_keycloak_ldap_url }}" ] \
|
||||||
|
|| [ "$MODE_ACTUEL" != "{{ serveur_keycloak_ldap_edit_mode }}" ]; then
|
||||||
"$KC" update components/"$FEDID" -r {{ serveur_keycloak_realm }} \
|
"$KC" update components/"$FEDID" -r {{ serveur_keycloak_realm }} \
|
||||||
-s 'config.connectionUrl=["{{ serveur_keycloak_ldap_url }}"]' \
|
-s 'config.connectionUrl=["{{ serveur_keycloak_ldap_url }}"]' \
|
||||||
-s 'config.usersDn=["{{ serveur_keycloak_ldap_users_dn }}"]' \
|
-s 'config.usersDn=["{{ serveur_keycloak_ldap_users_dn }}"]' \
|
||||||
-s 'config.bindDn=["{{ serveur_keycloak_ldap_bind_dn }}"]' >/dev/null
|
-s 'config.bindDn=["{{ serveur_keycloak_ldap_bind_dn }}"]' \
|
||||||
|
-s 'config.editMode=["{{ serveur_keycloak_ldap_edit_mode }}"]' >/dev/null
|
||||||
CHANGED=1
|
CHANGED=1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
@ -53,7 +60,7 @@
|
||||||
-s providerType=org.keycloak.storage.UserStorageProvider -s parentId="$RID" \
|
-s providerType=org.keycloak.storage.UserStorageProvider -s parentId="$RID" \
|
||||||
-s 'config.enabled=["true"]' \
|
-s 'config.enabled=["true"]' \
|
||||||
-s 'config.vendor=["other"]' \
|
-s 'config.vendor=["other"]' \
|
||||||
-s 'config.editMode=["READ_ONLY"]' \
|
-s 'config.editMode=["{{ serveur_keycloak_ldap_edit_mode }}"]' \
|
||||||
-s 'config.importEnabled=["true"]' \
|
-s 'config.importEnabled=["true"]' \
|
||||||
-s 'config.connectionUrl=["{{ serveur_keycloak_ldap_url }}"]' \
|
-s 'config.connectionUrl=["{{ serveur_keycloak_ldap_url }}"]' \
|
||||||
-s 'config.usersDn=["{{ serveur_keycloak_ldap_users_dn }}"]' \
|
-s 'config.usersDn=["{{ serveur_keycloak_ldap_users_dn }}"]' \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue