Skip to content

Commit

Permalink
lxd: Improves efficiency of operation cancel with permission checker.
Browse files Browse the repository at this point in the history
Previously, each url was checked with `(Authorizer).CheckPermission`.
With the fine-grained authorization driver this may use more database
calls than is necessary. This commit refactors the permission check to
use a permission checker instead, if there are multiple entities of a
given type. (See similar logic in `lxd/project.FilterUsedBy`).

Signed-off-by: Mark Laing <mark.laing@canonical.com>
  • Loading branch information
markylaing committed Mar 15, 2024
1 parent 4f3af9a commit 767b342
Showing 1 changed file with 32 additions and 2 deletions.
34 changes: 32 additions & 2 deletions lxd/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,44 @@ func operationDelete(d *Daemon, r *http.Request) response.Response {
projectName = api.ProjectDefaultName
}

// Separate resources by entity type. If there are multiple entries of a particular entity type we can reduce
// the number of calls to the authorizer.
objectType, entitlement := op.Permission()
urlsByEntityType := make(map[entity.Type][]api.URL)
if objectType != "" {
for _, v := range op.Resources() {
for _, u := range v {
err = s.Authorizer.CheckPermission(r.Context(), r, &u, entitlement)
entityType, _, _, _, err := entity.ParseURL(u.URL)
if err != nil {
return response.SmartError(err)
return response.InternalError(fmt.Errorf("Failed to parse operation resource entity URL: %w", err))
}

urlsByEntityType[entityType] = append(urlsByEntityType[entityType], u)
}
}
}

for entityType, urls := range urlsByEntityType {
// If only one entry of this type, check directly.
if len(urls) == 1 {
err := s.Authorizer.CheckPermission(r.Context(), r, &urls[0], entitlement)
if err != nil {
return response.SmartError(err)
}

continue
}

// Otherwise get a permission checker for the entity type.
hasPermission, err := s.Authorizer.GetPermissionChecker(r.Context(), r, entitlement, entityType)
if err != nil {
return response.SmartError(err)
}

// Check each URL.
for _, u := range urls {
if !hasPermission(&u) {
return response.Forbidden(nil)
}
}
}
Expand Down

0 comments on commit 767b342

Please sign in to comment.