From 3fe031d25db0c621a7824967fa8df55c4a27eee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 16 Jun 2017 21:25:24 -0400 Subject: [PATCH] refactoring: Dashboard guardian --- pkg/api/dashboard.go | 19 +++-- pkg/models/dashboard_acl.go | 4 +- pkg/models/user.go | 8 +++ pkg/services/guardian/guardian.go | 5 +- pkg/services/guardian/models.go | 96 ++++++++++++++++++++++++++ pkg/services/sqlstore/dashboard_acl.go | 6 +- 6 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 pkg/services/guardian/models.go diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 0364c0ab681..bebfc54fecd 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -46,13 +46,11 @@ func GetDashboard(c *middleware.Context) Response { } dash := query.Result + guardian := guardian.NewDashboardGuardian(dash, c.SignedInUser) - canView, canEdit, canSave, err := getPermissions(dash, c.OrgRole, c.IsGrafanaAdmin, c.UserId) - if err != nil { + if canView, err := guardian.CanView(); err != nil { return ApiError(500, "Error while checking dashboard permissions", err) - } - - if !canView { + } else if !canView { return ApiError(403, "Access denied to this dashboard", nil) } @@ -162,12 +160,11 @@ func DeleteDashboard(c *middleware.Context) Response { return ApiError(404, "Dashboard not found", err) } - _, _, canSave, err := getPermissions(query.Result, c.OrgRole, c.IsGrafanaAdmin, c.UserId) - if err != nil { - return ApiError(500, "Error while checking dashboard permissions", err) - } + guardian := guardian.NewDashboardGuardian(query.Result, c.SignedInUser) - if !canSave { + if canSave, err := guardian.CanSave(); err != nil { + return ApiError(500, "Error while checking dashboard permissions", err) + } else if !canSave { return ApiError(403, "Does not have permission to delete this dashboard", nil) } @@ -301,6 +298,8 @@ func GetHomeDashboard(c *middleware.Context) Response { dash := dtos.DashboardFullWithMeta{} dash.Meta.IsHome = true dash.Meta.CanEdit = canEditDashboard(c.OrgRole) + dash.Meta.FolderTitle = "Root" + jsonParser := json.NewDecoder(file) if err := jsonParser.Decode(&dash.Dashboard); err != nil { return ApiError(500, "Failed to load home dashboard", err) diff --git a/pkg/models/dashboard_acl.go b/pkg/models/dashboard_acl.go index 08d22ef5ee1..990fc49c386 100644 --- a/pkg/models/dashboard_acl.go +++ b/pkg/models/dashboard_acl.go @@ -54,8 +54,8 @@ type DashboardAclInfoDTO struct { UserEmail string `json:"userEmail"` UserGroupId int64 `json:"userGroupId"` UserGroup string `json:"userGroup"` - PermissionType PermissionType `json:"permissionType"` - Permissions string `json:"permissions"` + Permissions PermissionType `json:"permissions"` + PermissionName string `json:"permissionName"` } // diff --git a/pkg/models/user.go b/pkg/models/user.go index bdf81056232..3aac76768c6 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -162,6 +162,14 @@ type SignedInUser struct { HelpFlags1 HelpFlags1 } +func (user *SignedInUser) HasRole(role RoleType) bool { + if user.IsGrafanaAdmin { + return true + } + + return user.OrgRole.Includes(role) +} + type UserProfileDTO struct { Email string `json:"email"` Name string `json:"name"` diff --git a/pkg/services/guardian/guardian.go b/pkg/services/guardian/guardian.go index 3ed65c85465..fb9c8de3081 100644 --- a/pkg/services/guardian/guardian.go +++ b/pkg/services/guardian/guardian.go @@ -17,7 +17,6 @@ func FilterRestrictedDashboards(dashList []int64, orgId int64, userId int64) ([] } filteredList, err := getAllowedDashboards(dashList, orgId, userId) - return filteredList, err } @@ -101,12 +100,12 @@ func checkPermission(minimumPermission m.PermissionType, permissions []*m.Dashbo } for _, p := range permissions { - if p.UserId == userId && p.PermissionType >= minimumPermission { + if p.UserId == userId && p.Permissions >= minimumPermission { return true, nil } for _, ug := range userGroups { - if ug.Id == p.UserGroupId && p.PermissionType >= minimumPermission { + if ug.Id == p.UserGroupId && p.Permissions >= minimumPermission { return true, nil } } diff --git a/pkg/services/guardian/models.go b/pkg/services/guardian/models.go new file mode 100644 index 00000000000..33b76d122c9 --- /dev/null +++ b/pkg/services/guardian/models.go @@ -0,0 +1,96 @@ +package guardian + +import ( + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" +) + +type DashboardGuardian struct { + user *m.SignedInUser + dashboard *m.Dashboard + acl []*m.DashboardAclInfoDTO + groups []*m.UserGroup +} + +func NewDashboardGuardian(dash *m.Dashboard, user *m.SignedInUser) *DashboardGuardian { + return &DashboardGuardian{ + user: user, + dashboard: dash, + } +} + +func (g *DashboardGuardian) CanSave() (bool, error) { + if !g.dashboard.HasAcl { + return g.user.HasRole(m.ROLE_EDITOR), nil + } + + return g.HasPermission(m.PERMISSION_EDIT) +} + +func (g *DashboardGuardian) CanEdit() (bool, error) { + if !g.dashboard.HasAcl { + return g.user.HasRole(m.ROLE_READ_ONLY_EDITOR), nil + } + + return g.HasPermission(m.PERMISSION_READ_ONLY_EDIT) +} + +func (g *DashboardGuardian) CanView() (bool, error) { + if !g.dashboard.HasAcl { + return g.user.HasRole(m.ROLE_VIEWER), nil + } + + return g.HasPermission(m.PERMISSION_VIEW) +} + +func (g *DashboardGuardian) HasPermission(permission m.PermissionType) (bool, error) { + userGroups, err := g.getUserGroups() + if err != nil { + return false, err + } + + acl, err := g.getAcl() + if err != nil { + return false, err + } + + for _, p := range acl { + if p.UserId == g.user.UserId && p.Permissions >= permission { + return true, nil + } + + for _, ug := range userGroups { + if ug.Id == p.UserGroupId && p.Permissions >= permission { + return true, nil + } + } + } + + return false, nil +} + +func (g *DashboardGuardian) getAcl() ([]*m.DashboardAclInfoDTO, error) { + if g.acl != nil { + return g.acl, nil + } + + query := m.GetDashboardPermissionsQuery{DashboardId: g.dashboard.Id} + if err := bus.Dispatch(&query); err != nil { + return nil, err + } + + g.acl = query.Result + return g.acl, nil +} + +func (g *DashboardGuardian) getUserGroups() ([]*m.UserGroup, error) { + if g.groups == nil { + return g.groups, nil + } + + query := m.GetUserGroupsByUserQuery{UserId: g.user.UserId} + err := bus.Dispatch(&query) + + g.groups = query.Result + return query.Result, err +} diff --git a/pkg/services/sqlstore/dashboard_acl.go b/pkg/services/sqlstore/dashboard_acl.go index d3e80cc108b..9f26952e601 100644 --- a/pkg/services/sqlstore/dashboard_acl.go +++ b/pkg/services/sqlstore/dashboard_acl.go @@ -3,8 +3,6 @@ package sqlstore import ( "time" - "fmt" - "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" ) @@ -94,7 +92,7 @@ func GetDashboardPermissions(query *m.GetDashboardPermissionsQuery) error { da.dashboard_id, da.user_id, da.user_group_id, - da.permissions as permission_type, + da.permissions, da.created, da.updated, u.login AS user_login, @@ -110,7 +108,7 @@ func GetDashboardPermissions(query *m.GetDashboardPermissionsQuery) error { err := x.SQL(rawSQL, query.DashboardId).Find(&query.Result) for _, p := range query.Result { - p.Permissions = fmt.Sprint(p.PermissionType) + p.PermissionName = p.Permissions.String() } return err