[Security] Allow to set a check_path on json_login listener
This commit is contained in:
parent
4f0daa740a
commit
9f7eb618a4
@ -19,6 +19,8 @@ use Symfony\Component\DependencyInjection\Reference;
|
|||||||
* JsonLoginFactory creates services for JSON login authentication.
|
* JsonLoginFactory creates services for JSON login authentication.
|
||||||
*
|
*
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
|
*
|
||||||
|
* @experimental in version 3.3
|
||||||
*/
|
*/
|
||||||
class JsonLoginFactory extends AbstractFactory
|
class JsonLoginFactory extends AbstractFactory
|
||||||
{
|
{
|
||||||
@ -83,10 +85,10 @@ class JsonLoginFactory extends AbstractFactory
|
|||||||
{
|
{
|
||||||
$listenerId = $this->getListenerId();
|
$listenerId = $this->getListenerId();
|
||||||
$listener = new ChildDefinition($listenerId);
|
$listener = new ChildDefinition($listenerId);
|
||||||
$listener->replaceArgument(2, $id);
|
$listener->replaceArgument(3, $id);
|
||||||
$listener->replaceArgument(3, new Reference($this->createAuthenticationSuccessHandler($container, $id, $config)));
|
$listener->replaceArgument(4, new Reference($this->createAuthenticationSuccessHandler($container, $id, $config)));
|
||||||
$listener->replaceArgument(4, new Reference($this->createAuthenticationFailureHandler($container, $id, $config)));
|
$listener->replaceArgument(5, new Reference($this->createAuthenticationFailureHandler($container, $id, $config)));
|
||||||
$listener->replaceArgument(5, array_intersect_key($config, $this->options));
|
$listener->replaceArgument(6, array_intersect_key($config, $this->options));
|
||||||
|
|
||||||
$listenerId .= '.'.$id;
|
$listenerId .= '.'.$id;
|
||||||
$container->setDefinition($listenerId, $listener);
|
$container->setDefinition($listenerId, $listener);
|
||||||
|
@ -147,6 +147,7 @@
|
|||||||
<tag name="monolog.logger" channel="security" />
|
<tag name="monolog.logger" channel="security" />
|
||||||
<argument type="service" id="security.token_storage" />
|
<argument type="service" id="security.token_storage" />
|
||||||
<argument type="service" id="security.authentication.manager" />
|
<argument type="service" id="security.authentication.manager" />
|
||||||
|
<argument type="service" id="security.http_utils" />
|
||||||
<argument /> <!-- Provider-shared Key -->
|
<argument /> <!-- Provider-shared Key -->
|
||||||
<argument type="service" id="security.authentication.success_handler" />
|
<argument type="service" id="security.authentication.success_handler" />
|
||||||
<argument type="service" id="security.authentication.failure_handler" />
|
<argument type="service" id="security.authentication.failure_handler" />
|
||||||
|
@ -16,7 +16,7 @@ security:
|
|||||||
pattern: ^/
|
pattern: ^/
|
||||||
anonymous: true
|
anonymous: true
|
||||||
json_login:
|
json_login:
|
||||||
check_path: /mychk
|
check_path: /chk
|
||||||
username_path: user.login
|
username_path: user.login
|
||||||
password_path: user.password
|
password_path: user.password
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ CHANGELOG
|
|||||||
|
|
||||||
* deprecated `AccessDecisionManager::setVoters()` in favor of passing the
|
* deprecated `AccessDecisionManager::setVoters()` in favor of passing the
|
||||||
voters to the constructor.
|
voters to the constructor.
|
||||||
|
* [EXPERIMENTAL] added a `json_login` listener for stateless authentication
|
||||||
|
|
||||||
3.2.0
|
3.2.0
|
||||||
-----
|
-----
|
||||||
|
@ -29,6 +29,7 @@ use Symfony\Component\Security\Core\Security;
|
|||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
||||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||||
|
use Symfony\Component\Security\Http\HttpUtils;
|
||||||
use Symfony\Component\Security\Http\SecurityEvents;
|
use Symfony\Component\Security\Http\SecurityEvents;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,11 +37,14 @@ use Symfony\Component\Security\Http\SecurityEvents;
|
|||||||
* an authentication via a JSON document composed of a username and a password.
|
* an authentication via a JSON document composed of a username and a password.
|
||||||
*
|
*
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
|
*
|
||||||
|
* @experimental in version 3.3
|
||||||
*/
|
*/
|
||||||
class UsernamePasswordJsonAuthenticationListener implements ListenerInterface
|
class UsernamePasswordJsonAuthenticationListener implements ListenerInterface
|
||||||
{
|
{
|
||||||
private $tokenStorage;
|
private $tokenStorage;
|
||||||
private $authenticationManager;
|
private $authenticationManager;
|
||||||
|
private $httpUtils;
|
||||||
private $providerKey;
|
private $providerKey;
|
||||||
private $successHandler;
|
private $successHandler;
|
||||||
private $failureHandler;
|
private $failureHandler;
|
||||||
@ -49,10 +53,11 @@ class UsernamePasswordJsonAuthenticationListener implements ListenerInterface
|
|||||||
private $eventDispatcher;
|
private $eventDispatcher;
|
||||||
private $propertyAccessor;
|
private $propertyAccessor;
|
||||||
|
|
||||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $eventDispatcher = null, PropertyAccessorInterface $propertyAccessor = null)
|
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $eventDispatcher = null, PropertyAccessorInterface $propertyAccessor = null)
|
||||||
{
|
{
|
||||||
$this->tokenStorage = $tokenStorage;
|
$this->tokenStorage = $tokenStorage;
|
||||||
$this->authenticationManager = $authenticationManager;
|
$this->authenticationManager = $authenticationManager;
|
||||||
|
$this->httpUtils = $httpUtils;
|
||||||
$this->providerKey = $providerKey;
|
$this->providerKey = $providerKey;
|
||||||
$this->successHandler = $successHandler;
|
$this->successHandler = $successHandler;
|
||||||
$this->failureHandler = $failureHandler;
|
$this->failureHandler = $failureHandler;
|
||||||
@ -68,6 +73,11 @@ class UsernamePasswordJsonAuthenticationListener implements ListenerInterface
|
|||||||
public function handle(GetResponseEvent $event)
|
public function handle(GetResponseEvent $event)
|
||||||
{
|
{
|
||||||
$request = $event->getRequest();
|
$request = $event->getRequest();
|
||||||
|
|
||||||
|
if (isset($this->options['check_path']) && !$this->httpUtils->checkRequestPath($request, $this->options['check_path'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$data = json_decode($request->getContent());
|
$data = json_decode($request->getContent());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -24,6 +24,7 @@ use Symfony\Component\Security\Core\Security;
|
|||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
||||||
use Symfony\Component\Security\Http\Firewall\UsernamePasswordJsonAuthenticationListener;
|
use Symfony\Component\Security\Http\Firewall\UsernamePasswordJsonAuthenticationListener;
|
||||||
|
use Symfony\Component\Security\Http\HttpUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
@ -35,9 +36,15 @@ class UsernamePasswordJsonAuthenticationListenerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
private $listener;
|
private $listener;
|
||||||
|
|
||||||
private function createListener(array $options = array(), $success = true)
|
private function createListener(array $options = array(), $success = true, $matchCheckPath = true)
|
||||||
{
|
{
|
||||||
$tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock();
|
$tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock();
|
||||||
|
$httpUtils = $this->getMockBuilder(HttpUtils::class)->getMock();
|
||||||
|
$httpUtils
|
||||||
|
->expects($this->any())
|
||||||
|
->method('checkRequestPath')
|
||||||
|
->will($this->returnValue($matchCheckPath))
|
||||||
|
;
|
||||||
$authenticationManager = $this->getMockBuilder(AuthenticationManagerInterface::class)->getMock();
|
$authenticationManager = $this->getMockBuilder(AuthenticationManagerInterface::class)->getMock();
|
||||||
|
|
||||||
$authenticatedToken = $this->getMockBuilder(TokenInterface::class)->getMock();
|
$authenticatedToken = $this->getMockBuilder(TokenInterface::class)->getMock();
|
||||||
@ -53,7 +60,7 @@ class UsernamePasswordJsonAuthenticationListenerTest extends TestCase
|
|||||||
$authenticationFailureHandler = $this->getMockBuilder(AuthenticationFailureHandlerInterface::class)->getMock();
|
$authenticationFailureHandler = $this->getMockBuilder(AuthenticationFailureHandlerInterface::class)->getMock();
|
||||||
$authenticationFailureHandler->method('onAuthenticationFailure')->willReturn(new Response('ko'));
|
$authenticationFailureHandler->method('onAuthenticationFailure')->willReturn(new Response('ko'));
|
||||||
|
|
||||||
$this->listener = new UsernamePasswordJsonAuthenticationListener($tokenStorage, $authenticationManager, 'providerKey', $authenticationSuccessHandler, $authenticationFailureHandler, $options);
|
$this->listener = new UsernamePasswordJsonAuthenticationListener($tokenStorage, $authenticationManager, $httpUtils, 'providerKey', $authenticationSuccessHandler, $authenticationFailureHandler, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHandleSuccess()
|
public function testHandleSuccess()
|
||||||
@ -136,4 +143,25 @@ class UsernamePasswordJsonAuthenticationListenerTest extends TestCase
|
|||||||
$this->listener->handle($event);
|
$this->listener->handle($event);
|
||||||
$this->assertSame('ko', $event->getResponse()->getContent());
|
$this->assertSame('ko', $event->getResponse()->getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDoesNotAttemptAuthenticationIfRequestPathDoesNotMatchCheckPath()
|
||||||
|
{
|
||||||
|
$this->createListener(array('check_path' => '/'), true, false);
|
||||||
|
$request = new Request();
|
||||||
|
$event = new GetResponseEvent($this->getMockBuilder(KernelInterface::class)->getMock(), $request, KernelInterface::MASTER_REQUEST);
|
||||||
|
$event->setResponse(new Response('original'));
|
||||||
|
|
||||||
|
$this->listener->handle($event);
|
||||||
|
$this->assertSame('original', $event->getResponse()->getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAttemptAuthenticationIfRequestPathMatchesCheckPath()
|
||||||
|
{
|
||||||
|
$this->createListener(array('check_path' => '/'));
|
||||||
|
$request = new Request(array(), array(), array(), array(), array(), array(), '{"username": "dunglas", "password": "foo"}');
|
||||||
|
$event = new GetResponseEvent($this->getMockBuilder(KernelInterface::class)->getMock(), $request, KernelInterface::MASTER_REQUEST);
|
||||||
|
|
||||||
|
$this->listener->handle($event);
|
||||||
|
$this->assertSame('ok', $event->getResponse()->getContent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user