github.com/influxdata/influxdb/v2@v2.7.6/jsonweb/token.go (about) 1 package jsonweb 2 3 import ( 4 "errors" 5 6 "github.com/golang-jwt/jwt" 7 "github.com/influxdata/influxdb/v2" 8 "github.com/influxdata/influxdb/v2/kit/platform" 9 ) 10 11 const kind = "jwt" 12 13 var ( 14 // ErrKeyNotFound should be returned by a KeyStore when 15 // a key cannot be located for the provided key ID 16 ErrKeyNotFound = errors.New("key not found") 17 18 // EmptyKeyStore is a KeyStore implementation which contains no keys 19 EmptyKeyStore = KeyStoreFunc(func(string) ([]byte, error) { 20 return nil, ErrKeyNotFound 21 }) 22 ) 23 24 // KeyStore is a type which holds a set of keys accessed 25 // via an id 26 type KeyStore interface { 27 Key(string) ([]byte, error) 28 } 29 30 // KeyStoreFunc is a function which can be used as a KeyStore 31 type KeyStoreFunc func(string) ([]byte, error) 32 33 // Key delegates to the receiver KeyStoreFunc 34 func (k KeyStoreFunc) Key(v string) ([]byte, error) { return k(v) } 35 36 // TokenParser is a type which can parse and validate tokens 37 type TokenParser struct { 38 keyStore KeyStore 39 parser *jwt.Parser 40 } 41 42 // NewTokenParser returns a configured token parser used to 43 // parse Token types from strings 44 func NewTokenParser(keyStore KeyStore) *TokenParser { 45 return &TokenParser{ 46 keyStore: keyStore, 47 parser: &jwt.Parser{ 48 ValidMethods: []string{jwt.SigningMethodHS256.Alg()}, 49 }, 50 } 51 } 52 53 // Parse takes a string then parses and validates it as a jwt based on 54 // the key described within the token 55 func (t *TokenParser) Parse(v string) (*Token, error) { 56 jwt, err := t.parser.ParseWithClaims(v, &Token{}, func(jwt *jwt.Token) (interface{}, error) { 57 token, ok := jwt.Claims.(*Token) 58 if !ok { 59 return nil, errors.New("missing kid in token claims") 60 } 61 62 // fetch key for "kid" from key store 63 return t.keyStore.Key(token.KeyID) 64 }) 65 66 if err != nil { 67 return nil, err 68 } 69 70 token, ok := jwt.Claims.(*Token) 71 if !ok { 72 return nil, errors.New("token is unexpected type") 73 } 74 75 return token, nil 76 } 77 78 // IsMalformedError returns true if the error returned represents 79 // a jwt malformed token error 80 func IsMalformedError(err error) bool { 81 verr, ok := err.(*jwt.ValidationError) 82 return ok && verr.Errors&jwt.ValidationErrorMalformed > 0 83 } 84 85 // Token is a structure which is serialized as a json web token 86 // It contains the necessary claims required to authorize 87 type Token struct { 88 jwt.StandardClaims 89 // KeyID is the identifier of the key used to sign the token 90 KeyID string `json:"kid"` 91 // Permissions is the set of authorized permissions for the token 92 Permissions []influxdb.Permission `json:"permissions"` 93 // UserID for the token 94 UserID string `json:"uid,omitempty"` 95 } 96 97 // PermissionSet returns the set of permissions associated with the token. 98 func (t *Token) PermissionSet() (influxdb.PermissionSet, error) { 99 return t.Permissions, nil 100 } 101 102 // Identifier returns the identifier for this Token 103 // as found in the standard claims 104 func (t *Token) Identifier() platform.ID { 105 id, err := platform.IDFromString(t.Id) 106 if err != nil || id == nil { 107 return platform.ID(1) 108 } 109 110 return *id 111 } 112 113 // GetUserID returns an invalid id as tokens are generated 114 // with permissions rather than for or by a particular user 115 func (t *Token) GetUserID() platform.ID { 116 id, err := platform.IDFromString(t.UserID) 117 if err != nil { 118 return platform.InvalidID() 119 } 120 return *id 121 } 122 123 // Kind returns the string "jwt" which is used for auditing 124 func (t *Token) Kind() string { 125 return kind 126 } 127 128 // EphemeralAuth creates a influxdb Auth form a jwt token 129 func (t *Token) EphemeralAuth(orgID platform.ID) *influxdb.Authorization { 130 return &influxdb.Authorization{ 131 ID: t.Identifier(), 132 OrgID: orgID, 133 Status: influxdb.Active, 134 Permissions: t.Permissions, 135 } 136 }