Passed
Branch master (022a1c)
by Darwin
03:39
created

LdapAuthenticationProviderTest::willBind()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 6
rs 9.4285
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;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $ldapAuthenticationProvider exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
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;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $hideUserNotFoundExceptions exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
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) {
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $authenticationException exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
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 View Code Duplication
    public function testCheckAuthenticationWhenTokenNeedsReauthenticationWorksWithoutOriginalCredentials()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testCheckAuthenticationUnknownUserBadCredentials()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testCheckAuthenticationUnknownUserPasswordEmpty()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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());
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
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