aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/dgrijalva/jwt-go/parser.go
blob: 7bf1c4ea0842249c0c844bd1586a08810fbfcb42 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package jwt

import (
    "bytes"
    "encoding/json"
    "fmt"
    "strings"
)

type Parser struct {
    ValidMethods         []string // If populated, only these methods will be considered valid
    UseJSONNumber        bool     // Use JSON Number format in JSON decoder
    SkipClaimsValidation bool     // Skip claims validation during token parsing
}

// Parse, validate, and return a token.
// keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil
func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
    return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
}

func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
    parts := strings.Split(tokenString, ".")
    if len(parts) != 3 {
        return nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
    }

    var err error
    token := &Token{Raw: tokenString}

    // parse Header
    var headerBytes []byte
    if headerBytes, err = DecodeSegment(parts[0]); err != nil {
        if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
            return token, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
        }
        return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
    }
    if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
        return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
    }

    // parse Claims
    var claimBytes []byte
    token.Claims = claims

    if claimBytes, err = DecodeSegment(parts[1]); err != nil {
        return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
    }
    dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
    if p.UseJSONNumber {
        dec.UseNumber()
    }
    // JSON Decode.  Special case for map type to avoid weird pointer behavior
    if c, ok := token.Claims.(MapClaims); ok {
        err = dec.Decode(&c)
    } else {
        err = dec.Decode(&claims)
    }
    // Handle decode error
    if err != nil {
        return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
    }

    // Lookup signature method
    if method, ok := token.Header["alg"].(string); ok {
        if token.Method = GetSigningMethod(method); token.Method == nil {
            return token, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
        }
    } else {
        return token, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
    }

    // Verify signing method is in the required set
    if p.ValidMethods != nil {
        var signingMethodValid = false
        var alg = token.Method.Alg()
        for _, m := range p.ValidMethods {
            if m == alg {
                signingMethodValid = true
                break
            }
        }
        if !signingMethodValid {
            // signing method is not in the listed set
            return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
        }
    }

    // Lookup key
    var key interface{}
    if keyFunc == nil {
        // keyFunc was not provided.  short circuiting validation
        return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
    }
    if key, err = keyFunc(token); err != nil {
        // keyFunc returned an error
        return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
    }

    vErr := &ValidationError{}

    // Validate Claims
    if !p.SkipClaimsValidation {
        if err := token.Claims.Valid(); err != nil {

            // If the Claims Valid returned an error, check if it is a validation error,
            // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
            if e, ok := err.(*ValidationError); !ok {
                vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
            } else {
                vErr = e
            }
        }
    }

    // Perform validation
    token.Signature = parts[2]
    if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
        vErr.Inner = err
        vErr.Errors |= ValidationErrorSignatureInvalid
    }

    if vErr.valid() {
        token.Valid = true
        return token, nil
    }

    return token, vErr
}