feature #16835 [Security] Add Guard authenticator <supports> method (Amo, chalasr)
This PR was merged into the 3.4 branch. Discussion ---------- [Security] Add Guard authenticator <supports> method This method will be called before starting an authentication against a guard authenticator. The authentication will be tried only if the supports method returned `true` This improves understanding of code, increase consistency and removes responsability for `getCredentials` method to decide if the current request should be supported or not. | Q | A | | --- | --- | | Bug fix? | no | | New feature? | yes | | BC breaks? | yes | | Deprecations? | yes | | Tests pass? | yes | | Fixed tickets | none | | License | MIT | | Doc PR | | Commits -------78eecba780
Fix BC layera7a6f8a678
[Security] Add Guard authenticator <supports> method
This commit is contained in:
commit
02b77f54fb
@ -306,6 +306,9 @@ Security
|
|||||||
`DigestAuthenticationListener` and `DigestAuthenticationEntryPoint` will be
|
`DigestAuthenticationListener` and `DigestAuthenticationEntryPoint` will be
|
||||||
removed in 4.0. Use another authentication system like `http_basic` instead.
|
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
|
SecurityBundle
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -679,6 +679,9 @@ Security
|
|||||||
`DigestAuthenticationListener` and `DigestAuthenticationEntryPoint` classes
|
`DigestAuthenticationListener` and `DigestAuthenticationEntryPoint` classes
|
||||||
have been removed. Use another authentication system like `http_basic` instead.
|
have been removed. Use another authentication system like `http_basic` instead.
|
||||||
|
|
||||||
|
* The `GuardAuthenticatorInterface` interface has been removed.
|
||||||
|
Use `AuthenticatorInterface` instead.
|
||||||
|
|
||||||
SecurityBundle
|
SecurityBundle
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ CHANGELOG
|
|||||||
requests.
|
requests.
|
||||||
* deprecated HTTP digest authentication
|
* deprecated HTTP digest authentication
|
||||||
* Added a new password encoder for the Argon2i hashing algorithm
|
* Added a new password encoder for the Argon2i hashing algorithm
|
||||||
|
* deprecated `GuardAuthenticatorInterface` in favor of `AuthenticatorInterface`
|
||||||
|
|
||||||
3.3.0
|
3.3.0
|
||||||
-----
|
-----
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Security\Guard;
|
namespace Symfony\Component\Security\Guard;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
|
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
|
||||||
|
|
||||||
@ -19,8 +20,20 @@ use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
|
|||||||
*
|
*
|
||||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
* @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
|
||||||
|
*/
|
||||||
|
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
|
* Shortcut to create a PostAuthenticationGuardToken for you, if you don't really
|
||||||
* care about which authenticated token you're using.
|
* care about which authenticated token you're using.
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -15,9 +15,10 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||||
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
|
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
|
||||||
|
use Symfony\Component\Security\Guard\GuardAuthenticatorInterface;
|
||||||
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
||||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||||
use Symfony\Component\Security\Guard\GuardAuthenticatorInterface;
|
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||||
@ -28,6 +29,7 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
|||||||
* Authentication listener for the "guard" system.
|
* Authentication listener for the "guard" system.
|
||||||
*
|
*
|
||||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||||
|
* @author Amaury Leroux de Lens <amaury@lerouxdelens.com>
|
||||||
*/
|
*/
|
||||||
class GuardAuthenticationListener implements ListenerInterface
|
class GuardAuthenticationListener implements ListenerInterface
|
||||||
{
|
{
|
||||||
@ -39,11 +41,11 @@ class GuardAuthenticationListener implements ListenerInterface
|
|||||||
private $rememberMeServices;
|
private $rememberMeServices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param GuardAuthenticatorHandler $guardHandler The Guard handler
|
* @param GuardAuthenticatorHandler $guardHandler The Guard handler
|
||||||
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
|
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
|
||||||
* @param string $providerKey The provider (i.e. firewall) key
|
* @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 iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider
|
||||||
* @param LoggerInterface $logger A LoggerInterface instance
|
* @param LoggerInterface $logger A LoggerInterface instance
|
||||||
*/
|
*/
|
||||||
public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, $providerKey, $guardAuthenticators, LoggerInterface $logger = null)
|
public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, $providerKey, $guardAuthenticators, LoggerInterface $logger = null)
|
||||||
{
|
{
|
||||||
@ -100,12 +102,29 @@ class GuardAuthenticationListener implements ListenerInterface
|
|||||||
$this->logger->debug('Calling getCredentials() on guard configurator.', array('firewall_key' => $this->providerKey, 'authenticator' => get_class($guardAuthenticator)));
|
$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
|
// allow the authenticator to fetch authentication info from the request
|
||||||
$credentials = $guardAuthenticator->getCredentials($request);
|
$credentials = $guardAuthenticator->getCredentials($request);
|
||||||
|
|
||||||
// allow null to be returned to skip authentication
|
|
||||||
if (null === $credentials) {
|
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
|
// create a token with the unique key, so that the provider knows which authenticator to use
|
||||||
@ -172,10 +191,10 @@ class GuardAuthenticationListener implements ListenerInterface
|
|||||||
* Checks to see if remember me is supported in the authenticator and
|
* Checks to see if remember me is supported in the authenticator and
|
||||||
* on the firewall. If it is, the RememberMeServicesInterface is notified.
|
* on the firewall. If it is, the RememberMeServicesInterface is notified.
|
||||||
*
|
*
|
||||||
* @param GuardAuthenticatorInterface $guardAuthenticator
|
* @param AuthenticatorInterface $guardAuthenticator
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param TokenInterface $token
|
* @param TokenInterface $token
|
||||||
* @param Response $response
|
* @param Response $response
|
||||||
*/
|
*/
|
||||||
private function triggerRememberMe(GuardAuthenticatorInterface $guardAuthenticator, Request $request, TokenInterface $token, Response $response = null)
|
private function triggerRememberMe(GuardAuthenticatorInterface $guardAuthenticator, Request $request, TokenInterface $token, Response $response = null)
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,8 @@ use Symfony\Component\Security\Http\SecurityEvents;
|
|||||||
* can be called directly (e.g. for manual authentication) or overridden.
|
* can be called directly (e.g. for manual authentication) or overridden.
|
||||||
*
|
*
|
||||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||||
|
*
|
||||||
|
* @final since version 3.4
|
||||||
*/
|
*/
|
||||||
class GuardAuthenticatorHandler
|
class GuardAuthenticatorHandler
|
||||||
{
|
{
|
||||||
@ -61,10 +63,10 @@ class GuardAuthenticatorHandler
|
|||||||
/**
|
/**
|
||||||
* Returns the "on success" response for the given GuardAuthenticator.
|
* Returns the "on success" response for the given GuardAuthenticator.
|
||||||
*
|
*
|
||||||
* @param TokenInterface $token
|
* @param TokenInterface $token
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param GuardAuthenticatorInterface $guardAuthenticator
|
* @param AuthenticatorInterface $guardAuthenticator
|
||||||
* @param string $providerKey The provider (i.e. firewall) key
|
* @param string $providerKey The provider (i.e. firewall) key
|
||||||
*
|
*
|
||||||
* @return null|Response
|
* @return null|Response
|
||||||
*/
|
*/
|
||||||
@ -88,10 +90,10 @@ class GuardAuthenticatorHandler
|
|||||||
* Convenience method for authenticating the user and returning the
|
* Convenience method for authenticating the user and returning the
|
||||||
* Response *if any* for success.
|
* Response *if any* for success.
|
||||||
*
|
*
|
||||||
* @param UserInterface $user
|
* @param UserInterface $user
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param GuardAuthenticatorInterface $authenticator
|
* @param AuthenticatorInterface $authenticator
|
||||||
* @param string $providerKey The provider (i.e. firewall) key
|
* @param string $providerKey The provider (i.e. firewall) key
|
||||||
*
|
*
|
||||||
* @return Response|null
|
* @return Response|null
|
||||||
*/
|
*/
|
||||||
@ -110,10 +112,10 @@ class GuardAuthenticatorHandler
|
|||||||
* Handles an authentication failure and returns the Response for the
|
* Handles an authentication failure and returns the Response for the
|
||||||
* GuardAuthenticator.
|
* GuardAuthenticator.
|
||||||
*
|
*
|
||||||
* @param AuthenticationException $authenticationException
|
* @param AuthenticationException $authenticationException
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param GuardAuthenticatorInterface $guardAuthenticator
|
* @param AuthenticatorInterface $guardAuthenticator
|
||||||
* @param string $providerKey The key of the firewall
|
* @param string $providerKey The key of the firewall
|
||||||
*
|
*
|
||||||
* @return null|Response
|
* @return null|Response
|
||||||
*/
|
*/
|
||||||
|
@ -28,6 +28,8 @@ use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface
|
|||||||
* one location.
|
* one location.
|
||||||
*
|
*
|
||||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||||
|
*
|
||||||
|
* @deprecated since version 3.4, to be removed in 4.0. Use AuthenticatorInterface instead
|
||||||
*/
|
*/
|
||||||
interface GuardAuthenticatorInterface extends AuthenticationEntryPointInterface
|
interface GuardAuthenticatorInterface extends AuthenticationEntryPointInterface
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@ namespace Symfony\Component\Security\Guard\Provider;
|
|||||||
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
|
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
|
||||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
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\GuardTokenInterface;
|
||||||
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
||||||
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
||||||
@ -32,7 +32,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationExpiredException;
|
|||||||
class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var GuardAuthenticatorInterface[]
|
* @var AuthenticatorInterface[]
|
||||||
*/
|
*/
|
||||||
private $guardAuthenticators;
|
private $guardAuthenticators;
|
||||||
private $userProvider;
|
private $userProvider;
|
||||||
@ -40,10 +40,10 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
|||||||
private $userChecker;
|
private $userChecker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param iterable|GuardAuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationListener
|
* @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationListener
|
||||||
* @param UserProviderInterface $userProvider The user provider
|
* @param UserProviderInterface $userProvider The user provider
|
||||||
* @param string $providerKey The provider (i.e. firewall) key
|
* @param string $providerKey The provider (i.e. firewall) key
|
||||||
* @param UserCheckerInterface $userChecker
|
* @param UserCheckerInterface $userChecker
|
||||||
*/
|
*/
|
||||||
public function __construct($guardAuthenticators, UserProviderInterface $userProvider, $providerKey, UserCheckerInterface $userChecker)
|
public function __construct($guardAuthenticators, UserProviderInterface $userProvider, $providerKey, UserCheckerInterface $userChecker)
|
||||||
{
|
{
|
||||||
@ -101,7 +101,7 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
|||||||
// instances that will be checked if you have multiple firewalls.
|
// 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
|
// get the user from the GuardAuthenticator
|
||||||
$user = $guardAuthenticator->getUser($token->getCredentials(), $this->userProvider);
|
$user = $guardAuthenticator->getUser($token->getCredentials(), $this->userProvider);
|
||||||
|
@ -14,12 +14,16 @@ namespace Symfony\Component\Security\Guard\Tests\Firewall;
|
|||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||||
use Symfony\Component\Security\Guard\Firewall\GuardAuthenticationListener;
|
use Symfony\Component\Security\Guard\Firewall\GuardAuthenticationListener;
|
||||||
|
use Symfony\Component\Security\Guard\GuardAuthenticatorInterface;
|
||||||
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
||||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryan Weaver <weaverryan@gmail.com>
|
* @author Ryan Weaver <weaverryan@gmail.com>
|
||||||
|
* @author Amaury Leroux de Lens <amaury@lerouxdelens.com>
|
||||||
*/
|
*/
|
||||||
class GuardAuthenticationListenerTest extends TestCase
|
class GuardAuthenticationListenerTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -32,11 +36,16 @@ class GuardAuthenticationListenerTest extends TestCase
|
|||||||
|
|
||||||
public function testHandleSuccess()
|
public function testHandleSuccess()
|
||||||
{
|
{
|
||||||
$authenticator = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticator = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
$authenticateToken = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
|
$authenticateToken = $this->getMockBuilder(TokenInterface::class)->getMock();
|
||||||
$providerKey = 'my_firewall';
|
$providerKey = 'my_firewall';
|
||||||
|
|
||||||
$credentials = array('username' => 'weaverryan', 'password' => 'all_your_base');
|
$credentials = array('username' => 'weaverryan', 'password' => 'all_your_base');
|
||||||
|
|
||||||
|
$authenticator
|
||||||
|
->expects($this->once())
|
||||||
|
->method('supports')
|
||||||
|
->willReturn(true);
|
||||||
$authenticator
|
$authenticator
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('getCredentials')
|
->method('getCredentials')
|
||||||
@ -82,10 +91,14 @@ class GuardAuthenticationListenerTest extends TestCase
|
|||||||
|
|
||||||
public function testHandleSuccessStopsAfterResponseIsSet()
|
public function testHandleSuccessStopsAfterResponseIsSet()
|
||||||
{
|
{
|
||||||
$authenticator1 = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticator1 = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
$authenticator2 = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticator2 = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
|
|
||||||
// mock the first authenticator to fail, and set a Response
|
// mock the first authenticator to fail, and set a Response
|
||||||
|
$authenticator1
|
||||||
|
->expects($this->once())
|
||||||
|
->method('supports')
|
||||||
|
->willReturn(true);
|
||||||
$authenticator1
|
$authenticator1
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('getCredentials')
|
->method('getCredentials')
|
||||||
@ -112,10 +125,15 @@ class GuardAuthenticationListenerTest extends TestCase
|
|||||||
|
|
||||||
public function testHandleSuccessWithRememberMe()
|
public function testHandleSuccessWithRememberMe()
|
||||||
{
|
{
|
||||||
$authenticator = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticator = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
$authenticateToken = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
|
$authenticateToken = $this->getMockBuilder(TokenInterface::class)->getMock();
|
||||||
$providerKey = 'my_firewall_with_rememberme';
|
$providerKey = 'my_firewall_with_rememberme';
|
||||||
|
|
||||||
|
$authenticator
|
||||||
|
->expects($this->once())
|
||||||
|
->method('supports')
|
||||||
|
->with($this->equalTo($this->request))
|
||||||
|
->willReturn(true);
|
||||||
$authenticator
|
$authenticator
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('getCredentials')
|
->method('getCredentials')
|
||||||
@ -155,10 +173,14 @@ class GuardAuthenticationListenerTest extends TestCase
|
|||||||
|
|
||||||
public function testHandleCatchesAuthenticationException()
|
public function testHandleCatchesAuthenticationException()
|
||||||
{
|
{
|
||||||
$authenticator = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticator = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
$providerKey = 'my_firewall2';
|
$providerKey = 'my_firewall2';
|
||||||
|
|
||||||
$authException = new AuthenticationException('Get outta here crazy user with a bad password!');
|
$authException = new AuthenticationException('Get outta here crazy user with a bad password!');
|
||||||
|
$authenticator
|
||||||
|
->expects($this->once())
|
||||||
|
->method('supports')
|
||||||
|
->willReturn(true);
|
||||||
$authenticator
|
$authenticator
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('getCredentials')
|
->method('getCredentials')
|
||||||
@ -185,6 +207,96 @@ class GuardAuthenticationListenerTest extends TestCase
|
|||||||
$listener->handle($this->event);
|
$listener->handle($this->event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group legacy
|
||||||
|
*/
|
||||||
|
public function testLegacyInterfaceNullCredentials()
|
||||||
|
{
|
||||||
|
$authenticatorA = $this->getMockBuilder(GuardAuthenticatorInterface::class)->getMock();
|
||||||
|
$providerKey = 'my_firewall3';
|
||||||
|
|
||||||
|
$authenticatorA
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getCredentials')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
// this is not called
|
||||||
|
$this->authenticationManager
|
||||||
|
->expects($this->never())
|
||||||
|
->method('authenticate');
|
||||||
|
|
||||||
|
$this->guardAuthenticatorHandler
|
||||||
|
->expects($this->never())
|
||||||
|
->method('handleAuthenticationSuccess');
|
||||||
|
|
||||||
|
$listener = new GuardAuthenticationListener(
|
||||||
|
$this->guardAuthenticatorHandler,
|
||||||
|
$this->authenticationManager,
|
||||||
|
$providerKey,
|
||||||
|
array($authenticatorA),
|
||||||
|
$this->logger
|
||||||
|
);
|
||||||
|
|
||||||
|
$listener->handle($this->event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group legacy
|
||||||
|
*/
|
||||||
|
public function testLegacyInterfaceKeepsWorking()
|
||||||
|
{
|
||||||
|
$authenticator = $this->getMockBuilder(GuardAuthenticatorInterface::class)->getMock();
|
||||||
|
$authenticateToken = $this->getMockBuilder(TokenInterface::class)->getMock();
|
||||||
|
$providerKey = 'my_firewall';
|
||||||
|
|
||||||
|
$credentials = array('username' => 'weaverryan', 'password' => 'all_your_base');
|
||||||
|
|
||||||
|
$authenticator
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getCredentials')
|
||||||
|
->with($this->equalTo($this->request))
|
||||||
|
->will($this->returnValue($credentials));
|
||||||
|
|
||||||
|
// a clone of the token that should be created internally
|
||||||
|
$uniqueGuardKey = 'my_firewall_0';
|
||||||
|
$nonAuthedToken = new PreAuthenticationGuardToken($credentials, $uniqueGuardKey);
|
||||||
|
|
||||||
|
$this->authenticationManager
|
||||||
|
->expects($this->once())
|
||||||
|
->method('authenticate')
|
||||||
|
->with($this->equalTo($nonAuthedToken))
|
||||||
|
->will($this->returnValue($authenticateToken));
|
||||||
|
|
||||||
|
$this->guardAuthenticatorHandler
|
||||||
|
->expects($this->once())
|
||||||
|
->method('authenticateWithToken')
|
||||||
|
->with($authenticateToken, $this->request);
|
||||||
|
|
||||||
|
$this->guardAuthenticatorHandler
|
||||||
|
->expects($this->once())
|
||||||
|
->method('handleAuthenticationSuccess')
|
||||||
|
->with($authenticateToken, $this->request, $authenticator, $providerKey);
|
||||||
|
|
||||||
|
$listener = new GuardAuthenticationListener(
|
||||||
|
$this->guardAuthenticatorHandler,
|
||||||
|
$this->authenticationManager,
|
||||||
|
$providerKey,
|
||||||
|
array($authenticator),
|
||||||
|
$this->logger
|
||||||
|
);
|
||||||
|
|
||||||
|
$listener->setRememberMeServices($this->rememberMeServices);
|
||||||
|
// should never be called - our handleAuthenticationSuccess() does not return a Response
|
||||||
|
$this->rememberMeServices
|
||||||
|
->expects($this->never())
|
||||||
|
->method('loginSuccess');
|
||||||
|
|
||||||
|
$listener->handle($this->event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group legacy
|
||||||
|
*/
|
||||||
public function testReturnNullToSkipAuth()
|
public function testReturnNullToSkipAuth()
|
||||||
{
|
{
|
||||||
$authenticatorA = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticatorA = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
||||||
@ -220,6 +332,62 @@ class GuardAuthenticationListenerTest extends TestCase
|
|||||||
$listener->handle($this->event);
|
$listener->handle($this->event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSupportsReturnFalseSkipAuth()
|
||||||
|
{
|
||||||
|
$authenticator = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
|
$providerKey = 'my_firewall4';
|
||||||
|
|
||||||
|
$authenticator
|
||||||
|
->expects($this->once())
|
||||||
|
->method('supports')
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
// this is not called
|
||||||
|
$authenticator
|
||||||
|
->expects($this->never())
|
||||||
|
->method('getCredentials');
|
||||||
|
|
||||||
|
$listener = new GuardAuthenticationListener(
|
||||||
|
$this->guardAuthenticatorHandler,
|
||||||
|
$this->authenticationManager,
|
||||||
|
$providerKey,
|
||||||
|
array($authenticator),
|
||||||
|
$this->logger
|
||||||
|
);
|
||||||
|
|
||||||
|
$listener->handle($this->event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \UnexpectedValueException
|
||||||
|
*/
|
||||||
|
public function testReturnNullFromGetCredentials()
|
||||||
|
{
|
||||||
|
$authenticator = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
|
$providerKey = 'my_firewall4';
|
||||||
|
|
||||||
|
$authenticator
|
||||||
|
->expects($this->once())
|
||||||
|
->method('supports')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
// this will raise exception
|
||||||
|
$authenticator
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getCredentials')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$listener = new GuardAuthenticationListener(
|
||||||
|
$this->guardAuthenticatorHandler,
|
||||||
|
$this->authenticationManager,
|
||||||
|
$providerKey,
|
||||||
|
array($authenticator),
|
||||||
|
$this->logger
|
||||||
|
);
|
||||||
|
|
||||||
|
$listener->handle($this->event);
|
||||||
|
}
|
||||||
|
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
$this->authenticationManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager')
|
$this->authenticationManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager')
|
||||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Security\Guard\Tests;
|
|||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||||
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
|
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
|
||||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||||
@ -128,7 +129,7 @@ class GuardAuthenticatorHandlerTest extends TestCase
|
|||||||
$this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
|
$this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
|
||||||
$this->token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
|
$this->token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
|
||||||
$this->request = new Request(array(), array(), array(), array(), array(), array());
|
$this->request = new Request(array(), array(), array(), array(), array(), array());
|
||||||
$this->guardAuthenticator = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$this->guardAuthenticator = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function tearDown()
|
protected function tearDown()
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
namespace Symfony\Component\Security\Guard\Tests\Provider;
|
namespace Symfony\Component\Security\Guard\Tests\Provider;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||||
use Symfony\Component\Security\Guard\Provider\GuardAuthenticationProvider;
|
use Symfony\Component\Security\Guard\Provider\GuardAuthenticationProvider;
|
||||||
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
|
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
|
||||||
|
|
||||||
@ -28,6 +31,68 @@ class GuardAuthenticationProviderTest extends TestCase
|
|||||||
{
|
{
|
||||||
$providerKey = 'my_cool_firewall';
|
$providerKey = 'my_cool_firewall';
|
||||||
|
|
||||||
|
$authenticatorA = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
|
$authenticatorB = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
|
$authenticatorC = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||||
|
$authenticators = array($authenticatorA, $authenticatorB, $authenticatorC);
|
||||||
|
|
||||||
|
// called 2 times - for authenticator A and B (stops on B because of match)
|
||||||
|
$this->preAuthenticationToken->expects($this->exactly(2))
|
||||||
|
->method('getGuardProviderKey')
|
||||||
|
// it will return the "1" index, which will match authenticatorB
|
||||||
|
->will($this->returnValue('my_cool_firewall_1'));
|
||||||
|
|
||||||
|
$enteredCredentials = array(
|
||||||
|
'username' => '_weaverryan_test_user',
|
||||||
|
'password' => 'guard_auth_ftw',
|
||||||
|
);
|
||||||
|
$this->preAuthenticationToken->expects($this->atLeastOnce())
|
||||||
|
->method('getCredentials')
|
||||||
|
->will($this->returnValue($enteredCredentials));
|
||||||
|
|
||||||
|
// authenticators A and C are never called
|
||||||
|
$authenticatorA->expects($this->never())
|
||||||
|
->method('getUser');
|
||||||
|
$authenticatorC->expects($this->never())
|
||||||
|
->method('getUser');
|
||||||
|
|
||||||
|
$mockedUser = $this->getMockBuilder(UserInterface::class)->getMock();
|
||||||
|
$authenticatorB->expects($this->once())
|
||||||
|
->method('getUser')
|
||||||
|
->with($enteredCredentials, $this->userProvider)
|
||||||
|
->will($this->returnValue($mockedUser));
|
||||||
|
// checkCredentials is called
|
||||||
|
$authenticatorB->expects($this->once())
|
||||||
|
->method('checkCredentials')
|
||||||
|
->with($enteredCredentials, $mockedUser)
|
||||||
|
// authentication works!
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
$authedToken = $this->getMockBuilder(TokenInterface::class)->getMock();
|
||||||
|
$authenticatorB->expects($this->once())
|
||||||
|
->method('createAuthenticatedToken')
|
||||||
|
->with($mockedUser, $providerKey)
|
||||||
|
->will($this->returnValue($authedToken));
|
||||||
|
|
||||||
|
// user checker should be called
|
||||||
|
$this->userChecker->expects($this->once())
|
||||||
|
->method('checkPreAuth')
|
||||||
|
->with($mockedUser);
|
||||||
|
$this->userChecker->expects($this->once())
|
||||||
|
->method('checkPostAuth')
|
||||||
|
->with($mockedUser);
|
||||||
|
|
||||||
|
$provider = new GuardAuthenticationProvider($authenticators, $this->userProvider, $providerKey, $this->userChecker);
|
||||||
|
$actualAuthedToken = $provider->authenticate($this->preAuthenticationToken);
|
||||||
|
$this->assertSame($authedToken, $actualAuthedToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group legacy
|
||||||
|
*/
|
||||||
|
public function testLegacyAuthenticate()
|
||||||
|
{
|
||||||
|
$providerKey = 'my_cool_firewall';
|
||||||
|
|
||||||
$authenticatorA = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticatorA = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
||||||
$authenticatorB = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticatorB = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
||||||
$authenticatorC = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
$authenticatorC = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock();
|
||||||
|
@ -29,7 +29,7 @@ class PreAuthenticationGuardToken extends AbstractToken implements GuardTokenInt
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed $credentials
|
* @param mixed $credentials
|
||||||
* @param string $guardProviderKey Unique key that bind this token to a specific GuardAuthenticatorInterface
|
* @param string $guardProviderKey Unique key that bind this token to a specific AuthenticatorInterface
|
||||||
*/
|
*/
|
||||||
public function __construct($credentials, $guardProviderKey)
|
public function __construct($credentials, $guardProviderKey)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user