diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index 5cc31aebb68..005c97eba57 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -13,6 +13,7 @@ import ( alertmodels "github.com/grafana/grafana/pkg/services/alerting/models" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/ngalert/notifier/channels_config" @@ -113,7 +114,7 @@ func (hs *HTTPServer) GetAlerts(c *contextmodel.ReqContext) response.Response { DashboardIds: dashboardIDs, Type: string(model.DashHitDB), FolderIds: folderIDs, // nolint:staticcheck - Permission: dashboards.PERMISSION_VIEW, + Permission: dashboardaccess.PERMISSION_VIEW, } hits, err := hs.SearchService.SearchHandler(c.Req.Context(), &searchQuery) diff --git a/pkg/api/api.go b/pkg/api/api.go index b3137dc198d..9b360efe84b 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -64,7 +64,7 @@ func (hs *HTTPServer) registerRoutes() { reqSnapshotPublicModeOrSignedIn := middleware.SnapshotPublicModeOrSignedIn(hs.Cfg) redirectFromLegacyPanelEditURL := middleware.RedirectFromLegacyPanelEditURL(hs.Cfg) authorize := ac.Middleware(hs.AccessControl) - authorizeInOrg := ac.AuthorizeInOrgMiddleware(hs.AccessControl, hs.accesscontrolService, hs.userService) + authorizeInOrg := ac.AuthorizeInOrgMiddleware(hs.AccessControl, hs.accesscontrolService, hs.userService, hs.teamService) quota := middleware.Quota(hs.QuotaService) r := hs.RouteRegister diff --git a/pkg/api/dashboard_permission.go b/pkg/api/dashboard_permission.go index 22756e12430..c4fa0c04114 100644 --- a/pkg/api/dashboard_permission.go +++ b/pkg/api/dashboard_permission.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/auth/identity" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/web" ) @@ -166,10 +167,10 @@ func (hs *HTTPServer) UpdateDashboardPermissions(c *contextmodel.ReqContext) res return response.Success("Dashboard permissions updated") } -var dashboardPermissionMap = map[string]dashboards.PermissionType{ - "View": dashboards.PERMISSION_VIEW, - "Edit": dashboards.PERMISSION_EDIT, - "Admin": dashboards.PERMISSION_ADMIN, +var dashboardPermissionMap = map[string]dashboardaccess.PermissionType{ + "View": dashboardaccess.PERMISSION_VIEW, + "Edit": dashboardaccess.PERMISSION_EDIT, + "Admin": dashboardaccess.PERMISSION_ADMIN, } func (hs *HTTPServer) getDashboardACL(ctx context.Context, user identity.Requester, dashboard *dashboards.Dashboard) ([]*dashboards.DashboardACLInfoDTO, error) { @@ -313,11 +314,11 @@ func (hs *HTTPServer) updateDashboardAccessControl(ctx context.Context, orgID in func validatePermissionsUpdate(apiCmd dtos.UpdateDashboardACLCommand) error { for _, item := range apiCmd.Items { if item.UserID > 0 && item.TeamID > 0 { - return dashboards.ErrPermissionsWithUserAndTeamNotAllowed + return dashboardaccess.ErrPermissionsWithUserAndTeamNotAllowed } if (item.UserID > 0 || item.TeamID > 0) && item.Role != nil { - return dashboards.ErrPermissionsWithRoleNotAllowed + return dashboardaccess.ErrPermissionsWithRoleNotAllowed } } return nil diff --git a/pkg/api/dtos/acl.go b/pkg/api/dtos/acl.go index d6f4114157a..f17719a0c62 100644 --- a/pkg/api/dtos/acl.go +++ b/pkg/api/dtos/acl.go @@ -1,7 +1,7 @@ package dtos import ( - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/org" ) @@ -21,5 +21,5 @@ type DashboardACLUpdateItem struct { // * `2` - Edit // * `4` - Admin // Enum: 1,2,4 - Permission dashboards.PermissionType `json:"permission"` + Permission dashboardaccess.PermissionType `json:"permission"` } diff --git a/pkg/api/folder.go b/pkg/api/folder.go index b8fb520da39..f2ed1990e02 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/services/auth/identity" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/guardian" @@ -186,15 +187,15 @@ func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int } permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ - UserID: userID, Permission: dashboards.PERMISSION_ADMIN.String(), + UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(), }) } isNested := folder.ParentUID != "" if !isNested || !hs.Features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) { permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }...) } @@ -449,7 +450,7 @@ func (hs *HTTPServer) searchFolders(c *contextmodel.ReqContext) ([]*folder.Folde Limit: c.QueryInt64("limit"), OrgId: c.SignedInUser.GetOrgID(), Type: "dash-folder", - Permission: dashboards.PERMISSION_VIEW, + Permission: dashboardaccess.PERMISSION_VIEW, Page: c.QueryInt64("page"), } diff --git a/pkg/api/folder_bench_test.go b/pkg/api/folder_bench_test.go index 02b1137855c..1096b47989b 100644 --- a/pkg/api/folder_bench_test.go +++ b/pkg/api/folder_bench_test.go @@ -27,6 +27,7 @@ import ( "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/dashboards/database" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" @@ -270,7 +271,7 @@ func setupDB(b testing.TB) benchScenario { UserID: userID, TeamID: teamID, OrgID: orgID, - Permission: dashboards.PERMISSION_VIEW, + Permission: dashboardaccess.PERMISSION_VIEW, Created: now, Updated: now, }) diff --git a/pkg/api/folder_permission.go b/pkg/api/folder_permission.go index 9b157aaca44..10e34c3ffe7 100644 --- a/pkg/api/folder_permission.go +++ b/pkg/api/folder_permission.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/services/auth/identity" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/web" @@ -118,10 +119,10 @@ func (hs *HTTPServer) UpdateFolderPermissions(c *contextmodel.ReqContext) respon return response.Success("Folder permissions updated") } -var folderPermissionMap = map[string]dashboards.PermissionType{ - "View": dashboards.PERMISSION_VIEW, - "Edit": dashboards.PERMISSION_EDIT, - "Admin": dashboards.PERMISSION_ADMIN, +var folderPermissionMap = map[string]dashboardaccess.PermissionType{ + "View": dashboardaccess.PERMISSION_VIEW, + "Edit": dashboardaccess.PERMISSION_EDIT, + "Admin": dashboardaccess.PERMISSION_ADMIN, } func (hs *HTTPServer) getFolderACL(ctx context.Context, user identity.Requester, folder *folder.Folder) ([]*dashboards.DashboardACLInfoDTO, error) { diff --git a/pkg/api/org_users_test.go b/pkg/api/org_users_test.go index 4e6f6d7d2ab..fcc7223a8a3 100644 --- a/pkg/api/org_users_test.go +++ b/pkg/api/org_users_test.go @@ -437,6 +437,7 @@ func TestGetOrgUsersAPIEndpoint_AccessControl(t *testing.T) { } hs.authInfoService = &authinfotest.FakeService{} hs.userService = &usertest.FakeUserService{ExpectedSignedInUser: userWithPermissions(1, tc.permissions)} + hs.accesscontrolService = &actest.FakeService{} }) u := userWithPermissions(1, tc.permissions) @@ -482,6 +483,7 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) { ExpectedUser: &user.User{}, ExpectedSignedInUser: userWithPermissions(1, tt.permissions), } + hs.accesscontrolService = &actest.FakeService{} }) u := userWithPermissions(1, tt.permissions) diff --git a/pkg/api/search.go b/pkg/api/search.go index da9a27a8ab0..0ff77b123f9 100644 --- a/pkg/api/search.go +++ b/pkg/api/search.go @@ -7,7 +7,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/infra/metrics" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/services/search/model" "github.com/grafana/grafana/pkg/util" @@ -28,14 +28,14 @@ func (hs *HTTPServer) Search(c *contextmodel.ReqContext) response.Response { page := c.QueryInt64("page") dashboardType := c.Query("type") sort := c.Query("sort") - permission := dashboards.PERMISSION_VIEW + permission := dashboardaccess.PERMISSION_VIEW if limit > 5000 { return response.Error(422, "Limit is above maximum allowed (5000), use page parameter to access hits beyond limit", nil) } if c.Query("permission") == "Edit" { - permission = dashboards.PERMISSION_EDIT + permission = dashboardaccess.PERMISSION_EDIT } dbIDs := make([]int64, 0) diff --git a/pkg/infra/db/sqlbuilder.go b/pkg/infra/db/sqlbuilder.go index d3b3fd15ff9..b6d88a37879 100644 --- a/pkg/infra/db/sqlbuilder.go +++ b/pkg/infra/db/sqlbuilder.go @@ -4,7 +4,7 @@ import ( "bytes" "github.com/grafana/grafana/pkg/services/auth/identity" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/sqlstore/permissions" @@ -63,7 +63,7 @@ func (sb *SQLBuilder) AddParams(params ...any) { sb.params = append(sb.params, params...) } -func (sb *SQLBuilder) WriteDashboardPermissionFilter(user identity.Requester, permission dashboards.PermissionType, queryType string) { +func (sb *SQLBuilder) WriteDashboardPermissionFilter(user identity.Requester, permission dashboardaccess.PermissionType, queryType string) { var ( sql string params []any diff --git a/pkg/services/accesscontrol/accesscontrol.go b/pkg/services/accesscontrol/accesscontrol.go index 6434663080a..c4f2446034d 100644 --- a/pkg/services/accesscontrol/accesscontrol.go +++ b/pkg/services/accesscontrol/accesscontrol.go @@ -104,26 +104,20 @@ type User struct { // HasGlobalAccess checks user access with globally assigned permissions only func HasGlobalAccess(ac AccessControl, service Service, c *contextmodel.ReqContext) func(evaluator Evaluator) bool { return func(evaluator Evaluator) bool { - userCopy := *c.SignedInUser - userCopy.OrgID = GlobalOrgID - userCopy.OrgRole = "" - userCopy.OrgName = "" - if userCopy.Permissions[GlobalOrgID] == nil { - permissions, err := service.GetUserPermissions(c.Req.Context(), &userCopy, Options{}) - if err != nil { - c.Logger.Error("Failed fetching permissions for user", "userID", userCopy.UserID, "error", err) - } - userCopy.Permissions[GlobalOrgID] = GroupScopesByAction(permissions) + var targetOrgID int64 = GlobalOrgID + tmpUser, err := makeTmpUser(c.Req.Context(), service, nil, nil, c.SignedInUser, targetOrgID) + if err != nil { + deny(c, nil, fmt.Errorf("failed to authenticate user in target org: %w", err)) } - hasAccess, err := ac.Evaluate(c.Req.Context(), &userCopy, evaluator) + hasAccess, err := ac.Evaluate(c.Req.Context(), tmpUser, evaluator) if err != nil { c.Logger.Error("Error from access control system", "error", err) return false } // set on user so we don't fetch global permissions every time this is called - c.SignedInUser.Permissions[GlobalOrgID] = userCopy.Permissions[GlobalOrgID] + c.SignedInUser.Permissions[tmpUser.GetOrgID()] = tmpUser.GetPermissions() return hasAccess } diff --git a/pkg/services/accesscontrol/acimpl/service.go b/pkg/services/accesscontrol/acimpl/service.go index 67eeee8003c..3d8b5b829b9 100644 --- a/pkg/services/accesscontrol/acimpl/service.go +++ b/pkg/services/accesscontrol/acimpl/service.go @@ -22,7 +22,6 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/migrator" "github.com/grafana/grafana/pkg/services/accesscontrol/pluginutils" "github.com/grafana/grafana/pkg/services/auth/identity" - "github.com/grafana/grafana/pkg/services/authn" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" @@ -116,16 +115,9 @@ func (s *Service) getUserPermissions(ctx context.Context, user identity.Requeste } } - namespace, identifier := user.GetNamespacedID() - - var userID int64 - switch namespace { - case authn.NamespaceUser, authn.NamespaceServiceAccount: - var err error - userID, err = strconv.ParseInt(identifier, 10, 64) - if err != nil { - return nil, err - } + userID, err := identity.UserIdentifier(user.GetNamespacedID()) + if err != nil { + return nil, err } dbPermissions, err := s.store.GetUserPermissions(ctx, accesscontrol.GetUserPermissionsQuery{ diff --git a/pkg/services/accesscontrol/authorize_in_org_test.go b/pkg/services/accesscontrol/authorize_in_org_test.go index 0af24186f16..812f56634fa 100644 --- a/pkg/services/accesscontrol/authorize_in_org_test.go +++ b/pkg/services/accesscontrol/authorize_in_org_test.go @@ -13,6 +13,8 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" "github.com/grafana/grafana/pkg/services/accesscontrol/actest" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" + "github.com/grafana/grafana/pkg/services/team" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/setting" @@ -32,6 +34,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { acService accesscontrol.Service userCache user.Service ctxSignedInUser *user.SignedInUser + teamService team.Service expectedStatus int }{ { @@ -46,6 +49,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { acService: &actest.FakeService{ ExpectedPermissions: []accesscontrol.Permission{{Action: "users:read", Scope: "users:*"}}, }, + teamService: &teamtest.FakeService{}, expectedStatus: http.StatusOK, }, { @@ -58,6 +62,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { acService: &actest.FakeService{}, userCache: &usertest.FakeUserService{}, ctxSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{1: {"users:read": {"users:*"}}}}, + teamService: &teamtest.FakeService{}, expectedStatus: http.StatusOK, }, { @@ -69,6 +74,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { accessControl: ac, userCache: &usertest.FakeUserService{}, ctxSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{}}, + teamService: &teamtest.FakeService{}, acService: &actest.FakeService{}, expectedStatus: http.StatusForbidden, }, @@ -80,9 +86,12 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { evaluator: accesscontrol.EvalPermission("users:read", "users:*"), accessControl: ac, userCache: &usertest.FakeUserService{}, - ctxSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{accesscontrol.GlobalOrgID: {"users:read": {"users:*"}}}}, - acService: &actest.FakeService{}, - expectedStatus: http.StatusOK, + ctxSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{1: {"users:read": {"users:*"}}}}, + teamService: &teamtest.FakeService{}, + acService: &actest.FakeService{ + ExpectedPermissions: []accesscontrol.Permission{{Action: "users:read", Scope: "users:*"}}, + }, + expectedStatus: http.StatusOK, }, { name: "should return 403 when user has no permissions for a global org", @@ -93,6 +102,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { accessControl: ac, userCache: &usertest.FakeUserService{}, ctxSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{1: {"users:read": {"users:*"}}}}, + teamService: &teamtest.FakeService{}, acService: &actest.FakeService{}, expectedStatus: http.StatusForbidden, }, @@ -106,6 +116,20 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { userCache: &usertest.FakeUserService{ExpectedError: fmt.Errorf("user not found")}, acService: &actest.FakeService{}, ctxSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{1: {"users:read": {"users:*"}}}}, + teamService: &teamtest.FakeService{}, + expectedStatus: http.StatusForbidden, + }, + { + name: "should return 403 early when api key org ID doesn't match", + orgIDGetter: func(c *contextmodel.ReqContext) (int64, error) { + return 2, nil + }, + evaluator: accesscontrol.EvalPermission("users:read", "users:*"), + accessControl: ac, + userCache: &usertest.FakeUserService{}, + acService: &actest.FakeService{}, + ctxSignedInUser: &user.SignedInUser{ApiKeyID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{1: {"users:read": {"users:*"}}}}, + teamService: &teamtest.FakeService{}, expectedStatus: http.StatusForbidden, }, { @@ -118,6 +142,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { acService: &actest.FakeService{ ExpectedPermissions: []accesscontrol.Permission{{Action: "users:read", Scope: "users:*"}}, }, + teamService: &teamtest.FakeService{}, userCache: &usertest.FakeUserService{ GetSignedInUserFn: func(ctx context.Context, query *user.GetSignedInUserQuery) (*user.SignedInUser, error) { return &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: nil}, nil @@ -133,6 +158,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { }, evaluator: accesscontrol.EvalPermission("users:read", "users:*"), accessControl: ac, + teamService: &teamtest.FakeService{}, acService: &actest.FakeService{ ExpectedPermissions: []accesscontrol.Permission{{Action: "users:read", Scope: "users:*"}}, }, @@ -151,6 +177,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { }, evaluator: accesscontrol.EvalPermission("users:read", "users:*"), accessControl: ac, + teamService: &teamtest.FakeService{}, acService: &actest.FakeService{ ExpectedErr: fmt.Errorf("failed to get user permissions"), }, @@ -172,6 +199,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { acService: &actest.FakeService{}, userCache: &usertest.FakeUserService{}, ctxSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{1: {"users:read": {"users:*"}}}}, + teamService: &teamtest.FakeService{}, expectedStatus: http.StatusForbidden, }, } @@ -189,6 +217,7 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) { tc.accessControl, service, tc.userCache, + tc.teamService, )(tc.orgIDGetter, tc.evaluator) // Create test server diff --git a/pkg/services/accesscontrol/database/database_test.go b/pkg/services/accesscontrol/database/database_test.go index 567f13ea7b6..e21794867ab 100644 --- a/pkg/services/accesscontrol/database/database_test.go +++ b/pkg/services/accesscontrol/database/database_test.go @@ -13,7 +13,7 @@ import ( "github.com/grafana/grafana/pkg/infra/localcache" "github.com/grafana/grafana/pkg/services/accesscontrol" rs "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org/orgimpl" @@ -248,7 +248,7 @@ func createUserAndTeam(t *testing.T, userSrv user.Service, teamSvc team.Service, team, err := teamSvc.CreateTeam("team", "", orgID) require.NoError(t, err) - err = teamSvc.AddTeamMember(user.ID, orgID, team.ID, false, dashboards.PERMISSION_VIEW) + err = teamSvc.AddTeamMember(user.ID, orgID, team.ID, false, dashboardaccess.PERMISSION_VIEW) require.NoError(t, err) return user, team @@ -296,7 +296,7 @@ func createUsersAndTeams(t *testing.T, svcs helperServices, orgID int64, users [ team, err := svcs.teamSvc.CreateTeam(fmt.Sprintf("team%v", i+1), "", orgID) require.NoError(t, err) - err = svcs.teamSvc.AddTeamMember(user.ID, orgID, team.ID, false, dashboards.PERMISSION_VIEW) + err = svcs.teamSvc.AddTeamMember(user.ID, orgID, team.ID, false, dashboardaccess.PERMISSION_VIEW) require.NoError(t, err) err = svcs.orgSvc.UpdateOrgUser(context.Background(), diff --git a/pkg/services/accesscontrol/middleware.go b/pkg/services/accesscontrol/middleware.go index 573674b3e66..6c76060542d 100644 --- a/pkg/services/accesscontrol/middleware.go +++ b/pkg/services/accesscontrol/middleware.go @@ -19,6 +19,7 @@ import ( "github.com/grafana/grafana/pkg/services/authn" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" @@ -179,60 +180,108 @@ type userCache interface { GetSignedInUserWithCacheCtx(ctx context.Context, query *user.GetSignedInUserQuery) (*user.SignedInUser, error) } -func AuthorizeInOrgMiddleware(ac AccessControl, service Service, cache userCache) func(OrgIDGetter, Evaluator) web.Handler { +type teamService interface { + GetTeamIDsByUser(ctx context.Context, query *team.GetTeamIDsByUserQuery) ([]int64, error) +} + +func AuthorizeInOrgMiddleware(ac AccessControl, service Service, userService userCache, teamService teamService) func(OrgIDGetter, Evaluator) web.Handler { return func(getTargetOrg OrgIDGetter, evaluator Evaluator) web.Handler { return func(c *contextmodel.ReqContext) { - // We need to copy the user here because we're going to mutate it - userCopy := *(c.SignedInUser) targetOrgID, err := getTargetOrg(c) if err != nil { deny(c, nil, fmt.Errorf("failed to get target org: %w", err)) return } - if userCopy.OrgID != targetOrgID { - switch targetOrgID { - case GlobalOrgID: - userCopy.OrgID = GlobalOrgID - userCopy.OrgRole = org.RoleNone - userCopy.OrgName = "" - default: - query := user.GetSignedInUserQuery{UserID: c.UserID, OrgID: targetOrgID} - queryResult, err := cache.GetSignedInUserWithCacheCtx(c.Req.Context(), &query) - if err != nil { - deny(c, nil, fmt.Errorf("failed to authenticate user in target org: %w", err)) - return - } - userCopy.OrgID = queryResult.OrgID - userCopy.OrgName = queryResult.OrgName - userCopy.OrgRole = queryResult.OrgRole - } + tmpUser, err := makeTmpUser(c.Req.Context(), service, userService, teamService, c.SignedInUser, targetOrgID) + if err != nil { + deny(c, nil, fmt.Errorf("failed to authenticate user in target org: %w", err)) + return } - if userCopy.Permissions[targetOrgID] == nil { - permissions, err := service.GetUserPermissions(c.Req.Context(), &userCopy, Options{}) - if err != nil { - deny(c, nil, fmt.Errorf("failed to authenticate user in target org: %w", err)) - } - - // guard against nil map - if userCopy.Permissions == nil { - userCopy.Permissions = make(map[int64]map[string][]string) - } - userCopy.Permissions[targetOrgID] = GroupScopesByAction(permissions) - } - - authorize(c, ac, &userCopy, evaluator) + authorize(c, ac, tmpUser, evaluator) // guard against nil map if c.SignedInUser.Permissions == nil { c.SignedInUser.Permissions = make(map[int64]map[string][]string) } - c.SignedInUser.Permissions[targetOrgID] = userCopy.Permissions[targetOrgID] + c.SignedInUser.Permissions[tmpUser.GetOrgID()] = tmpUser.GetPermissions() } } } +// makeTmpUser creates a temporary user that can be used to evaluate access across orgs. +func makeTmpUser(ctx context.Context, service Service, cache userCache, + teamService teamService, reqUser identity.Requester, targetOrgID int64) (identity.Requester, error) { + tmpUser := &user.SignedInUser{ + OrgID: reqUser.GetOrgID(), + OrgName: reqUser.GetOrgName(), + OrgRole: reqUser.GetOrgRole(), + IsGrafanaAdmin: reqUser.GetIsGrafanaAdmin(), + Login: reqUser.GetLogin(), + Teams: reqUser.GetTeams(), + Permissions: map[int64]map[string][]string{ + reqUser.GetOrgID(): reqUser.GetPermissions(), + }, + } + + namespace, identifier := reqUser.GetNamespacedID() + id, _ := identity.IntIdentifier(namespace, identifier) + switch namespace { + case identity.NamespaceUser: + tmpUser.UserID = id + case identity.NamespaceAPIKey: + tmpUser.ApiKeyID = id + if tmpUser.OrgID != targetOrgID { + return nil, errors.New("API key does not belong to target org") + } + case identity.NamespaceServiceAccount: + tmpUser.UserID = id + tmpUser.IsServiceAccount = true + } + + if tmpUser.OrgID != targetOrgID { + switch targetOrgID { + case GlobalOrgID: + tmpUser.OrgID = GlobalOrgID + tmpUser.OrgRole = org.RoleNone + tmpUser.OrgName = "" + tmpUser.Teams = []int64{} + default: + if cache == nil { + return nil, errors.New("user cache is nil") + } + query := user.GetSignedInUserQuery{UserID: tmpUser.UserID, OrgID: targetOrgID} + queryResult, err := cache.GetSignedInUserWithCacheCtx(ctx, &query) + if err != nil { + return nil, err + } + tmpUser.OrgID = queryResult.OrgID + tmpUser.OrgName = queryResult.OrgName + tmpUser.OrgRole = queryResult.OrgRole + + if teamService != nil { + teamIDs, err := teamService.GetTeamIDsByUser(ctx, &team.GetTeamIDsByUserQuery{OrgID: targetOrgID, UserID: tmpUser.UserID}) + if err != nil { + return nil, err + } + tmpUser.Teams = teamIDs + } + } + } + + if tmpUser.Permissions[targetOrgID] == nil || len(tmpUser.Permissions[targetOrgID]) == 0 { + permissions, err := service.GetUserPermissions(ctx, tmpUser, Options{}) + if err != nil { + return nil, err + } + + tmpUser.Permissions[targetOrgID] = GroupScopesByAction(permissions) + } + + return tmpUser, nil +} + func UseOrgFromContextParams(c *contextmodel.ReqContext) (int64, error) { orgID, err := strconv.ParseInt(web.Params(c.Req)[":orgId"], 10, 64) diff --git a/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go b/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go index 7841365e725..5c5725ac55f 100644 --- a/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go +++ b/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions" "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/libraryelements" @@ -87,7 +88,7 @@ func ProvideTeamPermissions( case "Member": return teamimpl.AddOrUpdateTeamMemberHook(session, user.ID, orgID, teamId, user.IsExternal, 0) case "Admin": - return teamimpl.AddOrUpdateTeamMemberHook(session, user.ID, orgID, teamId, user.IsExternal, dashboards.PERMISSION_ADMIN) + return teamimpl.AddOrUpdateTeamMemberHook(session, user.ID, orgID, teamId, user.IsExternal, dashboardaccess.PERMISSION_ADMIN) case "": return teamimpl.RemoveTeamMemberHook(session, &team.RemoveTeamMemberCommand{ OrgID: orgID, diff --git a/pkg/services/alerting/store.go b/pkg/services/alerting/store.go index 40e80ab903d..762c110fbc0 100644 --- a/pkg/services/alerting/store.go +++ b/pkg/services/alerting/store.go @@ -10,7 +10,7 @@ import ( "github.com/grafana/grafana/pkg/infra/localcache" "github.com/grafana/grafana/pkg/infra/log" alertmodels "github.com/grafana/grafana/pkg/services/alerting/models" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/tag" "github.com/grafana/grafana/pkg/setting" @@ -167,7 +167,7 @@ func (ss *sqlStore) HandleAlertsQuery(ctx context.Context, query *alertmodels.Ge builder.Write(")") } - builder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW, "") + builder.WriteDashboardPermissionFilter(query.User, dashboardaccess.PERMISSION_VIEW, "") builder.Write(" ORDER BY name ASC") diff --git a/pkg/services/annotations/accesscontrol/accesscontrol.go b/pkg/services/annotations/accesscontrol/accesscontrol.go index 96092254820..67bdaa5f441 100644 --- a/pkg/services/annotations/accesscontrol/accesscontrol.go +++ b/pkg/services/annotations/accesscontrol/accesscontrol.go @@ -7,7 +7,7 @@ import ( ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/auth/identity" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/sqlstore/permissions" "github.com/grafana/grafana/pkg/services/sqlstore/searchstore" @@ -74,7 +74,7 @@ func (authz *AuthService) userVisibleDashboards(ctx context.Context, user identi } filters := []any{ - permissions.NewAccessControlDashboardPermissionFilter(user, dashboards.PERMISSION_VIEW, searchstore.TypeDashboard, authz.features, recursiveQueriesSupported), + permissions.NewAccessControlDashboardPermissionFilter(user, dashboardaccess.PERMISSION_VIEW, searchstore.TypeDashboard, authz.features, recursiveQueriesSupported), searchstore.OrgFilter{OrgId: orgID}, } diff --git a/pkg/services/dashboards/dashboard_acl.go b/pkg/services/dashboards/dashboardaccess/dashboard_access.go similarity index 97% rename from pkg/services/dashboards/dashboard_acl.go rename to pkg/services/dashboards/dashboardaccess/dashboard_access.go index 2068e7d5832..7711fe2a0a7 100644 --- a/pkg/services/dashboards/dashboard_acl.go +++ b/pkg/services/dashboards/dashboardaccess/dashboard_access.go @@ -1,4 +1,4 @@ -package dashboards +package dashboardaccess import ( "errors" diff --git a/pkg/services/dashboards/dashboard_acl_test.go b/pkg/services/dashboards/dashboardaccess/dashboard_access_test.go similarity index 95% rename from pkg/services/dashboards/dashboard_acl_test.go rename to pkg/services/dashboards/dashboardaccess/dashboard_access_test.go index 97ba21dd58a..19f22eb199c 100644 --- a/pkg/services/dashboards/dashboard_acl_test.go +++ b/pkg/services/dashboards/dashboardaccess/dashboard_access_test.go @@ -1,4 +1,4 @@ -package dashboards +package dashboardaccess import ( "fmt" diff --git a/pkg/services/dashboards/models.go b/pkg/services/dashboards/models.go index ba05e65e174..6ecdd9b0e89 100644 --- a/pkg/services/dashboards/models.go +++ b/pkg/services/dashboards/models.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/kinds/dashboard" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/auth/identity" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/quota" @@ -419,7 +420,7 @@ type DashboardACL struct { UserID int64 `xorm:"user_id"` TeamID int64 `xorm:"team_id"` Role *org.RoleType // pointer to be nullable - Permission PermissionType + Permission dashboardaccess.PermissionType Created time.Time Updated time.Time @@ -437,23 +438,23 @@ type DashboardACLInfoDTO struct { Created time.Time `json:"created"` Updated time.Time `json:"updated"` - UserID int64 `json:"userId" xorm:"user_id"` - UserLogin string `json:"userLogin"` - UserEmail string `json:"userEmail"` - UserAvatarURL string `json:"userAvatarUrl" xorm:"user_avatar_url"` - TeamID int64 `json:"teamId" xorm:"team_id"` - TeamEmail string `json:"teamEmail"` - TeamAvatarURL string `json:"teamAvatarUrl" xorm:"team_avatar_url"` - Team string `json:"team"` - Role *org.RoleType `json:"role,omitempty"` - Permission PermissionType `json:"permission"` - PermissionName string `json:"permissionName"` - UID string `json:"uid" xorm:"uid"` - Title string `json:"title"` - Slug string `json:"slug"` - IsFolder bool `json:"isFolder"` - URL string `json:"url" xorm:"url"` - Inherited bool `json:"inherited"` + UserID int64 `json:"userId" xorm:"user_id"` + UserLogin string `json:"userLogin"` + UserEmail string `json:"userEmail"` + UserAvatarURL string `json:"userAvatarUrl" xorm:"user_avatar_url"` + TeamID int64 `json:"teamId" xorm:"team_id"` + TeamEmail string `json:"teamEmail"` + TeamAvatarURL string `json:"teamAvatarUrl" xorm:"team_avatar_url"` + Team string `json:"team"` + Role *org.RoleType `json:"role,omitempty"` + Permission dashboardaccess.PermissionType `json:"permission"` + PermissionName string `json:"permissionName"` + UID string `json:"uid" xorm:"uid"` + Title string `json:"title"` + Slug string `json:"slug"` + IsFolder bool `json:"isFolder"` + URL string `json:"url" xorm:"url"` + Inherited bool `json:"inherited"` } func (dto *DashboardACLInfoDTO) hasSameRoleAs(other *DashboardACLInfoDTO) bool { @@ -490,7 +491,7 @@ type FindPersistedDashboardsQuery struct { Tags []string Limit int64 Page int64 - Permission PermissionType + Permission dashboardaccess.PermissionType Sort model.SortOption Filters []any diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 8dfa7c308eb..27713908a23 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" @@ -502,15 +503,15 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto * dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err) } else if namespaceID == identity.NamespaceUser && userID > 0 { permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ - UserID: userID, Permission: dashboards.PERMISSION_ADMIN.String(), + UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(), }) } } if !inFolder { permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }...) } diff --git a/pkg/services/libraryelements/database.go b/pkg/services/libraryelements/database.go index a3a7bdd56de..3622bbd59a9 100644 --- a/pkg/services/libraryelements/database.go +++ b/pkg/services/libraryelements/database.go @@ -14,6 +14,7 @@ import ( ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/libraryelements/model" "github.com/grafana/grafana/pkg/services/org" @@ -288,7 +289,7 @@ func (l *LibraryElementService) getLibraryElements(c context.Context, store db.D builder.Write(getFromLibraryElementDTOWithMeta(store.GetDialect())) builder.Write(" INNER JOIN dashboard AS dashboard on le.folder_id = dashboard.id AND le.folder_id <> 0") writeParamSelectorSQL(&builder, params...) - builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW, "") + builder.WriteDashboardPermissionFilter(signedInUser, dashboardaccess.PERMISSION_VIEW, "") builder.Write(` OR dashboard.id=0`) if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryElements); err != nil { return err @@ -421,7 +422,7 @@ func (l *LibraryElementService) getAllLibraryElements(c context.Context, signedI return err } if !signedInUser.HasRole(org.RoleAdmin) { - builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW, "") + builder.WriteDashboardPermissionFilter(signedInUser, dashboardaccess.PERMISSION_VIEW, "") } if query.SortDirection == search.SortAlphaDesc.Name { builder.Write(" ORDER BY 1 DESC") @@ -665,7 +666,7 @@ func (l *LibraryElementService) getConnections(c context.Context, signedInUser i builder.Write(" INNER JOIN dashboard AS dashboard on lec.connection_id = dashboard.id") builder.Write(` WHERE lec.element_id=?`, element.ID) if signedInUser.GetOrgRole() != org.RoleAdmin { - builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW, "") + builder.WriteDashboardPermissionFilter(signedInUser, dashboardaccess.PERMISSION_VIEW, "") } if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryElementConnections); err != nil { return err diff --git a/pkg/services/ngalert/migration/permissions.go b/pkg/services/ngalert/migration/permissions.go index 70a6e0aa134..c05e98782a6 100644 --- a/pkg/services/ngalert/migration/permissions.go +++ b/pkg/services/ngalert/migration/permissions.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/folder" migmodels "github.com/grafana/grafana/pkg/services/ngalert/migration/models" @@ -42,12 +43,12 @@ var ( // generalAlertingFolderTitle is the title of the general alerting folder. This is used for dashboard alerts in the general folder. generalAlertingFolderTitle = "General Alerting" - // permissionMap maps the "friendly" permission name for a ResourcePermissions actions to the dashboards.PermissionType. + // permissionMap maps the "friendly" permission name for a ResourcePermissions actions to the dashboardaccess.PermissionType. // A sort of reverse accesscontrol Service.MapActions similar to api.dashboardPermissionMap. - permissionMap = map[string]dashboards.PermissionType{ - "View": dashboards.PERMISSION_VIEW, - "Edit": dashboards.PERMISSION_EDIT, - "Admin": dashboards.PERMISSION_ADMIN, + permissionMap = map[string]dashboardaccess.PermissionType{ + "View": dashboardaccess.PERMISSION_VIEW, + "Edit": dashboardaccess.PERMISSION_EDIT, + "Admin": dashboardaccess.PERMISSION_ADMIN, } ) @@ -186,11 +187,11 @@ func isBasic(roleName string) bool { // There are two role types that we consider: // - managed (ex. managed:users:1:permissions, managed:builtins:editor:permissions, managed:teams:1:permissions): // These are the only roles that exist in OSS. For each of these roles, we add the actions of the highest -// dashboards.PermissionType between the folder and the dashboard. Permissions from the folder are inherited. +// dashboardaccess.PermissionType between the folder and the dashboard. Permissions from the folder are inherited. // The added actions should have scope=folder:uid:xxxxxx, where xxxxxx is the new folder uid. // - basic (ex. basic:admin, basic:editor): // These are roles used in enterprise. Every user should have one of these roles. They should be considered -// equivalent to managed:builtins. The highest dashboards.PermissionType between the two should be used. +// equivalent to managed:builtins. The highest dashboardaccess.PermissionType between the two should be used. // // There are two role types that we do not consider: // - fixed: (ex. fixed:dashboards:reader, fixed:dashboards:writer): @@ -205,7 +206,7 @@ func isBasic(roleName string) bool { // For now, we choose the simpler approach of handling managed and basic roles. Fixed and custom roles will not // be taken into account, but we will log a warning if they had the potential to override the folder permissions. func (om *OrgMigration) convertResourcePerms(rperms []accesscontrol.ResourcePermission) ([]accesscontrol.SetResourcePermissionCommand, []accesscontrol.ResourcePermission) { - keep := make(map[accesscontrol.SetResourcePermissionCommand]dashboards.PermissionType) + keep := make(map[accesscontrol.SetResourcePermissionCommand]dashboardaccess.PermissionType) unusedPerms := make([]accesscontrol.ResourcePermission, 0) for _, p := range rperms { if p.IsManaged || p.IsInherited || isBasic(p.RoleName) { @@ -254,8 +255,8 @@ func (om *OrgMigration) convertResourcePerms(rperms []accesscontrol.ResourcePerm // potentialOverrides returns a map of roles from unusedOldPerms that have dashboard permissions that could potentially // override the given folder permissions in newPerms. These overrides are always to increase permissions not decrease them. -func potentialOverrides(unusedOldPerms []accesscontrol.ResourcePermission, newPerms []accesscontrol.SetResourcePermissionCommand) map[string]dashboards.PermissionType { - var lowestPermission dashboards.PermissionType +func potentialOverrides(unusedOldPerms []accesscontrol.ResourcePermission, newPerms []accesscontrol.SetResourcePermissionCommand) map[string]dashboardaccess.PermissionType { + var lowestPermission dashboardaccess.PermissionType for _, p := range newPerms { if p.BuiltinRole == string(org.RoleEditor) || p.BuiltinRole == string(org.RoleViewer) { pType := permissionMap[p.Permission] @@ -265,18 +266,18 @@ func potentialOverrides(unusedOldPerms []accesscontrol.ResourcePermission, newPe } } - nonManagedPermissionTypes := make(map[string]dashboards.PermissionType) + nonManagedPermissionTypes := make(map[string]dashboardaccess.PermissionType) for _, p := range unusedOldPerms { existing, ok := nonManagedPermissionTypes[p.RoleName] - if ok && existing == dashboards.PERMISSION_EDIT { + if ok && existing == dashboardaccess.PERMISSION_EDIT { // We've already handled the highest permission we care about, no need to check this role anymore. continue } if p.Contains([]string{dashboards.ActionDashboardsWrite}) { - existing = dashboards.PERMISSION_EDIT + existing = dashboardaccess.PERMISSION_EDIT } else if p.Contains([]string{dashboards.ActionDashboardsRead}) { - existing = dashboards.PERMISSION_VIEW + existing = dashboardaccess.PERMISSION_VIEW } if existing > lowestPermission && existing > nonManagedPermissionTypes[p.RoleName] { diff --git a/pkg/services/ngalert/migration/permissions_test.go b/pkg/services/ngalert/migration/permissions_test.go index bc52ddce191..f74129f1d1f 100644 --- a/pkg/services/ngalert/migration/permissions_test.go +++ b/pkg/services/ngalert/migration/permissions_test.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol" "github.com/grafana/grafana/pkg/services/alerting/models" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" ngModels "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/team" @@ -245,8 +246,8 @@ func TestDashAlertPermissionMigration(t *testing.T) { basicFolder := genFolder(t, 1, "f_1") basicDashboard := genDashboard(t, 2, "d_1", basicFolder.ID) defaultPerms := genPerms( - accesscontrol.SetResourcePermissionCommand{BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - accesscontrol.SetResourcePermissionCommand{BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + accesscontrol.SetResourcePermissionCommand{BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + accesscontrol.SetResourcePermissionCommand{BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, ) basicAlert1 := genLegacyAlert("alert1", basicDashboard.ID, func(a *models.Alert) { a.PanelID = 1 }) @@ -304,8 +305,8 @@ func TestDashAlertPermissionMigration(t *testing.T) { dashboards: []*dashboards.Dashboard{basicDashboard}, dashboardPerms: map[string][]accesscontrol.SetResourcePermissionCommand{ basicDashboard.UID: { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_VIEW.String()}, // Change. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_VIEW.String()}, // Change. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, }, alerts: []*models.Alert{basicAlert1}, @@ -314,8 +315,8 @@ func TestDashAlertPermissionMigration(t *testing.T) { Alert: genAlert(basicAlert1.Name, basicFolder.UID, basicDashboard.UID), Folder: basicFolder, Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, // Inherits from Folder. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // Inherits from Folder. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, }, }, @@ -333,24 +334,24 @@ func TestDashAlertPermissionMigration(t *testing.T) { }, dashboardPerms: map[string][]accesscontrol.SetResourcePermissionCommand{ "d_1": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_EDIT.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // Change. }, "d_2": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. }, "d_3": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_EDIT.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // Change. }, "d_4": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, "d_5": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. }, }, alerts: []*models.Alert{genLegacyAlert("alert1", 2), genLegacyAlert("alert2", 3), genLegacyAlert("alert3", 4), genLegacyAlert("alert4", 5), genLegacyAlert("alert5", 6)}, @@ -359,40 +360,40 @@ func TestDashAlertPermissionMigration(t *testing.T) { Alert: genAlert("alert1", "", "d_1"), Folder: genCreatedFolder(t, "Original Folder f_1 Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_EDIT.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // Change. }, }, { Alert: genAlert("alert2", "", "d_2"), Folder: genCreatedFolder(t, "Original Folder f_1 Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. }, }, { Alert: genAlert("alert3", "", "d_3"), Folder: genCreatedFolder(t, "Original Folder f_1 Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_EDIT.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // Change. }, }, { Alert: genAlert("alert4", "", "d_4"), Folder: genCreatedFolder(t, "Original Folder f_1 Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, }, { Alert: genAlert("alert5", "", "d_5"), Folder: genCreatedFolder(t, "Original Folder f_1 Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Change. }, }, }, @@ -402,12 +403,12 @@ func TestDashAlertPermissionMigration(t *testing.T) { folders: []*dashboards.Dashboard{genFolder(t, 1, "f_1"), genFolder(t, 2, "f_2")}, folderPerms: map[string][]accesscontrol.SetResourcePermissionCommand{ "f_1": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_ADMIN.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, }, "f_2": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_VIEW.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, }, dashboards: []*dashboards.Dashboard{ @@ -418,16 +419,16 @@ func TestDashAlertPermissionMigration(t *testing.T) { }, dashboardPerms: map[string][]accesscontrol.SetResourcePermissionCommand{ "d_1": { - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, "d_2": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, }, "d_3": { - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, "d_4": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, }, }, alerts: []*models.Alert{genLegacyAlert("alert1", 3), genLegacyAlert("alert2", 4), genLegacyAlert("alert3", 5), genLegacyAlert("alert4", 6)}, @@ -436,32 +437,32 @@ func TestDashAlertPermissionMigration(t *testing.T) { Alert: genAlert("alert1", "f_1", "d_1"), Folder: genFolder(t, 1, "f_1"), // Original folder since the perms didn't change. Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, // Inherits from Folder. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_ADMIN.String()}, // Overrides from Folder. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Inherits from Folder. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Overrides from Folder. }, }, { Alert: genAlert("alert2", "f_1", "d_2"), Folder: genFolder(t, 1, "f_1"), // Original folder since the perms didn't change. Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_ADMIN.String()}, // Overrides from Folder. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_ADMIN.String()}, // Inherits from Folder. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Overrides from Folder. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // Inherits from Folder. }, }, { Alert: genAlert("alert3", "f_2", "d_3"), Folder: genFolder(t, 2, "f_2"), // Original folder since the perms didn't change. Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_VIEW.String()}, // Inherits from Folder. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_VIEW.String()}, // Inherits from Folder. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, }, { Alert: genAlert("alert4", "", "d_4"), Folder: genCreatedFolder(t, "Original Folder f_2 Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, // Inherits from Folder. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, // Inherits from Folder. }, }, }, @@ -471,13 +472,13 @@ func TestDashAlertPermissionMigration(t *testing.T) { folders: []*dashboards.Dashboard{basicFolder}, folderPerms: map[string][]accesscontrol.SetResourcePermissionCommand{ basicFolder.UID: { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, }, }, dashboards: []*dashboards.Dashboard{basicDashboard}, dashboardPerms: map[string][]accesscontrol.SetResourcePermissionCommand{ basicDashboard.UID: { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_VIEW.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_VIEW.String()}, }, }, alerts: []*models.Alert{basicAlert1}, @@ -486,7 +487,7 @@ func TestDashAlertPermissionMigration(t *testing.T) { Alert: genAlert(basicAlert1.Name, basicFolder.UID, basicDashboard.UID), Folder: basicFolder, Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, }, }, }, @@ -505,8 +506,8 @@ func TestDashAlertPermissionMigration(t *testing.T) { Alert: genAlert("alert1", "f_1", "d_1"), Folder: genCreatedFolder(t, "General Alerting Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, // From Dashboard. - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, // From Dashboard. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // From Dashboard. + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, // From Dashboard. }, }, }, @@ -516,7 +517,7 @@ func TestDashAlertPermissionMigration(t *testing.T) { dashboards: []*dashboards.Dashboard{genDashboard(t, 1, "d_1", 0)}, // Dashboard in general folder. dashboardPerms: map[string][]accesscontrol.SetResourcePermissionCommand{ "d_1": { // Missing viewer. - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, }, }, alerts: []*models.Alert{genLegacyAlert("alert1", 1)}, @@ -525,7 +526,7 @@ func TestDashAlertPermissionMigration(t *testing.T) { Alert: genAlert("alert1", "f_1", "d_1"), Folder: genCreatedFolder(t, "General Alerting Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, // From Dashboard. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // From Dashboard. }, }, }, @@ -555,8 +556,8 @@ func TestDashAlertPermissionMigration(t *testing.T) { }, dashboardPerms: map[string][]accesscontrol.SetResourcePermissionCommand{ "d_1": { - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_EDIT.String()}, // Change. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // Change. }, }, alerts: []*models.Alert{genLegacyAlert("alert1", 2)}, @@ -565,9 +566,9 @@ func TestDashAlertPermissionMigration(t *testing.T) { Alert: genAlert("alert1", "", "d_1"), Folder: genCreatedFolder(t, "Original Folder f_1 Alerts - %s"), Perms: []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleAdmin), Permission: dashboards.PERMISSION_ADMIN.String()}, // From basic:admin. - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_EDIT.String()}, // Change. + {BuiltinRole: string(org.RoleAdmin), Permission: dashboardaccess.PERMISSION_ADMIN.String()}, // From basic:admin. + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_EDIT.String()}, // Change. }, }, }, @@ -699,7 +700,7 @@ func TestDashAlertPermissionMigration(t *testing.T) { expected.Alert.NamespaceUID = "" } - keep := make(map[accesscontrol.SetResourcePermissionCommand]dashboards.PermissionType) + keep := make(map[accesscontrol.SetResourcePermissionCommand]dashboardaccess.PermissionType) for _, p := range rperms { if permission := service.migrationStore.MapActions(p); permission != "" { sp := accesscontrol.SetResourcePermissionCommand{ diff --git a/pkg/services/ngalert/store/alert_rule.go b/pkg/services/ngalert/store/alert_rule.go index 1fc475fc9e2..3c7ba5027fd 100644 --- a/pkg/services/ngalert/store/alert_rule.go +++ b/pkg/services/ngalert/store/alert_rule.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/folder" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/search/model" @@ -433,7 +434,7 @@ func (st DBstore) GetUserVisibleNamespaces(ctx context.Context, orgID int64, use SignedInUser: user, Type: searchstore.TypeAlertFolder, Limit: -1, - Permission: dashboards.PERMISSION_VIEW, + Permission: dashboardaccess.PERMISSION_VIEW, Sort: model.SortOption{}, Filters: []any{ searchstore.FolderWithAlertsFilter{}, diff --git a/pkg/services/publicdashboards/database/database.go b/pkg/services/publicdashboards/database/database.go index d4a214d7364..f53ee24ddc3 100644 --- a/pkg/services/publicdashboards/database/database.go +++ b/pkg/services/publicdashboards/database/database.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/publicdashboards" @@ -59,7 +60,7 @@ func (d *PublicDashboardStoreImpl) FindAllWithPagination(ctx context.Context, qu pubdashBuilder.Write(" JOIN dashboard ON dashboard.uid = dashboard_public.dashboard_uid AND dashboard.org_id = dashboard_public.org_id") pubdashBuilder.Write(` WHERE dashboard_public.org_id = ?`, query.OrgID) if query.User.OrgRole != org.RoleAdmin { - pubdashBuilder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW, searchstore.TypeDashboard) + pubdashBuilder.WriteDashboardPermissionFilter(query.User, dashboardaccess.PERMISSION_VIEW, searchstore.TypeDashboard) } pubdashBuilder.Write(" ORDER BY dashboard.title") pubdashBuilder.Write(d.sqlStore.GetDialect().LimitOffset(int64(query.Limit), int64(query.Offset))) @@ -70,7 +71,7 @@ func (d *PublicDashboardStoreImpl) FindAllWithPagination(ctx context.Context, qu counterBuilder.Write(" JOIN dashboard ON dashboard.uid = dashboard_public.dashboard_uid AND dashboard.org_id = dashboard_public.org_id") counterBuilder.Write(` WHERE dashboard_public.org_id = ?`, query.OrgID) if query.User.OrgRole != org.RoleAdmin { - counterBuilder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW, searchstore.TypeDashboard) + counterBuilder.WriteDashboardPermissionFilter(query.User, dashboardaccess.PERMISSION_VIEW, searchstore.TypeDashboard) } err = d.sqlStore.WithDbSession(ctx, func(sess *db.Session) error { diff --git a/pkg/services/search/service.go b/pkg/services/search/service.go index 463be58bedb..bfaa9daacc7 100644 --- a/pkg/services/search/service.go +++ b/pkg/services/search/service.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/search/model" "github.com/grafana/grafana/pkg/services/star" "github.com/grafana/grafana/pkg/services/user" @@ -40,7 +41,7 @@ type Query struct { // Deprecated: use FolderUID instead FolderIds []int64 FolderUIDs []string - Permission dashboards.PermissionType + Permission dashboardaccess.PermissionType Sort string } diff --git a/pkg/services/sqlstore/migrations/accesscontrol/dashboard_permissions.go b/pkg/services/sqlstore/migrations/accesscontrol/dashboard_permissions.go index 083a6fe2196..91bec67adba 100644 --- a/pkg/services/sqlstore/migrations/accesscontrol/dashboard_permissions.go +++ b/pkg/services/sqlstore/migrations/accesscontrol/dashboard_permissions.go @@ -10,19 +10,20 @@ import ( ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" ) -var dashboardPermissionTranslation = map[dashboards.PermissionType][]string{ - dashboards.PERMISSION_VIEW: { +var dashboardPermissionTranslation = map[dashboardaccess.PermissionType][]string{ + dashboardaccess.PERMISSION_VIEW: { dashboards.ActionDashboardsRead, }, - dashboards.PERMISSION_EDIT: { + dashboardaccess.PERMISSION_EDIT: { dashboards.ActionDashboardsRead, dashboards.ActionDashboardsWrite, dashboards.ActionDashboardsDelete, }, - dashboards.PERMISSION_ADMIN: { + dashboardaccess.PERMISSION_ADMIN: { dashboards.ActionDashboardsRead, dashboards.ActionDashboardsWrite, dashboards.ActionDashboardsCreate, @@ -32,17 +33,17 @@ var dashboardPermissionTranslation = map[dashboards.PermissionType][]string{ }, } -var folderPermissionTranslation = map[dashboards.PermissionType][]string{ - dashboards.PERMISSION_VIEW: append(dashboardPermissionTranslation[dashboards.PERMISSION_VIEW], []string{ +var folderPermissionTranslation = map[dashboardaccess.PermissionType][]string{ + dashboardaccess.PERMISSION_VIEW: append(dashboardPermissionTranslation[dashboardaccess.PERMISSION_VIEW], []string{ dashboards.ActionFoldersRead, }...), - dashboards.PERMISSION_EDIT: append(dashboardPermissionTranslation[dashboards.PERMISSION_EDIT], []string{ + dashboardaccess.PERMISSION_EDIT: append(dashboardPermissionTranslation[dashboardaccess.PERMISSION_EDIT], []string{ dashboards.ActionDashboardsCreate, dashboards.ActionFoldersRead, dashboards.ActionFoldersWrite, dashboards.ActionFoldersDelete, }...), - dashboards.PERMISSION_ADMIN: append(dashboardPermissionTranslation[dashboards.PERMISSION_ADMIN], []string{ + dashboardaccess.PERMISSION_ADMIN: append(dashboardPermissionTranslation[dashboardaccess.PERMISSION_ADMIN], []string{ dashboards.ActionFoldersRead, dashboards.ActionFoldersWrite, dashboards.ActionFoldersDelete, @@ -111,11 +112,11 @@ func (m dashboardPermissionsMigrator) migratePermissions(dashes []dashboard, acl if (d.IsFolder || d.FolderID == 0) && len(acls) == 0 && !d.HasAcl { permissionMap[d.OrgID]["managed:builtins:editor:permissions"] = append( permissionMap[d.OrgID]["managed:builtins:editor:permissions"], - m.mapPermission(d.ID, dashboards.PERMISSION_EDIT, d.IsFolder)..., + m.mapPermission(d.ID, dashboardaccess.PERMISSION_EDIT, d.IsFolder)..., ) permissionMap[d.OrgID]["managed:builtins:viewer:permissions"] = append( permissionMap[d.OrgID]["managed:builtins:viewer:permissions"], - m.mapPermission(d.ID, dashboards.PERMISSION_VIEW, d.IsFolder)..., + m.mapPermission(d.ID, dashboardaccess.PERMISSION_VIEW, d.IsFolder)..., ) } else { for _, a := range deduplicateAcl(acls) { @@ -192,7 +193,7 @@ func (m dashboardPermissionsMigrator) setPermissions(allRoles []*ac.Role, permis return nil } -func (m dashboardPermissionsMigrator) mapPermission(id int64, p dashboards.PermissionType, isFolder bool) []*ac.Permission { +func (m dashboardPermissionsMigrator) mapPermission(id int64, p dashboardaccess.PermissionType, isFolder bool) []*ac.Permission { if isFolder { actions := folderPermissionTranslation[p] scope := dashboards.ScopeFoldersProvider.GetResourceScope(strconv.FormatInt(id, 10)) @@ -661,15 +662,15 @@ func (m *managedFolderLibraryPanelActionsMigrator) Exec(sess *xorm.Session, mg * } func hasFolderAdmin(permissions []ac.Permission) bool { - return hasActions(folderPermissionTranslation[dashboards.PERMISSION_ADMIN], permissions) + return hasActions(folderPermissionTranslation[dashboardaccess.PERMISSION_ADMIN], permissions) } func hasFolderEdit(permissions []ac.Permission) bool { - return hasActions(folderPermissionTranslation[dashboards.PERMISSION_EDIT], permissions) + return hasActions(folderPermissionTranslation[dashboardaccess.PERMISSION_EDIT], permissions) } func hasFolderView(permissions []ac.Permission) bool { - return hasActions(folderPermissionTranslation[dashboards.PERMISSION_VIEW], permissions) + return hasActions(folderPermissionTranslation[dashboardaccess.PERMISSION_VIEW], permissions) } func hasActions(actions []string, permissions []ac.Permission) bool { diff --git a/pkg/services/sqlstore/migrations/accesscontrol/team_membership.go b/pkg/services/sqlstore/migrations/accesscontrol/team_membership.go index c2252b17860..aa3e108048e 100644 --- a/pkg/services/sqlstore/migrations/accesscontrol/team_membership.go +++ b/pkg/services/sqlstore/migrations/accesscontrol/team_membership.go @@ -8,7 +8,7 @@ import ( "xorm.io/xorm" "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/team" @@ -64,12 +64,12 @@ func (p *teamPermissionMigrator) setRolePermissions(roleID int64, permissions [] } // mapPermissionToRBAC translates the legacy membership (Member or Admin) into RBAC permissions -func (p *teamPermissionMigrator) mapPermissionToRBAC(permission dashboards.PermissionType, teamID int64) []accesscontrol.Permission { +func (p *teamPermissionMigrator) mapPermissionToRBAC(permission dashboardaccess.PermissionType, teamID int64) []accesscontrol.Permission { teamIDScope := accesscontrol.Scope("teams", "id", strconv.FormatInt(teamID, 10)) switch permission { case 0: return []accesscontrol.Permission{{Action: "teams:read", Scope: teamIDScope}} - case dashboards.PERMISSION_ADMIN: + case dashboardaccess.PERMISSION_ADMIN: return []accesscontrol.Permission{ {Action: "teams:delete", Scope: teamIDScope}, {Action: "teams:read", Scope: teamIDScope}, @@ -210,7 +210,7 @@ func (p *teamPermissionMigrator) generateAssociatedPermissions(teamMemberships [ // Downgrade team permissions if needed: // only admins or editors (when editorsCanAdmin option is enabled) // can access team administration endpoints - if m.Permission == dashboards.PERMISSION_ADMIN { + if m.Permission == dashboardaccess.PERMISSION_ADMIN { if userRolesByOrg[m.OrgID][m.UserID] == string(org.RoleViewer) || (userRolesByOrg[m.OrgID][m.UserID] == string(org.RoleEditor) && !p.editorsCanAdmin) { m.Permission = 0 diff --git a/pkg/services/sqlstore/migrations/accesscontrol/test/ac_test.go b/pkg/services/sqlstore/migrations/accesscontrol/test/ac_test.go index 67f8eb696d1..d02b401d2f6 100644 --- a/pkg/services/sqlstore/migrations/accesscontrol/test/ac_test.go +++ b/pkg/services/sqlstore/migrations/accesscontrol/test/ac_test.go @@ -13,7 +13,7 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore/migrations" @@ -358,7 +358,7 @@ func setupTeams(t *testing.T, x *xorm.Engine) { TeamID: 1, UserID: 2, External: false, - Permission: dashboards.PERMISSION_ADMIN, + Permission: dashboardaccess.PERMISSION_ADMIN, Created: now, Updated: now, }, @@ -368,7 +368,7 @@ func setupTeams(t *testing.T, x *xorm.Engine) { TeamID: 1, UserID: 3, External: false, - Permission: dashboards.PERMISSION_ADMIN, + Permission: dashboardaccess.PERMISSION_ADMIN, Created: now, Updated: now, }, @@ -378,7 +378,7 @@ func setupTeams(t *testing.T, x *xorm.Engine) { TeamID: 1, UserID: 4, External: false, - Permission: dashboards.PERMISSION_ADMIN, + Permission: dashboardaccess.PERMISSION_ADMIN, Created: now, Updated: now, }, diff --git a/pkg/services/sqlstore/permissions/dashboard.go b/pkg/services/sqlstore/permissions/dashboard.go index 1d1465c06aa..813343e2491 100644 --- a/pkg/services/sqlstore/permissions/dashboard.go +++ b/pkg/services/sqlstore/permissions/dashboard.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/login" @@ -44,11 +45,11 @@ type PermissionsFilter interface { nestedFoldersSelectors(permSelector string, permSelectorArgs []any, leftTableCol string, rightTableCol string, orgID int64) (string, []any) } -// NewAccessControlDashboardPermissionFilter creates a new AccessControlDashboardPermissionFilter that is configured with specific actions calculated based on the dashboards.PermissionType and query type +// NewAccessControlDashboardPermissionFilter creates a new AccessControlDashboardPermissionFilter that is configured with specific actions calculated based on the dashboardaccess.PermissionType and query type // The filter is configured to use the new permissions filter (without subqueries) if the feature flag is enabled // The filter is configured to use the old permissions filter (with subqueries) if the feature flag is disabled -func NewAccessControlDashboardPermissionFilter(user identity.Requester, permissionLevel dashboards.PermissionType, queryType string, features featuremgmt.FeatureToggles, recursiveQueriesAreSupported bool) PermissionsFilter { - needEdit := permissionLevel > dashboards.PERMISSION_VIEW +func NewAccessControlDashboardPermissionFilter(user identity.Requester, permissionLevel dashboardaccess.PermissionType, queryType string, features featuremgmt.FeatureToggles, recursiveQueriesAreSupported bool) PermissionsFilter { + needEdit := permissionLevel > dashboardaccess.PERMISSION_VIEW var folderActions []string var dashboardActions []string diff --git a/pkg/services/sqlstore/permissions/dashboard_test.go b/pkg/services/sqlstore/permissions/dashboard_test.go index 3b372254334..a7385bc119e 100644 --- a/pkg/services/sqlstore/permissions/dashboard_test.go +++ b/pkg/services/sqlstore/permissions/dashboard_test.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" @@ -40,7 +41,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { type testCase struct { desc string queryType string - permission dashboards.PermissionType + permission dashboardaccess.PermissionType permissions []accesscontrol.Permission expectedResult int } @@ -48,7 +49,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { tests := []testCase{ { desc: "Should be able to view all dashboards with wildcard scope", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeDashboardsAll}, }, @@ -56,7 +57,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should be able to view all dashboards with folder wildcard scope", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersAll}, }, @@ -64,7 +65,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should be able to view dashboards under the root with folders:uid:general scope", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.GeneralFolderUID)}, }, @@ -72,7 +73,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should not be able to view editable dashboards under the root with folders:uid:general scope if missing write action", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.GeneralFolderUID)}, }, @@ -80,7 +81,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should be able to view editable dashboards under the root with folders:uid:general scope if has write action", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.GeneralFolderUID)}, {Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.GeneralFolderUID)}, @@ -89,7 +90,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should be able to view a subset of dashboards with dashboard scopes", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:110"}, {Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:40"}, @@ -102,7 +103,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should be able to view a subset of dashboards with dashboard action and folder scope", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:8"}, {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:10"}, @@ -111,7 +112,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should be able to view all folders with folder wildcard", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:*"}, }, @@ -119,7 +120,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should be able to view a subset folders", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:6"}, @@ -129,7 +130,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should return folders and dashboard with 'edit' permission", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, {Action: dashboards.ActionDashboardsCreate, Scope: "folders:uid:3"}, @@ -140,7 +141,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should return the dashboards that the User has dashboards:write permission on in case of 'edit' permission", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, {Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:31"}, @@ -152,7 +153,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should return the folders that the User has dashboards:create permission on in case of 'edit' permission", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, {Action: dashboards.ActionDashboardsCreate, Scope: "folders:uid:3"}, @@ -164,7 +165,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should return folders that users can read alerts from", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, queryType: searchstore.TypeAlertFolder, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, @@ -176,7 +177,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) { }, { desc: "Should return folders that users can read alerts when user has read wildcard", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, queryType: searchstore.TypeAlertFolder, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "*"}, @@ -232,7 +233,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t type testCase struct { desc string queryType string - permission dashboards.PermissionType + permission dashboardaccess.PermissionType signedInUserPermissions []accesscontrol.Permission expectedResult int } @@ -240,7 +241,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t tests := []testCase{ { desc: "Should be able to view all dashboards with wildcard scope", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeDashboardsAll}, }, @@ -248,7 +249,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should be able to view all dashboards with folder wildcard scope", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersAll}, }, @@ -256,13 +257,13 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should not be able to view any dashboards or folders without any permissions", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{}, expectedResult: 0, }, { desc: "Should be able to view a subset of dashboards with dashboard scopes", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:110"}, {Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:40"}, @@ -275,7 +276,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should be able to view a subset of dashboards with dashboard action and folder scope", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:8"}, @@ -285,7 +286,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should be able to view dashboards under the root with folders:uid:general scope", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.GeneralFolderUID)}, }, @@ -293,7 +294,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should not be able to view editable dashboards under the root with folders:uid:general scope if missing write action", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.GeneralFolderUID)}, }, @@ -301,7 +302,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should be able to view editable dashboards under the root with folders:uid:general scope if has write action", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.GeneralFolderUID)}, {Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.GeneralFolderUID)}, @@ -310,7 +311,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should be able to view all folders with folder wildcard", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:*"}, }, @@ -318,7 +319,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should be able to view a subset folders", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:6"}, @@ -328,7 +329,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should return folders and dashboard with 'edit' permission", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, {Action: dashboards.ActionDashboardsCreate, Scope: "folders:uid:3"}, @@ -339,7 +340,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should return the dashboards that the User has dashboards:write permission on in case of 'edit' permission", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, {Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:31"}, @@ -351,7 +352,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should return the folders that the User has dashboards:create permission on in case of 'edit' permission", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, {Action: dashboards.ActionDashboardsCreate, Scope: "folders:uid:3"}, @@ -363,7 +364,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should return folders that users can read alerts from", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, queryType: searchstore.TypeAlertFolder, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:3"}, @@ -375,7 +376,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t }, { desc: "Should return folders that users can read alerts when user has read wildcard", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, queryType: searchstore.TypeAlertFolder, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "*"}, @@ -427,7 +428,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { testCases := []struct { desc string queryType string - permission dashboards.PermissionType + permission dashboardaccess.PermissionType permissions []accesscontrol.Permission expectedResult []string features []any @@ -435,7 +436,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { { desc: "Should not be able to view dashboards under inherited folders with no permissions if nested folders are enabled", queryType: searchstore.TypeDashboard, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: nil, features: []any{featuremgmt.FlagNestedFolders}, expectedResult: nil, @@ -443,14 +444,14 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { { desc: "Should not be able to view inherited folders with no permissions if nested folders are enabled", queryType: searchstore.TypeFolder, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: nil, features: []any{featuremgmt.FlagNestedFolders}, expectedResult: nil, }, { desc: "Should not be able to view inherited dashboards and folders with no permissions if nested folders are enabled", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: nil, features: []any{featuremgmt.FlagNestedFolders}, expectedResult: nil, @@ -458,7 +459,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { { desc: "Should be able to view dashboards under inherited folders with wildcard scope if nested folders are enabled", queryType: searchstore.TypeDashboard, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersAll}, }, @@ -468,7 +469,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { { desc: "Should be able to view dashboards under inherited folders if nested folders are enabled", queryType: searchstore.TypeDashboard, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:parent"}, }, @@ -478,7 +479,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { { desc: "Should not be able to view dashboards under inherited folders if nested folders are not enabled", queryType: searchstore.TypeDashboard, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:parent"}, }, @@ -488,7 +489,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { { desc: "Should be able to view inherited folders if nested folders are enabled", queryType: searchstore.TypeFolder, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:parent"}, }, @@ -498,7 +499,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { { desc: "Should not be able to view inherited folders if nested folders are not enabled", queryType: searchstore.TypeFolder, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:parent"}, }, @@ -507,7 +508,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { }, { desc: "Should be able to view inherited dashboards and folders if nested folders are enabled", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:parent"}, {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:parent"}, @@ -517,7 +518,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { }, { desc: "Should not be able to view inherited dashboards and folders if nested folders are not enabled", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, permissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:parent"}, {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:parent"}, @@ -580,7 +581,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission testCases := []struct { desc string queryType string - permission dashboards.PermissionType + permission dashboardaccess.PermissionType signedInUserPermissions []accesscontrol.Permission expectedResult []string features []any @@ -588,7 +589,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission { desc: "Should not be able to view dashboards under inherited folders with no permissions if nested folders are enabled", queryType: searchstore.TypeDashboard, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: nil, features: []any{featuremgmt.FlagNestedFolders}, expectedResult: nil, @@ -596,14 +597,14 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission { desc: "Should not be able to view inherited folders with no permissions if nested folders are enabled", queryType: searchstore.TypeFolder, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: nil, features: []any{featuremgmt.FlagNestedFolders}, expectedResult: nil, }, { desc: "Should not be able to view inherited dashboards and folders with no permissions if nested folders are enabled", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: nil, features: []any{featuremgmt.FlagNestedFolders}, expectedResult: nil, @@ -611,7 +612,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission { desc: "Should be able to view dashboards under inherited folders with wildcard scope if nested folders are enabled", queryType: searchstore.TypeDashboard, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: dashboards.ScopeFoldersAll}, }, @@ -621,7 +622,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission { desc: "Should be able to view dashboards under inherited folders if nested folders are enabled", queryType: searchstore.TypeDashboard, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:parent"}, }, @@ -631,7 +632,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission { desc: "Should not be able to view dashboards under inherited folders if nested folders are not enabled", queryType: searchstore.TypeDashboard, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:parent"}, }, @@ -641,7 +642,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission { desc: "Should be able to view inherited folders if nested folders are enabled", queryType: searchstore.TypeFolder, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:parent"}, }, @@ -651,7 +652,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission { desc: "Should not be able to view inherited folders if nested folders are not enabled", queryType: searchstore.TypeFolder, - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:parent"}, }, @@ -660,7 +661,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission }, { desc: "Should be able to view inherited dashboards and folders if nested folders are enabled", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:parent"}, {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:parent"}, @@ -670,7 +671,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission }, { desc: "Should not be able to view inherited dashboards and folders if nested folders are not enabled", - permission: dashboards.PERMISSION_VIEW, + permission: dashboardaccess.PERMISSION_VIEW, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:parent"}, {Action: dashboards.ActionDashboardsRead, Scope: "folders:uid:parent"}, @@ -680,7 +681,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission }, { desc: "Should be able to edit inherited dashboards and folders if nested folders are enabled", - permission: dashboards.PERMISSION_EDIT, + permission: dashboardaccess.PERMISSION_EDIT, signedInUserPermissions: []accesscontrol.Permission{ {Action: dashboards.ActionFoldersRead, Scope: "folders:uid:subfolder"}, {Action: dashboards.ActionDashboardsCreate, Scope: "folders:uid:subfolder"}, diff --git a/pkg/services/sqlstore/permissions/dashboards_bench_test.go b/pkg/services/sqlstore/permissions/dashboards_bench_test.go index 33f3733c8aa..42b78918e7e 100644 --- a/pkg/services/sqlstore/permissions/dashboards_bench_test.go +++ b/pkg/services/sqlstore/permissions/dashboards_bench_test.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" @@ -56,7 +57,7 @@ func benchmarkDashboardPermissionFilter(b *testing.B, numUsers, numDashboards, n b.ResetTimer() for i := 0; i < b.N; i++ { - filter := permissions.NewAccessControlDashboardPermissionFilter(&usr, dashboards.PERMISSION_VIEW, "", features, recursiveQueriesAreSupported) + filter := permissions.NewAccessControlDashboardPermissionFilter(&usr, dashboardaccess.PERMISSION_VIEW, "", features, recursiveQueriesAreSupported) var result int err := store.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { q, params := filter.Where() diff --git a/pkg/services/sqlstore/searchstore/search_test.go b/pkg/services/sqlstore/searchstore/search_test.go index 1dfa9c328e3..d2c06ccd795 100644 --- a/pkg/services/sqlstore/searchstore/search_test.go +++ b/pkg/services/sqlstore/searchstore/search_test.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore/permissions" @@ -299,7 +300,7 @@ func TestBuilder_RBAC(t *testing.T) { user.Permissions = map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tc.userPermissions)} } - level := dashboards.PERMISSION_EDIT + level := dashboardaccess.PERMISSION_EDIT builder := &searchstore.Builder{ Filters: []any{ diff --git a/pkg/services/stats/statsimpl/stats.go b/pkg/services/stats/statsimpl/stats.go index 1377dc8932c..9cb52295dff 100644 --- a/pkg/services/stats/statsimpl/stats.go +++ b/pkg/services/stats/statsimpl/stats.go @@ -7,7 +7,7 @@ import ( "time" "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/libraryelements/model" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" @@ -109,10 +109,10 @@ func (ss *sqlStatsService) GetSystemStats(ctx context.Context, query *stats.GetS WHERE d.is_folder = ? ) AS folder_permissions,`, dialect.BooleanStr(true)) - sb.Write(viewersPermissionsCounterSQL(ss.db, "dashboards_viewers_can_edit", false, dashboards.PERMISSION_EDIT)) - sb.Write(viewersPermissionsCounterSQL(ss.db, "dashboards_viewers_can_admin", false, dashboards.PERMISSION_ADMIN)) - sb.Write(viewersPermissionsCounterSQL(ss.db, "folders_viewers_can_edit", true, dashboards.PERMISSION_EDIT)) - sb.Write(viewersPermissionsCounterSQL(ss.db, "folders_viewers_can_admin", true, dashboards.PERMISSION_ADMIN)) + sb.Write(viewersPermissionsCounterSQL(ss.db, "dashboards_viewers_can_edit", false, dashboardaccess.PERMISSION_EDIT)) + sb.Write(viewersPermissionsCounterSQL(ss.db, "dashboards_viewers_can_admin", false, dashboardaccess.PERMISSION_ADMIN)) + sb.Write(viewersPermissionsCounterSQL(ss.db, "folders_viewers_can_edit", true, dashboardaccess.PERMISSION_EDIT)) + sb.Write(viewersPermissionsCounterSQL(ss.db, "folders_viewers_can_admin", true, dashboardaccess.PERMISSION_ADMIN)) sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_provisioning") + `) AS provisioned_dashboards,`) sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_snapshot") + `) AS snapshots,`) @@ -166,7 +166,7 @@ func (ss *sqlStatsService) roleCounterSQL(ctx context.Context) string { return sqlQuery } -func viewersPermissionsCounterSQL(db db.DB, statName string, isFolder bool, permission dashboards.PermissionType) string { +func viewersPermissionsCounterSQL(db db.DB, statName string, isFolder bool, permission dashboardaccess.PermissionType) string { dialect := db.GetDialect() return `( SELECT COUNT(*) diff --git a/pkg/services/team/model.go b/pkg/services/team/model.go index fd1a9c3799d..060ab84dfbb 100644 --- a/pkg/services/team/model.go +++ b/pkg/services/team/model.go @@ -8,7 +8,7 @@ import ( "github.com/grafana/grafana/pkg/kinds/team" "github.com/grafana/grafana/pkg/services/auth/identity" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/search/model" ) @@ -103,15 +103,15 @@ type SearchTeamsQuery struct { } type TeamDTO struct { - ID int64 `json:"id" xorm:"id"` - UID string `json:"uid" xorm:"uid"` - OrgID int64 `json:"orgId" xorm:"org_id"` - Name string `json:"name"` - Email string `json:"email"` - AvatarURL string `json:"avatarUrl"` - MemberCount int64 `json:"memberCount"` - Permission dashboards.PermissionType `json:"permission"` - AccessControl map[string]bool `json:"accessControl"` + ID int64 `json:"id" xorm:"id"` + UID string `json:"uid" xorm:"uid"` + OrgID int64 `json:"orgId" xorm:"org_id"` + Name string `json:"name"` + Email string `json:"email"` + AvatarURL string `json:"avatarUrl"` + MemberCount int64 `json:"memberCount"` + Permission dashboardaccess.PermissionType `json:"permission"` + AccessControl map[string]bool `json:"accessControl"` } type SearchTeamQueryResult struct { @@ -128,7 +128,7 @@ type TeamMember struct { TeamID int64 `xorm:"team_id"` UserID int64 `xorm:"user_id"` External bool // Signals that the membership has been created by an external systems, such as LDAP - Permission dashboards.PermissionType + Permission dashboardaccess.PermissionType Created time.Time Updated time.Time @@ -138,18 +138,18 @@ type TeamMember struct { // COMMANDS type AddTeamMemberCommand struct { - UserID int64 `json:"userId" binding:"Required"` - OrgID int64 `json:"-"` - TeamID int64 `json:"-"` - External bool `json:"-"` - Permission dashboards.PermissionType `json:"-"` + UserID int64 `json:"userId" binding:"Required"` + OrgID int64 `json:"-"` + TeamID int64 `json:"-"` + External bool `json:"-"` + Permission dashboardaccess.PermissionType `json:"-"` } type UpdateTeamMemberCommand struct { - UserID int64 `json:"-"` - OrgID int64 `json:"-"` - TeamID int64 `json:"-"` - Permission dashboards.PermissionType `json:"permission"` + UserID int64 `json:"-"` + OrgID int64 `json:"-"` + TeamID int64 `json:"-"` + Permission dashboardaccess.PermissionType `json:"permission"` } type RemoveTeamMemberCommand struct { @@ -174,16 +174,16 @@ type GetTeamMembersQuery struct { // Projections and DTOs type TeamMemberDTO struct { - OrgID int64 `json:"orgId" xorm:"org_id"` - TeamID int64 `json:"teamId" xorm:"team_id"` - TeamUID string `json:"teamUID" xorm:"uid"` - UserID int64 `json:"userId" xorm:"user_id"` - External bool `json:"-"` - AuthModule string `json:"auth_module"` - Email string `json:"email"` - Name string `json:"name"` - Login string `json:"login"` - AvatarURL string `json:"avatarUrl" xorm:"avatar_url"` - Labels []string `json:"labels"` - Permission dashboards.PermissionType `json:"permission"` + OrgID int64 `json:"orgId" xorm:"org_id"` + TeamID int64 `json:"teamId" xorm:"team_id"` + TeamUID string `json:"teamUID" xorm:"uid"` + UserID int64 `json:"userId" xorm:"user_id"` + External bool `json:"-"` + AuthModule string `json:"auth_module"` + Email string `json:"email"` + Name string `json:"name"` + Login string `json:"login"` + AvatarURL string `json:"avatarUrl" xorm:"avatar_url"` + Labels []string `json:"labels"` + Permission dashboardaccess.PermissionType `json:"permission"` } diff --git a/pkg/services/team/team.go b/pkg/services/team/team.go index 0ee734c0e38..74c51c5547f 100644 --- a/pkg/services/team/team.go +++ b/pkg/services/team/team.go @@ -3,7 +3,7 @@ package team import ( "context" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" ) type Service interface { @@ -14,7 +14,7 @@ type Service interface { GetTeamByID(ctx context.Context, query *GetTeamByIDQuery) (*TeamDTO, error) GetTeamsByUser(ctx context.Context, query *GetTeamsByUserQuery) ([]*TeamDTO, error) GetTeamIDsByUser(ctx context.Context, query *GetTeamIDsByUserQuery) ([]int64, error) - AddTeamMember(userID, orgID, teamID int64, isExternal bool, permission dashboards.PermissionType) error + AddTeamMember(userID, orgID, teamID int64, isExternal bool, permission dashboardaccess.PermissionType) error UpdateTeamMember(ctx context.Context, cmd *UpdateTeamMemberCommand) error IsTeamMember(orgId int64, teamId int64, userId int64) (bool, error) RemoveTeamMember(ctx context.Context, cmd *RemoveTeamMemberCommand) error diff --git a/pkg/services/team/teamapi/team.go b/pkg/services/team/teamapi/team.go index ab4b8b33c09..b12757856d2 100644 --- a/pkg/services/team/teamapi/team.go +++ b/pkg/services/team/teamapi/team.go @@ -10,7 +10,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/auth/identity" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/preference/prefapi" "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/services/team/sortopts" @@ -58,7 +58,7 @@ func (tapi *TeamAPI) createTeam(c *contextmodel.ReqContext) response.Response { break } if err := addOrUpdateTeamMember(c.Req.Context(), tapi.teamPermissionsService, userID, c.SignedInUser.GetOrgID(), - t.ID, dashboards.PERMISSION_ADMIN.String()); err != nil { + t.ID, dashboardaccess.PERMISSION_ADMIN.String()); err != nil { c.Logger.Error("Could not add creator to team", "error", err) } default: diff --git a/pkg/services/team/teamapi/team_members.go b/pkg/services/team/teamapi/team_members.go index a9f996a8c11..75c3317e8af 100644 --- a/pkg/services/team/teamapi/team_members.go +++ b/pkg/services/team/teamapi/team_members.go @@ -11,7 +11,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/services/accesscontrol" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/util" @@ -141,7 +141,7 @@ func (tapi *TeamAPI) updateTeamMember(c *contextmodel.ReqContext) response.Respo return response.Success("Team member updated") } -func getPermissionName(permission dashboards.PermissionType) string { +func getPermissionName(permission dashboardaccess.PermissionType) string { permissionName := permission.String() // Team member permission is 0, which maps to an empty string. // However, we want the team permission service to display "Member" for team members. This is a hack to make it work. diff --git a/pkg/services/team/teamimpl/store.go b/pkg/services/team/teamimpl/store.go index 77e7018413e..f5d4124bdce 100644 --- a/pkg/services/team/teamimpl/store.go +++ b/pkg/services/team/teamimpl/store.go @@ -10,7 +10,7 @@ import ( "github.com/grafana/grafana/pkg/infra/db" ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/auth/identity" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" @@ -25,7 +25,7 @@ type store interface { GetByUser(ctx context.Context, query *team.GetTeamsByUserQuery) ([]*team.TeamDTO, error) GetIDsByUser(ctx context.Context, query *team.GetTeamIDsByUserQuery) ([]int64, error) RemoveUsersMemberships(ctx context.Context, userID int64) error - AddMember(userID, orgID, teamID int64, isExternal bool, permission dashboards.PermissionType) error + AddMember(userID, orgID, teamID int64, isExternal bool, permission dashboardaccess.PermissionType) error UpdateMember(ctx context.Context, cmd *team.UpdateTeamMemberCommand) error IsMember(orgId int64, teamId int64, userId int64) (bool, error) RemoveMember(ctx context.Context, cmd *team.RemoveTeamMemberCommand) error @@ -354,7 +354,7 @@ WHERE tm.user_id=? AND tm.org_id=?;`, query.UserID, query.OrgID).Find(&queryResu } // AddTeamMember adds a user to a team -func (ss *xormStore) AddMember(userID, orgID, teamID int64, isExternal bool, permission dashboards.PermissionType) error { +func (ss *xormStore) AddMember(userID, orgID, teamID int64, isExternal bool, permission dashboardaccess.PermissionType) error { return ss.db.WithTransactionalDbSession(context.Background(), func(sess *db.Session) error { if isMember, err := isTeamMember(sess, orgID, teamID, userID); err != nil { return err @@ -412,7 +412,7 @@ func isTeamMember(sess *db.Session, orgId int64, teamId int64, userId int64) (bo // AddOrUpdateTeamMemberHook is called from team resource permission service // it adds user to a team or updates user permissions in a team within the given transaction session -func AddOrUpdateTeamMemberHook(sess *db.Session, userID, orgID, teamID int64, isExternal bool, permission dashboards.PermissionType) error { +func AddOrUpdateTeamMemberHook(sess *db.Session, userID, orgID, teamID int64, isExternal bool, permission dashboardaccess.PermissionType) error { isMember, err := isTeamMember(sess, orgID, teamID, userID) if err != nil { return err @@ -427,7 +427,7 @@ func AddOrUpdateTeamMemberHook(sess *db.Session, userID, orgID, teamID int64, is return err } -func addTeamMember(sess *db.Session, orgID, teamID, userID int64, isExternal bool, permission dashboards.PermissionType) error { +func addTeamMember(sess *db.Session, orgID, teamID, userID int64, isExternal bool, permission dashboardaccess.PermissionType) error { if _, err := teamExists(orgID, teamID, sess); err != nil { return err } @@ -446,13 +446,13 @@ func addTeamMember(sess *db.Session, orgID, teamID, userID int64, isExternal boo return err } -func updateTeamMember(sess *db.Session, orgID, teamID, userID int64, permission dashboards.PermissionType) error { +func updateTeamMember(sess *db.Session, orgID, teamID, userID int64, permission dashboardaccess.PermissionType) error { member, err := getTeamMember(sess, orgID, teamID, userID) if err != nil { return err } - if permission != dashboards.PERMISSION_ADMIN { + if permission != dashboardaccess.PERMISSION_ADMIN { permission = 0 // make sure we don't get invalid permission levels in store } diff --git a/pkg/services/team/teamimpl/store_test.go b/pkg/services/team/teamimpl/store_test.go index 54c6ba0a0bc..e864b08bf18 100644 --- a/pkg/services/team/teamimpl/store_test.go +++ b/pkg/services/team/teamimpl/store_test.go @@ -12,7 +12,7 @@ import ( "github.com/grafana/grafana/pkg/infra/db" ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/auth/identity" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/serviceaccounts" @@ -174,7 +174,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { UserID: userId, OrgID: testOrgID, TeamID: team1.ID, - Permission: dashboards.PERMISSION_ADMIN, + Permission: dashboardaccess.PERMISSION_ADMIN, }) require.NoError(t, err) @@ -182,7 +182,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { qAfterUpdate := &team.GetTeamMembersQuery{OrgID: testOrgID, TeamID: team1.ID, SignedInUser: testUser} qAfterUpdateResult, err := teamSvc.GetTeamMembers(context.Background(), qAfterUpdate) require.NoError(t, err) - require.Equal(t, qAfterUpdateResult[0].Permission, dashboards.PERMISSION_ADMIN) + require.Equal(t, qAfterUpdateResult[0].Permission, dashboardaccess.PERMISSION_ADMIN) }) t.Run("Should default to member permission level when updating a user with invalid permission level", func(t *testing.T) { @@ -197,7 +197,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { require.NoError(t, err) require.EqualValues(t, qBeforeUpdateResult[0].Permission, 0) - invalidPermissionLevel := dashboards.PERMISSION_EDIT + invalidPermissionLevel := dashboardaccess.PERMISSION_EDIT err = teamSvc.UpdateTeamMember(context.Background(), &team.UpdateTeamMemberCommand{ UserID: userID, OrgID: testOrgID, @@ -220,7 +220,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { UserID: 1, OrgID: testOrgID, TeamID: team1.ID, - Permission: dashboards.PERMISSION_ADMIN, + Permission: dashboardaccess.PERMISSION_ADMIN, }) require.Error(t, err, team.ErrTeamMemberNotFound) @@ -330,7 +330,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { }) t.Run("Should have empty teams", func(t *testing.T) { - err = teamSvc.AddTeamMember(userIds[0], testOrgID, team1.ID, false, dashboards.PERMISSION_ADMIN) + err = teamSvc.AddTeamMember(userIds[0], testOrgID, team1.ID, false, dashboardaccess.PERMISSION_ADMIN) require.NoError(t, err) t.Run("A user should be able to remove the admin permission for the last admin", func(t *testing.T) { @@ -347,10 +347,10 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { sqlStore = db.InitTestDB(t) setup() - err = teamSvc.AddTeamMember(userIds[0], testOrgID, team1.ID, false, dashboards.PERMISSION_ADMIN) + err = teamSvc.AddTeamMember(userIds[0], testOrgID, team1.ID, false, dashboardaccess.PERMISSION_ADMIN) require.NoError(t, err) - err = teamSvc.AddTeamMember(userIds[1], testOrgID, team1.ID, false, dashboards.PERMISSION_ADMIN) + err = teamSvc.AddTeamMember(userIds[1], testOrgID, team1.ID, false, dashboardaccess.PERMISSION_ADMIN) require.NoError(t, err) err = teamSvc.UpdateTeamMember(context.Background(), &team.UpdateTeamMemberCommand{OrgID: testOrgID, TeamID: team1.ID, UserID: userIds[0], Permission: 0}) require.NoError(t, err) diff --git a/pkg/services/team/teamimpl/team.go b/pkg/services/team/teamimpl/team.go index 7faf848755b..c6e7fa347f5 100644 --- a/pkg/services/team/teamimpl/team.go +++ b/pkg/services/team/teamimpl/team.go @@ -4,7 +4,7 @@ import ( "context" "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/setting" ) @@ -45,7 +45,7 @@ func (s *Service) GetTeamIDsByUser(ctx context.Context, query *team.GetTeamIDsBy return s.store.GetIDsByUser(ctx, query) } -func (s *Service) AddTeamMember(userID, orgID, teamID int64, isExternal bool, permission dashboards.PermissionType) error { +func (s *Service) AddTeamMember(userID, orgID, teamID int64, isExternal bool, permission dashboardaccess.PermissionType) error { return s.store.AddMember(userID, orgID, teamID, isExternal, permission) } diff --git a/pkg/services/team/teamtest/team.go b/pkg/services/team/teamtest/team.go index 00e43c95599..0f97e9077b3 100644 --- a/pkg/services/team/teamtest/team.go +++ b/pkg/services/team/teamtest/team.go @@ -3,7 +3,7 @@ package teamtest import ( "context" - "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/team" ) @@ -45,7 +45,7 @@ func (s *FakeService) GetTeamsByUser(ctx context.Context, query *team.GetTeamsBy return s.ExpectedTeamsByUser, s.ExpectedError } -func (s *FakeService) AddTeamMember(userID, orgID, teamID int64, isExternal bool, permission dashboards.PermissionType) error { +func (s *FakeService) AddTeamMember(userID, orgID, teamID int64, isExternal bool, permission dashboardaccess.PermissionType) error { return s.ExpectedError }