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

* Make identity.Requester available at Context

* Clean pkg/services/guardian/guardian.go

* Clean guardian provider and guardian AC

* Clean pkg/api/team.go

* Clean ctxhandler, datasources, plugin and live

* Question: what to do with the UserDisplayDTO?

* Clean dashboards and guardian

* Remove identity.Requester from ReqContext

* Implement NewUserDisplayDTOFromRequester

* Fix tests

* Change status code numbers for http constants

* Upgrade signature of ngalert services

* log parsing errors instead of throwing error

* Fix tests and add logs

* linting
This commit is contained in:
linoman
2023-08-28 12:04:36 -05:00
committed by GitHub
parent b043d8d0e8
commit 9b9c9e83dc
43 changed files with 523 additions and 359 deletions
+5 -5
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 *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
func (b *BroadcastRunner) OnSubscribe(_ context.Context, u identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
reply := model.SubscribeReply{
Presence: true,
JoinLeave: true,
}
query := &model.GetLiveMessageQuery{
OrgID: u.OrgID,
OrgID: u.GetOrgID(),
Channel: e.Channel,
}
msg, ok, err := b.liveMessageStore.GetLiveMessage(query)
@@ -57,9 +57,9 @@ func (b *BroadcastRunner) OnSubscribe(_ context.Context, u *user.SignedInUser, e
}
// OnPublish is called when a client wants to broadcast on the websocket
func (b *BroadcastRunner) OnPublish(_ context.Context, u *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
func (b *BroadcastRunner) OnPublish(_ context.Context, u identity.Requester, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
query := &model.SaveLiveMessageQuery{
OrgID: u.OrgID,
OrgID: u.GetOrgID(),
Channel: e.Channel,
Data: e.Data,
}
+12 -8
View File
@@ -9,6 +9,7 @@ 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"
@@ -52,7 +53,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 *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
func (h *DashboardHandler) OnSubscribe(ctx context.Context, user identity.Requester, 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
@@ -66,7 +67,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *user.SignedInU
// make sure can view this dashboard
if len(parts) == 2 && parts[0] == "uid" {
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.OrgID}
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.GetOrgID()}
queryResult, err := h.DashboardService.GetDashboard(ctx, &query)
if err != nil {
logger.Error("Error getting dashboard", "query", query, "error", err)
@@ -74,7 +75,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *user.SignedInU
}
dash := queryResult
guard, err := guardian.NewByDashboard(ctx, dash, user.OrgID, user)
guard, err := guardian.NewByDashboard(ctx, dash, user.GetOrgID(), user)
if err != nil {
return model.SubscribeReply{}, backend.SubscribeStreamStatusPermissionDenied, err
}
@@ -94,11 +95,11 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *user.SignedInU
}
// OnPublish is called when someone begins to edit a dashboard
func (h *DashboardHandler) OnPublish(ctx context.Context, user *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
func (h *DashboardHandler) OnPublish(ctx context.Context, requester identity.Requester, 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 !user.HasRole(org.RoleAdmin) {
if !requester.HasRole(org.RoleAdmin) {
return model.PublishReply{}, backend.PublishStreamStatusPermissionDenied, nil
}
@@ -117,14 +118,14 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, user *user.SignedInUse
// just ignore the event
return model.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("ignore???")
}
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: user.OrgID}
query := dashboards.GetDashboardQuery{UID: parts[1], OrgID: requester.GetOrgID()}
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, user.OrgID, user)
guard, err := guardian.NewByDashboard(ctx, queryResult, requester.GetOrgID(), requester)
if err != nil {
logger.Error("Failed to create guardian", "err", err)
return model.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("internal error")
@@ -141,7 +142,10 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, user *user.SignedInUse
}
// Tell everyone who is editing
event.User = user.ToUserDisplayDTO()
event.User, err = user.NewUserDisplayDTOFromRequester(requester)
if err != nil {
return model.PublishReply{}, backend.PublishStreamStatusNotFound, err
}
msg, err := json.Marshal(event)
if err != nil {
+5 -5
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 *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error)
GetPluginContext(ctx context.Context, user identity.Requester, 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 *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
func (r *PluginPathRunner) OnSubscribe(ctx context.Context, user identity.Requester, 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 *user.SignedInU
return model.SubscribeReply{}, resp.Status, nil
}
submitResult, err := r.runStreamManager.SubmitStream(ctx, user, orgchannel.PrependOrgID(user.OrgID, e.Channel), r.path, e.Data, pCtx, r.handler, false)
submitResult, err := r.runStreamManager.SubmitStream(ctx, user, orgchannel.PrependOrgID(user.GetOrgID(), 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 *user.SignedInU
}
// OnPublish passes control to a plugin.
func (r *PluginPathRunner) OnPublish(ctx context.Context, user *user.SignedInUser, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
func (r *PluginPathRunner) OnPublish(ctx context.Context, user identity.Requester, 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) {
+2 -2
View File
@@ -10,7 +10,7 @@ import (
gomock "github.com/golang/mock/gomock"
backend "github.com/grafana/grafana-plugin-sdk-go/backend"
user "github.com/grafana/grafana/pkg/services/user"
identity "github.com/grafana/grafana/pkg/services/auth/identity"
)
// 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 *user.SignedInUser, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) {
func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 identity.Requester, 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)
+35 -32
View File
@@ -32,6 +32,7 @@ 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"
@@ -299,10 +300,11 @@ 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: fmt.Sprintf("%d", user.UserID),
UserID: userID,
}
newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred)
newCtx = livecontext.SetContextSignedUser(newCtx, user)
@@ -593,7 +595,7 @@ func (g *GrafanaLive) handleOnSubscribe(ctx context.Context, client *centrifuge.
return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
}
if user.OrgID != orgID {
if user.GetOrgID() != orgID {
logger.Info("Error subscribing: wrong orgId", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
return centrifuge.SubscribeReply{}, centrifuge.ErrorPermissionDenied
}
@@ -603,7 +605,7 @@ func (g *GrafanaLive) handleOnSubscribe(ctx context.Context, client *centrifuge.
var ruleFound bool
if g.Pipeline != nil {
rule, ok, err := g.Pipeline.Get(user.OrgID, channel)
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), 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
@@ -694,13 +696,13 @@ func (g *GrafanaLive) handleOnPublish(ctx context.Context, client *centrifuge.Cl
return centrifuge.PublishReply{}, centrifuge.ErrorInternal
}
if user.OrgID != orgID {
if user.GetOrgID() != 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.OrgID, channel)
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), 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
@@ -724,7 +726,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.OrgID, channel, e.Data)
_, err := g.Pipeline.ProcessInput(client.Context(), user.GetOrgID(), 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
@@ -805,7 +807,7 @@ func publishStatusToHTTPError(status backend.PublishStreamStatus) (int, string)
}
// GetChannelHandler gives thread-safe access to the channel.
func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user *user.SignedInUser, channel string) (model.ChannelHandler, live.Channel, error) {
func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user identity.Requester, channel string) (model.ChannelHandler, live.Channel, error) {
// Parse the identifier ${scope}/${namespace}/${path}
addr, err := live.ParseChannel(channel)
if err != nil {
@@ -846,7 +848,7 @@ func (g *GrafanaLive) GetChannelHandler(ctx context.Context, user *user.SignedIn
// GetChannelHandlerFactory gets a ChannelHandlerFactory for a namespace.
// It gives thread-safe access to the channel.
func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user *user.SignedInUser, scope string, namespace string) (model.ChannelHandlerFactory, error) {
func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user identity.Requester, scope string, namespace string) (model.ChannelHandlerFactory, error) {
switch scope {
case live.ScopeGrafana:
return g.handleGrafanaScope(user, namespace)
@@ -861,14 +863,14 @@ func (g *GrafanaLive) GetChannelHandlerFactory(ctx context.Context, user *user.S
}
}
func (g *GrafanaLive) handleGrafanaScope(_ *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
func (g *GrafanaLive) handleGrafanaScope(_ identity.Requester, 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, _ *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
func (g *GrafanaLive) handlePluginScope(ctx context.Context, _ identity.Requester, 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)
@@ -882,11 +884,11 @@ func (g *GrafanaLive) handlePluginScope(ctx context.Context, _ *user.SignedInUse
), nil
}
func (g *GrafanaLive) handleStreamScope(u *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
return g.ManagedStreamRunner.GetOrCreateStream(u.OrgID, live.ScopeStream, namespace)
func (g *GrafanaLive) handleStreamScope(u identity.Requester, namespace string) (model.ChannelHandlerFactory, error) {
return g.ManagedStreamRunner.GetOrCreateStream(u.GetOrgID(), live.ScopeStream, namespace)
}
func (g *GrafanaLive) handleDatasourceScope(ctx context.Context, user *user.SignedInUser, namespace string) (model.ChannelHandlerFactory, error) {
func (g *GrafanaLive) handleDatasourceScope(ctx context.Context, user identity.Requester, 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)
@@ -929,12 +931,13 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
return response.Error(http.StatusBadRequest, "invalid channel ID", nil)
}
logger.Debug("Publish API cmd", "user", ctx.SignedInUser.UserID, "channel", cmd.Channel)
namespaceID, userID := ctx.SignedInUser.GetNamespacedID()
logger.Debug("Publish API cmd", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel)
user := ctx.SignedInUser
channel := cmd.Channel
if g.Pipeline != nil {
rule, ok, err := g.Pipeline.Get(user.OrgID, channel)
rule, ok, err := g.Pipeline.Get(user.GetOrgID(), 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)
@@ -954,7 +957,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.OrgID, channel, cmd.Data)
_, err := g.Pipeline.ProcessInput(ctx.Req.Context(), user.GetOrgID(), 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)
@@ -980,13 +983,13 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
return response.Error(code, text, nil)
}
if reply.Data != nil {
err = g.Publish(ctx.OrgID, cmd.Channel, cmd.Data)
err = g.Publish(ctx.SignedInUser.GetOrgID(), 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", "user", ctx.SignedInUser.UserID, "channel", cmd.Channel)
logger.Debug("Publication successful", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel)
return response.JSON(http.StatusOK, dtos.LivePublishResponse{})
}
@@ -999,9 +1002,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.OrgID)
channels, err = g.surveyCaller.CallManagedStreams(c.SignedInUser.GetOrgID())
} else {
channels, err = g.ManagedStreamRunner.GetManagedChannels(c.SignedInUser.OrgID)
channels, err = g.ManagedStreamRunner.GetManagedChannels(c.SignedInUser.GetOrgID())
}
if err != nil {
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err)
@@ -1017,7 +1020,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.OrgID),
"active": g.GrafanaScope.Dashboards.HasGitOpsObserver(ctx.SignedInUser.GetOrgID()),
})
}
return response.JSONStreaming(404, util.DynMap{
@@ -1027,7 +1030,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.OrgID)
result, err := g.pipelineStorage.ListChannelRules(c.Req.Context(), c.SignedInUser.GetOrgID())
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to get channel rules", err)
}
@@ -1112,7 +1115,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.OrgID, req.Channel)
rule, ok, err := channelRuleGetter.Get(c.SignedInUser.GetOrgID(), req.Channel)
if err != nil {
return response.Error(http.StatusInternalServerError, "Error getting channel rule", err)
}
@@ -1122,7 +1125,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.OrgID, req.Channel, []byte(req.Data))
channelFrames, err := pipe.DataToChannelFrames(c.Req.Context(), *rule, c.SignedInUser.GetOrgID(), req.Channel, []byte(req.Data))
if err != nil {
return response.Error(http.StatusInternalServerError, "Error converting data", err)
}
@@ -1142,7 +1145,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.OrgID, cmd)
rule, err := g.pipelineStorage.CreateChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to create channel rule", err)
}
@@ -1165,7 +1168,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.OrgID, cmd)
rule, err := g.pipelineStorage.UpdateChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update channel rule", err)
}
@@ -1188,7 +1191,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.OrgID, cmd)
err = g.pipelineStorage.DeleteChannelRule(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to delete channel rule", err)
}
@@ -1208,7 +1211,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.OrgID)
backends, err := g.pipelineStorage.ListWriteConfigs(c.Req.Context(), c.SignedInUser.GetOrgID())
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to get write configs", err)
}
@@ -1232,7 +1235,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.OrgID, cmd)
result, err := g.pipelineStorage.CreateWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to create write config", err)
}
@@ -1255,7 +1258,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.OrgID, pipeline.WriteConfigGetCmd{
existingBackend, ok, err := g.pipelineStorage.GetWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), pipeline.WriteConfigGetCmd{
UID: cmd.UID,
})
if err != nil {
@@ -1276,7 +1279,7 @@ func (g *GrafanaLive) HandleWriteConfigsPutHTTP(c *contextmodel.ReqContext) resp
}
}
}
result, err := g.pipelineStorage.UpdateWriteConfig(c.Req.Context(), c.OrgID, cmd)
result, err := g.pipelineStorage.UpdateWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update write config", err)
}
@@ -1299,7 +1302,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.OrgID, cmd)
err = g.pipelineStorage.DeleteWriteConfig(c.Req.Context(), c.SignedInUser.GetOrgID(), cmd)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to delete write config", err)
}
+4 -4
View File
@@ -3,21 +3,21 @@ package livecontext
import (
"context"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/auth/identity"
)
type signedUserContextKeyType int
var signedUserContextKey signedUserContextKeyType
func SetContextSignedUser(ctx context.Context, user *user.SignedInUser) context.Context {
func SetContextSignedUser(ctx context.Context, user identity.Requester) context.Context {
ctx = context.WithValue(ctx, signedUserContextKey, user)
return ctx
}
func GetContextSignedUser(ctx context.Context) (*user.SignedInUser, bool) {
func GetContextSignedUser(ctx context.Context) (identity.Requester, bool) {
if val := ctx.Value(signedUserContextKey); val != nil {
user, ok := val.(*user.SignedInUser)
user, ok := val.(identity.Requester)
return user, ok
}
return nil, false
+3 -3
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 *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error) {
func (g *ContextGetter) GetPluginContext(ctx context.Context, user identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error) {
if datasourceUID == "" {
return g.pluginContextProvider.Get(ctx, pluginID, user, user.OrgID)
return g.pluginContextProvider.Get(ctx, pluginID, user, user.GetOrgID())
}
ds, err := g.dataSourceCache.GetDatasourceByUID(ctx, datasourceUID, user, skipCache)
+4 -4
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 *user.SignedInUser, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
func (s *NamespaceStream) OnSubscribe(ctx context.Context, u identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
reply := model.SubscribeReply{}
frameJSON, ok, err := s.frameCache.GetFrame(ctx, u.OrgID, e.Channel)
frameJSON, ok, err := s.frameCache.GetFrame(ctx, u.GetOrgID(), e.Channel)
if err != nil {
return reply, 0, err
}
@@ -251,6 +251,6 @@ func (s *NamespaceStream) OnSubscribe(ctx context.Context, u *user.SignedInUser,
return reply, backend.SubscribeStreamStatusOK, nil
}
func (s *NamespaceStream) OnPublish(_ context.Context, _ *user.SignedInUser, _ model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
func (s *NamespaceStream) OnPublish(_ context.Context, _ identity.Requester, _ model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
return model.PublishReply{}, backend.PublishStreamStatusPermissionDenied, nil
}
+3 -3
View File
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/auth/identity"
)
// 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 *user.SignedInUser, e SubscribeEvent) (SubscribeReply, backend.SubscribeStreamStatus, error)
OnSubscribe(ctx context.Context, user identity.Requester, e SubscribeEvent) (SubscribeReply, backend.SubscribeStreamStatus, error)
// OnPublish is called when a client writes a message to the channel websocket.
OnPublish(ctx context.Context, user *user.SignedInUser, e PublishEvent) (PublishReply, backend.PublishStreamStatus, error)
OnPublish(ctx context.Context, user identity.Requester, e PublishEvent) (PublishReply, backend.PublishStreamStatus, error)
}
// ChannelHandlerFactory should be implemented by all core features.
+3 -3
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 *user.SignedInUser) (bool, error) {
func (s *RoleCheckAuthorizer) CanSubscribe(_ context.Context, u identity.Requester) (bool, error) {
return u.HasRole(s.role), nil
}
func (s *RoleCheckAuthorizer) CanPublish(_ context.Context, u *user.SignedInUser) (bool, error) {
func (s *RoleCheckAuthorizer) CanPublish(_ context.Context, u identity.Requester) (bool, error) {
return u.HasRole(s.role), nil
}
+3 -3
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 *user.SignedInUser) (bool, error)
CanPublish(ctx context.Context, u identity.Requester) (bool, error)
}
// SubscribeAuthChecker checks whether current user can subscribe to a channel.
type SubscribeAuthChecker interface {
CanSubscribe(ctx context.Context, u *user.SignedInUser) (bool, error)
CanSubscribe(ctx context.Context, u identity.Requester) (bool, error)
}
// LiveChannelRule is an in-memory representation of each specific rule to be executed by Pipeline.
@@ -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 *user.SignedInUser, channel string) (model.ChannelHandler, live.Channel, error)
GetChannelHandler(ctx context.Context, user identity.Requester, channel string) (model.ChannelHandler, live.Channel, error)
}
const SubscriberTypeBuiltin = "builtin"
+1 -1
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.OrgID, channelID, body)
ruleFound, err := s.pipeline.ProcessInput(r.Context(), user.GetOrgID(), channelID, body)
if err != nil {
logger.Error("Pipeline input processing error", "error", err, "body", string(body))
return
+1 -1
View File
@@ -67,7 +67,7 @@ func (s *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
break
}
stream, err := s.managedStreamRunner.GetOrCreateStream(user.OrgID, liveDto.ScopeStream, streamID)
stream, err := s.managedStreamRunner.GetOrCreateStream(user.GetOrgID(), liveDto.ScopeStream, streamID)
if err != nil {
logger.Error("Error getting stream", "error", err)
continue
+4 -4
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 *user.SignedInUser, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, error)
GetPluginContext(ctx context.Context, user identity.Requester, 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 *user.SignedInUser
user identity.Requester
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 *user.SignedInUser, channel string, path string, data []byte, pCtx backend.PluginContext, streamRunner StreamRunner, isResubmit bool) (*submitResult, error) {
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) {
if isResubmit {
// Resolve new plugin context as it could be modified since last call.
var datasourceUID string
+25 -15
View File
@@ -10,6 +10,7 @@ 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"
)
@@ -71,9 +72,11 @@ 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 *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)
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())
require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil
@@ -133,7 +136,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 *user.SignedInUser, 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 identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
return backend.PluginContext{}, true, nil
}).Times(0)
@@ -205,7 +208,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 *user.SignedInUser, 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 identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
return backend.PluginContext{}, true, nil
}).Times(0)
@@ -254,9 +257,11 @@ 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 *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)
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())
require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil
@@ -296,7 +301,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 *user.SignedInUser, 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 identity.Requester, pluginID string, datasourceUID string, skipCache bool) (backend.PluginContext, bool, error) {
return backend.PluginContext{}, true, nil
}).Times(0)
@@ -337,9 +342,12 @@ 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 *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)
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())
require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil
@@ -403,9 +411,11 @@ 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 *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)
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())
require.Equal(t, testPluginContext.PluginID, pluginID)
require.Equal(t, testPluginContext.DataSourceInstanceSettings.UID, datasourceUID)
return testPluginContext, true, nil
+2 -2
View File
@@ -10,7 +10,7 @@ import (
gomock "github.com/golang/mock/gomock"
backend "github.com/grafana/grafana-plugin-sdk-go/backend"
user "github.com/grafana/grafana/pkg/services/user"
identity "github.com/grafana/grafana/pkg/services/auth/identity"
)
// 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 *user.SignedInUser, arg2, arg3 string, arg4 bool) (backend.PluginContext, error) {
func (m *MockPluginContextGetter) GetPluginContext(arg0 context.Context, arg1 identity.Requester, 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)