Revert "Replace signed in user for identity.requester (#73750)" (#73962)

This reverts commit 9b9c9e83dc.
This commit is contained in:
Jo 2023-08-28 21:05:59 +02:00 committed by GitHub
parent 07eb4b1b90
commit a307582212
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 359 additions and 523 deletions

View File

@ -20,7 +20,6 @@ import (
"github.com/grafana/grafana/pkg/kinds/dashboard" "github.com/grafana/grafana/pkg/kinds/dashboard"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/auth/identity"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion" dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
@ -33,7 +32,6 @@ import (
"github.com/grafana/grafana/pkg/services/star" "github.com/grafana/grafana/pkg/services/star"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/errutil"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@ -46,27 +44,15 @@ func (hs *HTTPServer) isDashboardStarredByUser(c *contextmodel.ReqContext, dashI
return false, nil return false, nil
} }
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID() query := star.IsStarredByUserQuery{UserID: c.UserID, DashboardID: dashID}
if namespaceID != identity.NamespaceUser {
return false, errutil.BadRequest("User does not belong to a user namespace")
}
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
return false, err
}
query := star.IsStarredByUserQuery{UserID: userID, DashboardID: dashID}
return hs.starService.IsStarredByUser(c.Req.Context(), &query) return hs.starService.IsStarredByUser(c.Req.Context(), &query)
} }
func dashboardGuardianResponse(err error) response.Response { func dashboardGuardianResponse(err error) response.Response {
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Error while checking dashboard permissions", err) return response.Error(500, "Error while checking dashboard permissions", err)
} }
return response.Error(http.StatusForbidden, "Access denied to this dashboard", nil) return response.Error(403, "Access denied to this dashboard", nil)
} }
// swagger:route POST /dashboards/trim dashboards trimDashboard // swagger:route POST /dashboards/trim dashboards trimDashboard
@ -109,7 +95,7 @@ func (hs *HTTPServer) TrimDashboard(c *contextmodel.ReqContext) response.Respons
// 500: internalServerError // 500: internalServerError
func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response { func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response {
uid := web.Params(c.Req)[":uid"] uid := web.Params(c.Req)[":uid"]
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid) dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, 0, uid)
if rsp != nil { if rsp != nil {
return rsp return rsp
} }
@ -122,9 +108,9 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
// If public dashboards is enabled and we have a public dashboard, update meta // If public dashboards is enabled and we have a public dashboard, update meta
// values // values
if hs.Features.IsEnabled(featuremgmt.FlagPublicDashboards) { if hs.Features.IsEnabled(featuremgmt.FlagPublicDashboards) {
publicDashboard, err := hs.PublicDashboardsApi.PublicDashboardService.FindByDashboardUid(c.Req.Context(), c.SignedInUser.GetOrgID(), dash.UID) publicDashboard, err := hs.PublicDashboardsApi.PublicDashboardService.FindByDashboardUid(c.Req.Context(), c.OrgID, dash.UID)
if err != nil && !errors.Is(err, publicdashboardModels.ErrPublicDashboardNotFound) { if err != nil && !errors.Is(err, publicdashboardModels.ErrPublicDashboardNotFound) {
return response.Error(http.StatusInternalServerError, "Error while retrieving public dashboards", err) return response.Error(500, "Error while retrieving public dashboards", err)
} }
if publicDashboard != nil { if publicDashboard != nil {
@ -142,10 +128,10 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
} }
} }
if isEmptyData { if isEmptyData {
return response.Error(http.StatusInternalServerError, "Error while loading dashboard, dashboard data is invalid", nil) return response.Error(500, "Error while loading dashboard, dashboard data is invalid", nil)
} }
} }
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser) guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil { if err != nil {
return response.Err(err) return response.Err(err)
} }
@ -160,7 +146,7 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
isStarred, err := hs.isDashboardStarredByUser(c, dash.ID) isStarred, err := hs.isDashboardStarredByUser(c, dash.ID)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Error while checking if dashboard was starred by user", err) return response.Error(500, "Error while checking if dashboard was starred by user", err)
} }
// Finding creator and last updater of the dashboard // Finding creator and last updater of the dashboard
updater, creator := anonString, anonString updater, creator := anonString, anonString
@ -200,13 +186,13 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
// lookup folder title // lookup folder title
if dash.FolderID > 0 { if dash.FolderID > 0 {
query := dashboards.GetDashboardQuery{ID: dash.FolderID, OrgID: c.SignedInUser.GetOrgID()} query := dashboards.GetDashboardQuery{ID: dash.FolderID, OrgID: c.OrgID}
queryResult, err := hs.DashboardService.GetDashboard(c.Req.Context(), &query) queryResult, err := hs.DashboardService.GetDashboard(c.Req.Context(), &query)
if err != nil { if err != nil {
if errors.Is(err, dashboards.ErrFolderNotFound) { if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.Error(http.StatusNotFound, "Folder not found", err) return response.Error(404, "Folder not found", err)
} }
return response.Error(http.StatusInternalServerError, "Dashboard folder could not be read", err) return response.Error(500, "Dashboard folder could not be read", err)
} }
meta.FolderUid = queryResult.UID meta.FolderUid = queryResult.UID
meta.FolderTitle = queryResult.Title meta.FolderTitle = queryResult.Title
@ -215,7 +201,7 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
provisioningData, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardID(c.Req.Context(), dash.ID) provisioningData, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardID(c.Req.Context(), dash.ID)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Error while checking if dashboard is provisioned", err) return response.Error(500, "Error while checking if dashboard is provisioned", err)
} }
if provisioningData != nil { if provisioningData != nil {
@ -289,7 +275,7 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in
queryResult, err := hs.DashboardService.GetDashboard(ctx, &query) queryResult, err := hs.DashboardService.GetDashboard(ctx, &query)
if err != nil { if err != nil {
return nil, response.Error(http.StatusNotFound, "Dashboard not found", err) return nil, response.Error(404, "Dashboard not found", err)
} }
return queryResult, nil return queryResult, nil
@ -312,11 +298,11 @@ func (hs *HTTPServer) DeleteDashboardByUID(c *contextmodel.ReqContext) response.
} }
func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Response { func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Response {
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, web.Params(c.Req)[":uid"]) dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, 0, web.Params(c.Req)[":uid"])
if rsp != nil { if rsp != nil {
return rsp return rsp
} }
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser) guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil { if err != nil {
return response.Err(err) return response.Err(err)
} }
@ -325,17 +311,10 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
namespaceID, userIDStr := c.SignedInUser.GetNamespacedID()
// disconnect all library elements for this dashboard // disconnect all library elements for this dashboard
err = hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.ID) err = hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.ID)
if err != nil { if err != nil {
hs.log.Error( hs.log.Error("Failed to disconnect library elements", "dashboard", dash.ID, "user", c.SignedInUser.UserID, "error", err)
"Failed to disconnect library elements",
"dashboard", dash.ID,
"namespaceID", namespaceID,
"user", userIDStr,
"error", err)
} }
// deletes all related public dashboard entities // deletes all related public dashboard entities
@ -344,7 +323,7 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
hs.log.Error("Failed to delete public dashboard") hs.log.Error("Failed to delete public dashboard")
} }
err = hs.DashboardService.DeleteDashboard(c.Req.Context(), dash.ID, c.SignedInUser.GetOrgID()) err = hs.DashboardService.DeleteDashboard(c.Req.Context(), dash.ID, c.OrgID)
if err != nil { if err != nil {
var dashboardErr dashboards.DashboardErr var dashboardErr dashboards.DashboardErr
if ok := errors.As(err, &dashboardErr); ok { if ok := errors.As(err, &dashboardErr); ok {
@ -352,16 +331,11 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err) return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err)
} }
} }
return response.Error(http.StatusInternalServerError, "Failed to delete dashboard", err) return response.Error(500, "Failed to delete dashboard", err)
}
userDTODisplay, err := user.NewUserDisplayDTOFromRequester(c.SignedInUser)
if err != nil {
return response.Error(http.StatusInternalServerError, "Error while parsing the user DTO model", err)
} }
if hs.Live != nil { if hs.Live != nil {
err := hs.Live.GrafanaScope.Dashboards.DashboardDeleted(c.SignedInUser.GetOrgID(), userDTODisplay, dash.UID) err := hs.Live.GrafanaScope.Dashboards.DashboardDeleted(c.OrgID, c.ToUserDisplayDTO(), dash.UID)
if err != nil { if err != nil {
hs.log.Error("Failed to broadcast delete info", "dashboard", dash.UID, "error", err) hs.log.Error("Failed to broadcast delete info", "dashboard", dash.UID, "error", err)
} }
@ -422,26 +396,19 @@ func (hs *HTTPServer) PostDashboard(c *contextmodel.ReqContext) response.Respons
func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.SaveDashboardCommand) response.Response { func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.SaveDashboardCommand) response.Response {
ctx := c.Req.Context() ctx := c.Req.Context()
var err error var err error
cmd.OrgID = c.OrgID
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID() cmd.UserID = c.UserID
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
hs.log.Warn("Error while parsing user ID", "namespaceID", namespaceID, "userID", userIDstr)
}
cmd.OrgID = c.SignedInUser.GetOrgID()
cmd.UserID = userID
if cmd.FolderUID != "" { if cmd.FolderUID != "" {
folder, err := hs.folderService.Get(ctx, &folder.GetFolderQuery{ folder, err := hs.folderService.Get(ctx, &folder.GetFolderQuery{
OrgID: c.SignedInUser.GetOrgID(), OrgID: c.OrgID,
UID: &cmd.FolderUID, UID: &cmd.FolderUID,
SignedInUser: c.SignedInUser, SignedInUser: c.SignedInUser,
}) })
if err != nil { if err != nil {
if errors.Is(err, dashboards.ErrFolderNotFound) { if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.Error(http.StatusBadRequest, "Folder not found", err) return response.Error(400, "Folder not found", err)
} }
return response.Error(http.StatusInternalServerError, "Error while checking folder ID", err) return response.Error(500, "Error while checking folder ID", err)
} }
cmd.FolderID = folder.ID cmd.FolderID = folder.ID
} }
@ -451,10 +418,10 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
if newDashboard { if newDashboard {
limitReached, err := hs.QuotaService.QuotaReached(c, dashboards.QuotaTargetSrv) limitReached, err := hs.QuotaService.QuotaReached(c, dashboards.QuotaTargetSrv)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "failed to get quota", err) return response.Error(500, "failed to get quota", err)
} }
if limitReached { if limitReached {
return response.Error(http.StatusForbidden, "Quota reached", nil) return response.Error(403, "Quota reached", nil)
} }
} }
@ -462,13 +429,13 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
if dash.ID != 0 { if dash.ID != 0 {
data, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardID(c.Req.Context(), dash.ID) data, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardID(c.Req.Context(), dash.ID)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Error while checking if dashboard is provisioned using ID", err) return response.Error(500, "Error while checking if dashboard is provisioned using ID", err)
} }
provisioningData = data provisioningData = data
} else if dash.UID != "" { } else if dash.UID != "" {
data, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardUID(c.Req.Context(), dash.OrgID, dash.UID) data, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardUID(c.Req.Context(), dash.OrgID, dash.UID)
if err != nil && !errors.Is(err, dashboards.ErrProvisionedDashboardNotFound) && !errors.Is(err, dashboards.ErrDashboardNotFound) { if err != nil && !errors.Is(err, dashboards.ErrProvisionedDashboardNotFound) && !errors.Is(err, dashboards.ErrDashboardNotFound) {
return response.Error(http.StatusInternalServerError, "Error while checking if dashboard is provisioned", err) return response.Error(500, "Error while checking if dashboard is provisioned", err)
} }
provisioningData = data provisioningData = data
} }
@ -481,7 +448,7 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
dashItem := &dashboards.SaveDashboardDTO{ dashItem := &dashboards.SaveDashboardDTO{
Dashboard: dash, Dashboard: dash,
Message: cmd.Message, Message: cmd.Message,
OrgID: c.SignedInUser.GetOrgID(), OrgID: c.OrgID,
User: c.SignedInUser, User: c.SignedInUser,
Overwrite: cmd.Overwrite, Overwrite: cmd.Overwrite,
} }
@ -494,19 +461,14 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
dashboard = dash // the original request dashboard = dash // the original request
} }
userDTODisplay, err := user.NewUserDisplayDTOFromRequester(c.SignedInUser)
if err != nil {
return response.Error(http.StatusInternalServerError, "Error while parsing the user DTO model", err)
}
// This will broadcast all save requests only if a `gitops` observer exists. // This will broadcast all save requests only if a `gitops` observer exists.
// gitops is useful when trying to save dashboards in an environment where the user can not save // gitops is useful when trying to save dashboards in an environment where the user can not save
channel := hs.Live.GrafanaScope.Dashboards channel := hs.Live.GrafanaScope.Dashboards
liveerr := channel.DashboardSaved(c.SignedInUser.GetOrgID(), userDTODisplay, cmd.Message, dashboard, err) liveerr := channel.DashboardSaved(c.SignedInUser.OrgID, c.SignedInUser.ToUserDisplayDTO(), cmd.Message, dashboard, err)
// When an error exists, but the value broadcast to a gitops listener return 202 // When an error exists, but the value broadcast to a gitops listener return 202
if liveerr == nil && err != nil && channel.HasGitOpsObserver(c.SignedInUser.GetOrgID()) { if liveerr == nil && err != nil && channel.HasGitOpsObserver(c.SignedInUser.OrgID) {
return response.JSON(http.StatusAccepted, util.DynMap{ return response.JSON(202, util.DynMap{
"status": "pending", "status": "pending",
"message": "changes were broadcast to the gitops listener", "message": "changes were broadcast to the gitops listener",
}) })
@ -530,7 +492,7 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
// connect library panels for this dashboard after the dashboard is stored and has an ID // connect library panels for this dashboard after the dashboard is stored and has an ID
err = hs.LibraryPanelService.ConnectLibraryPanelsForDashboard(ctx, c.SignedInUser, dashboard) err = hs.LibraryPanelService.ConnectLibraryPanelsForDashboard(ctx, c.SignedInUser, dashboard)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Error while connecting library panels", err) return response.Error(500, "Error while connecting library panels", err)
} }
c.TimeRequest(metrics.MApiDashboardSave) c.TimeRequest(metrics.MApiDashboardSave)
@ -553,17 +515,12 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
// 401: unauthorisedError // 401: unauthorisedError
// 500: internalServerError // 500: internalServerError
func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response { func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response {
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID() prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.OrgID, UserID: c.SignedInUser.UserID, Teams: c.Teams}
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
hs.log.Warn("Error while parsing user ID", "namespaceID", namespaceID, "userID", userIDstr, "err", err)
}
prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.SignedInUser.GetOrgID(), UserID: userID, Teams: c.SignedInUser.GetTeams()}
homePage := hs.Cfg.HomePage homePage := hs.Cfg.HomePage
preference, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery) preference, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to get preferences", err) return response.Error(500, "Failed to get preferences", err)
} }
if preference.HomeDashboardID == 0 && len(homePage) > 0 { if preference.HomeDashboardID == 0 && len(homePage) > 0 {
@ -592,7 +549,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Resp
// nolint:gosec // nolint:gosec
file, err := os.Open(filePath) file, err := os.Open(filePath)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to load home dashboard", err) return response.Error(500, "Failed to load home dashboard", err)
} }
defer func() { defer func() {
if err := file.Close(); err != nil { if err := file.Close(); err != nil {
@ -607,7 +564,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Resp
jsonParser := json.NewDecoder(file) jsonParser := json.NewDecoder(file)
if err := jsonParser.Decode(dash.Dashboard); err != nil { if err := jsonParser.Decode(dash.Dashboard); err != nil {
return response.Error(http.StatusInternalServerError, "Failed to load home dashboard", err) return response.Error(500, "Failed to load home dashboard", err)
} }
hs.addGettingStartedPanelToHomeDashboard(c, dash.Dashboard) hs.addGettingStartedPanelToHomeDashboard(c, dash.Dashboard)
@ -679,12 +636,12 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
} }
} }
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), dashID, dashUID) dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, dashID, dashUID)
if rsp != nil { if rsp != nil {
return rsp return rsp
} }
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser) guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil { if err != nil {
return response.Err(err) return response.Err(err)
} }
@ -693,7 +650,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
} }
query := dashver.ListDashboardVersionsQuery{ query := dashver.ListDashboardVersionsQuery{
OrgID: c.SignedInUser.GetOrgID(), OrgID: c.OrgID,
DashboardID: dash.ID, DashboardID: dash.ID,
DashboardUID: dash.UID, DashboardUID: dash.UID,
Limit: c.QueryInt("limit"), Limit: c.QueryInt("limit"),
@ -702,7 +659,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
versions, err := hs.dashboardVersionService.List(c.Req.Context(), &query) versions, err := hs.dashboardVersionService.List(c.Req.Context(), &query)
if err != nil { if err != nil {
return response.Error(http.StatusNotFound, fmt.Sprintf("No versions found for dashboardId %d", dash.ID), err) return response.Error(404, fmt.Sprintf("No versions found for dashboardId %d", dash.ID), err)
} }
loginMem := make(map[int64]string, len(versions)) loginMem := make(map[int64]string, len(versions))
@ -790,12 +747,12 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R
} }
} }
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), dashID, dashUID) dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, dashID, dashUID)
if rsp != nil { if rsp != nil {
return rsp return rsp
} }
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser) guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil { if err != nil {
return response.Err(err) return response.Err(err)
} }
@ -806,7 +763,7 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R
version, _ := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 32) version, _ := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 32)
query := dashver.GetDashboardVersionQuery{ query := dashver.GetDashboardVersionQuery{
OrgID: c.SignedInUser.GetOrgID(), OrgID: c.OrgID,
DashboardID: dash.ID, DashboardID: dash.ID,
DashboardUID: dash.UID, DashboardUID: dash.UID,
Version: int(version), Version: int(version),
@ -814,7 +771,7 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R
res, err := hs.dashboardVersionService.Get(c.Req.Context(), &query) res, err := hs.dashboardVersionService.Get(c.Req.Context(), &query)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dash.ID), err) return response.Error(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dash.ID), err)
} }
creator := anonString creator := anonString
@ -922,7 +879,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
if err := web.Bind(c.Req, &apiOptions); err != nil { if err := web.Bind(c.Req, &apiOptions); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
guardianBase, err := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.SignedInUser.GetOrgID(), c.SignedInUser) guardianBase, err := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.OrgID, c.SignedInUser)
if err != nil { if err != nil {
return response.Err(err) return response.Err(err)
} }
@ -932,7 +889,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
} }
if apiOptions.Base.DashboardId != apiOptions.New.DashboardId { if apiOptions.Base.DashboardId != apiOptions.New.DashboardId {
guardianNew, err := guardian.New(c.Req.Context(), apiOptions.New.DashboardId, c.SignedInUser.GetOrgID(), c.SignedInUser) guardianNew, err := guardian.New(c.Req.Context(), apiOptions.New.DashboardId, c.OrgID, c.SignedInUser)
if err != nil { if err != nil {
return response.Err(err) return response.Err(err)
} }
@ -943,7 +900,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
} }
options := dashdiffs.Options{ options := dashdiffs.Options{
OrgId: c.SignedInUser.GetOrgID(), OrgId: c.OrgID,
DiffType: dashdiffs.ParseDiffType(apiOptions.DiffType), DiffType: dashdiffs.ParseDiffType(apiOptions.DiffType),
Base: dashdiffs.DiffTarget{ Base: dashdiffs.DiffTarget{
DashboardId: apiOptions.Base.DashboardId, DashboardId: apiOptions.Base.DashboardId,
@ -966,9 +923,9 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
baseVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &baseVersionQuery) baseVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &baseVersionQuery)
if err != nil { if err != nil {
if errors.Is(err, dashver.ErrDashboardVersionNotFound) { if errors.Is(err, dashver.ErrDashboardVersionNotFound) {
return response.Error(http.StatusNotFound, "Dashboard version not found", err) return response.Error(404, "Dashboard version not found", err)
} }
return response.Error(http.StatusInternalServerError, "Unable to compute diff", err) return response.Error(500, "Unable to compute diff", err)
} }
newVersionQuery := dashver.GetDashboardVersionQuery{ newVersionQuery := dashver.GetDashboardVersionQuery{
@ -980,9 +937,9 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
newVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &newVersionQuery) newVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &newVersionQuery)
if err != nil { if err != nil {
if errors.Is(err, dashver.ErrDashboardVersionNotFound) { if errors.Is(err, dashver.ErrDashboardVersionNotFound) {
return response.Error(http.StatusNotFound, "Dashboard version not found", err) return response.Error(404, "Dashboard version not found", err)
} }
return response.Error(http.StatusInternalServerError, "Unable to compute diff", err) return response.Error(500, "Unable to compute diff", err)
} }
baseData := baseVersionRes.Data baseData := baseVersionRes.Data
@ -992,9 +949,9 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
if err != nil { if err != nil {
if errors.Is(err, dashver.ErrDashboardVersionNotFound) { if errors.Is(err, dashver.ErrDashboardVersionNotFound) {
return response.Error(http.StatusNotFound, "Dashboard version not found", err) return response.Error(404, "Dashboard version not found", err)
} }
return response.Error(http.StatusInternalServerError, "Unable to compute diff", err) return response.Error(500, "Unable to compute diff", err)
} }
if options.DiffType == dashdiffs.DiffDelta { if options.DiffType == dashdiffs.DiffDelta {
@ -1046,12 +1003,12 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
} }
} }
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), dashID, dashUID) dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, dashID, dashUID)
if rsp != nil { if rsp != nil {
return rsp return rsp
} }
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser) guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil { if err != nil {
return response.Err(err) return response.Err(err)
} }
@ -1060,21 +1017,16 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
versionQuery := dashver.GetDashboardVersionQuery{DashboardID: dashID, DashboardUID: dash.UID, Version: apiCmd.Version, OrgID: c.SignedInUser.GetOrgID()} versionQuery := dashver.GetDashboardVersionQuery{DashboardID: dashID, DashboardUID: dash.UID, Version: apiCmd.Version, OrgID: c.OrgID}
version, err := hs.dashboardVersionService.Get(c.Req.Context(), &versionQuery) version, err := hs.dashboardVersionService.Get(c.Req.Context(), &versionQuery)
if err != nil { if err != nil {
return response.Error(http.StatusNotFound, "Dashboard version not found", nil) return response.Error(404, "Dashboard version not found", nil)
}
userID, err := identity.IntIdentifier(c.SignedInUser.GetNamespacedID())
if err != nil {
return response.Error(http.StatusInternalServerError, "failed to get user id", err)
} }
saveCmd := dashboards.SaveDashboardCommand{} saveCmd := dashboards.SaveDashboardCommand{}
saveCmd.RestoredFrom = version.Version saveCmd.RestoredFrom = version.Version
saveCmd.OrgID = c.SignedInUser.GetOrgID() saveCmd.OrgID = c.OrgID
saveCmd.UserID = userID saveCmd.UserID = c.UserID
saveCmd.Dashboard = version.Data saveCmd.Dashboard = version.Data
saveCmd.Dashboard.Set("version", dash.Version) saveCmd.Dashboard.Set("version", dash.Version)
saveCmd.Dashboard.Set("uid", dash.UID) saveCmd.Dashboard.Set("uid", dash.UID)
@ -1093,7 +1045,7 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
// 401: unauthorisedError // 401: unauthorisedError
// 500: internalServerError // 500: internalServerError
func (hs *HTTPServer) GetDashboardTags(c *contextmodel.ReqContext) { func (hs *HTTPServer) GetDashboardTags(c *contextmodel.ReqContext) {
query := dashboards.GetDashboardTagsQuery{OrgID: c.SignedInUser.GetOrgID()} query := dashboards.GetDashboardTagsQuery{OrgID: c.OrgID}
queryResult, err := hs.DashboardService.GetDashboardTags(c.Req.Context(), &query) queryResult, err := hs.DashboardService.GetDashboardTags(c.Req.Context(), &query)
if err != nil { if err != nil {
c.JsonApiErr(500, "Failed to get tags from database", err) c.JsonApiErr(500, "Failed to get tags from database", err)

View File

@ -78,7 +78,6 @@ func TestGetHomeDashboard(t *testing.T) {
preferenceService: prefService, preferenceService: prefService,
dashboardVersionService: dashboardVersionService, dashboardVersionService: dashboardVersionService,
Kinds: corekind.NewBase(nil), Kinds: corekind.NewBase(nil),
log: log.New("test-logger"),
} }
tests := []struct { tests := []struct {
@ -203,7 +202,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc) hs.callGetDashboardVersion(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
@ -212,7 +211,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
hs.callGetDashboardVersions(sc) hs.callGetDashboardVersions(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -235,7 +234,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc) hs.callGetDashboardVersion(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
var version *dashver.DashboardVersionMeta var version *dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&version) err := json.NewDecoder(sc.resp.Body).Decode(&version)
require.NoError(t, err) require.NoError(t, err)
@ -247,7 +246,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp() setUp()
hs.callGetDashboardVersions(sc) hs.callGetDashboardVersions(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
}) })
@ -311,7 +310,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.handlerFunc = hs.GetDashboard sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
@ -320,7 +319,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil) hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
@ -329,7 +328,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc) hs.callGetDashboardVersion(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
@ -337,7 +336,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp() setUp()
hs.callGetDashboardVersions(sc) hs.callGetDashboardVersions(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -350,7 +349,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.handlerFunc = hs.GetDashboard sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
@ -358,7 +357,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp() setUp()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil) hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
@ -366,7 +365,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp() setUp()
hs.callGetDashboardVersion(sc) hs.callGetDashboardVersion(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
@ -374,7 +373,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp() setUp()
hs.callGetDashboardVersions(sc) hs.callGetDashboardVersions(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -414,7 +413,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
pubdashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil) pubdashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil)
hs.callDeleteDashboardByUID(t, sc, dashboardService, pubdashService) hs.callDeleteDashboardByUID(t, sc, dashboardService, pubdashService)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -448,7 +447,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUpInner() setUpInner()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil) hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -487,21 +486,21 @@ func TestDashboardAPIEndpoint(t *testing.T) {
pubdashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil) pubdashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil)
hs.callDeleteDashboardByUID(t, sc, dashboardService, pubdashService) hs.callDeleteDashboardByUID(t, sc, dashboardService, pubdashService)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
hs.callGetDashboardVersion(sc) hs.callGetDashboardVersion(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
hs.callGetDashboardVersions(sc) hs.callGetDashboardVersions(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -531,21 +530,21 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUpInner() setUpInner()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil) hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
hs.callGetDashboardVersion(sc) hs.callGetDashboardVersion(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
hs.callGetDashboardVersions(sc) hs.callGetDashboardVersions(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
}) })
@ -655,7 +654,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
postDashboardScenario(t, "When calling POST on", "/api/dashboards", "/api/dashboards", cmd, dashboardService, mockFolder, func(sc *scenarioContext) { postDashboardScenario(t, "When calling POST on", "/api/dashboards", "/api/dashboards", cmd, dashboardService, mockFolder, func(sc *scenarioContext) {
callPostDashboard(sc) callPostDashboard(sc)
assert.Equal(t, http.StatusInternalServerError, sc.resp.Code) assert.Equal(t, 500, sc.resp.Code)
}) })
}) })
@ -665,23 +664,23 @@ func TestDashboardAPIEndpoint(t *testing.T) {
SaveError error SaveError error
ExpectedStatusCode int ExpectedStatusCode int
}{ }{
{SaveError: dashboards.ErrDashboardNotFound, ExpectedStatusCode: http.StatusNotFound}, {SaveError: dashboards.ErrDashboardNotFound, ExpectedStatusCode: 404},
{SaveError: dashboards.ErrFolderNotFound, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrFolderNotFound, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameUIDExists, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardWithSameUIDExists, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameNameInFolderExists, ExpectedStatusCode: http.StatusPreconditionFailed}, {SaveError: dashboards.ErrDashboardWithSameNameInFolderExists, ExpectedStatusCode: 412},
{SaveError: dashboards.ErrDashboardVersionMismatch, ExpectedStatusCode: http.StatusPreconditionFailed}, {SaveError: dashboards.ErrDashboardVersionMismatch, ExpectedStatusCode: 412},
{SaveError: dashboards.ErrDashboardTitleEmpty, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardTitleEmpty, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderCannotHaveParent, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardFolderCannotHaveParent, ExpectedStatusCode: 400},
{SaveError: alerting.ValidationError{Reason: "Mu"}, ExpectedStatusCode: http.StatusUnprocessableEntity}, {SaveError: alerting.ValidationError{Reason: "Mu"}, ExpectedStatusCode: 422},
{SaveError: dashboards.ErrDashboardTypeMismatch, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardTypeMismatch, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderWithSameNameAsDashboard, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardFolderWithSameNameAsDashboard, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameNameAsFolder, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardWithSameNameAsFolder, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderNameExists, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardFolderNameExists, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: http.StatusForbidden}, {SaveError: dashboards.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: 403},
{SaveError: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardCannotSaveProvisionedDashboard, ExpectedStatusCode: http.StatusBadRequest}, {SaveError: dashboards.ErrDashboardCannotSaveProvisionedDashboard, ExpectedStatusCode: 400},
{SaveError: dashboards.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: http.StatusPreconditionFailed}, {SaveError: dashboards.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: 412},
} }
cmd := dashboards.SaveDashboardCommand{ cmd := dashboards.SaveDashboardCommand{
@ -698,7 +697,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
postDashboardScenario(t, fmt.Sprintf("Expect '%s' error when calling POST on", tc.SaveError.Error()), postDashboardScenario(t, fmt.Sprintf("Expect '%s' error when calling POST on", tc.SaveError.Error()),
"/api/dashboards", "/api/dashboards", cmd, dashboardService, nil, func(sc *scenarioContext) { "/api/dashboards", "/api/dashboards", cmd, dashboardService, nil, func(sc *scenarioContext) {
callPostDashboard(sc) callPostDashboard(sc)
assert.Equal(t, tc.ExpectedStatusCode, sc.resp.Code, sc.resp.Body.String()) assert.Equal(t, tc.ExpectedStatusCode, sc.resp.Code)
}) })
} }
}) })
@ -717,7 +716,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callPostDashboard(sc) callPostDashboard(sc)
result := sc.ToJSON() result := sc.ToJSON()
assert.Equal(t, http.StatusUnprocessableEntity, sc.resp.Code) assert.Equal(t, 422, sc.resp.Code)
assert.False(t, result.Get("isValid").MustBool()) assert.False(t, result.Get("isValid").MustBool())
assert.NotEmpty(t, result.Get("message").MustString()) assert.NotEmpty(t, result.Get("message").MustString())
}, sqlmock) }, sqlmock)
@ -733,7 +732,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callPostDashboard(sc) callPostDashboard(sc)
result := sc.ToJSON() result := sc.ToJSON()
assert.Equal(t, http.StatusPreconditionFailed, sc.resp.Code) assert.Equal(t, 412, sc.resp.Code)
assert.False(t, result.Get("isValid").MustBool()) assert.False(t, result.Get("isValid").MustBool())
assert.Equal(t, "invalid schema version", result.Get("message").MustString()) assert.Equal(t, "invalid schema version", result.Get("message").MustString())
}, sqlmock) }, sqlmock)
@ -752,7 +751,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callPostDashboard(sc) callPostDashboard(sc)
result := sc.ToJSON() result := sc.ToJSON()
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
assert.True(t, result.Get("isValid").MustBool()) assert.True(t, result.Get("isValid").MustBool())
}, sqlmock) }, sqlmock)
}) })
@ -804,7 +803,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
setUp() setUp()
callPostDashboard(sc) callPostDashboard(sc)
assert.Equal(t, http.StatusForbidden, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, sqlmock, fakeDashboardVersionService) }, sqlmock, fakeDashboardVersionService)
}) })
@ -814,7 +813,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
// This test shouldn't hit GetDashboardACLInfoList, so no setup needed // This test shouldn't hit GetDashboardACLInfoList, so no setup needed
sc.dashboardVersionService = fakeDashboardVersionService sc.dashboardVersionService = fakeDashboardVersionService
callPostDashboard(sc) callPostDashboard(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}, sqlmock, fakeDashboardVersionService) }, sqlmock, fakeDashboardVersionService)
}) })
}) })
@ -851,7 +850,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.dashboardVersionService = fakeDashboardVersionService sc.dashboardVersionService = fakeDashboardVersionService
callRestoreDashboardVersion(sc) callRestoreDashboardVersion(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -884,7 +883,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
restoreDashboardVersionScenario(t, "When calling POST on", "/api/dashboards/id/1/restore", restoreDashboardVersionScenario(t, "When calling POST on", "/api/dashboards/id/1/restore",
"/api/dashboards/id/:dashboardId/restore", dashboardService, fakeDashboardVersionService, cmd, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/restore", dashboardService, fakeDashboardVersionService, cmd, func(sc *scenarioContext) {
callRestoreDashboardVersion(sc) callRestoreDashboardVersion(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -940,7 +939,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
} }
hs.callGetDashboard(sc) hs.callGetDashboard(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
dash := dtos.DashboardFullWithMeta{} dash := dtos.DashboardFullWithMeta{}
err := json.NewDecoder(sc.resp.Body).Decode(&dash) err := json.NewDecoder(sc.resp.Body).Decode(&dash)
@ -1012,7 +1011,7 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
ExpectedUser: &user.User{ID: 1, Login: "test-user"}, ExpectedUser: &user.User{ID: 1, Login: "test-user"},
}).callGetDashboardVersions(sc) }).callGetDashboardVersions(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
var versions []dashver.DashboardVersionMeta var versions []dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&versions) err := json.NewDecoder(sc.resp.Body).Decode(&versions)
require.NoError(t, err) require.NoError(t, err)
@ -1038,7 +1037,7 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
ExpectedError: user.ErrUserNotFound, ExpectedError: user.ErrUserNotFound,
}).callGetDashboardVersions(sc) }).callGetDashboardVersions(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
var versions []dashver.DashboardVersionMeta var versions []dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&versions) err := json.NewDecoder(sc.resp.Body).Decode(&versions)
require.NoError(t, err) require.NoError(t, err)
@ -1064,7 +1063,7 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
ExpectedError: fmt.Errorf("some error"), ExpectedError: fmt.Errorf("some error"),
}).callGetDashboardVersions(sc) }).callGetDashboardVersions(sc)
assert.Equal(t, http.StatusOK, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
var versions []dashver.DashboardVersionMeta var versions []dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&versions) err := json.NewDecoder(sc.resp.Body).Decode(&versions)
require.NoError(t, err) require.NoError(t, err)
@ -1193,7 +1192,6 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
Features: featuremgmt.WithFeatures(), Features: featuremgmt.WithFeatures(),
Kinds: corekind.NewBase(nil), Kinds: corekind.NewBase(nil),
accesscontrolService: actest.FakeService{}, accesscontrolService: actest.FakeService{},
log: log.New("test-logger"),
} }
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)

