RBAC: Remove user permissions in org when user is removed (#53782)

* RBAC: Add orgID to DeleteUserPermissions

* RBAC: Refactor query to delete all permissions in specified org, 0
deletes all permissions

* Delete user permission in org when user is removed

* Remove call to delete permissions in frontend

* Remove user permissions if removed orgs is detected during oauth sync

Co-authored-by: Jo <joao.guerreiro@grafana.com>
This commit is contained in:
Karl Persson
2022-08-17 16:32:02 +02:00
committed by GitHub
co-authored by Jo
parent 6fe2d4724a
commit 57d87389e0
10 changed files with 140 additions and 45 deletions
+34 -12
View File
@@ -131,20 +131,37 @@ func deletePermissions(sess *sqlstore.DBSession, ids []int64) error {
return nil
}
func (s *AccessControlStore) DeleteUserPermissions(ctx context.Context, userID int64) error {
func (s *AccessControlStore) DeleteUserPermissions(ctx context.Context, orgID, userID int64) error {
err := s.sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
roleDeleteQuery := "DELETE FROM user_role WHERE user_id = ?"
roleDeleteParams := []interface{}{roleDeleteQuery, userID}
if orgID != accesscontrol.GlobalOrgID {
roleDeleteQuery += " AND org_id = ?"
roleDeleteParams = []interface{}{roleDeleteQuery, userID, orgID}
}
// Delete user role assignments
if _, err := sess.Exec("DELETE FROM user_role WHERE user_id = ?", userID); err != nil {
if _, err := sess.Exec(roleDeleteParams...); err != nil {
return err
}
// Delete permissions that are scoped to user
if _, err := sess.Exec("DELETE FROM permission WHERE scope = ?", accesscontrol.Scope("users", "id", strconv.FormatInt(userID, 10))); err != nil {
return err
// only delete scopes to user if all permissions is removed (i.e. user is removed)
if orgID == accesscontrol.GlobalOrgID {
// Delete permissions that are scoped to user
if _, err := sess.Exec("DELETE FROM permission WHERE scope = ?", accesscontrol.Scope("users", "id", strconv.FormatInt(userID, 10))); err != nil {
return err
}
}
roleQuery := "SELECT id FROM role WHERE name = ?"
roleParams := []interface{}{accesscontrol.ManagedUserRoleName(userID)}
if orgID != accesscontrol.GlobalOrgID {
roleQuery += " AND org_id = ?"
roleParams = []interface{}{accesscontrol.ManagedUserRoleName(userID), orgID}
}
var roleIDs []int64
if err := sess.SQL("SELECT id FROM role WHERE name = ?", accesscontrol.ManagedUserRoleName(userID)).Find(&roleIDs); err != nil {
if err := sess.SQL(roleQuery, roleParams...).Find(&roleIDs); err != nil {
return err
}
@@ -152,20 +169,25 @@ func (s *AccessControlStore) DeleteUserPermissions(ctx context.Context, userID i
return nil
}
query := "DELETE FROM permission WHERE role_id IN(? " + strings.Repeat(",?", len(roleIDs)-1) + ")"
args := make([]interface{}, 0, len(roleIDs)+1)
args = append(args, query)
permissionDeleteQuery := "DELETE FROM permission WHERE role_id IN(? " + strings.Repeat(",?", len(roleIDs)-1) + ")"
permissionDeleteParams := make([]interface{}, 0, len(roleIDs)+1)
permissionDeleteParams = append(permissionDeleteParams, permissionDeleteQuery)
for _, id := range roleIDs {
args = append(args, id)
permissionDeleteParams = append(permissionDeleteParams, id)
}
// Delete managed user permissions
if _, err := sess.Exec(args...); err != nil {
if _, err := sess.Exec(permissionDeleteParams...); err != nil {
return err
}
managedRoleDeleteQuery := "DELETE FROM role WHERE id IN(? " + strings.Repeat(",?", len(roleIDs)-1) + ")"
managedRoleDeleteParams := []interface{}{managedRoleDeleteQuery}
for _, id := range roleIDs {
managedRoleDeleteParams = append(managedRoleDeleteParams, id)
}
// Delete managed user roles
if _, err := sess.Exec("DELETE FROM role WHERE name = ?", accesscontrol.ManagedUserRoleName(userID)); err != nil {
if _, err := sess.Exec(managedRoleDeleteParams...); err != nil {
return err
}
@@ -141,28 +141,85 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
}
func TestAccessControlStore_DeleteUserPermissions(t *testing.T) {
store, sql := setupTestEnv(t)
t.Run("expect permissions in all orgs to be deleted", func(t *testing.T) {
store, sql := setupTestEnv(t)
user, _ := createUserAndTeam(t, sql, 1)
user, _ := createUserAndTeam(t, sql, 1)
// generate permissions in org 1
_, err := store.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: user.ID}, types.SetResourcePermissionCommand{
Actions: []string{"dashboards:write"},
Resource: "dashboards",
ResourceID: "1",
}, nil)
require.NoError(t, err)
_, err := store.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: user.ID}, types.SetResourcePermissionCommand{
Actions: []string{"dashboards:write"},
Resource: "dashboards",
ResourceID: "1",
}, nil)
require.NoError(t, err)
// generate permissions in org 2
_, err = store.SetUserResourcePermission(context.Background(), 2, accesscontrol.User{ID: user.ID}, types.SetResourcePermissionCommand{
Actions: []string{"dashboards:write"},
Resource: "dashboards",
ResourceID: "1",
}, nil)
require.NoError(t, err)
err = store.DeleteUserPermissions(context.Background(), user.ID)
require.NoError(t, err)
err = store.DeleteUserPermissions(context.Background(), accesscontrol.GlobalOrgID, user.ID)
require.NoError(t, err)
permissions, err := store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
OrgID: 1,
UserID: user.ID,
Roles: []string{"Admin"},
Actions: []string{"dashboards:write"},
permissions, err := store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
OrgID: 1,
UserID: user.ID,
Roles: []string{"Admin"},
})
require.NoError(t, err)
assert.Len(t, permissions, 0)
permissions, err = store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
OrgID: 2,
UserID: user.ID,
Roles: []string{"Admin"},
})
require.NoError(t, err)
assert.Len(t, permissions, 0)
})
t.Run("expect permissions in org 1 to be deleted", func(t *testing.T) {
store, sql := setupTestEnv(t)
user, _ := createUserAndTeam(t, sql, 1)
// generate permissions in org 1
_, err := store.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: user.ID}, types.SetResourcePermissionCommand{
Actions: []string{"dashboards:write"},
Resource: "dashboards",
ResourceID: "1",
}, nil)
require.NoError(t, err)
// generate permissions in org 2
_, err = store.SetUserResourcePermission(context.Background(), 2, accesscontrol.User{ID: user.ID}, types.SetResourcePermissionCommand{
Actions: []string{"dashboards:write"},
Resource: "dashboards",
ResourceID: "1",
}, nil)
require.NoError(t, err)
err = store.DeleteUserPermissions(context.Background(), 1, user.ID)
require.NoError(t, err)
permissions, err := store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
OrgID: 1,
UserID: user.ID,
Roles: []string{"Admin"},
})
require.NoError(t, err)
assert.Len(t, permissions, 0)
permissions, err = store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
OrgID: 2,
UserID: user.ID,
Roles: []string{"Admin"},
})
require.NoError(t, err)
assert.Len(t, permissions, 1)
})
require.NoError(t, err)
assert.Len(t, permissions, 0)
}
func createUserAndTeam(t *testing.T, sql *sqlstore.SQLStore, orgID int64) (*user.User, models.Team) {