Skip to content

Commit ec9ca51

Browse files
committed
Move credentials to JWTImpl
1 parent 4efe7cf commit ec9ca51

File tree

5 files changed

+62
-46
lines changed

5 files changed

+62
-46
lines changed

src/Plugin/JWT/JWTFirebaseV5.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
/**
44
* The MIT License (MIT)
55
* Copyright (c) 2022 Redbit s.r.o., Jakub Bouček
6+
*
7+
* @noinspection PhpUndefinedClassInspection OpenSSL only optional dependency
68
*/
79

810
declare(strict_types=1);
@@ -15,6 +17,20 @@
1517

1618
class JWTFirebaseV5 implements JWTImpl
1719
{
20+
/** @var OpenSSLAsymmetricKey|OpenSSLCertificate|resource|string */
21+
protected $key;
22+
protected string $algorithm;
23+
24+
/**
25+
* @param OpenSSLAsymmetricKey|OpenSSLCertificate|resource|string $key
26+
* @param string $algorithm
27+
*/
28+
public function __construct($key, string $algorithm = 'HS256')
29+
{
30+
$this->key = $key;
31+
$this->algorithm = $algorithm;
32+
}
33+
1834
public static function isAvailable(): bool
1935
{
2036
if (class_exists(JWT::class) === false) {
@@ -34,14 +50,14 @@ public static function isAvailable(): bool
3450
&& $params[2]->getName() === 'allowed_algs';
3551
}
3652

37-
public function decode(string $jwt, $key, string $alg): stdClass
53+
public function decode(string $jwt): stdClass
3854
{
39-
return JWT::decode($jwt, $key, [$alg]);
55+
return JWT::decode($jwt, $this->key, [$this->algorithm]);
4056
}
4157

42-
public function encode(array $payload, $key, string $alg): string
58+
public function encode(array $payload): string
4359
{
44-
return JWT::encode($payload, $key, $alg);
60+
return JWT::encode($payload, $this->key, $this->algorithm);
4561
}
4662

4763
public function setTimestamp(?int $timestamp): void

src/Plugin/JWT/JWTFirebaseV6.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
/**
44
* The MIT License (MIT)
55
* Copyright (c) 2022 Redbit s.r.o., Jakub Bouček
6+
*
7+
* @noinspection PhpUndefinedClassInspection Library support JWT 5.0
68
*/
79

810
declare(strict_types=1);
@@ -33,9 +35,9 @@ public static function isAvailable(): bool
3335
return isset($params[2]) === false || $params[2]->getName() !== 'allowed_algs';
3436
}
3537

36-
public function decode(string $jwt, $key, string $alg): stdClass
38+
public function decode(string $jwt): stdClass
3739
{
38-
return JWT::decode($jwt, new Key($key, $alg));
40+
return JWT::decode($jwt, new Key($this->key, $this->algorithm));
3941
}
4042

4143

src/Plugin/JWT/JWTImpl.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ interface JWTImpl
1515
{
1616
public static function isAvailable(): bool;
1717

18-
public function decode(string $jwt, $key, string $alg): stdClass;
18+
public function decode(string $jwt): stdClass;
1919

20-
public function encode(array $payload, $key, string $alg): string;
20+
public function encode(array $payload): string;
2121

2222
public function setTimestamp(?int $timestamp): void;
2323
}

src/Plugin/SignedUrl.php

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,37 +45,35 @@ class SignedUrl implements Plugin
4545
private const URL_QUERY_TOKEN_KEY = '_debug';
4646
private const ISSUER_ID = 'cz.redbit.debug.url';
4747

48-
/** @var resource|string|OpenSSLAsymmetricKey|OpenSSLCertificate */
49-
private $key;
50-
private string $algorithm;
5148
private ?string $audience;
5249
private ?int $timestamp;
5350

5451
private JWTImpl $jwt;
5552

53+
/**
54+
* @param string|null $audience Recipient for which the JWT is intended
55+
*/
56+
public function __construct(JWTImpl $jwt, ?string $audience = null)
57+
{
58+
$this->jwt = $jwt;
59+
$this->audience = $audience;
60+
}
61+
5662
/**
5763
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The key.
5864
* @param string $algorithm Supported algorithms are 'ES384','ES256', 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
59-
* @param string|null $audience Recipient for which the JWT is intended
6065
* @noinspection PhpRedundantVariableDocTypeInspection
6166
*/
62-
public function __construct($key, string $algorithm = 'HS256', ?string $audience = null)
67+
public static function create($key, string $algorithm = 'HS256', ?string $audience = null): self
6368
{
6469
/** @var class-string<JWTImpl> $impl */
6570
foreach ([JWTFirebaseV5::class, JWTFirebaseV6::class] as $impl) {
6671
if ($impl::isAvailable()) {
67-
$this->jwt = new $impl;
68-
break;
72+
return new self(new $impl($key, $algorithm), $audience);
6973
}
7074
}
7175

72-
if (isset($this->jwt) === false) {
73-
throw new LogicException(__CLASS__ . ' requires JWT library: firebase/php-jwt version ~5.0 or ~6.0');
74-
}
75-
76-
$this->key = $key;
77-
$this->algorithm = $algorithm;
78-
$this->audience = $audience;
76+
throw new LogicException(__CLASS__ . ' requires JWT library: firebase/php-jwt version ~5.0 or ~6.0');
7977
}
8078

8179
/**
@@ -134,7 +132,7 @@ public function getToken(
134132
'val' => $value,
135133
];
136134

137-
return $this->jwt->encode($payload, $this->key, $this->algorithm);
135+
return $this->jwt->encode($payload);
138136
}
139137

140138
public function __invoke(Detector $detector): ?bool
@@ -246,7 +244,7 @@ public function verifyToken(string $token): array
246244
{
247245
try {
248246
/** @var ClaimsSet $payload */
249-
$payload = $this->jwt->decode($token, $this->key, $this->algorithm);
247+
$payload = $this->jwt->decode($token);
250248
} catch (RuntimeException $e) {
251249
throw new SignedUrlVerificationException('JWT Token invalid', 0, $e);
252250
}

