Skip to content

Updated documentation regarding the SecurityContext split #4188

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
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
48 changes: 32 additions & 16 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 Expand Up @@ -713,7 +713,7 @@ see :doc:`/cookbook/security/form_login`.
``/login_check`` doesn't match any firewall, you'll receive a ``Unable
to find the controller for path "/login_check"`` exception.

**4. Multiple firewalls don't share security context**
**4. Multiple firewalls don't share the same security context**

If you're using multiple firewalls and you authenticate against one firewall,
you will *not* be authenticated against any other firewalls automatically.
Expand Down Expand Up @@ -1174,7 +1174,7 @@ authorization from inside a controller::

public function helloAction($name)
{
if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) {
if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
throw $this->createAccessDeniedException('Unable to access this page!');
}

Expand All @@ -1186,6 +1186,10 @@ authorization from inside a controller::
.. versionadded:: 2.5
The ``createAccessDeniedException`` method was introduced in Symfony 2.5.

.. versionadded:: 2.6
The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior
to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service.

The :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::createAccessDeniedException`
method creates a special :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException`
object, which ultimately triggers a 403 HTTP response inside Symfony.
Expand Down Expand Up @@ -1618,14 +1622,18 @@ Retrieving the User Object
~~~~~~~~~~~~~~~~~~~~~~~~~~

After authentication, the ``User`` object of the current user can be accessed
via the ``security.context`` service. From inside a controller, this will
via the ``security.token_storage`` service. From inside a controller, this will
look like::

public function indexAction()
{
$user = $this->get('security.context')->getToken()->getUser();
$user = $this->get('security.token_storage')->getToken()->getUser();
}

.. versionadded:: 2.6
The ``security.token_storage`` service was introduced in Symfony 2.6. Prior
to Symfony 2.6, you had to use the ``getToken()`` method of the ``security.context`` service.

In a controller this can be shortcut to:

.. code-block:: php
Expand Down Expand Up @@ -1895,13 +1903,17 @@ authorization from inside a controller::

public function helloAction($name)
{
if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) {
if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
throw new AccessDeniedException();
}

// ...
}

.. versionadded:: 2.6
The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior
to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service.

.. caution::

A firewall must be active or an exception will be thrown when the ``isGranted()``
Expand All @@ -1925,7 +1937,7 @@ accepts an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` object::

public function indexAction()
{
if (!$this->get('security.context')->isGranted(new Expression(
if (!$this->get('security.authorization_checker')->isGranted(new Expression(
'"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())'
))) {
throw new AccessDeniedException();
Expand All @@ -1934,6 +1946,10 @@ accepts an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` object::
// ...
}

.. versionadded:: 2.6
The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior
to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service.

In this example, if the current user has ``ROLE_ADMIN`` or if the current
user object's ``isSuperAdmin()`` method returns ``true``, then access will
be granted (note: your User object may not have an ``isSuperAdmin`` method,
Expand Down Expand Up @@ -1979,10 +1995,10 @@ Additionally, you have access to a number of functions inside the expression:
use Symfony\Component\ExpressionLanguage\Expression;
// ...

$sc = $this->get('security.context');
$access1 = $sc->isGranted('IS_AUTHENTICATED_REMEMBERED');
$authorizationChecker = $this->get('security.authorization_checker');
$access1 = $authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED');

$access2 = $sc->isGranted(new Expression(
$access2 = $authorizationChecker->isGranted(new Expression(
'is_remember_me() or is_fully_authenticated()'
));

Expand Down
6 changes: 6 additions & 0 deletions book/templating.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,12 @@ automatically:
<p>Application Environment: <?php echo $app->getEnvironment() ?></p>
<?php endif ?>

.. versionadded:: 2.6
The global ``app.security`` variable (or the ``$app->getSecurity()``
method in PHP templates) is deprecated as of Symfony 2.6. Use `app.user`
(`$app->getUser()`) and `is_granted()` (`$view['security']->isGranted()`)
instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean with security context? And I don't get the location of this directive

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It refers to the app.security available as twig global, maybe I should add that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I would use "app.security global" (and PHP's alternative) instead of "security context".

Btw, don't forget to update reference/twig_reference.rst in that case.

.. tip::

You can add your own global template variables. See the cookbook example
Expand Down
16 changes: 11 additions & 5 deletions components/security/authentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,32 @@
Authentication
==============

.. versionadded:: 2.6
The ``TokenStorageInterface`` was introduced in Symfony 2.6. Prior, you
had to use the ``getToken()`` method of the
:class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface`.

When a request points to a secured area, and one of the listeners from the
firewall map is able to extract the user's credentials from the current
:class:`Symfony\\Component\\HttpFoundation\\Request` object, it should create
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 using
:class:`the token storage <Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface>`::

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 +60,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
24 changes: 15 additions & 9 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\\TokenStorageInterface`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a versionadded directive for the token storage in this document too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added one just below the list

using its :method:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface::setToken`
method.

From then on, the user is authenticated, i.e. identified. Now, other parts
Expand All @@ -29,6 +29,11 @@ An authorization decision will always be based on a few things:
Any object for which access control needs to be checked, like
an article or a comment object.

.. versionadded:: 2.6
The ``TokenStorageInterface`` was introduced in Symfony 2.6. Prior, you
had to use the ``setToken()`` method of the
:class:`Symfony\\Component\\Security\\Core\\SecurityContextInterface`.

.. _components-security-access-decision-manager:

Access Decision Manager
Expand Down Expand Up @@ -227,23 +232,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();
}
7 changes: 6 additions & 1 deletion components/security/firewall.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ certain action or resource of the application::
throw new AccessDeniedException();
}

.. versionadded:: 2.6
As of Symfony 2.6, the :class:`Symfony\\Component\\Security\\Core\\SecurityContext` class was split
in the :class:`Symfony\\Component\\Security\\Core\\Authentication\\Authorization\\AuthorizationChecker` and
:class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorage` classes.

.. note::

Read the dedicated sections to learn more about :doc:`/components/security/authentication`
Expand Down Expand Up @@ -115,7 +120,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
Loading