forked from argoproj/argo-cd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jwt.go
112 lines (100 loc) · 2.42 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
package jwt
import (
"encoding/json"
"fmt"
jwtgo "github.com/dgrijalva/jwt-go"
)
// MapClaims converts a jwt.Claims to a MapClaims
func MapClaims(claims jwtgo.Claims) (jwtgo.MapClaims, error) {
claimsBytes, err := json.Marshal(claims)
if err != nil {
return nil, err
}
var mapClaims jwtgo.MapClaims
err = json.Unmarshal(claimsBytes, &mapClaims)
if err != nil {
return nil, err
}
return mapClaims, nil
}
// GetField extracts a field from the claims as a string
func GetField(claims jwtgo.MapClaims, fieldName string) string {
if fieldIf, ok := claims[fieldName]; ok {
if field, ok := fieldIf.(string); ok {
return field
}
}
return ""
}
// GetScopeValues extracts the values of specified scopes from the claims
func GetScopeValues(claims jwtgo.MapClaims, scopes []string) []string {
groups := make([]string, 0)
for i := range scopes {
scopeIf, ok := claims[scopes[i]]
if !ok {
continue
}
switch val := scopeIf.(type) {
case []interface{}:
for _, groupIf := range val {
group, ok := groupIf.(string)
if ok {
groups = append(groups, group)
}
}
case []string:
groups = append(groups, val...)
case string:
groups = append(groups, val)
}
}
return groups
}
func GetID(m jwtgo.MapClaims) (string, error) {
if jtiIf, ok := m["jti"]; ok {
if jti, ok := jtiIf.(string); ok {
return jti, nil
}
}
return "", fmt.Errorf("jti '%v' is not a string", m["jti"])
}
// GetIssuedAt returns the issued at as an int64
func GetIssuedAt(m jwtgo.MapClaims) (int64, error) {
switch iat := m["iat"].(type) {
case float64:
return int64(iat), nil
case json.Number:
return iat.Int64()
case int64:
return iat, nil
default:
return 0, fmt.Errorf("iat '%v' is not a number", iat)
}
}
func Claims(in interface{}) jwtgo.Claims {
claims, ok := in.(jwtgo.Claims)
if ok {
return claims
}
return nil
}
// IsMember returns whether or not the user's claims is a member of any of the groups
func IsMember(claims jwtgo.Claims, groups []string) bool {
mapClaims, err := MapClaims(claims)
if err != nil {
return false
}
// TODO: groups is hard-wired but we should really be honoring the 'scopes' section in argocd-rbac-cm.
// O(n^2) loop
for _, userGroup := range GetGroups(mapClaims) {
for _, group := range groups {
if userGroup == group {
return true
}
}
}
return false
}
func GetGroups(mapClaims jwtgo.MapClaims) []string {
return GetScopeValues(mapClaims, []string{"groups"})
}