feat: harden the myep OAuth2 login

This commit is contained in:
fromme committed 2026-09-23 15:18:43 +02:00
1 parent 4517b84023
commit 91419294b8
25 files changed
+1013 -35

No files matched your search

+24 -1
View File
@@ -2,8 +2,31 @@
framework:
secret: '%env(APP_SECRET)%'
# The OAuth2 redirect_uri is generated from the incoming request, so the Host and the
# X-Forwarded-* headers decide where myep is told to send the authorization code. Both lists
# read the standard SYMFONY_* variables Symfony already defaults to, and are spelled out here
# because leaving them implicit is what made them easy to overlook. Set SYMFONY_TRUSTED_HOSTS
# per environment -- an empty value means every Host header is accepted.
trusted_hosts: '%env(default::SYMFONY_TRUSTED_HOSTS)%'
# Only ever needed behind a TLS-terminating proxy. Without it the generated redirect_uri of
# such a deployment comes out as http://, and the flow breaks rather than downgrading quietly.
trusted_proxies: '%env(default::SYMFONY_TRUSTED_PROXIES)%'
trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix']
# Note that the session will be started ONLY if you read or write from it.
session: true
#
# Everything here is pinned rather than left to the default, because a session cookie is the
# whole of this application's authentication once the OAuth2 flow is over. cookie_secure and
# cookie_samesite happen to match the defaults; save_path does not, and it is the one that
# matters in production -- deploy.php shares var/sessions between releases, and without this
# sessions land in PHP's default directory and every release logs everybody out.
session:
handler_id: session.handler.native_file
save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
name: epsession
cookie_secure: true
cookie_samesite: lax
cookie_httponly: true
form:
csrf_protection:
+16
View File
@@ -1,4 +1,9 @@
security:
# Symfony's default, stated because it is a decision: the session id is regenerated on a
# successful login, so a session id an attacker planted beforehand is not the one that ends
# up authenticated.
session_fixation_strategy: migrate
# No password_hashers: there are no passwords here. Authentication is OAuth2 against myep,
# which owns the credentials; ephub only ever sees a userinfo response.
@@ -19,9 +24,20 @@ security:
entry_point: App\Security\LoginEntryPoint
custom_authenticators:
- App\Security\EpAuthenticator
# The local lockout. Roles follow myep on every login and a deleted row is simply
# provisioned again, so this flag is the only thing here that myep cannot undo.
user_checker: App\Security\UserChecker
logout:
path: app_logout
target: app_login
# Without this any third-party page can log somebody out by embedding the URL.
# The header link is a form POST for the same reason.
enable_csrf: true
# Local only: there is no RP-initiated logout against myep and no token
# revocation, so this ends the ephub session and nothing else. It matters less
# than it usually would -- myep destroys its own session immediately after an
# external authorization request, so there is normally no SSO session left to
# end -- and the access token is gone either way, never having been stored.
access_control:
# The login surface itself has to stay reachable, or the entry point redirects in a loop.
+1 -1
View File
@@ -1293,7 +1293,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* lifetime?: int|Param, // Default: 31536000
* path?: scalar|Param|null, // Default: "/"
* domain?: scalar|Param|null, // Default: null
* secure?: true|false|"auto"|Param, // Default: "auto"
* secure?: true|false|"auto"|Param, // Default: true
* httponly?: bool|Param, // Default: true
* samesite?: null|"lax"|"strict"|"none"|Param, // Default: "lax"
* always_remember_me?: bool|Param, // Default: false