You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

parser.go 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package jwt
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/json"
  6. "fmt"
  7. "strings"
  8. )
  9. type Parser struct {
  10. // If populated, only these methods will be considered valid.
  11. validMethods []string
  12. // Use JSON Number format in JSON decoder.
  13. useJSONNumber bool
  14. // Skip claims validation during token parsing.
  15. skipClaimsValidation bool
  16. validator *Validator
  17. decodeStrict bool
  18. decodePaddingAllowed bool
  19. }
  20. // NewParser creates a new Parser with the specified options
  21. func NewParser(options ...ParserOption) *Parser {
  22. p := &Parser{
  23. validator: &Validator{},
  24. }
  25. // Loop through our parsing options and apply them
  26. for _, option := range options {
  27. option(p)
  28. }
  29. return p
  30. }
  31. // Parse parses, validates, verifies the signature and returns the parsed token.
  32. // keyFunc will receive the parsed token and should return the key for validating.
  33. func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
  34. return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
  35. }
  36. // ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims
  37. // interface. This provides default values which can be overridden and allows a caller to use their own type, rather
  38. // than the default MapClaims implementation of Claims.
  39. //
  40. // Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
  41. // make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
  42. // proper memory for it before passing in the overall claims, otherwise you might run into a panic.
  43. func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
  44. token, parts, err := p.ParseUnverified(tokenString, claims)
  45. if err != nil {
  46. return token, err
  47. }
  48. // Verify signing method is in the required set
  49. if p.validMethods != nil {
  50. var signingMethodValid = false
  51. var alg = token.Method.Alg()
  52. for _, m := range p.validMethods {
  53. if m == alg {
  54. signingMethodValid = true
  55. break
  56. }
  57. }
  58. if !signingMethodValid {
  59. // signing method is not in the listed set
  60. return token, newError(fmt.Sprintf("signing method %v is invalid", alg), ErrTokenSignatureInvalid)
  61. }
  62. }
  63. // Decode signature
  64. token.Signature, err = p.DecodeSegment(parts[2])
  65. if err != nil {
  66. return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
  67. }
  68. text := strings.Join(parts[0:2], ".")
  69. // Lookup key(s)
  70. if keyFunc == nil {
  71. // keyFunc was not provided. short circuiting validation
  72. return token, newError("no keyfunc was provided", ErrTokenUnverifiable)
  73. }
  74. got, err := keyFunc(token)
  75. if err != nil {
  76. return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
  77. }
  78. switch have := got.(type) {
  79. case VerificationKeySet:
  80. if len(have.Keys) == 0 {
  81. return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
  82. }
  83. // Iterate through keys and verify signature, skipping the rest when a match is found.
  84. // Return the last error if no match is found.
  85. for _, key := range have.Keys {
  86. if err = token.Method.Verify(text, token.Signature, key); err == nil {
  87. break
  88. }
  89. }
  90. default:
  91. err = token.Method.Verify(text, token.Signature, have)
  92. }
  93. if err != nil {
  94. return token, newError("", ErrTokenSignatureInvalid, err)
  95. }
  96. // Validate Claims
  97. if !p.skipClaimsValidation {
  98. // Make sure we have at least a default validator
  99. if p.validator == nil {
  100. p.validator = NewValidator()
  101. }
  102. if err := p.validator.Validate(claims); err != nil {
  103. return token, newError("", ErrTokenInvalidClaims, err)
  104. }
  105. }
  106. // No errors so far, token is valid.
  107. token.Valid = true
  108. return token, nil
  109. }
  110. // ParseUnverified parses the token but doesn't validate the signature.
  111. //
  112. // WARNING: Don't use this method unless you know what you're doing.
  113. //
  114. // It's only ever useful in cases where you know the signature is valid (since it has already
  115. // been or will be checked elsewhere in the stack) and you want to extract values from it.
  116. func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
  117. parts = strings.Split(tokenString, ".")
  118. if len(parts) != 3 {
  119. return nil, parts, newError("token contains an invalid number of segments", ErrTokenMalformed)
  120. }
  121. token = &Token{Raw: tokenString}
  122. // parse Header
  123. var headerBytes []byte
  124. if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
  125. return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
  126. }
  127. if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
  128. return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err)
  129. }
  130. // parse Claims
  131. token.Claims = claims
  132. claimBytes, err := p.DecodeSegment(parts[1])
  133. if err != nil {
  134. return token, parts, newError("could not base64 decode claim", ErrTokenMalformed, err)
  135. }
  136. // If `useJSONNumber` is enabled then we must use *json.Decoder to decode
  137. // the claims. However, this comes with a performance penalty so only use
  138. // it if we must and, otherwise, simple use json.Unmarshal.
  139. if !p.useJSONNumber {
  140. // JSON Unmarshal. Special case for map type to avoid weird pointer behavior.
  141. if c, ok := token.Claims.(MapClaims); ok {
  142. err = json.Unmarshal(claimBytes, &c)
  143. } else {
  144. err = json.Unmarshal(claimBytes, &claims)
  145. }
  146. } else {
  147. dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
  148. dec.UseNumber()
  149. // JSON Decode. Special case for map type to avoid weird pointer behavior.
  150. if c, ok := token.Claims.(MapClaims); ok {
  151. err = dec.Decode(&c)
  152. } else {
  153. err = dec.Decode(&claims)
  154. }
  155. }
  156. if err != nil {
  157. return token, parts, newError("could not JSON decode claim", ErrTokenMalformed, err)
  158. }
  159. // Lookup signature method
  160. if method, ok := token.Header["alg"].(string); ok {
  161. if token.Method = GetSigningMethod(method); token.Method == nil {
  162. return token, parts, newError("signing method (alg) is unavailable", ErrTokenUnverifiable)
  163. }
  164. } else {
  165. return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable)
  166. }
  167. return token, parts, nil
  168. }
  169. // DecodeSegment decodes a JWT specific base64url encoding. This function will
  170. // take into account whether the [Parser] is configured with additional options,
  171. // such as [WithStrictDecoding] or [WithPaddingAllowed].
  172. func (p *Parser) DecodeSegment(seg string) ([]byte, error) {
  173. encoding := base64.RawURLEncoding
  174. if p.decodePaddingAllowed {
  175. if l := len(seg) % 4; l > 0 {
  176. seg += strings.Repeat("=", 4-l)
  177. }
  178. encoding = base64.URLEncoding
  179. }
  180. if p.decodeStrict {
  181. encoding = encoding.Strict()
  182. }
  183. return encoding.DecodeString(seg)
  184. }
  185. // Parse parses, validates, verifies the signature and returns the parsed token.
  186. // keyFunc will receive the parsed token and should return the cryptographic key
  187. // for verifying the signature. The caller is strongly encouraged to set the
  188. // WithValidMethods option to validate the 'alg' claim in the token matches the
  189. // expected algorithm. For more details about the importance of validating the
  190. // 'alg' claim, see
  191. // https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
  192. func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
  193. return NewParser(options...).Parse(tokenString, keyFunc)
  194. }
  195. // ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
  196. //
  197. // Note: If you provide a custom claim implementation that embeds one of the
  198. // standard claims (such as RegisteredClaims), make sure that a) you either
  199. // embed a non-pointer version of the claims or b) if you are using a pointer,
  200. // allocate the proper memory for it before passing in the overall claims,
  201. // otherwise you might run into a panic.
  202. func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
  203. return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
  204. }