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/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/auth/identity"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/dashboards"
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/user"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/errutil"
"github.com/grafana/grafana/pkg/web"
)
@ -46,27 +44,15 @@ func (hs *HTTPServer) isDashboardStarredByUser(c *contextmodel.ReqContext, dashI
return false, nil
}
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID()
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}
query := star.IsStarredByUserQuery{UserID: c.UserID, DashboardID: dashID}
return hs.starService.IsStarredByUser(c.Req.Context(), &query)
}
func dashboardGuardianResponse(err error) response.Response {
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
@ -109,7 +95,7 @@ func (hs *HTTPServer) TrimDashboard(c *contextmodel.ReqContext) response.Respons
// 500: internalServerError
func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response {
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 {
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
// values
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) {
return response.Error(http.StatusInternalServerError, "Error while retrieving public dashboards", err)
return response.Error(500, "Error while retrieving public dashboards", err)
}
if publicDashboard != nil {
@ -142,10 +128,10 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
}
}
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 {
return response.Err(err)
}
@ -160,7 +146,7 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
isStarred, err := hs.isDashboardStarredByUser(c, dash.ID)
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
updater, creator := anonString, anonString
@ -200,13 +186,13 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
// lookup folder title
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)
if err != nil {
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.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)
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 {
@ -289,7 +275,7 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in
queryResult, err := hs.DashboardService.GetDashboard(ctx, &query)
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
@ -312,11 +298,11 @@ func (hs *HTTPServer) DeleteDashboardByUID(c *contextmodel.ReqContext) 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 {
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 {
return response.Err(err)
}
@ -325,17 +311,10 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
return dashboardGuardianResponse(err)
}
namespaceID, userIDStr := c.SignedInUser.GetNamespacedID()
// disconnect all library elements for this dashboard
err = hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.ID)
if err != nil {
hs.log.Error(
"Failed to disconnect library elements",
"dashboard", dash.ID,
"namespaceID", namespaceID,
"user", userIDStr,
"error", err)
hs.log.Error("Failed to disconnect library elements", "dashboard", dash.ID, "user", c.SignedInUser.UserID, "error", err)
}
// 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")
}
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 {
var dashboardErr dashboards.DashboardErr
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(http.StatusInternalServerError, "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)
return response.Error(500, "Failed to delete dashboard", err)
}
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 {
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 {
ctx := c.Req.Context()
var err error
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID()
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
cmd.OrgID = c.OrgID
cmd.UserID = c.UserID
if cmd.FolderUID != "" {
folder, err := hs.folderService.Get(ctx, &folder.GetFolderQuery{
OrgID: c.SignedInUser.GetOrgID(),
OrgID: c.OrgID,
UID: &cmd.FolderUID,
SignedInUser: c.SignedInUser,
})
if err != nil {
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
}
@ -451,10 +418,10 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
if newDashboard {
limitReached, err := hs.QuotaService.QuotaReached(c, dashboards.QuotaTargetSrv)
if err != nil {
return response.Error(http.StatusInternalServerError, "failed to get quota", err)
return response.Error(500, "failed to get quota", err)
}
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 {
data, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardID(c.Req.Context(), dash.ID)
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
} else if 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) {
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
}
@ -481,7 +448,7 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
dashItem := &dashboards.SaveDashboardDTO{
Dashboard: dash,
Message: cmd.Message,
OrgID: c.SignedInUser.GetOrgID(),
OrgID: c.OrgID,
User: c.SignedInUser,
Overwrite: cmd.Overwrite,
}
@ -494,19 +461,14 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
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.
// gitops is useful when trying to save dashboards in an environment where the user can not save
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
if liveerr == nil && err != nil && channel.HasGitOpsObserver(c.SignedInUser.GetOrgID()) {
return response.JSON(http.StatusAccepted, util.DynMap{
if liveerr == nil && err != nil && channel.HasGitOpsObserver(c.SignedInUser.OrgID) {
return response.JSON(202, util.DynMap{
"status": "pending",
"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
err = hs.LibraryPanelService.ConnectLibraryPanelsForDashboard(ctx, c.SignedInUser, dashboard)
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)
@ -553,17 +515,12 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
// 401: unauthorisedError
// 500: internalServerError
func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response {
namespaceID, userIDstr := c.SignedInUser.GetNamespacedID()
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()}
prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.OrgID, UserID: c.SignedInUser.UserID, Teams: c.Teams}
homePage := hs.Cfg.HomePage
preference, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery)
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 {
@ -592,7 +549,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Resp
// nolint:gosec
file, err := os.Open(filePath)
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() {
if err := file.Close(); err != nil {
@ -607,7 +564,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Resp
jsonParser := json.NewDecoder(file)
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)
@ -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 {
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 {
return response.Err(err)
}
@ -693,7 +650,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
}
query := dashver.ListDashboardVersionsQuery{
OrgID: c.SignedInUser.GetOrgID(),
OrgID: c.OrgID,
DashboardID: dash.ID,
DashboardUID: dash.UID,
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)
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))
@ -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 {
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 {
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)
query := dashver.GetDashboardVersionQuery{
OrgID: c.SignedInUser.GetOrgID(),
OrgID: c.OrgID,
DashboardID: dash.ID,
DashboardUID: dash.UID,
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)
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
@ -922,7 +879,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
if err := web.Bind(c.Req, &apiOptions); err != nil {
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 {
return response.Err(err)
}
@ -932,7 +889,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
}
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 {
return response.Err(err)
}
@ -943,7 +900,7 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
}
options := dashdiffs.Options{
OrgId: c.SignedInUser.GetOrgID(),
OrgId: c.OrgID,
DiffType: dashdiffs.ParseDiffType(apiOptions.DiffType),
Base: dashdiffs.DiffTarget{
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)
if err != nil {
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{
@ -980,9 +937,9 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
newVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &newVersionQuery)
if err != nil {
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
@ -992,9 +949,9 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
if err != nil {
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 {
@ -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 {
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 {
return response.Err(err)
}
@ -1060,21 +1017,16 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
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)
if err != nil {
return response.Error(http.StatusNotFound, "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)
return response.Error(404, "Dashboard version not found", nil)
}
saveCmd := dashboards.SaveDashboardCommand{}
saveCmd.RestoredFrom = version.Version
saveCmd.OrgID = c.SignedInUser.GetOrgID()
saveCmd.UserID = userID
saveCmd.OrgID = c.OrgID
saveCmd.UserID = c.UserID
saveCmd.Dashboard = version.Data
saveCmd.Dashboard.Set("version", dash.Version)
saveCmd.Dashboard.Set("uid", dash.UID)
@ -1093,7 +1045,7 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
// 401: unauthorisedError
// 500: internalServerError
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)
if err != nil {
c.JsonApiErr(500, "Failed to get tags from database", err)

View File

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

View File

@ -12,10 +12,10 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/tracing"
"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/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
)
@ -68,8 +68,8 @@ type Service struct {
}
type pluginContextProvider interface {
Get(ctx context.Context, pluginID string, user identity.Requester, orgID int64) (backend.PluginContext, error)
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
Get(ctx context.Context, pluginID string, user *user.SignedInUser, orgID int64) (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,

View File

@ -5,8 +5,8 @@ import (
"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/user"
)
type fakePluginContextProvider struct {
@ -20,7 +20,7 @@ type fakePluginContextProvider struct {
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 {
method string
params []interface{}
@ -31,9 +31,9 @@ func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user
var u *backend.User
if user != nil {
u = &backend.User{
Login: user.GetLogin(),
Name: user.GetDisplayName(),
Email: user.GetEmail(),
Login: user.Login,
Name: user.Name,
Email: user.Email,
}
}
return backend.PluginContext{
@ -45,7 +45,7 @@ func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user
}, 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 {
method string
params []interface{}
@ -57,7 +57,7 @@ func (f *fakePluginContextProvider) GetWithDataSource(ctx context.Context, plugi
orgId := int64(1)
if user != nil {
orgId = user.GetOrgID()
orgId = user.OrgID
}
r, err := f.Get(ctx, pluginID, user, orgId)
if ds != nil {

View File

@ -8,8 +8,8 @@ import (
"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/user"
)
// Request is similar to plugins.DataQuery but with the Time Ranges is per Query.
@ -18,7 +18,7 @@ type Request struct {
Debug bool
OrgId int64
Queries []Query
User identity.Requester
User *user.SignedInUser
}
// Query is like plugins.DataSubQuery, but with a a time range, and only the UID

View File

@ -4,8 +4,8 @@ import (
"sync"
"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/user"
)
// Job holds state about when the alert rule should be evaluated.
@ -46,7 +46,7 @@ type EvalMatch struct {
}
type DashAlertInfo struct {
User identity.Requester
User *user.SignedInUser
Dash *dashboards.Dashboard
OrgID int64
}

View File

@ -9,7 +9,6 @@ import (
"github.com/stretchr/testify/require"
"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/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
@ -84,12 +83,9 @@ func TestImportDashboardService(t *testing.T) {
require.NotNil(t, resp)
require.Equal(t, "UDdpyzz7z", resp.UID)
userID, err := identity.IntIdentifier(importDashboardArg.User.GetNamespacedID())
require.NoError(t, err)
require.NotNil(t, importDashboardArg)
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, int64(5), importDashboardArg.Dashboard.FolderID)
@ -151,12 +147,9 @@ func TestImportDashboardService(t *testing.T) {
require.NotNil(t, resp)
require.Equal(t, "UDdpyzz7z", resp.UID)
userID, err := identity.IntIdentifier(importDashboardArg.User.GetNamespacedID())
require.NoError(t, err)
require.NotNil(t, importDashboardArg)
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, int64(5), importDashboardArg.Dashboard.FolderID)

View File

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

View File

@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"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/datasources"
"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{
Dashboard: dash.Data,
Message: dto.Message,
OrgID: dto.OrgID,
Overwrite: dto.Overwrite,
UserID: userID,
UserID: dto.User.UserID,
FolderID: dash.FolderID,
IsFolder: dash.IsFolder,
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
// 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
if newDashboard {
@ -304,8 +297,7 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt
if dto.Dashboard.ID == 0 {
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, "namespaceID", namespaceID, "userID", userID, "error", err)
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
}
}
@ -345,8 +337,7 @@ func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.C
if dto.Dashboard.ID == 0 {
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, "namespaceID", namespaceID, "userID", userID, "error", err)
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
}
}
@ -394,8 +385,7 @@ func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *dashboar
// new dashboard created
if dto.Dashboard.ID == 0 {
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, "namespaceID", namespaceID, "userID", userID, "error", err)
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.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 {
namespaceID, userID := dto.User.GetNamespacedID()
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "user", dto.User.UserID, "error", err)
}
return dash, nil
@ -473,16 +462,9 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
inFolder := dash.FolderID > 0
var permissions []accesscontrol.SetResourcePermissionCommand
namespaceID, userIDstr := dto.User.GetNamespacedID()
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil {
return err
}
if !provisioned && namespaceID == identity.NamespaceUser {
if !provisioned && dto.User.IsRealUser() && !dto.User.IsAnonymous {
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
}
_, err = svc.SetPermissions(ctx, dto.OrgID, dash.UID, permissions...)
_, err := svc.SetPermissions(ctx, dto.OrgID, dash.UID, permissions...)
if err != nil {
return err
}

View File

@ -15,7 +15,6 @@ import (
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/alerting"
"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/database"
"github.com/grafana/grafana/pkg/services/featuremgmt"
@ -113,12 +112,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sqlStore)
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, 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",
@ -136,12 +132,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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",
@ -159,12 +152,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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",
@ -183,12 +173,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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",
@ -207,12 +194,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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",
@ -231,12 +215,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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",
@ -255,12 +236,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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",
@ -279,12 +257,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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",
@ -303,12 +278,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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",
@ -327,12 +299,9 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore)
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, 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"
"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.
@ -64,8 +64,8 @@ type DataSourceService interface {
// CacheService interface for retrieving a cached datasource.
type CacheService interface {
// 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(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 (
"context"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
)
type FakeCacheService struct {
@ -13,7 +13,7 @@ type FakeCacheService struct {
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 {
if datasource.ID == datasourceID {
return datasource, nil
@ -22,7 +22,7 @@ func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64
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 {
if datasource.UID == datasourceUID {
return datasource, nil

View File

@ -1,12 +1,12 @@
package guardian
import (
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
)
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 {
@ -20,6 +20,6 @@ func ProvideGuardian() *OSSProvider {
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{}
}

View File

@ -8,9 +8,9 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/localcache"
"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/guardian"
"github.com/grafana/grafana/pkg/services/user"
)
const (
@ -38,7 +38,7 @@ type CacheServiceImpl struct {
func (dc *CacheServiceImpl) GetDatasource(
ctx context.Context,
datasourceID int64,
user identity.Requester,
user *user.SignedInUser,
skipCache bool,
) (*datasources.DataSource, error) {
cacheKey := idKey(datasourceID)
@ -46,7 +46,7 @@ func (dc *CacheServiceImpl) GetDatasource(
if !skipCache {
if cached, found := dc.CacheService.Get(cacheKey); found {
ds := cached.(*datasources.DataSource)
if ds.OrgID == user.GetOrgID() {
if ds.OrgID == user.OrgID {
if err := dc.canQuery(user, ds); err != nil {
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}
ds, err := ss.GetDataSource(ctx, query)
if err != nil {
@ -79,21 +79,21 @@ func (dc *CacheServiceImpl) GetDatasource(
func (dc *CacheServiceImpl) GetDatasourceByUID(
ctx context.Context,
datasourceUID string,
user identity.Requester,
user *user.SignedInUser,
skipCache bool,
) (*datasources.DataSource, error) {
if datasourceUID == "" {
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")
}
uidCacheKey := uidKey(user.GetOrgID(), datasourceUID)
uidCacheKey := uidKey(user.OrgID, datasourceUID)
if !skipCache {
if cached, found := dc.CacheService.Get(uidCacheKey); found {
ds := cached.(*datasources.DataSource)
if ds.OrgID == user.GetOrgID() {
if ds.OrgID == user.OrgID {
if err := dc.canQuery(user, ds); err != nil {
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())
query := &datasources.GetDataSourceQuery{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.OrgID}
ss := SqlStore{db: dc.SQLStore, logger: dc.logger}
ds, err := ss.GetDataSource(ctx, query)
if err != nil {
@ -128,8 +128,8 @@ func uidKey(orgID int64, uid string) string {
return fmt.Sprintf("ds-orgid-uid-%d-%s", orgID, uid)
}
func (dc *CacheServiceImpl) canQuery(user identity.Requester, ds *datasources.DataSource) error {
guardian := dc.dsGuardian.New(user.GetOrgID(), user, *ds)
func (dc *CacheServiceImpl) canQuery(user *user.SignedInUser, ds *datasources.DataSource) error {
guardian := dc.dsGuardian.New(user.OrgID, user, *ds)
if canQuery, err := guardian.CanQuery(ds.ID); err != nil || !canQuery {
if err != nil {
return err

View File

@ -12,7 +12,6 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
"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/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
@ -281,12 +280,7 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (
dashFolder.SetUID(trimmedUID)
user := cmd.SignedInUser
namespaceID, userIDstr := 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)
}
userID := user.UserID
if userID == 0 {
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{
Dashboard: dash.Data,
Message: dto.Message,
OrgID: dto.OrgID,
Overwrite: dto.Overwrite,
UserID: userID,
UserID: dto.User.UserID,
FolderID: dash.FolderID,
IsFolder: dash.IsFolder,
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
// 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
if newDashboard {

View File

@ -5,7 +5,6 @@ import (
"time"
"github.com/grafana/grafana/pkg/infra/slugify"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util/errutil"
@ -139,7 +138,6 @@ type GetFolderQuery struct {
OrgID int64
SignedInUser *user.SignedInUser `json:"-"`
Requester identity.Requester `json:"-"`
}
// 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/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
)
@ -16,14 +16,14 @@ var _ DashboardGuardian = new(accessControlDashboardGuardian)
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardId.
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,
) (DashboardGuardian, error) {
var dashboard *dashboards.Dashboard
if dashboardId != 0 {
q := &dashboards.GetDashboardQuery{
ID: dashboardId,
OrgID: user.GetOrgID(),
OrgID: user.OrgID,
}
qResult, err := dashboardService.GetDashboard(ctx, q)
@ -65,14 +65,14 @@ func NewAccessControlDashboardGuardian(
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardUID.
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,
) (DashboardGuardian, error) {
var dashboard *dashboards.Dashboard
if dashboardUID != "" {
q := &dashboards.GetDashboardQuery{
UID: dashboardUID,
OrgID: user.GetOrgID(),
OrgID: user.OrgID,
}
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
// since it avoids querying the database for fetching the dashboard.
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,
) (DashboardGuardian, error) {
if dashboard != nil && dashboard.IsFolder {
@ -148,7 +148,7 @@ func NewAccessControlDashboardGuardianByDashboard(
// NewAccessControlFolderGuardian creates a folder guardian by the provided folder.
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,
) (DashboardGuardian, error) {
return &accessControlFolderGuardian{
@ -168,7 +168,7 @@ type accessControlBaseGuardian struct {
cfg *setting.Cfg
ctx context.Context
log log.Logger
user identity.Requester
user *user.SignedInUser
ac accesscontrol.AccessControl
dashboardService dashboards.DashboardService
}
@ -309,13 +309,12 @@ func (a *accessControlFolderGuardian) CanCreate(folderID int64, isFolder bool) (
func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
namespaceID, userID := a.user.GetNamespacedID()
if err != nil {
id := 0
if a.dashboard != nil {
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 {
@ -323,7 +322,7 @@ func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evalua
if a.dashboard != nil {
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
@ -331,7 +330,6 @@ func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evalua
func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
namespaceID, userID := a.user.GetNamespacedID()
if err != nil {
uid := ""
orgID := 0
@ -339,7 +337,7 @@ func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator
uid = a.folder.UID
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 {
@ -349,7 +347,7 @@ func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator
uid = a.folder.UID
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
@ -359,7 +357,7 @@ func (a *accessControlDashboardGuardian) loadParentFolder(folderID int64) (*dash
if folderID == 0 {
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)
if err != nil {
return nil, err
@ -371,7 +369,7 @@ func (a *accessControlFolderGuardian) loadParentFolder(folderID int64) (*dashboa
if folderID == 0 {
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)
if err != nil {
return nil, err

View File

@ -6,11 +6,11 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"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/folder"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util/errutil"
)
@ -35,7 +35,7 @@ type DashboardGuardian interface {
type dashboardGuardianImpl struct {
cfg *setting.Cfg
user identity.Requester
user *user.SignedInUser
dashId int64
orgId int64
acl []*dashboards.DashboardACLInfoDTO
@ -49,30 +49,30 @@ type dashboardGuardianImpl struct {
// New factory for creating a new dashboard guardian instance
// 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")
}
// NewByUID factory for creating a new dashboard guardian instance
// 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")
}
// NewByDashboard factory for creating a new dashboard guardian instance
// 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")
}
// NewByFolder factory for creating a new folder guardian instance
// 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")
}
// 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 {
q := &dashboards.GetDashboardQuery{
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.
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)
if dashUID != "" {
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.
// This constructor should be preferred over the other two if the dashboard in available
// 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{
cfg: cfg,
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
// since it avoids querying the database for fetching the dashboard.
// 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{
cfg: cfg,
user: user,
@ -198,7 +198,7 @@ func (g *dashboardGuardianImpl) CanCreate(_ int64, _ bool) (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)
}
@ -216,36 +216,32 @@ func (g *dashboardGuardianImpl) logHasPermissionResult(permission dashboards.Per
return hasPermission, err
}
var debugMessage string
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 {
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
}
func (g *dashboardGuardianImpl) checkACL(permission dashboards.PermissionType, acl []*dashboards.DashboardACLInfoDTO) (bool, error) {
orgRole := g.user.OrgRole
teamACLItems := []*dashboards.DashboardACLInfoDTO{}
for _, p := range acl {
userID, err := identity.IntIdentifier(g.user.GetNamespacedID())
if err != nil {
return false, err
}
// user match
if p.UserID > 0 && p.UserID == userID && p.Permission >= permission {
return true, nil
if !g.user.IsAnonymous && p.UserID > 0 {
if p.UserID == g.user.UserID && p.Permission >= permission {
return true, nil
}
}
// role match
if p.Role != nil && *p.Role == g.user.GetOrgRole() && p.Permission >= permission {
return true, nil
if p.Role != nil {
if *p.Role == orgRole && p.Permission >= permission {
return true, nil
}
}
// 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
}
@ -379,12 +375,7 @@ func (g *dashboardGuardianImpl) getTeams() ([]*team.TeamDTO, error) {
return g.teams, nil
}
userIdD, err := identity.IntIdentifier(g.user.GetNamespacedID())
if err != nil {
return nil, err
}
query := team.GetTeamsByUserQuery{OrgID: g.orgId, UserID: userIdD, SignedInUser: g.user}
query := team.GetTeamsByUserQuery{OrgID: g.orgId, UserID: g.user.UserID, SignedInUser: g.user}
queryResult, err := g.teamService.GetTeamsByUser(g.ctx, &query)
g.teams = queryResult
@ -393,7 +384,7 @@ func (g *dashboardGuardianImpl) getTeams() ([]*team.TeamDTO, error) {
func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.DashboardACL, error) {
hiddenACL := make([]*dashboards.DashboardACL, 0)
if g.user.GetIsGrafanaAdmin() {
if g.user.IsGrafanaAdmin {
return hiddenACL, nil
}
@ -403,7 +394,7 @@ func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.Da
}
for _, item := range existingPermissions {
if item.Inherited || item.UserLogin == g.user.GetLogin() {
if item.Inherited || item.UserLogin == g.user.Login {
continue
}
@ -425,11 +416,10 @@ func (g *dashboardGuardianImpl) GetHiddenACL(cfg *setting.Cfg) ([]*dashboards.Da
// nolint:unused
type FakeDashboardGuardian struct {
DashID int64
DashUID string
// OrgID can be retrieved from the identity.Requester.GetOrgID
DashID int64
DashUID string
OrgID int64
User identity.Requester
User *user.SignedInUser
CanSaveValue bool
CanEditValue bool
CanViewValue bool
@ -471,21 +461,21 @@ func (g *FakeDashboardGuardian) HasPermission(permission dashboards.PermissionTy
// nolint:unused
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.DashID = dashID
mock.User = user
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.DashUID = dashUID
mock.User = user
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.DashUID = dash.UID
mock.DashID = dash.ID
@ -493,7 +483,7 @@ func MockDashboardGuardian(mock *FakeDashboardGuardian) {
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.DashUID = f.UID
mock.DashID = f.ID

View File

@ -5,10 +5,10 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"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/folder"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/user"
"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) {
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)
}
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)
}
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)
}
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)
}
}
@ -48,19 +48,19 @@ func InitLegacyGuardian(cfg *setting.Cfg, store db.DB, dashSvc dashboards.Dashbo
func InitAccessControlGuardian(
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)
}
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)
}
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)
}
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)
}
}

View File

@ -6,8 +6,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"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/user"
)
var (
@ -37,13 +37,13 @@ func (b *BroadcastRunner) GetHandlerForPath(_ string) (model.ChannelHandler, err
}
// 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{
Presence: true,
JoinLeave: true,
}
query := &model.GetLiveMessageQuery{
OrgID: u.GetOrgID(),
OrgID: u.OrgID,
Channel: e.Channel,
}
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
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{
OrgID: u.GetOrgID(),
OrgID: u.OrgID,
Channel: e.Channel,
Data: e.Data,
}

View File

@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"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/guardian"
"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
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, "/")
if parts[0] == "gitops" {
// 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
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)
if err != nil {
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
guard, err := guardian.NewByDashboard(ctx, dash, user.GetOrgID(), user)
guard, err := guardian.NewByDashboard(ctx, dash, user.OrgID, user)
if err != nil {
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
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, "/")
if parts[0] == "gitops" {
// 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
}
@ -118,14 +117,14 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, requester identity.Req
// just ignore the event
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)
if err != nil {
logger.Error("Unknown dashboard", "query", query)
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 {
logger.Error("Failed to create guardian", "err", err)
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
event.User, err = user.NewUserDisplayDTOFromRequester(requester)
if err != nil {
return model.PublishReply{}, backend.PublishStreamStatusNotFound, err
}
event.User = user.ToUserDisplayDTO()
msg, err := json.Marshal(event)
if err != nil {

View File

@ -7,17 +7,17 @@ import (
"github.com/centrifugal/centrifuge"
"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/orgchannel"
"github.com/grafana/grafana/pkg/services/live/runstream"
"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
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.
@ -63,7 +63,7 @@ type PluginPathRunner struct {
}
// 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)
if err != nil {
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
}
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 {
logger.Error("Error submitting stream to manager", "error", err, "path", r.path)
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.
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)
if err != nil {
if errors.Is(err, plugincontext.ErrPluginNotFound) {

View File

@ -10,7 +10,7 @@ import (
gomock "github.com/golang/mock/gomock"
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.
@ -37,7 +37,7 @@ func (m *MockPluginContextGetter) EXPECT() *MockPluginContextGetterMockRecorder
}
// 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()
ret := m.ctrl.Call(m, "GetPluginContext", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(backend.PluginContext)

View File

@ -32,7 +32,6 @@ import (
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/auth/identity"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/datasources"
@ -300,11 +299,10 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
g.websocketHandler = func(ctx *contextmodel.ReqContext) {
user := ctx.SignedInUser
_, userID := user.GetNamespacedID()
// Centrifuge expects Credentials in context with a current user ID.
cred := &centrifuge.Credentials{
UserID: userID,
UserID: fmt.Sprintf("%d", user.UserID),
}
newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred)
newCtx = livecontext.SetContextSignedUser(newCtx, user)
@ -595,7 +593,7 @@ func (g *GrafanaLive) handleOnSubscribe(ctx context.Context, client *centrifuge.
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)
return centrifuge.SubscribeReply{}, centrifuge.ErrorPermissionDenied
}
@ -605,7 +603,7 @@ func (g *GrafanaLive) handleOnSubscribe(ctx context.Context, client *centrifuge.
var ruleFound bool
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 {
logger.Error("Error getting channel rule", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
@ -696,13 +694,13 @@ func (g *GrafanaLive) handleOnPublish(ctx context.Context, client *centrifuge.Cl
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)
return centrifuge.PublishReply{}, centrifuge.ErrorPermissionDenied
}
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 {
logger.Error("Error getting channel rule", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
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}
}
}
_, 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 {
logger.Error("Error processing input", "user", client.UserID(), "client", client.ID(), "channel", e.Channel, "error", err)
return centrifuge.PublishReply{}, centrifuge.ErrorInternal
@ -807,7 +805,7 @@ func publishStatusToHTTPError(status backend.PublishStreamStatus) (int, string)
}
// 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}
addr, err := live.ParseChannel(channel)
if err != nil {
@ -848,7 +846,7 @@ func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user identity.Reque
// GetChannelHandlerFactory gets a ChannelHandlerFactory for a namespace.
// 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 {
case live.ScopeGrafana:
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 {
return p, nil
}
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)
if err != nil {
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
}
func (g *GrafanaLive) handleStreamScope(u identity.Requester, namespace string) (model.ChannelHandlerFactory, error) {
return g.ManagedStreamRunner.GetOrCreateStream(u.GetOrgID(), live.ScopeStream, namespace)
func (g *GrafanaLive) handleStreamScope(u *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
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)
if err != nil {
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)
}
namespaceID, userID := ctx.SignedInUser.GetNamespacedID()
logger.Debug("Publish API cmd", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel)
logger.Debug("Publish API cmd", "user", ctx.SignedInUser.UserID, "channel", cmd.Channel)
user := ctx.SignedInUser
channel := cmd.Channel
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 {
logger.Error("Error getting channel rule", "user", user, "channel", channel, "error", err)
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)
}
}
_, 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 {
logger.Error("Error processing input", "user", user, "channel", channel, "error", err)
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)
}
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 {
logger.Error("Error publish to channel", "error", err, "channel", cmd.Channel)
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{})
}
@ -1002,9 +999,9 @@ func (g *GrafanaLive) HandleListHTTP(c *contextmodel.ReqContext) response.Respon
var channels []*managedstream.ManagedChannel
var err error
if g.IsHA() {
channels, err = g.surveyCaller.CallManagedStreams(c.SignedInUser.GetOrgID())
channels, err = g.surveyCaller.CallManagedStreams(c.SignedInUser.OrgID)
} else {
channels, err = g.ManagedStreamRunner.GetManagedChannels(c.SignedInUser.GetOrgID())
channels, err = g.ManagedStreamRunner.GetManagedChannels(c.SignedInUser.OrgID)
}
if err != nil {
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)["*"]
if path == "grafana/dashboards/gitops" {
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{
@ -1030,7 +1027,7 @@ func (g *GrafanaLive) HandleInfoHTTP(ctx *contextmodel.ReqContext) response.Resp
// HandleChannelRulesListHTTP ...
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 {
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 {
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 {
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 {
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 {
return response.Error(http.StatusInternalServerError, "Error converting data", err)
}
@ -1145,7 +1142,7 @@ func (g *GrafanaLive) HandleChannelRulesPostHTTP(c *contextmodel.ReqContext) res
if err != nil {
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 {
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 == "" {
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 {
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 == "" {
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 {
return response.Error(http.StatusInternalServerError, "Failed to delete channel rule", err)
}
@ -1211,7 +1208,7 @@ func (g *GrafanaLive) HandlePipelineEntitiesListHTTP(_ *contextmodel.ReqContext)
// HandleWriteConfigsListHTTP ...
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 {
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 {
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 {
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 == "" {
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,
})
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 {
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 == "" {
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 {
return response.Error(http.StatusInternalServerError, "Failed to delete write config", err)
}

View File

@ -3,21 +3,21 @@ package livecontext
import (
"context"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/user"
)
type signedUserContextKeyType int
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)
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 {
user, ok := val.(identity.Requester)
user, ok := val.(*user.SignedInUser)
return user, ok
}
return nil, false

View File

@ -7,11 +7,11 @@ import (
"github.com/centrifugal/centrifuge"
"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/live/orgchannel"
"github.com/grafana/grafana/pkg/services/live/pipeline"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/user"
)
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 == "" {
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)

View File

@ -13,9 +13,9 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/live"
"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/orgchannel"
"github.com/grafana/grafana/pkg/services/user"
)
var (
@ -239,9 +239,9 @@ func (s *NamespaceStream) GetHandlerForPath(_ string) (model.ChannelHandler, err
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{}
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 {
return reply, 0, err
}
@ -251,6 +251,6 @@ func (s *NamespaceStream) OnSubscribe(ctx context.Context, u identity.Requester,
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
}

View File

@ -7,7 +7,7 @@ import (
"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.
@ -54,10 +54,10 @@ type PublishReply struct {
// ChannelHandler defines the core channel behavior
type ChannelHandler interface {
// 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(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.

View File

@ -3,8 +3,8 @@ package pipeline
import (
"context"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
)
type RoleCheckAuthorizer struct {
@ -15,10 +15,10 @@ func NewRoleCheckAuthorizer(role org.RoleType) *RoleCheckAuthorizer {
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
}
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
}

View File

@ -17,8 +17,8 @@ import (
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"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/user"
)
const (
@ -113,12 +113,12 @@ type Subscriber interface {
// PublishAuthChecker checks whether current user can publish to a channel.
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.
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.

View File

@ -6,9 +6,9 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"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/model"
"github.com/grafana/grafana/pkg/services/user"
)
type BuiltinSubscriber struct {
@ -16,7 +16,7 @@ type BuiltinSubscriber struct {
}
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"

View File

@ -71,7 +71,7 @@ func (s *PipelinePushHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request)
"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 {
logger.Error("Pipeline input processing error", "error", err, "body", string(body))
return

View File

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

View File

@ -11,8 +11,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"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/user"
)
var (
@ -26,7 +26,7 @@ type ChannelLocalPublisher 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 {
@ -374,7 +374,7 @@ func (s *Manager) Run(ctx context.Context) error {
type streamRequest struct {
Channel string
Path string
user identity.Requester
user *user.SignedInUser
PluginContext backend.PluginContext
StreamRunner StreamRunner
Data []byte
@ -401,7 +401,7 @@ var errDatasourceNotFound = errors.New("datasource not found")
// SubmitStream submits stream handler in Manager to manage.
// 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 {
// Resolve new plugin context as it could be modified since last call.
var datasourceUID string

View File

@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/auth/identity"
"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) {
userID, err := identity.IntIdentifier(user.GetNamespacedID())
require.NoError(t, err)
require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID())
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) {
require.Equal(t, int64(2), user.UserID)
require.Equal(t, int64(1), user.OrgID)
require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
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("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
}).Times(0)
@ -208,7 +205,7 @@ func TestStreamManager_SubmitStream_CloseNoSubscribers(t *testing.T) {
startedCh := 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
}).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) {
userID, err := identity.IntIdentifier(user.GetNamespacedID())
require.NoError(t, err)
require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID())
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) {
require.Equal(t, int64(2), user.UserID)
require.Equal(t, int64(1), user.OrgID)
require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil
@ -301,7 +296,7 @@ func TestStreamManager_SubmitStream_NilErrorStopsRunStream(t *testing.T) {
_ = 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
}).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) {
userID, err := identity.IntIdentifier(user.GetNamespacedID())
require.NoError(t, err)
require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID())
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) {
require.Equal(t, int64(2), user.UserID)
require.Equal(t, int64(1), user.OrgID)
require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
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) {
userID, err := identity.IntIdentifier(user.GetNamespacedID())
require.NoError(t, err)
require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID())
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) {
require.Equal(t, int64(2), user.UserID)
require.Equal(t, int64(1), user.OrgID)
require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil

View File

@ -10,7 +10,7 @@ import (
gomock "github.com/golang/mock/gomock"
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.
@ -149,7 +149,7 @@ func (m *MockPluginContextGetter) EXPECT() *MockPluginContextGetterMockRecorder
}
// 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()
ret := m.ctrl.Call(m, "GetPluginContext", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(backend.PluginContext)

View File

@ -9,10 +9,10 @@ import (
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/auth/identity"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasourceproxy"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web"
)
@ -114,7 +114,7 @@ type fakeCacheService struct {
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 {
return nil, f.err
}
@ -122,7 +122,7 @@ func (f fakeCacheService) GetDatasource(_ context.Context, datasourceID int64, _
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 {
return nil, f.err
}

View File

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

View File

@ -11,10 +11,10 @@ import (
"github.com/grafana/grafana/pkg/infra/localcache"
"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/pluginsintegration/adapters"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
"github.com/grafana/grafana/pkg/services/user"
)
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
// then PluginContext.DataSourceInstanceSettings will be resolved and appended to
// returned context.
// Note: identity.Requester can be nil.
func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Requester, orgID int64) (backend.PluginContext, error) {
// Note: *user.SignedInUser can be nil.
func (p *Provider) Get(ctx context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error) {
plugin, exists := p.pluginStore.Plugin(ctx, pluginID)
if !exists {
return backend.PluginContext{}, ErrPluginNotFound
@ -50,7 +50,7 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Reque
PluginID: pluginID,
}
if user != nil {
pCtx.OrgID = user.GetOrgID()
pCtx.OrgID = user.OrgID
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
// resolved and appended to the returned context.
// 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)
if !exists {
return backend.PluginContext{}, ErrPluginNotFound
@ -78,7 +78,7 @@ func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user
PluginID: pluginID,
}
if user != nil {
pCtx.OrgID = user.GetOrgID()
pCtx.OrgID = user.OrgID
pCtx.User = adapters.BackendUserFromSignedInUser(user)
}

View File

@ -16,10 +16,10 @@ import (
"github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/infra/log"
"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/datasources"
"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/setting"
"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
type Service interface {
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
@ -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.
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
parsedReq, err := s.parseMetricRequest(ctx, user, skipDSCache, reqDTO)
if err != nil {
@ -111,7 +111,7 @@ type splitResponse struct {
}
// 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.SetLimit(s.concurrentQueryLimit) // prevent too many concurrent requests
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.
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{
Queries: []expr.Query{},
}
if user != nil { // for passthrough authentication, SSE does not authenticate
exprReq.User = user
exprReq.OrgId = user.GetOrgID()
exprReq.OrgId = user.OrgID
}
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
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()
ds := queries[0].datasource
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
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 {
return nil, ErrNoQueriesFound
}
@ -332,7 +332,7 @@ func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requ
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
uid := query.Get("datasource").Get("uid").MustString()
@ -352,7 +352,7 @@ func (s *ServiceImpl) getDataSourceFromQuery(ctx context.Context, user identity.
}
if uid == grafanads.DatasourceUID {
return grafanads.DataSourceModel(user.GetOrgID()), nil
return grafanads.DataSourceModel(user.OrgID), nil
}
if uid != "" {

View File

@ -11,7 +11,7 @@ import (
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
@ -20,11 +20,11 @@ type FakeQueryService struct {
}
// 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)
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)
} else {
if ret.Get(0) != nil {
@ -33,7 +33,7 @@ func (_m *FakeQueryService) QueryData(ctx context.Context, _a1 identity.Requeste
}
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)
} else {
r1 = ret.Error(1)

View File

@ -25,7 +25,6 @@ import (
"github.com/grafana/grafana/pkg/models/roletype"
"github.com/grafana/grafana/pkg/plugins"
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/ctxkey"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
@ -525,12 +524,12 @@ type fakeDataSourceCache struct {
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
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 {
if ds.UID == datasourceUID {
return ds, nil

View File

@ -43,9 +43,6 @@ func (u *SignedInUser) NameOrFallback() string {
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 {
return &UserDisplayDTO{
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 {
if u.IsGrafanaAdmin {
return true