-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[Cookbook] Use configured user provider instead of injection #5255
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
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,13 +35,6 @@ value and then a User object is created:: | |
|
||
class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface | ||
{ | ||
protected $userProvider; | ||
|
||
public function __construct(ApiKeyUserProvider $userProvider) | ||
{ | ||
$this->userProvider = $userProvider; | ||
} | ||
|
||
public function createToken(Request $request, $providerKey) | ||
{ | ||
// look for an apikey query parameter | ||
|
@@ -67,15 +60,15 @@ value and then a User object is created:: | |
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) | ||
{ | ||
$apiKey = $token->getCredentials(); | ||
$username = $this->userProvider->getUsernameForApiKey($apiKey); | ||
$username = $userProvider->getUsernameForApiKey($apiKey); | ||
|
||
if (!$username) { | ||
throw new AuthenticationException( | ||
sprintf('API Key "%s" does not exist.', $apiKey) | ||
); | ||
} | ||
|
||
$user = $this->userProvider->loadUserByUsername($username); | ||
$user = $userProvider->loadUserByUsername($username); | ||
|
||
return new PreAuthenticatedToken( | ||
$user, | ||
|
@@ -192,7 +185,7 @@ The ``$userProvider`` might look something like this:: | |
} | ||
} | ||
|
||
Now register your user provider as service: | ||
Now register your user provider as a service: | ||
|
||
.. configuration-block:: | ||
|
||
|
@@ -258,7 +251,7 @@ exception in ``refreshUser()``. | |
Handling Authentication Failure | ||
------------------------------- | ||
|
||
In order for your ``ApiKeyAuthentication`` to correctly display a 403 | ||
In order for your ``ApiKeyAuthenticator`` to correctly display a 403 | ||
http status when either bad credentials or authentication fails you will | ||
need to implement the :class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationFailureHandlerInterface` on your | ||
Authenticator. This will provide a method ``onAuthenticationFailure`` which | ||
|
@@ -290,11 +283,9 @@ you can use to create an error ``Response``. | |
Configuration | ||
------------- | ||
|
||
Once you have your ``ApiKeyAuthentication`` all setup, you need to register | ||
Once you have your ``ApiKeyAuthenticator`` all setup, you need to register | ||
it as a service and use it in your security configuration (e.g. ``security.yml``). | ||
First, register it as a service. This assumes that you have already setup | ||
your custom user provider as a service called ``your_api_key_user_provider`` | ||
(see :doc:`/cookbook/security/custom_provider`). | ||
First, register it as a service. | ||
|
||
.. configuration-block:: | ||
|
||
|
@@ -305,8 +296,7 @@ your custom user provider as a service called ``your_api_key_user_provider`` | |
# ... | ||
|
||
apikey_authenticator: | ||
class: AppBundle\Security\ApiKeyAuthenticator | ||
arguments: ["@api_key_user_provider"] | ||
class: AppBundle\Security\ApiKeyAuthenticator | ||
|
||
.. code-block:: xml | ||
|
||
|
@@ -319,11 +309,7 @@ your custom user provider as a service called ``your_api_key_user_provider`` | |
<services> | ||
<!-- ... --> | ||
|
||
<service id="apikey_authenticator" | ||
class="AppBundle\Security\ApiKeyAuthenticator" | ||
> | ||
<argument type="service" id="api_key_user_provider" /> | ||
</service> | ||
<service id="apikey_authenticator" class="AppBundle\Security\ApiKeyAuthenticator" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it can be private |
||
</services> | ||
</container> | ||
|
||
|
@@ -336,12 +322,12 @@ your custom user provider as a service called ``your_api_key_user_provider`` | |
// ... | ||
|
||
$container->setDefinition('apikey_authenticator', new Definition( | ||
'AppBundle\Security\ApiKeyAuthenticator', | ||
array(new Reference('api_key_user_provider')) | ||
'AppBundle\Security\ApiKeyAuthenticator' | ||
)); | ||
|
||
Now, activate it in the ``firewalls`` section of your security configuration | ||
using the ``simple_preauth`` key: | ||
Now, activate it and your custom user provider (see :doc:`/cookbook/security/custom_provider`) | ||
in the ``firewalls`` section of your security configuration | ||
using the ``simple_preauth`` and ``provider`` keys respectively: | ||
|
||
.. configuration-block:: | ||
|
||
|
@@ -357,6 +343,7 @@ using the ``simple_preauth`` key: | |
stateless: true | ||
simple_preauth: | ||
authenticator: apikey_authenticator | ||
provider: api_key_user_provider | ||
|
||
providers: | ||
api_key_user_provider: | ||
|
@@ -377,6 +364,7 @@ using the ``simple_preauth`` key: | |
<firewall name="secured_area" | ||
pattern="^/admin" | ||
stateless="true" | ||
provider="api_key_user_provider" | ||
> | ||
<simple-preauth authenticator="apikey_authenticator" /> | ||
</firewall> | ||
|
@@ -399,6 +387,7 @@ using the ``simple_preauth`` key: | |
'simple_preauth' => array( | ||
'authenticator' => 'apikey_authenticator', | ||
), | ||
'provider' => 'api_key_user_provider', | ||
), | ||
), | ||
'providers' => array( | ||
|
@@ -408,7 +397,7 @@ using the ``simple_preauth`` key: | |
), | ||
)); | ||
|
||
That's it! Now, your ``ApiKeyAuthentication`` should be called at the beginning | ||
That's it! Now, your ``ApiKeyAuthenticator`` should be called at the beginning | ||
of each request and your authentication process will take place. | ||
|
||
The ``stateless`` configuration parameter prevents Symfony from trying to | ||
|
@@ -444,6 +433,7 @@ configuration or set it to ``false``: | |
stateless: false | ||
simple_preauth: | ||
authenticator: apikey_authenticator | ||
provider: api_key_user_provider | ||
|
||
providers: | ||
api_key_user_provider: | ||
|
@@ -464,6 +454,7 @@ configuration or set it to ``false``: | |
<firewall name="secured_area" | ||
pattern="^/admin" | ||
stateless="false" | ||
provider="api_key_user_provider" | ||
> | ||
<simple-preauth authenticator="apikey_authenticator" /> | ||
</firewall> | ||
|
@@ -485,6 +476,7 @@ configuration or set it to ``false``: | |
'simple_preauth' => array( | ||
'authenticator' => 'apikey_authenticator', | ||
), | ||
'provider' => 'api_key_user_provider', | ||
), | ||
), | ||
'providers' => array( | ||
|
@@ -508,7 +500,7 @@ to see if the stored token has a valid User object that can be used:: | |
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) | ||
{ | ||
$apiKey = $token->getCredentials(); | ||
$username = $this->userProvider->getUsernameForApiKey($apiKey); | ||
$username = $userProvider->getUsernameForApiKey($apiKey); | ||
|
||
// User is the Entity which represents your user | ||
$user = $token->getUser(); | ||
|
@@ -527,7 +519,7 @@ to see if the stored token has a valid User object that can be used:: | |
); | ||
} | ||
|
||
$user = $this->userProvider->loadUserByUsername($username); | ||
$user = $userProvider->loadUserByUsername($username); | ||
|
||
return new PreAuthenticatedToken( | ||
$user, | ||
|
@@ -601,13 +593,10 @@ current URL is before creating the token in ``createToken()``:: | |
|
||
class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface | ||
{ | ||
protected $userProvider; | ||
|
||
protected $httpUtils; | ||
|
||
public function __construct(UserProviderInterface $userProvider, HttpUtils $httpUtils) | ||
public function __construct(HttpUtils $httpUtils) | ||
{ | ||
$this->userProvider = $userProvider; | ||
$this->httpUtils = $httpUtils; | ||
} | ||
|
||
|
@@ -642,7 +631,7 @@ service: | |
|
||
apikey_authenticator: | ||
class: AppBundle\Security\ApiKeyAuthenticator | ||
arguments: ["@api_key_user_provider", "@security.http_utils"] | ||
arguments: ["@security.http_utils"] | ||
|
||
.. code-block:: xml | ||
|
||
|
@@ -658,7 +647,6 @@ service: | |
<service id="apikey_authenticator" | ||
class="AppBundle\Security\ApiKeyAuthenticator" | ||
> | ||
<argument type="service" id="api_key_user_provider" /> | ||
<argument type="service" id="security.http_utils" /> | ||
</service> | ||
</services> | ||
|
@@ -675,7 +663,6 @@ service: | |
$container->setDefinition('apikey_authenticator', new Definition( | ||
'AppBundle\Security\ApiKeyAuthenticator', | ||
array( | ||
new Reference('api_key_user_provider'), | ||
new Reference('security.http_utils') | ||
) | ||
)); | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we need to check first if the
ApiKeyAuthenticator
actually supports the given token? So, something like the following at the beginning of the method:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And we also have to ensure that the given
$userProvider
actually is an instance ofApiKeyUserProvider
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xabbuh I like your first question, but I think it is out of scope of this topic. Even without my changes, same question could be asked. The cookbook referenced in this PR says
If supportsToken() returns true, Symfony will now call authenticateToken()
(in explanation how authentication process works). So Symfony checks that automatically. Would be strange if it wouldn't check. IMHO when method is defined in interface it's so not because you should use it internally.Thanks for the note about user provider, I agree that we should add check here. I will update my PR later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this again and I think we actually do not need to check for the token type. The authenticator doesn't do anything special with the token and so it should work just fine.