-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
120 lines (95 loc) · 2.84 KB
/
main.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 firebasegoa
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
"golang.org/x/sync/singleflight"
"github.com/auth0/go-jwt-middleware"
jwtgo "github.com/dgrijalva/jwt-go"
"github.com/goadesign/goa"
"github.com/goadesign/goa/middleware/security/jwt"
)
const (
jwksEndpoint = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"
)
// GetPemCert retrieves public keys to verify tokens
type GetPemCert func(*jwtgo.Token) (string, error)
// BridgeMiddlewareHandler converts jwt middleware into goa middleware.
type BridgeMiddlewareHandler struct {
Middleware *jwtmiddleware.JWTMiddleware
}
// Handle implements goa.Middleware interface
func (h *BridgeMiddlewareHandler) Handle(nextHandler goa.Handler) goa.Handler {
return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
if err := h.Middleware.CheckJWT(rw, req); err != nil {
return jwt.ErrJWTError(err)
}
token := req.Context().Value(h.Middleware.Options.UserProperty).(*jwtgo.Token)
newCtx := jwt.WithJWT(ctx, token)
return nextHandler(newCtx, rw, req)
}
}
// NewJWTMiddleware returns a jwt middleware for Auth0
func NewJWTMiddleware(aud, iss string, getPemCert GetPemCert) *jwtmiddleware.JWTMiddleware {
return jwtmiddleware.New(jwtmiddleware.Options{
ValidationKeyGetter: func(token *jwtgo.Token) (interface{}, error) {
// Verify 'aud' claim
checkAud := token.Claims.(jwtgo.MapClaims).VerifyAudience(aud, false)
if !checkAud {
return token, errors.New("Invalid audience")
}
// Verify 'iss' claim
checkIss := token.Claims.(jwtgo.MapClaims).VerifyIssuer(iss, false)
if !checkIss {
return token, errors.New("Invalid issuer")
}
cert, err := getPemCert(token)
if err != nil {
return nil, err
}
result, _ := jwtgo.ParseRSAPublicKeyFromPEM([]byte(cert))
return result, nil
},
SigningMethod: jwtgo.SigningMethodRS256,
})
}
// NewGetPemCert creates a cacheable pem getter function
func NewGetPemCert() GetPemCert {
var group singleflight.Group
var updatedTime time.Time
var cacheJWKS *Jwks
return func(token *jwtgo.Token) (string, error) {
v, err, _ := group.Do("jwks", func() (interface{}, error) {
if cacheJWKS != nil && time.Now().Sub(updatedTime) < 30*time.Minute {
return cacheJWKS, nil
}
resp, err := http.Get(jwksEndpoint)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var jwks Jwks
err = json.NewDecoder(resp.Body).Decode(&jwks)
if err != nil {
return nil, err
}
cacheJWKS = &jwks
updatedTime = time.Now()
return &jwks, nil
})
if err != nil {
return "", err
}
jwks := v.(*Jwks) // Do not edit
var cert string
cert, ok := (*jwks)[fmt.Sprint(token.Header["kid"])]
if !ok {
err := errors.New("Unable to find appropriate key")
return "", err
}
return cert, nil
}
}