diff --git a/pkg/api/folder.go b/pkg/api/folder.go index b7fa8a75006..8a11618cfe3 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" "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/featuremgmt" @@ -18,7 +19,6 @@ import ( "github.com/grafana/grafana/pkg/services/libraryelements/model" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/search" - "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" ) @@ -172,11 +172,20 @@ func (hs *HTTPServer) CreateFolder(c *contextmodel.ReqContext) response.Response return response.JSON(http.StatusOK, folderDTO) } -func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int64, user *user.SignedInUser, folder *folder.Folder) error { +func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int64, user identity.Requester, folder *folder.Folder) error { var permissions []accesscontrol.SetResourcePermissionCommand - if user.IsRealUser() && !user.IsAnonymous { + var userID int64 + + namespace, id := user.GetNamespacedID() + if namespace == identity.NamespaceUser { + var errID error + userID, errID = identity.IntIdentifier(namespace, id) + if errID != nil { + return errID + } + permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ - UserID: user.UserID, Permission: dashboards.PERMISSION_ADMIN.String(), + UserID: userID, Permission: dashboards.PERMISSION_ADMIN.String(), }) } diff --git a/pkg/services/dashboards/dashboard.go b/pkg/services/dashboards/dashboard.go index 86342d88084..dd2a8268de7 100644 --- a/pkg/services/dashboards/dashboard.go +++ b/pkg/services/dashboards/dashboard.go @@ -4,9 +4,9 @@ import ( "context" alertmodels "github.com/grafana/grafana/pkg/services/alerting/models" + "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/search/model" - "github.com/grafana/grafana/pkg/services/user" ) // DashboardService is a service for operating on dashboards. @@ -26,7 +26,7 @@ type DashboardService interface { SearchDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) (model.HitList, error) UpdateDashboardACL(ctx context.Context, uid int64, items []*DashboardACL) error DeleteACLByUser(ctx context.Context, userID int64) error - CountInFolder(ctx context.Context, orgID int64, folderUID string, user *user.SignedInUser) (int64, error) + CountInFolder(ctx context.Context, orgID int64, folderUID string, user identity.Requester) (int64, error) } // PluginService is a service for operating on plugin dashboards. diff --git a/pkg/services/dashboards/dashboard_service_mock.go b/pkg/services/dashboards/dashboard_service_mock.go index 2ad05c430b9..e4c47eb8c5e 100644 --- a/pkg/services/dashboards/dashboard_service_mock.go +++ b/pkg/services/dashboards/dashboard_service_mock.go @@ -1,14 +1,12 @@ -// Code generated by mockery v2.28.0. DO NOT EDIT. - package dashboards import ( context "context" - model "github.com/grafana/grafana/pkg/services/search/model" mock "github.com/stretchr/testify/mock" - user "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/auth/identity" + model "github.com/grafana/grafana/pkg/services/search/model" ) // FakeDashboardService is an autogenerated mock type for the DashboardService type @@ -43,21 +41,21 @@ func (_m *FakeDashboardService) BuildSaveDashboardCommand(ctx context.Context, d } // CountInFolder provides a mock function with given fields: ctx, orgID, folderUID, _a3 -func (_m *FakeDashboardService) CountInFolder(ctx context.Context, orgID int64, folderUID string, _a3 *user.SignedInUser) (int64, error) { +func (_m *FakeDashboardService) CountInFolder(ctx context.Context, orgID int64, folderUID string, _a3 identity.Requester) (int64, error) { ret := _m.Called(ctx, orgID, folderUID, _a3) var r0 int64 var r1 error - if rf, ok := ret.Get(0).(func(context.Context, int64, string, *user.SignedInUser) (int64, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, int64, string, identity.Requester) (int64, error)); ok { return rf(ctx, orgID, folderUID, _a3) } - if rf, ok := ret.Get(0).(func(context.Context, int64, string, *user.SignedInUser) int64); ok { + if rf, ok := ret.Get(0).(func(context.Context, int64, string, identity.Requester) int64); ok { r0 = rf(ctx, orgID, folderUID, _a3) } else { r0 = ret.Get(0).(int64) } - if rf, ok := ret.Get(1).(func(context.Context, int64, string, *user.SignedInUser) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, int64, string, identity.Requester) error); ok { r1 = rf(ctx, orgID, folderUID, _a3) } else { r1 = ret.Error(1) diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 3a5fdddbeaf..aa041d7d315 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -19,7 +19,6 @@ import ( "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/search/model" "github.com/grafana/grafana/pkg/services/store/entity" - "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -609,7 +608,7 @@ func (dr *DashboardServiceImpl) DeleteACLByUser(ctx context.Context, userID int6 return dr.dashboardStore.DeleteACLByUser(ctx, userID) } -func (dr DashboardServiceImpl) CountInFolder(ctx context.Context, orgID int64, folderUID string, u *user.SignedInUser) (int64, error) { +func (dr DashboardServiceImpl) CountInFolder(ctx context.Context, orgID int64, folderUID string, u identity.Requester) (int64, error) { folder, err := dr.folderService.Get(ctx, &folder.GetFolderQuery{UID: &folderUID, OrgID: orgID, SignedInUser: u}) if err != nil { return 0, err @@ -618,7 +617,7 @@ func (dr DashboardServiceImpl) CountInFolder(ctx context.Context, orgID int64, f return dr.dashboardStore.CountDashboardsInFolder(ctx, &dashboards.CountDashboardsInFolderRequest{FolderID: folder.ID, OrgID: orgID}) } -func (dr *DashboardServiceImpl) DeleteInFolder(ctx context.Context, orgID int64, folderUID string, u *user.SignedInUser) error { +func (dr *DashboardServiceImpl) DeleteInFolder(ctx context.Context, orgID int64, folderUID string, u identity.Requester) error { return dr.dashboardStore.DeleteDashboardsInFolder(ctx, &dashboards.DeleteDashboardsInFolderRequest{FolderUID: folderUID, OrgID: orgID}) } diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index 38f51e4a510..6276f91bf00 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -20,7 +20,6 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/store/entity" - "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -410,9 +409,17 @@ func (s *Service) legacyUpdate(ctx context.Context, cmd *folder.UpdateFolderComm if cmd.SignedInUser == nil { return nil, folder.ErrBadRequest.Errorf("missing signed in user") } - user := cmd.SignedInUser - prepareForUpdate(dashFolder, cmd.OrgID, cmd.SignedInUser.UserID, cmd) + var userID int64 + namespace, id := cmd.SignedInUser.GetNamespacedID() + if namespace == identity.NamespaceUser || namespace == identity.NamespaceServiceAccount { + userID, err = identity.IntIdentifier(namespace, id) + if err != nil { + logger.Error("failed to parse user ID", "namespace", namespace, "userID", id, "error", err) + } + } + + prepareForUpdate(dashFolder, cmd.OrgID, userID, cmd) dto := &dashboards.SaveDashboardDTO{ Dashboard: dashFolder, @@ -445,7 +452,7 @@ func (s *Service) legacyUpdate(ctx context.Context, cmd *folder.UpdateFolderComm UID: dash.UID, OrgID: cmd.OrgID, }); err != nil { - logger.Error("failed to publish FolderTitleUpdated event", "folder", foldr.Title, "user", user.UserID, "error", err) + logger.Error("failed to publish FolderTitleUpdated event", "folder", foldr.Title, "user", id, "namespace", namespace, "error", err) } } return foldr, nil @@ -537,7 +544,7 @@ func (s *Service) Delete(ctx context.Context, cmd *folder.DeleteFolderCommand) e return err } -func (s *Service) deleteChildrenInFolder(ctx context.Context, orgID int64, folderUID string, user *user.SignedInUser) error { +func (s *Service) deleteChildrenInFolder(ctx context.Context, orgID int64, folderUID string, user identity.Requester) error { for _, v := range s.registry { if err := v.DeleteInFolder(ctx, orgID, folderUID, user); err != nil { return err diff --git a/pkg/services/folder/model.go b/pkg/services/folder/model.go index 8890d310584..13e62c196ca 100644 --- a/pkg/services/folder/model.go +++ b/pkg/services/folder/model.go @@ -6,7 +6,6 @@ import ( "github.com/grafana/grafana/pkg/infra/slugify" "github.com/grafana/grafana/pkg/services/auth/identity" - "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util/errutil" ) @@ -82,7 +81,7 @@ type CreateFolderCommand struct { Description string `json:"description"` ParentUID string `json:"parentUid"` - SignedInUser *user.SignedInUser `json:"-"` + SignedInUser identity.Requester `json:"-"` } // UpdateFolderCommand captures the information required by the folder service @@ -101,7 +100,7 @@ type UpdateFolderCommand struct { // Overwrite only used by the legacy folder implementation Overwrite bool `json:"overwrite"` - SignedInUser *user.SignedInUser `json:"-"` + SignedInUser identity.Requester `json:"-"` } // MoveFolderCommand captures the information required by the folder service @@ -111,7 +110,7 @@ type MoveFolderCommand struct { NewParentUID string `json:"parentUid"` OrgID int64 `json:"-"` - SignedInUser *user.SignedInUser `json:"-"` + SignedInUser identity.Requester `json:"-"` } // DeleteFolderCommand captures the information required by the folder service @@ -121,7 +120,7 @@ type DeleteFolderCommand struct { OrgID int64 `json:"orgId" xorm:"org_id"` ForceDeleteRules bool `json:"forceDeleteRules"` - SignedInUser *user.SignedInUser `json:"-"` + SignedInUser identity.Requester `json:"-"` } // GetFolderQuery is used for all folder Get requests. Only one of UID, ID, or @@ -158,15 +157,15 @@ type GetChildrenQuery struct { Limit int64 Page int64 - SignedInUser *user.SignedInUser `json:"-"` + SignedInUser identity.Requester `json:"-"` } type HasEditPermissionInFoldersQuery struct { - SignedInUser *user.SignedInUser + SignedInUser identity.Requester } type HasAdminPermissionInDashboardsOrFoldersQuery struct { - SignedInUser *user.SignedInUser + SignedInUser identity.Requester } // GetDescendantCountsQuery captures the information required by the folder service @@ -175,7 +174,7 @@ type GetDescendantCountsQuery struct { UID *string OrgID int64 - SignedInUser *user.SignedInUser `json:"-"` + SignedInUser identity.Requester `json:"-"` } type DescendantCounts map[string]int64 diff --git a/pkg/services/folder/registry.go b/pkg/services/folder/registry.go index efbb89008dd..7a6ff865b0e 100644 --- a/pkg/services/folder/registry.go +++ b/pkg/services/folder/registry.go @@ -3,11 +3,11 @@ package folder import ( "context" - "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/auth/identity" ) type RegistryService interface { - DeleteInFolder(ctx context.Context, orgID int64, folderUID string, user *user.SignedInUser) error - CountInFolder(ctx context.Context, orgID int64, folderUID string, user *user.SignedInUser) (int64, error) + DeleteInFolder(ctx context.Context, orgID int64, folderUID string, user identity.Requester) error + CountInFolder(ctx context.Context, orgID int64, folderUID string, user identity.Requester) (int64, error) Kind() string } diff --git a/pkg/services/librarypanels/librarypanels.go b/pkg/services/librarypanels/librarypanels.go index fff7738a13a..163bcf9153e 100644 --- a/pkg/services/librarypanels/librarypanels.go +++ b/pkg/services/librarypanels/librarypanels.go @@ -15,7 +15,6 @@ import ( "github.com/grafana/grafana/pkg/services/libraryelements" "github.com/grafana/grafana/pkg/services/libraryelements/model" "github.com/grafana/grafana/pkg/services/store/entity" - "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -187,7 +186,7 @@ func importLibraryPanelsRecursively(c context.Context, service libraryelements.S // CountInFolder is a handler for retrieving the number of library panels contained // within a given folder and for a specific organisation. -func (lps LibraryPanelService) CountInFolder(ctx context.Context, orgID int64, folderUID string, u *user.SignedInUser) (int64, error) { +func (lps LibraryPanelService) CountInFolder(ctx context.Context, orgID int64, folderUID string, u identity.Requester) (int64, error) { var count int64 return count, lps.SQLStore.WithDbSession(ctx, func(sess *db.Session) error { folder, err := lps.FolderService.Get(ctx, &folder.GetFolderQuery{UID: &folderUID, OrgID: orgID, SignedInUser: u}) @@ -195,7 +194,7 @@ func (lps LibraryPanelService) CountInFolder(ctx context.Context, orgID int64, f return err } - q := sess.Table("library_element").Where("org_id = ?", u.OrgID). + q := sess.Table("library_element").Where("org_id = ?", u.GetOrgID()). Where("folder_id = ?", folder.ID).Where("kind = ?", int64(model.PanelElement)) count, err = q.Count() return err @@ -203,7 +202,7 @@ func (lps LibraryPanelService) CountInFolder(ctx context.Context, orgID int64, f } // DeleteInFolder deletes the library panels contained in a given folder. -func (lps LibraryPanelService) DeleteInFolder(ctx context.Context, orgID int64, folderUID string, user *user.SignedInUser) error { +func (lps LibraryPanelService) DeleteInFolder(ctx context.Context, orgID int64, folderUID string, user identity.Requester) error { return lps.LibraryElementService.DeleteLibraryElementsInFolder(ctx, user, folderUID) } diff --git a/pkg/services/ngalert/store/alert_rule.go b/pkg/services/ngalert/store/alert_rule.go index d4515f83ec4..ae0f2aeb5ad 100644 --- a/pkg/services/ngalert/store/alert_rule.go +++ b/pkg/services/ngalert/store/alert_rule.go @@ -9,6 +9,7 @@ import ( "github.com/google/uuid" "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/folder" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" @@ -311,7 +312,7 @@ func newTitlesOverlapExisting(rules []ngmodels.UpdateRule) bool { // CountInFolder is a handler for retrieving the number of alert rules of // specific organisation associated with a given namespace (parent folder). -func (st DBstore) CountInFolder(ctx context.Context, orgID int64, folderUID string, u *user.SignedInUser) (int64, error) { +func (st DBstore) CountInFolder(ctx context.Context, orgID int64, folderUID string, u identity.Requester) (int64, error) { var count int64 var err error err = st.SQLStore.WithDbSession(ctx, func(sess *db.Session) error { @@ -584,7 +585,7 @@ func (st DBstore) GetAlertRulesForScheduling(ctx context.Context, query *ngmodel } // DeleteInFolder deletes the rules contained in a given folder along with their associated data. -func (st DBstore) DeleteInFolder(ctx context.Context, orgID int64, folderUID string, user *user.SignedInUser) error { +func (st DBstore) DeleteInFolder(ctx context.Context, orgID int64, folderUID string, user identity.Requester) error { rules, err := st.ListAlertRules(ctx, &ngmodels.ListAlertRulesQuery{ OrgID: orgID, NamespaceUIDs: []string{folderUID}, diff --git a/pkg/services/ngalert/tests/fakes/rules.go b/pkg/services/ngalert/tests/fakes/rules.go index 72f341e518c..2e6e547a053 100644 --- a/pkg/services/ngalert/tests/fakes/rules.go +++ b/pkg/services/ngalert/tests/fakes/rules.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/user" @@ -348,6 +349,6 @@ func (f *RuleStore) Count(ctx context.Context, orgID int64) (int64, error) { return 0, nil } -func (f *RuleStore) CountInFolder(ctx context.Context, orgID int64, folderUID string, u *user.SignedInUser) (int64, error) { +func (f *RuleStore) CountInFolder(ctx context.Context, orgID int64, folderUID string, u identity.Requester) (int64, error) { return 0, nil }