1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package auth
16
17 import (
18 "go.etcd.io/etcd/api/v3/authpb"
19 "go.etcd.io/etcd/pkg/v3/adt"
20 "go.etcd.io/etcd/server/v3/mvcc/backend"
21
22 "go.uber.org/zap"
23 )
24
25 func getMergedPerms(lg *zap.Logger, tx backend.ReadTx, userName string) *unifiedRangePermissions {
26 user := getUser(lg, tx, userName)
27 if user == nil {
28 return nil
29 }
30
31 readPerms := adt.NewIntervalTree()
32 writePerms := adt.NewIntervalTree()
33
34 for _, roleName := range user.Roles {
35 role := getRole(lg, tx, roleName)
36 if role == nil {
37 continue
38 }
39
40 for _, perm := range role.KeyPermission {
41 var ivl adt.Interval
42 var rangeEnd []byte
43
44 if len(perm.RangeEnd) != 1 || perm.RangeEnd[0] != 0 {
45 rangeEnd = perm.RangeEnd
46 }
47
48 if len(perm.RangeEnd) != 0 {
49 ivl = adt.NewBytesAffineInterval(perm.Key, rangeEnd)
50 } else {
51 ivl = adt.NewBytesAffinePoint(perm.Key)
52 }
53
54 switch perm.PermType {
55 case authpb.READWRITE:
56 readPerms.Insert(ivl, struct{}{})
57 writePerms.Insert(ivl, struct{}{})
58
59 case authpb.READ:
60 readPerms.Insert(ivl, struct{}{})
61
62 case authpb.WRITE:
63 writePerms.Insert(ivl, struct{}{})
64 }
65 }
66 }
67
68 return &unifiedRangePermissions{
69 readPerms: readPerms,
70 writePerms: writePerms,
71 }
72 }
73
74 func checkKeyInterval(
75 lg *zap.Logger,
76 cachedPerms *unifiedRangePermissions,
77 key, rangeEnd []byte,
78 permtyp authpb.Permission_Type) bool {
79 if isOpenEnded(rangeEnd) {
80 rangeEnd = nil
81
82
83 }
84
85 ivl := adt.NewBytesAffineInterval(key, rangeEnd)
86 switch permtyp {
87 case authpb.READ:
88 return cachedPerms.readPerms.Contains(ivl)
89 case authpb.WRITE:
90 return cachedPerms.writePerms.Contains(ivl)
91 default:
92 lg.Panic("unknown auth type", zap.String("auth-type", permtyp.String()))
93 }
94 return false
95 }
96
97 func checkKeyPoint(lg *zap.Logger, cachedPerms *unifiedRangePermissions, key []byte, permtyp authpb.Permission_Type) bool {
98 pt := adt.NewBytesAffinePoint(key)
99 switch permtyp {
100 case authpb.READ:
101 return cachedPerms.readPerms.Intersects(pt)
102 case authpb.WRITE:
103 return cachedPerms.writePerms.Intersects(pt)
104 default:
105 lg.Panic("unknown auth type", zap.String("auth-type", permtyp.String()))
106 }
107 return false
108 }
109
110 func (as *authStore) isRangeOpPermitted(userName string, key, rangeEnd []byte, permtyp authpb.Permission_Type) bool {
111 as.rangePermCacheMu.RLock()
112 defer as.rangePermCacheMu.RUnlock()
113
114 rangePerm, ok := as.rangePermCache[userName]
115 if !ok {
116 as.lg.Error(
117 "user doesn't exist",
118 zap.String("user-name", userName),
119 )
120 return false
121 }
122
123 if len(rangeEnd) == 0 {
124 return checkKeyPoint(as.lg, rangePerm, key, permtyp)
125 }
126
127 return checkKeyInterval(as.lg, rangePerm, key, rangeEnd, permtyp)
128 }
129
130 func (as *authStore) refreshRangePermCache(tx backend.ReadTx) {
131
132
133
134 as.rangePermCacheMu.Lock()
135 defer as.rangePermCacheMu.Unlock()
136
137 as.rangePermCache = make(map[string]*unifiedRangePermissions)
138
139 users := getAllUsers(as.lg, tx)
140 for _, user := range users {
141 userName := string(user.Name)
142 perms := getMergedPerms(as.lg, tx, userName)
143 if perms == nil {
144 as.lg.Error(
145 "failed to create a merged permission",
146 zap.String("user-name", userName),
147 )
148 continue
149 }
150 as.rangePermCache[userName] = perms
151 }
152 }
153
154 type unifiedRangePermissions struct {
155 readPerms adt.IntervalTree
156 writePerms adt.IntervalTree
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182 func isOpenEnded(rangeEnd []byte) bool {
183 return len(rangeEnd) == 1 && rangeEnd[0] == 0
184 }
185
186 func isValidPermissionRange(key, rangeEnd []byte) bool {
187 if len(key) == 0 {
188 return false
189 }
190 if rangeEnd == nil || len(rangeEnd) == 0 {
191 return true
192 }
193
194 begin := adt.BytesAffineComparable(key)
195 end := adt.BytesAffineComparable(rangeEnd)
196 if begin.Compare(end) == -1 {
197 return true
198 }
199
200 if isOpenEnded(rangeEnd) {
201 return true
202 }
203
204 return false
205 }
206
View as plain text