Skip to content

Commit d5fe901

Browse files
committedJan 2, 2014
Merge branch '2.4'
2 parents 8735384 + 1c927a6 commit d5fe901

File tree

5 files changed

+457
-65
lines changed

5 files changed

+457
-65
lines changed
 

‎components/dom_crawler.rst‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,14 @@ explicitly.
106106

107107
Consider the XML below:
108108

109+
.. code-block:: xml
110+
109111
<?xml version="1.0" encoding="UTF-8"?>
110112
<entry
111-
xmlns="http://www.w3.org/2005/Atom"
112-
xmlns:media="http://search.yahoo.com/mrss/"
113-
xmlns:yt="http://gdata.youtube.com/schemas/2007">
113+
xmlns="http://www.w3.org/2005/Atom"
114+
xmlns:media="http://search.yahoo.com/mrss/"
115+
xmlns:yt="http://gdata.youtube.com/schemas/2007"
116+
>
114117
<id>tag:youtube.com,2008:video:kgZRZmEc9j4</id>
115118
<yt:accessControl action="comment" permission="allowed"/>
116119
<yt:accessControl action="videoRespond" permission="moderated"/>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
After Symfony calls ``createToken()``, it will then call ``supportsToken()``
2+
on your class (and any other authentication listeners) to figure out who should
3+
handle the token. This is just a way to allow several authentication mechanisms
4+
to be used for the same firewall (that way, you can for instance first try
5+
to authenticate the user via a certificate or an API key and fall back to
6+
a form login).
7+
8+
Mostly, you just need to make sure that this method returns ``true`` for a
9+
token that has been created by ``createToken()``. Your logic should probably
10+
look exactly like this example.

‎cookbook/security/api_key_authentication.rst‎

Lines changed: 366 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ How to Authenticate Users with API Keys
66

77
Nowadays, it's quite usual to authenticate the user via an API key (when developing
88
a web service for instance). The API key is provided for every request and is
9-
passed as a query string parameter or via a HTTP header.
9+
passed as a query string parameter or via an HTTP header.
1010

1111
The API Key Authenticator
1212
-------------------------
@@ -16,7 +16,11 @@ The API Key Authenticator
1616

1717
Authenticating a user based on the Request information should be done via a
1818
pre-authentication mechanism. The :class:`Symfony\\Component\\Security\\Core\\Authentication\\SimplePreAuthenticatorInterface`
19-
interface allows to implement such a scheme really easily::
19+
allows you to implement such a scheme really easily.
20+
21+
Your exact situation may differ, but in this example, a token is read
22+
from an ``apikey`` query parameter, the proper username is loaded from that
23+
value and then a User object is created::
2024

2125
// src/Acme/HelloBundle/Security/ApiKeyAuthenticator.php
2226
namespace Acme\HelloBundle\Security;
@@ -26,7 +30,6 @@ interface allows to implement such a scheme really easily::
2630
use Symfony\Component\Security\Core\Exception\AuthenticationException;
2731
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
2832
use Symfony\Component\HttpFoundation\Request;
29-
use Symfony\Component\Security\Core\User\User;
3033
use Symfony\Component\Security\Core\User\UserProviderInterface;
3134
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
3235
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
@@ -55,22 +58,20 @@ interface allows to implement such a scheme really easily::
5558

5659
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
5760
{
58-
$apikey = $token->getCredentials();
59-
if (!$this->userProvider->getUsernameForApiKey($apikey)) {
61+
$apiKey = $token->getCredentials();
62+
$username = $this->userProvider->getUsernameForApiKey($apiKey)
63+
64+
if (!$username) {
6065
throw new AuthenticationException(
61-
sprintf('API Key "%s" does not exist.', $apikey)
66+
sprintf('API Key "%s" does not exist.', $apiKey)
6267
);
6368
}
6469

65-
$user = new User(
66-
$this->userProvider->getUsernameForApiKey($apikey),
67-
$apikey,
68-
array('ROLE_USER')
69-
);
70+
$user = $this->userProvider->loadUserByUsername($username);
7071

7172
return new PreAuthenticatedToken(
7273
$user,
73-
$apikey,
74+
$apiKey,
7475
$providerKey,
7576
$user->getRoles()
7677
);
@@ -82,31 +83,143 @@ interface allows to implement such a scheme really easily::
8283
}
8384
}
8485

