Jelajahi Sumber

refactoring: Dashboard guardian

Torkel Ödegaard 8 tahun lalu
induk
melakukan
3fe031d25d

+ 9 - 10
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)

+ 2 - 2
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"`
 }
 
 //

+ 8 - 0
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"`

+ 2 - 3
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
 			}
 		}

+ 96 - 0
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
+}

+ 2 - 4
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