-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterceptor.go
112 lines (89 loc) · 2.77 KB
/
interceptor.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 vanguard
import (
"context"
"log"
"sync"
"github.com/google/cel-go/interpreter"
pb "github.com/srikrsna/vanguard/vanguard"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type ErrorLogger func(v ...interface{})
// PermissionsFunc is used to retreive the permissions of the current user.
// The context passed is an incoming grpc context.
//
// If it returns an error, it will be returned to the user.
type PermissionsFunc func(context.Context) ([]*Permission, error)
type InterceptorOptions struct {
Skip bool
ErrorLogger ErrorLogger
}
// Interceptor is grpc UnaryServerInterceptor that asserts that a caller has permission to access the endpoints.
// PermissionsFunc is used to retreive the permissions of the current user
func Interceptor(store Vanguard, pf PermissionsFunc, opt *InterceptorOptions) grpc.UnaryServerInterceptor {
if opt.Skip {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
return handler(ctx, req)
}
}
if opt.ErrorLogger == nil {
opt.ErrorLogger = log.Println
}
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
assert, ok := store[info.FullMethod]
if !ok {
return handler(ctx, req)
}
perms, err := pf(ctx)
if err != nil {
return nil, err
}
vars := varPool.Get()
defer varPool.Put(vars)
vars.R = req
vars.U = perms
v, _, err := assert.Eval(vars)
if err != nil {
opt.ErrorLogger("vanguard: unable to evaluate access assertions, most likely a bug in vanguard, please open an issue: %v", err)
return nil, status.Error(codes.Unknown, "Unknown error")
}
allow, ok := v.Value().(bool)
if !ok {
opt.ErrorLogger("vanguard: unable to evaluate access assertions to bool, most likely a bug in vanguard, please open an issue: type: %[0]T, value: %[0]v", v.Value())
return nil, status.Error(codes.Unknown, "Unknown error")
}
if !allow {
return nil, status.Error(codes.PermissionDenied, codes.PermissionDenied.String())
}
return handler(ctx, req)
}
}
type varPoolType sync.Pool
func (vp *varPoolType) Get() *activation {
return ((*sync.Pool)(vp)).Get().(*activation)
}
func (vp *varPoolType) Put(a *activation) {
((*sync.Pool)(vp)).Put(a)
}
var varPool = varPoolType{
New: func() interface{} {
return new(activation)
},
}
var _ interpreter.Activation = (*activation)(nil)
type activation struct {
R interface{}
U []*pb.Permission
}
func (a *activation) ResolveName(name string) (interface{}, bool) {
switch name {
case "r":
return a.R, true
case "u":
return a.U, true
default:
return nil, false
}
}
func (a *activation) Parent() interpreter.Activation { return nil }