Skip to content

Added configuration of the user provider #4895

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 4 commits into from
Closed
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
101 changes: 79 additions & 22 deletions cookbook/security/api_key_authentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Your exact situation may differ, but in this example, a token is read
from an ``apikey`` query parameter, the proper username is loaded from that
value and then a User object is created::

// src/Acme/HelloBundle/Security/ApiKeyAuthenticator.php
namespace Acme\HelloBundle\Security;
// src/AppBundle/Security/ApiKeyAuthenticator.php
namespace AppBundle\Security;

use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
Expand Down Expand Up @@ -142,8 +142,8 @@ used by Symfony's core user provider system).

The ``$userProvider`` might look something like this::

// src/Acme/HelloBundle/Security/ApiKeyUserProvider.php
namespace Acme\HelloBundle\Security;
// src/AppBundle/Security/ApiKeyUserProvider.php
namespace AppBundle\Security;

use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\User;
Expand Down Expand Up @@ -187,6 +187,41 @@ The ``$userProvider`` might look something like this::
}
}

Now register your user provider as service:

.. configuration-block::

.. code-block:: yaml

# app/config/services.yml
services:
api_key_user_provider:
class: AppBundle\Security\ApiKeyUserProvider

.. code-block:: xml

<!-- app/config/services.xml -->
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<!-- ... -->

<service id="api_key_user_provider"
class="AppBundle\Security\ApiKeyUserProvider" />
</services>
</container>

.. code-block:: php

// app/config/services.php

// ...
$container
->register('api_key_user_provider', 'AppBundle\Security\ApiKeyUserProvider');

.. note::

Read the dedicated article to learn
Expand Down Expand Up @@ -226,8 +261,8 @@ you can use to create an error ``Response``.

.. code-block:: php

// src/Acme/HelloBundle/Security/ApiKeyAuthenticator.php
namespace Acme\HelloBundle\Security;
// src/AppBundle/Security/ApiKeyAuthenticator.php
namespace AppBundle\Security;

use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
Expand Down Expand Up @@ -265,8 +300,8 @@ your custom user provider as a service called ``your_api_key_user_provider``
# ...

apikey_authenticator:
class: Acme\HelloBundle\Security\ApiKeyAuthenticator
arguments: ["@your_api_key_user_provider"]
class: AppBundle\Security\ApiKeyAuthenticator
arguments: ["@api_key_user_provider"]

.. code-block:: xml

Expand All @@ -280,9 +315,9 @@ your custom user provider as a service called ``your_api_key_user_provider``
<!-- ... -->

<service id="apikey_authenticator"
class="Acme\HelloBundle\Security\ApiKeyAuthenticator"
class="AppBundle\Security\ApiKeyAuthenticator"
>
<argument type="service" id="your_api_key_user_provider" />
<argument type="service" id="api_key_user_provider" />
</service>
</services>
</container>
Expand All @@ -296,8 +331,8 @@ your custom user provider as a service called ``your_api_key_user_provider``
// ...

$container->setDefinition('apikey_authenticator', new Definition(
'Acme\HelloBundle\Security\ApiKeyAuthenticator',
array(new Reference('your_api_key_user_provider'))
'AppBundle\Security\ApiKeyAuthenticator',
array(new Reference('api_key_user_provider'))
));

Now, activate it in the ``firewalls`` section of your security configuration
Expand All @@ -318,6 +353,10 @@ using the ``simple_preauth`` key:
simple_preauth:
authenticator: apikey_authenticator

providers:
api_key_user_provider:
id: api_key_user_provider

Copy link
Member

Choose a reason for hiding this comment

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

The class behind this service would be the ApiKeyUserProvider class that we create in this article, right? If so, I'd like your thought on going even a bit further:

  1. Change the name from simple_preauth to something else, because I don't think this needs to correspond with the authentication name under the firewall (so using something else will make that obvious)

  2. Change the key used here to be something like api_key_user_provider

  3. After we show them the ApiKeyUserProvider, we just kind of link to the "custom user provider" article. What do you think about adding the service configuration below that code block and also show the security.yml configuration? I don't want to duplicate, but I feel like maybe we're leaving the user hanging without enough details.

Thanks :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@weaverryan Updated as per your comments, I think adding the service makes sense. I actually had this before, but then removed it again due to the reference. But that should not be an issue to maintain.

