forked from euforia/ladon
-
Notifications
You must be signed in to change notification settings - Fork 1
/
manager_rdb.go
142 lines (121 loc) · 3.24 KB
/
manager_rdb.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
package rdb
import (
"fmt"
. "github.com/d3sw/ladon"
"github.com/pkg/errors"
r "gopkg.in/gorethink/gorethink.v3"
)
// RdbManager is a rethinkdb implementation of Manager to store policies persistently.
type RdbManager struct {
session *r.Session
table r.Term
s SchemaManager
}
// NewRdbManager initializes a new RdbManager for given session.
func NewRdbManager(session *r.Session, table string, s SchemaManager) *RdbManager {
return &RdbManager{
session: session,
table: r.Table(table),
s: s,
}
}
// Create inserts a new policy.
func (m *RdbManager) Create(policy Policy) error {
s := m.s.NewSchema()
s.PopulateWithPolicy(policy)
if _, err := m.table.Insert(s).RunWrite(m.session); err != nil {
return errors.WithStack(err)
}
return nil
}
// Update updates an existing policy.
func (m *RdbManager) Update(policy Policy) error {
s := m.s.NewSchema()
s.PopulateWithPolicy(policy)
if _, err := m.table.Get(s.GetID()).Update(s).RunWrite(m.session); err != nil {
return errors.WithStack(err)
}
return nil
}
// Get retrieves a policy.
func (m *RdbManager) Get(id string) (Policy, error) {
res, err := m.table.Get(id).Run(m.session)
if err != nil {
return nil, errors.WithStack(err)
}
defer res.Close()
for v := range m.s.ProcessResult(res) {
if v.Err != nil {
return nil, v.Err
}
p, err := v.Schema.GetPolicy()
if err != nil {
return nil, err
}
return p, err
}
return nil, fmt.Errorf("failed to find policy %s", id)
}
// Delete removes a policy.
func (m *RdbManager) Delete(id string) error {
if _, err := m.table.Get(id).Delete().RunWrite(m.session); err != nil {
return errors.WithStack(err)
}
return nil
}
// GetAll returns all policies.
func (m *RdbManager) GetAll(limit, offset int64) (Policies, error) {
res, err := m.table.Skip(offset).Limit(limit).Run(m.session)
if err != nil {
return nil, errors.WithStack(err)
}
defer res.Close()
var policies Policies
for s := range m.s.ProcessResult(res) {
if s.Err != nil {
return nil, s.Err
}
p, err := s.Schema.GetPolicy()
if err != nil {
return policies, errors.WithStack(err)
}
policies = append(policies, p)
}
if err := res.Err(); err != nil {
return nil, err
}
return policies, nil
}
type FilterFunc func(t r.Term) r.Term
// FindRequestCandidates returns candidates that could match the request object. It either returns
// a set that exactly matches the request, or a superset of it. If an error occurs, it returns nil and
// the error.
func (m *RdbManager) FindRequestCandidates(req *Request) (Policies, error) {
mp := map[string]bool{}
var policies Policies
if err := req.Validate(); err != nil {
return nil, errors.WithStack(err)
}
for _, s := range req.Subjects {
res, err := m.s.GetRequestCandidatesTerm(m.table, s, req.Resource, req.Action).Run(m.session)
if err != nil {
return nil, err
}
for v := range m.s.ProcessResult(res) {
if v.Err != nil {
return nil, errors.WithStack(v.Err)
}
if _, ok := mp[v.Schema.GetID()]; !ok {
p, err := v.Schema.GetPolicy()
if err != nil {
return nil, errors.WithStack(err)
}
mp[v.Schema.GetID()] = true
policies = append(policies, p)
}
}
// This call isn't deferred to prevent leaks in loop
res.Close()
}
return policies, nil
}