From 1ba825919c78aa948a1736ead3e746a6021b0681 Mon Sep 17 00:00:00 2001 From: Benjamin Clay Date: Sat, 29 Nov 2014 14:02:10 +0100 Subject: [PATCH] feature #4511 [Security] update security context to token storage and authorization checker --- book/security.rst | 14 ++++++------ components/security/authentication.rst | 12 +++++----- components/security/authorization.rst | 17 +++++++------- components/security/firewall.rst | 22 +++++++++++-------- .../custom_authentication_provider.rst | 14 ++++++------ cookbook/security/securing_services.rst | 22 +++++++++---------- cookbook/security/voters_data_permission.rst | 6 ++--- reference/dic_tags.rst | 2 +- 8 files changed, 57 insertions(+), 52 deletions(-) diff --git a/book/security.rst b/book/security.rst index c26108826d2..c9c52ecc405 100644 --- a/book/security.rst +++ b/book/security.rst @@ -438,7 +438,7 @@ Next, create the controller that will display the login form:: use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\Security\Core\SecurityContextInterface; + use Symfony\Component\Security\Core\Security; class SecurityController extends Controller { @@ -447,19 +447,19 @@ Next, create the controller that will display the login form:: $session = $request->getSession(); // get the login error if there is one - if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { + if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) { $error = $request->attributes->get( - SecurityContextInterface::AUTHENTICATION_ERROR + Security::AUTHENTICATION_ERROR ); - } elseif (null !== $session && $session->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { - $error = $session->get(SecurityContextInterface::AUTHENTICATION_ERROR); - $session->remove(SecurityContextInterface::AUTHENTICATION_ERROR); + } elseif (null !== $session && $session->has(Security::AUTHENTICATION_ERROR)) { + $error = $session->get(Security::AUTHENTICATION_ERROR); + $session->remove(Security::AUTHENTICATION_ERROR); } else { $error = ''; } // last username entered by the user - $lastUsername = (null === $session) ? '' : $session->get(SecurityContextInterface::LAST_USERNAME); + $lastUsername = (null === $session) ? '' : $session->get(Security::LAST_USERNAME); return $this->render( 'AcmeSecurityBundle:Security:login.html.twig', diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 01841b5bb4a..a699e709ba0 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -10,10 +10,10 @@ firewall map is able to extract the user's credentials from the current a token, containing these credentials. The next thing the listener should do is ask the authentication manager to validate the given token, and return an *authenticated* token if the supplied credentials were found to be valid. -The listener should then store the authenticated token in the security context:: +The listener should then store the authenticated token in the token storage:: use Symfony\Component\Security\Http\Firewall\ListenerInterface; - use Symfony\Component\Security\Core\SecurityContextInterface; + use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; @@ -21,9 +21,9 @@ The listener should then store the authenticated token in the security context:: class SomeAuthenticationListener implements ListenerInterface { /** - * @var SecurityContextInterface + * @var TokenStorageInterface */ - private $securityContext; + private $tokenStorage; /** * @var AuthenticationManagerInterface @@ -54,7 +54,7 @@ The listener should then store the authenticated token in the security context:: ->authenticationManager ->authenticate($unauthenticatedToken); - $this->securityContext->setToken($authenticatedToken); + $this->tokenStorage->setToken($authenticatedToken); } } @@ -257,7 +257,7 @@ in) is correct, you can use:: // fetch the Acme\Entity\LegacyUser $user = ...; - + // the submitted password, e.g. from the login form $plainPassword = ...; diff --git a/components/security/authorization.rst b/components/security/authorization.rst index c5b357e5118..bb20dd50acd 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -7,8 +7,8 @@ Authorization When any of the authentication providers (see :ref:`authentication_providers`) has verified the still-unauthenticated token, an authenticated token will be returned. The authentication listener should set this token directly -in the :class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface` -using its :method:`Symfony\\Component\\Security\\Core\\SecurityContextInterface::setToken` +in the :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorage` +using its :method:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorage::setToken` method. From then on, the user is authenticated, i.e. identified. Now, other parts @@ -227,23 +227,24 @@ are required for the current user to get access to the application:: $authenticationManager ); -Security Context +Authorization Checker ~~~~~~~~~~~~~~~~ The access decision manager is also available to other parts of the application -via the :method:`Symfony\\Component\\Security\\Core\\SecurityContext::isGranted` -method of the :class:`Symfony\\Component\\Security\\Core\\SecurityContext`. +via the :method:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationChecker::isGranted` +method of the :class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationChecker`. A call to this method will directly delegate the question to the access decision manager:: - use Symfony\Component\Security\SecurityContext; + use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; use Symfony\Component\Security\Core\Exception\AccessDeniedException; - $securityContext = new SecurityContext( + $authorizationChecker = new AuthorizationChecker( + $tokenStorage, $authenticationManager, $accessDecisionManager ); - if (!$securityContext->isGranted('ROLE_ADMIN')) { + if (!$authorizationChecker->isGranted('ROLE_ADMIN')) { throw new AccessDeniedException(); } diff --git a/components/security/firewall.rst b/components/security/firewall.rst index 8d30debff6e..4c4817c1a63 100644 --- a/components/security/firewall.rst +++ b/components/security/firewall.rst @@ -1,16 +1,16 @@ .. index:: single: Security, Firewall -The Firewall and Security Context -================================= +The Firewall and Authorization Checker +====================================== -Central to the Security component is the security context, which is an instance -of :class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface`. When all +The Security component has an Authorization Checker, which is an instance +of :class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface`. When all steps in the process of authenticating the user have been taken successfully, -you can ask the security context if the authenticated user has access to a +you can ask the authorization checker if the authenticated user has access to a certain action or resource of the application:: - use Symfony\Component\Security\Core\SecurityContext; + use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; use Symfony\Component\Security\Core\Exception\AccessDeniedException; // instance of Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface @@ -19,14 +19,18 @@ certain action or resource of the application:: // instance of Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface $accessDecisionManager = ...; - $securityContext = new SecurityContext( + // instance of Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface + $tokenStorage = ...; + + $authorizationChecker = new AuthorizationChecker( + $tokenStorage, $authenticationManager, $accessDecisionManager ); // ... authenticate the user - if (!$securityContext->isGranted('ROLE_ADMIN')) { + if (!$authorizationChecker->isGranted('ROLE_ADMIN')) { throw new AccessDeniedException(); } @@ -115,7 +119,7 @@ which will eventually result in an "HTTP/1.1 403: Access Denied" response. Entry Points ~~~~~~~~~~~~ -When the user is not authenticated at all (i.e. when the security context +When the user is not authenticated at all (i.e. when the token storage has no token yet), the firewall's entry point will be called to "start" the authentication process. An entry point should implement :class:`Symfony\\Component\\Security\\Http\\EntryPoint\\AuthenticationEntryPointInterface`, diff --git a/cookbook/security/custom_authentication_provider.rst b/cookbook/security/custom_authentication_provider.rst index 4232c04ba32..37f736c9583 100644 --- a/cookbook/security/custom_authentication_provider.rst +++ b/cookbook/security/custom_authentication_provider.rst @@ -113,18 +113,18 @@ set an authenticated token in the security context if successful. use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Http\Firewall\ListenerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; - use Symfony\Component\Security\Core\SecurityContextInterface; + use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Acme\DemoBundle\Security\Authentication\Token\WsseUserToken; class WsseListener implements ListenerInterface { - protected $securityContext; + protected $tokenStorage; protected $authenticationManager; - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager) { - $this->securityContext = $securityContext; + $this->tokenStorage = $tokenStorage; $this->authenticationManager = $authenticationManager; } @@ -146,7 +146,7 @@ set an authenticated token in the security context if successful. try { $authToken = $this->authenticationManager->authenticate($token); - $this->securityContext->setToken($authToken); + $this->tokenStorage->setToken($authToken); return; } catch (AuthenticationException $failed) { @@ -154,9 +154,9 @@ set an authenticated token in the security context if successful. // To deny the authentication clear the token. This will redirect to the login page. // Make sure to only clear your token, not those of other authentication listeners. - // $token = $this->securityContext->getToken(); + // $token = $this->tokenStorage->getToken(); // if ($token instanceof WsseUserToken && $this->providerKey === $token->getProviderKey()) { - // $this->securityContext->setToken(null); + // $this->tokenStorage->setToken(null); // } // return; } diff --git a/cookbook/security/securing_services.rst b/cookbook/security/securing_services.rst index 641a43f04ec..ad5aa4533d4 100644 --- a/cookbook/security/securing_services.rst +++ b/cookbook/security/securing_services.rst @@ -45,23 +45,23 @@ role. Before you add security, the class looks something like this: } Your goal is to check the user's role when the ``sendNewsletter()`` method is -called. The first step towards this is to inject the ``security.context`` +called. The first step towards this is to inject the ``security.authorization_checker`` service into the object. Since it won't make sense *not* to perform the security check, this is an ideal candidate for constructor injection, which guarantees -that the security context object will be available inside the ``NewsletterManager`` +that the authorization checker object will be available inside the ``NewsletterManager`` class:: namespace Acme\HelloBundle\Newsletter; - use Symfony\Component\Security\Core\SecurityContextInterface; + use Symfony\Component\Security\Core\AuthorizationCheckerInterface; class NewsletterManager { - protected $securityContext; + protected $authorizationChecker; - public function __construct(SecurityContextInterface $securityContext) + public function __construct(AuthorizationCheckerInterface $securityContext) { - $this->securityContext = $securityContext; + $this->authorizationChecker = $authorizationChecker; } // ... @@ -114,21 +114,21 @@ The injected service can then be used to perform the security check when the namespace Acme\HelloBundle\Newsletter; use Symfony\Component\Security\Core\Exception\AccessDeniedException; - use Symfony\Component\Security\Core\SecurityContextInterface; + use Symfony\Component\Security\Core\AuthorizationCheckerInterface; // ... class NewsletterManager { - protected $securityContext; + protected $authorizationChecker; - public function __construct(SecurityContextInterface $securityContext) + public function __construct(AuthorizationCheckerInterface $authorizationChecker) { - $this->securityContext = $securityContext; + $this->authorizationChecker = $authorizationChecker; } public function sendNewsletter() { - if (false === $this->securityContext->isGranted('ROLE_NEWSLETTER_ADMIN')) { + if (false === $this->authorizationChecker->isGranted('ROLE_NEWSLETTER_ADMIN')) { throw new AccessDeniedException(); } diff --git a/cookbook/security/voters_data_permission.rst b/cookbook/security/voters_data_permission.rst index 0238ee5e4ce..652f30423d9 100644 --- a/cookbook/security/voters_data_permission.rst +++ b/cookbook/security/voters_data_permission.rst @@ -25,7 +25,7 @@ How Symfony Uses Voters In order to use voters, you have to understand how Symfony works with them. All voters are called each time you use the ``isGranted()`` method on Symfony's -security context (i.e. the ``security.context`` service). Each one decides +authorization checker (i.e. the ``security.authorization_checker`` service). Each one decides if the current user should have access to some resource. Ultimately, Symfony uses one of three different approaches on what to do @@ -194,7 +194,7 @@ How to Use the Voter in a Controller ------------------------------------ The registered voter will then always be asked as soon as the method ``isGranted()`` -from the security context is called. +from the authorization checker is called. .. code-block:: php @@ -213,7 +213,7 @@ from the security context is called. $post = ...; // keep in mind, this will call all registered security voters - if (false === $this->get('security.context')->isGranted('view', $post)) { + if (false === $this->get('security.authorization_checker')->isGranted('view', $post)) { throw new AccessDeniedException('Unauthorised access!'); } diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 87774a94f44..8a58ff4e8b1 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -933,7 +933,7 @@ security.voter **Purpose**: To add a custom voter to Symfony's authorization logic -When you call ``isGranted`` on Symfony's security context, a system of "voters" +When you call ``isGranted`` on Symfony's authorization checker, a system of "voters" is used behind the scenes to determine if the user should have access. The ``security.voter`` tag allows you to add your own custom voter to that system.