Skip to content

Commit

Permalink
Updated documentation regarding the SecurityContext split; symfony/sy…
Browse files Browse the repository at this point in the history
  • Loading branch information
Iltar van der Berg committed Nov 24, 2014
1 parent 51224e9 commit 14ce4c7
Show file tree
Hide file tree
Showing 14 changed files with 168 additions and 99 deletions.
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 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 @@ -1621,14 +1625,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 @@ -1898,13 +1906,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 @@ -1928,7 +1940,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 @@ -1937,6 +1949,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 @@ -1982,10 +1998,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 @@ -1166,6 +1166,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.

.. 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`
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

0 comments on commit 14ce4c7

Please sign in to comment.