Securing Web Apps with Symfony Security Component"TITLE"Symfony Security: Authentication, Authorization and Firewalls" TITLE"Build Secure Symfony Apps Using Authentication and Authorization"TITLE"Symfony Security Best Practices for Web Applications"TITLE"Symfony Security Component Tutorial: Authentication and Firewalls
L'authentification et l’autorisation sont omniprésents dans les applications web. Cependant la sécurisation des applications Symfony semble assez compliquée surtout pour les débutants. Je vous propose d'examiner le composant Security de Symfony pour comprendre comment la couche d'authentification est organisée et comment les règles d'autorisation sont implémentées. Nous verrons les classes qui se cachent derrière la configuration dans votre security.yml.
Similar to Securing Web Apps with Symfony Security Component"TITLE"Symfony Security: Authentication, Authorization and Firewalls" TITLE"Build Secure Symfony Apps Using Authentication and Authorization"TITLE"Symfony Security Best Practices for Web Applications"TITLE"Symfony Security Component Tutorial: Authentication and Firewalls
Similar to Securing Web Apps with Symfony Security Component"TITLE"Symfony Security: Authentication, Authorization and Firewalls" TITLE"Build Secure Symfony Apps Using Authentication and Authorization"TITLE"Symfony Security Best Practices for Web Applications"TITLE"Symfony Security Component Tutorial: Authentication and Firewalls (20)
Securing Web Apps with Symfony Security Component"TITLE"Symfony Security: Authentication, Authorization and Firewalls" TITLE"Build Secure Symfony Apps Using Authentication and Authorization"TITLE"Symfony Security Best Practices for Web Applications"TITLE"Symfony Security Component Tutorial: Authentication and Firewalls
1. Sécurisation de vos applications web
à l’aide du composant Security de Symfony
25 sept 2018
3. Symfony 3
1. Concepts de sécurité
2. Authentification artisanale
3. Firewall
4. Token anonyme
5. User provider
6. Authentication provider
7. HTTP Basic
8. Formulaire de connexion
9. Autorisation autour des rôles
Plan
4. Symfony 4
Authentification est un processus permettant à l’application de s’assurer que la requête
a été faite par un utilisateur légitime.
C’est une confirmation de son identité grâce à des identifiants.
Identification est une sélection d’utilisateur grâce à son identifiant.
Autorisation est une vérification des droits d’accès d’un utilisateur sur une ressource en
se basant sur une politique d’accès.
5. Auth simple 5
Authentifier chaque requête à l’application à l’aide d’un identifiant et d’un
mot de passe.Tâche 1
Front controller
Token
public/index.php reçoit toutes les requêtes client quelque soit le
path et les paramètres
HttpFoundation
Composant de Symfony qui fournit la couche orientée-objet pour
HTTP : Request, Response, Session, etc.
Conserve des données sur l’utilisateur :
• Objet d’utilisateur
• Username
• Credentials
• Roles
• Authentifié ou pas
6. SymfonyComponentSecurityCoreAuthenticationToken
6
Security listeners
Token Conserve des données sur l’utilisateur
+ getUser()
+ getUsername()
+ getCredentials()
+ isAuthenticated()
+ getRoles()
TokenInterface
+ getProviderKey()
UsernamePasswordToken
+ getSecret()
AnonymousToken
Listeners qui extraient les identifiants et les vérifient.
Ils créent ensuite un Token puis le stockent dans le Token storage.
Token storage Objet/service qui contient un Token
Auth simple
7. 7Auth simple
// public/index.php
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorage;
use SymfonyComponentHttpFoundationResponse;
$request = Request::createFromGlobals(); // HTTP request
$tokenStorage = new TokenStorage(); // Service that stores user token
// Call security listener on every request.
$securityListener = new AppSecuritySecurityListener($tokenStorage);
$securityListener->onRequest($request);
// Any code you can imagine to generate a response.
// You can deny access if no token were set.
$token = $tokenStorage->getToken();
$response = new Response(
'Request uri: '.$request->getRequestUri().'<br>'
.'Token: '.(is_object($token) ? get_class($token) : gettype($token)).'<br>'
.'Username: '.($token ? $token->getUsername(): 'NULL')
);
$response->send(); // Send response
8. 8Auth simple
namespace AppSecurity;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorageInterface;
use SymfonyComponentSecurityCoreAuthenticationTokenUsernamePasswordToken;
class SecurityListener
{
/** @var TokenStorageInterface */
private $tokenStorage;
public function onRequest(Request $request)
{
$user = $request->query->get('auth_user');
$password = $request->query->get('auth_pw');
if ($user === 'gordon' && $password === 'freeman') {
// Credentials are valid.
// Create a token with user object, credentials, provider key and roles
$token = new UsernamePasswordToken($user, $password, 'main', ['ROLE_USER']);
// Save it to token storage
$this->tokenStorage->setToken($token);
}
}
}
9. Firewall 9
Centraliser l’authentification dans un firewall afin de pouvoir utiliser
plusieurs systèmes d’authentification.Tâche 2
HttpKernel
Le composant de Symfony qui fournit un processus structuré pour
convertir Request en Response en utilisant EventDispatcher.
EventDispatcher
Le composant de Symfony qui permet aux composants de
communiquer entre eux à l’aide d’événements.
Request ResponseExecute controller
EXCEPTIONEvent Dispatcher
10. 10Firewall
Le Front controller crée $kernel et lui demande de traiter la requête.
// public/index.php
use SymfonyComponentEventDispatcherEventDispatcher;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpKernelHttpKernel;
use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorage;
$request = Request::createFromGlobals(); // HTTP request.
$tokenStorage = new TokenStorage(); // Service that stores user token.
$dispatcher = new EventDispatcher();
// Controller creates a response to send to the user.
$controller = new AppController($request, $tokenStorage);
$controllerResolver = new AppControllerResolver([$controller, 'defaultAction']);
// Kernel is in charge of converting a Request into a Response by using the event dispatcher.
$kernel = new HttpKernel($dispatcher, $controllerResolver);
// We will add security listeners to dispatcher in few minutes.
$response = $kernel->handle($request); // Launch kernel and retrieve response.
$response->send(); // Send response.
11. 11
Kernel demande à ControllerResolver de renvoyer le contrôleur en fonction de la
requête. C’est l’emplacement idéal pour la logique de Routing.
Firewall
namespace App;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpKernelControllerControllerResolverInterface;
class ControllerResolver implements ControllerResolverInterface
{
/** @var callable */
private $default;
public function __construct(callable $default)
{
$this->default = $default;
}
public function getController(Request $request)
{
return $this->default;
}
}
12. 12
La méthode Controller::defaultAction est un contrôleur qui sera exécuté par Kernel.
Firewall
namespace App;
class Controller
{
/** @var Request */
private $request;
/** @var TokenStorageInterface */
private $tokenStorage;
public function defaultAction()
{
$token = $this->tokenStorage->getToken();
return new Response(
'Request uri: '.$this->request->getRequestUri().'<br>'
.'Token: '.(is_object($token) ? get_class($token) : gettype($token)).'<br>'
.'Username: '.($token ? $token->getUsername(): 'NULL')
);
}
}
13. SymfonyComponentSecurityHttp
13
- map: array
+ getListeners(Request $request)
Firewall
- map: FirewallMap
+ onKernelRequest(GetResponseEvent $event)
FirewallMap
RequestMatcher
- path: string
=>
][
Le firewall est un listener de l’événement
REQUEST.
Il permet d’implémenter des stratégies
d’authentification en fonction de la
requête.
FirewallMap renvoie les listeners
configurés pour le requête spécifique.
ListenerInterface
+ handle(GetResponseEvent $event) , …
Firewall
14. 14
RequestMatcher
- path = ^/lambda
- host = half-life.com
=>
][ BasicAuthenticationListener
Utiliser l’authentification HTTP basic pour toutes les requêtes qui commencent par
/lambda sur le serveur half-life.com :
Firewall
# config/packages/security.yaml
security:
firewalls:
half_life:
pattern: ^/lambda
host: half-life.com
http_basic:
realm: "Lambda Complex"
15. 15
RequestMatcher
- path: ^/customer
=>
][ ContextListener
,
SimpleFormAuthenticationListener
Authentifier les requêtes qui commencent par /customer à l’aide d’un formulaire classique
Firewall
# config/packages/security.yaml
security:
firewalls:
half_life:
# ...
customer:
pattern: ^/customer
form_login:
check_path: /login_check
login_path: /login
17. 17
Firewall attends l’événement REQUEST pour exécuter MainSecurityListener si le path de
la requête commence par /main.
Firewall
// public/index.php
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpFirewallMap;
use SymfonyComponentSecurityHttpFirewall;
// ...
// Create main security listener that handles authentication.
$securityListener = new AppSecurityMainSecurityListener($tokenStorage);
// Create firewall map and add main security listener under URLs starting with "/main".
$firewallMap = new FirewallMap();
$firewallMap->add(new RequestMatcher('^/main'), [$securityListener]);
// Create firewall and add it to dispatcher.
$firewall = new Firewall($firewallMap, $dispatcher);
$dispatcher->addSubscriber($firewall);
// ...
18. 18
MainSecurityListener implémente désormais ListenerInterface.
Firewall
namespace AppSecurity;
use SymfonyComponentHttpKernelEventGetResponseEvent;
use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorageInterface;
use SymfonyComponentSecurityCoreAuthenticationTokenUsernamePasswordToken;
use SymfonyComponentSecurityHttpFirewallListenerInterface;
class MainSecurityListener implements ListenerInterface
{
/** @var TokenStorageInterface */
private $tokenStorage;
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
$user = $request->query->get('auth_user');
$password = $request->query->get('auth_pw');
if ($user === 'gordon' && $password === 'freeman') {
$token = new UsernamePasswordToken($user, $password, 'main', ['ROLE_USER']);
$this->tokenStorage->setToken($token);
}
}
}
19. App
SymfonyComponentSecurityHttpFirewall
anon. 19
Permettre aux utilisateurs de s’authentifier comme des anonymes.Tâche 3
RequestMatcher
- path = ^/main =>
][
MainSecurityListener
AnonymousAuthenticationListener
# config/packages/security.yaml
security:
firewalls:
main:
# ...
anonymous: true
20. anon. 20
// public/index.php
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpFirewallMap;
use SymfonyComponentSecurityHttpFirewallAnonymousAuthenticationListener;
// ...
// Create a security listener that adds anonymous token if none is already present.
$anonListener = new AnonymousAuthenticationListener($tokenStorage, 'secret');
// Create firewall map and add main security listener under URLs starting with "/main".
$firewallMap = new FirewallMap();
$firewallMap->add(new RequestMatcher('^/main'), [$securityListener, $anonListener]);
// ...
Plusieurs security listeners peuvent s'enchaîner :
21. User provider 21
Abstraire le moyen de récupération des utilisateurs et déplacer cette logique
en dehors des security listeners.Tâche 4
SymfonyComponentSecurityCoreUser
UserProviderInterface
+ loadUserByUsername($username): UserInterface
+ refreshUser(UserInterface $user)
+ supportsClass($class)
Security Listener
- userProvider
+ loadUserByUsername($username):User
UserInterface
+ getUsername()
+ getRoles()
+ getPassword()
+ getSalt()
+ eraseCredentials()
+ isEnabled()
UserInMemoryUserProvider
22. 22User provider
use SymfonyComponentHttpKernelEventGetResponseEvent;
use SymfonyComponentSecurityCoreAuthenticationTokenUsernamePasswordToken;
use SymfonyComponentSecurityCoreExceptionUsernameNotFoundException;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityHttpFirewallListenerInterface;
class MainSecurityListener implements ListenerInterface
{
/** @var UserProviderInterface */
private $userProvider;
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
$username = $request->query->get('auth_user');
$password = $request->query->get('auth_pw');
try {
$user = $this->userProvider->loadUserByUsername($username);
if ($user->getPassword() === $password) {
$token = new UsernamePasswordToken($user, $password, 'main', $user->getRoles());
$this->tokenStorage->setToken($token);
}
} catch (UsernameNotFoundException $e) { }
}
}
23. 23User provider
Création d’un user provider pour main security listener.
// public/index.php
use SymfonyComponentEventDispatcherEventDispatcher;
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpFirewallMap;
use SymfonyComponentSecurityHttpFirewall;
use SymfonyComponentSecurityCoreUserInMemoryUserProvider;
// ...
// Create user provider that will be used by authentication listener.
$mainUserProvider = new InMemoryUserProvider([
'gordon' => ['password' => 'freeman', 'roles' => ['ROLE_USER']],
]);
// Create main security listener that handles authentication.
$mainSecurityListener = new AppSecurityMainSecurityListener($tokenStorage, $mainUserProvider);
// Create firewall map and add main security listener under URLs starting with "/main".
$firewallMap = new FirewallMap();
$firewallMap->add(new RequestMatcher('^/main'), [$mainSecurityListener, $anonListener]);
// ...
25. App
25Auth provider
Ajouter l’encodage du mot de passe, n’accepter que des utilisateurs activés.
Déplacer la logique d’authentification en dehors des security listeners.Tâche 5
- tokenStorage
- authenticationManager
SymfonyComponentSecurityCoreAuthentication
AuthenticationManagerInterface
+ authenticate(TokenInterface $token)
MainSecurityListener
̶ Être rappelé par Firewall pendant l’événement
REQUEST
̶ Extraire l’identifiant et le mot de passe
̶ Créer le token non authentifié
̶ Passer le token à l’authentification manager
̶ Mettre le token authentifié dans le token storage
̶ Récupérer l’utilisateur grâce à l’identifiant et à
l’aide de user provider
̶ Vérifier le mot de passe à l’aide de password
encoder
̶ Vérifier les autres paramètres
̶ Renvoyer le token authentifié
$token->setAuthenticated(true)
créer un nouveau token
29. 29Auth provider
use SymfonyComponentSecurityCoreAuthenticationAuthenticationManagerInterface;
class MainSecurityListener implements ListenerInterface
{
/** @var AuthenticationManagerInterface */
private $authenticationManager;
public function handle(GetResponseEvent $event)
{
// Extract credentials from request...
if ($username && $credentials) {
try {
// Token is not authenticated because no role is passed.
$token = new UsernamePasswordToken($username, $credentials, 'main');
// Try to authenticate the token.
// If there is an authentication error an AuthenticationException is thrown.
$token = $this->authenticationManager->authenticate($token);
// Add authenticated token to storage.
$this->tokenStorage->setToken($token);
} catch (AuthenticationException $e) { }
}
}
}
30. use SymfonyComponentSecurityCoreUserInMemoryUserProvider;
use SymfonyComponentSecurityCoreAuthenticationProviderDaoAuthenticationProvider;
use SymfonyComponentSecurityCoreEncoderEncoderFactory;
use SymfonyComponentSecurityCoreUserUser;
use SymfonyComponentSecurityCoreEncoderBCryptPasswordEncoder;
// Create user provider that will be used by authentication listener.
$mainUserProvider = new InMemoryUserProvider([
'gordon' => [
'password' => '$2y$10$50MJW4ov/LHLBdl6uYsxI.7MdWYoJ8K1MqBXfG677nOXbsSVVue6i',
'roles' => ['ROLE_USER'],
'enabled' => true,
],
]);
// Service that checks whether a user is non-locked, enabled, not expired, etc.
$mainUserChecker = new SymfonyComponentSecurityCoreUserUserChecker();
// A factory that specifies encoding algorithm to each user class.
$encoderFactory = new EncoderFactory([User::class => new BCryptPasswordEncoder(10)]);
// Create a provider to which security listener will delegate an authentication.
$mainAuthProvider = new DaoAuthenticationProvider(
$mainUserProvider, $mainUserChecker, 'main', $encoderFactory
);
// Create main security listener that handles authentication.
$mainSecurityListener = new AppSecurityMainSecurityListener($tokenStorage, $mainAuthProvider);
30Auth provider
32. 32HTTP basic auth
Mettre en place l’authentification HTTP, laisser passer seulement les
utilisateurs connectés.Tâche 6
SymfonyComponentSecurityHttpFirewall
- tokenStorage
- authenticationManager
BasicAuthenticationListener
- tokenStorage
- accessDecisionManager
AccessListener
RequestMatcher
- path: ^/main
=>
Extraire l’identifiant et le mot de
passe de l'en-tête Authorization.
Créer le token, l'authentifier, le
sauvegarder dans token storage.
Lancer une exception si les
credentials ne sont pas valides. Lancer une exception si le token
n’est pas présent ou s’il ne
respecte pas les règles d’accès.
33. 33
SymfonyComponentSecurityHttpEntryPoint
+ start(Request $request, $authException): Response
AuthenticationEntryPointInterface
- realmName: string
BasicAuthenticationEntryPoint
Lors de l'exception d’authentification (accès anonyme ou identifiants non valides) il faut
aider l’utilisateur à (re-)commencer l’authentification.
SymfonyComponentSecurityHttpFirewall
- tokenStorage
- authenticationManager
- authenticationEntryPoint
BasicAuthenticationListener
EventDispatcher
- Kernel::EXCEPTION => [...]
- authenticationEntryPoint
ExceptionListener
HTTP basic auth
34. 34HTTP basic auth
// public/index.php
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpAccessMap;
use SymfonyComponentSecurityHttpFirewallMap;
use SymfonyComponentSecurityHttpFirewallBasicAuthenticationListener;
use SymfonyComponentSecurityHttpFirewallAccessListener;
use SymfonyComponentSecurityHttpEntryPointBasicAuthenticationEntryPoint;
use SymfonyComponentSecurityCoreAuthorizationAccessDecisionManager;
// ...
// Entry point helps user to authenticate.
$basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint('Black mesa');
// Create HTTP basic security listener that extracts credentials from headers (RFC 7617).
$mainSecurityListener = new BasicAuthenticationListener(
$tokenStorage, $mainAuthProvider, 'main', $basicAuthenticationEntryPoint
);
$accessDecisionManager = new AccessDecisionManager();
$accessMap = new AccessMap();
// Access listener will throw an exception when no token is already present.
$accessListener = new AccessListener(
$tokenStorage, $accessDecisionManager, $accessMap, $mainAuthProvider
);
// ...
35. 35HTTP basic auth
// public/index.php
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpFirewallMap;
use SymfonyComponentSecurityHttpFirewallExceptionListener;
use SymfonyComponentSecurityCoreAuthenticationAuthenticationTrustResolver;
use SymfonyComponentSecurityCoreAuthenticationTokenAnonymousToken;
use SymfonyComponentSecurityCoreAuthenticationTokenRememberMeToken;
// ...
// ExceptionListener catches authentication exception and converts them to Response instance.
// In this case it invites user to enter its credentials by returning 401 response.
$authTrustResolver = new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class);
$mainExceptionListener = new ExceptionListener(
$tokenStorage, $authTrustResolver, $httpUtils, 'main', $basicAuthenticationEntryPoint
);
// Create firewall map and add main security listener under URLs starting with "/main".
$firewallMap = new FirewallMap();
$firewallMap->add(
new RequestMatcher('^/main’),
[$mainSecurityListener, $accessListener],
$mainExceptionListener
);
// ...
37. 37Formulaire de connexion
Mettre en place l’authentification par le formulaire de connexion pour une
autre partie de site.Tâche 7
SymfonyComponentSecurityHttpFirewall
- tokenStorage
- userProviders
ContextListener
- tokenStorage
- accessDecisionManager
- options
- successHandler
- failureHandler
UsernamePasswordFormAuthenticationListener
RequestMatcher
- path: ^/front
=>
+ handle(GetResponseEvent $event)
+ onKernelResponse(FilterResponseEvent $event)
+ handle(GetResponseEvent $event)
Récupérer le token d’une session
lors de l’événement REQUEST.
Sauvegarder le token dans une
session lors de l’événement
RESPONSE.
Authentifier l’utilisateur
seulement quand le formulaire de
connexion est envoyé
(POST sur /front/login_check).
38. 38Formulaire de connexion
Nouvelle action pour visualiser le formulaire de conexion : POST sur /front/login_check.
namespace App;
class Controller
{
public function loginFormAction()
{
return new Response(<<<END
<form action="/front/login_check" method="POST">
<input type="text" name="_username" placeholder="username">
<input type="password" name="_password" placeholder="password">
<input type="submit">
</form>
END
);
}
public function defaultAction()
{
$token = $this->tokenStorage->getToken();
$user = $token ? $token->getUser() : null;
// ...
}
}
39. 39Formulaire de connexion
La nouvelle action sera appelée quand la requête est faite sur /font/login.
namespace App;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpKernelControllerControllerResolverInterface;
class ControllerResolver implements ControllerResolverInterface
{
/** @var callable[] */
private $routes;
/** @var callable */
private $default;
public function getController(Request $request)
{
foreach ($this->routes as $pattern => $controller) {
if (preg_match($pattern, $request->getPathInfo())) {
return $controller;
}
}
return $this->default;
}
}
40. 40Formulaire de connexion
La nouvelle action sera appelée quand la requête est faite sur /font/login.
// public/index.php
use SymfonyComponentEventDispatcherEventDispatcher;
use SymfonyComponentHttpKernelHttpKernel;
// ...
$dispatcher = new EventDispatcher();
// Controller creates a response to send to the user.
$controller = new AppController($request, $tokenStorage);
$controllerResolver = new AppControllerResolver(
['/^/front/login$/' => [$controller, 'loginFormAction']],
[$controller, 'defaultAction']
);
// Kernel is in charge of converting a Request into a Response by using the event dispatcher.
$kernel = new HttpKernel($dispatcher, $controllerResolver);
// ...
41. 41Formulaire de connexion
Context security listener :
// public/index.php
use SymfonyComponentSecurityHttpFirewallContextListener;
// ...
// ContextListener retrieves previously authenticated token from the session during REQUEST event.
// It also saves token during RESPONSE event.
$contextListener = new ContextListener(
$tokenStorage, [$mainUserProvider], 'front', null, $dispatcher
);
// ...
42. 42Formulaire de connexion
use SymfonyComponentSecurityHttpAuthenticationDefaultAuthenticationSuccessHandler;
use SymfonyComponentSecurityHttpAuthenticationDefaultAuthenticationFailureHandler;
use SymfonyComponentSecurityHttpFirewallUsernamePasswordFormAuthenticationListener;
use SymfonyComponentSecurityHttpSessionSessionAuthenticationStrategy;
$sessionAuthenticationStrategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE);
$successHandler = new DefaultAuthenticationSuccessHandler(
$httpUtils, ['default_target_path' => '/front/success’]
);
$failureHandler = new DefaultAuthenticationFailureHandler(
$kernel, $httpUtils, ['login_path' => '/front/login’]
);
// Listens for login form being send (POST to '/front/login_check').
// It extracts credentials, creates token, authenticates it and puts it to the token storage.
$formAuthListener = new UsernamePasswordFormAuthenticationListener(
$tokenStorage,
$frontAuthProvider, // The same authentication provider as for HTTP basic (except 'key'='front').
$sessionAuthenticationStrategy,
$httpUtils,
'front',
$successHandler, // Redirect user to '/front/success' if credentials are valid
$failureHandler, // Redirect user to '/front/login' if credentials are invalid
['check_path' => '/front/login_check', 'post_only' => true] // Act only on POST to '/front/login_check'
);
43. 43Formulaire de connexion
Ajout de security listeners dans le Firewall :
// public/index.php
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpFirewallMap;
use SymfonyComponentSecurityHttpFirewall;
// ...
// Create firewall map
$firewallMap = new FirewallMap();
// Add basic http security listener under URLs starting with "/main".
$firewallMap->add(
new RequestMatcher('^/main'), [$mainSecurityListener, $accessListener], $mainExceptionListener
);
// Add login form security listeners under URLs starting with "/front".
$firewallMap->add(new RequestMatcher('^/front'), [$contextListener, $formAuthListener]);
// Create firewall and add it to dispatcher.
$firewall = new Firewall($firewallMap, $dispatcher);
$dispatcher->addSubscriber($firewall);
// ...
44. SymfonyComponentSecurityCoreAuthorization
44Formulaire de connexion
Vérifier les rôles d’utilisateurs avant de les autoriser à accéder
aux certains URLs.Tâche 8
- voters : VoterInterface[]
+ decide($token, $attributes, $object)
AuthorizationChecker
- tokenStorage
- accessDecisionManager
+ isGranted($attributes, $object)
AccessDecisionManager
Voter
+ vote($token, $subject, $attributes)
VoterInterface
RoleVoter AuthenticatedVoter
ROLE_*
IS_AUTHENTICATED_FULLY
IS_AUTHENTICATED_REMEMBERED
IS_AUTHENTICATED_ANONYMOUSLY
45. SymfonyComponentSecurityHttp
45Formulaire de connexion
AccessMap
+ add($requestMatcher, $attributes, $channel)
+ getPatterns(Request $request): array
- map: array
# config/security.yaml
security:
access_control:
- { path: ^/main, roles: ROLE_SCIENTIST }
- { path: ^/front/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/front, roles: ROLE_EMPLOYER }
// public/index.php
// Access map defines authorization rules, it maps request to attributes.
// It helps access listeners to determine the attributes the user must possess.
$accessMap = new AccessMap();
$accessMap->add(new RequestMatcher('^/main'), ['ROLE_SCIENTIST']);
$accessMap->add(new RequestMatcher('^/front/login$'), ['IS_AUTHENTICATED_ANONYMOUSLY']);
$accessMap->add(new RequestMatcher('^/front'), ['ROLE_EMPLOYER’]);
//...
Access map renvoi les attributs que l’utilisateur doit posséder :
46. 46Formulaire de connexion
AccessListener
+ handle(GetResponseEvent $event)
- tokenStorage
- authManager
- accessDecisionManager
- map
Access map renvoi les attributs que l’utilisateur doit posséder :
SymfonyComponentSecurityHttp
AccessMapInterface
+ getPatterns(Request $request): array
SymfonyComponentSecurityCoreAuthorization
+ decide($token, $attributes, $object)
AccessDecisionManager
47. 47Formulaire de connexion
// public/index.php
use SymfonyComponentSecurityCoreAuthorizationVoterAuthenticatedVoter;
use SymfonyComponentSecurityCoreAuthorizationVoterRoleVoter;
use SymfonyComponentSecurityCoreAuthorizationAccessDecisionManager;
// ...
// RoleVoter can determine if authenticated user has necessary roles
// like 'ROLE_SCIENTIST' or 'ROLE_EMPLOYER'.
$roleVoter = new RoleVoter();
// AuthenticatedVoter can determine if token is anonymous or fully authentified.
$authenticatedVoter = new AuthenticatedVoter($authTrustResolver);
// Access decision manager verifies authorisation of authentified token thanks to voters.
$accessDecisionManager = new AccessDecisionManager([$roleVoter, $authenticatedVoter]);
// ...
48. 48Formulaire de connexion
// public/index.php
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpAccessMap;
use SymfonyComponentSecurityCoreUserInMemoryUserProvider;
// Access map defines authorization rules, it maps request to attributes.
// It helps access listeners to determine the attributes the user must possess.
$accessMap = new AccessMap();
$accessMap->add(new RequestMatcher('^/main'), ['ROLE_SCIENTIST']);
$accessMap->add(new RequestMatcher('^/front/login$'), ['IS_AUTHENTICATED_ANONYMOUSLY']);
$accessMap->add(new RequestMatcher('^/front'), ['ROLE_EMPLOYER']);
// Create user provider that will be used by authentication listener.
$mainUserProvider = new InMemoryUserProvider([
'gordon' => [
'password' => '$2y$10$50MJW4ov/LHLBdl6uYsxI.7MdWYoJ8K1MqBXfG677nOXbsSVVue6i',
'roles' => ['ROLE_SCIENTIST'],
],
'g-man' => [
'password' => '$2y$10$.23HMg6E0qsMXYcscJyJBOVFzSC31aWY8wd3CHJeO86dRljos0zie',
'roles' => ['ROLE_EMPLOYER'],
],
]);
// ...
49. 49Formulaire de connexion
// public/index.php
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpFirewallAccessListener;
// ...
// Access listener will throw an exception when no token is already present.
$mainAccessListener = new AccessListener(
$tokenStorage, $accessDecisionManager, $accessMap, $mainAuthProvider
);
// Add basic http security listener under URLs starting with "/main".
$firewallMap->add(
new RequestMatcher('^/main’),
[$mainSecurityListener, $mainAccessListener],
$mainExceptionListener
);
// ...
50. 50Formulaire de connexion
// public/index.php
use SymfonyComponentHttpFoundationRequestMatcher;
use SymfonyComponentSecurityHttpFirewallAccessListener;
// ...
// Access listener will throw an exception when no token is already present.
$frontAccessListener = new AccessListener(
$tokenStorage, $accessDecisionManager, $accessMap, $frontAuthProvider
);
// Add login form security listeners under URLs starting with "/front".
$firewallMap->add(
new RequestMatcher('^/front’),
[$contextListener, $formAuthListener, $frontAnonListener, $frontAccessListener],
$frontExceptionListener
);
// ...
51. Merci pour votre attention
Le code de cette présentation :
https://github.com/vria/symfony-security-component-use