-
Notifications
You must be signed in to change notification settings - Fork 24
/
token_validator.go
120 lines (93 loc) · 2.33 KB
/
token_validator.go
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
package uaa
import (
"errors"
"fmt"
"sync"
"github.com/golang-jwt/jwt/v5"
"github.com/pivotal-cf-experimental/warrant"
"github.com/pivotal-golang/lager"
)
type keysFetcher interface {
GetSigningKeys() ([]warrant.SigningKey, error)
}
type TokenValidator struct {
keysFetcher keysFetcher
keyMap map[string]warrant.SigningKey
keyMutex sync.RWMutex
logger lager.Logger
}
func NewTokenValidator(logger lager.Logger, keysFetcher keysFetcher) *TokenValidator {
logger = logger.Session("uaa.token.validator")
return &TokenValidator{
logger: logger,
keysFetcher: keysFetcher,
keyMap: make(map[string]warrant.SigningKey),
}
}
func (v *TokenValidator) LoadSigningKeys() error {
v.logger.Info("loading.keys")
keys, err := v.keysFetcher.GetSigningKeys()
if err != nil {
v.logger.Error("loading.keys.failed", err)
return err
}
keyMap := make(map[string]warrant.SigningKey, len(keys))
keyNames := make([]string, 0, len(keys))
for _, key := range keys {
keyMap[key.KeyId] = key
keyNames = append(keyNames, key.KeyId)
}
v.logger.Info("loaded.keys", lager.Data{
"keys": keyNames,
})
v.keyMutex.Lock()
defer v.keyMutex.Unlock()
v.keyMap = keyMap
return nil
}
func (v *TokenValidator) findKey(id string) (warrant.SigningKey, bool) {
v.keyMutex.RLock()
defer v.keyMutex.RUnlock()
key, ok := v.keyMap[id]
return key, ok
}
func (v *TokenValidator) lookUp(keyId string) (string, error) {
key, ok := v.findKey(keyId)
if ok {
return key.Value, nil
}
if err := v.LoadSigningKeys(); err != nil {
return "", err
}
key, ok = v.findKey(keyId)
if !ok {
return "", fmt.Errorf("unknown key with id %s", keyId)
}
return key.Value, nil
}
func (v *TokenValidator) Parse(rawToken string) (*jwt.Token, error) {
return jwt.Parse(rawToken, func(t *jwt.Token) (interface{}, error) {
switch t.Method {
case
jwt.SigningMethodRS256,
jwt.SigningMethodRS384,
jwt.SigningMethodRS512:
break
default:
return nil, fmt.Errorf("Unsupported signing method %v", t.Method.Alg())
}
keyId, ok := t.Header["kid"].(string)
if !ok {
return nil, errors.New("Unable to lookup key id for the token")
}
key, err := v.lookUp(keyId)
if err != nil {
return nil, err
}
pubKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(key))
if err != nil {
return nil, err
}
return pubKey, nil
})
}