Skip to content

[Security] Add Guard authenticator <supports> method #16835

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

Merged
merged 2 commits into from
Oct 5, 2017
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions UPGRADE-3.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ Security
* Deprecated the HTTP digest authentication: `NonceExpiredException`,
`DigestAuthenticationListener` and `DigestAuthenticationEntryPoint` will be
removed in 4.0. Use another authentication system like `http_basic` instead.

* The `GuardAuthenticatorInterface` has been deprecated and will be removed in 4.0.
Use `AuthenticatorInterface` instead.

SecurityBundle
--------------
Expand Down
3 changes: 3 additions & 0 deletions UPGRADE-4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,9 @@ Security
`DigestAuthenticationListener` and `DigestAuthenticationEntryPoint` classes
have been removed. Use another authentication system like `http_basic` instead.

* The `GuardAuthenticatorInterface` interface has been removed.
Use `AuthenticatorInterface` instead.

SecurityBundle
--------------

Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Security/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ CHANGELOG
requests.
* deprecated HTTP digest authentication
* Added a new password encoder for the Argon2i hashing algorithm
* deprecated `GuardAuthenticatorInterface` in favor of `AuthenticatorInterface`

3.3.0
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\Security\Guard;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;

Expand All @@ -19,8 +20,20 @@
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
abstract class AbstractGuardAuthenticator implements GuardAuthenticatorInterface
abstract class AbstractGuardAuthenticator implements AuthenticatorInterface
{
/**
* {@inheritdoc}
*
* @deprecated since version 3.4, to be removed in 4.0
Copy link
Member

Choose a reason for hiding this comment

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

If I remove this line, the false positive deprecation notice is removed. Should I open a PR?

Copy link
Member

Choose a reason for hiding this comment

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

Please do. This method must be implemented by concrete subclasses and it is unlikely to be called directly.

*/
public function supports(Request $request)
{
@trigger_error(sprintf('The "%s()" method is deprecated since version 3.4 and will be removed in 4.0. Implement the "%s::supports()" method in class "%s" instead.', __METHOD__, AuthenticatorInterface::class, get_class($this)), E_USER_DEPRECATED);

return true;
}

/**
* Shortcut to create a PostAuthenticationGuardToken for you, if you don't really
* care about which authenticated token you're using.
Expand Down
63 changes: 63 additions & 0 deletions src/Symfony/Component/Security/Guard/AuthenticatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Security\Guard;

use Symfony\Component\HttpFoundation\Request;

/**
* The interface for all "guard" authenticators.
*
* The methods on this interface are called throughout the guard authentication
* process to give you the power to control most parts of the process from
* one location.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
* @author Amaury Leroux de Lens <amaury@lerouxdelens.com>
*/
interface AuthenticatorInterface extends GuardAuthenticatorInterface
{
/**
* Does the authenticator support the given Request?
*
* If this returns false, the authenticator will be skipped.
*
* @param Request $request
*
* @return bool
*/
public function supports(Request $request);

/**
* Get the authentication credentials from the request and return them
* as any type (e.g. an associate array).
*
* Whatever value you return here will be passed to getUser() and checkCredentials()
*
* For example, for a form login, you might:
*
* return array(
* 'username' => $request->request->get('_username'),
* 'password' => $request->request->get('_password'),
* );
*
* Or for an API token that's on a header, you might use:
*
* return array('api_key' => $request->headers->get('X-API-TOKEN'));
*
* @param Request $request
*
* @return mixed Any non-null value
*
* @throws \UnexpectedValueException If null is returned
*/
public function getCredentials(Request $request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use Symfony\Component\Security\Guard\GuardAuthenticatorInterface;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Guard\GuardAuthenticatorInterface;
use Symfony\Component\Security\Guard\AuthenticatorInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
Expand All @@ -28,6 +29,7 @@
* Authentication listener for the "guard" system.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
* @author Amaury Leroux de Lens <amaury@lerouxdelens.com>
*/
class GuardAuthenticationListener implements ListenerInterface
{
Expand All @@ -39,11 +41,11 @@ class GuardAuthenticationListener implements ListenerInterface
private $rememberMeServices;

/**
* @param GuardAuthenticatorHandler $guardHandler The Guard handler
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
* @param string $providerKey The provider (i.e. firewall) key
* @param iterable|GuardAuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider
* @param LoggerInterface $logger A LoggerInterface instance
* @param GuardAuthenticatorHandler $guardHandler The Guard handler
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
* @param string $providerKey The provider (i.e. firewall) key
* @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider
* @param LoggerInterface $logger A LoggerInterface instance
*/
public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, $providerKey, $guardAuthenticators, LoggerInterface $logger = null)
{
Expand Down Expand Up @@ -100,12 +102,29 @@ private function executeGuardAuthenticator($uniqueGuardKey, GuardAuthenticatorIn
$this->logger->debug('Calling getCredentials() on guard configurator.', array('firewall_key' => $this->providerKey, 'authenticator' => get_class($guardAuthenticator)));
}

// abort the execution of the authenticator if it doesn't support the request
if ($guardAuthenticator instanceof AuthenticatorInterface) {
if (!$guardAuthenticator->supports($request)) {
return;
}
// as there was a support for given request,
// authenticator is expected to give not-null credentials.
$credentialsCanBeNull = false;
} else {
// deprecated since version 3.4, to be removed in 4.0
$credentialsCanBeNull = true;
}

// allow the authenticator to fetch authentication info from the request
$credentials = $guardAuthenticator->getCredentials($request);

// allow null to be returned to skip authentication
if (null === $credentials) {
return;
// deprecated since version 3.4, to be removed in 4.0
if ($credentialsCanBeNull) {
return;
}

throw new \UnexpectedValueException(sprintf('The return value of "%s::getCredentials()" must not be null. Return false from "%s::supports()" instead.', get_class($guardAuthenticator), get_class($guardAuthenticator)));
}

// create a token with the unique key, so that the provider knows which authenticator to use
Expand Down Expand Up @@ -172,10 +191,10 @@ public function setRememberMeServices(RememberMeServicesInterface $rememberMeSer
* Checks to see if remember me is supported in the authenticator and
* on the firewall. If it is, the RememberMeServicesInterface is notified.
*
* @param GuardAuthenticatorInterface $guardAuthenticator
* @param Request $request
* @param TokenInterface $token
* @param Response $response
* @param AuthenticatorInterface $guardAuthenticator
* @param Request $request
* @param TokenInterface $token
* @param Response $response
*/
private function triggerRememberMe(GuardAuthenticatorInterface $guardAuthenticator, Request $request, TokenInterface $token, Response $response = null)
{
Expand Down
26 changes: 14 additions & 12 deletions src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
* can be called directly (e.g. for manual authentication) or overridden.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*
* @final since version 3.4
*/
class GuardAuthenticatorHandler
{
Expand Down Expand Up @@ -61,10 +63,10 @@ public function authenticateWithToken(TokenInterface $token, Request $request)
/**
* Returns the "on success" response for the given GuardAuthenticator.
*
* @param TokenInterface $token
* @param Request $request
* @param GuardAuthenticatorInterface $guardAuthenticator
* @param string $providerKey The provider (i.e. firewall) key
* @param TokenInterface $token
* @param Request $request
* @param AuthenticatorInterface $guardAuthenticator
* @param string $providerKey The provider (i.e. firewall) key
*
* @return null|Response
*/
Expand All @@ -88,10 +90,10 @@ public function handleAuthenticationSuccess(TokenInterface $token, Request $requ
* Convenience method for authenticating the user and returning the
* Response *if any* for success.
*
* @param UserInterface $user
* @param Request $request
* @param GuardAuthenticatorInterface $authenticator
* @param string $providerKey The provider (i.e. firewall) key
* @param UserInterface $user
* @param Request $request
* @param AuthenticatorInterface $authenticator
* @param string $providerKey The provider (i.e. firewall) key
*
* @return Response|null
*/
Expand All @@ -110,10 +112,10 @@ public function authenticateUserAndHandleSuccess(UserInterface $user, Request $r
* Handles an authentication failure and returns the Response for the
* GuardAuthenticator.
*
* @param AuthenticationException $authenticationException
* @param Request $request
* @param GuardAuthenticatorInterface $guardAuthenticator
* @param string $providerKey The key of the firewall
* @param AuthenticationException $authenticationException
* @param Request $request
* @param AuthenticatorInterface $guardAuthenticator
* @param string $providerKey The key of the firewall
*
* @return null|Response
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
* one location.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*
* @deprecated since version 3.4, to be removed in 4.0. Use AuthenticatorInterface instead
*/
interface GuardAuthenticatorInterface extends AuthenticationEntryPointInterface
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Guard\GuardAuthenticatorInterface;
use Symfony\Component\Security\Guard\AuthenticatorInterface;
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
Expand All @@ -32,18 +32,18 @@
class GuardAuthenticationProvider implements AuthenticationProviderInterface
{
/**
* @var GuardAuthenticatorInterface[]
* @var AuthenticatorInterface[]
*/
private $guardAuthenticators;
private $userProvider;
private $providerKey;
private $userChecker;

/**
* @param iterable|GuardAuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationListener
* @param UserProviderInterface $userProvider The user provider
* @param string $providerKey The provider (i.e. firewall) key
* @param UserCheckerInterface $userChecker
* @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationListener
* @param UserProviderInterface $userProvider The user provider
* @param string $providerKey The provider (i.e. firewall) key
* @param UserCheckerInterface $userChecker
*/
public function __construct($guardAuthenticators, UserProviderInterface $userProvider, $providerKey, UserCheckerInterface $userChecker)
{
Expand Down Expand Up @@ -101,7 +101,7 @@ public function authenticate(TokenInterface $token)
// instances that will be checked if you have multiple firewalls.
}

private function authenticateViaGuard(GuardAuthenticatorInterface $guardAuthenticator, PreAuthenticationGuardToken $token)
private function authenticateViaGuard($guardAuthenticator, PreAuthenticationGuardToken $token)
{
// get the user from the GuardAuthenticator
$user = $guardAuthenticator->getUser($token->getCredentials(), $this->userProvider);
Expand Down
Loading