I also changed everything to your favorite, the AppBundle.. :)

.. code-block:: xml

<!-- app/config/security.xml -->
Expand All @@ -336,6 +375,8 @@ using the ``simple_preauth`` key:
>
<simple-preauth authenticator="apikey_authenticator" />
</firewall>

<provider name="api_key_user_provider" id="api_key_user_provider" />
</config>
</srv:container>

Expand All @@ -355,6 +396,11 @@ using the ``simple_preauth`` key:
),
),
),
'providers' => array(
'api_key_user_provider' => array(
'id' => 'api_key_user_provider',
),
),
));

That's it! Now, your ``ApiKeyAuthentication`` should be called at the beginning
Expand Down Expand Up @@ -394,6 +440,10 @@ configuration or set it to ``false``:
simple_preauth:
authenticator: apikey_authenticator

providers:
api_key_user_provider:
id: api_key_user_provider

.. code-block:: xml

<!-- app/config/security.xml -->
Expand All @@ -412,6 +462,8 @@ configuration or set it to ``false``:
>
<simple-preauth authenticator="apikey_authenticator" />
</firewall>

<provider name="api_key_user_provider" id="api_key_user_provider" />
</config>
</srv:container>

Expand All @@ -430,14 +482,19 @@ configuration or set it to ``false``:
),
),
),
'providers' => array(
'api_key_user_provider' => array(
'id' => 'api_key_user_provider',
),
),
));

Even though the token is being stored in the session, the credentials - in this
case the API key (i.e. ``$token->getCredentials()``) - are not stored in the session
for security reasons. To take advantage of the session, update ``ApiKeyAuthenticator``
to see if the stored token has a valid User object that can be used::

// src/Acme/HelloBundle/Security/ApiKeyAuthenticator.php
// src/AppBundle/Security/ApiKeyAuthenticator.php
// ...

class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface
Expand Down Expand Up @@ -491,7 +548,7 @@ stored in the database, then you may want to re-query for a fresh version
of the user to make sure it's not out-of-date. But regardless of your requirements,
``refreshUser()`` should now return the User object::

// src/Acme/HelloBundle/Security/ApiKeyUserProvider.php
// src/AppBundle/Security/ApiKeyUserProvider.php

// ...
class ApiKeyUserProvider implements UserProviderInterface
Expand Down Expand Up @@ -531,7 +588,7 @@ a certain URL (e.g. the redirect URL in OAuth).
Fortunately, handling this situation is easy: just check to see what the
current URL is before creating the token in ``createToken()``::

// src/Acme/HelloBundle/Security/ApiKeyAuthenticator.php
// src/AppBundle/Security/ApiKeyAuthenticator.php

// ...
use Symfony\Component\Security\Http\HttpUtils;
Expand All @@ -543,7 +600,7 @@ current URL is before creating the token in ``createToken()``::

protected $httpUtils;

public function __construct(ApiKeyUserProviderInterface $userProvider, HttpUtils $httpUtils)
public function __construct(UserProviderInterface $userProvider, HttpUtils $httpUtils)
{
$this->userProvider = $userProvider;
$this->httpUtils = $httpUtils;
Expand Down Expand Up @@ -579,8 +636,8 @@ service:
# ...

apikey_authenticator:
class: Acme\HelloBundle\Security\ApiKeyAuthenticator
arguments: ["@your_api_key_user_provider", "@security.http_utils"]
class: AppBundle\Security\ApiKeyAuthenticator
arguments: ["@api_key_user_provider", "@security.http_utils"]

.. code-block:: xml

Expand All @@ -594,9 +651,9 @@ service:
<!-- ... -->

<service id="apikey_authenticator"
class="Acme\HelloBundle\Security\ApiKeyAuthenticator"
class="AppBundle\Security\ApiKeyAuthenticator"
>
<argument type="service" id="your_api_key_user_provider" />
<argument type="service" id="api_key_user_provider" />
<argument type="service" id="security.http_utils" />
</service>
</services>
Expand All @@ -611,9 +668,9 @@ service:
// ...

$container->setDefinition('apikey_authenticator', new Definition(
'Acme\HelloBundle\Security\ApiKeyAuthenticator',
'AppBundle\Security\ApiKeyAuthenticator',
array(
new Reference('your_api_key_user_provider'),
new Reference('api_key_user_provider'),
new Reference('security.http_utils')
)
));
Expand Down