mirror of
https://github.com/grafana/grafana.git
synced 2026-08-16 16:14:59 -05:00
RBAC: Add a function to delete external service roles (#68317)
* RBAC: Add function to delete external service roles * Adding a test to the service * Update pkg/services/accesscontrol/acimpl/service_test.go Co-authored-by: Ieva <ieva.vasiljeva@grafana.com> --------- Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
@@ -10,6 +10,52 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
)
|
||||
|
||||
func extServiceRoleUID(externalServiceID string) string {
|
||||
uid := fmt.Sprintf("%s%s_permissions", accesscontrol.ExternalServiceRoleUIDPrefix, externalServiceID)
|
||||
return uid
|
||||
}
|
||||
|
||||
func extServiceRoleName(externalServiceID string) string {
|
||||
name := fmt.Sprintf("%s%s:permissions", accesscontrol.ExternalServiceRolePrefix, externalServiceID)
|
||||
return name
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) DeleteExternalServiceRole(ctx context.Context, externalServiceID string) error {
|
||||
uid := extServiceRoleUID(externalServiceID)
|
||||
|
||||
return s.sql.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
stored, errGet := getRoleByUID(ctx, sess, uid)
|
||||
if errGet != nil {
|
||||
// Role not found, nothing to do
|
||||
if errors.Is(errGet, accesscontrol.ErrRoleNotFound) {
|
||||
return nil
|
||||
}
|
||||
return errGet
|
||||
}
|
||||
|
||||
// Delete the assignments
|
||||
_, errDel := sess.Exec("DELETE FROM user_role WHERE role_id = ?", stored.ID)
|
||||
if errDel != nil {
|
||||
return errDel
|
||||
}
|
||||
// Shouldn't happen but just in case delete any team assignments
|
||||
_, errDel = sess.Exec("DELETE FROM team_role WHERE role_id = ?", stored.ID)
|
||||
if errDel != nil {
|
||||
return errDel
|
||||
}
|
||||
|
||||
// Delete the permissions
|
||||
_, errDel = sess.Exec("DELETE FROM permission WHERE role_id = ?", stored.ID)
|
||||
if errDel != nil {
|
||||
return errDel
|
||||
}
|
||||
|
||||
// Delete the role
|
||||
_, errDel = sess.Exec("DELETE FROM role WHERE id = ?", stored.ID)
|
||||
return errDel
|
||||
})
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) SaveExternalServiceRole(ctx context.Context, cmd accesscontrol.SaveExternalServiceRoleCommand) error {
|
||||
role := genExternalServiceRole(cmd)
|
||||
assignment := genExternalServiceAssignment(cmd)
|
||||
@@ -39,8 +85,8 @@ func genExternalServiceRole(cmd accesscontrol.SaveExternalServiceRoleCommand) ac
|
||||
role := accesscontrol.Role{
|
||||
OrgID: cmd.OrgID,
|
||||
Version: 1,
|
||||
Name: fmt.Sprintf("%s%s:permissions", accesscontrol.ExternalServiceRolePrefix, cmd.ExternalServiceID),
|
||||
UID: fmt.Sprintf("%s%s_permissions", accesscontrol.ExternalServiceRoleUIDPrefix, cmd.ExternalServiceID),
|
||||
Name: extServiceRoleName(cmd.ExternalServiceID),
|
||||
UID: extServiceRoleUID(cmd.ExternalServiceID),
|
||||
DisplayName: fmt.Sprintf("External Service %s Permissions", cmd.ExternalServiceID),
|
||||
Description: fmt.Sprintf("External Service %s permissions", cmd.ExternalServiceID),
|
||||
Group: "External Service",
|
||||
|
||||
@@ -2,6 +2,7 @@ package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
@@ -189,3 +190,113 @@ func TestAccessControlStore_SaveExternalServiceRole(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccessControlStore_DeleteExternalServiceRole(t *testing.T) {
|
||||
extID := "app1"
|
||||
tests := []struct {
|
||||
name string
|
||||
init func(t *testing.T, ctx context.Context, s *AccessControlStore)
|
||||
id string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "delete no role",
|
||||
id: extID,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "delete local role",
|
||||
init: func(t *testing.T, ctx context.Context, s *AccessControlStore) {
|
||||
errSave := s.SaveExternalServiceRole(ctx, accesscontrol.SaveExternalServiceRoleCommand{
|
||||
OrgID: 2,
|
||||
ExternalServiceID: extID,
|
||||
ServiceAccountID: 3,
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{Action: "users:read", Scope: "users:id:1"},
|
||||
{Action: "users:write", Scope: "users:id:1"},
|
||||
},
|
||||
})
|
||||
require.NoError(t, errSave)
|
||||
},
|
||||
id: extID,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "delete global role",
|
||||
init: func(t *testing.T, ctx context.Context, s *AccessControlStore) {
|
||||
errSave := s.SaveExternalServiceRole(ctx, accesscontrol.SaveExternalServiceRoleCommand{
|
||||
Global: true,
|
||||
ExternalServiceID: extID,
|
||||
ServiceAccountID: 3,
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{Action: "users:read", Scope: "users:id:1"},
|
||||
{Action: "users:write", Scope: "users:id:1"},
|
||||
},
|
||||
})
|
||||
require.NoError(t, errSave)
|
||||
},
|
||||
id: extID,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s := &AccessControlStore{
|
||||
sql: db.InitTestDB(t),
|
||||
}
|
||||
if tt.init != nil {
|
||||
tt.init(t, ctx, s)
|
||||
}
|
||||
roleID := int64(-1)
|
||||
err := s.sql.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
role, err := getRoleByUID(ctx, sess, extServiceRoleUID(tt.id))
|
||||
if err != nil && !errors.Is(err, accesscontrol.ErrRoleNotFound) {
|
||||
return err
|
||||
}
|
||||
if role != nil {
|
||||
roleID = role.ID
|
||||
}
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = s.DeleteExternalServiceRole(ctx, tt.id)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Only check removal if the role existed before
|
||||
if roleID == -1 {
|
||||
return
|
||||
}
|
||||
|
||||
// Assignments should be deleted
|
||||
_ = s.sql.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
var assignment accesscontrol.UserRole
|
||||
count, err := sess.Where("role_id = ?", roleID).Count(&assignment)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, count)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Permissions should be deleted
|
||||
_ = s.sql.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
var permission accesscontrol.Permission
|
||||
count, err := sess.Where("role_id = ?", roleID).Count(&permission)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, count)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Role should be deleted
|
||||
_ = s.sql.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
storedRole, err := getRoleByUID(ctx, sess, extServiceRoleUID(tt.id))
|
||||
require.ErrorIs(t, err, accesscontrol.ErrRoleNotFound)
|
||||
require.Nil(t, storedRole)
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user