Skip to content

feature #4511 [Security][HackDay] update security context to token storage and authorization checker #4541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions book/security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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',
Expand Down
12 changes: 6 additions & 6 deletions components/security/authentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ 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;

class SomeAuthenticationListener implements ListenerInterface
{
/**
* @var SecurityContextInterface
* @var TokenStorageInterface
*/
private $securityContext;
private $tokenStorage;

/**
* @var AuthenticationManagerInterface
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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 = ...;

Expand Down
17 changes: 9 additions & 8 deletions components/security/authorization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
}
22 changes: 13 additions & 9 deletions components/security/firewall.rst
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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();
}

Expand Down Expand Up @@ -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`,
Expand Down
14 changes: 7 additions & 7 deletions cookbook/security/custom_authentication_provider.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -146,17 +146,17 @@ 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) {
// ... you might log something here

// 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;
}
Expand Down
22 changes: 11 additions & 11 deletions cookbook/security/securing_services.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

// ...
Expand Down Expand Up @@ -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();
}

Expand Down
6 changes: 3 additions & 3 deletions cookbook/security/voters_data_permission.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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!');
}

Expand Down
2 changes: 1 addition & 1 deletion reference/dic_tags.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down