Add SSO E-Cosplay (Keycloak OIDC) and dynamic navbar active state

- Install knpuniversity/oauth2-client-bundle and stevenmaguire/oauth2-keycloak
- Register KnpUOAuth2ClientBundle in bundles.php
- Configure Keycloak OIDC client (realm e-cosplay, auth.esy-web.dev)
- Add keycloakId field to User entity with migration
- Create KeycloakAuthenticator with group-to-role mapping (/superadmin -> ROLE_ROOT)
- Create OAuthController with SSO routes (/connection/sso/login, logout, check)
- Add custom_authenticator to security firewall with form_login entry point
- Add auth.esy-web.dev to nelmio external_redirects whitelist and CSP form-action
- Add SSO button and error flash messages to login page
- Make navbar active state dynamic based on current route (desktop + mobile)
- Add Keycloak env vars to .env, .env.local, and ansible/env.local.j2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-03-19 10:38:19 +01:00
parent 28763e7ee1
commit 2405fcc2da
15 changed files with 557 additions and 5 deletions

View File

@@ -82,9 +82,10 @@
</div>
<div class="hidden lg:flex items-center space-x-1">
<a href="{{ path('app_home') }}" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all bg-yellow-400 border-2 border-gray-900 shadow-[2px_2px_0px_rgba(0,0,0,1)]"><span itemprop="name">Accueil</span></a>
{% set current_route = app.request.attributes.get('_route') %}
<a href="{{ path('app_home') }}" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all {{ current_route == 'app_home' ? 'bg-yellow-400 border-2 border-gray-900 shadow-[2px_2px_0px_rgba(0,0,0,1)]' : 'hover:text-indigo-600' }}"><span itemprop="name">Accueil</span></a>
<a href="#" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all hover:text-indigo-600"><span itemprop="name">Evenements</span></a>
<a href="{{ path('app_contact') }}" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all hover:text-indigo-600"><span itemprop="name">Contact</span></a>
<a href="{{ path('app_contact') }}" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all {{ current_route == 'app_contact' ? 'bg-yellow-400 border-2 border-gray-900 shadow-[2px_2px_0px_rgba(0,0,0,1)]' : 'hover:text-indigo-600' }}"><span itemprop="name">Contact</span></a>
</div>
<div class="flex items-center space-x-4 border-l-4 border-gray-900 pl-6 h-full">
@@ -110,9 +111,9 @@
<div id="mobile-menu" class="hidden lg:hidden border-t-4 border-gray-900 bg-white" role="menu">
<div class="p-4 space-y-2 uppercase font-black italic">
<a href="{{ path('app_home') }}" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Accueil</a>
<a href="{{ path('app_home') }}" class="block p-3 border-2 {{ current_route == 'app_home' ? 'border-gray-900 bg-yellow-400' : 'border-transparent hover:border-gray-900 hover:bg-gray-50' }}" role="menuitem">Accueil</a>
<a href="#" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Evenements</a>
<a href="{{ path('app_contact') }}" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Contact</a>
<a href="{{ path('app_contact') }}" class="block p-3 border-2 {{ current_route == 'app_contact' ? 'border-gray-900 bg-yellow-400' : 'border-transparent hover:border-gray-900 hover:bg-gray-50' }}" role="menuitem">Contact</a>
{% if app.user %}
<a href="{{ path('app_account') }}" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Mon espace</a>
{% else %}