forked from lestrrat-go/jwx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
options.go
418 lines (356 loc) · 13.1 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
package jwt
import (
"time"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwe"
"github.com/lestrrat-go/jwx/jwk"
"github.com/lestrrat-go/jwx/jws"
"github.com/lestrrat-go/option"
)
type Option = option.Interface
// GlobalOption describes an Option that can be passed to `Settings()`.
type GlobalOption interface {
Option
globalOption()
}
type globalOption struct {
Option
}
func (*globalOption) globalOption() {}
// ParseRequestOption describes an Option that can be passed to `ParseRequest()`.
type ParseRequestOption interface {
ParseOption
httpParseOption()
}
type httpParseOption struct {
ParseOption
}
func (*httpParseOption) httpParseOption() {}
// ParseOption describes an Option that can be passed to `Parse()`.
// ParseOption also implements ReadFileOption, therefore it may be
// safely pass them to `jwt.ReadFile()`
type ParseOption interface {
ReadFileOption
parseOption()
}
type parseOption struct {
Option
}
func newParseOption(n interface{}, v interface{}) ParseOption {
return &parseOption{option.New(n, v)}
}
func (*parseOption) parseOption() {}
func (*parseOption) readFileOption() {}
// SignOption describes an Option that can be passed to Sign() or
// (jwt.Serializer).Sign
type SignOption interface {
Option
signOption()
}
type signOption struct {
Option
}
func newSignOption(n interface{}, v interface{}) SignOption {
return &signOption{option.New(n, v)}
}
func (*signOption) signOption() {}
// EncryptOption describes an Option that can be passed to Encrypt() or
// (jwt.Serializer).Encrypt
type EncryptOption interface {
Option
encryptOption()
}
type encryptOption struct {
Option
}
func newEncryptOption(n interface{}, v interface{}) EncryptOption {
return &encryptOption{option.New(n, v)}
}
func (*encryptOption) encryptOption() {}
// ValidateOption describes an Option that can be passed to Validate().
// ValidateOption also implements ParseOption, therefore it may be
// safely passed to `Parse()` (and thus `jwt.ReadFile()`)
type ValidateOption interface {
ParseOption
validateOption()
}
type validateOption struct {
ParseOption
}
func newValidateOption(n interface{}, v interface{}) ValidateOption {
return &validateOption{newParseOption(n, v)}
}
func (*validateOption) validateOption() {}
type identAcceptableSkew struct{}
type identAudience struct{}
type identClaim struct{}
type identClock struct{}
type identDecrypt struct{}
type identDefault struct{}
type identFlattenAudience struct{}
type identIssuer struct{}
type identJweHeaders struct{}
type identJwsHeaders struct{}
type identJwtid struct{}
type identKeySet struct{}
type identPedantic struct{}
type identRequiredClaim struct{}
type identSubject struct{}
type identTimeDelta struct{}
type identToken struct{}
type identTypedClaim struct{}
type identValidate struct{}
type identVerify struct{}
type identHeaderKey struct{}
type identFormKey struct{}
type VerifyParameters interface {
Algorithm() jwa.SignatureAlgorithm
Key() interface{}
}
type verifyParams struct {
alg jwa.SignatureAlgorithm
key interface{}
}
func (p *verifyParams) Algorithm() jwa.SignatureAlgorithm {
return p.alg
}
func (p *verifyParams) Key() interface{} {
return p.key
}
// WithVerify forces the Parse method to verify the JWT message
// using the given key. XXX Should have been named something like
// WithVerificationKey
func WithVerify(alg jwa.SignatureAlgorithm, key interface{}) ParseOption {
return newParseOption(identVerify{}, &verifyParams{
alg: alg,
key: key,
})
}
// WithKeySet forces the Parse method to verify the JWT message
// using one of the keys in the given key set. The key to be used
// is chosen by matching the Key ID of the JWT and the ID of the
// given keys.
//
// When using this option, keys MUST have a properly 'alg' field
// set. This is because we need to know the exact algorithm that
// you (the user) wants to use to verify the token. We do NOT
// trust the token's headers, because they can easily be tampered with.
func WithKeySet(set jwk.Set) ParseOption {
return newParseOption(identKeySet{}, set)
}
// UseDefaultKey is used in conjunction with the option WithKeySet
// to instruct the Parse method to default to the single key in a key
// set when no Key ID is included in the JWT. If the key set contains
// multiple keys then the behaviour is unchanged.
func UseDefaultKey(value bool) ParseOption {
return newParseOption(identDefault{}, value)
}
// WithToken specifies the token instance that is used when parsing
// JWT tokens.
func WithToken(t Token) ParseOption {
return newParseOption(identToken{}, t)
}
// WithHeaders is passed to `jwt.Sign()` function, to allow specifying arbitrary
// header values to be included in the header section of the jws message
//
// This option will be deprecated in the next major version. Use
// jwt.WithJwsHeaders() instead.
func WithHeaders(hdrs jws.Headers) SignOption {
return WithJwsHeaders(hdrs)
}
// WithJwsHeaders is passed to `jwt.Sign()` function or
// "jwt.Serializer".Sign() method, to allow specifying arbitrary
// header values to be included in the header section of the JWE message
func WithJwsHeaders(hdrs jws.Headers) SignOption {
return newSignOption(identJwsHeaders{}, hdrs)
}
// WithJweHeaders is passed to "jwt.Serializer".Encrypt() method to allow
// specifying arbitrary header values to be included in the protected header
// of the JWE message
func WithJweHeaders(hdrs jwe.Headers) EncryptOption {
return newEncryptOption(identJweHeaders{}, hdrs)
}
// WithValidate is passed to `Parse()` method to denote that the
// validation of the JWT token should be performed after a successful
// parsing of the incoming payload.
func WithValidate(b bool) ParseOption {
return newParseOption(identValidate{}, b)
}
// WithClock specifies the `Clock` to be used when verifying
// claims exp and nbf.
func WithClock(c Clock) ValidateOption {
return newValidateOption(identClock{}, c)
}
// WithAcceptableSkew specifies the duration in which exp and nbf
// claims may differ by. This value should be positive
func WithAcceptableSkew(dur time.Duration) ValidateOption {
return newValidateOption(identAcceptableSkew{}, dur)
}
// WithIssuer specifies that expected issuer value. If not specified,
// the value of issuer is not verified at all.
func WithIssuer(s string) ValidateOption {
return newValidateOption(identIssuer{}, s)
}
// WithSubject specifies that expected subject value. If not specified,
// the value of subject is not verified at all.
func WithSubject(s string) ValidateOption {
return newValidateOption(identSubject{}, s)
}
// WithJwtID specifies that expected jti value. If not specified,
// the value of jti is not verified at all.
func WithJwtID(s string) ValidateOption {
return newValidateOption(identJwtid{}, s)
}
// WithAudience specifies that expected audience value.
// `Validate()` will return true if one of the values in the `aud` element
// matches this value. If not specified, the value of issuer is not
// verified at all.
func WithAudience(s string) ValidateOption {
return newValidateOption(identAudience{}, s)
}
type claimValue struct {
name string
value interface{}
}
// WithClaimValue specifies that expected any claim value.
func WithClaimValue(name string, v interface{}) ValidateOption {
return newValidateOption(identClaim{}, claimValue{name, v})
}
// WithHeaderKey is used to specify header keys to search for tokens.
//
// While the type system allows this option to be passed to jwt.Parse() directly,
// doing so will have no effect. Only use it for HTTP request parsing functions
func WithHeaderKey(v string) ParseRequestOption {
return &httpParseOption{newParseOption(identHeaderKey{}, v)}
}
// WithFormKey is used to specify header keys to search for tokens.
//
// While the type system allows this option to be passed to jwt.Parse() directly,
// doing so will have no effect. Only use it for HTTP request parsing functions
func WithFormKey(v string) ParseRequestOption {
return &httpParseOption{newParseOption(identFormKey{}, v)}
}
// WithFlattenAudience specifies if the "aud" claim should be flattened
// to a single string upon the token being serialized to JSON.
//
// This is sometimes important when a JWT consumer does not understand that
// the "aud" claim can actually take the form of an array of strings.
//
// The default value is `false`, which means that "aud" claims are always
// rendered as a arrays of strings. This setting has a global effect,
// and will change the behavior for all JWT serialization.
func WithFlattenAudience(v bool) GlobalOption {
return &globalOption{option.New(identFlattenAudience{}, v)}
}
type typedClaimPair struct {
Name string
Value interface{}
}
// WithTypedClaim allows a private claim to be parsed into the object type of
// your choice. It works much like the RegisterCustomField, but the effect
// is only applicable to the jwt.Parse function call which receives this option.
//
// While this can be extremely useful, this option should be used with caution:
// There are many caveats that your entire team/user-base needs to be aware of,
// and therefore in general its use is discouraged. Only use it when you know
// what you are doing, and you document its use clearly for others.
//
// First and foremost, this is a "per-object" option. Meaning that given the same
// serialized format, it is possible to generate two objects whose internal
// representations may differ. That is, if you parse one _WITH_ the option,
// and the other _WITHOUT_, their internal representation may completely differ.
// This could potentially lead to problems.
//
// Second, specifying this option will slightly slow down the decoding process
// as it needs to consult multiple definitions sources (global and local), so
// be careful if you are decoding a large number of tokens, as the effects will stack up.
//
// Finally, this option will also NOT work unless the tokens themselves support such
// parsing mechanism. For example, while tokens obtained from `jwt.New()` and
// `openid.New()` will respect this option, if you provide your own custom
// token type, it will need to implement the TokenWithDecodeCtx interface.
func WithTypedClaim(name string, object interface{}) ParseOption {
return newParseOption(identTypedClaim{}, typedClaimPair{Name: name, Value: object})
}
// WithRequiredClaim specifies that the claim identified the given name
// must exist in the token. Only the existence of the claim is checked:
// the actual value associated with that field is not checked.
func WithRequiredClaim(name string) ValidateOption {
return newValidateOption(identRequiredClaim{}, name)
}
type delta struct {
c1 string
c2 string
dur time.Duration
less bool // if true, d =< c1 - c2. otherwise d >= c1 - c2
}
// WithMaxDelta specifies that given two claims `c1` and `c2` that represent time, the difference in
// time.Duration must be less than equal to the value specified by `d`. If `c1` or `c2` is the
// empty string, the current time (as computed by `time.Now` or the object passed via
// `WithClock()`) is used for the comparison.
//
// `c1` and `c2` are also assumed to be required, therefore not providing either claim in the
// token will result in an error.
//
// Because there is no way of reliably knowing how to parse private claims, we currently only
// support `iat`, `exp`, and `nbf` claims.
//
// If the empty string is passed to c1 or c2, then the current time (as calculated by time.Now() or
// the clock object provided via WithClock()) is used.
//
// For example, in order to specify that `exp` - `iat` < 10*time.Second, you would write
//
// jwt.Validate(token, jwt.WithMaxDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey))
//
// If AcceptableSkew of 2 second is specified, the above will return valid for any value of
// `exp` - `iat` between 8 (10-2) and 12 (10+2).
func WithMaxDelta(dur time.Duration, c1, c2 string) ValidateOption {
return newValidateOption(identTimeDelta{}, delta{
c1: c1,
c2: c2,
dur: dur,
less: true,
})
}
// WithMinDelta is almost exactly the same as WithMaxDelta, but force validation to fail if
// the difference between time claims are less than dur.
//
// For example, in order to specify that `exp` - `iat` > 10*time.Second, you would write
//
// jwt.Validate(token, jwt.WithMinDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey))
//
func WithMinDelta(dur time.Duration, c1, c2 string) ValidateOption {
return newValidateOption(identTimeDelta{}, delta{
c1: c1,
c2: c2,
dur: dur,
less: false,
})
}
type decryptParams struct {
alg jwa.KeyEncryptionAlgorithm
key interface{}
}
type DecryptParameters interface {
Algorithm() jwa.KeyEncryptionAlgorithm
Key() interface{}
}
func (dp *decryptParams) Algorithm() jwa.KeyEncryptionAlgorithm {
return dp.alg
}
func (dp *decryptParams) Key() interface{} {
return dp.key
}
// WithDecrypt allows users to specify parameters for decryption using
// `jwe.Decrypt`. You must specify this if your JWT is encrypted.
func WithDecrypt(alg jwa.KeyEncryptionAlgorithm, key interface{}) ParseOption {
return newParseOption(identDecrypt{}, &decryptParams{
alg: alg,
key: key,
})
}
// WithPedantic enables pedantic mode for parsing JWTs. Currently this only
// applies to checking for the correct `typ` and/or `cty` when necessary.
func WithPedantic(v bool) ParseOption {
return newParseOption(identPedantic{}, v)
}