Skip to content
This repository was archived by the owner on Aug 7, 2023. It is now read-only.

Commit 62ec332

Browse files
Depend on PSR7 message instead HttpFoundation
1 parent 31ff9d7 commit 62ec332

13 files changed

+132
-80
lines changed

composer.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"minimum-stability": "stable",
1616
"require": {
1717
"php": ">=8.0",
18-
"symfony/http-foundation": "^5.3"
18+
"psr/http-message": "^1.0"
1919
},
2020
"autoload": {
2121
"psr-4": {
@@ -28,6 +28,8 @@
2828
}
2929
},
3030
"require-dev": {
31+
"nyholm/psr7": "^1.4",
32+
"nyholm/psr7-server": "^1.0",
3133
"phpunit/phpunit": "^9.5"
3234
}
3335
}

src/AbstractExtractor.php

+23-13
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,47 @@
1010

1111
namespace Istio\JWTPayloadExtractor;
1212

13-
use Symfony\Component\HttpFoundation\HeaderBag;
14-
use Symfony\Component\HttpFoundation\InputBag;
15-
use Symfony\Component\HttpFoundation\Request;
13+
use Psr\Http\Message\ServerRequestInterface;
1614

1715
abstract class AbstractExtractor implements ExtractorInterface
1816
{
19-
private string $requestBag;
17+
private string $in;
2018

21-
private string $itemName;
19+
private string $item;
2220

2321
private string $issuer;
2422

2523
public function __construct(
2624
string $issuer,
27-
string $requestBag,
28-
string $itemName
25+
string $in,
26+
string $item
2927
) {
3028
if ('' === $issuer) {
3129
throw new \LogicException('Issuer can not be blank!');
3230
}
3331

32+
if (ExtractorInterface::IN_HEADER !== $in && ExtractorInterface::IN_QUERY_PARAM !== $in) {
33+
throw new \LogicException(
34+
sprintf(
35+
'Origin token must in: `%s` or `%s`, can not in: `%s`',
36+
ExtractorInterface::IN_HEADER,
37+
ExtractorInterface::IN_QUERY_PARAM,
38+
$in
39+
)
40+
);
41+
}
42+
3443
$this->issuer = $issuer;
35-
$this->requestBag = $requestBag;
36-
$this->itemName = $itemName;
44+
$this->in = $in;
45+
$this->item = $item;
3746
}
3847

39-
final public function extract(Request $request): ?array
48+
final public function extract(ServerRequestInterface $request): ?array
4049
{
41-
/** @var InputBag|HeaderBag $bag */
42-
$bag = $request->{$this->requestBag};
43-
$value = $bag->get($this->itemName);
50+
$value = match ($this->in) {
51+
ExtractorInterface::IN_HEADER => $request->getHeader($this->item)[0] ?? null,
52+
ExtractorInterface::IN_QUERY_PARAM => $request->getQueryParams()[$this->item] ?? null
53+
};
4454

4555
if (false === is_string($value)) {
4656
return null;

src/Base64HeaderExtractor.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212

1313
final class Base64HeaderExtractor extends AbstractExtractor
1414
{
15-
public function __construct(string $issuer, string $itemName)
15+
public function __construct(string $issuer, string $item)
1616
{
17-
parent::__construct($issuer, 'headers', $itemName);
17+
parent::__construct($issuer, ExtractorInterface::IN_HEADER, $item);
1818
}
1919

2020
protected function extractFromValue(string $value): ?array

src/CompositeExtractor.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010

1111
namespace Istio\JWTPayloadExtractor;
1212

13-
use Symfony\Component\HttpFoundation\Request;
13+
use Psr\Http\Message\ServerRequestInterface;
1414

1515
final class CompositeExtractor implements ExtractorInterface
1616
{
1717
public function __construct(private iterable $extractors)
1818
{
1919
}
2020

21-
public function extract(Request $request): ?array
21+
public function extract(ServerRequestInterface $request): ?array
2222
{
2323
foreach ($this->extractors as $extractor) {
2424
/** @var ExtractorInterface $extractor */

src/ExtractorFactory.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ public static function fromBase64Header(string $issuer, string $header): Base64H
1919

2020
public static function fromOriginTokenHeader(string $issuer, string $header): OriginTokenExtractor
2121
{
22-
return new OriginTokenExtractor($issuer, 'headers', $header);
22+
return new OriginTokenExtractor($issuer, ExtractorInterface::IN_HEADER, $header);
2323
}
2424

2525
public static function fromOriginTokenQueryParam(string $issuer, string $queryParam): OriginTokenExtractor
2626
{
27-
return new OriginTokenExtractor($issuer, 'query', $queryParam);
27+
return new OriginTokenExtractor($issuer, ExtractorInterface::IN_QUERY_PARAM, $queryParam);
2828
}
2929

3030
public static function fromExtractors(ExtractorInterface ...$extractors): CompositeExtractor

src/ExtractorInterface.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010

1111
namespace Istio\JWTPayloadExtractor;
1212

13-
use Symfony\Component\HttpFoundation\Request;
13+
use Psr\Http\Message\ServerRequestInterface;
1414

1515
interface ExtractorInterface
1616
{
17-
public function extract(Request $request): ?array;
17+
public const IN_HEADER = 'header';
18+
19+
public const IN_QUERY_PARAM = 'query_param';
20+
21+
public function extract(ServerRequestInterface $request): ?array;
1822
}

src/OriginTokenExtractor.php

-9
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,6 @@
1212

1313
final class OriginTokenExtractor extends AbstractExtractor
1414
{
15-
public function __construct(string $issuer, string $requestBag, string $itemName)
16-
{
17-
if ('headers' !== $requestBag && 'query' !== $requestBag) {
18-
throw new \LogicException(sprintf('Invalid request bag `%s`! Origin token must in: `headers` or `query` bag.', $requestBag));
19-
}
20-
21-
parent::__construct($issuer, $requestBag, $itemName);
22-
}
23-
2415
protected function extractFromValue(string $value): ?array
2516
{
2617
$tokenParts = explode('.', $value, 3);

tests/Base64HeaderExtractorTest.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
use Istio\JWTPayloadExtractor\Base64HeaderExtractor;
1414
use PHPUnit\Framework\TestCase;
15-
use Symfony\Component\HttpFoundation\Request;
15+
use Psr\Http\Message\ServerRequestInterface;
1616

1717
class Base64HeaderExtractorTest extends TestCase
1818
{
@@ -23,13 +23,13 @@ public function testInitWithBlankIssuer(): void
2323
$this->expectException(\LogicException::class);
2424
$this->expectExceptionMessageMatches('~can not be blank!~');
2525

26-
new Base64HeaderExtractor('', 'Authorization');
26+
new Base64HeaderExtractor('', 'authorization');
2727
}
2828

2929
/**
3030
* @dataProvider invalidRequests
3131
*/
32-
public function testExtractFromInvalidRequests(Request $inHeader)
32+
public function testExtractFromInvalidRequests(ServerRequestInterface $inHeader)
3333
{
3434
$extractor = new Base64HeaderExtractor('valid', 'Authorization');
3535
$payloadFromHeader = $extractor->extract($inHeader);
@@ -40,7 +40,7 @@ public function testExtractFromInvalidRequests(Request $inHeader)
4040
/**
4141
* @dataProvider validRequests
4242
*/
43-
public function testExtractFromValidRequests(Request $inHeader)
43+
public function testExtractFromValidRequests(ServerRequestInterface $inHeader)
4444
{
4545
$extractor = new Base64HeaderExtractor('valid', 'Authorization');
4646
$payloadFromHeader = $extractor->extract($inHeader);

tests/CompositeExtractorTest.php

+20-18
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
use Istio\JWTPayloadExtractor\ExtractorFactory;
1414
use Istio\JWTPayloadExtractor\ExtractorInterface;
1515
use PHPUnit\Framework\TestCase;
16-
use Symfony\Component\HttpFoundation\Request;
16+
use Psr\Http\Message\ServerRequestInterface;
1717

1818
class CompositeExtractorTest extends TestCase
1919
{
20+
use RequestCreatorTrait;
21+
2022
/**
2123
* @dataProvider validRequests
2224
*/
23-
public function testExtractFromValidRequestsWithEmptyExtractors(Request $request): void
25+
public function testExtractFromValidRequestsWithEmptyExtractors(ServerRequestInterface $request): void
2426
{
2527
$extractor = ExtractorFactory::fromExtractors();
2628
$payload = $extractor->extract($request);
@@ -31,7 +33,7 @@ public function testExtractFromValidRequestsWithEmptyExtractors(Request $request
3133
/**
3234
* @dataProvider validRequests
3335
*/
34-
public function testExtractFromValidRequests(Request $request): void
36+
public function testExtractFromValidRequests(ServerRequestInterface $request): void
3537
{
3638
$extractor = $this->getExtractor();
3739
$payload = $extractor->extract($request);
@@ -43,7 +45,7 @@ public function testExtractFromValidRequests(Request $request): void
4345
/**
4446
* @dataProvider invalidRequests
4547
*/
46-
public function testExtractFromInvalidRequests(Request $request): void
48+
public function testExtractFromInvalidRequests(ServerRequestInterface $request): void
4749
{
4850
$extractor = $this->getExtractor();
4951
$payload = $extractor->extract($request);
@@ -54,32 +56,32 @@ public function testExtractFromInvalidRequests(Request $request): void
5456
public function validRequests(): array
5557
{
5658
return [
57-
[Request::create('', server: ['HTTP_X_JWT_PAYLOAD' => $this->getValidBase64Payload()])],
58-
[Request::create('', server: ['HTTP_AUTHORIZATION' => $this->getValidOriginToken()])],
59-
[Request::create('', parameters: ['token' => $this->getValidOriginToken()])],
59+
[$this->createRequest(headers: ['x-jwt-payload' => $this->getValidBase64Payload()])],
60+
[$this->createRequest(headers: ['authorization' => $this->getValidOriginToken()])],
61+
[$this->createRequest(queryParams: ['token' => $this->getValidOriginToken()])],
6062
];
6163
}
6264

6365
public function invalidRequests(): array
6466
{
6567
return [
66-
[Request::create('')],
67-
[Request::create('', server: ['HTTP_X_JWT_PAYLOAD' => ''])],
68-
[Request::create('', server: ['HTTP_AUTHORIZATION' => ''])],
69-
[Request::create('', parameters: ['token' => ''])],
70-
[Request::create('', server: ['HTTP_X_JWT_PAYLOAD' => $this->getValidOriginToken()])],
71-
[Request::create('', server: ['HTTP_AUTHORIZATION' => $this->getValidBase64Payload()])],
72-
[Request::create('', server: ['HTTP_X_JWT_PAYLOAD' => $this->getInvalidBase64Payload()])],
73-
[Request::create('', server: ['HTTP_AUTHORIZATION' => $this->getInvalidOriginToken()])],
74-
[Request::create('', parameters: ['token' => $this->getInvalidOriginToken()])],
68+
[$this->createRequest()],
69+
[$this->createRequest(headers: ['x-jwt-payload' => ''])],
70+
[$this->createRequest(headers: ['authorization' => ''])],
71+
[$this->createRequest(queryParams: ['token' => ''])],
72+
[$this->createRequest(headers: ['x-jwt-payload' => $this->getValidOriginToken()])],
73+
[$this->createRequest(headers: ['authorization' => $this->getValidBase64Payload()])],
74+
[$this->createRequest(headers: ['x-jwt-payload' => $this->getInvalidBase64Payload()])],
75+
[$this->createRequest(headers: ['authorization' => $this->getInvalidOriginToken()])],
76+
[$this->createRequest(queryParams: ['token' => $this->getInvalidOriginToken()])],
7577
];
7678
}
7779

7880
private function getExtractor(): ExtractorInterface
7981
{
8082
return ExtractorFactory::fromExtractors(
81-
ExtractorFactory::fromBase64Header('valid', 'X-JWT-Payload'),
82-
ExtractorFactory::fromOriginTokenHeader('valid', 'Authorization'),
83+
ExtractorFactory::fromBase64Header('valid', 'x-jwt-payload'),
84+
ExtractorFactory::fromOriginTokenHeader('valid', 'authorization'),
8385
ExtractorFactory::fromOriginTokenQueryParam('valid', 'token'),
8486
);
8587
}

tests/ExtractorFactoryTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function testMatchInstanceOf(): void
2222
{
2323
$this->assertInstanceOf(
2424
OriginTokenExtractor::class,
25-
ExtractorFactory::fromOriginTokenHeader('valid', 'Authorization')
25+
ExtractorFactory::fromOriginTokenHeader('valid', 'authorization')
2626
);
2727

2828
$this->assertInstanceOf(
@@ -32,7 +32,7 @@ public function testMatchInstanceOf(): void
3232

3333
$this->assertInstanceOf(
3434
Base64HeaderExtractor::class,
35-
ExtractorFactory::fromBase64Header('valid', 'Authorization')
35+
ExtractorFactory::fromBase64Header('valid', 'authorization')
3636
);
3737

3838
$this->assertInstanceOf(

tests/OriginTokenExtractorTest.php

+16-11
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010

1111
namespace Istio\JWTPayloadExtractor\Tests;
1212

13+
use Istio\JWTPayloadExtractor\ExtractorInterface;
1314
use Istio\JWTPayloadExtractor\OriginTokenExtractor;
1415
use PHPUnit\Framework\TestCase;
15-
use Symfony\Component\HttpFoundation\Request;
16+
use Psr\Http\Message\ServerRequestInterface;
1617

1718
class OriginTokenExtractorTest extends TestCase
1819
{
@@ -23,22 +24,26 @@ public function testInitWithBlankIssuer(): void
2324
$this->expectException(\LogicException::class);
2425
$this->expectExceptionMessageMatches('~can not be blank!~');
2526

26-
new OriginTokenExtractor('', 'headers', 'Authorization');
27+
new OriginTokenExtractor('', 'headers', 'authorization');
2728
}
2829

29-
public function testInitWithInvalidRequestBag(): void
30+
public function testInitWithInvalidIn(): void
3031
{
3132
$this->expectException(\LogicException::class);
32-
$this->expectExceptionMessageMatches('~`headers` or `query`~');
33+
$this->expectExceptionMessageMatches(
34+
sprintf('~`%s` or `%s`~', ExtractorInterface::IN_HEADER, ExtractorInterface::IN_QUERY_PARAM)
35+
);
3336

34-
new OriginTokenExtractor('valid', 'invalid bag', 'Authorization');
37+
new OriginTokenExtractor('valid', 'invalid', 'authorization');
3538
}
3639

3740
/**
3841
* @dataProvider invalidRequests
3942
*/
40-
public function testExtractFromInvalidRequests(Request $inHeader, Request $inQueryParam): void
41-
{
43+
public function testExtractFromInvalidRequests(
44+
ServerRequestInterface $inHeader,
45+
ServerRequestInterface $inQueryParam
46+
): void {
4247
[$payloadFromHeader, $payloadFromQueryParam] = $this->extractRequests($inHeader, $inQueryParam);
4348

4449
$this->assertNull($payloadFromHeader);
@@ -48,7 +53,7 @@ public function testExtractFromInvalidRequests(Request $inHeader, Request $inQue
4853
/**
4954
* @dataProvider validRequests
5055
*/
51-
public function testExtractFromValidRequests(Request $inHeader, Request $inQueryParam)
56+
public function testExtractFromValidRequests(ServerRequestInterface $inHeader, ServerRequestInterface $inQueryParam)
5257
{
5358
[$payloadFromHeader, $payloadFromQueryParam] = $this->extractRequests($inHeader, $inQueryParam);
5459

@@ -58,10 +63,10 @@ public function testExtractFromValidRequests(Request $inHeader, Request $inQuery
5863
$this->assertSame('valid', $payloadFromQueryParam['iss']);
5964
}
6065

61-
private function extractRequests(Request $inHeader, Request $inQueryParam): array
66+
private function extractRequests(ServerRequestInterface $inHeader, ServerRequestInterface $inQueryParam): array
6267
{
63-
$headerExtractor = new OriginTokenExtractor('valid', 'headers', 'Authorization');
64-
$queryParamExtractor = new OriginTokenExtractor('valid', 'query', 'token');
68+
$headerExtractor = new OriginTokenExtractor('valid', ExtractorInterface::IN_HEADER, 'authorization');
69+
$queryParamExtractor = new OriginTokenExtractor('valid', ExtractorInterface::IN_QUERY_PARAM, 'token');
6570

6671
return [$headerExtractor->extract($inHeader), $queryParamExtractor->extract($inQueryParam)];
6772
}

tests/RequestCreatorTrait.php

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/*
3+
* (c) Minh Vuong <[email protected]>
4+
*
5+
* This source file is subject to the MIT license that is bundled
6+
* with this source code in the file LICENSE.
7+
*/
8+
9+
declare(strict_types=1);
10+
11+
namespace Istio\JWTPayloadExtractor\Tests;
12+
13+
use Nyholm\Psr7\Factory\Psr17Factory;
14+
use Nyholm\Psr7Server\ServerRequestCreator;
15+
use Psr\Http\Message\ServerRequestInterface;
16+
17+
trait RequestCreatorTrait
18+
{
19+
private function createRequest(array $headers = [], array $queryParams = []): ServerRequestInterface
20+
{
21+
$psr17Factory = new Psr17Factory();
22+
$creator = new ServerRequestCreator(
23+
$psr17Factory,
24+
$psr17Factory,
25+
$psr17Factory,
26+
$psr17Factory
27+
);
28+
29+
return $creator->fromArrays(
30+
[
31+
'REQUEST_METHOD' => 'GET',
32+
'REQUEST_URI' => '/',
33+
],
34+
headers: $headers,
35+
get: $queryParams
36+
);
37+
}
38+
}

0 commit comments

Comments
 (0)