forked from pydio/cells
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bitmask.go
134 lines (120 loc) · 3.51 KB
/
bitmask.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
125
126
127
128
129
130
131
132
133
134
package permissions
import (
"context"
"fmt"
"github.com/pydio/cells/common"
"github.com/pydio/cells/common/log"
"github.com/pydio/cells/common/proto/idm"
"github.com/pydio/cells/common/proto/tree"
"go.uber.org/zap"
)
type BitmaskFlag uint32
const (
FlagRead BitmaskFlag = 1 << iota
FlagWrite
FlagDeny
FlagList
FlagDelete
FlagPolicy
FlagQuota
FlagLock
)
var (
NamesToFlags = map[string]BitmaskFlag{
"read": FlagRead,
"write": FlagWrite,
"deny": FlagDeny,
"list": FlagList,
"delete": FlagDelete,
"policy": FlagPolicy,
"quota": FlagQuota,
"lock": FlagLock,
}
FlagsToNames = map[BitmaskFlag]string{
FlagRead: "read",
FlagWrite: "write",
FlagDeny: "deny",
FlagList: "list",
FlagDelete: "delete",
FlagPolicy: "policy",
FlagQuota: "quota",
FlagLock: "lock",
}
)
type Bitmask struct {
BitmaskFlag
PolicyIds map[string]string
ValueFlags map[BitmaskFlag]string
}
func (f Bitmask) checkPolicy(ctx context.Context, initialMeta map[string]string, subjects []string, action string, ctxNode *tree.Node) bool {
policyContext := make(map[string]string, len(initialMeta))
for k, v := range initialMeta {
policyContext[k] = v
}
if ctxNode != nil {
PolicyContextFromNode(policyContext, ctxNode)
}
req := &idm.PolicyEngineRequest{
Subjects: subjects,
Resource: "acl",
Action: action,
Context: policyContext,
}
if resp, err := ResolvePolicyRequest(ctx, req); err == nil && resp.Allowed {
log.Logger(ctx).Debug("Policy Allowed", zap.Any("req", req))
return true
} else {
log.Logger(ctx).Debug("Policy Not Allowed", zap.Any("req", req))
return false
}
}
// HasFlag checks if current bitmask matches a given flag. If bitmask has a Policy Flag, it will
// extract metadata from context and from nodes and use the PolicyResolver to dynamically test these properties.
func (f Bitmask) HasFlag(ctx context.Context, flag BitmaskFlag, ctxNodes ...*tree.Node) bool {
if flag != FlagPolicy && flag != FlagDeny && f.BitmaskFlag&FlagPolicy != 0 && ResolvePolicyRequest != nil {
// We should first resolve the policy, given the ctx and the node
policyContext := make(map[string]string)
PolicyContextFromMetadata(policyContext, ctx)
var subjects []string
for k, _ := range f.PolicyIds {
subjects = append(subjects, fmt.Sprintf("policy:%s", k))
}
if len(ctxNodes) == 0 {
return f.checkPolicy(ctx, policyContext, subjects, FlagsToNames[flag], nil)
}
// Check all parents, break if check is false (not allowed).
for _, ctxNode := range ctxNodes {
polNode := ctxNode
if ctxNode.GetPath() == "" || ctxNode.GetPath() == "/" { // Do not try to check nodes meta on root
polNode = nil
policyContext[PolicyNodeMeta_+common.MetaFlagWorkspaceRoot] = "true"
}
if c := f.checkPolicy(ctx, policyContext, subjects, FlagsToNames[flag], polNode); !c {
log.Logger(ctx).Debug("Found forbidden access on node", ctxNode.ZapPath())
return false
}
}
return true
}
return f.BitmaskFlag&flag != 0
}
// AddFlag adds a simple flag.
func (f *Bitmask) AddFlag(flag BitmaskFlag) {
f.BitmaskFlag |= flag
}
// AddPolicyFlag adds a policy flag and stacks policies.
func (f *Bitmask) AddPolicyFlag(policyId string) {
f.AddFlag(FlagPolicy)
if f.PolicyIds == nil {
f.PolicyIds = make(map[string]string)
}
f.PolicyIds[policyId] = policyId
}
// AddValueFlag stores the value of a BitmaskFlag.
func (f *Bitmask) AddValueFlag(flag BitmaskFlag, value string) {
f.AddFlag(flag)
if f.ValueFlags == nil {
f.ValueFlags = make(map[BitmaskFlag]string)
}
f.ValueFlags[flag] = value
}