Skip to content

Commit

Permalink
feature #4188 Updated documentation regarding the SecurityContext spl…
Browse files Browse the repository at this point in the history
…it (iltar)

This PR was submitted for the master branch but it was merged into the 2.6 branch instead (closes #4188).

Discussion
----------

Updated documentation regarding the SecurityContext split

| Q             | A
| ------------- | ---
| Doc fix?      | yes
| New docs?     | no
| Applies to    | >=2.6
| Fixed tickets | symfony/symfony#11690

This PR is to update the documentation regarding my PR on symfony/symfony. I require some feedback regarding:
 - Code Examples, I did not change *all* examples because the class using the `$securityContext` was not updated in my PR as it's Backwards Compatible
 - The usage of "security context". The term is correct, but it might get really confusing for people who see that the security context is deprecated. However, this is only regarding the `SecurityContext`, `SecurityContextInterface` and `@security.context`.
 - The above point is what confused me too so the docs might be out of context in certain spots, please review this thoroughly

Commits
-------

deff25f Updated documentation regarding the SecurityContext split; symfony/symfony#11690
  • Loading branch information
weaverryan committed Dec 7, 2014
2 parents 5ef52ee + deff25f commit 5363542
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 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.

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

Please sign in to comment.