4
4
5
5
use Exception ;
6
6
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 ;
7
13
use Jose \Component \Core \AlgorithmManager ;
8
14
use Jose \Component \Core \Util \JsonConverter ;
9
15
use Jose \Component \Signature \Algorithm \HS256 ;
10
16
use Jose \Component \Signature \JWSBuilder ;
17
+ use Jose \Component \Signature \JWSTokenSupport ;
18
+ use Jose \Component \Signature \JWSVerifier ;
19
+ use Jose \Component \Signature \Serializer \JWSSerializerManager ;
11
20
use Toyokumo \JWTBundle \Exception \InvalidJWTException ;
12
21
use Toyokumo \JWTBundle \Exception \NotVerifiedJWTException ;
13
22
use Jose \Component \Checker \InvalidClaimException ;
14
23
use Jose \Component \Checker \InvalidHeaderException ;
15
24
use Jose \Component \Core \JWKSet ;
16
25
use Jose \Component \KeyManagement \JWKFactory ;
17
26
use Jose \Component \Signature \Serializer \CompactSerializer ;
18
- use Jose \Easy \Load ;
19
27
20
28
/**
21
29
* Class JWTService
@@ -29,6 +37,14 @@ class JWTService
29
37
30
38
private CompactSerializer $ compactSerializer ;
31
39
40
+ private JWSVerifier $ jwsVerifier ;
41
+
42
+ private JWSSerializerManager $ serializerManager ;
43
+
44
+ private HeaderCheckerManager $ headerCheckerManager ;
45
+
46
+ private ClaimCheckerManager $ claimCheckerManager ;
47
+
32
48
/**
33
49
* JWTService constructor.
34
50
* @param string $keyDirPath
@@ -69,6 +85,29 @@ public function __construct(string $keyDirPath, array $jwkInfos)
69
85
new HS256 ()
70
86
]));
71
87
$ 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
+ );
72
111
}
73
112
74
113
/**
@@ -111,39 +150,29 @@ public function generateJWSToken(
111
150
public function extractValueFromToken (string $ token , string $ claimKey )
112
151
{
113
152
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 ();
118
161
$ signature = $ signatures [0 ];
119
- if (!$ signature ->hasProtectedHeaderParameter ('kid ' )) {
120
- throw new NotVerifiedJWTException ('Token is not verified. ' );
121
- }
122
162
$ 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 ) {
124
166
throw new NotVerifiedJWTException ('Token is not verified. ' );
125
167
}
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. ' );
140
168
} 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 ' )) {
143
171
throw new NotVerifiedJWTException ('Token is not verified. ' );
144
172
}
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 ' )) {
147
176
throw new NotVerifiedJWTException ('Token is not verified. ' );
148
177
}
149
178
throw $ e ;
@@ -154,6 +183,6 @@ public function extractValueFromToken(string $token, string $claimKey)
154
183
throw $ e ;
155
184
}
156
185
157
- return $ jwt -> claims -> get ( $ claimKey) ;
186
+ return $ claims[ $ claimKey] ;
158
187
}
159
188
}
0 commit comments