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  }