Skip to content

Commit c58f928

Browse files
committed
mod: extractValueFromToken から use Jose\Easy\Load を取り除いた
1 parent 83ba9f3 commit c58f928

File tree

2 files changed

+59
-29
lines changed

2 files changed

+59
-29
lines changed

src/JWTService.php

+57-28
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,26 @@
44

55
use Exception;
66
use InvalidArgumentException;
7+
use Jose\Component\Checker\AlgorithmChecker;
8+
use Jose\Component\Checker\ClaimCheckerManager;
9+
use Jose\Component\Checker\ExpirationTimeChecker;
10+
use Jose\Component\Checker\HeaderCheckerManager;
11+
use Jose\Component\Checker\IssuedAtChecker;
12+
use Jose\Component\Checker\NotBeforeChecker;
713
use Jose\Component\Core\AlgorithmManager;
814
use Jose\Component\Core\Util\JsonConverter;
915
use Jose\Component\Signature\Algorithm\HS256;
1016
use Jose\Component\Signature\JWSBuilder;
17+
use Jose\Component\Signature\JWSTokenSupport;
18+
use Jose\Component\Signature\JWSVerifier;
19+
use Jose\Component\Signature\Serializer\JWSSerializerManager;
1120
use Toyokumo\JWTBundle\Exception\InvalidJWTException;
1221
use Toyokumo\JWTBundle\Exception\NotVerifiedJWTException;
1322
use Jose\Component\Checker\InvalidClaimException;
1423
use Jose\Component\Checker\InvalidHeaderException;
1524
use Jose\Component\Core\JWKSet;
1625
use Jose\Component\KeyManagement\JWKFactory;
1726
use Jose\Component\Signature\Serializer\CompactSerializer;
18-
use Jose\Easy\Load;
1927

2028
/**
2129
* Class JWTService
@@ -29,6 +37,14 @@ class JWTService
2937

3038
private CompactSerializer $compactSerializer;
3139

40+
private JWSVerifier $jwsVerifier;
41+
42+
private JWSSerializerManager $serializerManager;
43+
44+
private HeaderCheckerManager $headerCheckerManager;
45+
46+
private ClaimCheckerManager $claimCheckerManager;
47+
3248
/**
3349
* JWTService constructor.
3450
* @param string $keyDirPath
@@ -69,6 +85,29 @@ public function __construct(string $keyDirPath, array $jwkInfos)
6985
new HS256()
7086
]));
7187
$this->compactSerializer = new CompactSerializer();
88+
$this->jwsVerifier = new JWSVerifier(new AlgorithmManager([
89+
new HS256()
90+
]));
91+
$this->serializerManager = new JWSSerializerManager([
92+
new CompactSerializer()
93+
]);
94+
// https://web-token.spomky-labs.com/the-components/header-checker#header-checker-manager
95+
$this->headerCheckerManager = new HeaderCheckerManager([
96+
new AlgorithmChecker(['HS256']),
97+
// We want to verify that the header "alg" (algorithm)
98+
// is present and contains "HS256"
99+
],
100+
[
101+
new JWSTokenSupport(), // Adds JWS token type support
102+
]);
103+
// https://web-token.spomky-labs.com/the-components/claim-checker#claim-checker-manager
104+
$this->claimCheckerManager = new ClaimCheckerManager(
105+
[
106+
new IssuedAtChecker(),
107+
new NotBeforeChecker(),
108+
new ExpirationTimeChecker(),
109+
]
110+
);
72111
}
73112

74113
/**
@@ -111,39 +150,29 @@ public function generateJWSToken(
111150
public function extractValueFromToken(string $token, string $claimKey)
112151
{
113152
try {
114-
// Get kid for identifying jwk
115-
$signatures = (new CompactSerializer())
116-
->unserialize($token)
117-
->getSignatures();
153+
$jws = $this->serializerManager->unserialize($token);
154+
// header validation
155+
$this->headerCheckerManager->check($jws, 0, ['alg', 'kid']);
156+
// payload validation
157+
$claims = JsonConverter::decode($jws->getPayload());
158+
$this->claimCheckerManager->check($claims);
159+
// signature validation
160+
$signatures = $jws->getSignatures();
118161
$signature = $signatures[0];
119-
if (!$signature->hasProtectedHeaderParameter('kid')) {
120-
throw new NotVerifiedJWTException('Token is not verified.');
121-
}
122162
$kid = $signature->getProtectedHeaderParameter('kid');
123-
if (!$this->jwkSet->has($kid)) {
163+
$jwk = $this->jwkSet->get($kid);
164+
$isVerified = $this->jwsVerifier->verifyWithKey($jws, $jwk, 0);
165+
if (!$isVerified) {
124166
throw new NotVerifiedJWTException('Token is not verified.');
125167
}
126-
$jwk = $this->jwkSet->get($kid);
127-
128-
$jwt = Load::jws($token)
129-
->alg($jwk->get('alg'))
130-
->exp()
131-
->nbf()
132-
->key($jwk)
133-
->run();
134-
} catch (InvalidClaimException $e) {
135-
// token expiration etc..
136-
throw new InvalidJWTException('Token is invalid.');
137-
} catch (InvalidHeaderException $e) {
138-
// alg=none tampering etc..
139-
throw new NotVerifiedJWTException('Token is not verified.');
140168
} catch (InvalidArgumentException $e) {
141-
if ($e->getMessage() === 'Unsupported input') {
142-
// failed to decode token
169+
// 表記揺れがあるので str_contains で対応
170+
if (str_contains($e->getMessage(), 'Unsupported input')) {
143171
throw new NotVerifiedJWTException('Token is not verified.');
144172
}
145-
if ($e->getMessage() === 'Undefined index') {
146-
// there is no JWK corresponding to kid
173+
174+
// 表記揺れがあるので str_contains で対応
175+
if (str_contains($e->getMessage(), 'Undefined index')) {
147176
throw new NotVerifiedJWTException('Token is not verified.');
148177
}
149178
throw $e;
@@ -154,6 +183,6 @@ public function extractValueFromToken(string $token, string $claimKey)
154183
throw $e;
155184
}
156185

157-
return $jwt->claims->get($claimKey);
186+
return $claims[$claimKey];
158187
}
159188
}

tests/JWTServiceTest.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Toyokumo\JWTBundle;
44

5+
use Jose\Component\Checker\InvalidClaimException;
56
use PHPUnit\Framework\TestCase;
67
use Toyokumo\JWTBundle\Exception\InvalidJWTException;
78
use Toyokumo\JWTBundle\Exception\NotVerifiedJWTException;
@@ -49,7 +50,7 @@ public function testExpireJWSToken(): void
4950
{
5051
$token = $this->jwt->generateJWSToken(['hoge' => 'fuga'], 'test_key', -1); // exp = -1 means expire right now
5152

52-
$this->expectException(InvalidJWTException::class);
53+
$this->expectException(InvalidClaimException::class);
5354
$this->jwt->extractValueFromToken($token, 'hoge');
5455
}
5556

0 commit comments

Comments
 (0)