@@ -19,28 +19,34 @@ type PreparedAuthorized interface {
19
19
}
20
20
21
21
// Filter takes in a list of objects, and will filter the list removing all
22
- // the elements the subject does not have permission for. All objects must be
23
- // of the same type.
22
+ // the elements the subject does not have permission for. This function slows
23
+ // down if the list contains objects of multiple types. Attempt to only
24
+ // filter objects of the same type for faster performance.
24
25
func Filter [O Objecter ](ctx context.Context , auth Authorizer , subjID string , subjRoles []string , action Action , objects []O ) ([]O , error ) {
25
26
if len (objects ) == 0 {
26
27
// Nothing to filter
27
28
return objects , nil
28
29
}
29
- objectType := objects [0 ].RBACObject ().Type
30
30
31
31
filtered := make ([]O , 0 )
32
- prepared , err := auth .PrepareByRoleName (ctx , subjID , subjRoles , action , objectType )
33
- if err != nil {
34
- return nil , xerrors .Errorf ("prepare: %w" , err )
35
- }
32
+ prepared := make (map [string ]PreparedAuthorized )
36
33
37
34
for i := range objects {
38
35
object := objects [i ]
39
- rbacObj := object .RBACObject ()
40
- if rbacObj .Type != objectType {
41
- return nil , xerrors .Errorf ("object types must be uniform across the set (%s), found %s" , objectType , object .RBACObject ().Type )
36
+ objectType := object .RBACObject ().Type
37
+ // objectAuth is the prepared authorization for the object type.
38
+ objectAuth , ok := prepared [object .RBACObject ().Type ]
39
+ if ! ok {
40
+ var err error
41
+ objectAuth , err = auth .PrepareByRoleName (ctx , subjID , subjRoles , action , objectType )
42
+ if err != nil {
43
+ return nil , xerrors .Errorf ("prepare: %w" , err )
44
+ }
45
+ prepared [objectType ] = objectAuth
42
46
}
43
- err := prepared .Authorize (ctx , rbacObj )
47
+
48
+ rbacObj := object .RBACObject ()
49
+ err := objectAuth .Authorize (ctx , rbacObj )
44
50
if err == nil {
45
51
filtered = append (filtered , object )
46
52
}
0 commit comments