@@ -19,6 +19,14 @@ import (
19
19
"gopkg.in/macaroon.v2"
20
20
)
21
21
22
+ // readOnlyAction defines the keyword that a permission action should be set to
23
+ // when the entity is set to "uri" in order to activate the special case that
24
+ // will result in all read-only permissions known to lit to be added to a
25
+ // session's macaroon. The purpose of the three '*'s is to make this keyword
26
+ // an invalid URI and an invalid regex so that it does not ever clash with the
27
+ // other special cases.
28
+ const readOnlyAction = "***readonly***"
29
+
22
30
// sessionRpcServer is the gRPC server for the Session RPC interface.
23
31
type sessionRpcServer struct {
24
32
litrpc.UnimplementedSessionsServer
@@ -126,7 +134,21 @@ func (s *sessionRpcServer) AddSession(_ context.Context,
126
134
return nil , err
127
135
}
128
136
129
- var permissions []bakery.Op
137
+ // Store the entity-action permission pairs in a map in order to
138
+ // de-dup any repeat perms.
139
+ permissions := make (map [string ]map [string ]struct {})
140
+
141
+ // addPerm is a closure that can be used to add entity-action pairs to
142
+ // the permissions map.
143
+ addPerm := func (entity , action string ) {
144
+ _ , ok := permissions [entity ]
145
+ if ! ok {
146
+ permissions [entity ] = make (map [string ]struct {})
147
+ }
148
+
149
+ permissions [entity ][action ] = struct {}{}
150
+ }
151
+
130
152
switch typ {
131
153
// For the default session types we use empty caveats and permissions,
132
154
// the macaroons are baked correctly when creating the session.
@@ -144,10 +166,23 @@ func (s *sessionRpcServer) AddSession(_ context.Context,
144
166
145
167
for _ , op := range req .MacaroonCustomPermissions {
146
168
if op .Entity != macaroons .PermissionEntityCustomURI {
147
- permissions = append (permissions , bakery.Op {
148
- Entity : op .Entity ,
149
- Action : op .Action ,
150
- })
169
+ addPerm (op .Entity , op .Action )
170
+
171
+ continue
172
+ }
173
+
174
+ // If the action specified was equal to the
175
+ // readOnlyAction keyword, then this is taken to mean
176
+ // that the permissions for all read-only URIs should be
177
+ // granted.
178
+ if op .Action == readOnlyAction {
179
+ readPerms := s .cfg .permMgr .ActivePermissions (
180
+ true ,
181
+ )
182
+
183
+ for _ , p := range readPerms {
184
+ addPerm (p .Entity , p .Action )
185
+ }
151
186
152
187
continue
153
188
}
@@ -159,12 +194,7 @@ func (s *sessionRpcServer) AddSession(_ context.Context,
159
194
// the matching URIs returned from the
160
195
// permissions' manager.
161
196
for _ , uri := range uris {
162
- permissions = append (
163
- permissions , bakery.Op {
164
- Entity : op .Entity ,
165
- Action : uri ,
166
- },
167
- )
197
+ addPerm (op .Entity , uri )
168
198
}
169
199
continue
170
200
}
@@ -177,10 +207,7 @@ func (s *sessionRpcServer) AddSession(_ context.Context,
177
207
"LiT" , op .Action )
178
208
}
179
209
180
- permissions = append (permissions , bakery.Op {
181
- Entity : op .Entity ,
182
- Action : op .Action ,
183
- })
210
+ addPerm (op .Entity , op .Action )
184
211
}
185
212
186
213
// No other types are currently supported.
@@ -189,9 +216,20 @@ func (s *sessionRpcServer) AddSession(_ context.Context,
189
216
"readonly and custom macaroon types supported in LiT" )
190
217
}
191
218
219
+ // Collect the de-duped permissions.
220
+ var perms []bakery.Op
221
+ for entity , actions := range permissions {
222
+ for action := range actions {
223
+ perms = append (perms , bakery.Op {
224
+ Entity : entity ,
225
+ Action : action ,
226
+ })
227
+ }
228
+ }
229
+
192
230
sess , err := session .NewSession (
193
231
req .Label , typ , expiry , req .MailboxServerAddr , req .DevServer ,
194
- permissions , nil ,
232
+ perms , nil ,
195
233
)
196
234
if err != nil {
197
235
return nil , fmt .Errorf ("error creating new session: %v" , err )
0 commit comments