-
Notifications
You must be signed in to change notification settings - Fork 4
/
test.go
79 lines (73 loc) · 2.58 KB
/
test.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
package iamcel
import (
"context"
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/interpreter/functions"
"go.einride.tech/iam/iampermission"
iamv1 "go.einride.tech/iam/proto/gen/einride/iam/v1"
expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// TestFunction is the name of the test permission function.
const TestFunction = "test"
// permission test function overloads.
const testFunctionOverload = "test_caller_string_bool"
// NewTestFunctionDeclaration creates a new declaration for the test permission function.
func NewTestFunctionDeclaration() *expr.Decl {
return decls.NewFunction(
TestFunction,
decls.NewOverload(
testFunctionOverload,
[]*expr.Type{
decls.NewObjectType(string((&iamv1.Caller{}).ProtoReflect().Descriptor().FullName())),
decls.String,
},
decls.Bool,
),
)
}
// NewTestFunctionImplementation creates a new implementation for the test permission function.
func NewTestFunctionImplementation(
options *iamv1.MethodAuthorizationOptions,
tester PermissionTester,
) *functions.Overload {
return &functions.Overload{
Operator: testFunctionOverload,
Binary: func(callerVal, resourceVal ref.Val) ref.Val {
caller, ok := callerVal.Value().(*iamv1.Caller)
if !ok {
return types.NewErr("test: unexpected type of arg 1, expected %T but got %T", &iamv1.Caller{}, callerVal.Value())
}
resource, ok := resourceVal.Value().(string)
if !ok {
return types.NewErr("test: unexpected type of arg 2, expected string but got %T", resourceVal.Value())
}
permission, ok := iampermission.ResolveMethodPermission(options, resource)
if !ok {
return types.NewErr("%s: no permission configured for resource '%s'", codes.PermissionDenied, resource)
}
// TODO: When cel-go supports async functions, use the caller context here.
ctx := context.Background()
if caller.GetContext().GetDeadline() != nil {
var cancel context.CancelFunc
ctx, cancel = context.WithDeadline(ctx, caller.GetContext().GetDeadline().AsTime())
defer cancel()
}
result, err := tester.TestPermissions(ctx, caller, map[string]string{resource: permission})
switch {
case err != nil:
if s, ok := status.FromError(err); ok {
return types.NewErr("%s: %s", s.Code(), s.Message())
}
return types.NewErr("test: error testing permission '%s': %v", permission, err)
case !result[resource]:
return types.False
default:
return types.True
}
},
}
}