View File

@ -12,10 +12,10 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -68,8 +68,8 @@ type Service struct {
} }
type pluginContextProvider interface { type pluginContextProvider interface {
Get(ctx context.Context, pluginID string, user identity.Requester, orgID int64) (backend.PluginContext, error) Get(ctx context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error)
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, error)
} }
func ProvideService(cfg *setting.Cfg, pluginClient plugins.Client, pCtxProvider *plugincontext.Provider, func ProvideService(cfg *setting.Cfg, pluginClient plugins.Client, pCtxProvider *plugincontext.Provider,

View File

@ -5,8 +5,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
) )
type fakePluginContextProvider struct { type fakePluginContextProvider struct {
@ -20,7 +20,7 @@ type fakePluginContextProvider struct {
var _ pluginContextProvider = &fakePluginContextProvider{} var _ pluginContextProvider = &fakePluginContextProvider{}
func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user identity.Requester, orgID int64) (backend.PluginContext, error) { func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error) {
f.recordings = append(f.recordings, struct { f.recordings = append(f.recordings, struct {
method string method string
params []interface{} params []interface{}
@ -31,9 +31,9 @@ func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user
var u *backend.User var u *backend.User
if user != nil { if user != nil {
u = &backend.User{ u = &backend.User{
Login: user.GetLogin(), Login: user.Login,
Name: user.GetDisplayName(), Name: user.Name,
Email: user.GetEmail(), Email: user.Email,
} }
} }
return backend.PluginContext{ return backend.PluginContext{
@ -45,7 +45,7 @@ func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user
}, nil }, nil
} }
func (f *fakePluginContextProvider) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) { func (f *fakePluginContextProvider) GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, error) {
f.recordings = append(f.recordings, struct { f.recordings = append(f.recordings, struct {
method string method string
params []interface{} params []interface{}
@ -57,7 +57,7 @@ func (f *fakePluginContextProvider) GetWithDataSource(ctx context.Context, plugi
orgId := int64(1) orgId := int64(1)
if user != nil { if user != nil {
orgId = user.GetOrgID() orgId = user.OrgID
} }
r, err := f.Get(ctx, pluginID, user, orgId) r, err := f.Get(ctx, pluginID, user, orgId)
if ds != nil { if ds != nil {

View File

@ -8,8 +8,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
) )
// Request is similar to plugins.DataQuery but with the Time Ranges is per Query. // Request is similar to plugins.DataQuery but with the Time Ranges is per Query.
@ -18,7 +18,7 @@ type Request struct {
Debug bool Debug bool
OrgId int64 OrgId int64
Queries []Query Queries []Query
User identity.Requester User *user.SignedInUser
} }
// Query is like plugins.DataSubQuery, but with a a time range, and only the UID // Query is like plugins.DataSubQuery, but with a a time range, and only the UID

View File

@ -4,8 +4,8 @@ import (
"sync" "sync"
"github.com/grafana/grafana/pkg/components/null" "github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/user"
) )
// Job holds state about when the alert rule should be evaluated. // Job holds state about when the alert rule should be evaluated.
@ -46,7 +46,7 @@ type EvalMatch struct {
} }
type DashAlertInfo struct { type DashAlertInfo struct {
User identity.Requester User *user.SignedInUser
Dash *dashboards.Dashboard Dash *dashboards.Dashboard
OrgID int64 OrgID int64
} }

View File

@ -9,7 +9,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboardimport" "github.com/grafana/grafana/pkg/services/dashboardimport"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder"
@ -84,12 +83,9 @@ func TestImportDashboardService(t *testing.T) {
require.NotNil(t, resp) require.NotNil(t, resp)
require.Equal(t, "UDdpyzz7z", resp.UID) require.Equal(t, "UDdpyzz7z", resp.UID)
userID, err := identity.IntIdentifier(importDashboardArg.User.GetNamespacedID())
require.NoError(t, err)
require.NotNil(t, importDashboardArg) require.NotNil(t, importDashboardArg)
require.Equal(t, int64(3), importDashboardArg.OrgID) require.Equal(t, int64(3), importDashboardArg.OrgID)
require.Equal(t, int64(2), userID) require.Equal(t, int64(2), importDashboardArg.User.UserID)
require.Equal(t, "prometheus", importDashboardArg.Dashboard.PluginID) require.Equal(t, "prometheus", importDashboardArg.Dashboard.PluginID)
require.Equal(t, int64(5), importDashboardArg.Dashboard.FolderID) require.Equal(t, int64(5), importDashboardArg.Dashboard.FolderID)
@ -151,12 +147,9 @@ func TestImportDashboardService(t *testing.T) {
require.NotNil(t, resp) require.NotNil(t, resp)
require.Equal(t, "UDdpyzz7z", resp.UID) require.Equal(t, "UDdpyzz7z", resp.UID)
userID, err := identity.IntIdentifier(importDashboardArg.User.GetNamespacedID())
require.NoError(t, err)
require.NotNil(t, importDashboardArg) require.NotNil(t, importDashboardArg)
require.Equal(t, int64(3), importDashboardArg.OrgID) require.Equal(t, int64(3), importDashboardArg.OrgID)
require.Equal(t, int64(2), userID) require.Equal(t, int64(2), importDashboardArg.User.UserID)
require.Equal(t, "", importDashboardArg.Dashboard.PluginID) require.Equal(t, "", importDashboardArg.Dashboard.PluginID)
require.Equal(t, int64(5), importDashboardArg.Dashboard.FolderID) require.Equal(t, int64(5), importDashboardArg.Dashboard.FolderID)

View File

@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana/pkg/kinds" "github.com/grafana/grafana/pkg/kinds"
"github.com/grafana/grafana/pkg/kinds/dashboard" "github.com/grafana/grafana/pkg/kinds/dashboard"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/quota"
@ -338,7 +337,7 @@ type GetDashboardRefByIDQuery struct {
type SaveDashboardDTO struct { type SaveDashboardDTO struct {
OrgID int64 OrgID int64
UpdatedAt time.Time UpdatedAt time.Time
User identity.Requester User *user.SignedInUser
Message string Message string
Overwrite bool Overwrite bool
Dashboard *Dashboard Dashboard *Dashboard

View File

@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/alerting" "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"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
@ -182,18 +181,12 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
} }
} }
namespaceID, userIDstr := dto.User.GetNamespacedID()
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
dr.log.Warn("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err)
}
cmd := &dashboards.SaveDashboardCommand{ cmd := &dashboards.SaveDashboardCommand{
Dashboard: dash.Data, Dashboard: dash.Data,
Message: dto.Message, Message: dto.Message,
OrgID: dto.OrgID, OrgID: dto.OrgID,
Overwrite: dto.Overwrite, Overwrite: dto.Overwrite,
UserID: userID, UserID: dto.User.UserID,
FolderID: dash.FolderID, FolderID: dash.FolderID,
IsFolder: dash.IsFolder, IsFolder: dash.IsFolder,
PluginID: dash.PluginID, PluginID: dash.PluginID,
@ -216,7 +209,7 @@ func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context.
// getGuardianForSavePermissionCheck returns the guardian to be used for checking permission of dashboard // getGuardianForSavePermissionCheck returns the guardian to be used for checking permission of dashboard
// It replaces deleted Dashboard.GetDashboardIdForSavePermissionCheck() // It replaces deleted Dashboard.GetDashboardIdForSavePermissionCheck()
func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user identity.Requester) (guardian.DashboardGuardian, error) { func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user *user.SignedInUser) (guardian.DashboardGuardian, error) {
newDashboard := d.ID == 0 newDashboard := d.ID == 0
if newDashboard { if newDashboard {
@ -304,8 +297,7 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt
if dto.Dashboard.ID == 0 { if dto.Dashboard.ID == 0 {
if err := dr.setDefaultPermissions(ctx, dto, dash, true); err != nil { if err := dr.setDefaultPermissions(ctx, dto, dash, true); err != nil {
namespaceID, userID := dto.User.GetNamespacedID() dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
} }
} }
@ -345,8 +337,7 @@ func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.C
if dto.Dashboard.ID == 0 { if dto.Dashboard.ID == 0 {
if err := dr.setDefaultPermissions(ctx, dto, dash, true); err != nil { if err := dr.setDefaultPermissions(ctx, dto, dash, true); err != nil {
namespaceID, userID := dto.User.GetNamespacedID() dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
} }
} }
@ -394,8 +385,7 @@ func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *dashboar
// new dashboard created // new dashboard created
if dto.Dashboard.ID == 0 { if dto.Dashboard.ID == 0 {
if err := dr.setDefaultPermissions(ctx, dto, dash, false); err != nil { if err := dr.setDefaultPermissions(ctx, dto, dash, false); err != nil {
namespaceID, userID := dto.User.GetNamespacedID() dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
} }
} }
@ -452,8 +442,7 @@ func (dr *DashboardServiceImpl) ImportDashboard(ctx context.Context, dto *dashbo
} }
if err := dr.setDefaultPermissions(ctx, dto, dash, false); err != nil { if err := dr.setDefaultPermissions(ctx, dto, dash, false); err != nil {
namespaceID, userID := dto.User.GetNamespacedID() dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
} }
return dash, nil return dash, nil
@ -473,16 +462,9 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
inFolder := dash.FolderID > 0 inFolder := dash.FolderID > 0
var permissions []accesscontrol.SetResourcePermissionCommand var permissions []accesscontrol.SetResourcePermissionCommand
namespaceID, userIDstr := dto.User.GetNamespacedID() if !provisioned && dto.User.IsRealUser() && !dto.User.IsAnonymous {
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
return err
}
if !provisioned && namespaceID == identity.NamespaceUser {
permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{
UserID: userID, Permission: dashboards.PERMISSION_ADMIN.String(), UserID: dto.User.UserID, Permission: dashboards.PERMISSION_ADMIN.String(),
}) })
} }
@ -498,7 +480,7 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
svc = dr.folderPermissions svc = dr.folderPermissions
} }
_, err = svc.SetPermissions(ctx, dto.OrgID, dash.UID, permissions...) _, err := svc.SetPermissions(ctx, dto.OrgID, dash.UID, permissions...)
if err != nil { if err != nil {
return err return err
} }

View File

@ -15,7 +15,6 @@ import (
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/alerting/models" "github.com/grafana/grafana/pkg/services/alerting/models"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
@ -113,12 +112,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sqlStore) err := callSaveWithError(t, cmd, sqlStore)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, "", sc.dashboardGuardianMock.DashUID) assert.Equal(t, "", sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When creating a new dashboard in other folder, it should create dashboard guardian for other folder with correct arguments and rsult in access denied error", permissionScenario(t, "When creating a new dashboard in other folder, it should create dashboard guardian for other folder with correct arguments and rsult in access denied error",
@ -136,12 +132,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.otherSavedFolder.ID, sc.dashboardGuardianMock.DashID) assert.Equal(t, sc.otherSavedFolder.ID, sc.dashboardGuardianMock.DashID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When creating a new dashboard by existing title in folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error", permissionScenario(t, "When creating a new dashboard by existing title in folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
@ -159,12 +152,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When creating a new dashboard by existing UID in folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error", permissionScenario(t, "When creating a new dashboard by existing UID in folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
@ -183,12 +173,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When updating a dashboard by existing id in the General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error", permissionScenario(t, "When updating a dashboard by existing id in the General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
@ -207,12 +194,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When updating a dashboard by existing id in other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error", permissionScenario(t, "When updating a dashboard by existing id in other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
@ -231,12 +215,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When moving a dashboard by existing ID to other folder from General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error", permissionScenario(t, "When moving a dashboard by existing ID to other folder from General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
@ -255,12 +236,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When moving a dashboard by existing id to the General folder from other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error", permissionScenario(t, "When moving a dashboard by existing id to the General folder from other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
@ -279,12 +257,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When moving a dashboard by existing uid to other folder from General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error", permissionScenario(t, "When moving a dashboard by existing uid to other folder from General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
@ -303,12 +278,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
permissionScenario(t, "When moving a dashboard by existing UID to the General folder from other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error", permissionScenario(t, "When moving a dashboard by existing UID to the General folder from other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
@ -327,12 +299,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetNamespacedID())
require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID) assert.Equal(t, cmd.OrgID, sc.dashboardGuardianMock.OrgID)
assert.Equal(t, cmd.UserID, userID) assert.Equal(t, cmd.UserID, sc.dashboardGuardianMock.User.UserID)
}) })
}) })

