1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace AbterPhp\Admin\Oauth2\Repository; |
6
|
|
|
|
7
|
|
|
use AbterPhp\Admin\Exception\Database; |
8
|
|
|
use AbterPhp\Admin\Oauth2\Entity\AccessToken as Entity; |
9
|
|
|
use AbterPhp\Framework\TestCase\Database\QueryTestCase; |
10
|
|
|
use AbterPhp\Framework\TestDouble\Database\MockStatementFactory; |
11
|
|
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface; |
12
|
|
|
use League\OAuth2\Server\Entities\ClientEntityInterface; |
13
|
|
|
use League\OAuth2\Server\Entities\ScopeEntityInterface; |
14
|
|
|
use Opulence\Orm\Ids\Generators\UuidV4Generator; |
15
|
|
|
use PHPUnit\Framework\MockObject\MockObject; |
16
|
|
|
|
17
|
|
|
class AccessTokenTest extends QueryTestCase |
18
|
|
|
{ |
19
|
|
|
/** @var AccessToken - System Under Test */ |
20
|
|
|
protected $sut; |
21
|
|
|
|
22
|
|
|
/** @var UuidV4Generator|MockObject */ |
23
|
|
|
protected $uuidGeneratorMock; |
24
|
|
|
|
25
|
|
|
public function setUp(): void |
26
|
|
|
{ |
27
|
|
|
parent::setUp(); |
28
|
|
|
|
29
|
|
|
$this->uuidGeneratorMock = $this->createMock(UuidV4Generator::class); |
30
|
|
|
|
31
|
|
|
$this->sut = new AccessToken($this->uuidGeneratorMock, $this->connectionPoolMock); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
public function testGetNewToken() |
35
|
|
|
{ |
36
|
|
|
/** @var ClientEntityInterface|MockObject $clientEntityStub */ |
37
|
|
|
$clientEntityStub = $this->createMock(ClientEntityInterface::class); |
38
|
|
|
|
39
|
|
|
$scopes = []; |
40
|
|
|
$userIdentifier = null; |
41
|
|
|
|
42
|
|
|
$actualResult = $this->sut->getNewToken($clientEntityStub, $scopes, $userIdentifier); |
43
|
|
|
|
44
|
|
|
$this->assertInstanceOf(Entity::class, $actualResult); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
public function testPersistNewAccessToken() |
48
|
|
|
{ |
49
|
|
|
$tokenId = 'foo'; |
50
|
|
|
$clientName = 'bar'; |
51
|
|
|
$expiresAt = new \DateTime(); |
52
|
|
|
|
53
|
|
|
$accessTokenEntityMock = $this->createAccessTokenStub($tokenId, $clientName, $expiresAt, []); |
54
|
|
|
|
55
|
|
|
$sql0 = 'INSERT INTO tokens (id, api_client_id, expires_at) VALUES (?, ?, ?)'; // phpcs:ignore |
56
|
|
|
$valuesToBind0 = [ |
57
|
|
|
[$tokenId, \PDO::PARAM_STR], |
58
|
|
|
[$clientName, \PDO::PARAM_STR], |
59
|
|
|
[$expiresAt->format('Y-m-d H:i:s'), \PDO::PARAM_STR], |
60
|
|
|
]; |
61
|
|
|
$statement0 = MockStatementFactory::createWriteStatement($this, $valuesToBind0); |
62
|
|
|
|
63
|
|
|
$this->writeConnectionMock |
64
|
|
|
->expects($this->exactly(1)) |
65
|
|
|
->method('prepare') |
66
|
|
|
->withConsecutive([$sql0]) |
67
|
|
|
->willReturnOnConsecutiveCalls($statement0); |
68
|
|
|
|
69
|
|
|
$this->sut->persistNewAccessToken($accessTokenEntityMock); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
public function testPersistNewAccessTokenDbFailureThrowsException() |
73
|
|
|
{ |
74
|
|
|
$expectedCode = 17; |
75
|
|
|
$expectedMessage = 'Foo is great before: FROM api_clients AS ac'; |
76
|
|
|
|
77
|
|
|
$this->expectException(Database::class); |
78
|
|
|
$this->expectExceptionCode($expectedCode); |
79
|
|
|
$this->expectExceptionMessage($expectedMessage); |
80
|
|
|
|
81
|
|
|
$tokenId = 'foo'; |
82
|
|
|
$clientName = 'bar'; |
83
|
|
|
$expiresAt = new \DateTime(); |
84
|
|
|
|
85
|
|
|
$accessTokenEntityMock = $this->createAccessTokenStub($tokenId, $clientName, $expiresAt, []); |
86
|
|
|
|
87
|
|
|
$sql0 = 'INSERT INTO tokens (id, api_client_id, expires_at) VALUES (?, ?, ?)'; // phpcs:ignore |
88
|
|
|
$valuesToBind0 = [ |
89
|
|
|
[$tokenId, \PDO::PARAM_STR], |
90
|
|
|
[$clientName, \PDO::PARAM_STR], |
91
|
|
|
[$expiresAt->format('Y-m-d H:i:s'), \PDO::PARAM_STR], |
92
|
|
|
]; |
93
|
|
|
$errorInfo0 = ['FOO', $expectedCode, $expectedMessage]; |
94
|
|
|
$statement0 = MockStatementFactory::createErrorStatement($this, $valuesToBind0, $errorInfo0); |
95
|
|
|
|
96
|
|
|
$this->writeConnectionMock |
97
|
|
|
->expects($this->exactly(1)) |
98
|
|
|
->method('prepare') |
99
|
|
|
->withConsecutive([$sql0]) |
100
|
|
|
->willReturnOnConsecutiveCalls($statement0); |
101
|
|
|
|
102
|
|
|
$this->sut->persistNewAccessToken($accessTokenEntityMock); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
public function testPersistNewAccessTokenWithScopes() |
106
|
|
|
{ |
107
|
|
|
$tokenId = 'foo'; |
108
|
|
|
$clientName = 'bar'; |
109
|
|
|
$expiresAt = new \DateTime(); |
110
|
|
|
|
111
|
|
|
$scopeId0 = '0c4554ca-c379-46ab-9389-bfc84790bb46'; |
112
|
|
|
$scopeId1 = 'aa7076d8-02c1-4d79-becc-e754450a392f'; |
113
|
|
|
|
114
|
|
|
$scopeIdentifier0 = 'scope-0'; |
115
|
|
|
$scopeIdentifier1 = 'scope-1'; |
116
|
|
|
|
117
|
|
|
$this->uuidGeneratorMock |
118
|
|
|
->expects($this->exactly(2)) |
119
|
|
|
->method('generate') |
120
|
|
|
->willReturnOnConsecutiveCalls($scopeId0, $scopeId1); |
121
|
|
|
|
122
|
|
|
$scope = $this->createMock(ScopeEntityInterface::class); |
123
|
|
|
$scope |
124
|
|
|
->expects($this->any()) |
125
|
|
|
->method('getIdentifier') |
126
|
|
|
->willReturn($scopeIdentifier0, $scopeIdentifier1); |
127
|
|
|
|
128
|
|
|
$accessTokenEntityMock = $this->createAccessTokenStub( |
129
|
|
|
$tokenId, |
130
|
|
|
$clientName, |
131
|
|
|
$expiresAt, |
132
|
|
|
[$scope, $scope] |
133
|
|
|
); |
134
|
|
|
|
135
|
|
|
$sql0 = 'INSERT INTO tokens (id, api_client_id, expires_at) VALUES (?, ?, ?)'; // phpcs:ignore |
136
|
|
|
$valuesToBind0 = [ |
137
|
|
|
[$tokenId, \PDO::PARAM_STR], |
138
|
|
|
[$clientName, \PDO::PARAM_STR], |
139
|
|
|
[$expiresAt->format('Y-m-d H:i:s'), \PDO::PARAM_STR], |
140
|
|
|
]; |
141
|
|
|
$statement0 = MockStatementFactory::createWriteStatement($this, $valuesToBind0); |
142
|
|
|
|
143
|
|
|
$sql1 = 'INSERT INTO tokens_admin_resources (id, token_id, admin_resource_id) VALUES (?, ?, ?)'; // phpcs:ignore |
144
|
|
|
$valuesToBind1 = [ |
145
|
|
|
[$scopeId0, \PDO::PARAM_STR], |
146
|
|
|
[$tokenId, \PDO::PARAM_STR], |
147
|
|
|
[$scopeIdentifier0, \PDO::PARAM_STR], |
148
|
|
|
]; |
149
|
|
|
$statement1 = MockStatementFactory::createWriteStatement($this, $valuesToBind1); |
150
|
|
|
|
151
|
|
|
$sql2 = 'INSERT INTO tokens_admin_resources (id, token_id, admin_resource_id) VALUES (?, ?, ?)'; // phpcs:ignore |
152
|
|
|
$valuesToBind2 = [ |
153
|
|
|
[$scopeId1, \PDO::PARAM_STR], |
154
|
|
|
[$tokenId, \PDO::PARAM_STR], |
155
|
|
|
[$scopeIdentifier1, \PDO::PARAM_STR], |
156
|
|
|
]; |
157
|
|
|
$statement2 = MockStatementFactory::createWriteStatement($this, $valuesToBind2); |
158
|
|
|
|
159
|
|
|
$this->writeConnectionMock |
160
|
|
|
->expects($this->exactly(3)) |
161
|
|
|
->method('prepare') |
162
|
|
|
->withConsecutive([$sql0], [$sql1], [$sql2]) |
163
|
|
|
->willReturnOnConsecutiveCalls($statement0, $statement1, $statement2); |
164
|
|
|
|
165
|
|
|
$this->sut->persistNewAccessToken($accessTokenEntityMock); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
public function testPersistNewAccessTokenWithScopesDbFailureThrowsException() |
169
|
|
|
{ |
170
|
|
|
$expectedCode = 17; |
171
|
|
|
$expectedMessage = 'Foo is great before: FROM api_clients AS ac'; |
172
|
|
|
|
173
|
|
|
$this->expectException(Database::class); |
174
|
|
|
$this->expectExceptionCode($expectedCode); |
175
|
|
|
$this->expectExceptionMessage($expectedMessage); |
176
|
|
|
|
177
|
|
|
$tokenId = 'foo'; |
178
|
|
|
$clientName = 'bar'; |
179
|
|
|
$expiresAt = new \DateTime(); |
180
|
|
|
|
181
|
|
|
$scopeId0 = '0c4554ca-c379-46ab-9389-bfc84790bb46'; |
182
|
|
|
|
183
|
|
|
$scopeIdentifier0 = 'scope-0'; |
184
|
|
|
|
185
|
|
|
$this->uuidGeneratorMock |
186
|
|
|
->expects($this->exactly(1)) |
187
|
|
|
->method('generate') |
188
|
|
|
->willReturnOnConsecutiveCalls($scopeId0); |
189
|
|
|
|
190
|
|
|
$scope = $this->createMock(ScopeEntityInterface::class); |
191
|
|
|
$scope |
192
|
|
|
->expects($this->any()) |
193
|
|
|
->method('getIdentifier') |
194
|
|
|
->willReturn($scopeIdentifier0); |
195
|
|
|
|
196
|
|
|
$accessTokenEntityMock = $this->createAccessTokenStub( |
197
|
|
|
$tokenId, |
198
|
|
|
$clientName, |
199
|
|
|
$expiresAt, |
200
|
|
|
[$scope] |
201
|
|
|
); |
202
|
|
|
|
203
|
|
|
$sql0 = 'INSERT INTO tokens (id, api_client_id, expires_at) VALUES (?, ?, ?)'; // phpcs:ignore |
204
|
|
|
$valuesToBind0 = [ |
205
|
|
|
[$tokenId, \PDO::PARAM_STR], |
206
|
|
|
[$clientName, \PDO::PARAM_STR], |
207
|
|
|
[$expiresAt->format('Y-m-d H:i:s'), \PDO::PARAM_STR], |
208
|
|
|
]; |
209
|
|
|
$statement0 = MockStatementFactory::createWriteStatement($this, $valuesToBind0); |
210
|
|
|
|
211
|
|
|
$sql1 = 'INSERT INTO tokens_admin_resources (id, token_id, admin_resource_id) VALUES (?, ?, ?)'; // phpcs:ignore |
212
|
|
|
$valuesToBind1 = [ |
213
|
|
|
[$scopeId0, \PDO::PARAM_STR], |
214
|
|
|
[$tokenId, \PDO::PARAM_STR], |
215
|
|
|
[$scopeIdentifier0, \PDO::PARAM_STR], |
216
|
|
|
]; |
217
|
|
|
$errorInfo1 = ['FOO', $expectedCode, $expectedMessage]; |
218
|
|
|
$statement1 = MockStatementFactory::createErrorStatement($this, $valuesToBind1, $errorInfo1); |
219
|
|
|
|
220
|
|
|
$this->writeConnectionMock |
221
|
|
|
->expects($this->exactly(2)) |
222
|
|
|
->method('prepare') |
223
|
|
|
->withConsecutive([$sql0], [$sql1]) |
224
|
|
|
->willReturnOnConsecutiveCalls($statement0, $statement1); |
225
|
|
|
|
226
|
|
|
$this->sut->persistNewAccessToken($accessTokenEntityMock); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* @param string $scopeId |
231
|
|
|
* @param string $identifier |
232
|
|
|
* @param int $at |
233
|
|
|
* |
234
|
|
|
* @return ScopeEntityInterface |
235
|
|
|
*/ |
236
|
|
|
protected function createScopeStub(string $scopeId, string $identifier, int $at): ScopeEntityInterface |
237
|
|
|
{ |
238
|
|
|
$this->uuidGeneratorMock->expects($this->at($at))->method('generate')->willReturn($scopeId); |
|
|
|
|
239
|
|
|
|
240
|
|
|
$scope = $this->createMock(ScopeEntityInterface::class); |
241
|
|
|
$scope->expects($this->any())->method('getIdentifier')->willReturn($identifier); |
242
|
|
|
|
243
|
|
|
return $scope; |
|
|
|
|
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* @param string $tokenId |
248
|
|
|
* @param string $clientName |
249
|
|
|
* @param \DateTime $expiresAt |
250
|
|
|
* @param ScopeEntityInterface[] $scopes |
251
|
|
|
* |
252
|
|
|
* @return AccessTokenEntityInterface|MockObject |
253
|
|
|
*/ |
254
|
|
|
protected function createAccessTokenStub( |
255
|
|
|
string $tokenId, |
256
|
|
|
string $clientName, |
257
|
|
|
\DateTime $expiresAt, |
258
|
|
|
array $scopes |
259
|
|
|
): AccessTokenEntityInterface { |
260
|
|
|
$clientStub = $this->createMock(ClientEntityInterface::class); |
261
|
|
|
$clientStub->expects($this->any())->method('getName')->willReturn($clientName); |
262
|
|
|
|
263
|
|
|
/** @var AccessTokenEntityInterface|MockObject $accessTokenEntityMock */ |
264
|
|
|
$accessTokenEntityMock = $this->createMock(AccessTokenEntityInterface::class); |
265
|
|
|
|
266
|
|
|
$accessTokenEntityMock->expects($this->any())->method('getIdentifier')->willReturn($tokenId); |
267
|
|
|
$accessTokenEntityMock->expects($this->any())->method('getClient')->willReturn($clientStub); |
268
|
|
|
$accessTokenEntityMock->expects($this->any())->method('getExpiryDateTime')->willReturn($expiresAt); |
269
|
|
|
$accessTokenEntityMock->expects($this->any())->method('getScopes')->willReturn($scopes); |
270
|
|
|
|
271
|
|
|
return $accessTokenEntityMock; |
|
|
|
|
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
public function testRevokeAccessToken() |
275
|
|
|
{ |
276
|
|
|
$tokenId = 'foo'; |
277
|
|
|
|
278
|
|
|
$this->sut->revokeAccessToken($tokenId); |
279
|
|
|
|
280
|
|
|
// This test is expected to break if there's anything happening in AccessToken::revokeAccessToken |
281
|
|
|
$this->assertTrue(true); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
public function testIsAccessTokenRevoked() |
285
|
|
|
{ |
286
|
|
|
$tokenId = 'foo'; |
287
|
|
|
|
288
|
|
|
$actualResult = $this->sut->isAccessTokenRevoked($tokenId); |
289
|
|
|
|
290
|
|
|
$this->assertFalse($actualResult); |
291
|
|
|
} |
292
|
|
|
} |
293
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.