New in Symfony 5.1: Updated Security System
May 26, 2020 • Published by Javier Eguiluz
Warning: This post is about an unsupported Symfony version. Some of this information may be out of date. Read the most recent Symfony Docs.
Contributed by
Wouter De Jong
in #33558,
#36570
and #36574.
Symfony 5.1 will include a new Security system as one of its biggest new features. After several months of planning, discussions and hard work, we could finish it on time for Symfony 5.1 as an experimental feature.
The main differences with respect to the previous system are:
1) Removed everything but Guards
In the new Security system, there's only one listener that passes the request to an authenticator manager provided by Symfony. That manager takes care of session management, storing the token, "Remember me" functionality, etc.
Everything is related to a single concept and interface: authenticators. This simplifies the internals of the Security component and makes everything easier to understand for developers.
2) Moved to an event-based system
The Security component didn't use Symfony events to extend all its features. The new system changes that and it's based on three events:
CheckPassportEvent
, this is the main event and checks the validity of the given credentials (a password, a certificate, a CSRF token, etc.)LoginSuccessEvent
, dispatched when credentials are valid.LoginFailureEvent
, dispatched when credentials are wrong.
That's all! Three simple events give you all the flexibility needed by your applications.
3) Next generation Guards
Security Guards were introduced in Symfony 2.8 via the GuardAuthenticatorInterface
.
The new Security system allows to simplify some Guard features and improves others.
For starters, the checkCredentials()
method is removed and the getCredentials()
and getUser()
methods have been merged into a method called authenticate()
.
This introduces a couple of new concepts:
Passport
, theauthenticate()
method returns a "security passport" that contains the user object and any credentials needed to authenticate it;Badges
, the extra information needed by the passport.
Passports and badges are used by listeners of the CheckPassportEvent
, which
will validate and check the passport and all its badges. If all badges are
resolved, the user is successfully authenticated.
Here's a simplified example of the new system in action when used in a login form:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
class FormAuthenticator implements AuthenticatorInterface
{
// ...
public function authenticate(Request $request): PassportInterface
{
// find a user based on an "email" form field
$user = $this->userRepository->findOneByEmail($request->get('email'));
if (!$user) {
throw new UsernameNotFoundException();
}
return new Passport($user, new PasswordCredentials($request->get('password')), [
// and CSRF protection using a "csrf_token" field
new CsrfTokenBadge('loginform', $request->get('csrf_token')),
// and add support for upgrading the password hash
new PasswordUpgradeBadge($request->get('password'), $this->userRepository)
]);
}
}
The new Security system is disabled by default, but you can enable it as follows:
1 2 3 4
# config/packages/security.yaml
security:
# ...
enable_authenticator_manager: true
We'll revamp all Symfony Doc articles about security very soon to start using this new Security system. Meanwhile, you can read the following blog post: Meet the new Symfony Security: Authenticators published by Wouter De Jong, the main developer behind this new Security system. This article was completely based on Wouter's blog post.
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.
What if we cannot read the user data without the authentication?
For example, the userRepository may have a method to authenticate the provided credentials ([email, password] → user or null), but it may not allow reads without authentication — the repository has additional layer of guards regarding both security and workflows.
Similarly, when authenticating against LDAP, we must call `bind(userDN, password)` before reading anything from the LDAP server because the LDAP server has its own set of access rules.
https://github.com/symfony/symfony/pull/36600
So unless you're implementing AuthenticationProviderInterface (or use a bundle that does this), you can switch to the new system without a problem.
I would highly advise anyone to do so, and show their findings on Slack or in a GitHub issue. That'll help us make the new system stable and perfect once it's out of experimental phase.
I just added support for the new authentication system in the ecphp/cas-bundle !
See: https://github.com/ecphp/cas-bundle/pull/8