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

Commit 14e3fd7

Browse files
First commit
0 parents  commit 14e3fd7

11 files changed

+339
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*.log
2+
/.php_cs
3+
/.php_cs.cache
4+
/.phpunit.result.cache
5+
/vendor/
6+
/composer.lock
7+
.php-cs-fixer.php
8+
.php-cs-fixer.cache

.php-cs-fixer.dist.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
$finder = PhpCsFixer\Finder::create()
6+
->in(__DIR__)
7+
->append([__FILE__]);
8+
9+
return (new PhpCsFixer\Config())
10+
->setUsingCache(true)
11+
->setRules(
12+
[
13+
'@PSR12' => true,
14+
'@Symfony' => true,
15+
'array_indentation' => true,
16+
'class_definition' => ['multi_line_extends_each_single_line' => true],
17+
'compact_nullable_typehint' => true,
18+
'concat_space' => ['spacing' => 'one'],
19+
'declare_strict_types' => true,
20+
'heredoc_to_nowdoc' => true,
21+
'global_namespace_import' => [
22+
'import_classes' => false,
23+
'import_constants' => false,
24+
'import_functions' => false,
25+
],
26+
'list_syntax' => ['syntax' => 'short'],
27+
'no_null_property_initialization' => true,
28+
'phpdoc_to_comment' => false,
29+
'phpdoc_align' => ['align' => 'left'],
30+
'phpdoc_summary' => false,
31+
'ternary_to_null_coalescing' => true,
32+
]
33+
)
34+
->setRiskyAllowed(true)
35+
->setFinder($finder);

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License
2+
3+
Copyright (c) 2021 Minh Vuong <vuongxuongminh@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

composer.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "php-istio/jwt-payload-extractor",
3+
"description": "Library to help extract JWT payload from Istio Envoy proxy.",
4+
"type": "library",
5+
"license": "MIT",
6+
"authors": [
7+
{
8+
"name": "Minh Vuong",
9+
"email": "vuongxuongminh@gmail.com"
10+
}
11+
],
12+
"config": {
13+
"sort-packages": true
14+
},
15+
"minimum-stability": "stable",
16+
"require": {
17+
"php": ">=8.0",
18+
"symfony/http-foundation": "^5.3"
19+
},
20+
"autoload": {
21+
"psr-4": {
22+
"Istio\\JWTPayloadExtractor\\": "src"
23+
}
24+
},
25+
"autoload-dev": {
26+
"psr-4": {
27+
"Istio\\JWTPayloadExtractor\\Tests\\": "tests"
28+
}
29+
},
30+
"require-dev": {
31+
"phpunit/phpunit": "^9.5"
32+
}
33+
}

phpunit.xml.dist

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true">
4+
<php>
5+
<ini name="error_reporting" value="-1" />
6+
</php>
7+
8+
<testsuites>
9+
<testsuite name="Library Test Suite">
10+
<directory>tests</directory>
11+
</testsuite>
12+
</testsuites>
13+
14+
<coverage processUncoveredFiles="true">
15+
<include>
16+
<directory>.</directory>
17+
</include>
18+
<exclude>
19+
<directory>tests</directory>
20+
<directory>vendor</directory>
21+
<file>.php-cs-fixer.dist.php</file>
22+
</exclude>
23+
</coverage>
24+
</phpunit>

