-
Notifications
You must be signed in to change notification settings - Fork 19
/
rule_acl_resolver.go
76 lines (67 loc) · 2.41 KB
/
rule_acl_resolver.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
package lang
import (
"fmt"
"github.com/Aptomi/aptomi/pkg/lang/expression"
"sync"
)
// ACLResolver is a struct which allows to perform ACL resolution, allowing to retrieve user privileges for the
// objects they access
type ACLResolver struct {
rules []*ACLRule
cache *expression.Cache
roleMapCache sync.Map
}
// NewACLResolver creates a new ACLResolver
func NewACLResolver(globalRules *GlobalRules) *ACLResolver {
return &ACLResolver{
rules: globalRules.GetRulesSortedByWeight(),
cache: expression.NewCache(),
roleMapCache: sync.Map{},
}
}
// GetUserPrivileges is a main method which determines privileges that a given user has for a given object
func (resolver *ACLResolver) GetUserPrivileges(user *User, obj Base) (*Privilege, error) {
roleMap, err := resolver.GetUserRoleMap(user)
if err != nil {
return nil, err
}
// figure out which role's privileges apply
for _, role := range ACLRolesOrderedList {
namespaceSpan := roleMap[role.ID]
if namespaceSpan[namespaceAll] || namespaceSpan[obj.GetNamespace()] {
return role.Privileges.getObjectPrivileges(obj), nil
}
}
return nobody.Privileges.getObjectPrivileges(obj), nil
}
// GetUserRoleMap returns the map role ID -> to which namespaces this role applies, for a given user.
// Note that user may have multiple roles at the same time. E.g.
// - domain admin (i.e. for all namespaces within Aptomi domain)
// - namespace admin for a set of given namespaces
// - service consumer for a set of given namespaces
func (resolver *ACLResolver) GetUserRoleMap(user *User) (map[string]map[string]bool, error) {
roleMapCached, ok := resolver.roleMapCache.Load(user.Name)
if ok {
return roleMapCached.(map[string]map[string]bool), nil
}
result := NewRuleActionResult(NewLabelSet(make(map[string]string)))
if user.DomainAdmin {
// this user is explicitly specified as domain admin
result.RoleMap[domainAdmin.ID] = make(map[string]bool)
result.RoleMap[domainAdmin.ID][namespaceAll] = true
} else {
// we need to run this user through ACL list
params := expression.NewParams(user.Labels, nil)
for _, rule := range resolver.rules {
matched, err := rule.Matches(params, resolver.cache)
if err != nil {
return nil, fmt.Errorf("unable to resolve role for user '%s': %s", user.Name, err)
}
if matched {
rule.ApplyActions(result)
}
}
}
resolver.roleMapCache.Store(user.Name, result.RoleMap)
return result.RoleMap, nil
}