diff --git a/CHANGELOG.md b/CHANGELOG.md index b0b4bf2..45d9515 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ (canvas + aurore, le template n'en ayant pas) — étoiles scintillantes qui dérivent, liens de constellation cyan, blob d'aurore ondulant ; respecte `prefers-reduced-motion`. Prouvé : `constellation.js` référencé + servi (200). + **Console de compte thémée aussi** (thème `account`, `parent=keycloak.v3`) : overlay CSS + surchargeant les variables PatternFly 5 (fond aurore, cartes en verre, accent aurore) + la même + constellation animée. Var `serveur_keycloak_account_theme` via `kcadm -s accountTheme`. Prouvé : + console charge (HTTP 200, `keycloak.v3` intact), `account.css` servi (200). - **Soumission courriel `:587` interne (authentifiée) — la boucle souveraine est bouclée.** Postfix (`edge-mta`) sert la **soumission `:587`** (bloc `master.cf` : STARTTLS requis, `SMTP AUTH`, seuls les authentifiés relaient) ; l'auth SASL est **déléguée à Dovecot** (`infra-mail`, passdb LDAP diff --git a/roles/serveur_keycloak/defaults/main.yml b/roles/serveur_keycloak/defaults/main.yml index a3fa8f1..ff3167a 100644 --- a/roles/serveur_keycloak/defaults/main.yml +++ b/roles/serveur_keycloak/defaults/main.yml @@ -25,8 +25,9 @@ serveur_keycloak_admin_password: "{{ vault_keycloak_admin | default('') }}" # r # Requiert client_pki sur ce nœud (racine step_ca dans le bundle système pour LDAPS). serveur_keycloak_ldap_federation: true serveur_keycloak_realm: "chezlepro" -# Thème de login du realm (déployé depuis files/themes/). Vide = thème Keycloak par défaut. +# Thèmes du realm (déployés depuis files/themes/). Vide = thème Keycloak par défaut. serveur_keycloak_login_theme: "" +serveur_keycloak_account_theme: "" serveur_keycloak_ldap_nom: "openldap" # Connexion à l'annuaire (url, users_dn, bind_dn, bind_password) : fournie par le rôle # partagé resoudre_annuaire (voir tasks/main.yml « Adopter la connexion annuaire »). diff --git a/roles/serveur_keycloak/files/themes/alliance-boreale/account/resources/css/account.css b/roles/serveur_keycloak/files/themes/alliance-boreale/account/resources/css/account.css new file mode 100644 index 0000000..4d609b0 --- /dev/null +++ b/roles/serveur_keycloak/files/themes/alliance-boreale/account/resources/css/account.css @@ -0,0 +1,62 @@ +/* ========================================================================= + Alliance Boréale — console de compte Keycloak (SPA PatternFly 5) + Overlay : ciel nocturne aurore, cartes en verre, accent aurore. + ========================================================================= */ +:root, +.pf-v5-theme-dark, +html { + --pf-v5-global--Color--100: #e9ecff; + --pf-v5-global--Color--200: #99a1c9; + --pf-v5-global--link--Color: #56c2ff; + --pf-v5-global--link--Color--hover: #a98bff; + --pf-v5-global--primary-color--100: #56c2ff; + --pf-v5-global--primary-color--200: #4fe3c1; + --pf-v5-global--BorderColor--100: rgba(255, 255, 255, 0.12); + --pf-v5-global--BackgroundColor--100: rgba(255, 255, 255, 0.05); + --pf-v5-global--BackgroundColor--200: #0a0d24; + --pf-v5-global--FontFamily--text: -apple-system, BlinkMacSystemFont, "Segoe UI", + Roboto, Oxygen, Ubuntu, Cantarell, "Noto Sans", "Helvetica Neue", Arial, sans-serif; +} + +html, body, #app, .pf-v5-c-page, .pf-v5-c-page__main { + background: transparent !important; + color: #e9ecff; +} +body { + background: + radial-gradient(1200px 700px at 80% -10%, #131a44 0%, transparent 60%), + radial-gradient(900px 600px at 10% 0%, #0e1640 0%, transparent 55%), + linear-gradient(180deg, #0a0d24 0%, #05060f 70%) fixed !important; +} + +/* En-tête / masthead + cartes : verre */ +.pf-v5-c-masthead, +.pf-v5-c-card, +.pf-v5-c-page__sidebar, +.pf-v5-c-nav { + background: rgba(255, 255, 255, 0.05) !important; + border-color: rgba(255, 255, 255, 0.10) !important; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); +} +.pf-v5-c-card { border-radius: 16px; box-shadow: 0 18px 50px rgba(0, 0, 0, 0.4); } + +/* Textes, titres */ +.pf-v5-c-title, .pf-v5-c-content, h1, h2, h3, label { color: #e9ecff !important; } +a, .pf-v5-c-button.pf-m-link { color: #56c2ff; } + +/* Champs */ +.pf-v5-c-form-control, input, select, textarea { + background: rgba(255, 255, 255, 0.06) !important; + color: #e9ecff !important; + border: 1px solid rgba(255, 255, 255, 0.14) !important; +} + +/* Bouton primaire : ruban d'aurore */ +.pf-v5-c-button.pf-m-primary { + background: linear-gradient(100deg, #4fe3c1, #56c2ff) !important; + color: #04121a !important; + border: none !important; + border-radius: 999px !important; + font-weight: 600 !important; +} diff --git a/roles/serveur_keycloak/files/themes/alliance-boreale/account/resources/js/constellation.js b/roles/serveur_keycloak/files/themes/alliance-boreale/account/resources/js/constellation.js new file mode 100644 index 0000000..3cc80dc --- /dev/null +++ b/roles/serveur_keycloak/files/themes/alliance-boreale/account/resources/js/constellation.js @@ -0,0 +1,93 @@ +/* Alliance Boréale — champ d'étoiles + constellation, adapté au login Keycloak. + Vanilla JS, aucune dépendance. Crée son propre ciel en fond (le template + Keycloak n'a pas de ). Respecte prefers-reduced-motion. + Métaphore : chaque artisan est une étoile ; reliés, ils forment la constellation. */ +(function () { + "use strict"; + if (document.querySelector(".ab-sky")) return; + + var sky = document.createElement("div"); + sky.className = "ab-sky"; + sky.setAttribute("aria-hidden", "true"); + var canvas = document.createElement("canvas"); + canvas.id = "ab-constellation"; + var aurora = document.createElement("div"); + aurora.className = "ab-aurora"; + sky.appendChild(canvas); + sky.appendChild(aurora); + document.body.insertBefore(sky, document.body.firstChild); + + var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches; + var ctx = canvas.getContext("2d"); + var stars = []; + var w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2); + var LINK_DIST = 130; + + function resize() { + w = canvas.clientWidth; + h = canvas.clientHeight; + canvas.width = w * dpr; + canvas.height = h * dpr; + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + seed(); + } + + function seed() { + var count = Math.round((w * h) / 14000); + count = Math.max(40, Math.min(160, count)); + stars = []; + for (var i = 0; i < count; i++) { + stars.push({ + x: Math.random() * w, + y: Math.random() * h, + r: Math.random() * 1.3 + 0.4, + vx: (Math.random() - 0.5) * 0.12, + vy: (Math.random() - 0.5) * 0.12, + tw: Math.random() * Math.PI * 2 + }); + } + } + + function draw() { + ctx.clearRect(0, 0, w, h); + for (var i = 0; i < stars.length; i++) { + for (var j = i + 1; j < stars.length; j++) { + var dx = stars[i].x - stars[j].x; + var dy = stars[i].y - stars[j].y; + var d = Math.sqrt(dx * dx + dy * dy); + if (d < LINK_DIST) { + var a = (1 - d / LINK_DIST) * 0.22; + ctx.strokeStyle = "rgba(120, 200, 255," + a + ")"; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(stars[i].x, stars[i].y); + ctx.lineTo(stars[j].x, stars[j].y); + ctx.stroke(); + } + } + } + for (var k = 0; k < stars.length; k++) { + var s = stars[k]; + s.tw += 0.02; + var glow = 0.6 + Math.sin(s.tw) * 0.4; + ctx.beginPath(); + ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2); + ctx.fillStyle = "rgba(255,255,255," + glow + ")"; + ctx.shadowColor = "rgba(160,220,255,0.9)"; + ctx.shadowBlur = 6; + ctx.fill(); + ctx.shadowBlur = 0; + if (!reduce) { + s.x += s.vx; + s.y += s.vy; + if (s.x < 0 || s.x > w) s.vx *= -1; + if (s.y < 0 || s.y > h) s.vy *= -1; + } + } + if (!reduce) requestAnimationFrame(draw); + } + + window.addEventListener("resize", resize); + resize(); + draw(); +})(); diff --git a/roles/serveur_keycloak/files/themes/alliance-boreale/account/theme.properties b/roles/serveur_keycloak/files/themes/alliance-boreale/account/theme.properties new file mode 100644 index 0000000..457f972 --- /dev/null +++ b/roles/serveur_keycloak/files/themes/alliance-boreale/account/theme.properties @@ -0,0 +1,3 @@ +parent=keycloak.v3 +styles=css/account.css +scripts=js/constellation.js diff --git a/roles/serveur_keycloak/tasks/main.yml b/roles/serveur_keycloak/tasks/main.yml index 662372b..d321903 100644 --- a/roles/serveur_keycloak/tasks/main.yml +++ b/roles/serveur_keycloak/tasks/main.yml @@ -169,3 +169,27 @@ when: - serveur_keycloak_login_theme | length > 0 - not ansible_check_mode + +- name: Definir le theme de la console de compte (identite Alliance Boreale) + ansible.builtin.shell: + executable: /bin/bash + cmd: | + set -euo pipefail + KC={{ serveur_keycloak_home }}/bin/kcadm.sh + "$KC" config credentials --server http://localhost:8080 --realm master \ + --user {{ serveur_keycloak_admin_user }} --password "$KC_ADMIN_PW" >/dev/null + if "$KC" get realms/{{ serveur_keycloak_realm }} --fields accountTheme 2>/dev/null \ + | grep -q '"{{ serveur_keycloak_account_theme }}"'; then + echo SETOPS_OK + else + "$KC" update realms/{{ serveur_keycloak_realm }} \ + -s accountTheme={{ serveur_keycloak_account_theme }} >/dev/null + echo SETOPS_CHANGED + fi + environment: + KC_ADMIN_PW: "{{ serveur_keycloak_admin_password }}" + register: serveur_keycloak_account_res + changed_when: "'SETOPS_CHANGED' in serveur_keycloak_account_res.stdout" + when: + - serveur_keycloak_account_theme | length > 0 + - not ansible_check_mode