-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathAuth.php
171 lines (151 loc) · 4.78 KB
/
Auth.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<?php
declare(strict_types=1);
namespace App\Tests\TestCase;
use App\ApiKey\Domain\Entity\ApiKey;
use App\General\Domain\Utils\JSON;
use App\Role\Application\Security\Interfaces\RolesServiceInterface;
use JsonException;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Component\HttpKernel\KernelInterface;
use Throwable;
use UnexpectedValueException;
use function array_key_exists;
use function file_get_contents;
use function file_put_contents;
use function getenv;
use function is_string;
use function property_exists;
use function sha1;
use function sprintf;
use function str_pad;
use function sys_get_temp_dir;
use const DIRECTORY_SEPARATOR;
/**
* @package App\Tests
*/
class Auth
{
public function __construct(
private readonly KernelInterface $kernel,
private readonly RolesServiceInterface $rolesService
) {
}
/**
* Method to get authorization headers for specified user.
*
* @return array<string, string>
*
* @throws Throwable
*/
public function getAuthorizationHeadersForUser(string $username, string $password): array
{
// Return valid authorization headers for user
return $this->getAuthorizationHeaders($this->getToken($username, $password));
}
/**
* Method to get authorization headers for specified API Key role.
*
* @return array<string, string>
*/
public function getAuthorizationHeadersForApiKey(string $role): array
{
return [
...$this->getContentTypeHeader(),
...[
'HTTP_AUTHORIZATION' => 'ApiKey '
. str_pad($this->rolesService->getShort($role), ApiKey::TOKEN_LENGTH, '_'),
],
];
}
/**
* Method to get authorization headers for specified token.
*
* @return array<string, string>
*/
public function getAuthorizationHeaders(string $token): array
{
return [
...$this->getContentTypeHeader(),
...[
'HTTP_AUTHORIZATION' => 'Bearer ' . $token,
],
];
}
/**
* @return array<string, string>
*/
public function getJwtHeaders(): array
{
return [
'REMOTE_ADDR' => '123.123.123.123',
'HTTP_USER_AGENT' => 'foobar',
];
}
/**
* Method to make actual login to application with specified username and password.
*
* @codeCoverageIgnore
*
* @throws UnexpectedValueException
* @throws JsonException
*/
private function getToken(string $username, string $password): string
{
$testChannel = getenv('ENV_TEST_CHANNEL_READABLE');
// Specify used cache file
$filename = sprintf(
'%s%stest_jwt_auth_cache%s.json',
sys_get_temp_dir(),
DIRECTORY_SEPARATOR,
is_string($testChannel) ? $testChannel : '',
);
// Read current cache
$cache = (array)JSON::decode((string)file_get_contents($filename), true);
// Create hash for username + password
$hash = sha1($username . $password);
// User + password doesn't exist on cache - so we need to make real login
if (!array_key_exists($hash, $cache)) {
/** @var KernelBrowser $client */
$client = $this->kernel->getContainer()->get('test.client');
// Create request to make login using given credentials
$client->request(
'POST',
WebTestCase::API_URL_PREFIX . '/v1/auth/get_token',
[],
[],
[
...$this->getJwtHeaders(),
...$this->getContentTypeHeader(),
...[
'HTTP_X-Requested-With' => 'XMLHttpRequest',
],
],
JSON::encode([
'username' => $username,
'password' => $password,
])
);
$response = $client->getResponse();
if ($response->getStatusCode() !== 200) {
throw new UnexpectedValueException(
'Invalid status code: ' . $response->getStatusCode() . " Response:\n" . $response
);
}
/** @var object $payload */
$payload = JSON::decode((string)$response->getContent());
$cache[$hash] = property_exists($payload, 'token') ? (string)$payload->token : '';
}
// And finally store cache for later usage
file_put_contents($filename, JSON::encode($cache));
return (string)$cache[$hash];
}
/**
* @return array<string, string>
*/
private function getContentTypeHeader(): array
{
return [
'CONTENT_TYPE' => 'application/json',
];
}
}