diff --git a/pkg/api/dashboard_permission.go b/pkg/api/dashboard_permission.go index f609bd65857..0b35ec0cc92 100644 --- a/pkg/api/dashboard_permission.go +++ b/pkg/api/dashboard_permission.go @@ -24,7 +24,7 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) response. return dashboardGuardianResponse(err) } - acl, err := g.GetAcl() + acl, err := g.GetACLWithoutDuplicates() if err != nil { return response.Error(500, "Failed to get dashboard permissions", err) } diff --git a/pkg/services/guardian/guardian.go b/pkg/services/guardian/guardian.go index 1f9fe85d3eb..91f6868bb57 100644 --- a/pkg/services/guardian/guardian.go +++ b/pkg/services/guardian/guardian.go @@ -22,7 +22,14 @@ type DashboardGuardian interface { CanAdmin() (bool, error) HasPermission(permission models.PermissionType) (bool, error) CheckPermissionBeforeUpdate(permission models.PermissionType, updatePermissions []*models.DashboardAcl) (bool, error) + + // GetAcl returns ACL. GetAcl() ([]*models.DashboardAclInfoDTO, error) + + // GetACLWithoutDuplicates returns ACL and strips any permission + // that already has an inherited permission with higher or equal + // permission. + GetACLWithoutDuplicates() ([]*models.DashboardAclInfoDTO, error) GetHiddenACL(*setting.Cfg) ([]*models.DashboardAcl, error) } @@ -202,6 +209,42 @@ func (g *dashboardGuardianImpl) GetAcl() ([]*models.DashboardAclInfoDTO, error) return g.acl, nil } +func (g *dashboardGuardianImpl) GetACLWithoutDuplicates() ([]*models.DashboardAclInfoDTO, error) { + acl, err := g.GetAcl() + if err != nil { + return nil, err + } + + nonInherited := []*models.DashboardAclInfoDTO{} + inherited := []*models.DashboardAclInfoDTO{} + for _, aclItem := range acl { + if aclItem.Inherited { + inherited = append(inherited, aclItem) + } else { + nonInherited = append(nonInherited, aclItem) + } + } + + result := []*models.DashboardAclInfoDTO{} + for _, nonInheritedAclItem := range nonInherited { + duplicate := false + for _, inheritedAclItem := range inherited { + if nonInheritedAclItem.IsDuplicateOf(inheritedAclItem) && nonInheritedAclItem.Permission <= inheritedAclItem.Permission { + duplicate = true + break + } + } + + if !duplicate { + result = append(result, nonInheritedAclItem) + } + } + + result = append(inherited, result...) + + return result, nil +} + func (g *dashboardGuardianImpl) getTeams() ([]*models.TeamDTO, error) { if g.teams != nil { return g.teams, nil @@ -290,6 +333,10 @@ func (g *FakeDashboardGuardian) GetAcl() ([]*models.DashboardAclInfoDTO, error) return g.GetAclValue, nil } +func (g *FakeDashboardGuardian) GetACLWithoutDuplicates() ([]*models.DashboardAclInfoDTO, error) { + return g.GetAcl() +} + func (g *FakeDashboardGuardian) GetHiddenACL(cfg *setting.Cfg) ([]*models.DashboardAcl, error) { return g.GetHiddenAclValue, nil } diff --git a/pkg/services/guardian/guardian_test.go b/pkg/services/guardian/guardian_test.go index 4303894dff8..3b9fdcb4ed0 100644 --- a/pkg/services/guardian/guardian_test.go +++ b/pkg/services/guardian/guardian_test.go @@ -726,3 +726,45 @@ func TestGuardianGetHiddenACL(t *testing.T) { }) }) } + +func TestGuardianGetAclWithoutDuplicates(t *testing.T) { + t.Run("Get hidden ACL tests", func(t *testing.T) { + t.Cleanup(bus.ClearBusHandlers) + + bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error { + query.Result = []*models.DashboardAclInfoDTO{ + {Inherited: true, UserId: 3, UserLogin: "user3", Permission: models.PERMISSION_EDIT}, + {Inherited: false, UserId: 3, UserLogin: "user3", Permission: models.PERMISSION_VIEW}, + {Inherited: false, UserId: 2, UserLogin: "user2", Permission: models.PERMISSION_ADMIN}, + {Inherited: true, UserId: 4, UserLogin: "user4", Permission: models.PERMISSION_ADMIN}, + {Inherited: false, UserId: 4, UserLogin: "user4", Permission: models.PERMISSION_ADMIN}, + {Inherited: false, UserId: 5, UserLogin: "user5", Permission: models.PERMISSION_EDIT}, + {Inherited: true, UserId: 6, UserLogin: "user6", Permission: models.PERMISSION_VIEW}, + {Inherited: false, UserId: 6, UserLogin: "user6", Permission: models.PERMISSION_EDIT}, + } + return nil + }) + + t.Run("Should get acl without duplicates", func(t *testing.T) { + user := &models.SignedInUser{ + OrgId: orgID, + UserId: 1, + Login: "user1", + } + g := New(dashboardID, orgID, user) + + acl, err := g.GetACLWithoutDuplicates() + require.NoError(t, err) + require.NotNil(t, acl) + require.Len(t, acl, 6) + require.ElementsMatch(t, []*models.DashboardAclInfoDTO{ + {Inherited: true, UserId: 3, UserLogin: "user3", Permission: models.PERMISSION_EDIT}, + {Inherited: true, UserId: 4, UserLogin: "user4", Permission: models.PERMISSION_ADMIN}, + {Inherited: true, UserId: 6, UserLogin: "user6", Permission: models.PERMISSION_VIEW}, + {Inherited: false, UserId: 2, UserLogin: "user2", Permission: models.PERMISSION_ADMIN}, + {Inherited: false, UserId: 5, UserLogin: "user5", Permission: models.PERMISSION_EDIT}, + {Inherited: false, UserId: 6, UserLogin: "user6", Permission: models.PERMISSION_EDIT}, + }, acl) + }) + }) +}