mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
guardian: when updating permissions should verify existing permissions
Before in CheckPermissionBeforeUpdate, access was verified for updated permissions. Now access is verified for existing permissions. Refactored guardian tests to cover more test cases for org admin, editor and viewer roles
This commit is contained in:
parent
84d034c688
commit
f3e1557761
@ -173,7 +173,7 @@ func (g *dashboardGuardianImpl) CheckPermissionBeforeUpdate(permission m.Permiss
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return g.checkAcl(permission, acl)
|
return g.checkAcl(permission, existingPermissions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAcl returns dashboard acl
|
// GetAcl returns dashboard acl
|
||||||
|
File diff suppressed because it is too large
Load Diff
256
pkg/services/guardian/guardian_util_test.go
Normal file
256
pkg/services/guardian/guardian_util_test.go
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
package guardian
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
type scenarioContext struct {
|
||||||
|
t *testing.T
|
||||||
|
orgRoleScenario string
|
||||||
|
permissionScenario string
|
||||||
|
g DashboardGuardian
|
||||||
|
givenUser *m.SignedInUser
|
||||||
|
givenDashboardID int64
|
||||||
|
givenPermissions []*m.DashboardAclInfoDTO
|
||||||
|
givenTeams []*m.Team
|
||||||
|
updatePermissions []*m.DashboardAcl
|
||||||
|
expectedFlags permissionFlags
|
||||||
|
callerFile string
|
||||||
|
callerLine int
|
||||||
|
}
|
||||||
|
|
||||||
|
type scenarioFunc func(c *scenarioContext)
|
||||||
|
|
||||||
|
func orgRoleScenario(desc string, t *testing.T, role m.RoleType, fn scenarioFunc) {
|
||||||
|
user := &m.SignedInUser{
|
||||||
|
UserId: userID,
|
||||||
|
OrgId: orgID,
|
||||||
|
OrgRole: role,
|
||||||
|
}
|
||||||
|
guard := New(dashboardID, orgID, user)
|
||||||
|
sc := &scenarioContext{
|
||||||
|
t: t,
|
||||||
|
orgRoleScenario: desc,
|
||||||
|
givenUser: user,
|
||||||
|
givenDashboardID: dashboardID,
|
||||||
|
g: guard,
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey(desc, func() {
|
||||||
|
fn(sc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func permissionScenario(desc string, dashboardID int64, sc *scenarioContext, permissions []*m.DashboardAclInfoDTO, fn scenarioFunc) {
|
||||||
|
bus.ClearBusHandlers()
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
if query.OrgId != sc.givenUser.OrgId {
|
||||||
|
sc.reportFailure("Invalid organization id for GetDashboardAclInfoListQuery", sc.givenUser.OrgId, query.OrgId)
|
||||||
|
}
|
||||||
|
if query.DashboardId != sc.givenDashboardID {
|
||||||
|
sc.reportFailure("Invalid dashboard id for GetDashboardAclInfoListQuery", sc.givenDashboardID, query.DashboardId)
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Result = permissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
teams := []*m.Team{}
|
||||||
|
|
||||||
|
for _, p := range permissions {
|
||||||
|
if p.TeamId > 0 {
|
||||||
|
teams = append(teams, &m.Team{Id: p.TeamId})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
|
||||||
|
if query.OrgId != sc.givenUser.OrgId {
|
||||||
|
sc.reportFailure("Invalid organization id for GetTeamsByUserQuery", sc.givenUser.OrgId, query.OrgId)
|
||||||
|
}
|
||||||
|
if query.UserId != sc.givenUser.UserId {
|
||||||
|
sc.reportFailure("Invalid user id for GetTeamsByUserQuery", sc.givenUser.UserId, query.UserId)
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Result = teams
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
sc.permissionScenario = desc
|
||||||
|
sc.g = New(dashboardID, sc.givenUser.OrgId, sc.givenUser)
|
||||||
|
sc.givenDashboardID = dashboardID
|
||||||
|
sc.givenPermissions = permissions
|
||||||
|
sc.givenTeams = teams
|
||||||
|
|
||||||
|
Convey(desc, func() {
|
||||||
|
fn(sc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type permissionType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
USER permissionType = 1 << iota
|
||||||
|
TEAM
|
||||||
|
EDITOR
|
||||||
|
VIEWER
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p permissionType) String() string {
|
||||||
|
names := map[uint8]string{
|
||||||
|
uint8(USER): "user",
|
||||||
|
uint8(TEAM): "team",
|
||||||
|
uint8(EDITOR): "editor role",
|
||||||
|
uint8(VIEWER): "viewer role",
|
||||||
|
}
|
||||||
|
return names[uint8(p)]
|
||||||
|
}
|
||||||
|
|
||||||
|
type permissionFlags uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
NO_ACCESS permissionFlags = 1 << iota
|
||||||
|
CAN_ADMIN
|
||||||
|
CAN_EDIT
|
||||||
|
CAN_SAVE
|
||||||
|
CAN_VIEW
|
||||||
|
FULL_ACCESS = CAN_ADMIN | CAN_EDIT | CAN_SAVE | CAN_VIEW
|
||||||
|
EDITOR_ACCESS = CAN_EDIT | CAN_SAVE | CAN_VIEW
|
||||||
|
VIEWER_ACCESS = CAN_VIEW
|
||||||
|
)
|
||||||
|
|
||||||
|
func (flag permissionFlags) canAdmin() bool {
|
||||||
|
return flag&CAN_ADMIN != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flag permissionFlags) canEdit() bool {
|
||||||
|
return flag&CAN_EDIT != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flag permissionFlags) canSave() bool {
|
||||||
|
return flag&CAN_SAVE != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flag permissionFlags) canView() bool {
|
||||||
|
return flag&CAN_VIEW != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flag permissionFlags) noAccess() bool {
|
||||||
|
return flag&(CAN_ADMIN|CAN_EDIT|CAN_SAVE|CAN_VIEW) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f permissionFlags) String() string {
|
||||||
|
r := []string{}
|
||||||
|
|
||||||
|
if f.canAdmin() {
|
||||||
|
r = append(r, "admin")
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.canEdit() {
|
||||||
|
r = append(r, "edit")
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.canSave() {
|
||||||
|
r = append(r, "save")
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.canView() {
|
||||||
|
r = append(r, "view")
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.noAccess() {
|
||||||
|
r = append(r, "<no access>")
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(r[:], ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *scenarioContext) reportSuccess() {
|
||||||
|
So(true, ShouldBeTrue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *scenarioContext) reportFailure(desc string, expected interface{}, actual interface{}) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString("\n")
|
||||||
|
buf.WriteString(sc.orgRoleScenario)
|
||||||
|
buf.WriteString(" ")
|
||||||
|
buf.WriteString(sc.permissionScenario)
|
||||||
|
buf.WriteString("\n ")
|
||||||
|
buf.WriteString(desc)
|
||||||
|
buf.WriteString("\n")
|
||||||
|
buf.WriteString(fmt.Sprintf("Source test: %s:%d\n", sc.callerFile, sc.callerLine))
|
||||||
|
buf.WriteString(fmt.Sprintf("Expected: %v\n", expected))
|
||||||
|
buf.WriteString(fmt.Sprintf("Actual: %v\n", actual))
|
||||||
|
buf.WriteString("Context:")
|
||||||
|
buf.WriteString(fmt.Sprintf("\n Given user: orgRole=%s, id=%d, orgId=%d", sc.givenUser.OrgRole, sc.givenUser.UserId, sc.givenUser.OrgId))
|
||||||
|
buf.WriteString(fmt.Sprintf("\n Given dashboard id: %d", sc.givenDashboardID))
|
||||||
|
|
||||||
|
for i, p := range sc.givenPermissions {
|
||||||
|
r := "<nil>"
|
||||||
|
if p.Role != nil {
|
||||||
|
r = string(*p.Role)
|
||||||
|
}
|
||||||
|
buf.WriteString(fmt.Sprintf("\n Given permission (%d): dashboardId=%d, userId=%d, teamId=%d, role=%v, permission=%s", i, p.DashboardId, p.UserId, p.TeamId, r, p.Permission.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, t := range sc.givenTeams {
|
||||||
|
buf.WriteString(fmt.Sprintf("\n Given team (%d): id=%d", i, t.Id))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, p := range sc.updatePermissions {
|
||||||
|
r := "<nil>"
|
||||||
|
if p.Role != nil {
|
||||||
|
r = string(*p.Role)
|
||||||
|
}
|
||||||
|
buf.WriteString(fmt.Sprintf("\n Update permission (%d): dashboardId=%d, userId=%d, teamId=%d, role=%v, permission=%s", i, p.DashboardId, p.UserId, p.TeamId, r, p.Permission.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.t.Fatalf(buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCustomUserPermission(dashboardID int64, userID int64, permission m.PermissionType) *m.DashboardAcl {
|
||||||
|
return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, UserId: userID, Permission: permission}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDefaultUserPermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
|
||||||
|
return newCustomUserPermission(dashboardID, userID, permission)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCustomTeamPermission(dashboardID int64, teamID int64, permission m.PermissionType) *m.DashboardAcl {
|
||||||
|
return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, TeamId: teamID, Permission: permission}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDefaultTeamPermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
|
||||||
|
return newCustomTeamPermission(dashboardID, teamID, permission)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAdminRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
|
||||||
|
return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &adminRole, Permission: permission}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEditorRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
|
||||||
|
return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &editorRole, Permission: permission}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newViewerRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
|
||||||
|
return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &viewerRole, Permission: permission}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toDto(acl *m.DashboardAcl) *m.DashboardAclInfoDTO {
|
||||||
|
return &m.DashboardAclInfoDTO{
|
||||||
|
OrgId: acl.OrgId,
|
||||||
|
DashboardId: acl.DashboardId,
|
||||||
|
UserId: acl.UserId,
|
||||||
|
TeamId: acl.TeamId,
|
||||||
|
Role: acl.Role,
|
||||||
|
Permission: acl.Permission,
|
||||||
|
PermissionName: acl.Permission.String(),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user