-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathportcullis.go
124 lines (111 loc) · 2.95 KB
/
portcullis.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
package portcullis
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"sort"
"strings"
"golang.org/x/net/context"
"google.golang.org/grpc/metadata"
"github.com/kubex/portcullis-go/keys"
)
// ReqInfo is the structure for deserialised request information
type ReqInfo struct {
ProjectID string
UserID string
AppID string
VendorID string
Username string
FirstName string
LastName string
signature string
meta metadata.MD
Roles []string
Permissions []string
}
// Verify checks that the request signature matches using signature key
func (r *ReqInfo) Verify(sigKey string) bool {
mac := hmac.New(sha256.New, []byte(sigKey))
mk := make([]string, len(r.meta))
i := 0
for k := range r.meta {
mk[i] = k
i++
}
sort.Strings(mk)
m := ""
for _, v := range mk {
if strings.HasPrefix(v, keys.GetKeyPrefix()) {
m = m + v
b := r.meta[v]
sort.Strings(b)
for _, a := range b {
m = m + a
}
}
}
mac.Write([]byte(m))
expectedMAC := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(r.signature), []byte(expectedMAC))
}
// GlobalAppID is getter for requesting app's Global ID
func (r *ReqInfo) GlobalAppID() string {
return fmt.Sprintf("%s/%s", r.VendorID, r.AppID)
}
// HasRole check if the user has a specific role
func (r *ReqInfo) HasRole(checkRole string) bool {
for _, role := range r.Roles {
if role == r.ProjectID+"/"+checkRole {
return true
}
}
return false
}
// HasPermission check if the user has a specific permission
func (r *ReqInfo) HasPermission(checkPermission string) bool {
for _, permission := range r.Permissions {
if permission == r.ProjectID+"/"+checkPermission {
return true
}
}
return false
}
// FromContext retrieves request info from given request context
func FromContext(ctx context.Context) ReqInfo {
md, _ := metadata.FromContext(ctx)
res := ReqInfo{
ProjectID: safeGetMetaValString(keys.GetProjectKey(), md),
UserID: safeGetMetaValString(keys.GetUserIDKey(), md),
Username: safeGetMetaValString(keys.GetUsernameKey(), md),
FirstName: safeGetMetaValString(keys.GetFirstNameKey(), md),
LastName: safeGetMetaValString(keys.GetLastNameKey(), md),
AppID: safeGetMetaValString(keys.GetAppIDKey(), md),
VendorID: safeGetMetaValString(keys.GetAppVendorKey(), md),
signature: safeGetMetaValString(keys.GetSignatureKey(), md),
Roles: safeGetMetaValStringSlice(keys.GetRolesKey(), md),
Permissions: safeGetMetaValStringSlice(keys.GetPermissionsKey(), md),
meta: md,
}
return res
}
func safeGetMetaValString(key string, md metadata.MD) string {
result := ""
if md != nil {
if len(md[key]) != 0 {
result = md[key][0]
}
}
return result
}
func safeGetMetaValStringSlice(key string, md metadata.MD) []string {
result := []string{}
if md != nil {
if sliceKeys, hasKey := md[key]; hasKey {
for _, sliceValue := range sliceKeys {
result = append(result, sliceValue)
}
}
}
return result
}