85-
``$userProvider`` can be any user provider implementing an interface similar to
86-
this::
86+
Once you've :ref:`configured <cookbook-security-api-key-config>` everything,
87+
you'll be able to authenticate by adding an apikey parameter to the query
88+
string, like ``http://example.com/admin/foo?apikey=37b51d194a7513e45b56f6524f2d51f2``.
89+
90+
The authentication process has several steps, and your implementation will
91+
probably differ:
92+
93+
1. createToken
94+
~~~~~~~~~~~~~~
95+
96+
Early in the request cycle, Symfony calls ``createToken()``. Your job here
97+
is to create a token object that contains all of the information from the
98+
request that you need to authenticate the user (e.g. the ``apikey`` query
99+
parameter). If that information is missing, throwing a
100+
:class:`Symfony\\Component\\Security\\Core\\Exception\\BadCredentialsException`
101+
will cause authentication to fail.
102+
103+
2. supportsToken
104+
~~~~~~~~~~~~~~~~
105+
106+
.. include:: _supportsToken.rst.inc
107+
108+
3. authenticateToken
109+
~~~~~~~~~~~~~~~~~~~~
87110

88-
// src/Acme/HelloBundle/Security/ApiKeyUserProviderInterface.php
111+
If ``supportsToken()`` returns ``true``, Symfony will now call ``authenticateToken()``.
112+
One key part is the ``$userProvider``, which is an external class that helps
113+
you load information about the user. You'll learn more about this next.
114+
115+
In this specific example, the following things happen in ``authenticateToken()``:
116+
117+
#. First, you use the ``$userProvider`` to somehow look up the ``$username`` that
118+
corresponds to the ``$apiKey``;
119+
#. Second, you use the ``$userProvider`` again to load or create a ``User``
120+
object for the ``$username``;
121+
#. Finally, you create an *authenticated token* (i.e. a token with at least one
122+
role) that has the proper roles and the User object attached to it.
123+
124+
The goal is ultimately to use the ``$apiKey`` to find or create a ``User``
125+
object. *How* you do this (e.g. query a database) and the exact class for
126+
your ``User`` object may vary. Those differences will be most obvious in your
127+
user provider.
128+
129+
The User Provider
130+
~~~~~~~~~~~~~~~~~
131+
132+
The ``$userProvider`` can be any user provider (see :doc:`/cookbook/security/custom_provider`).
133+
In this example, the ``$apiKey`` is used to somehow find the username for
134+
the user. This work is done in a ``getUsernameForApiKey()`` method, which
135+
is created entirely custom for this use-case (i.e. this isn't a method that's
136+
used by Symfony's core user provider system).
137+
138+
The ``$userProvider`` might look something like this::
139+
140+
// src/Acme/HelloBundle/Security/ApiKeyUserProvider.php
89141
namespace Acme\HelloBundle\Security;
90142

91143
use Symfony\Component\Security\Core\User\UserProviderInterface;
144+
use Symfony\Component\Security\Core\User\User;
145+
use Symfony\Component\Security\Core\User\UserInterface;
146+
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
92147

93-
interface ApiKeyUserProviderInterface extends UserProviderInterface
148+
class ApiKeyUserProvider extends UserProviderInterface
94149
{
95-
public function getUsernameForApiKey($apikey);
150+
public function getUsernameForApiKey($apiKey)
151+
{
152+
// Look up the username based on the token in the database, via
153+
// an API call, or do something entirely different
154+
$username = ...;
155+
156+
return $username;
157+
}
158+
159+
public function loadUserByUsername($username)
160+
{
161+
return new User(
162+
$username,
163+
null,
164+
// the roles for the user - you may choose to determine
165+
// these dynamically somehow based on the user
166+
array('ROLE_USER')
167+
);
168+
}
169+
170+
public function refreshUser(UserInterface $user)
171+
{
172+
// this is used for storing authentication in the session
173+
// but in this example, the token is sent in each request,
174+
// so authentication can be stateless. Throwing this exception
175+
// is proper to make things stateless
176+
throw new UnsupportedUserException();
177+
}
178+
179+
public function supportsClass($class)
180+
{
181+
return 'Symfony\Component\Security\Core\User\User' === $class;
182+
}
96183
}
97184

98185
.. note::
99186

100187
Read the dedicated article to learn
101188
:doc:`how to create a custom user provider </cookbook/security/custom_provider>`.
102189

103-
To access a resource protected by such an authenticator, you need to add an apikey
104-
parameter to the query string, like in ``http://example.com/admin/foo?apikey=37b51d194a7513e45b56f6524f2d51f2``.
190+
The logic inside ``getUsernameForApiKey()`` is up to you. You may somehow transform
191+
the API key (e.g. ``37b51d``) into a username (e.g. ``jondoe``) by looking
192+
up some information in a "token" database table.
193+
194+
The same is true for ``loadUserByUsername()``. In this example, Symfony's core
195+
:class:`Symfony\\Component\\Security\\Core\\User\\User` class is simply created.
196+
This makes sense if you don't need to store any extra information on your
197+
User object (e.g. ``firstName``). But if you do, you may instead have your *own*
198+
user class which you create and populate here by querying a database. This
199+
would allow you to have custom data on the ``User`` object.
200+
201+
Finally, just make sure that ``supportsClass()`` returns ``true`` for User
202+
objects with the same class as whatever user you return in ``loadUserByUsername()``.
203+
If your authentication is stateless like in this example (i.e. you expect
204+
the user to send the API key with every request and so you don't save the
205+
login to the session), then you can simply throw the ``UnsupportedUserException``
206+
exception in ``refreshUser()``.
207+
208+
.. note::
209+
210+
If you *do* want to store authentication data in the session so that
211+
the key doesn't need to be sent on every request, see :ref:`cookbook-security-api-key-session`.
212+
213+
.. _cookbook-security-api-key-config:
105214

106215
Configuration
107216
-------------
108217

109-
Configure your ``ApiKeyAuthenticator`` as a service:
218+
Once you have your ``ApiKeyAuthentication`` all setup, you need to register
219+
it as a service and use it in your security configuration (e.g. ``security.yml``).
220+
First, register it as a service. This assumes that you have already setup
221+
your custom user provider as a service called ``your_api_key_user_provider``
222+
(see :doc:`/cookbook/security/custom_provider`).
110223

111224
.. configuration-block::
112225

@@ -118,7 +231,7 @@ Configure your ``ApiKeyAuthenticator`` as a service:
118231
119232
apikey_authenticator:
120233
class: Acme\HelloBundle\Security\ApiKeyAuthenticator
121-
arguments: [@your_api_key_user_provider]
234+
arguments: ["@your_api_key_user_provider"]
122235
123236
.. code-block:: xml
124237
@@ -152,20 +265,23 @@ Configure your ``ApiKeyAuthenticator`` as a service:
152265
array(new Reference('your_api_key_user_provider'))
153266
));
154267
155-
Then, activate it in your firewalls section using the ``simple-preauth`` key
156-
like this:
268+
Now, activate it in the ``firewalls`` section of your security configuration
269+
using the ``simple_preauth`` key:
157270

