forked from mikespook/gorbac
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrbac.go
157 lines (137 loc) · 3.79 KB
/
rbac.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
goRBAC provides a lightweight role-based access control implementation
in Golang.
For the purposes of this package:
* an identity has one or more roles.
* a role requests access to a permission.
* a permission is given to a role.
Thus, RBAC has the following model:
* many to many relationship between identities and roles.
* many to many relationship between roles and permissions.
* roles can have parent roles.
*/
package gorbac
import (
"strconv"
"sync"
)
const (
bufferSize = 16
)
// Assertion function supplies more fine-grained permission controls.
type AssertionFunc func(string, string, *Rbac) bool
// Export RBAC to a structure data
type Map map[string]RoleMap
// RBAC
type Rbac struct {
mutex sync.RWMutex
roles map[string]Role
factory RoleFactoryFunc
}
// Return a RBAC structure with a specific factory function.
// Role structure will be generated by the function.
func NewWithFactory(factory RoleFactoryFunc) *Rbac {
rbac := &Rbac{
roles: make(map[string]Role, bufferSize),
factory: factory,
}
return rbac
}
// Return a RBAC structure.
// The default role structure will be used.
func New() *Rbac {
return NewWithFactory(newBaseRole)
}
// Restore rbac from a map, use factory for your own data structure
func RestoreWithFactory(data Map, factory RoleFactoryFunc) *Rbac {
rbac := NewWithFactory(factory)
for role, value := range data {
rbac.Add(value[RankKey].(int), role, value[PermissionKey].([]string), value[ParentKey].([]string), value[DescriptionKey].(string))
}
return rbac
}
// Restore rbac from a map, a default role implamentation used
func Restore(data Map) *Rbac {
return RestoreWithFactory(data, newBaseRole)
}
// Set a role with `name`. It has `permissions` and `parents`.
// If the role is not existing, a new one will be created.
// This function will cover role's orignal permissions and parents.
func (rbac *Rbac) Set(rank int, name string, permissions, parents []string, description string) {
rbac.mutex.Lock()
defer rbac.mutex.Unlock()
role := rbac.getRole(name)
role.Reset()
role.AddRank(rank)
role.AddDescription(description)
for _, p := range permissions {
role.AddPermission(p)
}
for _, pname := range parents {
role.AddParent(pname)
}
}
// Add a role with `name`. It has `permissions` and `parents`.
// If the role is not existing, a new one will be created.
// This function will add new permissions and parents to the role,
// and keep orignals.
func (rbac *Rbac) Add(rank int, name string, permissions, parents []string, description string) {
rbac.mutex.Lock()
defer rbac.mutex.Unlock()
role := rbac.getRole(name)
role.AddRank(rank)
role.AddDescription(description)
for _, p := range permissions {
role.AddPermission(p)
}
for _, pname := range parents {
role.AddParent(pname)
}
}
// Remove a role.
func (rbac *Rbac) Remove(name string) {
rbac.mutex.Lock()
defer rbac.mutex.Unlock()
delete(rbac.roles, name)
}
// Internal getRole
func (rbac *Rbac) getRole(name string) Role {
role, ok := rbac.roles[name]
if !ok {
role = rbac.factory(rbac, name)
rbac.roles[name] = role
}
return role
}
// Return a role or nil if not exists.
func (rbac *Rbac) Get(name string) Role {
rbac.mutex.RLock()
defer rbac.mutex.RUnlock()
role, ok := rbac.roles[name]
if !ok {
return nil
}
return role
}
// Test if the `name` has `permission` in the `assert` condition.
func (rbac *Rbac) IsGranted(name, permission string,
assert AssertionFunc) bool {
rbac.mutex.RLock()
defer rbac.mutex.RUnlock()
if assert != nil && !assert(name, permission, rbac) {
return false
}
if role, ok := rbac.roles[name]; ok {
return role.HasPermission(permission)
}
return false
}
// Dump RBAC
func (rbac *Rbac) Dump() Map {
m := make(Map)
for _, role := range rbac.roles {
roleMap := RoleToMap(role)
m[strconv.Itoa(role.Rank())+role.Name()] = roleMap
}
return m
}