-
Notifications
You must be signed in to change notification settings - Fork 0
/
jwt.go
127 lines (101 loc) · 2.43 KB
/
jwt.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
121
122
123
124
125
126
127
package shared
import (
"errors"
"fmt"
"os"
"regexp"
"time"
"github.com/aws/aws-lambda-go/events"
"github.com/golang-jwt/jwt/v5"
)
const (
sirius string = "opg.poas.sirius"
mrlpa = "opg.poas.makeregister"
)
var validIssuers []string = []string{
sirius,
mrlpa,
}
type lpaStoreClaims struct {
jwt.RegisteredClaims
}
// note that default validation for RegisteredClaims checks exp is in the future
func (l lpaStoreClaims) Validate() error {
// validate issued at (iat)
iat, err := l.GetIssuedAt()
if err != nil {
return err
}
if iat.Time.After(time.Now()) {
return errors.New("IssuedAt must not be in the future")
}
// validate issuer (iss)
iss, err := l.GetIssuer()
if err != nil {
return err
}
isValid := false
for _, validIssuer := range validIssuers {
if validIssuer == iss {
isValid = true
break
}
}
if !isValid {
return errors.New("Invalid Issuer")
}
// validate subject (sub) depending on the issuer value
sub, err := l.GetSubject()
if err != nil {
return err
}
if iss == sirius {
emailRegex := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
if !emailRegex.MatchString(sub) {
return errors.New("Subject is not a valid email")
}
}
if iss == mrlpa {
uidRegex := regexp.MustCompile("^.+$")
if !uidRegex.MatchString(sub) {
return errors.New("Subject is not a valid UID")
}
}
return nil
}
type JWTVerifier struct {
secretKey []byte
}
func NewJWTVerifier() JWTVerifier {
return JWTVerifier{
secretKey: []byte(os.Getenv("JWT_SECRET_KEY")),
}
}
// tokenStr is the JWT token, minus any "Bearer: " prefix
func (v JWTVerifier) VerifyToken(tokenStr string) error {
lsc := lpaStoreClaims{}
parsedToken, err := jwt.ParseWithClaims(tokenStr, &lsc, func(token *jwt.Token) (interface{}, error) {
return v.secretKey, nil
})
if err != nil {
return err
}
if !parsedToken.Valid {
return fmt.Errorf("Invalid JWT")
}
return nil
}
var bearerRegexp = regexp.MustCompile("^Bearer[ ]+")
// verify JWT from event header
// returns true if verified, false otherwise
func (v JWTVerifier) VerifyHeader(event events.APIGatewayProxyRequest) bool {
jwtHeaders := GetEventHeader("X-Jwt-Authorization", event)
if len(jwtHeaders) < 1 {
return false
}
tokenStr := bearerRegexp.ReplaceAllString(jwtHeaders[0], "")
if v.VerifyToken(tokenStr) != nil {
return false
}
return true
}