/
rule.go
90 lines (83 loc) · 3.19 KB
/
rule.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
// Copyright 2019-present Facebook Inc. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package rule
import (
"context"
"entgo.io/ent/examples/privacytenant/ent"
"entgo.io/ent/examples/privacytenant/ent/predicate"
"entgo.io/ent/examples/privacytenant/ent/privacy"
"entgo.io/ent/examples/privacytenant/ent/tenant"
"entgo.io/ent/examples/privacytenant/ent/user"
"entgo.io/ent/examples/privacytenant/viewer"
)
// DenyIfNoViewer is a rule that returns deny decision if the viewer is missing in the context.
func DenyIfNoViewer() privacy.QueryMutationRule {
return privacy.ContextQueryMutationRule(func(ctx context.Context) error {
view := viewer.FromContext(ctx)
if view == nil {
return privacy.Denyf("viewer-context is missing")
}
// Skip to the next privacy rule (equivalent to return nil).
return privacy.Skip
})
}
// AllowIfAdmin is a rule that returns allow decision if the viewer is admin.
func AllowIfAdmin() privacy.QueryMutationRule {
return privacy.ContextQueryMutationRule(func(ctx context.Context) error {
view := viewer.FromContext(ctx)
if view.Admin() {
return privacy.Allow
}
// Skip to the next privacy rule (equivalent to return nil).
return privacy.Skip
})
}
// FilterTenantRule is a query/mutation rule that filters out entities that are not in the tenant.
func FilterTenantRule() privacy.QueryMutationRule {
// TenantsFilter is an interface to wrap WhereHasTenantWith()
// predicate that is used by both `Group` and `User` schemas.
type TenantsFilter interface {
WhereHasTenantWith(...predicate.Tenant)
}
return privacy.FilterFunc(func(ctx context.Context, f privacy.Filter) error {
view := viewer.FromContext(ctx)
if view.Tenant() == "" {
return privacy.Denyf("missing tenant information in viewer")
}
tf, ok := f.(TenantsFilter)
if !ok {
return privacy.Denyf("unexpected filter type %T", f)
}
// Make sure that a tenant reads only entities that has an edge to it.
tf.WhereHasTenantWith(tenant.Name(view.Tenant()))
// Skip to the next privacy rule (equivalent to return nil).
return privacy.Skip
})
}
// DenyMismatchedTenants is a rule that runs only on create operations and returns a deny
// decision if the operation tries to add users to groups that are not in the same tenant.
func DenyMismatchedTenants() privacy.MutationRule {
return privacy.GroupMutationRuleFunc(func(ctx context.Context, m *ent.GroupMutation) error {
tid, exists := m.TenantID()
if !exists {
return privacy.Denyf("missing tenant information in mutation")
}
users := m.UsersIDs()
// If there are no users in the mutation, skip this rule-check.
if len(users) == 0 {
return privacy.Skip
}
// Query the tenant-id of all users. Expect to have exact 1 result,
// and it matches the tenant-id of the group above.
id, err := m.Client().User.Query().Where(user.IDIn(users...)).QueryTenant().OnlyID(ctx)
if err != nil {
return privacy.Denyf("querying the tenant-id %v", err)
}
if id != tid {
return privacy.Denyf("mismatch tenant-ids for group/users %d != %d", tid, id)
}
// Skip to the next privacy rule (equivalent to return nil).
return privacy.Skip
})
}