assertValidAuthenticatedToken()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace DoL\LdapBundle\Tests\Security\Authentication;
4
5
use Exception;
6
use DoL\LdapBundle\Security\Authentication\LdapAuthenticationProvider;
7
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
8
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
9
use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
10
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
11
use Symfony\Component\Security\Core\User\UserCheckerInterface;
12
use Symfony\Component\Security\Core\User\UserInterface;
13
14
/**
15
 * @covers \DoL\LdapBundle\Security\Authentication\LdapAuthenticationProvider
16
 */
17
class LdapAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
18
{
19
    /**
20
     * @var LdapAuthenticationProvider
21
     */
22
    protected $ldapAuthenticationProvider;
23
24
    /**
25
     * @var \Symfony\Component\Security\Core\User\UserProviderInterface|\PHPUnit_Framework_MockObject_MockObject
26
     */
27
    protected $userProvider;
28
29
    /**
30
     * @var \DoL\LdapBundle\Ldap\LdapManagerInterface|\PHPUnit_Framework_MockObject_MockObject
31
     */
32
    protected $ldapManager;
33
34
    /**
35
     * Sets up the fixture, for example, opens a network connection.
36
     * This method is called before a test is executed.
37
     */
38
    protected function setUp()
39
    {
40
        /** @var UserCheckerInterface|\PHPUnit_Framework_MockObject_MockObject $userChecker */
41
        $userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface');
42
        $providerKey = 'provider_key';
43
        $this->userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
44
        $this->ldapManager = $this->getMock('DoL\LdapBundle\Ldap\LdapManagerInterface');
45
        $hideUserNotFoundExceptions = false;
46
47
        $this->ldapAuthenticationProvider = new LdapAuthenticationProvider($userChecker, $providerKey, $this->userProvider, $this->ldapManager, $hideUserNotFoundExceptions);
48
    }
49
50
    /**
51
     * @dataProvider validTokensProvider
52
     *
53
     * @param string $username
54
     * @param string $password
55
     */
56
    public function testAuthenticate($username, $password)
57
    {
58
        $user = $this->createUserMock();
59
        $token = $this->createToken($username, $password);
60
61
        $this->willRetrieveUser($username, $user);
62
        $this->willBind($user, $password);
63
64
        $authenticatedToken = $this->ldapAuthenticationProvider->authenticate($token);
65
66
        $this->assertValidAuthenticatedToken($authenticatedToken, $user);
67
    }
68
69
    public function validTokensProvider()
70
    {
71
        return [
72
            'normal' => ['test_username', 'password'],
73
            'password_0' => ['test_username', '0'],
74
        ];
75
    }
76
77
    /**
78
     * @expectedException \Symfony\Component\Security\Core\Exception\UsernameNotFoundException
79
     */
80
    public function testRetrieveUserNotFound()
81
    {
82
        $username = 'notfound_username';
83
        $token = $this->createToken($username, 'password');
84
85
        $this->willRetrieveUser($username, new UsernameNotFoundException(''));
86
87
        $this->ldapAuthenticationProvider->authenticate($token);
88
    }
89
90
    public function testRetrieveUserUnexpectedError()
91
    {
92
        $username = 'username';
93
        $token = $this->createToken($username, 'password');
94
95
        $this->willRetrieveUser($username, new Exception(''));
96
97
        try {
98
            $this->ldapAuthenticationProvider->authenticate($token);
99
            self::fail('Expected Symfony\Component\Security\Core\Exception\AuthenticationServiceException to be thrown');
100
        } catch (AuthenticationServiceException $authenticationException) {
101
            self::assertEquals($token, $authenticationException->getToken());
102
        }
103
    }
104
105
    public function testRetrieveUserReturnsUserFromTokenOnReauthentication()
106
    {
107
        $user = $this->createUserMock();
108
        $password = 'password';
109
        $token = $this->createToken($user, $password);
110
111
        $this->userProvider->expects($this->never())
112
            ->method('loadUserByUsername');
113
114
        $this->willBind($user, $password);
115
116
        $authenticatedToken = $this->ldapAuthenticationProvider->authenticate($token);
117
118
        $this->assertValidAuthenticatedToken($authenticatedToken, $user);
119
    }
120
121
    public function testCheckAuthenticationWhenTokenNeedsReauthenticationWorksWithoutOriginalCredentials()
122
    {
123
        $password = 'password';
124
        $user = $this->createUserMock();
125
126
        $token = $this->createToken($user, $password);
127
128
        $this->willBind($user, $password);
129
130
        $authenticatedToken = $this->ldapAuthenticationProvider->authenticate($token);
131
132
        $this->assertValidAuthenticatedToken($authenticatedToken, $user);
133
    }
134
135
    /**
136
     * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
137
     * @expectedExceptionMessage The password in the token is empty. You may forgive turn off `erase_credentials` in your `security.yml`
138
     */
139
    public function testCheckAuthenticationKnownUserCredentialsAreErased()
140
    {
141
        $password = '';
142
        $user = $this->createUserMock();
143
144
        $token = $this->createToken($user, $password);
145
146
        $this->ldapAuthenticationProvider->authenticate($token);
147
    }
148
149
    /**
150
     * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
151
     * @expectedExceptionMessage The credentials were changed from another session.
152
     */
153
    public function testCheckAuthenticationKnownUserCredentialsChanged()
154
    {
155
        $password = 'other_password';
156
        $user = $this->createUserMock();
157
158
        $token = $this->createToken($user, $password);
159
160
        $this->willBind($user, $password, false);
161
162
        $this->ldapAuthenticationProvider->authenticate($token);
163
    }
164
165
    /**
166
     * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
167
     * @expectedExceptionMessage The presented password is invalid.
168
     */
169
    public function testCheckAuthenticationUnknownUserBadCredentials()
170
    {
171
        $username = 'test_username';
172
        $password = 'bad_password';
173
        $user = $this->createUserMock();
174
        $token = $this->createToken($username, $password);
175
176
        $this->willRetrieveUser($username, $user);
177
        $this->willBind($user, $password, false);
178
179
        $this->ldapAuthenticationProvider->authenticate($token);
180
    }
181
182
    /**
183
     * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
184
     * @expectedExceptionMessage The presented password cannot be empty.
185
     */
186
    public function testCheckAuthenticationUnknownUserPasswordEmpty()
187
    {
188
        $username = 'test_username';
189
        $password = '';
190
        $user = $this->createUserMock();
191
192
        $this->willRetrieveUser($username, $user);
193
        $token = $this->createToken($username, $password);
194
195
        $this->ldapAuthenticationProvider->authenticate($token);
196
    }
197
198
    /**
199
     * @return UserInterface|\PHPUnit_Framework_MockObject_MockObject
200
     */
201
    private function createUserMock()
202
    {
203
        $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
204
        $user->expects($this->any())
205
            ->method('getRoles')
206
            ->willReturn([]);
207
208
        return $user;
209
    }
210
211
    /**
212
     * @param TokenInterface $authenticatedToken
213
     * @param UserInterface  $expectedUser
214
     */
215
    private function assertValidAuthenticatedToken($authenticatedToken, UserInterface $expectedUser)
216
    {
217
        self::assertInstanceOf(
218
            'Symfony\Component\Security\Core\Authentication\Token\TokenInterface',
219
            $authenticatedToken
220
        );
221
222
        self::assertEquals($expectedUser, $authenticatedToken->getUser());
223
        //self::assertTrue($authenticatedToken->isAuthenticated());
224
    }
225
226
    /**
227
     * @param UserInterface|string|object $user
228
     * @param string                      $credentials
229
     *
230
     * @return UsernamePasswordToken
231
     */
232
    private function createToken($user, $credentials)
233
    {
234
        return new UsernamePasswordToken($user, $credentials, 'provider_key');
235
    }
236
237
    /**
238
     * @param UserInterface $user
239
     * @param string        $password
240
     * @param bool          $result
241
     */
242
    private function willBind(UserInterface $user, $password, $result = true)
243
    {
244
        $this->ldapManager->expects($this->once())
245
            ->method('bind')
246
            ->with($this->equalTo($user), $this->equalTo($password))
247
            ->will($this->returnValue($result))
248
        ;
249
    }
250
251
    /**
252
     * @param string                  $username
253
     * @param UserInterface|Exception $userOrException
254
     */
255
    private function willRetrieveUser($username, $userOrException)
256
    {
257
        $mock = $this->userProvider->expects($this->atMost(1))
258
            ->method('loadUserByUsername')
259
            ->with($this->equalTo($username))
260
        ;
261
262
        if ($userOrException instanceof Exception) {
263
            $mock->will($this->throwException($userOrException));
264
        } else {
265
            $mock->will($this->returnValue($userOrException));
266
        }
267
    }
268
}
269