src/AbstractExtractor.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
/*
3+
* (c) Minh Vuong <vuongxuongminh@gmail.com>
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;
12+
13+
use Symfony\Component\HttpFoundation\HeaderBag;
14+
use Symfony\Component\HttpFoundation\InputBag;
15+
use Symfony\Component\HttpFoundation\Request;
16+
17+
abstract class AbstractExtractor implements ExtractorInterface
18+
{
19+
private string $requestBag;
20+
21+
private string $itemName;
22+
23+
private string $issuer;
24+
25+
public function __construct(
26+
string $issuer,
27+
string $requestBag,
28+
string $itemName
29+
) {
30+
if ('' === $issuer) {
31+
throw new \LogicException('Issuer can not be blank!');
32+
}
33+
34+
$this->issuer = $issuer;
35+
$this->requestBag = $requestBag;
36+
$this->itemName = $itemName;
37+
}
38+
39+
final public function extract(Request $request): ?array
40+
{
41+
/** @var InputBag|HeaderBag $bag */
42+
$bag = $request->{$this->requestBag};
43+
$value = $bag->get($this->itemName);
44+
45+
if (null === $value) {
46+
return null;
47+
}
48+
49+
$payload = $this->extractFromValue($value);
50+
51+
if (null === $payload || $this->issuer !== ($payload['iss'] ?? null)) {
52+
return null;
53+
}
54+
55+
return $payload;
56+
}
57+
58+
abstract protected function extractFromValue(mixed $value): ?array;
59+
60+
final protected function extractFromBase64EncodedPayload(string $encodedPayload): ?array
61+
{
62+
$jsonPayload = base64_decode($encodedPayload, true);
63+
64+
if (false === $jsonPayload) {
65+
return null;
66+
}
67+
68+
$payload = json_decode($jsonPayload, true);
69+
70+
if (null === $payload) {
71+
return null;
72+
}
73+
74+
return $payload;
75+
}
76+
}

src/Base64HeaderExtractor.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/*
3+
* (c) Minh Vuong <vuongxuongminh@gmail.com>
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;
12+
13+
final class Base64HeaderExtractor extends AbstractExtractor
14+
{
15+
public function __construct(string $issuer, string $itemName)
16+
{
17+
parent::__construct($issuer, 'headers', $itemName);
18+
}
19+
20+
protected function extractFromValue(mixed $value): ?array
21+
{
22+
return $this->extractFromBase64EncodedPayload($value);
23+
}
24+
}

src/CompositeExtractor.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
/*
3+
* (c) Minh Vuong <vuongxuongminh@gmail.com>
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;
12+
13+
use Symfony\Component\HttpFoundation\Request;
14+
15+
final class CompositeExtractor implements ExtractorInterface
16+
{
17+
public function __construct(private iterable $extractors)
18+
{
19+
}
20+
21+
public function extract(Request $request): ?array
22+
{
23+
foreach ($this->extractors as $extractor) {
24+
/** @var ExtractorInterface $extractor */
25+
if ($payload = $extractor->extract($request)) {
26+
return $payload;
27+
}
28+
}
29+
30+
return null;
31+
}
32+
}

src/ExtractorFactory.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/*
3+
* (c) Minh Vuong <vuongxuongminh@gmail.com>
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;
12+
13+
class ExtractorFactory
14+
{
15+
public static function fromBase64Header(string $issuer, string $header): Base64HeaderExtractor
16+
{
17+
return new Base64HeaderExtractor($issuer, $header);
18+
}
19+
20+
public static function fromOriginTokenHeader(string $issuer, string $header): OriginTokenExtractor
21+
{
22+
return new OriginTokenExtractor($issuer, 'headers', $header);
23+
}
24+
25+
public static function fromOriginTokenQueryParam(string $issuer, string $queryParam): OriginTokenExtractor
26+
{
27+
return new OriginTokenExtractor($issuer, 'query', $queryParam);
28+
}
29+
30+
public static function fromExtractors(ExtractorInterface ...$extractors): CompositeExtractor
31+
{
32+
return new CompositeExtractor($extractors);
33+
}
34+
}

src/ExtractorInterface.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
/*
3+
* (c) Minh Vuong <vuongxuongminh@gmail.com>
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;
12+
13+
use Symfony\Component\HttpFoundation\Request;
14+
15+
interface ExtractorInterface
16+
{
17+
public function extract(Request $request): ?array;
18+
}

0 commit comments

Comments
 (0)