Completed
Pull Request — master (#564)
by Michał
07:58
created

testWillRefuseToAuthenticateWhenInvalidInstanceIsFound()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 23
rs 9.0856
cc 1
eloc 16
nc 1
nop 0
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace DoctrineModuleTest\Authentication\Adapter;
21
22
use Doctrine\Common\Persistence\ObjectManager;
23
use Doctrine\Common\Persistence\ObjectRepository;
24
use DoctrineModule\Authentication\Adapter\ObjectRepository as ObjectRepositoryAdapter;
25
use Zend\Authentication\Adapter\Exception;
26
27
/**
28
 * Tests for the ObjectRepository based authentication adapter
29
 *
30
 * @license MIT
31
 * @link    http://www.doctrine-project.org/
32
 * @author  Marco Pivetta <[email protected]>
33
 */
34
class ObjectRepositoryTest extends \PHPUnit_Framework_TestCase
35
{
36
    public function testWillRejectInvalidIdentityProperty()
37
    {
38
        $this->expectException(Exception\InvalidArgumentException::class);
39
        $this->expectExceptionMessage('Provided $identityProperty is invalid, boolean given');
40
41
        new ObjectRepositoryAdapter(['identity_property' => false]);
42
    }
43
44
    public function testWillRejectInvalidCredentialProperty()
45
    {
46
        $this->expectException(Exception\InvalidArgumentException::class);
47
        $this->expectExceptionMessage('Provided $credentialProperty is invalid, boolean given');
48
49
        new ObjectRepositoryAdapter(['credential_property' => false]);
50
    }
51
52
    public function testWillRequireIdentityValue()
53
    {
54
        $this->expectException(Exception\RuntimeException::class);
55
        $this->expectExceptionMessage(
56
            'A value for the identity was not provided prior to authentication with ObjectRepository authentication'
57
            . ' adapter'
58
        );
59
60
        $adapter = new ObjectRepositoryAdapter();
61
        $adapter->setOptions([
62
            'object_manager' => $this->createMock(ObjectManager::class),
63
            'identity_class' => TestAsset\IdentityObject::class,
64
        ]);
65
        $adapter->setCredential('a credential');
66
        $adapter->authenticate();
67
    }
68
69
    public function testWillRequireCredentialValue()
70
    {
71
        $this->expectException(Exception\RuntimeException::class);
72
        $this->expectExceptionMessage(
73
            'A credential value was not provided prior to authentication with ObjectRepository authentication adapter'
74
        );
75
76
        $adapter = new ObjectRepositoryAdapter();
77
        $adapter->setOptions([
78
            'object_manager' => $this->createMock(ObjectManager::class),
79
            'identity_class' => TestAsset\IdentityObject::class,
80
        ]);
81
82
        $adapter->setIdentity('an identity');
83
        $adapter->authenticate();
84
    }
85
86
    public function testWillRejectInvalidCredentialCallable()
87
    {
88
        $this->expectException(Exception\InvalidArgumentException::class);
89
        $this->expectExceptionMessage('"array" is not a callable');
90
91
        $adapter = new ObjectRepositoryAdapter();
92
        $adapter->setOptions([
93
            'object_manager'      => $this->createMock(ObjectManager::class),
94
            'identity_class'      => TestAsset\IdentityObject::class,
95
            'credential_callable' => [],
96
        ]);
97
98
        $adapter->authenticate();
99
    }
100
101
    public function testAuthentication()
102
    {
103
        $entity = new TestAsset\IdentityObject();
104
        $entity->setUsername('a username');
105
        $entity->setPassword('a password');
106
107
        $objectRepository = $this->createMock(ObjectRepository::class);
108
        $method           = $objectRepository
109
            ->expects($this->exactly(2))
110
            ->method('findOneBy')
111
            ->with($this->equalTo(['username' => 'a username']))
112
            ->will($this->returnValue($entity));
113
114
        $objectManager = $this->createMock(ObjectManager::class);
115
        $objectManager->expects($this->exactly(2))
116
                      ->method('getRepository')
117
                      ->with($this->equalTo(TestAsset\IdentityObject::class))
118
                      ->will($this->returnValue($objectRepository));
119
120
        $adapter = new ObjectRepositoryAdapter();
121
        $adapter->setOptions([
122
            'object_manager'      => $objectManager,
123
            'identity_class'      => TestAsset\IdentityObject::class,
124
            'credential_property' => 'password',
125
            'identity_property'   => 'username',
126
        ]);
127
128
        $adapter->setIdentity('a username');
129
        $adapter->setCredential('a password');
130
131
        $result = $adapter->authenticate();
132
133
        $this->assertTrue($result->isValid());
134
        $this->assertInstanceOf(TestAsset\IdentityObject::class, $result->getIdentity());
135
136
        $method->will($this->returnValue(null));
137
138
        $result = $adapter->authenticate();
139
140
        $this->assertFalse($result->isValid());
141
    }
142
143
    public function testAuthenticationWithPublicProperties()
144
    {
145
        $entity           = new TestAsset\PublicPropertiesIdentityObject();
146
        $entity->username = 'a username';
147
        $entity->password = 'a password';
148
149
        $objectRepository = $this->createMock(ObjectRepository::class);
150
        $method           = $objectRepository
151
            ->expects($this->exactly(2))
152
            ->method('findOneBy')
153
            ->with($this->equalTo(['username' => 'a username']))
154
            ->will($this->returnValue($entity));
155
156
        $adapter = new ObjectRepositoryAdapter();
157
        $adapter->setOptions([
158
            'object_repository'   => $objectRepository,
159
            'credential_property' => 'password',
160
            'identity_property'   => 'username',
161
        ]);
162
163
        $adapter->setIdentity('a username');
164
        $adapter->setCredential('a password');
165
166
        $result = $adapter->authenticate();
167
168
        $this->assertTrue($result->isValid());
169
170
        $method->will($this->returnValue(null));
171
172
        $result = $adapter->authenticate();
173
174
        $this->assertFalse($result->isValid());
175
    }
176
177
    public function testWillRefuseToAuthenticateWithoutGettersOrPublicMethods()
178
    {
179
        $this->expectException(Exception\UnexpectedValueException::class);
180
181
        $objectRepository = $this->createMock(ObjectRepository::class);
182
        $objectRepository
183
            ->expects($this->once())
184
            ->method('findOneBy')
185
            ->with($this->equalTo(['username' => 'a username']))
186
            ->will($this->returnValue(new \stdClass()));
187
188
        $adapter = new ObjectRepositoryAdapter();
189
        $adapter->setOptions([
190
            'object_repository'   => $objectRepository,
191
            'credential_property' => 'password',
192
            'identity_property'   => 'username',
193
        ]);
194
195
        $adapter->setIdentity('a username');
196
        $adapter->setCredential('a password');
197
        $adapter->authenticate();
198
    }
199
200
    public function testCanValidateWithSpecialCrypt()
201
    {
202
        $hash   = '$2y$07$usesomesillystringforsalt$';
203
        $entity = new TestAsset\IdentityObject();
204
        $entity->setUsername('username');
205
        // Crypt password using Blowfish
206
        $entity->setPassword(crypt('password', $hash));
207
208
        $objectRepository = $this->createMock(ObjectRepository::class);
209
        $objectRepository
210
            ->expects($this->exactly(2))
211
            ->method('findOneBy')
212
            ->with($this->equalTo(['username' => 'username']))
213
            ->will($this->returnValue($entity));
214
215
        $adapter = new ObjectRepositoryAdapter();
216
        $adapter->setOptions([
217
            'object_repository'   => $objectRepository,
218
            'credential_property' => 'password',
219
            'identity_property'   => 'username',
220
            // enforced type hinting to verify that closure is invoked correctly
221
            'credential_callable' => function (TestAsset\IdentityObject $identity, $credentialValue) use ($hash) {
222
                return $identity->getPassword() === crypt($credentialValue, $hash);
223
            },
224
        ]);
225
226
        $adapter->setIdentity('username');
227
        $adapter->setCredential('password');
228
229
        $result = $adapter->authenticate();
230
231
        $this->assertTrue($result->isValid());
232
233
        $adapter->setCredential('wrong password');
234
        $result = $adapter->authenticate();
235
236
        $this->assertFalse($result->isValid());
237
    }
238
239
    public function testWillRefuseToAuthenticateWhenInvalidInstanceIsFound()
240
    {
241
        $this->expectException(Exception\UnexpectedValueException::class);
242
243
        $objectRepository = $this->createMock(ObjectRepository::class);
244
        $objectRepository
245
            ->expects($this->once())
246
            ->method('findOneBy')
247
            ->with($this->equalTo(['username' => 'a username']))
248
            ->will($this->returnValue(new \stdClass()));
249
250
        $adapter = new ObjectRepositoryAdapter();
251
        $adapter->setOptions([
252
            'object_repository'   => $objectRepository,
253
            'credential_property' => 'password',
254
            'identity_property'   => 'username',
255
        ]);
256
257
        $adapter->setIdentity('a username');
258
        $adapter->setCredential('a password');
259
260
        $adapter->authenticate();
261
    }
262
263
    public function testWillNotCastAuthCredentialValue()
264
    {
265
        $objectRepository = $this->createMock(ObjectRepository::class);
266
        $adapter          = new ObjectRepositoryAdapter();
267
        $entity           = new TestAsset\IdentityObject();
268
269
        $entity->setPassword(0);
270
        $adapter->setOptions([
271
             'object_repository'   => $objectRepository,
272
             'credential_property' => 'password',
273
             'identity_property'   => 'username',
274
        ]);
275
        $adapter->setIdentity('a username');
276
        $adapter->setCredential('00000');
277
        $objectRepository
278
            ->expects($this->once())
279
            ->method('findOneBy')
280
            ->with($this->equalTo(['username' => 'a username']))
281
            ->will($this->returnValue($entity));
282
283
        $this->assertFalse($adapter->authenticate()->isValid());
284
    }
285
}
286