forked from travelgateX/go-jwt-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
auth.go
115 lines (103 loc) · 3.25 KB
/
auth.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
package jwt
import (
"fmt"
"strings"
"github.com/dgrijalva/jwt-go"
authorization "github.com/travelgateX/go-jwt-tools"
)
var _ authorization.Parser = (*Parser)(nil)
type Parser struct {
ParserConfig
KeyFunc func(token *jwt.Token) (interface{}, error)
}
// ParserConfig is the data required to instance a Parser
type ParserConfig struct {
PublicKey string `json:"public_key_str"`
AdminGroup string `json:"admin_group"`
DummyToken string `json:"dummy_token"`
IgnoreExpiration bool `json:"ignore_expiration"`
MemberIDClaim []string `json:"member_id_claim"`
GroupsClaim []string `json:"groups_claim"`
FetchNeededClaim []string `json:"fetch_needed_claim"`
}
// NewParser returns an instance of Parser which parses bearers from a publicKey
func NewParser(p ParserConfig) *Parser {
jkf := func(token *jwt.Token) (interface{}, error) {
var result interface{}
result, _ = jwt.ParseRSAPublicKeyFromPEM([]byte(p.PublicKey))
return result, nil
}
return &Parser{
KeyFunc: jkf,
ParserConfig: p,
}
}
func (p *Parser) Parse(authorizationHeader string) (*authorization.User, error) {
// validate bearer
authorizationHeaderParts := strings.SplitN(authorizationHeader, " ", 2)
if len(authorizationHeaderParts) != 2 || authorizationHeaderParts[0] != "Bearer" {
return nil, fmt.Errorf("authorizationorization header format must be Bearer {token}")
}
// dummy treatment
if p.DummyToken != "" && authorizationHeaderParts[1] == p.DummyToken {
return &authorization.User{
AuthorizationValue: authorizationHeader,
IsDummy: true,
Permissions: nil, // TODO: NoopImpl?
}, nil
}
// parse token
jwtp := &jwt.Parser{SkipClaimsValidation: p.IgnoreExpiration}
token, err := jwtp.Parse(authorizationHeaderParts[1], p.KeyFunc)
if err != nil {
return nil, fmt.Errorf("error parsing bearer: %v", err)
}
if jwt.SigningMethodRS256.Alg() != token.Header["alg"] {
message := fmt.Sprintf("Expected %s signing method but token specified %s",
jwt.SigningMethodRS256.Alg(),
token.Header["alg"])
return nil, fmt.Errorf("Error validating token algorithm: %s", message)
}
// check if the parsed token is valid...
if !token.Valid {
return nil, authorization.ErrInvalidUser
}
return p.createUser(token)
}
func (p *Parser) createUser(token *jwt.Token) (*authorization.User, error) {
claimsMap := token.Claims.(jwt.MapClaims)
// TODO: remove when migration finishes
groups := make([]interface{}, 0, len(p.GroupsClaim))
for _, g := range p.GroupsClaim {
if c, ok := claimsMap[g]; ok {
groups = append(groups, c)
}
}
if len(groups) == 0 {
return nil, fmt.Errorf("Your token doesn't contain any group")
}
memberIDs := make([]string, 0, len(p.MemberIDClaim))
for _, m := range p.MemberIDClaim {
if c, ok := claimsMap[m]; ok {
if mID, ok := c.(string); ok {
memberIDs = append(memberIDs, mID)
}
}
}
fetchNeeded := false
for _, f := range p.FetchNeededClaim {
if c, ok := claimsMap[f]; ok {
if c.(bool) {
fetchNeeded = true
break
}
}
}
return &authorization.User{
AuthorizationValue: "Bearer " + token.Raw,
IsDummy: false,
FetchNeeded: fetchNeeded,
Permissions: NewPermissions(groups, memberIDs, p.AdminGroup),
UserID: memberIDs,
}, nil
}