diff --git a/pkg/services/accesscontrol/mock/permissions_services_mock.go b/pkg/services/accesscontrol/mock/permissions_services_mock.go index 2d3d9d41304..01b545ab997 100644 --- a/pkg/services/accesscontrol/mock/permissions_services_mock.go +++ b/pkg/services/accesscontrol/mock/permissions_services_mock.go @@ -8,32 +8,32 @@ var _ accesscontrol.PermissionsServices = new(PermissionsServicesMock) func NewPermissionsServicesMock() *PermissionsServicesMock { return &PermissionsServicesMock{ - teams: &MockPermissionsService{}, - folders: &MockPermissionsService{}, - dashboards: &MockPermissionsService{}, - datasources: &MockPermissionsService{}, + Teams: &MockPermissionsService{}, + Folders: &MockPermissionsService{}, + Dashboards: &MockPermissionsService{}, + Datasources: &MockPermissionsService{}, } } type PermissionsServicesMock struct { - teams *MockPermissionsService - folders *MockPermissionsService - dashboards *MockPermissionsService - datasources *MockPermissionsService + Teams *MockPermissionsService + Folders *MockPermissionsService + Dashboards *MockPermissionsService + Datasources *MockPermissionsService } func (p PermissionsServicesMock) GetTeamService() accesscontrol.PermissionsService { - return p.teams + return p.Teams } func (p PermissionsServicesMock) GetFolderService() accesscontrol.PermissionsService { - return p.folders + return p.Folders } func (p PermissionsServicesMock) GetDashboardService() accesscontrol.PermissionsService { - return p.dashboards + return p.Dashboards } func (p PermissionsServicesMock) GetDataSourceService() accesscontrol.PermissionsService { - return p.datasources + return p.Datasources } diff --git a/pkg/services/guardian/accesscontrol_guardian.go b/pkg/services/guardian/accesscontrol_guardian.go index 976d11034ea..c68217718a7 100644 --- a/pkg/services/guardian/accesscontrol_guardian.go +++ b/pkg/services/guardian/accesscontrol_guardian.go @@ -203,8 +203,36 @@ func (a *AccessControlDashboardGuardian) GetACLWithoutDuplicates() ([]*models.Da } func (a *AccessControlDashboardGuardian) GetHiddenACL(cfg *setting.Cfg) ([]*models.DashboardAcl, error) { - // not used with access control - return nil, nil + var hiddenACL []*models.DashboardAcl + if a.user.IsGrafanaAdmin { + return hiddenACL, nil + } + + existingPermissions, err := a.GetAcl() + if err != nil { + return hiddenACL, err + } + + for _, item := range existingPermissions { + if item.Inherited || item.UserLogin == a.user.Login { + continue + } + + if _, hidden := cfg.HiddenUsers[item.UserLogin]; hidden { + hiddenACL = append(hiddenACL, &models.DashboardAcl{ + OrgID: item.OrgId, + DashboardID: item.DashboardId, + UserID: item.UserId, + TeamID: item.TeamId, + Role: item.Role, + Permission: item.Permission, + Created: item.Created, + Updated: item.Updated, + }) + } + } + + return hiddenACL, nil } func (a *AccessControlDashboardGuardian) loadDashboard() error { diff --git a/pkg/services/guardian/accesscontrol_guardian_test.go b/pkg/services/guardian/accesscontrol_guardian_test.go index 65a69e07242..8b42047ff86 100644 --- a/pkg/services/guardian/accesscontrol_guardian_test.go +++ b/pkg/services/guardian/accesscontrol_guardian_test.go @@ -2,8 +2,11 @@ package guardian import ( "context" + "fmt" "testing" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -537,6 +540,54 @@ func TestAccessControlDashboardGuardian_CanCreate(t *testing.T) { } } +type accessControlGuardianGetHiddenACLTestCase struct { + desc string + permissions []accesscontrol.ResourcePermission + hiddenUsers map[string]struct{} +} + +func TestAccessControlDashboardGuardian_GetHiddenACL(t *testing.T) { + tests := []accessControlGuardianGetHiddenACLTestCase{ + { + desc: "should only return permissions containing hidden users", + permissions: []accesscontrol.ResourcePermission{ + {RoleName: "managed:users:1:permissions", UserId: 1, UserLogin: "user1"}, + {RoleName: "managed:teams:1:permissions", TeamId: 1, Team: "team1"}, + {RoleName: "managed:users:2:permissions", UserId: 2, UserLogin: "user2"}, + {RoleName: "managed:users:3:permissions", UserId: 3, UserLogin: "user3"}, + {RoleName: "managed:users:4:permissions", UserId: 4, UserLogin: "user4"}, + }, + hiddenUsers: map[string]struct{}{"user2": {}, "user3": {}}, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + guardian := setupAccessControlGuardianTest(t, 1, nil) + guardian.permissionServices.GetDashboardService() + + mocked := accesscontrolmock.NewPermissionsServicesMock() + guardian.permissionServices = mocked + mocked.Dashboards.On("MapActions", mock.Anything).Return("View") + mocked.Dashboards.On("GetPermissions", mock.Anything, mock.Anything, mock.Anything).Return(tt.permissions, nil) + + cfg := setting.NewCfg() + cfg.HiddenUsers = tt.hiddenUsers + + permissions, err := guardian.GetHiddenACL(cfg) + require.NoError(t, err) + var hiddenUserNames []string + for name := range tt.hiddenUsers { + hiddenUserNames = append(hiddenUserNames, name) + } + assert.Len(t, permissions, len(hiddenUserNames)) + for _, p := range permissions { + assert.Contains(t, hiddenUserNames, fmt.Sprintf("user%d", p.UserID)) + } + }) + } +} + func setupAccessControlGuardianTest(t *testing.T, dashID int64, permissions []*accesscontrol.Permission) *AccessControlDashboardGuardian { t.Helper() store := sqlstore.InitTestDB(t)