Parcourir la source

dashboards: don't allow override of permissions with a lower precedence

If a dashboard inherits permissions from a folder, don't allow same permission to be added
to the dashboard with a lower permission.
Add backend validation so that you cannot add same permission to folder/dashboard, for example
same user/team with different permissions
Marcus Efraimsson il y a 7 ans
Parent
commit
955dfcc8fe
2 fichiers modifiés avec 702 ajouts et 7 suppressions
  1. 43 7
      pkg/services/guardian/guardian.go
  2. 659 0
      pkg/services/guardian/guardian_test.go

+ 43 - 7
pkg/services/guardian/guardian.go

@@ -1,12 +1,19 @@
 package guardian
 
 import (
+	"errors"
+
 	"github.com/grafana/grafana/pkg/bus"
 	"github.com/grafana/grafana/pkg/log"
 	m "github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/setting"
 )
 
+var (
+	ErrGuardianDuplicatePermission     = errors.New("You cannot add multiple permissions for a user, team or role")
+	ErrGuardianOverrideLowerPresedence = errors.New("You cannot override a permission with a lower presedence permission")
+)
+
 // DashboardGuardian to be used for guard against operations without access on dashboard and acl
 type DashboardGuardian interface {
 	CanSave() (bool, error)
@@ -119,14 +126,41 @@ func (g *dashboardGuardianImpl) checkAcl(permission m.PermissionType, acl []*m.D
 }
 
 func (g *dashboardGuardianImpl) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
-	if g.user.OrgRole == m.ROLE_ADMIN {
-		return true, nil
-	}
-
 	acl := []*m.DashboardAclInfoDTO{}
 
 	for _, p := range updatePermissions {
-		acl = append(acl, &m.DashboardAclInfoDTO{UserId: p.UserId, TeamId: p.TeamId, Role: p.Role, Permission: p.Permission})
+		for _, a := range acl {
+			if (a.UserId <= 0 && a.TeamId <= 0 && a.UserId == p.UserId && a.TeamId == p.TeamId && a.Role == p.Role) ||
+				(a.UserId > 0 && a.UserId == p.UserId) ||
+				(a.TeamId > 0 && a.TeamId == p.TeamId) {
+				return false, ErrGuardianDuplicatePermission
+			}
+		}
+
+		acl = append(acl, &m.DashboardAclInfoDTO{DashboardId: p.DashboardId, UserId: p.UserId, TeamId: p.TeamId, Role: p.Role, Permission: p.Permission})
+	}
+
+	existingPermissions, err := g.GetAcl()
+	if err != nil {
+		return false, err
+	}
+
+	for _, a := range acl {
+		for _, existingPerm := range existingPermissions {
+			if a.DashboardId == existingPerm.DashboardId {
+				continue
+			}
+
+			if (a.UserId <= 0 && a.TeamId <= 0 && a.UserId == existingPerm.UserId && a.TeamId == existingPerm.TeamId && *a.Role == *existingPerm.Role && a.Permission <= existingPerm.Permission) ||
+				(a.UserId > 0 && a.UserId == existingPerm.UserId && a.Permission <= existingPerm.Permission) ||
+				(a.TeamId > 0 && a.TeamId == existingPerm.TeamId && a.Permission <= existingPerm.Permission) {
+				return false, ErrGuardianOverrideLowerPresedence
+			}
+		}
+	}
+
+	if g.user.OrgRole == m.ROLE_ADMIN {
+		return true, nil
 	}
 
 	return g.checkAcl(permission, acl)
@@ -169,6 +203,8 @@ type FakeDashboardGuardian struct {
 	CanAdminValue                    bool
 	HasPermissionValue               bool
 	CheckPermissionBeforeUpdateValue bool
+	CheckPermissionBeforeUpdateError error
+	GetAclValue                      []*m.DashboardAclInfoDTO
 }
 
 func (g *FakeDashboardGuardian) CanSave() (bool, error) {
@@ -192,11 +228,11 @@ func (g *FakeDashboardGuardian) HasPermission(permission m.PermissionType) (bool
 }
 
 func (g *FakeDashboardGuardian) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
-	return g.CheckPermissionBeforeUpdateValue, nil
+	return g.CheckPermissionBeforeUpdateValue, g.CheckPermissionBeforeUpdateError
 }
 
 func (g *FakeDashboardGuardian) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
-	return nil, nil
+	return g.GetAclValue, nil
 }
 
 func MockDashboardGuardian(mock *FakeDashboardGuardian) {

+ 659 - 0
pkg/services/guardian/guardian_test.go

@@ -0,0 +1,659 @@
+package guardian
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/grafana/grafana/pkg/bus"
+
+	m "github.com/grafana/grafana/pkg/models"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestGuardian(t *testing.T) {
+	Convey("Guardian permission tests", t, func() {
+		orgRoleScenario("Given user has admin org role", m.ROLE_ADMIN, func(sc *scenarioContext) {
+			canAdmin, _ := sc.g.CanAdmin()
+			canEdit, _ := sc.g.CanEdit()
+			canSave, _ := sc.g.CanSave()
+			canView, _ := sc.g.CanView()
+			So(canAdmin, ShouldBeTrue)
+			So(canEdit, ShouldBeTrue)
+			So(canSave, ShouldBeTrue)
+			So(canView, ShouldBeTrue)
+
+			Convey("When trying to update permissions", func() {
+				Convey("With duplicate user/role permissions should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW},
+						{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianDuplicatePermission)
+				})
+
+				Convey("With duplicate team/role permissions should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW},
+						{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianDuplicatePermission)
+				})
+
+				Convey("With duplicate everyone/role permissions should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 1, Permission: m.PERMISSION_VIEW},
+						{OrgId: 1, DashboardId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianDuplicatePermission)
+				})
+			})
+
+			Convey("Given parent folder has user admin permission", func() {
+				existingPermissions := []*m.DashboardAclInfoDTO{
+					{OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_ADMIN},
+				}
+
+				bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+					query.Result = existingPermissions
+					return nil
+				})
+
+				Convey("When trying to update dashboard permissions with admin user permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+
+				Convey("When trying to update dashboard permissions with edit user permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+
+				Convey("When trying to update dashboard permissions with view user permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+			})
+
+			Convey("Given parent folder has user edit permission", func() {
+				existingPermissions := []*m.DashboardAclInfoDTO{
+					{OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_EDIT},
+				}
+
+				bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+					query.Result = existingPermissions
+					return nil
+				})
+
+				Convey("When trying to update dashboard permissions with admin user permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with edit user permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+
+				Convey("When trying to update dashboard permissions with view user permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+			})
+
+			Convey("Given parent folder has user view permission", func() {
+				existingPermissions := []*m.DashboardAclInfoDTO{
+					{OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_VIEW},
+				}
+
+				bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+					query.Result = existingPermissions
+					return nil
+				})
+
+				Convey("When trying to update dashboard permissions with admin user permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with edit user permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with view user permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+			})
+
+			Convey("Given parent folder has team admin permission", func() {
+				existingPermissions := []*m.DashboardAclInfoDTO{
+					{OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_ADMIN},
+				}
+
+				bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+					query.Result = existingPermissions
+					return nil
+				})
+
+				Convey("When trying to update dashboard permissions with admin team permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+
+				Convey("When trying to update dashboard permissions with edit team permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+
+				Convey("When trying to update dashboard permissions with view team permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+			})
+
+			Convey("Given parent folder has team edit permission", func() {
+				existingPermissions := []*m.DashboardAclInfoDTO{
+					{OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_EDIT},
+				}
+
+				bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+					query.Result = existingPermissions
+					return nil
+				})
+
+				Convey("When trying to update dashboard permissions with admin team permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with edit team permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+
+				Convey("When trying to update dashboard permissions with view team permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+			})
+
+			Convey("Given parent folder has team view permission", func() {
+				existingPermissions := []*m.DashboardAclInfoDTO{
+					{OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_VIEW},
+				}
+
+				bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+					query.Result = existingPermissions
+					return nil
+				})
+
+				Convey("When trying to update dashboard permissions with admin team permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with edit team permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with view team permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+			})
+
+			Convey("Given parent folder has editor role with edit permission", func() {
+				r := m.ROLE_EDITOR
+				existingPermissions := []*m.DashboardAclInfoDTO{
+					{OrgId: 1, DashboardId: 2, Role: &r, Permission: m.PERMISSION_EDIT},
+				}
+
+				bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+					query.Result = existingPermissions
+					return nil
+				})
+
+				Convey("When trying to update dashboard permissions with everyone with editor role can admin permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_ADMIN},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with everyone with editor role can edit permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_EDIT},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+
+				Convey("When trying to update dashboard permissions with everyone with editor role can view permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_VIEW},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+			})
+
+			Convey("Given parent folder has editor role with view permission", func() {
+				r := m.ROLE_EDITOR
+				existingPermissions := []*m.DashboardAclInfoDTO{
+					{OrgId: 1, DashboardId: 2, Role: &r, Permission: m.PERMISSION_VIEW},
+				}
+
+				bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+					query.Result = existingPermissions
+					return nil
+				})
+
+				Convey("When trying to update dashboard permissions with everyone with viewer role can admin permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_ADMIN},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with everyone with viewer role can edit permission should be allowed", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_EDIT},
+					}
+					ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(ok, ShouldBeTrue)
+				})
+
+				Convey("When trying to update dashboard permissions with everyone with viewer role can view permission should return error", func() {
+					p := []*m.DashboardAcl{
+						{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_VIEW},
+					}
+					_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+					So(err, ShouldEqual, ErrGuardianOverrideLowerPresedence)
+				})
+			})
+		})
+
+		orgRoleScenario("Given user has editor org role", m.ROLE_EDITOR, func(sc *scenarioContext) {
+			everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeTrue)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeTrue)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeFalse)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeFalse)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeFalse)
+			})
+
+			userWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeTrue)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			userWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			userWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeTrue)
+			})
+
+			teamWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeTrue)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			teamWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			teamWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeTrue)
+			})
+
+			Convey("When trying to update permissions should return false", func() {
+				p := []*m.DashboardAcl{
+					{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW},
+					{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN},
+				}
+				ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+				So(ok, ShouldBeFalse)
+			})
+		})
+
+		orgRoleScenario("Given user has viewer org role", m.ROLE_VIEWER, func(sc *scenarioContext) {
+			everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeFalse)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeFalse)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeFalse)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeTrue)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeTrue)
+			})
+
+			userWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeTrue)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			userWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeTrue)
+				So(canSave, ShouldBeTrue)
+				So(canView, ShouldBeTrue)
+			})
+
+			userWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
+				canAdmin, _ := sc.g.CanAdmin()
+				canEdit, _ := sc.g.CanEdit()
+				canSave, _ := sc.g.CanSave()
+				canView, _ := sc.g.CanView()
+				So(canAdmin, ShouldBeFalse)
+				So(canEdit, ShouldBeFalse)
+				So(canSave, ShouldBeFalse)
+				So(canView, ShouldBeTrue)
+			})
+
+			Convey("When trying to update permissions should return false", func() {
+				p := []*m.DashboardAcl{
+					{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW},
+					{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN},
+				}
+				ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
+				So(ok, ShouldBeFalse)
+			})
+		})
+	})
+}
+
+type scenarioContext struct {
+	g DashboardGuardian
+}
+
+type scenarioFunc func(c *scenarioContext)
+
+func orgRoleScenario(desc string, role m.RoleType, fn scenarioFunc) {
+	user := &m.SignedInUser{
+		UserId:  1,
+		OrgId:   1,
+		OrgRole: role,
+	}
+	guard := New(1, 1, user)
+	sc := &scenarioContext{
+		g: guard,
+	}
+
+	Convey(desc, func() {
+		fn(sc)
+	})
+}
+
+func permissionScenario(desc string, sc *scenarioContext, permissions []*m.DashboardAclInfoDTO, fn scenarioFunc) {
+	bus.ClearBusHandlers()
+
+	bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
+		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 {
+		query.Result = teams
+		return nil
+	})
+
+	Convey(desc, func() {
+		fn(sc)
+	})
+}
+
+func userWithPermissionScenario(permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) {
+	p := []*m.DashboardAclInfoDTO{
+		{OrgId: 1, DashboardId: 1, UserId: 1, Permission: permission},
+	}
+	permissionScenario(fmt.Sprintf("and user has permission to %s item", permission), sc, p, fn)
+}
+
+func teamWithPermissionScenario(permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) {
+	p := []*m.DashboardAclInfoDTO{
+		{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: permission},
+	}
+	permissionScenario(fmt.Sprintf("and team has permission to %s item", permission), sc, p, fn)
+}
+
+func everyoneWithRoleScenario(role m.RoleType, permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) {
+	p := []*m.DashboardAclInfoDTO{
+		{OrgId: 1, DashboardId: 1, UserId: -1, Role: &role, Permission: permission},
+	}
+	permissionScenario(fmt.Sprintf("and everyone with %s role can %s item", role, permission), sc, p, fn)
+}