View File

@ -7,7 +7,7 @@ import (
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/infra/httpclient" "github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/user"
) )
// DataSourceService interface for interacting with datasources. // DataSourceService interface for interacting with datasources.
@ -64,8 +64,8 @@ type DataSourceService interface {
// CacheService interface for retrieving a cached datasource. // CacheService interface for retrieving a cached datasource.
type CacheService interface { type CacheService interface {
// GetDatasource gets a datasource identified by datasource numeric identifier. // GetDatasource gets a datasource identified by datasource numeric identifier.
GetDatasource(ctx context.Context, datasourceID int64, user identity.Requester, skipCache bool) (*DataSource, error) GetDatasource(ctx context.Context, datasourceID int64, user *user.SignedInUser, skipCache bool) (*DataSource, error)
// GetDatasourceByUID gets a datasource identified by datasource unique identifier (UID). // GetDatasourceByUID gets a datasource identified by datasource unique identifier (UID).
GetDatasourceByUID(ctx context.Context, datasourceUID string, user identity.Requester, skipCache bool) (*DataSource, error) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *user.SignedInUser, skipCache bool) (*DataSource, error)
} }

View File

@ -3,8 +3,8 @@ package datasources
import ( import (
"context" "context"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
) )
type FakeCacheService struct { type FakeCacheService struct {
@ -13,7 +13,7 @@ type FakeCacheService struct {
var _ datasources.CacheService = &FakeCacheService{} var _ datasources.CacheService = &FakeCacheService{}
func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64, user identity.Requester, skipCache bool) (*datasources.DataSource, error) { func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
for _, datasource := range c.DataSources { for _, datasource := range c.DataSources {
if datasource.ID == datasourceID { if datasource.ID == datasourceID {
return datasource, nil return datasource, nil
@ -22,7 +22,7 @@ func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64
return nil, datasources.ErrDataSourceNotFound return nil, datasources.ErrDataSourceNotFound
} }
func (c *FakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, user identity.Requester, skipCache bool) (*datasources.DataSource, error) { func (c *FakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
for _, datasource := range c.DataSources { for _, datasource := range c.DataSources {
if datasource.UID == datasourceUID { if datasource.UID == datasourceUID {
return datasource, nil return datasource, nil

View File

@ -1,12 +1,12 @@
package guardian package guardian
import ( import (
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
) )
type DatasourceGuardianProvider interface { type DatasourceGuardianProvider interface {
New(orgID int64, user identity.Requester, dataSources ...datasources.DataSource) DatasourceGuardian New(orgID int64, user *user.SignedInUser, dataSources ...datasources.DataSource) DatasourceGuardian
} }
type DatasourceGuardian interface { type DatasourceGuardian interface {
@ -20,6 +20,6 @@ func ProvideGuardian() *OSSProvider {
type OSSProvider struct{} type OSSProvider struct{}
func (p *OSSProvider) New(orgID int64, user identity.Requester, dataSources ...datasources.DataSource) DatasourceGuardian { func (p *OSSProvider) New(orgID int64, user *user.SignedInUser, dataSources ...datasources.DataSource) DatasourceGuardian {
return &AllowGuardian{} return &AllowGuardian{}
} }

View File

@ -8,9 +8,9 @@ import (
"github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/localcache" "github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/datasources/guardian" "github.com/grafana/grafana/pkg/services/datasources/guardian"
"github.com/grafana/grafana/pkg/services/user"
) )
const ( const (
@ -38,7 +38,7 @@ type CacheServiceImpl struct {
func (dc *CacheServiceImpl) GetDatasource( func (dc *CacheServiceImpl) GetDatasource(
ctx context.Context, ctx context.Context,
datasourceID int64, datasourceID int64,
user identity.Requester, user *user.SignedInUser,
skipCache bool, skipCache bool,
) (*datasources.DataSource, error) { ) (*datasources.DataSource, error) {
cacheKey := idKey(datasourceID) cacheKey := idKey(datasourceID)
@ -46,7 +46,7 @@ func (dc *CacheServiceImpl) GetDatasource(
if !skipCache { if !skipCache {
if cached, found := dc.CacheService.Get(cacheKey); found { if cached, found := dc.CacheService.Get(cacheKey); found {
ds := cached.(*datasources.DataSource) ds := cached.(*datasources.DataSource)
if ds.OrgID == user.GetOrgID() { if ds.OrgID == user.OrgID {
if err := dc.canQuery(user, ds); err != nil { if err := dc.canQuery(user, ds); err != nil {
return nil, err return nil, err
} }
@ -55,9 +55,9 @@ func (dc *CacheServiceImpl) GetDatasource(
} }
} }
dc.logger.FromContext(ctx).Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.GetOrgID()) dc.logger.FromContext(ctx).Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.OrgID)
query := &datasources.GetDataSourceQuery{ID: datasourceID, OrgID: user.GetOrgID()} query := &datasources.GetDataSourceQuery{ID: datasourceID, OrgID: user.OrgID}
ss := SqlStore{db: dc.SQLStore, logger: dc.logger} ss := SqlStore{db: dc.SQLStore, logger: dc.logger}
ds, err := ss.GetDataSource(ctx, query) ds, err := ss.GetDataSource(ctx, query)
if err != nil { if err != nil {
@ -79,21 +79,21 @@ func (dc *CacheServiceImpl) GetDatasource(
func (dc *CacheServiceImpl) GetDatasourceByUID( func (dc *CacheServiceImpl) GetDatasourceByUID(
ctx context.Context, ctx context.Context,
datasourceUID string, datasourceUID string,
user identity.Requester, user *user.SignedInUser,
skipCache bool, skipCache bool,
) (*datasources.DataSource, error) { ) (*datasources.DataSource, error) {
if datasourceUID == "" { if datasourceUID == "" {
return nil, fmt.Errorf("can not get data source by uid, uid is empty") return nil, fmt.Errorf("can not get data source by uid, uid is empty")
} }
if user.GetOrgID() == 0 { if user.OrgID == 0 {
return nil, fmt.Errorf("can not get data source by uid, orgId is missing") return nil, fmt.Errorf("can not get data source by uid, orgId is missing")
} }
uidCacheKey := uidKey(user.GetOrgID(), datasourceUID) uidCacheKey := uidKey(user.OrgID, datasourceUID)
if !skipCache { if !skipCache {
if cached, found := dc.CacheService.Get(uidCacheKey); found { if cached, found := dc.CacheService.Get(uidCacheKey); found {
ds := cached.(*datasources.DataSource) ds := cached.(*datasources.DataSource)
if ds.OrgID == user.GetOrgID() { if ds.OrgID == user.OrgID {
if err := dc.canQuery(user, ds); err != nil { if err := dc.canQuery(user, ds); err != nil {
return nil, err return nil, err
} }
@ -102,8 +102,8 @@ func (dc *CacheServiceImpl) GetDatasourceByUID(
} }
} }
dc.logger.FromContext(ctx).Debug("Querying for data source via SQL store", "uid", datasourceUID, "orgId", user.GetOrgID()) dc.logger.FromContext(ctx).Debug("Querying for data source via SQL store", "uid", datasourceUID, "orgId", user.OrgID)
query := &datasources.GetDataSourceQuery{UID: datasourceUID, OrgID: user.GetOrgID()} query := &datasources.GetDataSourceQuery{UID: datasourceUID, OrgID: user.OrgID}
ss := SqlStore{db: dc.SQLStore, logger: dc.logger} ss := SqlStore{db: dc.SQLStore, logger: dc.logger}
ds, err := ss.GetDataSource(ctx, query) ds, err := ss.GetDataSource(ctx, query)
if err != nil { if err != nil {
@ -128,8 +128,8 @@ func uidKey(orgID int64, uid string) string {
return fmt.Sprintf("ds-orgid-uid-%d-%s", orgID, uid) return fmt.Sprintf("ds-orgid-uid-%d-%s", orgID, uid)
} }
func (dc *CacheServiceImpl) canQuery(user identity.Requester, ds *datasources.DataSource) error { func (dc *CacheServiceImpl) canQuery(user *user.SignedInUser, ds *datasources.DataSource) error {
guardian := dc.dsGuardian.New(user.GetOrgID(), user, *ds) guardian := dc.dsGuardian.New(user.OrgID, user, *ds)
if canQuery, err := guardian.CanQuery(ds.ID); err != nil || !canQuery { if canQuery, err := guardian.CanQuery(ds.ID); err != nil || !canQuery {
if err != nil { if err != nil {
return err return err

View File

@ -12,7 +12,6 @@ import (
"github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol" "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"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder"
@ -281,12 +280,7 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (
dashFolder.SetUID(trimmedUID) dashFolder.SetUID(trimmedUID)
user := cmd.SignedInUser user := cmd.SignedInUser
namespaceID, userIDstr := user.GetNamespacedID() userID := user.UserID
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
s.log.Warn("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err)
}
if userID == 0 { if userID == 0 {
userID = -1 userID = -1
} }
@ -769,18 +763,12 @@ func (s *Service) BuildSaveDashboardCommand(ctx context.Context, dto *dashboards
} }
} }
namespaceID, userIDstr := dto.User.GetNamespacedID()
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
s.log.Warn("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err)
}
cmd := &dashboards.SaveDashboardCommand{ cmd := &dashboards.SaveDashboardCommand{
Dashboard: dash.Data, Dashboard: dash.Data,
Message: dto.Message, Message: dto.Message,
OrgID: dto.OrgID, OrgID: dto.OrgID,
Overwrite: dto.Overwrite, Overwrite: dto.Overwrite,
UserID: userID, UserID: dto.User.UserID,
FolderID: dash.FolderID, FolderID: dash.FolderID,
IsFolder: dash.IsFolder, IsFolder: dash.IsFolder,
PluginID: dash.PluginID, PluginID: dash.PluginID,
@ -795,7 +783,7 @@ func (s *Service) BuildSaveDashboardCommand(ctx context.Context, dto *dashboards
// getGuardianForSavePermissionCheck returns the guardian to be used for checking permission of dashboard // getGuardianForSavePermissionCheck returns the guardian to be used for checking permission of dashboard
// It replaces deleted Dashboard.GetDashboardIdForSavePermissionCheck() // It replaces deleted Dashboard.GetDashboardIdForSavePermissionCheck()
func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user identity.Requester) (guardian.DashboardGuardian, error) { func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user *user.SignedInUser) (guardian.DashboardGuardian, error) {
newDashboard := d.ID == 0 newDashboard := d.ID == 0
if newDashboard { if newDashboard {

View File

@ -5,7 +5,6 @@ import (
"time" "time"
"github.com/grafana/grafana/pkg/infra/slugify" "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/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util/errutil" "github.com/grafana/grafana/pkg/util/errutil"
@ -139,7 +138,6 @@ type GetFolderQuery struct {
OrgID int64 OrgID int64
SignedInUser *user.SignedInUser `json:"-"` SignedInUser *user.SignedInUser `json:"-"`
Requester identity.Requester `json:"-"`
} }
// GetParentsQuery captures the information required by the folder service to // GetParentsQuery captures the information required by the folder service to

View File

@ -6,9 +6,9 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol" "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"
"github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -16,14 +16,14 @@ var _ DashboardGuardian = new(accessControlDashboardGuardian)
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardId. // NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardId.
func NewAccessControlDashboardGuardian( func NewAccessControlDashboardGuardian(
ctx context.Context, cfg *setting.Cfg, dashboardId int64, user identity.Requester, ctx context.Context, cfg *setting.Cfg, dashboardId int64, user *user.SignedInUser,
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
) (DashboardGuardian, error) { ) (DashboardGuardian, error) {
var dashboard *dashboards.Dashboard var dashboard *dashboards.Dashboard
if dashboardId != 0 { if dashboardId != 0 {
q := &dashboards.GetDashboardQuery{ q := &dashboards.GetDashboardQuery{
ID: dashboardId, ID: dashboardId,
OrgID: user.GetOrgID(), OrgID: user.OrgID,
} }
qResult, err := dashboardService.GetDashboard(ctx, q) qResult, err := dashboardService.GetDashboard(ctx, q)
@ -65,14 +65,14 @@ func NewAccessControlDashboardGuardian(
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardUID. // NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardUID.
func NewAccessControlDashboardGuardianByUID( func NewAccessControlDashboardGuardianByUID(
ctx context.Context, cfg *setting.Cfg, dashboardUID string, user identity.Requester, ctx context.Context, cfg *setting.Cfg, dashboardUID string, user *user.SignedInUser,
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
) (DashboardGuardian, error) { ) (DashboardGuardian, error) {
var dashboard *dashboards.Dashboard var dashboard *dashboards.Dashboard
if dashboardUID != "" { if dashboardUID != "" {
q := &dashboards.GetDashboardQuery{ q := &dashboards.GetDashboardQuery{
UID: dashboardUID, UID: dashboardUID,
OrgID: user.GetOrgID(), OrgID: user.OrgID,
} }
qResult, err := dashboardService.GetDashboard(ctx, q) qResult, err := dashboardService.GetDashboard(ctx, q)
@ -116,7 +116,7 @@ func NewAccessControlDashboardGuardianByUID(
// This constructor should be preferred over the other two if the dashboard in available // This constructor should be preferred over the other two if the dashboard in available
// since it avoids querying the database for fetching the dashboard. // since it avoids querying the database for fetching the dashboard.
func NewAccessControlDashboardGuardianByDashboard( func NewAccessControlDashboardGuardianByDashboard(
ctx context.Context, cfg *setting.Cfg, dashboard *dashboards.Dashboard, user identity.Requester, ctx context.Context, cfg *setting.Cfg, dashboard *dashboards.Dashboard, user *user.SignedInUser,
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
) (DashboardGuardian, error) { ) (DashboardGuardian, error) {
if dashboard != nil && dashboard.IsFolder { if dashboard != nil && dashboard.IsFolder {
@ -148,7 +148,7 @@ func NewAccessControlDashboardGuardianByDashboard(
// NewAccessControlFolderGuardian creates a folder guardian by the provided folder. // NewAccessControlFolderGuardian creates a folder guardian by the provided folder.
func NewAccessControlFolderGuardian( func NewAccessControlFolderGuardian(
ctx context.Context, cfg *setting.Cfg, f *folder.Folder, user identity.Requester, ctx context.Context, cfg *setting.Cfg, f *folder.Folder, user *user.SignedInUser,
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
) (DashboardGuardian, error) { ) (DashboardGuardian, error) {
return &accessControlFolderGuardian{ return &accessControlFolderGuardian{
@ -168,7 +168,7 @@ type accessControlBaseGuardian struct {
cfg *setting.Cfg cfg *setting.Cfg
ctx context.Context ctx context.Context
log log.Logger log log.Logger
user identity.Requester user *user.SignedInUser
ac accesscontrol.AccessControl ac accesscontrol.AccessControl
dashboardService dashboards.DashboardService dashboardService dashboards.DashboardService
} }
@ -309,13 +309,12 @@ func (a *accessControlFolderGuardian) CanCreate(folderID int64, isFolder bool) (
func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) { func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator) ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
namespaceID, userID := a.user.GetNamespacedID()
if err != nil { if err != nil {
id := 0 id := 0
if a.dashboard != nil { if a.dashboard != nil {
id = int(a.dashboard.ID) id = int(a.dashboard.ID)
} }
a.log.Debug("Failed to evaluate access control to dashboard", "error", err, "namespaceID", namespaceID, "userId", userID, "id", id) a.log.Debug("Failed to evaluate access control to dashboard", "error", err, "userId", a.user.UserID, "id", id)
} }
if !ok && err == nil { if !ok && err == nil {
@ -323,7 +322,7 @@ func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evalua
if a.dashboard != nil { if a.dashboard != nil {
id = int(a.dashboard.ID) id = int(a.dashboard.ID)
} }
a.log.Debug("Access denied to dashboard", "namespaceID", namespaceID, "userId", userID, "id", id, "permissions", evaluator.GoString()) a.log.Debug("Access denied to dashboard", "userId", a.user.UserID, "id", id, "permissions", evaluator.GoString())
} }
return ok, err return ok, err
@ -331,7 +330,6 @@ func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evalua
func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) { func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator) ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
namespaceID, userID := a.user.GetNamespacedID()
if err != nil { if err != nil {
uid := "" uid := ""
orgID := 0 orgID := 0
@ -339,7 +337,7 @@ func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator
uid = a.folder.UID uid = a.folder.UID
orgID = int(a.folder.OrgID) orgID = int(a.folder.OrgID)
} }
a.log.Debug("Failed to evaluate access control to folder", "error", err, "namespaceID", namespaceID, "userId", userID, "orgID", orgID, "uid", uid) a.log.Debug("Failed to evaluate access control to folder", "error", err, "userId", a.user.UserID, "orgID", orgID, "uid", uid)
} }
if !ok && err == nil { if !ok && err == nil {
@ -349,7 +347,7 @@ func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator
uid = a.folder.UID uid = a.folder.UID
orgID = int(a.folder.OrgID) orgID = int(a.folder.OrgID)
} }
a.log.Debug("Access denied to folder", "namespaceID", namespaceID, "userId", userID, "orgID", orgID, "uid", uid, "permissions", evaluator.GoString()) a.log.Debug("Access denied to folder", "userId", a.user.UserID, "orgID", orgID, "uid", uid, "permissions", evaluator.GoString())
} }
return ok, err return ok, err
@ -359,7 +357,7 @@ func (a *accessControlDashboardGuardian) loadParentFolder(folderID int64) (*dash
if folderID == 0 { if folderID == 0 {
return &dashboards.Dashboard{UID: accesscontrol.GeneralFolderUID}, nil return &dashboards.Dashboard{UID: accesscontrol.GeneralFolderUID}, nil
} }
folderQuery := &dashboards.GetDashboardQuery{ID: folderID, OrgID: a.user.GetOrgID()} folderQuery := &dashboards.GetDashboardQuery{ID: folderID, OrgID: a.user.OrgID}
folderQueryResult, err := a.dashboardService.GetDashboard(a.ctx, folderQuery) folderQueryResult, err := a.dashboardService.GetDashboard(a.ctx, folderQuery)
if err != nil { if err != nil {
return nil, err return nil, err
@ -371,7 +369,7 @@ func (a *accessControlFolderGuardian) loadParentFolder(folderID int64) (*dashboa
if folderID == 0 { if folderID == 0 {
return &dashboards.Dashboard{UID: accesscontrol.GeneralFolderUID}, nil return &dashboards.Dashboard{UID: accesscontrol.GeneralFolderUID}, nil
} }
folderQuery := &dashboards.GetDashboardQuery{ID: folderID, OrgID: a.user.GetOrgID()} folderQuery := &dashboards.GetDashboardQuery{ID: folderID, OrgID: a.user.OrgID}
folderQueryResult, err := a.dashboardService.GetDashboard(a.ctx, folderQuery) folderQueryResult, err := a.dashboardService.GetDashboard(a.ctx, folderQuery)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -6,11 +6,11 @@ import (
"github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/team" "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/setting"
"github.com/grafana/grafana/pkg/util/errutil" "github.com/grafana/grafana/pkg/util/errutil"
) )
@ -35,7 +35,7 @@ type DashboardGuardian interface {
type dashboardGuardianImpl struct { type dashboardGuardianImpl struct {
cfg *setting.Cfg cfg *setting.Cfg
user identity.Requester user *user.SignedInUser
dashId int64 dashId int64
orgId int64 orgId int64
acl []*dashboards.DashboardACLInfoDTO acl []*dashboards.DashboardACLInfoDTO
@ -49,30 +49,30 @@ type dashboardGuardianImpl struct {
// New factory for creating a new dashboard guardian instance // New factory for creating a new dashboard guardian instance
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned // When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
var New = func(ctx context.Context, dashId int64, orgId int64, user identity.Requester) (DashboardGuardian, error) { var New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
panic("no guardian factory implementation provided") panic("no guardian factory implementation provided")
} }
// NewByUID factory for creating a new dashboard guardian instance // NewByUID factory for creating a new dashboard guardian instance
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned // When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
var NewByUID = func(ctx context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) { var NewByUID = func(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
panic("no guardian factory implementation provided") panic("no guardian factory implementation provided")
} }
// NewByDashboard factory for creating a new dashboard guardian instance // NewByDashboard factory for creating a new dashboard guardian instance
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned // When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
var NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) { var NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
panic("no guardian factory implementation provided") panic("no guardian factory implementation provided")
} }
// NewByFolder factory for creating a new folder guardian instance // NewByFolder factory for creating a new folder guardian instance
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned // When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
var NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) { var NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
panic("no guardian factory implementation provided") panic("no guardian factory implementation provided")
} }
// newDashboardGuardian creates a dashboard guardian by the provided dashId. // newDashboardGuardian creates a dashboard guardian by the provided dashId.
func newDashboardGuardian(ctx context.Context, cfg *setting.Cfg, dashId int64, orgId int64, user identity.Requester, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) { func newDashboardGuardian(ctx context.Context, cfg *setting.Cfg, dashId int64, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
if dashId != 0 { if dashId != 0 {
q := &dashboards.GetDashboardQuery{ q := &dashboards.GetDashboardQuery{
ID: dashId, ID: dashId,
@ -101,7 +101,7 @@ func newDashboardGuardian(ctx context.Context, cfg *setting.Cfg, dashId int64, o
} }
// newDashboardGuardianByUID creates a dashboard guardian by the provided dashUID. // newDashboardGuardianByUID creates a dashboard guardian by the provided dashUID.
func newDashboardGuardianByUID(ctx context.Context, cfg *setting.Cfg, dashUID string, orgId int64, user identity.Requester, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) { func newDashboardGuardianByUID(ctx context.Context, cfg *setting.Cfg, dashUID string, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
dashID := int64(0) dashID := int64(0)
if dashUID != "" { if dashUID != "" {
q := &dashboards.GetDashboardQuery{ q := &dashboards.GetDashboardQuery{
@ -135,7 +135,7 @@ func newDashboardGuardianByUID(ctx context.Context, cfg *setting.Cfg, dashUID st
// newDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboard. // newDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboard.
// This constructor should be preferred over the other two if the dashboard in available // This constructor should be preferred over the other two if the dashboard in available
// since it avoids querying the database for fetching the dashboard. // since it avoids querying the database for fetching the dashboard.
func newDashboardGuardianByDashboard(ctx context.Context, cfg *setting.Cfg, dash *dashboards.Dashboard, orgId int64, user identity.Requester, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) { func newDashboardGuardianByDashboard(ctx context.Context, cfg *setting.Cfg, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
return &dashboardGuardianImpl{ return &dashboardGuardianImpl{
cfg: cfg, cfg: cfg,
user: user, user: user,
@ -153,7 +153,7 @@ func newDashboardGuardianByDashboard(ctx context.Context, cfg *setting.Cfg, dash
// This constructor should be preferred over the other two if the dashboard in available // This constructor should be preferred over the other two if the dashboard in available
// since it avoids querying the database for fetching the dashboard. // since it avoids querying the database for fetching the dashboard.
// The folder.ID should be the sequence ID in the dashboard table. // The folder.ID should be the sequence ID in the dashboard table.
func newDashboardGuardianByFolder(ctx context.Context, cfg *setting.Cfg, f *folder.Folder, orgId int64, user identity.Requester, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) { func newDashboardGuardianByFolder(ctx context.Context, cfg *setting.Cfg, f *folder.Folder, orgId int64, user *user.SignedInUser, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) (*dashboardGuardianImpl, error) {
return &dashboardGuardianImpl{ return &dashboardGuardianImpl{
cfg: cfg, cfg: cfg,
user: user, user: user,
@ -198,7 +198,7 @@ func (g *dashboardGuardianImpl) CanCreate(_ int64, _ bool) (bool, error) {
} }
func (g *dashboardGuardianImpl) HasPermission(permission dashboards.PermissionType) (bool, error) { func (g *dashboardGuardianImpl) HasPermission(permission dashboards.PermissionType) (bool, error) {
if g.user.HasRole(org.RoleAdmin) { if g.user.OrgRole == org.RoleAdmin {
return g.logHasPermissionResult(permission, true, nil) return g.logHasPermissionResult(permission, true, nil)
} }
@ -216,36 +216,32 @@ func (g *dashboardGuardianImpl) logHasPermissionResult(permission dashboards.Per
return hasPermission, err return hasPermission, err
} }
var debugMessage string
if hasPermission { if hasPermission {
debugMessage = "User granted access to execute action" g.log.Debug("User granted access to execute action", "userId", g.user.UserID, "orgId", g.orgId, "uname", g.user.Login, "dashId", g.dashId, "action", permission)
} else { } else {
debugMessage = "User denied access to execute action" g.log.Debug("User denied access to execute action", "userId", g.user.UserID, "orgId", g.orgId, "uname", g.user.Login, "dashId", g.dashId, "action", permission)
} }
namespaceID, identifier := g.user.GetNamespacedID()
g.log.Debug(debugMessage, "namespaceID", namespaceID, "identifier", identifier, "orgId", g.orgId, "uname", g.user.GetLogin(), "dashId", g.dashId, "action", permission)
return hasPermission, err return hasPermission, err
} }
func (g *dashboardGuardianImpl) checkACL(permission dashboards.PermissionType, acl []*dashboards.DashboardACLInfoDTO) (bool, error) { func (g *dashboardGuardianImpl) checkACL(permission dashboards.PermissionType, acl []*dashboards.DashboardACLInfoDTO) (bool, error) {
orgRole := g.user.OrgRole
teamACLItems := []*dashboards.DashboardACLInfoDTO{} teamACLItems := []*dashboards.DashboardACLInfoDTO{}
for _, p := range acl { for _, p := range acl {
userID, err := identity.IntIdentifier(g.user.GetNamespacedID())
if err != nil {
return false, err
}
// user match // user match
if p.UserID > 0 && p.UserID == userID && p.Permission >= permission { if !g.user.IsAnonymous && p.UserID > 0 {
return true, nil if p.UserID == g.user.UserID && p.Permission >= permission {
return true, nil
}
} }
// role match // role match
if p.Role != nil && *p.Role == g.user.GetOrgRole() && p.Permission >= permission { if p.Role != nil {
return true, nil if *p.Role == orgRole && p.Permission >= permission {
return true, nil
}
} }
// remember this rule for later // remember this rule for later
@ -316,7 +312,7 @@ func (g *dashboardGuardianImpl) CheckPermissionBeforeUpdate(permission dashboard
} }
} }
if g.user.HasRole(org.RoleAdmin) { if g.user.OrgRole == org.RoleAdmin {
return true, nil return true, nil
} }
@ -379,12 +375,7 @@ func (g *dashboardGuardianImpl) getTeams() ([]*team.TeamDTO, error) {
return g.teams, nil return g.teams, nil
} }
userIdD, err := identity.IntIdentifier(g.user.GetNamespacedID()) query := team.GetTeamsByUserQuery{OrgID: g.orgId, UserID: g.user.UserID, SignedInUser: g.user}
if err != nil {
return nil, err
}
query := team.GetTeamsByUserQuery{OrgID: g.orgId, UserID: userIdD, SignedInUser: g.user}
queryResult, err := g.teamService.GetTeamsByUser(g.ctx, &query) queryResult, err := g.teamService.GetTeamsByUser(g.ctx, &query)
g.teams = queryResult g.teams = queryResult
@ -393,7 +384,7 @@ func (g *dashboardGuardianImpl) getTeams() ([]*team.TeamDTO, error) {
func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.DashboardACL, error) { func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.DashboardACL, error) {
hiddenACL := make([]*dashboards.DashboardACL, 0) hiddenACL := make([]*dashboards.DashboardACL, 0)
if g.user.GetIsGrafanaAdmin() { if g.user.IsGrafanaAdmin {
return hiddenACL, nil return hiddenACL, nil
} }
@ -403,7 +394,7 @@ func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.Da
} }
for _, item := range existingPermissions { for _, item := range existingPermissions {
if item.Inherited || item.UserLogin == g.user.GetLogin() { if item.Inherited || item.UserLogin == g.user.Login {
continue continue
} }
@ -425,11 +416,10 @@ func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.Da
// nolint:unused // nolint:unused
type FakeDashboardGuardian struct { type FakeDashboardGuardian struct {
DashID int64 DashID int64
DashUID string DashUID string
// OrgID can be retrieved from the identity.Requester.GetOrgID
OrgID int64 OrgID int64
User identity.Requester User *user.SignedInUser
CanSaveValue bool CanSaveValue bool
CanEditValue bool CanEditValue bool
CanViewValue bool CanViewValue bool
@ -471,21 +461,21 @@ func (g *FakeDashboardGuardian) HasPermission(permission dashboards.PermissionTy
// nolint:unused // nolint:unused
func MockDashboardGuardian(mock *FakeDashboardGuardian) { func MockDashboardGuardian(mock *FakeDashboardGuardian) {
New = func(_ context.Context, dashID int64, orgId int64, user identity.Requester) (DashboardGuardian, error) { New = func(_ context.Context, dashID int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
mock.OrgID = orgId mock.OrgID = orgId
mock.DashID = dashID mock.DashID = dashID
mock.User = user mock.User = user
return mock, nil return mock, nil
} }
NewByUID = func(_ context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByUID = func(_ context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
mock.OrgID = orgId mock.OrgID = orgId
mock.DashUID = dashUID mock.DashUID = dashUID
mock.User = user mock.User = user
return mock, nil return mock, nil
} }
NewByDashboard = func(_ context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByDashboard = func(_ context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
mock.OrgID = orgId mock.OrgID = orgId
mock.DashUID = dash.UID mock.DashUID = dash.UID
mock.DashID = dash.ID mock.DashID = dash.ID
@ -493,7 +483,7 @@ func MockDashboardGuardian(mock *FakeDashboardGuardian) {
return mock, nil return mock, nil
} }
NewByFolder = func(_ context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByFolder = func(_ context.Context, f *folder.Folder, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
mock.OrgID = orgId mock.OrgID = orgId
mock.DashUID = f.UID mock.DashUID = f.UID
mock.DashID = f.ID mock.DashID = f.ID

View File

@ -5,10 +5,10 @@ import (
"github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/accesscontrol" "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"
"github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/team" "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/setting"
) )
@ -28,19 +28,19 @@ func ProvideService(
} }
func InitLegacyGuardian(cfg *setting.Cfg, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) { func InitLegacyGuardian(cfg *setting.Cfg, store db.DB, dashSvc dashboards.DashboardService, teamSvc team.Service) {
New = func(ctx context.Context, dashId int64, orgId int64, user identity.Requester) (DashboardGuardian, error) { New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
return newDashboardGuardian(ctx, cfg, dashId, orgId, user, store, dashSvc, teamSvc) return newDashboardGuardian(ctx, cfg, dashId, orgId, user, store, dashSvc, teamSvc)
} }
NewByUID = func(ctx context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByUID = func(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
return newDashboardGuardianByUID(ctx, cfg, dashUID, orgId, user, store, dashSvc, teamSvc) return newDashboardGuardianByUID(ctx, cfg, dashUID, orgId, user, store, dashSvc, teamSvc)
} }
NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
return newDashboardGuardianByDashboard(ctx, cfg, dash, orgId, user, store, dashSvc, teamSvc) return newDashboardGuardianByDashboard(ctx, cfg, dash, orgId, user, store, dashSvc, teamSvc)
} }
NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
return newDashboardGuardianByFolder(ctx, cfg, f, orgId, user, store, dashSvc, teamSvc) return newDashboardGuardianByFolder(ctx, cfg, f, orgId, user, store, dashSvc, teamSvc)
} }
} }
@ -48,19 +48,19 @@ func InitLegacyGuardian(cfg *setting.Cfg, store db.DB, dashSvc dashboards.Dashbo
func InitAccessControlGuardian( func InitAccessControlGuardian(
cfg *setting.Cfg, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService, cfg *setting.Cfg, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
) { ) {
New = func(ctx context.Context, dashId int64, orgId int64, user identity.Requester) (DashboardGuardian, error) { New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
return NewAccessControlDashboardGuardian(ctx, cfg, dashId, user, ac, dashboardService) return NewAccessControlDashboardGuardian(ctx, cfg, dashId, user, ac, dashboardService)
} }
NewByUID = func(ctx context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByUID = func(ctx context.Context, dashUID string, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
return NewAccessControlDashboardGuardianByUID(ctx, cfg, dashUID, user, ac, dashboardService) return NewAccessControlDashboardGuardianByUID(ctx, cfg, dashUID, user, ac, dashboardService)
} }
NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
return NewAccessControlDashboardGuardianByDashboard(ctx, cfg, dash, user, ac, dashboardService) return NewAccessControlDashboardGuardianByDashboard(ctx, cfg, dash, user, ac, dashboardService)
} }
NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) { NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user *user.SignedInUser) (DashboardGuardian, error) {
return NewAccessControlFolderGuardian(ctx, cfg, f, user, ac, dashboardService) return NewAccessControlFolderGuardian(ctx, cfg, f, user, ac, dashboardService)
} }
} }

View File

@ -6,8 +6,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/live/model" "github.com/grafana/grafana/pkg/services/live/model"
"github.com/grafana/grafana/pkg/services/user"
) )
var ( var (
@ -37,13 +37,13 @@ func (b *BroadcastRunner) GetHandlerForPath(_ string) (model.ChannelHandler, err
} }
// OnSubscribe will let anyone connect to the path // OnSubscribe will let anyone connect to the path
func (b *BroadcastRunner) OnSubscribe(_ context.Context, u identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) { func (b *BroadcastRunner) OnSubscribe(_ context.Context, u *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
reply := model.SubscribeReply{ reply := model.SubscribeReply{
Presence: true, Presence: true,
JoinLeave: true, JoinLeave: true,
} }
query := &model.GetLiveMessageQuery{ query := &model.GetLiveMessageQuery{
OrgID: u.GetOrgID(), OrgID: u.OrgID,
Channel: e.Channel, Channel: e.Channel,
} }
msg, ok, err := b.liveMessageStore.GetLiveMessage(query) msg, ok, err := b.liveMessageStore.GetLiveMessage(query)
@ -57,9 +57,9 @@ func (b *BroadcastRunner) OnSubscribe(_ context.Context, u identity.Requester, e
} }
// OnPublish is called when a client wants to broadcast on the websocket // OnPublish is called when a client wants to broadcast on the websocket
func (b *BroadcastRunner) OnPublish(_ context.Context, u identity.Requester, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) { func (b *BroadcastRunner) OnPublish(_ context.Context, u *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
query := &model.SaveLiveMessageQuery{ query := &model.SaveLiveMessageQuery{
OrgID: u.GetOrgID(), OrgID: u.OrgID,
Channel: e.Channel, Channel: e.Channel,
Data: e.Data, Data: e.Data,
} }

View File

@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/db" "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"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/live/model" "github.com/grafana/grafana/pkg/services/live/model"
@ -53,7 +52,7 @@ func (h *DashboardHandler) GetHandlerForPath(_ string) (model.ChannelHandler, er
} }
// OnSubscribe for now allows anyone to subscribe to any dashboard // OnSubscribe for now allows anyone to subscribe to any dashboard
func (h *DashboardHandler) OnSubscribe(ctx context.Context, user identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) { func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
parts := strings.Split(e.Path, "/") parts := strings.Split(e.Path, "/")
if parts[0] == "gitops" { if parts[0] == "gitops" {
// gitops gets all changes for everything, so lets make sure it is an admin user // gitops gets all changes for everything, so lets make sure it is an admin user
@ -67,7 +66,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user identity.Reques
// make sure can view this dashboard // make sure can view this dashboard
if len(parts) == 2 && parts[0] == "uid" { if len(parts) == 2 && parts[0] == "uid" {
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.GetOrgID()} query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.OrgID}
queryResult, err := h.DashboardService.GetDashboard(ctx, &query) queryResult, err := h.DashboardService.GetDashboard(ctx, &query)
if err != nil { if err != nil {
logger.Error("Error getting dashboard", "query", query, "error", err) logger.Error("Error getting dashboard", "query", query, "error", err)
@ -75,7 +74,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user identity.Reques
} }
dash := queryResult dash := queryResult
guard, err := guardian.NewByDashboard(ctx, dash, user.GetOrgID(), user) guard, err := guardian.NewByDashboard(ctx, dash, user.OrgID, user)
if err != nil { if err != nil {
return model.SubscribeReply{}, backend.SubscribeStreamStatusPermissionDenied, err return model.SubscribeReply{}, backend.SubscribeStreamStatusPermissionDenied, err
} }
@ -95,11 +94,11 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user identity.Reques
} }
// OnPublish is called when someone begins to edit a dashboard // OnPublish is called when someone begins to edit a dashboard
func (h *DashboardHandler) OnPublish(ctx context.Context, requester identity.Requester, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) { func (h *DashboardHandler) OnPublish(ctx context.Context, user *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
parts := strings.Split(e.Path, "/") parts := strings.Split(e.Path, "/")
if parts[0] == "gitops" { if parts[0] == "gitops" {
// gitops gets all changes for everything, so lets make sure it is an admin user // gitops gets all changes for everything, so lets make sure it is an admin user
if !requester.HasRole(org.RoleAdmin) { if !user.HasRole(org.RoleAdmin) {
return model.PublishReply{}, backend.PublishStreamStatusPermissionDenied, nil return model.PublishReply{}, backend.PublishStreamStatusPermissionDenied, nil
} }
@ -118,14 +117,14 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, requester identity.Req
// just ignore the event // just ignore the event
return model.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("ignore???") return model.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("ignore???")
} }
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: requester.GetOrgID()} query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.OrgID}
queryResult, err := h.DashboardService.GetDashboard(ctx, &query) queryResult, err := h.DashboardService.GetDashboard(ctx, &query)
if err != nil { if err != nil {
logger.Error("Unknown dashboard", "query", query) logger.Error("Unknown dashboard", "query", query)
return model.PublishReply{}, backend.PublishStreamStatusNotFound, nil return model.PublishReply{}, backend.PublishStreamStatusNotFound, nil
} }
guard, err := guardian.NewByDashboard(ctx, queryResult, requester.GetOrgID(), requester) guard, err := guardian.NewByDashboard(ctx, queryResult, user.OrgID, user)
if err != nil { if err != nil {
logger.Error("Failed to create guardian", "err", err) logger.Error("Failed to create guardian", "err", err)
return model.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("internal error") return model.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("internal error")
@ -142,10 +141,7 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, requester identity.Req
} }
// Tell everyone who is editing // Tell everyone who is editing
event.User, err = user.NewUserDisplayDTOFromRequester(requester) event.User = user.ToUserDisplayDTO()
if err != nil {
return model.PublishReply{}, backend.PublishStreamStatusNotFound, err
}
msg, err := json.Marshal(event) msg, err := json.Marshal(event)
if err != nil { if err != nil {

View File

@ -7,17 +7,17 @@ import (
"github.com/centrifugal/centrifuge" "github.com/centrifugal/centrifuge"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/live/model" "github.com/grafana/grafana/pkg/services/live/model"
"github.com/grafana/grafana/pkg/services/live/orgchannel" "github.com/grafana/grafana/pkg/services/live/orgchannel"
"github.com/grafana/grafana/pkg/services/live/runstream" "github.com/grafana/grafana/pkg/services/live/runstream"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/user"
) )
//go:generate mockgen -destination=plugin_mock.go -package=features github.com/grafana/grafana/pkg/services/live/features PluginContextGetter //go:generate mockgen -destination=plugin_mock.go -package=features github.com/grafana/grafana/pkg/services/live/features PluginContextGetter
type PluginContextGetter interface { type PluginContextGetter interface {
GetPluginContext(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error) GetPluginContext(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error)
} }
// PluginRunner can handle streaming operations for channels belonging to plugins. // PluginRunner can handle streaming operations for channels belonging to plugins.
@ -63,7 +63,7 @@ type PluginPathRunner struct {
} }
// OnSubscribe passes control to a plugin. // OnSubscribe passes control to a plugin.
func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) { func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
pCtx, err := r.pluginContextGetter.GetPluginContext(ctx, user, r.pluginID, r.datasourceUID, false) pCtx, err := r.pluginContextGetter.GetPluginContext(ctx, user, r.pluginID, r.datasourceUID, false)
if err != nil { if err != nil {
if errors.Is(err, plugincontext.ErrPluginNotFound) { if errors.Is(err, plugincontext.ErrPluginNotFound) {
@ -86,7 +86,7 @@ func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user identity.Reques
return model.SubscribeReply{}, resp.Status, nil return model.SubscribeReply{}, resp.Status, nil
} }
submitResult, err := r.runStreamManager.SubmitStream(ctx, user, orgchannel.PrependOrgID(user.GetOrgID(), e.Channel), r.path, e.Data, pCtx, r.handler, false) submitResult, err := r.runStreamManager.SubmitStream(ctx, user, orgchannel.PrependOrgID(user.OrgID, e.Channel), r.path, e.Data, pCtx, r.handler, false)
if err != nil { if err != nil {
logger.Error("Error submitting stream to manager", "error", err, "path", r.path) logger.Error("Error submitting stream to manager", "error", err, "path", r.path)
return model.SubscribeReply{}, 0, centrifuge.ErrorInternal return model.SubscribeReply{}, 0, centrifuge.ErrorInternal
@ -107,7 +107,7 @@ func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user identity.Reques
} }
// OnPublish passes control to a plugin. // OnPublish passes control to a plugin.
func (r *PluginPathRunner) OnPublish(ctx context.Context, user identity.Requester, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) { func (r *PluginPathRunner) OnPublish(ctx context.Context, user *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
pCtx, err := r.pluginContextGetter.GetPluginContext(ctx, user, r.pluginID, r.datasourceUID, false) pCtx, err := r.pluginContextGetter.GetPluginContext(ctx, user, r.pluginID, r.datasourceUID, false)
if err != nil { if err != nil {
if errors.Is(err, plugincontext.ErrPluginNotFound) { if errors.Is(err, plugincontext.ErrPluginNotFound) {

View File

@ -10,7 +10,7 @@ import (
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
backend "github.com/grafana/grafana-plugin-sdk-go/backend" backend "github.com/grafana/grafana-plugin-sdk-go/backend"
identity "github.com/grafana/grafana/pkg/services/auth/identity" user "github.com/grafana/grafana/pkg/services/user"
) )
// MockPluginContextGetter is a mock of PluginContextGetter interface. // MockPluginContextGetter is a mock of PluginContextGetter interface.
@ -37,7 +37,7 @@ func (m *MockPluginContextGetter) EXPECT() *MockPluginContextGetterMockRecorder
} }
// GetPluginContext mocks base method. // GetPluginContext mocks base method.
func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 identity.Requester, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) { func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 *user.SignedInUser, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetPluginContext", arg0, arg1, arg2, arg3, arg4) ret := m.ctrl.Call(m, "GetPluginContext", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(backend.PluginContext) ret0, _ := ret[0].(backend.PluginContext)

View File

@ -32,7 +32,6 @@ import (
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/auth/identity"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
@ -300,11 +299,10 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
g.websocketHandler = func(ctx *contextmodel.ReqContext) { g.websocketHandler = func(ctx *contextmodel.ReqContext) {
user := ctx.SignedInUser user := ctx.SignedInUser
_, userID := user.GetNamespacedID()
// Centrifuge expects Credentials in context with a current user ID. // Centrifuge expects Credentials in context with a current user ID.
cred := &centrifuge.Credentials{ cred := &centrifuge.Credentials{
UserID: userID, UserID: fmt.Sprintf("%d", user.UserID),
} }
newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred) newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred)
newCtx = livecontext.SetContextSignedUser(newCtx, user) newCtx = livecontext.SetContextSignedUser(newCtx, user)
@ -595,7 +593,7 @@ func (g *GrafanaLive) handleOnSubscribe(ctx context.Context, client *centrifuge.
return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
} }
if user.GetOrgID() != orgID { if user.OrgID != orgID {
logger.Info("Error subscribing: wrong orgId", "user", client.UserID(), "client", client.ID(), "channel", e.Channel) logger.Info("Error subscribing: wrong orgId", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
return centrifuge.SubscribeReply{}, centrifuge.ErrorPermissionDenied return centrifuge.SubscribeReply{}, centrifuge.ErrorPermissionDenied
} }
@ -605,7 +603,7 @@ func (g *GrafanaLive) handleOnSubscribe(ctx context.Context, client *centrifuge.
var ruleFound bool var ruleFound bool
if g.Pipeline != nil { if g.Pipeline != nil {
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), channel) rule, ok, err := g.Pipeline.Get(user.OrgID, channel)
if err != nil { if err != nil {
logger.Error("Error getting channel rule", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err) logger.Error("Error getting channel rule", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
@ -696,13 +694,13 @@ func (g *GrafanaLive) handleOnPublish(ctx context.Context, client *centrifuge.Cl
return centrifuge.PublishReply{}, centrifuge.ErrorInternal return centrifuge.PublishReply{}, centrifuge.ErrorInternal
} }
if user.GetOrgID() != orgID { if user.OrgID != orgID {
logger.Info("Error subscribing: wrong orgId", "user", client.UserID(), "client", client.ID(), "channel", e.Channel) logger.Info("Error subscribing: wrong orgId", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
return centrifuge.PublishReply{}, centrifuge.ErrorPermissionDenied return centrifuge.PublishReply{}, centrifuge.ErrorPermissionDenied
} }
if g.Pipeline != nil { if g.Pipeline != nil {
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), channel) rule, ok, err := g.Pipeline.Get(user.OrgID, channel)
if err != nil { if err != nil {
logger.Error("Error getting channel rule", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err) logger.Error("Error getting channel rule", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
return centrifuge.PublishReply{}, centrifuge.ErrorInternal return centrifuge.PublishReply{}, centrifuge.ErrorInternal
@ -726,7 +724,7 @@ func (g *GrafanaLive) handleOnPublish(ctx context.Context, client *centrifuge.Cl
return centrifuge.PublishReply{}, &centrifuge.Error{Code: uint32(code), Message: text} return centrifuge.PublishReply{}, &centrifuge.Error{Code: uint32(code), Message: text}
} }
} }
_, err := g.Pipeline.ProcessInput(client.Context(), user.GetOrgID(), channel, e.Data) _, err := g.Pipeline.ProcessInput(client.Context(), user.OrgID, channel, e.Data)
if err != nil { if err != nil {
logger.Error("Error processing input", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err) logger.Error("Error processing input", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
return centrifuge.PublishReply{}, centrifuge.ErrorInternal return centrifuge.PublishReply{}, centrifuge.ErrorInternal
@ -807,7 +805,7 @@ func publishStatusToHTTPError(status backend.PublishStreamStatus) (int, string)
} }
// GetChannelHandler gives thread-safe access to the channel. // GetChannelHandler gives thread-safe access to the channel.
func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user identity.Requester, channel string) (model.ChannelHandler, live.Channel, error) { func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user *user.SignedInUser, channel string) (model.ChannelHandler, live.Channel, error) {
// Parse the identifier ${scope}/${namespace}/${path} // Parse the identifier ${scope}/${namespace}/${path}
addr, err := live.ParseChannel(channel) addr, err := live.ParseChannel(channel)
if err != nil { if err != nil {
@ -848,7 +846,7 @@ func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user identity.Reque
// GetChannelHandlerFactory gets a ChannelHandlerFactory for a namespace. // GetChannelHandlerFactory gets a ChannelHandlerFactory for a namespace.
// It gives thread-safe access to the channel. // It gives thread-safe access to the channel.
func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user identity.Requester, scope string, namespace string) (model.ChannelHandlerFactory, error) { func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user *user.SignedInUser, scope string, namespace string) (model.ChannelHandlerFactory, error) {
switch scope { switch scope {
case live.ScopeGrafana: case live.ScopeGrafana:
return g.handleGrafanaScope(user, namespace) return g.handleGrafanaScope(user, namespace)
@ -863,14 +861,14 @@ func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user identit
} }
} }
func (g *GrafanaLive) handleGrafanaScope(_ identity.Requester, namespace string) (model.ChannelHandlerFactory, error) { func (g *GrafanaLive) handleGrafanaScope(_ *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
if p, ok := g.GrafanaScope.Features[namespace]; ok { if p, ok := g.GrafanaScope.Features[namespace]; ok {
return p, nil return p, nil
} }
return nil, fmt.Errorf("unknown feature: %q", namespace) return nil, fmt.Errorf("unknown feature: %q", namespace)
} }
func (g *GrafanaLive) handlePluginScope(ctx context.Context, _ identity.Requester, namespace string) (model.ChannelHandlerFactory, error) { func (g *GrafanaLive) handlePluginScope(ctx context.Context, _ *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
streamHandler, err := g.getStreamPlugin(ctx, namespace) streamHandler, err := g.getStreamPlugin(ctx, namespace)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't find stream plugin: %s", namespace) return nil, fmt.Errorf("can't find stream plugin: %s", namespace)
@ -884,11 +882,11 @@ func (g *GrafanaLive) handlePluginScope(ctx context.Context, _ identity.Requeste
), nil ), nil
} }
func (g *GrafanaLive) handleStreamScope(u identity.Requester, namespace string) (model.ChannelHandlerFactory, error) { func (g *GrafanaLive) handleStreamScope(u *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
return g.ManagedStreamRunner.GetOrCreateStream(u.GetOrgID(), live.ScopeStream, namespace) return g.ManagedStreamRunner.GetOrCreateStream(u.OrgID, live.ScopeStream, namespace)
} }
func (g *GrafanaLive) handleDatasourceScope(ctx context.Context, user identity.Requester, namespace string) (model.ChannelHandlerFactory, error) { func (g *GrafanaLive) handleDatasourceScope(ctx context.Context, user *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
ds, err := g.DataSourceCache.GetDatasourceByUID(ctx, namespace, user, false) ds, err := g.DataSourceCache.GetDatasourceByUID(ctx, namespace, user, false)
if err != nil { if err != nil {
return nil, fmt.Errorf("error getting datasource: %w", err) return nil, fmt.Errorf("error getting datasource: %w", err)
@ -931,13 +929,12 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
return response.Error(http.StatusBadRequest, "invalid channel ID", nil) return response.Error(http.StatusBadRequest, "invalid channel ID", nil)
} }
namespaceID, userID := ctx.SignedInUser.GetNamespacedID() logger.Debug("Publish API cmd", "user", ctx.SignedInUser.UserID, "channel", cmd.Channel)
logger.Debug("Publish API cmd", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel)
user := ctx.SignedInUser user := ctx.SignedInUser
channel := cmd.Channel channel := cmd.Channel
if g.Pipeline != nil { if g.Pipeline != nil {
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), channel) rule, ok, err := g.Pipeline.Get(user.OrgID, channel)
if err != nil { if err != nil {
logger.Error("Error getting channel rule", "user", user, "channel", channel, "error", err) logger.Error("Error getting channel rule", "user", user, "channel", channel, "error", err)
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil) return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil)
@ -957,7 +954,7 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
return response.Error(http.StatusForbidden, http.StatusText(http.StatusForbidden), nil) return response.Error(http.StatusForbidden, http.StatusText(http.StatusForbidden), nil)
} }
} }
_, err := g.Pipeline.ProcessInput(ctx.Req.Context(), user.GetOrgID(), channel, cmd.Data) _, err := g.Pipeline.ProcessInput(ctx.Req.Context(), user.OrgID, channel, cmd.Data)
if err != nil { if err != nil {
logger.Error("Error processing input", "user", user, "channel", channel, "error", err) logger.Error("Error processing input", "user", user, "channel", channel, "error", err)
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil) return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil)
@ -983,13 +980,13 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
return response.Error(code, text, nil) return response.Error(code, text, nil)
} }
if reply.Data != nil { if reply.Data != nil {
err = g.Publish(ctx.SignedInUser.GetOrgID(), cmd.Channel, cmd.Data) err = g.Publish(ctx.OrgID, cmd.Channel, cmd.Data)
if err != nil { if err != nil {
logger.Error("Error publish to channel", "error", err, "channel", cmd.Channel) logger.Error("Error publish to channel", "error", err, "channel", cmd.Channel)
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil) return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil)
} }
} }
logger.Debug("Publication successful", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel) logger.Debug("Publication successful", "user", ctx.SignedInUser.UserID, "channel", cmd.Channel)
return response.JSON(http.StatusOK, dtos.LivePublishResponse{}) return response.JSON(http.StatusOK, dtos.LivePublishResponse{})
} }
@ -1002,9 +999,9 @@ func (g *GrafanaLive) HandleListHTTP(c *contextmodel.ReqContext) response.Respon
var channels []*managedstream.ManagedChannel var channels []*managedstream.ManagedChannel
var err error var err error
if g.IsHA() { if g.IsHA() {
channels, err = g.surveyCaller.CallManagedStreams(c.SignedInUser.GetOrgID()) channels, err = g.surveyCaller.CallManagedStreams(c.SignedInUser.OrgID)
} else { } else {
channels, err = g.ManagedStreamRunner.GetManagedChannels(c.SignedInUser.GetOrgID()) channels, err = g.ManagedStreamRunner.GetManagedChannels(c.SignedInUser.OrgID)
} }
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err) return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err)
@ -1020,7 +1017,7 @@ func (g *GrafanaLive) HandleInfoHTTP(ctx *contextmodel.ReqContext) response.Resp
path := web.Params(ctx.Req)["*"] path := web.Params(ctx.Req)["*"]
if path == "grafana/dashboards/gitops" { if path == "grafana/dashboards/gitops" {
return response.JSON(http.StatusOK, util.DynMap{ return response.JSON(http.StatusOK, util.DynMap{
"active": g.GrafanaScope.Dashboards.HasGitOpsObserver(ctx.SignedInUser.GetOrgID()), "active": g.GrafanaScope.Dashboards.HasGitOpsObserver(ctx.SignedInUser.OrgID),
}) })
} }
return response.JSONStreaming(404, util.DynMap{ return response.JSONStreaming(404, util.DynMap{
@ -1030,7 +1027,7 @@ func (g *GrafanaLive) HandleInfoHTTP(ctx *contextmodel.ReqContext) response.Resp
// HandleChannelRulesListHTTP ... // HandleChannelRulesListHTTP ...
func (g *GrafanaLive) HandleChannelRulesListHTTP(c *contextmodel.ReqContext) response.Response { func (g *GrafanaLive) HandleChannelRulesListHTTP(c *contextmodel.ReqContext) response.Response {
result, err := g.pipelineStorage.ListChannelRules(c.Req.Context(), c.SignedInUser.GetOrgID()) result, err := g.pipelineStorage.ListChannelRules(c.Req.Context(), c.OrgID)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to get channel rules", err) return response.Error(http.StatusInternalServerError, "Failed to get channel rules", err)
} }
@ -1115,7 +1112,7 @@ func (g *GrafanaLive) HandlePipelineConvertTestHTTP(c *contextmodel.ReqContext)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Error creating pipeline", err) return response.Error(http.StatusInternalServerError, "Error creating pipeline", err)
} }
rule, ok, err := channelRuleGetter.Get(c.SignedInUser.GetOrgID(), req.Channel) rule, ok, err := channelRuleGetter.Get(c.OrgID, req.Channel)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Error getting channel rule", err) return response.Error(http.StatusInternalServerError, "Error getting channel rule", err)
} }
@ -1125,7 +1122,7 @@ func (g *GrafanaLive) HandlePipelineConvertTestHTTP(c *contextmodel.ReqContext)
if rule.Converter == nil { if rule.Converter == nil {
return response.Error(http.StatusNotFound, "No converter found", nil) return response.Error(http.StatusNotFound, "No converter found", nil)
} }
channelFrames, err := pipe.DataToChannelFrames(c.Req.Context(), *rule, c.SignedInUser.GetOrgID(), req.Channel, []byte(req.Data)) channelFrames, err := pipe.DataToChannelFrames(c.Req.Context(), *rule, c.OrgID, req.Channel, []byte(req.Data))
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Error converting data", err) return response.Error(http.StatusInternalServerError, "Error converting data", err)
} }
@ -1145,7 +1142,7 @@ func (g *GrafanaLive) HandleChannelRulesPostHTTP(c *contextmodel.ReqContext) res
if err != nil { if err != nil {
return response.Error(http.StatusBadRequest, "Error decoding channel rule", err) return response.Error(http.StatusBadRequest, "Error decoding channel rule", err)
} }
rule, err := g.pipelineStorage.CreateChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd) rule, err := g.pipelineStorage.CreateChannelRule(c.Req.Context(), c.OrgID, cmd)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to create channel rule", err) return response.Error(http.StatusInternalServerError, "Failed to create channel rule", err)
} }
@ -1168,7 +1165,7 @@ func (g *GrafanaLive) HandleChannelRulesPutHTTP(c *contextmodel.ReqContext) resp
if cmd.Pattern == "" { if cmd.Pattern == "" {
return response.Error(http.StatusBadRequest, "Rule pattern required", nil) return response.Error(http.StatusBadRequest, "Rule pattern required", nil)
} }
rule, err := g.pipelineStorage.UpdateChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd) rule, err := g.pipelineStorage.UpdateChannelRule(c.Req.Context(), c.OrgID, cmd)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update channel rule", err) return response.Error(http.StatusInternalServerError, "Failed to update channel rule", err)
} }
@ -1191,7 +1188,7 @@ func (g *GrafanaLive) HandleChannelRulesDeleteHTTP(c *contextmodel.ReqContext) r
if cmd.Pattern == "" { if cmd.Pattern == "" {
return response.Error(http.StatusBadRequest, "Rule pattern required", nil) return response.Error(http.StatusBadRequest, "Rule pattern required", nil)
} }
err = g.pipelineStorage.DeleteChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd) err = g.pipelineStorage.DeleteChannelRule(c.Req.Context(), c.OrgID, cmd)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to delete channel rule", err) return response.Error(http.StatusInternalServerError, "Failed to delete channel rule", err)
} }
@ -1211,7 +1208,7 @@ func (g *GrafanaLive) HandlePipelineEntitiesListHTTP(_ *contextmodel.ReqContext)
// HandleWriteConfigsListHTTP ... // HandleWriteConfigsListHTTP ...
func (g *GrafanaLive) HandleWriteConfigsListHTTP(c *contextmodel.ReqContext) response.Response { func (g *GrafanaLive) HandleWriteConfigsListHTTP(c *contextmodel.ReqContext) response.Response {
backends, err := g.pipelineStorage.ListWriteConfigs(c.Req.Context(), c.SignedInUser.GetOrgID()) backends, err := g.pipelineStorage.ListWriteConfigs(c.Req.Context(), c.OrgID)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to get write configs", err) return response.Error(http.StatusInternalServerError, "Failed to get write configs", err)
} }
@ -1235,7 +1232,7 @@ func (g *GrafanaLive) HandleWriteConfigsPostHTTP(c *contextmodel.ReqContext) res
if err != nil { if err != nil {
return response.Error(http.StatusBadRequest, "Error decoding write config create command", err) return response.Error(http.StatusBadRequest, "Error decoding write config create command", err)
} }
result, err := g.pipelineStorage.CreateWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd) result, err := g.pipelineStorage.CreateWriteConfig(c.Req.Context(), c.OrgID, cmd)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to create write config", err) return response.Error(http.StatusInternalServerError, "Failed to create write config", err)
} }
@ -1258,7 +1255,7 @@ func (g *GrafanaLive) HandleWriteConfigsPutHTTP(c *contextmodel.ReqContext) resp
if cmd.UID == "" { if cmd.UID == "" {
return response.Error(http.StatusBadRequest, "UID required", nil) return response.Error(http.StatusBadRequest, "UID required", nil)
} }
existingBackend, ok, err := g.pipelineStorage.GetWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), pipeline.WriteConfigGetCmd{ existingBackend, ok, err := g.pipelineStorage.GetWriteConfig(c.Req.Context(), c.OrgID, pipeline.WriteConfigGetCmd{
UID: cmd.UID, UID: cmd.UID,
}) })
if err != nil { if err != nil {
@ -1279,7 +1276,7 @@ func (g *GrafanaLive) HandleWriteConfigsPutHTTP(c *contextmodel.ReqContext) resp
} }
} }
} }
result, err := g.pipelineStorage.UpdateWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd) result, err := g.pipelineStorage.UpdateWriteConfig(c.Req.Context(), c.OrgID, cmd)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update write config", err) return response.Error(http.StatusInternalServerError, "Failed to update write config", err)
} }
@ -1302,7 +1299,7 @@ func (g *GrafanaLive) HandleWriteConfigsDeleteHTTP(c *contextmodel.ReqContext) r
if cmd.UID == "" { if cmd.UID == "" {
return response.Error(http.StatusBadRequest, "UID required", nil) return response.Error(http.StatusBadRequest, "UID required", nil)
} }
err = g.pipelineStorage.DeleteWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd) err = g.pipelineStorage.DeleteWriteConfig(c.Req.Context(), c.OrgID, cmd)
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to delete write config", err) return response.Error(http.StatusInternalServerError, "Failed to delete write config", err)
} }

View File

@ -3,21 +3,21 @@ package livecontext
import ( import (
"context" "context"
"github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/user"
) )
type signedUserContextKeyType int type signedUserContextKeyType int
var signedUserContextKey signedUserContextKeyType var signedUserContextKey signedUserContextKeyType
func SetContextSignedUser(ctx context.Context, user identity.Requester) context.Context { func SetContextSignedUser(ctx context.Context, user *user.SignedInUser) context.Context {
ctx = context.WithValue(ctx, signedUserContextKey, user) ctx = context.WithValue(ctx, signedUserContextKey, user)
return ctx return ctx
} }
func GetContextSignedUser(ctx context.Context) (identity.Requester, bool) { func GetContextSignedUser(ctx context.Context) (*user.SignedInUser, bool) {
if val := ctx.Value(signedUserContextKey); val != nil { if val := ctx.Value(signedUserContextKey); val != nil {
user, ok := val.(identity.Requester) user, ok := val.(*user.SignedInUser)
return user, ok return user, ok
} }
return nil, false return nil, false

View File

@ -7,11 +7,11 @@ import (
"github.com/centrifugal/centrifuge" "github.com/centrifugal/centrifuge"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/live/orgchannel" "github.com/grafana/grafana/pkg/services/live/orgchannel"
"github.com/grafana/grafana/pkg/services/live/pipeline" "github.com/grafana/grafana/pkg/services/live/pipeline"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/user"
) )
type ChannelLocalPublisher struct { type ChannelLocalPublisher struct {
@ -72,9 +72,9 @@ func NewContextGetter(pluginContextProvider *plugincontext.Provider, dataSourceC
} }
} }
func (g *ContextGetter) GetPluginContext(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error) { func (g *ContextGetter) GetPluginContext(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error) {
if datasourceUID == "" { if datasourceUID == "" {
return g.pluginContextProvider.Get(ctx, pluginID, user, user.GetOrgID()) return g.pluginContextProvider.Get(ctx, pluginID, user, user.OrgID)
} }
ds, err := g.dataSourceCache.GetDatasourceByUID(ctx, datasourceUID, user, skipCache) ds, err := g.dataSourceCache.GetDatasourceByUID(ctx, datasourceUID, user, skipCache)

View File

@ -13,9 +13,9 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/live" "github.com/grafana/grafana-plugin-sdk-go/live"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/live/model" "github.com/grafana/grafana/pkg/services/live/model"
"github.com/grafana/grafana/pkg/services/live/orgchannel" "github.com/grafana/grafana/pkg/services/live/orgchannel"
"github.com/grafana/grafana/pkg/services/user"
) )
var ( var (
@ -239,9 +239,9 @@ func (s *NamespaceStream) GetHandlerForPath(_ string) (model.ChannelHandler, err
return s, nil return s, nil
} }
func (s *NamespaceStream) OnSubscribe(ctx context.Context, u identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) { func (s *NamespaceStream) OnSubscribe(ctx context.Context, u *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
reply := model.SubscribeReply{} reply := model.SubscribeReply{}
frameJSON, ok, err := s.frameCache.GetFrame(ctx, u.GetOrgID(), e.Channel) frameJSON, ok, err := s.frameCache.GetFrame(ctx, u.OrgID, e.Channel)
if err != nil { if err != nil {
return reply, 0, err return reply, 0, err
} }
@ -251,6 +251,6 @@ func (s *NamespaceStream) OnSubscribe(ctx context.Context, u identity.Requester,
return reply, backend.SubscribeStreamStatusOK, nil return reply, backend.SubscribeStreamStatusOK, nil
} }
func (s *NamespaceStream) OnPublish(_ context.Context, _ identity.Requester, _ model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) { func (s *NamespaceStream) OnPublish(_ context.Context, _ *user.SignedInUser, _ model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
return model.PublishReply{}, backend.PublishStreamStatusPermissionDenied, nil return model.PublishReply{}, backend.PublishStreamStatusPermissionDenied, nil
} }

View File

@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/user"
) )
// ChannelPublisher writes data into a channel. Note that permissions are not checked. // ChannelPublisher writes data into a channel. Note that permissions are not checked.
@ -54,10 +54,10 @@ type PublishReply struct {
// ChannelHandler defines the core channel behavior // ChannelHandler defines the core channel behavior
type ChannelHandler interface { type ChannelHandler interface {
// OnSubscribe is called when a client wants to subscribe to a channel // OnSubscribe is called when a client wants to subscribe to a channel
OnSubscribe(ctx context.Context, user identity.Requester, e SubscribeEvent) (SubscribeReply, backend.SubscribeStreamStatus, error) OnSubscribe(ctx context.Context, user *user.SignedInUser, e SubscribeEvent) (SubscribeReply, backend.SubscribeStreamStatus, error)
// OnPublish is called when a client writes a message to the channel websocket. // OnPublish is called when a client writes a message to the channel websocket.
OnPublish(ctx context.Context, user identity.Requester, e PublishEvent) (PublishReply, backend.PublishStreamStatus, error) OnPublish(ctx context.Context, user *user.SignedInUser, e PublishEvent) (PublishReply, backend.PublishStreamStatus, error)
} }
// ChannelHandlerFactory should be implemented by all core features. // ChannelHandlerFactory should be implemented by all core features.

View File

@ -3,8 +3,8 @@ package pipeline
import ( import (
"context" "context"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
) )
type RoleCheckAuthorizer struct { type RoleCheckAuthorizer struct {
@ -15,10 +15,10 @@ func NewRoleCheckAuthorizer(role org.RoleType) *RoleCheckAuthorizer {
return &RoleCheckAuthorizer{role: role} return &RoleCheckAuthorizer{role: role}
} }
func (s *RoleCheckAuthorizer) CanSubscribe(_ context.Context, u identity.Requester) (bool, error) { func (s *RoleCheckAuthorizer) CanSubscribe(_ context.Context, u *user.SignedInUser) (bool, error) {
return u.HasRole(s.role), nil return u.HasRole(s.role), nil
} }
func (s *RoleCheckAuthorizer) CanPublish(_ context.Context, u identity.Requester) (bool, error) { func (s *RoleCheckAuthorizer) CanPublish(_ context.Context, u *user.SignedInUser) (bool, error) {
return u.HasRole(s.role), nil return u.HasRole(s.role), nil
} }

View File

@ -17,8 +17,8 @@ import (
semconv "go.opentelemetry.io/otel/semconv/v1.4.0" semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/live/model" "github.com/grafana/grafana/pkg/services/live/model"
"github.com/grafana/grafana/pkg/services/user"
) )
const ( const (
@ -113,12 +113,12 @@ type Subscriber interface {
// PublishAuthChecker checks whether current user can publish to a channel. // PublishAuthChecker checks whether current user can publish to a channel.
type PublishAuthChecker interface { type PublishAuthChecker interface {
CanPublish(ctx context.Context, u identity.Requester) (bool, error) CanPublish(ctx context.Context, u *user.SignedInUser) (bool, error)
} }
// SubscribeAuthChecker checks whether current user can subscribe to a channel. // SubscribeAuthChecker checks whether current user can subscribe to a channel.
type SubscribeAuthChecker interface { type SubscribeAuthChecker interface {
CanSubscribe(ctx context.Context, u identity.Requester) (bool, error) CanSubscribe(ctx context.Context, u *user.SignedInUser) (bool, error)
} }
// LiveChannelRule is an in-memory representation of each specific rule to be executed by Pipeline. // LiveChannelRule is an in-memory representation of each specific rule to be executed by Pipeline.

View File

@ -6,9 +6,9 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/live" "github.com/grafana/grafana-plugin-sdk-go/live"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/live/livecontext" "github.com/grafana/grafana/pkg/services/live/livecontext"
"github.com/grafana/grafana/pkg/services/live/model" "github.com/grafana/grafana/pkg/services/live/model"
"github.com/grafana/grafana/pkg/services/user"
) )
type BuiltinSubscriber struct { type BuiltinSubscriber struct {
@ -16,7 +16,7 @@ type BuiltinSubscriber struct {
} }
type ChannelHandlerGetter interface { type ChannelHandlerGetter interface {
GetChannelHandler(ctx context.Context, user identity.Requester, channel string) (model.ChannelHandler, live.Channel, error) GetChannelHandler(ctx context.Context, user *user.SignedInUser, channel string) (model.ChannelHandler, live.Channel, error)
} }
const SubscriberTypeBuiltin = "builtin" const SubscriberTypeBuiltin = "builtin"

View File

@ -71,7 +71,7 @@ func (s *PipelinePushHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request)
"bodyLength", len(body), "bodyLength", len(body),
) )
ruleFound, err := s.pipeline.ProcessInput(r.Context(), user.GetOrgID(), channelID, body) ruleFound, err := s.pipeline.ProcessInput(r.Context(), user.OrgID, channelID, body)
if err != nil { if err != nil {
logger.Error("Pipeline input processing error", "error", err, "body", string(body)) logger.Error("Pipeline input processing error", "error", err, "body", string(body))
return return

View File

@ -67,7 +67,7 @@ func (s *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
break break
} }
stream, err := s.managedStreamRunner.GetOrCreateStream(user.GetOrgID(), liveDto.ScopeStream, streamID) stream, err := s.managedStreamRunner.GetOrCreateStream(user.OrgID, liveDto.ScopeStream, streamID)
if err != nil { if err != nil {
logger.Error("Error getting stream", "error", err) logger.Error("Error getting stream", "error", err)
continue continue

View File

@ -11,8 +11,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/user"
) )
var ( var (
@ -26,7 +26,7 @@ type ChannelLocalPublisher interface {
} }
type PluginContextGetter interface { type PluginContextGetter interface {
GetPluginContext(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error) GetPluginContext(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error)
} }
type NumLocalSubscribersGetter interface { type NumLocalSubscribersGetter interface {
@ -374,7 +374,7 @@ func (s *Manager) Run(ctx context.Context) error {
type streamRequest struct { type streamRequest struct {
Channel string Channel string
Path string Path string
user identity.Requester user *user.SignedInUser
PluginContext backend.PluginContext PluginContext backend.PluginContext
StreamRunner StreamRunner StreamRunner StreamRunner
Data []byte Data []byte
@ -401,7 +401,7 @@ var errDatasourceNotFound = errors.New("datasource not found")
// SubmitStream submits stream handler in Manager to manage. // SubmitStream submits stream handler in Manager to manage.
// The stream will be opened and kept till channel has active subscribers. // The stream will be opened and kept till channel has active subscribers.
func (s *Manager) SubmitStream(ctx context.Context, user identity.Requester, channel string, path string, data []byte, pCtx backend.PluginContext, streamRunner StreamRunner, isResubmit bool) (*submitResult, error) { func (s *Manager) SubmitStream(ctx context.Context, user *user.SignedInUser, channel string, path string, data []byte, pCtx backend.PluginContext, streamRunner StreamRunner, isResubmit bool) (*submitResult, error) {
if isResubmit { if isResubmit {
// Resolve new plugin context as it could be modified since last call. // Resolve new plugin context as it could be modified since last call.
var datasourceUID string var datasourceUID string

View File

@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
) )
@ -72,11 +71,9 @@ func TestStreamManager_SubmitStream_Send(t *testing.T) {
}, },
} }
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) { mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
userID, err := identity.IntIdentifier(user.GetNamespacedID()) require.Equal(t, int64(2), user.UserID)
require.NoError(t, err) require.Equal(t, int64(1), user.OrgID)
require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID())
require.Equal(t, testPluginContext.PluginID, pluginID) require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID) require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil return testPluginContext, true, nil
@ -136,7 +133,7 @@ func TestStreamManager_SubmitStream_DifferentOrgID(t *testing.T) {
mockPacketSender.EXPECT().PublishLocal("1/test", gomock.Any()).Times(1) mockPacketSender.EXPECT().PublishLocal("1/test", gomock.Any()).Times(1)
mockPacketSender.EXPECT().PublishLocal("2/test", gomock.Any()).Times(1) mockPacketSender.EXPECT().PublishLocal("2/test", gomock.Any()).Times(1)
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) { mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
return backend.PluginContext{}, true, nil return backend.PluginContext{}, true, nil
}).Times(0) }).Times(0)
@ -208,7 +205,7 @@ func TestStreamManager_SubmitStream_CloseNoSubscribers(t *testing.T) {
startedCh := make(chan struct{}) startedCh := make(chan struct{})
doneCh := make(chan struct{}) doneCh := make(chan struct{})
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) { mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
return backend.PluginContext{}, true, nil return backend.PluginContext{}, true, nil
}).Times(0) }).Times(0)
@ -257,11 +254,9 @@ func TestStreamManager_SubmitStream_ErrorRestartsRunStream(t *testing.T) {
}, },
} }
mockContextGetter.EXPECT().GetPluginContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) { mockContextGetter.EXPECT().GetPluginContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
userID, err := identity.IntIdentifier(user.GetNamespacedID()) require.Equal(t, int64(2), user.UserID)
require.NoError(t, err) require.Equal(t, int64(1), user.OrgID)
require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID())
require.Equal(t, testPluginContext.PluginID, pluginID) require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID) require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil return testPluginContext, true, nil
@ -301,7 +296,7 @@ func TestStreamManager_SubmitStream_NilErrorStopsRunStream(t *testing.T) {
_ = manager.Run(ctx) _ = manager.Run(ctx)
}() }()
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) { mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
return backend.PluginContext{}, true, nil return backend.PluginContext{}, true, nil
}).Times(0) }).Times(0)
@ -342,12 +337,9 @@ func TestStreamManager_HandleDatasourceUpdate(t *testing.T) {
}, },
} }
mockContextGetter.EXPECT().GetPluginContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) { mockContextGetter.EXPECT().GetPluginContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
userID, err := identity.IntIdentifier(user.GetNamespacedID()) require.Equal(t, int64(2), user.UserID)
require.NoError(t, err) require.Equal(t, int64(1), user.OrgID)
require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID())
require.Equal(t, testPluginContext.PluginID, pluginID) require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID) require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil return testPluginContext, true, nil
@ -411,11 +403,9 @@ func TestStreamManager_HandleDatasourceDelete(t *testing.T) {
}, },
} }
mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) { mockContextGetter.EXPECT().GetPluginContext(context.Background(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, user *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
userID, err := identity.IntIdentifier(user.GetNamespacedID()) require.Equal(t, int64(2), user.UserID)
require.NoError(t, err) require.Equal(t, int64(1), user.OrgID)
require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID())
require.Equal(t, testPluginContext.PluginID, pluginID) require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID) require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil return testPluginContext, true, nil

View File

@ -10,7 +10,7 @@ import (
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
backend "github.com/grafana/grafana-plugin-sdk-go/backend" backend "github.com/grafana/grafana-plugin-sdk-go/backend"
identity "github.com/grafana/grafana/pkg/services/auth/identity" user "github.com/grafana/grafana/pkg/services/user"
) )
// MockChannelLocalPublisher is a mock of ChannelLocalPublisher interface. // MockChannelLocalPublisher is a mock of ChannelLocalPublisher interface.
@ -149,7 +149,7 @@ func (m *MockPluginContextGetter) EXPECT() *MockPluginContextGetterMockRecorder
} }
// GetPluginContext mocks base method. // GetPluginContext mocks base method.
func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 identity.Requester, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) { func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 *user.SignedInUser, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetPluginContext", arg0, arg1, arg2, arg3, arg4) ret := m.ctrl.Call(m, "GetPluginContext", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(backend.PluginContext) ret0, _ := ret[0].(backend.PluginContext)

View File

@ -9,10 +9,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/auth/identity"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasourceproxy" "github.com/grafana/grafana/pkg/services/datasourceproxy"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@ -114,7 +114,7 @@ type fakeCacheService struct {
err error err error
} }
func (f fakeCacheService) GetDatasource(_ context.Context, datasourceID int64, _ identity.Requester, _ bool) (*datasources.DataSource, error) { func (f fakeCacheService) GetDatasource(_ context.Context, datasourceID int64, _ *user.SignedInUser, _ bool) (*datasources.DataSource, error) {
if f.err != nil { if f.err != nil {
return nil, f.err return nil, f.err
} }
@ -122,7 +122,7 @@ func (f fakeCacheService) GetDatasource(_ context.Context, datasourceID int64, _
return f.datasource, nil return f.datasource, nil
} }
func (f fakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, _ identity.Requester, skipCache bool) (*datasources.DataSource, error) { func (f fakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
if f.err != nil { if f.err != nil {
return nil, f.err return nil, f.err
} }

View File

@ -7,8 +7,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
) )
// ModelToInstanceSettings converts a datasources.DataSource to a backend.DataSourceInstanceSettings. // ModelToInstanceSettings converts a datasources.DataSource to a backend.DataSourceInstanceSettings.
@ -43,16 +43,16 @@ func ModelToInstanceSettings(ds *datasources.DataSource, decryptFn func(ds *data
}, err }, err
} }
// BackendUserFromSignedInUser converts Grafana's context request identity // BackendUserFromSignedInUser converts Grafana's SignedInUser model
// to the backend plugin's model. // to the backend plugin's model.
func BackendUserFromSignedInUser(requester identity.Requester) *backend.User { func BackendUserFromSignedInUser(su *user.SignedInUser) *backend.User {
if requester == nil { if su == nil {
return nil return nil
} }
return &backend.User{ return &backend.User{
Login: requester.GetLogin(), Login: su.Login,
Name: requester.GetDisplayName(), Name: su.Name,
Email: requester.GetEmail(), Email: su.Email,
Role: string(requester.GetOrgRole()), Role: string(su.OrgRole),
} }
} }

View File

@ -11,10 +11,10 @@ import (
"github.com/grafana/grafana/pkg/infra/localcache" "github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/pluginsintegration/adapters" "github.com/grafana/grafana/pkg/services/pluginsintegration/adapters"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings" "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
"github.com/grafana/grafana/pkg/services/user"
) )
var ErrPluginNotFound = errors.New("plugin not found") var ErrPluginNotFound = errors.New("plugin not found")
@ -39,8 +39,8 @@ type Provider struct {
// Get allows getting plugin context by its ID. If datasourceUID is not empty string // Get allows getting plugin context by its ID. If datasourceUID is not empty string
// then PluginContext.DataSourceInstanceSettings will be resolved and appended to // then PluginContext.DataSourceInstanceSettings will be resolved and appended to
// returned context. // returned context.
// Note: identity.Requester can be nil. // Note: *user.SignedInUser can be nil.
func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Requester, orgID int64) (backend.PluginContext, error) { func (p *Provider) Get(ctx context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error) {
plugin, exists := p.pluginStore.Plugin(ctx, pluginID) plugin, exists := p.pluginStore.Plugin(ctx, pluginID)
if !exists { if !exists {
return backend.PluginContext{}, ErrPluginNotFound return backend.PluginContext{}, ErrPluginNotFound
@ -50,7 +50,7 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Reque
PluginID: pluginID, PluginID: pluginID,
} }
if user != nil { if user != nil {
pCtx.OrgID = user.GetOrgID() pCtx.OrgID = user.OrgID
pCtx.User = adapters.BackendUserFromSignedInUser(user) pCtx.User = adapters.BackendUserFromSignedInUser(user)
} }
@ -68,7 +68,7 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Reque
// GetWithDataSource allows getting plugin context by its ID and PluginContext.DataSourceInstanceSettings will be // GetWithDataSource allows getting plugin context by its ID and PluginContext.DataSourceInstanceSettings will be
// resolved and appended to the returned context. // resolved and appended to the returned context.
// Note: *user.SignedInUser can be nil. // Note: *user.SignedInUser can be nil.
func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) { func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, error) {
_, exists := p.pluginStore.Plugin(ctx, pluginID) _, exists := p.pluginStore.Plugin(ctx, pluginID)
if !exists { if !exists {
return backend.PluginContext{}, ErrPluginNotFound return backend.PluginContext{}, ErrPluginNotFound
@ -78,7 +78,7 @@ func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user
PluginID: pluginID, PluginID: pluginID,
} }
if user != nil { if user != nil {
pCtx.OrgID = user.GetOrgID() pCtx.OrgID = user.OrgID
pCtx.User = adapters.BackendUserFromSignedInUser(user) pCtx.User = adapters.BackendUserFromSignedInUser(user)
} }

View File

@ -16,10 +16,10 @@ import (
"github.com/grafana/grafana/pkg/expr" "github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/validations" "github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/grafanads" "github.com/grafana/grafana/pkg/tsdb/grafanads"
@ -61,7 +61,7 @@ func ProvideService(
//go:generate mockery --name Service --structname FakeQueryService --inpackage --filename query_service_mock.go //go:generate mockery --name Service --structname FakeQueryService --inpackage --filename query_service_mock.go
type Service interface { type Service interface {
Run(ctx context.Context) error Run(ctx context.Context) error
QueryData(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) QueryData(ctx context.Context, user *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error)
} }
// Gives us compile time error if the service does not adhere to the contract of the interface // Gives us compile time error if the service does not adhere to the contract of the interface
@ -85,7 +85,7 @@ func (s *ServiceImpl) Run(ctx context.Context) error {
} }
// QueryData processes queries and returns query responses. It handles queries to single or mixed datasources, as well as expressions. // QueryData processes queries and returns query responses. It handles queries to single or mixed datasources, as well as expressions.
func (s *ServiceImpl) QueryData(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) { func (s *ServiceImpl) QueryData(ctx context.Context, user *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) {
// Parse the request into parsed queries grouped by datasource uid // Parse the request into parsed queries grouped by datasource uid
parsedReq, err := s.parseMetricRequest(ctx, user, skipDSCache, reqDTO) parsedReq, err := s.parseMetricRequest(ctx, user, skipDSCache, reqDTO)
if err != nil { if err != nil {
@ -111,7 +111,7 @@ type splitResponse struct {
} }
// executeConcurrentQueries executes queries to multiple datasources concurrently and returns the aggregate result. // executeConcurrentQueries executes queries to multiple datasources concurrently and returns the aggregate result.
func (s *ServiceImpl) executeConcurrentQueries(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest, queriesbyDs map[string][]parsedQuery) (*backend.QueryDataResponse, error) { func (s *ServiceImpl) executeConcurrentQueries(ctx context.Context, user *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest, queriesbyDs map[string][]parsedQuery) (*backend.QueryDataResponse, error) {
g, ctx := errgroup.WithContext(ctx) g, ctx := errgroup.WithContext(ctx)
g.SetLimit(s.concurrentQueryLimit) // prevent too many concurrent requests g.SetLimit(s.concurrentQueryLimit) // prevent too many concurrent requests
rchan := make(chan splitResponse, len(queriesbyDs)) rchan := make(chan splitResponse, len(queriesbyDs))
@ -198,14 +198,14 @@ func buildErrorResponses(err error, queries []*simplejson.Json) splitResponse {
} }
// handleExpressions handles POST /api/ds/query when there is an expression. // handleExpressions handles POST /api/ds/query when there is an expression.
func (s *ServiceImpl) handleExpressions(ctx context.Context, user identity.Requester, parsedReq *parsedRequest) (*backend.QueryDataResponse, error) { func (s *ServiceImpl) handleExpressions(ctx context.Context, user *user.SignedInUser, parsedReq *parsedRequest) (*backend.QueryDataResponse, error) {
exprReq := expr.Request{ exprReq := expr.Request{
Queries: []expr.Query{}, Queries: []expr.Query{},
} }
if user != nil { // for passthrough authentication, SSE does not authenticate if user != nil { // for passthrough authentication, SSE does not authenticate
exprReq.User = user exprReq.User = user
exprReq.OrgId = user.GetOrgID() exprReq.OrgId = user.OrgID
} }
for _, pq := range parsedReq.getFlattenedQueries() { for _, pq := range parsedReq.getFlattenedQueries() {
@ -239,7 +239,7 @@ func (s *ServiceImpl) handleExpressions(ctx context.Context, user identity.Reque
} }
// handleQuerySingleDatasource handles one or more queries to a single datasource // handleQuerySingleDatasource handles one or more queries to a single datasource
func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user identity.Requester, parsedReq *parsedRequest) (*backend.QueryDataResponse, error) { func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user *user.SignedInUser, parsedReq *parsedRequest) (*backend.QueryDataResponse, error) {
queries := parsedReq.getFlattenedQueries() queries := parsedReq.getFlattenedQueries()
ds := queries[0].datasource ds := queries[0].datasource
if err := s.pluginRequestValidator.Validate(ds.URL, nil); err != nil { if err := s.pluginRequestValidator.Validate(ds.URL, nil); err != nil {
@ -271,7 +271,7 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user iden
} }
// parseRequest parses a request into parsed queries grouped by datasource uid // parseRequest parses a request into parsed queries grouped by datasource uid
func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*parsedRequest, error) { func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest) (*parsedRequest, error) {
if len(reqDTO.Queries) == 0 { if len(reqDTO.Queries) == 0 {
return nil, ErrNoQueriesFound return nil, ErrNoQueriesFound
} }
@ -332,7 +332,7 @@ func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requ
return req, req.validateRequest(ctx) return req, req.validateRequest(ctx)
} }
func (s *ServiceImpl) getDataSourceFromQuery(ctx context.Context, user identity.Requester, skipDSCache bool, query *simplejson.Json, history map[string]*datasources.DataSource) (*datasources.DataSource, error) { func (s *ServiceImpl) getDataSourceFromQuery(ctx context.Context, user *user.SignedInUser, skipDSCache bool, query *simplejson.Json, history map[string]*datasources.DataSource) (*datasources.DataSource, error) {
var err error var err error
uid := query.Get("datasource").Get("uid").MustString() uid := query.Get("datasource").Get("uid").MustString()
@ -352,7 +352,7 @@ func (s *ServiceImpl) getDataSourceFromQuery(ctx context.Context, user identity.
} }
if uid == grafanads.DatasourceUID { if uid == grafanads.DatasourceUID {
return grafanads.DataSourceModel(user.GetOrgID()), nil return grafanads.DataSourceModel(user.OrgID), nil
} }
if uid != "" { if uid != "" {

View File

@ -11,7 +11,7 @@ import (
mock "github.com/stretchr/testify/mock" mock "github.com/stretchr/testify/mock"
identity "github.com/grafana/grafana/pkg/services/auth/identity" user "github.com/grafana/grafana/pkg/services/user"
) )
// FakeQueryService is an autogenerated mock type for the Service type // FakeQueryService is an autogenerated mock type for the Service type
@ -20,11 +20,11 @@ type FakeQueryService struct {
} }
// QueryData provides a mock function with given fields: ctx, _a1, skipDSCache, reqDTO // QueryData provides a mock function with given fields: ctx, _a1, skipDSCache, reqDTO
func (_m *FakeQueryService) QueryData(ctx context.Context, _a1 identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) { func (_m *FakeQueryService) QueryData(ctx context.Context, _a1 *user.SignedInUser, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) {
ret := _m.Called(ctx, _a1, skipDSCache, reqDTO) ret := _m.Called(ctx, _a1, skipDSCache, reqDTO)
var r0 *backend.QueryDataResponse var r0 *backend.QueryDataResponse
if rf, ok := ret.Get(0).(func(context.Context, identity.Requester, bool, dtos.MetricRequest) *backend.QueryDataResponse); ok { if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, bool, dtos.MetricRequest) *backend.QueryDataResponse); ok {
r0 = rf(ctx, _a1, skipDSCache, reqDTO) r0 = rf(ctx, _a1, skipDSCache, reqDTO)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
@ -33,7 +33,7 @@ func (_m *FakeQueryService) QueryData(ctx context.Context, _a1 identity.Requeste
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(context.Context, identity.Requester, bool, dtos.MetricRequest) error); ok { if rf, ok := ret.Get(1).(func(context.Context, *user.SignedInUser, bool, dtos.MetricRequest) error); ok {
r1 = rf(ctx, _a1, skipDSCache, reqDTO) r1 = rf(ctx, _a1, skipDSCache, reqDTO)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)

View File

@ -25,7 +25,6 @@ import (
"github.com/grafana/grafana/pkg/models/roletype" "github.com/grafana/grafana/pkg/models/roletype"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
pluginFakes "github.com/grafana/grafana/pkg/plugins/manager/fakes" pluginFakes "github.com/grafana/grafana/pkg/plugins/manager/fakes"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
@ -525,12 +524,12 @@ type fakeDataSourceCache struct {
cache []*datasources.DataSource cache []*datasources.DataSource
} }
func (c *fakeDataSourceCache) GetDatasource(ctx context.Context, datasourceID int64, user identity.Requester, skipCache bool) (*datasources.DataSource, error) { func (c *fakeDataSourceCache) GetDatasource(ctx context.Context, datasourceID int64, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
// deprecated: fake an error to ensure we are using GetDatasourceByUID // deprecated: fake an error to ensure we are using GetDatasourceByUID
return nil, fmt.Errorf("not found") return nil, fmt.Errorf("not found")
} }
func (c *fakeDataSourceCache) GetDatasourceByUID(ctx context.Context, datasourceUID string, user identity.Requester, skipCache bool) (*datasources.DataSource, error) { func (c *fakeDataSourceCache) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *user.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
for _, ds := range c.cache { for _, ds := range c.cache {
if ds.UID == datasourceUID { if ds.UID == datasourceUID {
return ds, nil return ds, nil

View File

@ -43,9 +43,6 @@ func (u *SignedInUser) NameOrFallback() string {
return u.Email return u.Email
} }
// TODO: There's a need to remove this struct since it creates a circular dependency
// DEPRECATED: This function uses `UserDisplayDTO` model which we want to remove
func (u *SignedInUser) ToUserDisplayDTO() *UserDisplayDTO { func (u *SignedInUser) ToUserDisplayDTO() *UserDisplayDTO {
return &UserDisplayDTO{ return &UserDisplayDTO{
ID: u.UserID, ID: u.UserID,
@ -54,16 +51,6 @@ func (u *SignedInUser) ToUserDisplayDTO() *UserDisplayDTO {
} }
} }
// Static function to parse a requester into a UserDisplayDTO
func NewUserDisplayDTOFromRequester(requester identity.Requester) (*UserDisplayDTO, error) {
userID, _ := identity.IntIdentifier(requester.GetNamespacedID())
return &UserDisplayDTO{
ID: userID,
Login: requester.GetLogin(),
Name: requester.GetDisplayName(),
}, nil
}
func (u *SignedInUser) HasRole(role roletype.RoleType) bool { func (u *SignedInUser) HasRole(role roletype.RoleType) bool {
if u.IsGrafanaAdmin { if u.IsGrafanaAdmin {
return true return true