tests/Plugin/SignUrlTest.php

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function testSign(): void
3131
{
3232
$audience = 'test.' . __FUNCTION__;
3333

34-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
34+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
3535
$plugin->setTimestamp(1600000000);
3636
$token = $plugin->signUrl('https://host.tld/path', 1600000600);
3737

@@ -54,7 +54,7 @@ public function testSignQuery(): void
5454
{
5555
$audience = 'test.' . __FUNCTION__;
5656

57-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
57+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
5858
$plugin->setTimestamp(1600000000);
5959
$token = $plugin->signUrl('https://host.tld/path?query=value', 1600000600);
6060

@@ -77,7 +77,7 @@ public function testSignFragment(): void
7777
{
7878
$audience = 'test.' . __FUNCTION__;
7979

80-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
80+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
8181
$plugin->setTimestamp(1600000000);
8282
$token = $plugin->signUrl('https://host.tld/path?query=value#fragment', 1600000600);
8383

@@ -100,7 +100,7 @@ public function testGetToken(): void
100100
{
101101
$audience = 'test.' . __FUNCTION__;
102102

103-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
103+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
104104
$plugin->setTimestamp(1600000000);
105105
$token = $plugin->getToken(
106106
'https://host.tld/path?query=value',
@@ -130,7 +130,7 @@ public function testVerifyToken(): void
130130
$audience = 'test.' . __FUNCTION__;
131131
$timestamp = 1600000000;
132132

133-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
133+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
134134
$plugin->setTimestamp($timestamp);
135135
$token = $plugin->getToken(
136136
'https://host.tld/path?query=value',
@@ -140,7 +140,7 @@ public function testVerifyToken(): void
140140
SignedUrl::VALUE_ENABLE
141141
);
142142

143-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
143+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
144144
$plugin->setTimestamp($timestamp);
145145
JWT::$timestamp = $timestamp;
146146
$parsed = $plugin->verifyToken($token);
@@ -154,11 +154,11 @@ public function testVerifyUrl(): void
154154
$timestamp = 1600000000;
155155
$url = 'https://host.tld/path';
156156

157-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
157+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
158158
$plugin->setTimestamp($timestamp);
159159
$tokenUrl = $plugin->signUrl($url, 1600000600);
160160

161-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
161+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
162162
$plugin->setTimestamp($timestamp);
163163
JWT::$timestamp = $timestamp;
164164
$parsed = $plugin->verifyUrl($tokenUrl);
@@ -172,11 +172,11 @@ public function testVerifyUrlQuery(): void
172172
$timestamp = 1600000000;
173173
$url = 'https://host.tld/path?query=value';
174174

175-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
175+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
176176
$plugin->setTimestamp($timestamp);
177177
$tokenUrl = $plugin->signUrl($url, 1600000600);
178178

179-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
179+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
180180
$plugin->setTimestamp($timestamp);
181181
JWT::$timestamp = $timestamp;
182182
$parsed = $plugin->verifyUrl($tokenUrl);
@@ -190,11 +190,11 @@ public function testVerifyRequest(): void
190190
$timestamp = 1600000000;
191191
$url = 'https://host.tld/path?query=value';
192192

193-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
193+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
194194
$plugin->setTimestamp($timestamp);
195195
$tokenUrl = $plugin->signUrl($url, 1600000600);
196196

197-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
197+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
198198
$plugin->setTimestamp($timestamp);
199199
JWT::$timestamp = $timestamp;
200200
$parsed = $plugin->verifyRequest(false, $tokenUrl, 'GET');
@@ -206,7 +206,7 @@ public function testSignInvalidUrl(): void
206206
{
207207
Assert::exception(static function () {
208208
$url = (string)base64_decode('Ly8Eijrg+qawZw==');
209-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256');
209+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256');
210210
$plugin->signUrl($url, 1600000600);
211211
}, LogicException::class);
212212
}
@@ -215,7 +215,7 @@ public function testSignRelativeUrl(): void
215215
{
216216
Assert::exception(static function () {
217217
$url = '/login?email=foo@bar.cz';
218-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256');
218+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256');
219219
$plugin->signUrl($url, 1600000600);
220220
}, LogicException::class);
221221
}
@@ -226,11 +226,11 @@ public function testVerifyPostRequest(): void
226226
$timestamp = 1600000000;
227227
$url = 'https://host.tld/path?query=value';
228228

229-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
229+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
230230
$plugin->setTimestamp($timestamp);
231231
$tokenUrl = $plugin->signUrl($url, 1600000600);
232232

233-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
233+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256', $audience);
234234
$plugin->setTimestamp($timestamp);
235235
JWT::$timestamp = $timestamp;
236236
Assert::exception(static function () use ($plugin, $tokenUrl) {
@@ -241,7 +241,7 @@ public function testVerifyPostRequest(): void
241241
public function testVerifyInvalidRequest(): void
242242
{
243243
Assert::exception(static function () {
244-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256');
244+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256');
245245
$url = (string)base64_decode('Ly8Eijrg+qawZw==');
246246
$plugin->verifyRequest(false, $url, 'GET');
247247
}, SignedUrlVerificationException::class, 'Url is invalid');
@@ -250,7 +250,7 @@ public function testVerifyInvalidRequest(): void
250250
public function testVerifyInvalidUrl(): void
251251
{
252252
Assert::exception(static function () {
253-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256');
253+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256');
254254
$plugin->verifyUrl('https://host.tld/path?query=value');
255255
}, SignedUrlVerificationException::class, 'No token in URL');
256256
}
@@ -260,15 +260,15 @@ public function testVerifyUrlWithSuffix(): void
260260
$timestamp = 1600000000;
261261
$url = 'https://host.tld/path?query=value';
262262

263-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256');
263+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256');
264264
$plugin->setTimestamp($timestamp);
265265
$tokenUrl = $plugin->signUrl($url, 1600000600);
266266

267267
$tokenUrl .= '&fbclid=123456789';
268268

269269
Assert::exception(
270270
static function () use ($timestamp, $tokenUrl) {
271-
$plugin = new SignedUrl(self::KEY_HS256, 'HS256');
271+
$plugin = SignedUrl::create(self::KEY_HS256, 'HS256');
272272
$plugin->setTimestamp($timestamp);
273273
JWT::$timestamp = $timestamp;
274274
$plugin->verifyUrl($tokenUrl);
@@ -288,7 +288,7 @@ public function testVerifyUrlWithSuffixRedirect(): void
288288
. '&fbclid=123456789';
289289

290290
// Mock plugin without redirect
291-
$plugin = new class(self::KEY_HS256, 'HS256', 'test.testSign') extends SignedUrl {
291+
$plugin = new class(SignedUrl::create(self::KEY_HS256)->getJwt(), 'test.testSign') extends SignedUrl {
292292
protected function sendRedirectResponse(string $canonicalUrl): void
293293
{
294294
$expected = 'https://host.tld/path?query=value&_debug=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJj'
@@ -315,7 +315,7 @@ public function testVerifyUrlWithSuffixRedirectFragment(): void
315315
. '#hash';
316316

317317
// Mock plugin without redirect
318-
$plugin = new class(self::KEY_HS256, 'HS256', 'test.testSign') extends SignedUrl {
318+
$plugin = new class(SignedUrl::create(self::KEY_HS256)->getJwt(), 'test.testSign') extends SignedUrl {
319319
protected function sendRedirectResponse(string $canonicalUrl): void
320320
{
321321
$expected = 'https://host.tld/path?query=value'

0 commit comments

Comments
 (0)