8000 [Security] Add UsernamePasswordJsonAuthenticationListener class · symfony/symfony@f9ad5c9 · GitHub
[go: up one dir, main page]

Skip to content

Commit f9ad5c9

Browse files
committed
[Security] Add UsernamePasswordJsonAuthenticationListener class
1 parent 031b850 commit f9ad5c9

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Http\Firewall;
13+
14+
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
16+
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
18+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
19+
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
20+
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
21+
use Symfony\Component\Security\Core\Security;
22+
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
23+
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
24+
use Symfony\Component\Security\Http\HttpUtils;
25+
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
26+
27+
/**
28+
* UsernamePasswordJsonAuthenticationListener is an implementation of
29+
* an authentication via a JSON document composed of a username and a password.
30+
*
31+
* @author Kévin Dunglas <dunglas@gmail.com>
32+
*/
33+
class UsernamePasswordJsonAuthenticationListener extends AbstractAuthenticationListener
34+
{
35+
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
36+
{
37+
parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
38+
'username_parameter' => '_username',
39+
'password_parameter' => '_password',
40+
), $options), $logger, $dispatcher);
41+
}
42+
43+
/**
44+
* {@inheritdoc}
45+
*/
46+
protected function attemptAuthentication(Request $request)
47+
{
48+
$data = json_decode($request->getContent(), true);
49+
50+
if (!isset($data[$this->options['username_parameter']])) {
51+
throw new BadCredentialsException(sprintf('Missing key "%s".', $this->options['username_parameter']));
52+
}
53+
54+
if (!isset($data[$this->options['password_parameter']])) {
55+
throw new BadCredentialsException(sprintf('Missing key "%s".', $this->options['password_parameter']));
56+
}
57+
58+
$username = $data[$this->options['username_parameter']];
59+
if (!is_string($username)) {
60+
throw new BadCredentialsException(sprintf('The key "%s" must contain a string.', $this->options['username_parameter']));
61+
}
62+
63+
if (strlen($username) > Security::MAX_USERNAME_LENGTH) {
64+
throw new BadCredentialsException('Invalid username.');
65+
}
66+
67+
$password = $data[$this->options['password_parameter']];
68+
if (!is_string($password)) {
69+
throw new BadCredentialsException(sprintf('The key "%s" must contain a string.', $this->options['password_parameter']));
70+
}
71+
72+
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
73+
}
74+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Tests\Http\Firewall;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
16+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
17+
use Symfony\Component\Security\Core\Security;
18+
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
19+
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
20+
use Symfony\Component\Security\Http\Firewall\UsernamePasswordJsonAuthenticationListener;
21+
use Symfony\Component\Security\Http\HttpUtils;
22+
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
23+
24+
/**
25+
* @author Kévin Dunglas <dunglas@gmail.com>
26+
*/
27+
class UsernamePasswordJsonAuthenticationListenerTest extends \PHPUnit_Framework_TestCase
28+
{
29+
/**
30+
* @var UsernamePasswordJsonAuthenticationListener
31+
*/
32+
private $listener;
33+
34+
/**
35+
* @var \ReflectionMethod
36+
*/
37+
private $attemptAuthenticationMethod;
38+
39+
protected function setUp() {
40+
$tokenStorage = $this->getMock(TokenStorageInterface::class);
41+
$authenticationManager = $this->getMock(AuthenticationManagerInterface::class);
42+
$authenticationManager->method('authenticate')->willReturn(true);
43+
$sessionAuthenticationStrategyInterface = $this->getMock(SessionAuthenticationStrategyInterface::class);
44+
$httpUtils = $this->getMock(HttpUtils::class);
45+
$authenticationSuccessHandler = $this->getMock(AuthenticationSuccessHandlerInterface::class);
46+
$authenticationFailureHandler = $this->getMock(AuthenticationFailureHandlerInterface::class);
47+
48+
$this->listener = new UsernamePasswordJsonAuthenticationListener($tokenStorage, $authenticationManager, $sessionAuthenticationStrategyInterface, $httpUtils, 'providerKey', $authenticationSuccessHandler, $authenticationFailureHandler);
49+
$this->attemptAuthenticationMethod = new \ReflectionMethod($this->listener, 'attemptAuthentication');
50+
$this->attemptAuthenticationMethod->setAccessible(true);
51+
}
52+
53+
public function testAttemptAuthentication()
54+
{
55+
$request = new Request(array(), array(), array(), array(), array(), array(), '{"_username": "dunglas", "_password": "foo"}');
56+
57+
$result = $this->attemptAuthenticationMethod->invokeArgs($this->listener, array($request));
58+
$this->assertTrue($result);
59+
}
60+
61+
/**
62+
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
63+
*/
64+
public function testAttemptAuthenticationNoUsername()
65+
{
66+
$request = new Request(array(), array(), array(), array(), array(), array(), '{"usr": "dunglas", "_password": "foo"}');
67+
$this->attemptAuthenticationMethod->invokeArgs($this->listener, array($request));
68+
}
69+
70+
/**
71+
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
72+
*/
73+
public function testAttemptAuthenticationNoPassword()
74+
{
75+
$request = new Request(array(), array(), array(), array(), array(), array(), '{"_username": "dunglas", "pass": "foo"}');
76+
$this->attemptAuthenticationMethod->invokeArgs($this->listener, array($request));
77+
}
78+
79+
/**
80+
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
81+
*/
82+
public function testAttemptAuthenticationUsernameNotAString()
83+
{
84+
$request = new Request(array(), array(), array(), array(), array(), array(), '{"_username": 1, "_password": "foo"}');
85+
$this->attemptAuthenticationMethod->invokeArgs($this->listener, array($request));
86+
}
87+
88+
/**
89+
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
90+
*/
91+
public function testAttemptAuthenticationPasswordNotAString()
92+
{
93+
$request = new Request(array(), array(), array(), array(), array(), array(), '{"_username": "dunglas", "_password": 1}');
94+
$this->attemptAuthenticationMethod->invokeArgs($this->listener, array($request));
95+
}
96+
97+
/**
98+
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
99+
*/
100+
public function testAttemptAuthenticationUsernameTooLong()
101+
{
102+
$username = str_repeat('x', Security::MAX_USERNAME_LENGTH + 1);
103+
$request = new Request(array(), array(), array(), array(), array(), array(), sprintf('{"_username": "%s", "_password": 1}', $username));
104+
105+
$this->attemptAuthenticationMethod->invokeArgs($this->listener, array($request));
106+
}
107+
}

0 commit comments

Comments
 (0)
0