jwt: Simplify JWT parsing (#8802)
JWT parsing is simplified by using a custom claim data structure such as MapClaims{}, also writes a custom Unmarshaller for faster unmarshalling. - Avoid as much reflections as possible - Provide the right types for functions as much as possible - Avoid strings.Join, strings.Split to reduce allocations, rely on indexes directly.master
parent
9990464cd5
commit
bfe8a9bccc
@ -0,0 +1,371 @@ |
||||
/* |
||||
* MinIO Cloud Storage, (C) 2020 MinIO, Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package jwt |
||||
|
||||
// This file is a re-implementation of the original code here with some
|
||||
// additional allocation tweaks reproduced using GODEBUG=allocfreetrace=1
|
||||
// original file https://github.com/dgrijalva/jwt-go/blob/master/parser.go
|
||||
// borrowed under MIT License https://github.com/dgrijalva/jwt-go/blob/master/LICENSE
|
||||
|
||||
import ( |
||||
"crypto" |
||||
"crypto/hmac" |
||||
"encoding/base64" |
||||
"encoding/json" |
||||
"fmt" |
||||
"strings" |
||||
"sync" |
||||
"time" |
||||
|
||||
jwtgo "github.com/dgrijalva/jwt-go" |
||||
jsoniter "github.com/json-iterator/go" |
||||
) |
||||
|
||||
// SigningMethodHMAC - Implements the HMAC-SHA family of signing methods signing methods
|
||||
// Expects key type of []byte for both signing and validation
|
||||
type SigningMethodHMAC struct { |
||||
Name string |
||||
Hash crypto.Hash |
||||
} |
||||
|
||||
// Specific instances for HS256, HS384, HS512
|
||||
var ( |
||||
SigningMethodHS256 *SigningMethodHMAC |
||||
SigningMethodHS384 *SigningMethodHMAC |
||||
SigningMethodHS512 *SigningMethodHMAC |
||||
) |
||||
|
||||
var ( |
||||
base64BufPool sync.Pool |
||||
hmacSigners []*SigningMethodHMAC |
||||
) |
||||
|
||||
func init() { |
||||
base64BufPool = sync.Pool{ |
||||
New: func() interface{} { |
||||
buf := make([]byte, 1024) |
||||
return &buf |
||||
}, |
||||
} |
||||
|
||||
hmacSigners = []*SigningMethodHMAC{ |
||||
{"HS256", crypto.SHA256}, |
||||
{"HS384", crypto.SHA384}, |
||||
{"HS512", crypto.SHA512}, |
||||
} |
||||
} |
||||
|
||||
// StandardClaims are basically standard claims with "accessKey"
|
||||
type StandardClaims struct { |
||||
AccessKey string `json:"accessKey,omitempty"` |
||||
jwtgo.StandardClaims |
||||
} |
||||
|
||||
// MapClaims - implements custom unmarshaller
|
||||
type MapClaims struct { |
||||
AccessKey string `json:"accessKey,omitempty"` |
||||
jwtgo.MapClaims |
||||
} |
||||
|
||||
// NewStandardClaims - initializes standard claims
|
||||
func NewStandardClaims() *StandardClaims { |
||||
return &StandardClaims{} |
||||
} |
||||
|
||||
// SetIssuer sets issuer for these claims
|
||||
func (c *StandardClaims) SetIssuer(issuer string) { |
||||
c.Issuer = issuer |
||||
} |
||||
|
||||
// SetAudience sets audience for these claims
|
||||
func (c *StandardClaims) SetAudience(aud string) { |
||||
c.Audience = aud |
||||
} |
||||
|
||||
// SetExpiry sets expiry in unix epoch secs
|
||||
func (c *StandardClaims) SetExpiry(t time.Time) { |
||||
c.ExpiresAt = t.Unix() |
||||
} |
||||
|
||||
// SetAccessKey sets access key as jwt subject and custom
|
||||
// "accessKey" field.
|
||||
func (c *StandardClaims) SetAccessKey(accessKey string) { |
||||
c.Subject = accessKey |
||||
c.AccessKey = accessKey |
||||
} |
||||
|
||||
// Valid - implements https://godoc.org/github.com/dgrijalva/jwt-go#Claims compatible
|
||||
// claims interface, additionally validates "accessKey" fields.
|
||||
func (c *StandardClaims) Valid() error { |
||||
if err := c.StandardClaims.Valid(); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if c.AccessKey == "" && c.Subject == "" { |
||||
return jwtgo.NewValidationError("accessKey/sub missing", |
||||
jwtgo.ValidationErrorClaimsInvalid) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// NewMapClaims - Initializes a new map claims
|
||||
func NewMapClaims() *MapClaims { |
||||
return &MapClaims{MapClaims: jwtgo.MapClaims{}} |
||||
} |
||||
|
||||
// Lookup returns the value and if the key is found.
|
||||
func (c *MapClaims) Lookup(key string) (value string, ok bool) { |
||||
var vinterface interface{} |
||||
vinterface, ok = c.MapClaims[key] |
||||
if ok { |
||||
value, ok = vinterface.(string) |
||||
} |
||||
return |
||||
} |
||||
|
||||
// SetExpiry sets expiry in unix epoch secs
|
||||
func (c *MapClaims) SetExpiry(t time.Time) { |
||||
c.MapClaims["exp"] = t.Unix() |
||||
} |
||||
|
||||
// SetAccessKey sets access key as jwt subject and custom
|
||||
// "accessKey" field.
|
||||
func (c *MapClaims) SetAccessKey(accessKey string) { |
||||
c.MapClaims["sub"] = accessKey |
||||
c.MapClaims["accessKey"] = accessKey |
||||
} |
||||
|
||||
// Valid - implements https://godoc.org/github.com/dgrijalva/jwt-go#Claims compatible
|
||||
// claims interface, additionally validates "accessKey" fields.
|
||||
func (c *MapClaims) Valid() error { |
||||
if err := c.MapClaims.Valid(); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if c.AccessKey == "" { |
||||
return jwtgo.NewValidationError("accessKey/sub missing", |
||||
jwtgo.ValidationErrorClaimsInvalid) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// Map returns underlying low-level map claims.
|
||||
func (c *MapClaims) Map() map[string]interface{} { |
||||
return c.MapClaims |
||||
} |
||||
|
||||
// MarshalJSON marshals the MapClaims struct
|
||||
func (c *MapClaims) MarshalJSON() ([]byte, error) { |
||||
return json.Marshal(c.MapClaims) |
||||
} |
||||
|
||||
// ParseWithStandardClaims - parse the token string, valid methods.
|
||||
func ParseWithStandardClaims(tokenStr string, claims *StandardClaims, key []byte) error { |
||||
// Key is not provided.
|
||||
if key == nil { |
||||
// keyFunc was not provided, return error.
|
||||
return jwtgo.NewValidationError("no key was provided.", jwtgo.ValidationErrorUnverifiable) |
||||
} |
||||
|
||||
bufp := base64BufPool.Get().(*[]byte) |
||||
defer base64BufPool.Put(bufp) |
||||
|
||||
signer, err := ParseUnverifiedStandardClaims(tokenStr, claims, *bufp) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
i := strings.LastIndex(tokenStr, ".") |
||||
if i < 0 { |
||||
return jwtgo.ErrSignatureInvalid |
||||
} |
||||
|
||||
n, err := base64Decode(tokenStr[i+1:], *bufp) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
hasher := hmac.New(signer.Hash.New, key) |
||||
hasher.Write([]byte(tokenStr[:i])) |
||||
if !hmac.Equal((*bufp)[:n], hasher.Sum(nil)) { |
||||
return jwtgo.ErrSignatureInvalid |
||||
} |
||||
|
||||
if claims.AccessKey == "" && claims.Subject == "" { |
||||
return jwtgo.NewValidationError("accessKey/sub missing", |
||||
jwtgo.ValidationErrorClaimsInvalid) |
||||
} |
||||
|
||||
// Signature is valid, lets validate the claims for
|
||||
// other fields such as expiry etc.
|
||||
return claims.Valid() |
||||
} |
||||
|
||||
// https://tools.ietf.org/html/rfc7519#page-11
|
||||
type jwtHeader struct { |
||||
Algorithm string `json:"alg"` |
||||
Type string `json:"typ"` |
||||
} |
||||
|
||||
// ParseUnverifiedStandardClaims - WARNING: Don't use this method unless you know what you're doing
|
||||
//
|
||||
// This method parses the token but doesn't validate the signature. It's only
|
||||
// ever useful in cases where you know the signature is valid (because it has
|
||||
// been checked previously in the stack) and you want to extract values from
|
||||
// it.
|
||||
func ParseUnverifiedStandardClaims(tokenString string, claims *StandardClaims, buf []byte) (*SigningMethodHMAC, error) { |
||||
if strings.Count(tokenString, ".") != 2 { |
||||
return nil, jwtgo.ErrSignatureInvalid |
||||
} |
||||
|
||||
i := strings.Index(tokenString, ".") |
||||
j := strings.LastIndex(tokenString, ".") |
||||
|
||||
n, err := base64Decode(tokenString[:i], buf) |
||||
if err != nil { |
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed} |
||||
} |
||||
|
||||
var header = jwtHeader{} |
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary |
||||
if err = json.Unmarshal(buf[:n], &header); err != nil { |
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed} |
||||
} |
||||
|
||||
n, err = base64Decode(tokenString[i+1:j], buf) |
||||
if err != nil { |
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed} |
||||
} |
||||
|
||||
if err = json.Unmarshal(buf[:n], claims); err != nil { |
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed} |
||||
} |
||||
|
||||
for _, signer := range hmacSigners { |
||||
if header.Algorithm == signer.Name { |
||||
return signer, nil |
||||
} |
||||
} |
||||
|
||||
return nil, jwtgo.NewValidationError(fmt.Sprintf("signing method (%s) is unavailable.", header.Algorithm), |
||||
jwtgo.ValidationErrorUnverifiable) |
||||
} |
||||
|
||||
// ParseWithClaims - parse the token string, valid methods.
|
||||
func ParseWithClaims(tokenStr string, claims *MapClaims, fn func(*MapClaims) ([]byte, error)) error { |
||||
// Key lookup function has to be provided.
|
||||
if fn == nil { |
||||
// keyFunc was not provided, return error.
|
||||
return jwtgo.NewValidationError("no Keyfunc was provided.", jwtgo.ValidationErrorUnverifiable) |
||||
} |
||||
|
||||
bufp := base64BufPool.Get().(*[]byte) |
||||
defer base64BufPool.Put(bufp) |
||||
|
||||
signer, err := ParseUnverifiedMapClaims(tokenStr, claims, *bufp) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
i := strings.LastIndex(tokenStr, ".") |
||||
if i < 0 { |
||||
return jwtgo.ErrSignatureInvalid |
||||
} |
||||
|
||||
n, err := base64Decode(tokenStr[i+1:], *bufp) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
var ok bool |
||||
claims.AccessKey, ok = claims.Lookup("accessKey") |
||||
if !ok { |
||||
claims.AccessKey, ok = claims.Lookup("sub") |
||||
if !ok { |
||||
return jwtgo.NewValidationError("accessKey/sub missing", |
||||
jwtgo.ValidationErrorClaimsInvalid) |
||||
} |
||||
} |
||||
|
||||
// Lookup key from claims, claims may not be valid and may return
|
||||
// invalid key which is okay as the signature verification will fail.
|
||||
key, err := fn(claims) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
hasher := hmac.New(signer.Hash.New, key) |
||||
hasher.Write([]byte(tokenStr[:i])) |
||||
if !hmac.Equal((*bufp)[:n], hasher.Sum(nil)) { |
||||
return jwtgo.ErrSignatureInvalid |
||||
} |
||||
|
||||
// Signature is valid, lets validate the claims for
|
||||
// other fields such as expiry etc.
|
||||
return claims.Valid() |
||||
} |
||||
|
||||
// base64Decode returns the bytes represented by the base64 string s.
|
||||
func base64Decode(s string, buf []byte) (int, error) { |
||||
return base64.RawURLEncoding.Decode(buf, []byte(s)) |
||||
} |
||||
|
||||
// ParseUnverifiedMapClaims - WARNING: Don't use this method unless you know what you're doing
|
||||
//
|
||||
// This method parses the token but doesn't validate the signature. It's only
|
||||
// ever useful in cases where you know the signature is valid (because it has
|
||||
// been checked previously in the stack) and you want to extract values from
|
||||
// it.
|
||||
func ParseUnverifiedMapClaims(tokenString string, claims *MapClaims, buf []byte) (*SigningMethodHMAC, error) { |
||||
if strings.Count(tokenString, ".") != 2 { |
||||
return nil, jwtgo.ErrSignatureInvalid |
||||
} |
||||
|
||||
i := strings.Index(tokenString, ".") |
||||
j := strings.LastIndex(tokenString, ".") |
||||
|
||||
n, err := base64Decode(tokenString[:i], buf) |
||||
if err != nil { |
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed} |
||||
} |
||||
|
||||
var header = jwtHeader{} |
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary |
||||
if err = json.Unmarshal(buf[:n], &header); err != nil { |
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed} |
||||
} |
||||
|
||||
n, err = base64Decode(tokenString[i+1:j], buf) |
||||
if err != nil { |
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed} |
||||
} |
||||
|
||||
if err = json.Unmarshal(buf[:n], &claims.MapClaims); err != nil { |
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed} |
||||
} |
||||
|
||||
for _, signer := range hmacSigners { |
||||
if header.Algorithm == signer.Name { |
||||
return signer, nil |
||||
} |
||||
} |
||||
|
||||
return nil, jwtgo.NewValidationError(fmt.Sprintf("signing method (%s) is unavailable.", header.Algorithm), |
||||
jwtgo.ValidationErrorUnverifiable) |
||||
} |
@ -0,0 +1,214 @@ |
||||
/* |
||||
* MinIO Cloud Storage, (C) 2020 MinIO, Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package jwt |
||||
|
||||
// This file is a re-implementation of the original code here with some
|
||||
// additional allocation tweaks reproduced using GODEBUG=allocfreetrace=1
|
||||
// original file https://github.com/dgrijalva/jwt-go/blob/master/parser.go
|
||||
// borrowed under MIT License https://github.com/dgrijalva/jwt-go/blob/master/LICENSE
|
||||
|
||||
import ( |
||||
"fmt" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/dgrijalva/jwt-go" |
||||
jwtgo "github.com/dgrijalva/jwt-go" |
||||
) |
||||
|
||||
var ( |
||||
defaultKeyFunc = func(claim *MapClaims) ([]byte, error) { return []byte("HelloSecret"), nil } |
||||
emptyKeyFunc = func(claim *MapClaims) ([]byte, error) { return nil, nil } |
||||
errorKeyFunc = func(claim *MapClaims) ([]byte, error) { return nil, fmt.Errorf("error loading key") } |
||||
) |
||||
|
||||
var jwtTestData = []struct { |
||||
name string |
||||
tokenString string |
||||
keyfunc func(*MapClaims) ([]byte, error) |
||||
claims jwt.Claims |
||||
valid bool |
||||
errors int32 |
||||
}{ |
||||
{ |
||||
"basic", |
||||
"", |
||||
defaultKeyFunc, |
||||
&MapClaims{ |
||||
MapClaims: jwtgo.MapClaims{ |
||||
"foo": "bar", |
||||
}, |
||||
}, |
||||
true, |
||||
0, |
||||
}, |
||||
{ |
||||
"basic expired", |
||||
"", // autogen
|
||||
defaultKeyFunc, |
||||
&MapClaims{ |
||||
MapClaims: jwtgo.MapClaims{ |
||||
"foo": "bar", |
||||
"exp": float64(time.Now().Unix() - 100), |
||||
}, |
||||
}, |
||||
false, |
||||
-1, |
||||
}, |
||||
{ |
||||
"basic nbf", |
||||
"", // autogen
|
||||
defaultKeyFunc, |
||||
&MapClaims{ |
||||
MapClaims: jwtgo.MapClaims{ |
||||
"foo": "bar", |
||||
"nbf": float64(time.Now().Unix() + 100), |
||||
}, |
||||
}, |
||||
false, |
||||
-1, |
||||
}, |
||||
{ |
||||
"expired and nbf", |
||||
"", // autogen
|
||||
defaultKeyFunc, |
||||
&MapClaims{ |
||||
MapClaims: jwtgo.MapClaims{ |
||||
"foo": "bar", |
||||
"nbf": float64(time.Now().Unix() + 100), |
||||
"exp": float64(time.Now().Unix() - 100), |
||||
}, |
||||
}, |
||||
false, |
||||
-1, |
||||
}, |
||||
{ |
||||
"basic invalid", |
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", |
||||
defaultKeyFunc, |
||||
&MapClaims{ |
||||
MapClaims: jwtgo.MapClaims{ |
||||
"foo": "bar", |
||||
}, |
||||
}, |
||||
false, |
||||
-1, |
||||
}, |
||||
{ |
||||
"basic nokeyfunc", |
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", |
||||
nil, |
||||
&MapClaims{ |
||||
MapClaims: jwtgo.MapClaims{ |
||||
"foo": "bar", |
||||
}, |
||||
}, |
||||
false, |
||||
-1, |
||||
}, |
||||
{ |
||||
"basic nokey", |
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", |
||||
emptyKeyFunc, |
||||
&MapClaims{ |
||||
MapClaims: jwtgo.MapClaims{ |
||||
"foo": "bar", |
||||
}, |
||||
}, |
||||
false, |
||||
-1, |
||||
}, |
||||
{ |
||||
"basic errorkey", |
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", |
||||
errorKeyFunc, |
||||
&MapClaims{ |
||||
MapClaims: jwtgo.MapClaims{ |
||||
"foo": "bar", |
||||
}, |
||||
}, |
||||
false, |
||||
-1, |
||||
}, |
||||
{ |
||||
"Standard Claims", |
||||
"", |
||||
defaultKeyFunc, |
||||
&StandardClaims{ |
||||
StandardClaims: jwtgo.StandardClaims{ |
||||
ExpiresAt: time.Now().Add(time.Second * 10).Unix(), |
||||
}, |
||||
}, |
||||
true, |
||||
0, |
||||
}, |
||||
} |
||||
|
||||
func mapClaimsToken(claims *MapClaims) string { |
||||
claims.SetAccessKey("test") |
||||
j := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims) |
||||
tk, _ := j.SignedString([]byte("HelloSecret")) |
||||
return tk |
||||
} |
||||
|
||||
func standardClaimsToken(claims *StandardClaims) string { |
||||
claims.AccessKey = "test" |
||||
claims.Subject = "test" |
||||
j := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims) |
||||
tk, _ := j.SignedString([]byte("HelloSecret")) |
||||
return tk |
||||
} |
||||
|
||||
func TestParserParse(t *testing.T) { |
||||
// Iterate over test data set and run tests
|
||||
for _, data := range jwtTestData { |
||||
data := data |
||||
t.Run(data.name, func(t *testing.T) { |
||||
// Parse the token
|
||||
var err error |
||||
|
||||
// Figure out correct claims type
|
||||
switch claims := data.claims.(type) { |
||||
case *MapClaims: |
||||
if data.tokenString == "" { |
||||
data.tokenString = mapClaimsToken(claims) |
||||
} |
||||
err = ParseWithClaims(data.tokenString, &MapClaims{}, data.keyfunc) |
||||
case *StandardClaims: |
||||
if data.tokenString == "" { |
||||
data.tokenString = standardClaimsToken(claims) |
||||
} |
||||
err = ParseWithStandardClaims(data.tokenString, &StandardClaims{}, []byte("HelloSecret")) |
||||
} |
||||
|
||||
if data.valid && err != nil { |
||||
t.Errorf("Error while verifying token: %T:%v", err, err) |
||||
} |
||||
|
||||
if !data.valid && err == nil { |
||||
t.Errorf("Invalid token passed validation") |
||||
} |
||||
|
||||
if data.errors != 0 { |
||||
_, ok := err.(*jwt.ValidationError) |
||||
if !ok { |
||||
t.Errorf("Expected *jwt.ValidationError, but got %#v instead", err) |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
} |
Loading…
Reference in new issue