parser.go raw

   1  package jwt
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/json"
   6  	"fmt"
   7  	"strings"
   8  )
   9  
  10  const tokenDelimiter = "."
  11  
  12  type Parser struct {
  13  	// If populated, only these methods will be considered valid.
  14  	//
  15  	// Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
  16  	ValidMethods []string
  17  
  18  	// Use JSON Number format in JSON decoder.
  19  	//
  20  	// Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
  21  	UseJSONNumber bool
  22  
  23  	// Skip claims validation during token parsing.
  24  	//
  25  	// Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
  26  	SkipClaimsValidation bool
  27  }
  28  
  29  // NewParser creates a new Parser with the specified options
  30  func NewParser(options ...ParserOption) *Parser {
  31  	p := &Parser{}
  32  
  33  	// loop through our parsing options and apply them
  34  	for _, option := range options {
  35  		option(p)
  36  	}
  37  
  38  	return p
  39  }
  40  
  41  // Parse parses, validates, verifies the signature and returns the parsed token. keyFunc will
  42  // receive the parsed token and should return the key for validating.
  43  func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
  44  	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
  45  }
  46  
  47  // ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object
  48  // implementing the Claims interface. This provides default values which can be overridden and
  49  // allows a caller to use their own type, rather than the default MapClaims implementation of
  50  // Claims.
  51  //
  52  // Note: If you provide a custom claim implementation that embeds one of the standard claims (such
  53  // as RegisteredClaims), make sure that a) you either embed a non-pointer version of the claims or
  54  // b) if you are using a pointer, allocate the proper memory for it before passing in the overall
  55  // claims, otherwise you might run into a panic.
  56  func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
  57  	token, parts, err := p.ParseUnverified(tokenString, claims)
  58  	if err != nil {
  59  		return token, err
  60  	}
  61  
  62  	// Verify signing method is in the required set
  63  	if p.ValidMethods != nil {
  64  		var signingMethodValid = false
  65  		var alg = token.Method.Alg()
  66  		for _, m := range p.ValidMethods {
  67  			if m == alg {
  68  				signingMethodValid = true
  69  				break
  70  			}
  71  		}
  72  		if !signingMethodValid {
  73  			// signing method is not in the listed set
  74  			return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
  75  		}
  76  	}
  77  
  78  	// Lookup key
  79  	var key interface{}
  80  	if keyFunc == nil {
  81  		// keyFunc was not provided.  short circuiting validation
  82  		return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
  83  	}
  84  	if key, err = keyFunc(token); err != nil {
  85  		// keyFunc returned an error
  86  		if ve, ok := err.(*ValidationError); ok {
  87  			return token, ve
  88  		}
  89  		return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
  90  	}
  91  
  92  	// Perform validation
  93  	token.Signature = parts[2]
  94  	if err := token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
  95  		return token, &ValidationError{Inner: err, Errors: ValidationErrorSignatureInvalid}
  96  	}
  97  
  98  	vErr := &ValidationError{}
  99  
 100  	// Validate Claims
 101  	if !p.SkipClaimsValidation {
 102  		if err := token.Claims.Valid(); err != nil {
 103  			// If the Claims Valid returned an error, check if it is a validation error,
 104  			// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
 105  			if e, ok := err.(*ValidationError); !ok {
 106  				vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
 107  			} else {
 108  				vErr = e
 109  			}
 110  			return token, vErr
 111  		}
 112  	}
 113  
 114  	// No errors so far, token is valid.
 115  	token.Valid = true
 116  
 117  	return token, nil
 118  }
 119  
 120  // ParseUnverified parses the token but doesn't validate the signature.
 121  //
 122  // WARNING: Don't use this method unless you know what you're doing.
 123  //
 124  // It's only ever useful in cases where you know the signature is valid (because it has
 125  // been checked previously in the stack) and you want to extract values from it.
 126  func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
 127  	var ok bool
 128  	parts, ok = splitToken(tokenString)
 129  	if !ok {
 130  		return nil, nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
 131  	}
 132  
 133  	token = &Token{Raw: tokenString}
 134  
 135  	// parse Header
 136  	var headerBytes []byte
 137  	if headerBytes, err = DecodeSegment(parts[0]); err != nil {
 138  		if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
 139  			return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
 140  		}
 141  		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
 142  	}
 143  	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
 144  		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
 145  	}
 146  
 147  	// parse Claims
 148  	var claimBytes []byte
 149  	token.Claims = claims
 150  
 151  	if claimBytes, err = DecodeSegment(parts[1]); err != nil {
 152  		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
 153  	}
 154  	dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
 155  	if p.UseJSONNumber {
 156  		dec.UseNumber()
 157  	}
 158  	// JSON Decode.  Special case for map type to avoid weird pointer behavior
 159  	if c, ok := token.Claims.(MapClaims); ok {
 160  		err = dec.Decode(&c)
 161  	} else {
 162  		err = dec.Decode(&claims)
 163  	}
 164  	// Handle decode error
 165  	if err != nil {
 166  		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
 167  	}
 168  
 169  	// Lookup signature method
 170  	if method, ok := token.Header["alg"].(string); ok {
 171  		if token.Method = GetSigningMethod(method); token.Method == nil {
 172  			return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
 173  		}
 174  	} else {
 175  		return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
 176  	}
 177  
 178  	return token, parts, nil
 179  }
 180  
 181  // splitToken splits a token string into three parts: header, claims, and signature. It will only
 182  // return true if the token contains exactly two delimiters and three parts. In all other cases, it
 183  // will return nil parts and false.
 184  func splitToken(token string) ([]string, bool) {
 185  	parts := make([]string, 3)
 186  	header, remain, ok := strings.Cut(token, tokenDelimiter)
 187  	if !ok {
 188  		return nil, false
 189  	}
 190  	parts[0] = header
 191  	claims, remain, ok := strings.Cut(remain, tokenDelimiter)
 192  	if !ok {
 193  		return nil, false
 194  	}
 195  	parts[1] = claims
 196  	// One more cut to ensure the signature is the last part of the token and there are no more
 197  	// delimiters. This avoids an issue where malicious input could contain additional delimiters
 198  	// causing unecessary overhead parsing tokens.
 199  	signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
 200  	if unexpected {
 201  		return nil, false
 202  	}
 203  	parts[2] = signature
 204  
 205  	return parts, true
 206  }
 207