1 package jwt_test
2
3 import (
4 "crypto"
5 "crypto/rsa"
6 "encoding/json"
7 "errors"
8 "fmt"
9 "reflect"
10 "testing"
11 "time"
12
13 "github.com/golang-jwt/jwt/v5"
14 "github.com/golang-jwt/jwt/v5/test"
15 )
16
17 var errKeyFuncError error = fmt.Errorf("error loading key")
18
19 var (
20 jwtTestDefaultKey *rsa.PublicKey
21 jwtTestRSAPrivateKey *rsa.PrivateKey
22 jwtTestEC256PublicKey crypto.PublicKey
23 jwtTestEC256PrivateKey crypto.PrivateKey
24 paddedKey crypto.PublicKey
25 defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil }
26 ecdsaKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestEC256PublicKey, nil }
27 paddedKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return paddedKey, nil }
28 emptyKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, nil }
29 errorKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, errKeyFuncError }
30 nilKeyFunc jwt.Keyfunc = nil
31 multipleZeroKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return []interface{}{}, nil }
32 multipleEmptyKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) {
33 return jwt.VerificationKeySet{Keys: []jwt.VerificationKey{nil, nil}}, nil
34 }
35 multipleVerificationKeysFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) {
36 return []jwt.VerificationKey{jwtTestDefaultKey, jwtTestEC256PublicKey}, nil
37 }
38 multipleLastKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) {
39 return jwt.VerificationKeySet{Keys: []jwt.VerificationKey{jwtTestEC256PublicKey, jwtTestDefaultKey}}, nil
40 }
41 multipleFirstKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) {
42 return jwt.VerificationKeySet{Keys: []jwt.VerificationKey{jwtTestDefaultKey, jwtTestEC256PublicKey}}, nil
43 }
44 multipleAltTypedKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) {
45 return jwt.VerificationKeySet{Keys: []jwt.VerificationKey{jwtTestDefaultKey, jwtTestDefaultKey}}, nil
46 }
47 emptyVerificationKeySetFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) {
48 return jwt.VerificationKeySet{}, nil
49 }
50 )
51
52 func init() {
53
54 jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub")
55 jwtTestEC256PublicKey = test.LoadECPublicKeyFromDisk("test/ec256-public.pem")
56
57
58
59 paddedKey = test.LoadECPublicKeyFromDisk("test/examplePaddedKey-public.pem")
60
61
62 jwtTestRSAPrivateKey = test.LoadRSAPrivateKeyFromDisk("test/sample_key")
63 jwtTestEC256PrivateKey = test.LoadECPrivateKeyFromDisk("test/ec256-private.pem")
64 }
65
66 var jwtTestData = []struct {
67 name string
68 tokenString string
69 keyfunc jwt.Keyfunc
70 claims jwt.Claims
71 valid bool
72 err []error
73 parser *jwt.Parser
74 signingMethod jwt.SigningMethod
75 }{
76 {
77 "invalid JWT",
78 "thisisnotreallyajwt",
79 defaultKeyFunc,
80 nil,
81 false,
82 []error{jwt.ErrTokenMalformed},
83 nil,
84 jwt.SigningMethodRS256,
85 },
86 {
87 "invalid JSON claim",
88 "eyJhbGciOiJSUzI1NiIsInppcCI6IkRFRiJ9.eNqqVkqtKFCyMjQ1s7Q0sbA0MtFRyk3NTUot8kxRslIKLbZQggn4JeamAoUcfRz99HxcXRWeze172tr4bFq7Ui0AAAD__w.jBXD4LT4aq4oXTgDoPkiV6n4QdSZPZI1Z4J8MWQC42aHK0oXwcovEU06dVbtB81TF-2byuu0-qi8J0GUttODT67k6gCl6DV_iuCOV7gczwTcvKslotUvXzoJ2wa0QuujnjxLEE50r0p6k0tsv_9OIFSUZzDksJFYNPlJH2eFG55DROx4TsOz98az37SujZi9GGbTc9SLgzFHPrHMrovRZ5qLC_w4JrdtsLzBBI11OQJgRYwV8fQf4O8IsMkHtetjkN7dKgUkJtRarNWOk76rpTPppLypiLU4_J0-wrElLMh1TzUVZW6Fz2cDHDDBACJgMmKQ2pOFEDK_vYZN74dLCF5GiTZV6DbXhNxO7lqT7JUN4a3p2z96G7WNRjblf2qZeuYdQvkIsiK-rCbSIE836XeY5gaBgkOzuEvzl_tMrpRmb5Oox1ibOfVT2KBh9Lvqsb1XbQjCio2CLE2ViCLqoe0AaRqlUyrk3n8BIG-r0IW4dcw96CEryEMIjsjVp9mtPXamJzf391kt8Rf3iRBqwv3zP7Plg1ResXbmsFUgOflAUPcYmfLug4W3W52ntcUlTHAKXrNfaJL9QQiYAaDukG-ZHDytsOWTuuXw7lVxjt-XYi1VbRAIjh1aIYSELEmEpE4Ny74htQtywYXMQNfJpB0nNn8IiWakgcYYMJ0TmKM",
89 defaultKeyFunc,
90 nil,
91 false,
92 []error{jwt.ErrTokenMalformed},
93 nil,
94 jwt.SigningMethodRS256,
95 },
96 {
97 "bearer in JWT",
98 "bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
99 defaultKeyFunc,
100 nil,
101 false,
102 []error{jwt.ErrTokenMalformed},
103 nil,
104 jwt.SigningMethodRS256,
105 },
106 {
107 "basic",
108 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
109 defaultKeyFunc,
110 jwt.MapClaims{"foo": "bar"},
111 true,
112 nil,
113 nil,
114 jwt.SigningMethodRS256,
115 },
116 {
117 "multiple keys, last matches",
118 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
119 multipleLastKeyFunc,
120 jwt.MapClaims{"foo": "bar"},
121 true,
122 nil,
123 nil,
124 jwt.SigningMethodRS256,
125 },
126 {
127 "multiple keys not []interface{} type, all match",
128 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
129 multipleAltTypedKeyFunc,
130 jwt.MapClaims{"foo": "bar"},
131 true,
132 nil,
133 nil,
134 jwt.SigningMethodRS256,
135 },
136 {
137 "multiple keys, first matches",
138 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
139 multipleFirstKeyFunc,
140 jwt.MapClaims{"foo": "bar"},
141 true,
142 nil,
143 nil,
144 jwt.SigningMethodRS256,
145 },
146 {
147 "public keys slice, not allowed",
148 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
149 multipleVerificationKeysFunc,
150 jwt.MapClaims{"foo": "bar"},
151 false,
152 []error{jwt.ErrTokenSignatureInvalid},
153 nil,
154 jwt.SigningMethodRS256,
155 },
156 {
157 "basic expired",
158 "",
159 defaultKeyFunc,
160 jwt.MapClaims{"foo": "bar", "exp": float64(time.Now().Unix() - 100)},
161 false,
162 []error{jwt.ErrTokenExpired},
163 nil,
164 jwt.SigningMethodRS256,
165 },
166 {
167 "basic nbf",
168 "",
169 defaultKeyFunc,
170 jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100)},
171 false,
172 []error{jwt.ErrTokenNotValidYet},
173 nil,
174 jwt.SigningMethodRS256,
175 },
176 {
177 "expired and nbf",
178 "",
179 defaultKeyFunc,
180 jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100), "exp": float64(time.Now().Unix() - 100)},
181 false,
182 []error{jwt.ErrTokenNotValidYet, jwt.ErrTokenExpired},
183 nil,
184 jwt.SigningMethodRS256,
185 },
186 {
187 "basic invalid",
188 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
189 defaultKeyFunc,
190 jwt.MapClaims{"foo": "bar"},
191 false,
192 []error{jwt.ErrTokenSignatureInvalid, rsa.ErrVerification},
193 nil,
194 jwt.SigningMethodRS256,
195 },
196 {
197 "basic nokeyfunc",
198 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
199 nilKeyFunc,
200 jwt.MapClaims{"foo": "bar"},
201 false,
202 []error{jwt.ErrTokenUnverifiable},
203 nil,
204 jwt.SigningMethodRS256,
205 },
206 {
207 "basic nokey",
208 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
209 emptyKeyFunc,
210 jwt.MapClaims{"foo": "bar"},
211 false,
212 []error{jwt.ErrTokenSignatureInvalid},
213 nil,
214 jwt.SigningMethodRS256,
215 },
216 {
217 "multiple nokey",
218 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
219 multipleEmptyKeyFunc,
220 jwt.MapClaims{"foo": "bar"},
221 false,
222 []error{jwt.ErrTokenSignatureInvalid},
223 nil,
224 jwt.SigningMethodRS256,
225 },
226 {
227 "empty verification key set",
228 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
229 emptyVerificationKeySetFunc,
230 jwt.MapClaims{"foo": "bar"},
231 false,
232 []error{jwt.ErrTokenUnverifiable},
233 nil,
234 jwt.SigningMethodRS256,
235 },
236 {
237 "zero length key list",
238 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
239 multipleZeroKeyFunc,
240 jwt.MapClaims{"foo": "bar"},
241 false,
242 []error{jwt.ErrTokenSignatureInvalid},
243 nil,
244 jwt.SigningMethodRS256,
245 },
246 {
247 "basic errorkey",
248 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
249 errorKeyFunc,
250 jwt.MapClaims{"foo": "bar"},
251 false,
252 []error{jwt.ErrTokenUnverifiable, errKeyFuncError},
253 nil,
254 jwt.SigningMethodRS256,
255 },
256 {
257 "invalid signing method",
258 "",
259 defaultKeyFunc,
260 jwt.MapClaims{"foo": "bar"},
261 false,
262 []error{jwt.ErrTokenSignatureInvalid},
263 jwt.NewParser(jwt.WithValidMethods([]string{"HS256"})),
264 jwt.SigningMethodRS256,
265 },
266 {
267 "valid RSA signing method",
268 "",
269 defaultKeyFunc,
270 jwt.MapClaims{"foo": "bar"},
271 true,
272 nil,
273 jwt.NewParser(jwt.WithValidMethods([]string{"RS256", "HS256"})),
274 jwt.SigningMethodRS256,
275 },
276 {
277 "ECDSA signing method not accepted",
278 "",
279 ecdsaKeyFunc,
280 jwt.MapClaims{"foo": "bar"},
281 false,
282 []error{jwt.ErrTokenSignatureInvalid},
283 jwt.NewParser(jwt.WithValidMethods([]string{"RS256", "HS256"})),
284 jwt.SigningMethodES256,
285 },
286 {
287 "valid ECDSA signing method",
288 "",
289 ecdsaKeyFunc,
290 jwt.MapClaims{"foo": "bar"},
291 true,
292 nil,
293 jwt.NewParser(jwt.WithValidMethods([]string{"HS256", "ES256"})),
294 jwt.SigningMethodES256,
295 },
296 {
297 "JSON Number",
298 "",
299 defaultKeyFunc,
300 jwt.MapClaims{"foo": json.Number("123.4")},
301 true,
302 nil,
303 jwt.NewParser(jwt.WithJSONNumber()),
304 jwt.SigningMethodRS256,
305 },
306 {
307 "JSON Number - basic expired",
308 "",
309 defaultKeyFunc,
310 jwt.MapClaims{"foo": "bar", "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
311 false,
312 []error{jwt.ErrTokenExpired},
313 jwt.NewParser(jwt.WithJSONNumber()),
314 jwt.SigningMethodRS256,
315 },
316 {
317 "JSON Number - basic nbf",
318 "",
319 defaultKeyFunc,
320 jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
321 false,
322 []error{jwt.ErrTokenNotValidYet},
323 jwt.NewParser(jwt.WithJSONNumber()),
324 jwt.SigningMethodRS256,
325 },
326 {
327 "JSON Number - expired and nbf",
328 "",
329 defaultKeyFunc,
330 jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100)), "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
331 false,
332 []error{jwt.ErrTokenNotValidYet, jwt.ErrTokenExpired},
333 jwt.NewParser(jwt.WithJSONNumber()),
334 jwt.SigningMethodRS256,
335 },
336 {
337 "SkipClaimsValidation during token parsing",
338 "",
339 defaultKeyFunc,
340 jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
341 true,
342 nil,
343 jwt.NewParser(jwt.WithJSONNumber(), jwt.WithoutClaimsValidation()),
344 jwt.SigningMethodRS256,
345 },
346 {
347 "RFC7519 Claims",
348 "",
349 defaultKeyFunc,
350 &jwt.RegisteredClaims{
351 ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Second * 10)),
352 },
353 true,
354 nil,
355 jwt.NewParser(jwt.WithJSONNumber()),
356 jwt.SigningMethodRS256,
357 },
358 {
359 "RFC7519 Claims - single aud",
360 "",
361 defaultKeyFunc,
362 &jwt.RegisteredClaims{
363 Audience: jwt.ClaimStrings{"test"},
364 },
365 true,
366 nil,
367 jwt.NewParser(jwt.WithJSONNumber()),
368 jwt.SigningMethodRS256,
369 },
370 {
371 "RFC7519 Claims - multiple aud",
372 "",
373 defaultKeyFunc,
374 &jwt.RegisteredClaims{
375 Audience: jwt.ClaimStrings{"test", "test"},
376 },
377 true,
378 nil,
379 jwt.NewParser(jwt.WithJSONNumber()),
380 jwt.SigningMethodRS256,
381 },
382 {
383 "RFC7519 Claims - single aud with wrong type",
384 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOjF9.8mAIDUfZNQT3TGm1QFIQp91OCpJpQpbB1-m9pA2mkHc",
385 defaultKeyFunc,
386 &jwt.RegisteredClaims{
387 Audience: nil,
388 },
389 false,
390 []error{jwt.ErrTokenMalformed},
391 jwt.NewParser(jwt.WithJSONNumber()),
392 jwt.SigningMethodRS256,
393 },
394 {
395 "RFC7519 Claims - multiple aud with wrong types",
396 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidGVzdCIsMV19.htEBUf7BVbfSmVoTFjXf3y6DLmDUuLy1vTJ14_EX7Ws",
397 defaultKeyFunc,
398 &jwt.RegisteredClaims{
399 Audience: nil,
400 },
401 false,
402 []error{jwt.ErrTokenMalformed},
403 jwt.NewParser(jwt.WithJSONNumber()),
404 jwt.SigningMethodRS256,
405 },
406 {
407 "RFC7519 Claims - nbf with 60s skew",
408 "",
409 defaultKeyFunc,
410 &jwt.RegisteredClaims{NotBefore: jwt.NewNumericDate(time.Now().Add(time.Second * 100))},
411 false,
412 []error{jwt.ErrTokenNotValidYet},
413 jwt.NewParser(jwt.WithLeeway(time.Minute)),
414 jwt.SigningMethodRS256,
415 },
416 {
417 "RFC7519 Claims - nbf with 120s skew",
418 "",
419 defaultKeyFunc,
420 &jwt.RegisteredClaims{NotBefore: jwt.NewNumericDate(time.Now().Add(time.Second * 100))},
421 true,
422 nil,
423 jwt.NewParser(jwt.WithLeeway(2 * time.Minute)),
424 jwt.SigningMethodRS256,
425 },
426 {
427 "rejects if exp is required but missing",
428 "",
429 defaultKeyFunc,
430 &jwt.RegisteredClaims{},
431 false,
432 []error{jwt.ErrTokenInvalidClaims},
433 jwt.NewParser(jwt.WithExpirationRequired()),
434 jwt.SigningMethodRS256,
435 },
436 }
437
438
439 func signToken(claims jwt.Claims, signingMethod jwt.SigningMethod) string {
440 var privateKey interface{}
441 switch signingMethod {
442 case jwt.SigningMethodRS256:
443 privateKey = jwtTestRSAPrivateKey
444 case jwt.SigningMethodES256:
445 privateKey = jwtTestEC256PrivateKey
446 default:
447 return ""
448 }
449 return test.MakeSampleToken(claims, signingMethod, privateKey)
450 }
451
452 func TestParser_Parse(t *testing.T) {
453
454 for _, data := range jwtTestData {
455 t.Run(data.name, func(t *testing.T) {
456
457 if data.tokenString == "" {
458 data.tokenString = signToken(data.claims, data.signingMethod)
459 }
460
461
462 var token *jwt.Token
463 var err error
464 var parser = data.parser
465 if parser == nil {
466 parser = jwt.NewParser()
467 }
468
469 switch data.claims.(type) {
470 case jwt.MapClaims:
471 token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)
472 case *jwt.RegisteredClaims:
473 token, err = parser.ParseWithClaims(data.tokenString, &jwt.RegisteredClaims{}, data.keyfunc)
474 case nil:
475 token, err = parser.ParseWithClaims(data.tokenString, nil, data.keyfunc)
476 }
477
478
479 if data.claims != nil && !reflect.DeepEqual(data.claims, token.Claims) {
480 t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims)
481 }
482
483 if data.valid && err != nil {
484 t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
485 }
486
487 if !data.valid && err == nil {
488 t.Errorf("[%v] Invalid token passed validation", data.name)
489 }
490
491
492
493 if !errors.Is(err, jwt.ErrTokenMalformed) &&
494 ((err == nil && !token.Valid) || (err != nil && token.Valid)) {
495 t.Errorf("[%v] Inconsistent behavior between returned error and token.Valid", data.name)
496 }
497
498 if data.err != nil {
499 if err == nil {
500 t.Errorf("[%v] Expecting error(s). Didn't get one.", data.name)
501 } else {
502 var all = false
503 for _, e := range data.err {
504 all = errors.Is(err, e)
505 }
506
507 if !all {
508 t.Errorf("[%v] Errors don't match expectation. %v should contain all of %v", data.name, err, data.err)
509 }
510 }
511 }
512
513 if data.valid {
514 if len(token.Signature) == 0 {
515 t.Errorf("[%v] Signature is left unpopulated after parsing", data.name)
516 }
517 if !token.Valid {
518
519 t.Errorf("[%v] Token.Valid field mismatch. Expecting true, got %v", data.name, token.Valid)
520 }
521 }
522 })
523 }
524 }
525
526 func TestParser_ParseUnverified(t *testing.T) {
527
528 for _, data := range jwtTestData {
529
530 if len(data.err) == 1 && errors.Is(data.err[0], jwt.ErrTokenMalformed) {
531 continue
532 }
533
534 t.Run(data.name, func(t *testing.T) {
535
536 if data.tokenString == "" {
537 data.tokenString = signToken(data.claims, data.signingMethod)
538 }
539
540
541 var token *jwt.Token
542 var err error
543 var parser = data.parser
544 if parser == nil {
545 parser = new(jwt.Parser)
546 }
547
548 switch data.claims.(type) {
549 case jwt.MapClaims:
550 token, _, err = parser.ParseUnverified(data.tokenString, jwt.MapClaims{})
551 case *jwt.RegisteredClaims:
552 token, _, err = parser.ParseUnverified(data.tokenString, &jwt.RegisteredClaims{})
553 }
554
555 if err != nil {
556 t.Errorf("[%v] Invalid token", data.name)
557 }
558
559
560 if !reflect.DeepEqual(data.claims, token.Claims) {
561 t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims)
562 }
563
564 if data.valid && err != nil {
565 t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
566 }
567 if token.Valid {
568
569 t.Errorf("[%v] Token.Valid field mismatch. Expecting false, got %v", data.name, token.Valid)
570 }
571 if len(token.Signature) != 0 {
572
573 t.Errorf("[%v] Token.Signature field mismatch. Expecting '', got %v", data.name, token.Signature)
574 }
575 })
576 }
577 }
578
579 var setPaddingTestData = []struct {
580 name string
581 tokenString string
582 claims jwt.Claims
583 paddedDecode bool
584 strictDecode bool
585 signingMethod jwt.SigningMethod
586 keyfunc jwt.Keyfunc
587 valid bool
588 }{
589 {
590 name: "Validated non-padded token with padding disabled",
591 tokenString: "",
592 claims: jwt.MapClaims{"foo": "paddedbar"},
593 paddedDecode: false,
594 signingMethod: jwt.SigningMethodRS256,
595 keyfunc: defaultKeyFunc,
596 valid: true,
597 },
598 {
599 name: "Validated non-padded token with padding enabled",
600 tokenString: "",
601 claims: jwt.MapClaims{"foo": "paddedbar"},
602 paddedDecode: true,
603 signingMethod: jwt.SigningMethodRS256,
604 keyfunc: defaultKeyFunc,
605 valid: true,
606 },
607 {
608 name: "Error for padded token with padding disabled",
609 tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ==.20kGGJaYekGTRFf8b0TwhuETcR8lv5z2363X5jf7G1yTWVTwOmte5Ii8L8_OQbYwPoiVHmZY6iJPbt_DhCN42AeFY74BcsUhR-BVrYUVhKK0RppuzEcSlILDNeQsJDLEL035CPm1VO6Jrgk7enQPIctVxUesRgswP71OpGvJxy3j1k_J8p0WzZvRZTe1D_2Misa0UDGwnEIHhmr97fIpMSZjFxlcygQw8QN34IHLHIXMaTY1eiCf4CCr6rOS9wUeu7P3CPkmFq9XhxBT_LLCmIMhHnxP5x27FUJE_JZlfek0MmARcrhpsZS2sFhHAiWrjxjOE27jkDtv1nEwn65wMw==",
610 claims: jwt.MapClaims{"foo": "paddedbar"},
611 paddedDecode: false,
612 signingMethod: jwt.SigningMethodRS256,
613 keyfunc: defaultKeyFunc,
614 valid: false,
615 },
616 {
617 name: "Validated padded token with padding enabled",
618 tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ==.20kGGJaYekGTRFf8b0TwhuETcR8lv5z2363X5jf7G1yTWVTwOmte5Ii8L8_OQbYwPoiVHmZY6iJPbt_DhCN42AeFY74BcsUhR-BVrYUVhKK0RppuzEcSlILDNeQsJDLEL035CPm1VO6Jrgk7enQPIctVxUesRgswP71OpGvJxy3j1k_J8p0WzZvRZTe1D_2Misa0UDGwnEIHhmr97fIpMSZjFxlcygQw8QN34IHLHIXMaTY1eiCf4CCr6rOS9wUeu7P3CPkmFq9XhxBT_LLCmIMhHnxP5x27FUJE_JZlfek0MmARcrhpsZS2sFhHAiWrjxjOE27jkDtv1nEwn65wMw==",
619 claims: jwt.MapClaims{"foo": "paddedbar"},
620 paddedDecode: true,
621 signingMethod: jwt.SigningMethodRS256,
622 keyfunc: defaultKeyFunc,
623 valid: true,
624 },
625 {
626 name: "Error for example padded token with padding disabled",
627 tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==",
628 claims: nil,
629 paddedDecode: false,
630 signingMethod: jwt.SigningMethodES256,
631 keyfunc: paddedKeyFunc,
632 valid: false,
633 },
634 {
635 name: "Validated example padded token with padding enabled",
636 tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==",
637 claims: nil,
638 paddedDecode: true,
639 signingMethod: jwt.SigningMethodES256,
640 keyfunc: paddedKeyFunc,
641 valid: true,
642 },
643
644 {
645 name: "Validated non-padded token with padding disabled, non-strict decode, non-tweaked signature",
646 tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
647 "g",
648 claims: nil,
649 paddedDecode: false,
650 strictDecode: false,
651 signingMethod: jwt.SigningMethodRS256,
652 keyfunc: defaultKeyFunc,
653 valid: true,
654 },
655 {
656 name: "Validated non-padded token with padding disabled, non-strict decode, tweaked signature",
657 tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
658 "h",
659 claims: nil,
660 paddedDecode: false,
661 strictDecode: false,
662 signingMethod: jwt.SigningMethodRS256,
663 keyfunc: defaultKeyFunc,
664 valid: true,
665 },
666 {
667 name: "Validated non-padded token with padding disabled, strict decode, non-tweaked signature",
668 tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
669 "g",
670 claims: nil,
671 paddedDecode: false,
672 strictDecode: true,
673 signingMethod: jwt.SigningMethodRS256,
674 keyfunc: defaultKeyFunc,
675 valid: true,
676 },
677 {
678 name: "Error for non-padded token with padding disabled, strict decode, tweaked signature",
679 tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
680 "h",
681 claims: nil,
682 paddedDecode: false,
683 strictDecode: true,
684 signingMethod: jwt.SigningMethodRS256,
685 keyfunc: defaultKeyFunc,
686 valid: false,
687 },
688
689 {
690 name: "Validated padded token with padding enabled, non-strict decode, non-tweaked signature",
691 tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
692 "w==",
693 claims: nil,
694 paddedDecode: true,
695 strictDecode: false,
696 signingMethod: jwt.SigningMethodES256,
697 keyfunc: paddedKeyFunc,
698 valid: true,
699 },
700 {
701 name: "Validated padded token with padding enabled, non-strict decode, tweaked signature",
702 tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
703 "x==",
704 claims: nil,
705 paddedDecode: true,
706 strictDecode: false,
707 signingMethod: jwt.SigningMethodES256,
708 keyfunc: paddedKeyFunc,
709 valid: true,
710 },
711 {
712 name: "Validated padded token with padding enabled, strict decode, non-tweaked signature",
713 tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
714 "w==",
715 claims: nil,
716 paddedDecode: true,
717 strictDecode: true,
718 signingMethod: jwt.SigningMethodES256,
719 keyfunc: paddedKeyFunc,
720 valid: true,
721 },
722 {
723 name: "Error for padded token with padding enabled, strict decode, tweaked signature",
724 tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
725 "x==",
726 claims: nil,
727 paddedDecode: true,
728 strictDecode: true,
729 signingMethod: jwt.SigningMethodES256,
730 keyfunc: paddedKeyFunc,
731 valid: false,
732 },
733 }
734
735
736 func TestSetPadding(t *testing.T) {
737 for _, data := range setPaddingTestData {
738 t.Run(data.name, func(t *testing.T) {
739
740 if data.tokenString == "" {
741 data.tokenString = signToken(data.claims, data.signingMethod)
742 }
743
744
745 var token *jwt.Token
746 var err error
747 var opts []jwt.ParserOption = []jwt.ParserOption{jwt.WithoutClaimsValidation()}
748
749 if data.paddedDecode {
750 opts = append(opts, jwt.WithPaddingAllowed())
751 }
752 if data.strictDecode {
753 opts = append(opts, jwt.WithStrictDecoding())
754 }
755
756 parser := jwt.NewParser(opts...)
757
758
759 token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)
760
761 if (err == nil) != data.valid || token.Valid != data.valid {
762 t.Errorf("[%v] Error Parsing Token with decoding padding set to %v: %v",
763 data.name,
764 data.paddedDecode,
765 err,
766 )
767 }
768 })
769 }
770 }
771
772 func BenchmarkParseUnverified(b *testing.B) {
773
774 for _, data := range jwtTestData {
775
776 if data.tokenString == "" {
777 data.tokenString = signToken(data.claims, data.signingMethod)
778 }
779
780
781 var parser = data.parser
782 if parser == nil {
783 parser = new(jwt.Parser)
784 }
785
786 switch data.claims.(type) {
787 case jwt.MapClaims:
788 b.Run("map_claims", func(b *testing.B) {
789 benchmarkParsing(b, parser, data.tokenString, jwt.MapClaims{})
790 })
791 case *jwt.RegisteredClaims:
792 b.Run("registered_claims", func(b *testing.B) {
793 benchmarkParsing(b, parser, data.tokenString, &jwt.RegisteredClaims{})
794 })
795 }
796 }
797 }
798
799
800 func benchmarkParsing(b *testing.B, parser *jwt.Parser, tokenString string, claims jwt.Claims) {
801 b.Helper()
802 b.ReportAllocs()
803 b.ResetTimer()
804 b.RunParallel(func(pb *testing.PB) {
805 for pb.Next() {
806 _, _, err := parser.ParseUnverified(tokenString, jwt.MapClaims{})
807 if err != nil {
808 b.Fatal(err)
809 }
810 }
811 })
812 }
813
814
815 func benchmarkSigning(b *testing.B, method jwt.SigningMethod, key interface{}) {
816 b.Helper()
817 t := jwt.New(method)
818 b.ReportAllocs()
819 b.ResetTimer()
820 b.RunParallel(func(pb *testing.PB) {
821 for pb.Next() {
822 if _, err := t.SignedString(key); err != nil {
823 b.Fatal(err)
824 }
825 }
826 })
827 }
828
View as plain text