158271
.. configuration-block::
159272

160273
.. code-block:: yaml
161274
275+
# app/config/security.yml
162276
security:
163-
firewalls:
164-
secured_area:
165-
pattern: ^/admin
166-
simple-preauth:
167-
provider: ...
168-
authenticator: apikey_authenticator
277+
# ...
278+
279+
firewalls:
280+
secured_area:
281+
pattern: ^/admin
282+
stateless: true
283+
simple_preauth:
284+
authenticator: apikey_authenticator
169285
170286
.. code-block:: xml
171287
@@ -181,7 +297,7 @@ like this:
181297
182298
<firewall name="secured_area"
183299
pattern="^/admin"
184-
provider="..."
300+
stateless="true"
185301
>
186302
<simple-preauth authenticator="apikey_authenticator" />
187303
</firewall>
@@ -198,11 +314,228 @@ like this:
198314
'firewalls' => array(
199315
'secured_area' => array(
200316
'pattern' => '^/admin',
201-
'provider' => 'authenticator',
202-
'simple-preauth' => array(
203-
'provider' => ...,
317+
'stateless' => true,
318+
'simple_preauth' => array(
319+
'authenticator' => 'apikey_authenticator',
320+
),
321+
),
322+
),
323+
));
324+
325+
That's it! Now, your ``ApiKeyAuthentication`` should be called at the beginning
326+
of each request and your authentication process will take place.
327+
328+
The ``stateless`` configuration parameter prevents Symfony from trying to
329+
store the authentication information in the session, which isn't necessary
330+
since the client will send the ``apikey`` on each request. If you *do* need
331+
to store authentication in the session, keep reading!
332+
333+
.. _cookbook-security-api-key-session:
334+
335+
Storing Authentication in the Session
336+
-------------------------------------
337+
338+
So far, this entry has described a situation where some sort of authentication
339+
token is sent on every request. But in some situations (like an OAuth flow),
340+
the token may be sent on only *one* request. In this case, you will want to
341+
authenticate the user and store that authentication in the session so that
342+
the user is automatically logged in for every subsequent request.
343+
344+
To make this work, first remove the ``stateless`` key from your firewall
345+
configuration or set it to ``false``:
346+
347+
.. configuration-block::
348+
349+
.. code-block:: yaml
350+
351+
# app/config/security.yml
352+
security:
353+
# ...
354+
355+
firewalls:
356+
secured_area:
357+
pattern: ^/admin
358+
stateless: false
359+
simple_preauth:
360+
authenticator: apikey_authenticator
361+
362+
.. code-block:: xml
363+
364+
<!-- app/config/security.xml -->
365+
<?xml version="1.0" encoding="UTF-8"?>
366+
<srv:container xmlns="http://symfony.com/schema/dic/security"
367+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
368+
xmlns:srv="http://symfony.com/schema/dic/services"
369+
xsi:schemaLocation="http://symfony.com/schema/dic/services
370+
http://symfony.com/schema/dic/services/services-1.0.xsd">
371+
<config>
372+
<!-- ... -->
373+
374+
<firewall name="secured_area"
375+
pattern="^/admin"
376+
stateless="false"
377+
>
378+
<simple-preauth authenticator="apikey_authenticator" />
379+
</firewall>
380+
</config>
381+
</srv:container>
382+
383+
.. code-block:: php
384+
385+
// app/config/security.php
386+
387+
// ..
388+
$container->loadFromExtension('security', array(
389+
'firewalls' => array(
390+
'secured_area' => array(
391+
'pattern' => '^/admin',
392+
'stateless' => false,
393+
'simple_preauth' => array(
204394
'authenticator' => 'apikey_authenticator',
205395
),
206396
),
207397
),
208398
));
399+
400+
Storing authentication information in the session works like this:
401+
402+
#. At the end of each request, Symfony serializes the token object (returned
403+
from ``authenticateToken()``), which also serializes the ``User`` object
404+
(since it's set on a property on the token);
405+
#. On the next request the token is deserialized and the deserialized ``User``
406+
object is passed to the ``refreshUser()`` function of the user provider.
407+
408+
The second step is the important one: Symfony calls ``refreshUser()`` and passes
409+
you the user object that was serialized in the session. If your users are
410+
stored in the database, then you may want to re-query for a fresh version
411+
of the user to make sure it's not out-of-date. But regardless of your requirements,
412+
``refreshUser()`` should now return the User object::
413+
414+
// src/Acme/HelloBundle/Security/ApiKeyUserProvider.php
415+
416+
// ...
417+
class ApiKeyUserProvider extends UserProviderInterface
418+
{
419+
// ...
420+
421+
public function refreshUser(UserInterface $user)
422+
{
423+
// $user is the User that you set in the token inside authenticateToken()
424+
// after it has been deserialized from the session
425+
426+
// you might use $user to query the database for a fresh user
427+
// $id = $user->getId();
428+
// use $id to make a query
429+
430+
// if you are *not* reading from a database and are just creating
431+
// a User object (like in this example), you can just return it
432+
return $user;
433+
}
434+
}
435+
436+
.. note::
437+
438+
You'll also want to make sure that your ``User`` object is being serialized
439+
correctly. If your ``User`` object has private properties, PHP can't serialize
440+
those. In this case, you may get back a User object that has a ``null``
441+
value for each property. For an example, see :doc:`/cookbook/security/entity_provider`.
442+
443+
Only Authenticating for Certain URLs
444+
------------------------------------
445+
446+
This entry has assumed that you want to look for the ``apikey`` authentication
447+
on *every* request. But in some situations (like an OAuth flow), you only
448+
really need to look for authentication information once the user has reached
449+
a certain URL (e.g. the redirect URL in OAuth).
450+
451+
Fortunately, handling this situation is easy: just check to see what the
452+
current URL is before creating the token in ``createToken()``::
453+
454+
// src/Acme/HelloBundle/Security/ApiKeyAuthenticator.php
455+
456+
// ...
457+
use Symfony\Component\Security\Http\HttpUtils;
458+
use Symfony\Component\HttpFoundation\Request;
459+
460+
class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface
461+
{
462+
protected $userProvider;
463+
464+
protected $httpUtils;
465+
466+
public function __construct(ApiKeyUserProviderInterface $userProvider, HttpUtils $httpUtils)
467+
{
468+
$this->userProvider = $userProvider;
469+
$this->httpUtils = $httpUtils;
470+
}
471+
472+
public function createToken(Request $request, $providerKey)
473+
{
474+
// set the only URL where we should look for auth information
475+
// and only return the token if we're at that URL
476+
$targetUrl = '/login/check';
477+
if (!$this->httpUtils->checkRequestPath($request, $targetUrl)) {
478+
return;
479+
}
480+
481+
// ...
482+
}
483+
}
484+
485+
This uses the handy :class:`Symfony\\Component\\Security\\Http\\HttpUtils`
486+
class to check if the current URL matches the URL you're looking for. In this
487+
case, the URL (``/login/check``) has been hardcoded in the class, but you
488+
could also inject it as the third constructor argument.
489+
490+
Next, just update your service configuration to inject the ``security.http_utils``
491+
service:
492+
493+
.. configuration-block::
494+
495+
.. code-block:: yaml
496+
497+
# app/config/config.yml
498+
services:
499+
# ...
500+
501+
apikey_authenticator:
502+
class: Acme\HelloBundle\Security\ApiKeyAuthenticator
503+
arguments: ["@your_api_key_user_provider", "@security.http_utils"]
504+
505+
.. code-block:: xml
506+
507+
<!-- app/config/config.xml -->
508+
<?xml version="1.0" ?>
509+
<container xmlns="http://symfony.com/schema/dic/services"
510+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
511+
xsi:schemaLocation="http://symfony.com/schema/dic/services
512+
http://symfony.com/schema/dic/services/services-1.0.xsd">
513+
<services>
514+
<!-- ... -->
515+
516+
<service id="apikey_authenticator"
517+
class="Acme\HelloBundle\Security\ApiKeyAuthenticator"
518+
>
519+
<argument type="service" id="your_api_key_user_provider" />
520+
<argument type="service" id="security.http_utils" />
521+
</service>
522+
</services>
523+
</container>
524+
525+
.. code-block:: php
526+
527+
// app/config/config.php
528+
use Symfony\Component\DependencyInjection\Definition;
529+
use Symfony\Component\DependencyInjection\Reference;
530+
531+
// ...
532+
533+
$container->setDefinition('apikey_authenticator', new Definition(
534+
'Acme\HelloBundle\Security\ApiKeyAuthenticator',
535+
array(
536+
new Reference('your_api_key_user_provider'),
537+
new Reference('security.http_utils')
538+
)
539+
));
540+
541+
That's it! Have fun!

‎cookbook/security/custom_authentication_provider.rst‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
How to create a custom Authentication Provider
55
==============================================
66

7+
.. tip::
8+
9+
Creating a custom authentication system is hard, and this entry will walk
10+
you through that process. But depending on your needs, you may be able
11+
to solve your problem in a simpler way using these documents:
12+
13+
* :doc:`/cookbook/security/custom_password_authenticator`
14+
* :doc:`/cookbook/security/api_key_authentication`
15+
716
If you have read the chapter on :doc:`/book/security`, you understand the
817
distinction Symfony2 makes between authentication and authorization in the
918
implementation of security. This chapter discusses the core classes involved

‎cookbook/security/custom_password_authenticator.rst‎

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
.. index::
22
single: Security; Custom Password Authenticator
33

4-
How to create a Custom Password Authenticator
5-
=============================================
4+
How to Create a Custom Form Password Authenticator
5+
==================================================
66

7-
Imagine you want to allow access to your website only between 2pm and 4pm (for
8-
the UTC timezone). Before Symfony 2.4, you had to create a custom token, factory,
9-
listener and provider.
7+
Imagine you want to allow access to your website only between 2pm and 4pm
8+
UTC. Before Symfony 2.4, you had to create a custom token, factory, listener
9+
and provider. In this entry, you'll learn how to do this for a login form
10+
(i.e. where your user submits their username and password).
1011

1112
The Password Authenticator
1213
--------------------------
1314

1415
.. versionadded:: 2.4
1516
The ``SimpleFormAuthenticatorInterface`` interface was added in Symfony 2.4.
1617

17-
But now, thanks to new simplified authentication customization options in
18-
Symfony 2.4, you don't need to create a whole bunch of new classes, but use the
19-
:class:`Symfony\\Component\\Security\\Core\\Authentication\\SimpleFormAuthenticatorInterface`
20-
interface instead::
18+
First, create a new class that implements
19+
:class:`Symfony\\Component\\Security\\Core\\Authentication\\SimpleFormAuthenticatorInterface`.
20+
Eventually, this will allow you to create custom logic for authenticating
21+
the user::
2122

2223
// src/Acme/HelloBundle/Security/TimeAuthenticator.php
2324
namespace Acme\HelloBundle\Security;
@@ -90,18 +91,43 @@ interface instead::
9091
How it Works
9192
------------
9293

93-
There are a lot of things going on:
94+
Great! Now you just need to setup some :ref:`cookbook-security-password-authenticator-config`.
95+
But first, you can find out more about what each method in this class does.
9496

95-
* ``createToken()`` creates a Token that will be used to authenticate the user;
96-
* ``authenticateToken()`` checks that the Token is allowed to log in by first
97-
getting the User via the user provider and then, by checking the password
98-
and the current time (a Token with roles is authenticated);
99-
* ``supportsToken()`` is just a way to allow several authentication mechanisms to
100-
be used for the same firewall (that way, you can for instance first try to
101-
authenticate the user via a certificate or an API key and fall back to a
102-
form login);
103-
* An encoder is needed to check the user password's validity; this is a
104-
service provided by default::
97+
1) createToken
98+
~~~~~~~~~~~~~~
99+
100+
When Symfony begins handling a request, ``createToken()`` is called, where
101+
you create a :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface`
102+
object that contains whatever information you need in ``authenticateToken()``
103+
to authenticate the user (e.g. the username and password).
104+
105+
Whatever token object you create here will be passed to you later in ``authenticateToken()``.
106+
107+
2) supportsToken
108+
~~~~~~~~~~~~~~~~
109+
110+
.. include:: _supportsToken.rst.inc
111+
112+
3) authenticateToken
113+
~~~~~~~~~~~~~~~~~~~~
114+
115+
If ``supportsToken`` returns ``true``, Symfony will now call ``authenticateToken()``.
116+
Your job here is to check that the token is allowed to log in by first
117+
getting the ``User`` object via the user provider and then, by checking the password
118+
and the current time.
119+
120+
.. note::
121+
122+
The "flow" of how you get the ``User`` object and determine whether or not
123+
the token is valid (e.g. checking the password), may vary based on your
124+
requirements.
125+
126+
Ultimately, your job is to return a *new* token object that is "authenticated"
127+
(i.e. it has at least 1 role set on it) and which has the ``User`` object
128+
inside of it.
129+
130+
Inside this method, an encoder is needed to check the password's validity::
105131

106132
$encoder = $this->encoderFactory->getEncoder($user);
107133
$passwordValid = $encoder->isPasswordValid(
@@ -110,6 +136,12 @@ There are a lot of things going on:
110136
$user->getSalt()
111137
);
112138

139+
This is a service that is already available in Symfony and the password algorithm
140+
is configured in the security configuration (e.g. ``security.yml``) under
141+
the ``encoders`` key. Below, you'll see how to inject that into the ``TimeAuthenticator``.
142+
143+
.. _cookbook-security-password-authenticator-config:
144+
113145
Configuration
114146
-------------
115147

@@ -125,7 +157,7 @@ Now, configure your ``TimeAuthenticator`` as a service:
125157
126158
time_authenticator:
127159
class: Acme\HelloBundle\Security\TimeAuthenticator
128-
arguments: [@security.encoder_factory]
160+
arguments: ["@security.encoder_factory"]
129161
130162
.. code-block:: xml
131163
@@ -159,8 +191,8 @@ Now, configure your ``TimeAuthenticator`` as a service:
159191
array(new Reference('security.encoder_factory'))
160192
));
161193
162-
Then, activate it in your ``firewalls`` section using the ``simple-form`` key
163-
like this:
194+
Then, activate it in the ``firewalls`` section of the security configuration
195+
using the ``simple_form`` key:
164196

165197
.. configuration-block::
166198

@@ -173,9 +205,8 @@ like this:
173205
firewalls:
174206
secured_area:
175207
pattern: ^/admin
176-
provider: authenticator
177-
simple-form:
178-
provider: ...
208+
# ...
209+
simple_form:
179210
authenticator: time_authenticator
180211
check_path: login_check
181212
login_path: login
@@ -194,7 +225,7 @@ like this:
194225
195226
<firewall name="secured_area"
196227
pattern="^/admin"
197-
provider="authenticator">
228+
>
198229
<simple-form authenticator="time_authenticator"
199230
check-path="login_check"
200231
login-path="login"
@@ -213,8 +244,7 @@ like this:
213244
'firewalls' => array(
214245
'secured_area' => array(
215246
'pattern' => '^/admin',
216-
'provider' => 'authenticator',
217-
'simple-form' => array(
247+
'simple_form' => array(
218248
'provider' => ...,
219249
'authenticator' => 'time_authenticator',
220250
'check_path' => 'login_check',
@@ -223,3 +253,10 @@ like this:
223253
),
224254
),
225255
));
256+
257+
The ``simple_form`` key has the same options as the normal ``form_login``
258+
option, but with the additional ``authenticator`` key that points to the
259+
new service. For details, see :ref:`reference-security-firewall-form-login`.
260+
261+
If creating a login form in general is new to you or you don't understand
262+
the ``check_path`` or ``login_path`` options, see :doc:`/cookbook/security/form_login`.

0 commit comments

Comments
 (0)
Please sign in to comment.