-
Notifications
You must be signed in to change notification settings - Fork 0
/
jwks_reader.go
109 lines (91 loc) · 2.54 KB
/
jwks_reader.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
package jwks
import (
"crypto/rsa"
"encoding/base64"
"encoding/json"
"github.com/golang-jwt/jwt/v4"
"github.com/pkg/errors"
"github.com/thomasduchatelle/dphoto/pkg/acl/aclcore"
"math/big"
"net/http"
"strings"
)
type openIdConfiguration struct {
Issuer string `json:"issuer"`
JwksUri string `json:"jwks_uri"`
}
type jwksKey struct {
Kty string `json:"kty"`
Kid string `json:"kid"`
E string `json:"e"`
Alg string `json:"alg"`
Use string `json:"use"`
N string `json:"n"`
}
type jwksResponse struct {
Keys []jwksKey `json:"keys"`
}
func readUrl(openIdConfigUrl string) (string, aclcore.OAuth2IssuerConfig, error) {
index, err := readConfigIndex(openIdConfigUrl)
if err != nil {
return "", aclcore.OAuth2IssuerConfig{}, errors.Wrapf(err, "failed to read JWKS config from %s", openIdConfigUrl)
}
jwks, err := readJWKS(index.JwksUri)
if err != nil {
return "", aclcore.OAuth2IssuerConfig{}, errors.Wrapf(err, "invalid JWKS URL %s", index.JwksUri)
}
return index.Issuer, aclcore.OAuth2IssuerConfig{
ConfigSource: openIdConfigUrl,
PublicKeysLookup: func(method aclcore.OAuthTokenMethod) (interface{}, error) {
if method.Algorithm != jwt.SigningMethodRS256.Alg() {
return nil, errors.Errorf("[OAuth2JwksConfigReader] %s algorithm is not supported.", method.Algorithm)
}
var kids []string
for _, key := range jwks.Keys {
kids = append(kids, key.Kid)
if key.Kid == method.Kid {
return parseJwks(key)
}
}
return nil, errors.Errorf("kid '%s' is not defined in %s [%s] config. Available kids are: %s.", method.Kid, index.Issuer, openIdConfigUrl, strings.Join(kids, ", "))
},
}, nil
}
func readConfigIndex(openIdConfigUrl string) (*openIdConfiguration, error) {
response, err := http.Get(openIdConfigUrl)
if err != nil {
return nil, err
}
defer response.Body.Close()
config := &openIdConfiguration{}
err = json.NewDecoder(response.Body).Decode(config)
return config, err
}
func readJWKS(uri string) (*jwksResponse, error) {
response, err := http.Get(uri)
if err != nil {
return nil, err
}
defer response.Body.Close()
jwks := &jwksResponse{}
err = json.NewDecoder(response.Body).Decode(jwks)
return jwks, err
}
func parseJwks(key jwksKey) (*rsa.PublicKey, error) {
n, err := base64.RawURLEncoding.DecodeString(key.N)
if err != nil {
return nil, err
}
e, err := base64.RawURLEncoding.DecodeString(key.E)
if err != nil {
return nil, err
}
ei := big.NewInt(0).SetBytes(e).Int64()
if err != nil {
return nil, err
}
return &rsa.PublicKey{
N: big.NewInt(0).SetBytes(n),
E: int(ei),
}, nil
}