this repo has no description
1package rbac
2
3import (
4 "database/sql"
5 "path"
6 "strings"
7
8 sqladapter "github.com/Blank-Xu/sql-adapter"
9 "github.com/casbin/casbin/v2"
10 "github.com/casbin/casbin/v2/model"
11)
12
13const (
14 Model = `
15[request_definition]
16r = sub, dom, obj, act
17
18[policy_definition]
19p = sub, dom, obj, act
20
21[role_definition]
22g = _, _, _
23
24[policy_effect]
25e = some(where (p.eft == allow))
26
27[matchers]
28m = r.act == p.act && r.dom == p.dom && keyMatch2(r.obj, p.obj) && g(r.sub, p.sub, r.dom)
29`
30)
31
32type Enforcer struct {
33 E *casbin.SyncedEnforcer
34}
35
36func keyMatch2(key1 string, key2 string) bool {
37 matched, _ := path.Match(key2, key1)
38 return matched
39}
40
41func NewEnforcer(path string) (*Enforcer, error) {
42 m, err := model.NewModelFromString(Model)
43 if err != nil {
44 return nil, err
45 }
46
47 db, err := sql.Open("sqlite3", path)
48 if err != nil {
49 return nil, err
50 }
51
52 a, err := sqladapter.NewAdapter(db, "sqlite3", "acl")
53 if err != nil {
54 return nil, err
55 }
56
57 e, err := casbin.NewSyncedEnforcer(m, a)
58 if err != nil {
59 return nil, err
60 }
61
62 e.EnableAutoSave(true)
63 e.AddFunction("keyMatch2", keyMatch2Func)
64
65 return &Enforcer{e}, nil
66}
67
68func (e *Enforcer) AddDomain(domain string) error {
69 // Add policies with patterns
70 _, err := e.E.AddPolicies([][]string{
71 {"server:owner", domain, domain, "server:invite"},
72 {"server:member", domain, domain, "repo:create"},
73 })
74 if err != nil {
75 return err
76 }
77
78 // all owners are also members
79 _, err = e.E.AddGroupingPolicy("server:owner", "server:member", domain)
80 return err
81}
82
83func (e *Enforcer) AddOwner(domain, owner string) error {
84 _, err := e.E.AddGroupingPolicy(owner, "server:owner", domain)
85 return err
86}
87
88func (e *Enforcer) AddMember(domain, member string) error {
89 _, err := e.E.AddGroupingPolicy(member, "server:member", domain)
90 return err
91}
92
93func (e *Enforcer) AddRepo(member, domain, repo string) error {
94 _, err := e.E.AddPolicies([][]string{
95 {member, domain, repo, "repo:push"},
96 {member, domain, repo, "repo:owner"},
97 {member, domain, repo, "repo:invite"},
98 {member, domain, repo, "repo:delete"},
99 {"server:owner", domain, repo, "repo:delete"}, // server owner can delete any repo
100 })
101 return err
102}
103
104func (e *Enforcer) GetUserByRole(role, domain string) ([]string, error) {
105 var membersWithoutRoles []string
106
107 // this includes roles too, casbin does not differentiate.
108 // the filtering criteria is to remove strings not starting with `did:`
109 members, err := e.E.Enforcer.GetImplicitUsersForRole(role, domain)
110 for _, m := range members {
111 if strings.HasPrefix(m, "did:") {
112 membersWithoutRoles = append(membersWithoutRoles, m)
113 }
114 }
115 if err != nil {
116 return nil, err
117 }
118
119 return membersWithoutRoles, nil
120}
121
122func (e *Enforcer) isRole(user, role, domain string) (bool, error) {
123 return e.E.HasGroupingPolicy(user, role, domain)
124}
125
126func (e *Enforcer) IsServerOwner(user, domain string) (bool, error) {
127 return e.isRole(user, "server:owner", domain)
128}
129
130func (e *Enforcer) IsServerMember(user, domain string) (bool, error) {
131 return e.isRole(user, "server:member", domain)
132}
133
134func (e *Enforcer) IsPushAllowed(user, domain, repo string) (bool, error) {
135 return e.E.Enforce(user, domain, repo, "repo:push")
136}
137
138// keyMatch2Func is a wrapper for keyMatch2 to make it compatible with Casbin
139func keyMatch2Func(args ...interface{}) (interface{}, error) {
140 name1 := args[0].(string)
141 name2 := args[1].(string)
142
143 return keyMatch2(name1, name2), nil
144}