Le super admin (table super_admins, master DB) ne pouvait pas se connecter via /api/login car ce firewall n'utilisait que le provider tenant. De même, le JWT n'était pas enrichi pour les super admins, l'endpoint /api/me/roles les rejetait, et le frontend redirigeait systématiquement vers /dashboard. Un chain provider (super_admin + tenant) résout l'authentification, le JwtPayloadEnricher et MyRolesProvider gèrent désormais les deux types d'utilisateurs, et le frontend redirige selon le rôle après login.
91 lines
3.7 KiB
YAML
91 lines
3.7 KiB
YAML
security:
|
|
# Role hierarchy — Direction inherits read permissions on whole school (AC3, FR5)
|
|
role_hierarchy:
|
|
ROLE_SUPER_ADMIN: [ROLE_ADMIN]
|
|
ROLE_ADMIN: [ROLE_PROF, ROLE_VIE_SCOLAIRE, ROLE_SECRETARIAT]
|
|
ROLE_PROF: [ROLE_USER]
|
|
ROLE_VIE_SCOLAIRE: [ROLE_USER]
|
|
ROLE_SECRETARIAT: [ROLE_USER]
|
|
ROLE_PARENT: [ROLE_USER]
|
|
ROLE_ELEVE: [ROLE_USER]
|
|
|
|
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
|
password_hashers:
|
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
|
# Named hasher for domain services (decoupled from User entity)
|
|
common:
|
|
algorithm: auto
|
|
|
|
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
|
providers:
|
|
# User provider for API authentication (Story 1.4)
|
|
app_user_provider:
|
|
id: App\Administration\Infrastructure\Security\DatabaseUserProvider
|
|
# Super Admin authentication — master database, not per-tenant (Story 2.10)
|
|
super_admin_provider:
|
|
id: App\SuperAdmin\Infrastructure\Security\SuperAdminUserProvider
|
|
# Chain provider: tries super admin first, then tenant user
|
|
all_users_provider:
|
|
chain:
|
|
providers: ['super_admin_provider', 'app_user_provider']
|
|
|
|
firewalls:
|
|
dev:
|
|
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
|
security: false
|
|
# Monitoring endpoints - no authentication, restricted by IP in production
|
|
monitoring:
|
|
pattern: ^/(health|metrics)$
|
|
stateless: true
|
|
security: false
|
|
api_login:
|
|
pattern: ^/api/login$
|
|
stateless: true
|
|
json_login:
|
|
check_path: /api/login
|
|
username_path: email
|
|
password_path: password
|
|
success_handler: lexik_jwt_authentication.handler.authentication_success
|
|
failure_handler: App\Administration\Infrastructure\Security\LoginFailureHandler
|
|
provider: all_users_provider
|
|
super_admin_api:
|
|
pattern: ^/api/super-admin
|
|
stateless: true
|
|
jwt: ~
|
|
provider: super_admin_provider
|
|
api_public:
|
|
pattern: ^/api/(activation-tokens|activate|token/(refresh|logout)|password/(forgot|reset)|docs)(/|$)
|
|
stateless: true
|
|
security: false
|
|
api:
|
|
pattern: ^/api
|
|
stateless: true
|
|
jwt: ~
|
|
provider: all_users_provider
|
|
main:
|
|
lazy: true
|
|
provider: app_user_provider
|
|
|
|
# Easy way to control access for large sections of your site
|
|
# Note: Only the *first* access control that matches will be used
|
|
access_control:
|
|
- { path: ^/api/docs, roles: PUBLIC_ACCESS }
|
|
- { path: ^/api/super-admin, roles: ROLE_SUPER_ADMIN }
|
|
- { path: ^/api/login, roles: PUBLIC_ACCESS }
|
|
- { path: ^/api/activation-tokens, roles: PUBLIC_ACCESS }
|
|
- { path: ^/api/activate, roles: PUBLIC_ACCESS }
|
|
- { path: ^/api/token/refresh, roles: PUBLIC_ACCESS }
|
|
- { path: ^/api/token/logout, roles: PUBLIC_ACCESS }
|
|
- { path: ^/api/password/forgot, roles: PUBLIC_ACCESS }
|
|
- { path: ^/api/password/reset, roles: PUBLIC_ACCESS }
|
|
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
|
|
|
|
when@test:
|
|
security:
|
|
password_hashers:
|
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
|
algorithm: auto
|
|
cost: 4 # Lowest possible value for bcrypt
|
|
time_cost: 3 # Lowest possible value for argon
|
|
memory_cost: 10 # Lowest possible value for argon
|