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