fix(09): WR-17 merge an admin's own permissions over the role's, honouring denies
This commit is contained in:
@@ -61,9 +61,44 @@ func (p BackendUsers) FindByID(ctx context.Context, id uint) (*bouncer.Principal
|
||||
}
|
||||
principal.PermissionGrants[code] = true
|
||||
}
|
||||
// The administrator's own permissions are applied last, over the role's
|
||||
// and the code-declared role grants, as Winter's getMergedPermissions does.
|
||||
principal.PermissionGrants = applyUserPermissions(principal.PermissionGrants, user.Permissions)
|
||||
return principal, nil
|
||||
}
|
||||
|
||||
// applyUserPermissions overlays an administrator's own backend_users.permissions
|
||||
// onto the grants that come from the role, the way Winter's
|
||||
// User::getMergedPermissions does: the user's value for a code replaces the
|
||||
// role's, and only a value of 1 grants. A user-level -1 (or 0) therefore removes
|
||||
// a permission the role grants, and a user-level 1 adds one the role does not.
|
||||
// Winter compares codes exactly while merging, so a deny of one code never
|
||||
// removes a wildcard grant such as "acme.*"; it removes that exact code.
|
||||
func applyUserPermissions(grants map[string]bool, raw string) map[string]bool {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" || raw == "{}" || raw == "null" {
|
||||
return grants
|
||||
}
|
||||
var decoded map[string]any
|
||||
if err := json.Unmarshal([]byte(raw), &decoded); err != nil {
|
||||
return grants
|
||||
}
|
||||
for code, value := range decoded {
|
||||
if truthyGrant(value) {
|
||||
if grants == nil {
|
||||
grants = map[string]bool{}
|
||||
}
|
||||
grants[code] = true
|
||||
continue
|
||||
}
|
||||
delete(grants, code)
|
||||
}
|
||||
if len(grants) == 0 {
|
||||
return nil
|
||||
}
|
||||
return grants
|
||||
}
|
||||
|
||||
func principalFrom(user BackendUser) *bouncer.Principal {
|
||||
principal := &bouncer.Principal{
|
||||
ID: user.ID,
|
||||
|
||||
Reference in New Issue
Block a user