keycloak : URI de retour apres deconnexion, derivees de web_origins
Nextcloud se connectait et echouait a la deconnexion — « invalid redirect uri ». Keycloak valide ces URI SEPAREMENT des URI de rappel, et aucun des quatre clients ne declarait l'attribut ; Nextcloud etait seulement le seul a en envoyer une. post.logout.redirect.uris derivee de web_origins, qui porte deja l'URL de base du service. Posee par l'API : attributes est une map, et kcadm -s sur une map accepte sans ecrire (meme leçon que smtpServer ce matin). Relu apres ecriture. Le second passage a revele un defaut de l'heure precedente : la tache de journalisation se declarait changed a chaque deploiement — Jinja rendait True et 1209600 en CHAINES, la comparaison au reel ne pouvait aboutir. Compose en une seule expression, types natifs. Deux passages a changed=0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
eef44c2dce
commit
44ee6d4d36
4 changed files with 93 additions and 5 deletions
24
CHANGELOG.md
24
CHANGELOG.md
|
|
@ -1,5 +1,29 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-08-08 — Déconnexion OIDC : Keycloak valide une SECONDE liste d'URI
|
||||
|
||||
Nextcloud se connectait parfaitement et échouait à la déconnexion, sur un
|
||||
« We are sorry… invalid redirect uri » qui ne dit pas de quelle liste il parle.
|
||||
|
||||
Keycloak valide les URI de retour **après déconnexion** séparément des URI de rappel.
|
||||
Aucun des quatre clients ne déclarait l'attribut ; Nextcloud était seulement le seul à
|
||||
envoyer une URI de retour, donc le seul à révéler le trou. Les trois autres l'auraient
|
||||
rencontré dès qu'on leur aurait câblé une déconnexion propre.
|
||||
|
||||
`post.logout.redirect.uris` est désormais **dérivée de `web_origins`**, qui porte déjà
|
||||
l'URL de base de chaque service : la connaissance existait, il n'y avait pas à la
|
||||
réécrire. Posée par l'API et non par `kcadm -s` — `attributes` est une map, et sur une map
|
||||
kcadm accepte la commande, sort en succès et n'écrit rien (mesuré le même jour sur
|
||||
`smtpServer`). Relu après écriture, comme il se doit maintenant.
|
||||
|
||||
**Et le second passage a révélé un défaut dans le travail de l'heure précédente.** La tâche
|
||||
de journalisation se déclarait `changed` à chaque déploiement : écrits champ par champ,
|
||||
Jinja rendait `True` et `1209600` en **chaînes**, et la comparaison au réel (booléen,
|
||||
entier) ne pouvait jamais être satisfaite. Corrigé en composant le dictionnaire en une
|
||||
seule expression, qui rend des types natifs. Un `changed` permanent n'est pas cosmétique :
|
||||
c'est un bruit qui finit par masquer un vrai changement. Deux passages consécutifs à
|
||||
`changed=0` désormais.
|
||||
|
||||
## 2026-08-08 — 502 sur Icinga : le tampon de nginx, après une authentification réussie
|
||||
|
||||
Symptôme trompeur s'il en est : `oauth2-proxy` journalisait `AuthSuccess` — jeton, jeton
|
||||
|
|
|
|||
56
roles/serveur_keycloak/tasks/deconnexion-oidc.yml
Normal file
56
roles/serveur_keycloak/tasks/deconnexion-oidc.yml
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
# URI de retour APRES DECONNEXION, par client.
|
||||
#
|
||||
# Keycloak les valide separement des URI de rappel : un client peut donc se connecter
|
||||
# parfaitement et echouer a la deconnexion, sur un « We are sorry… invalid redirect uri »
|
||||
# qui ne dit pas de quelle liste il parle. Constate le 2026-08-08 sur Nextcloud — et
|
||||
# AUCUN des quatre clients ne declarait cet attribut ; Nextcloud etait seulement le seul
|
||||
# a envoyer une URI de retour.
|
||||
#
|
||||
# DERIVEE de `web_origins`, qui porte deja l'URL de base du service : la connaissance
|
||||
# existe, il n'y a pas a la reecrire. `/*` couvre la page d'accueil et les chemins de
|
||||
# retour que chaque application choisit.
|
||||
#
|
||||
# Par l'API et non `kcadm -s` : `attributes` est une MAP, et sur une map kcadm accepte
|
||||
# la commande, sort en succes et n'ecrit rien (mesure du meme jour sur `smtpServer`).
|
||||
# On relit systematiquement apres avoir pose.
|
||||
|
||||
- name: Lire les clients du realm
|
||||
ansible.builtin.uri:
|
||||
url: "http://localhost:8080/admin/realms/{{ serveur_keycloak_realm }}/clients"
|
||||
headers:
|
||||
Authorization: "Bearer {{ serveur_keycloak_pol_jeton.json.access_token }}"
|
||||
register: serveur_keycloak_clients_actuels
|
||||
no_log: true
|
||||
|
||||
- name: Composer les URI de déconnexion attendues
|
||||
ansible.builtin.set_fact:
|
||||
serveur_keycloak_deconnexion: >-
|
||||
{{ dict(serveur_keycloak_clients | map(attribute='clientId') | list
|
||||
| zip(serveur_keycloak_clients
|
||||
| map(attribute='web_origins')
|
||||
| map('map', 'regex_replace', '/?$', '/*')
|
||||
| map('join', '##') | list)) }}
|
||||
|
||||
- name: Déclarer l'URI de retour après déconnexion
|
||||
ansible.builtin.uri:
|
||||
url: >-
|
||||
http://localhost:8080/admin/realms/{{ serveur_keycloak_realm
|
||||
}}/clients/{{ item.id }}
|
||||
method: PUT
|
||||
status_code: [204]
|
||||
headers:
|
||||
Authorization: "Bearer {{ serveur_keycloak_pol_jeton.json.access_token }}"
|
||||
body_format: json
|
||||
body: >-
|
||||
{{ item | combine({'attributes': (item.attributes | default({}))
|
||||
| combine({'post.logout.redirect.uris': serveur_keycloak_deconnexion[item.clientId]})}) }}
|
||||
loop: "{{ serveur_keycloak_clients_actuels.json }}"
|
||||
loop_control:
|
||||
label: "{{ item.clientId }}"
|
||||
no_log: true
|
||||
changed_when: true
|
||||
when:
|
||||
- item.clientId in serveur_keycloak_deconnexion
|
||||
- (item.attributes | default({})).get('post.logout.redirect.uris', '')
|
||||
!= serveur_keycloak_deconnexion[item.clientId]
|
||||
|
|
@ -17,12 +17,16 @@
|
|||
no_log: true
|
||||
|
||||
- name: Composer la configuration attendue
|
||||
# Une seule expression, pour obtenir des types NATIFS. Ecrit champ par champ, Jinja
|
||||
# rendait « True » et « 1209600 » en CHAINES : la comparaison au reel (booleen, entier)
|
||||
# ne pouvait jamais etre satisfaite, et la tache se declarait `changed` a chaque
|
||||
# passage. Un bruit permanent finit par masquer un vrai changement.
|
||||
ansible.builtin.set_fact:
|
||||
serveur_keycloak_journal_attendu:
|
||||
eventsEnabled: "{{ serveur_keycloak_journal_actif | bool }}"
|
||||
eventsExpiration: "{{ serveur_keycloak_journal_retention | int }}"
|
||||
adminEventsEnabled: "{{ serveur_keycloak_journal_admin | bool }}"
|
||||
adminEventsDetailsEnabled: "{{ serveur_keycloak_journal_admin | bool }}"
|
||||
serveur_keycloak_journal_attendu: >-
|
||||
{{ {'eventsEnabled': serveur_keycloak_journal_actif | bool,
|
||||
'eventsExpiration': serveur_keycloak_journal_retention | int,
|
||||
'adminEventsEnabled': serveur_keycloak_journal_admin | bool,
|
||||
'adminEventsDetailsEnabled': serveur_keycloak_journal_admin | bool} }}
|
||||
|
||||
- name: Activer le journal des évènements du realm
|
||||
ansible.builtin.uri:
|
||||
|
|
|
|||
|
|
@ -181,6 +181,10 @@
|
|||
ansible.builtin.include_tasks: clients-oidc.yml
|
||||
when: serveur_keycloak_clients | length > 0
|
||||
|
||||
- name: Déclarer les URI de retour après déconnexion
|
||||
ansible.builtin.include_tasks: deconnexion-oidc.yml
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: Configurer le RBAC OIDC (roles de realm + mapper + assignations)
|
||||
ansible.builtin.include_tasks: rbac-oidc.yml
|
||||
when: >
|
||||
|
|
|
|||
Loading…
Reference in a new issue