From 8919cafcb40ff53ea29a5e9a5b35660104616f46 Mon Sep 17 00:00:00 2001 From: Jo Date: Mon, 9 Oct 2023 16:07:28 +0200 Subject: [PATCH] Identity: Unfurl UserID and Email in pkg/api to user identity.Requester (#76112) * Unfurl OrgRole in pkg/api to allow using identity.Requester interface * Unfurl Email in pkg/api to allow using identity.Requester interface * Update UserID in pkg/api to allow using identity.Requester interface * fix authed test * fix datasource tests * guard login * fix preferences anon testing * fix anonymous index rendering * do not error with user id 0 --- pkg/api/annotations.go | 31 ++++++++++++++++++++---- pkg/api/annotations_test.go | 2 +- pkg/api/dashboard_snapshot.go | 9 ++++++- pkg/api/datasources.go | 9 ++++++- pkg/api/datasources_test.go | 9 ++++++- pkg/api/index.go | 14 ++++++----- pkg/api/login.go | 23 ++++++++++++++---- pkg/api/preferences.go | 32 +++++++++++++++++++++---- pkg/api/preferences_test.go | 5 ++++ pkg/api/render.go | 10 ++++++-- pkg/api/signup.go | 8 ++++++- pkg/services/auth/identity/requester.go | 18 ++++++++++++++ 12 files changed, 145 insertions(+), 25 deletions(-) diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 7f1e849c479..4247f15a48a 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "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/guardian" @@ -132,9 +133,14 @@ func (hs *HTTPServer) PostAnnotation(c *contextmodel.ReqContext) response.Respon return response.Error(400, "Failed to save annotation", err) } + userID, err := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if err != nil { + return response.Error(http.StatusInternalServerError, "Failed to save annotation", err) + } + item := annotations.Item{ OrgID: c.SignedInUser.GetOrgID(), - UserID: c.UserID, + UserID: userID, DashboardID: cmd.DashboardId, PanelID: cmd.PanelId, Epoch: cmd.Time, @@ -214,9 +220,14 @@ func (hs *HTTPServer) PostGraphiteAnnotation(c *contextmodel.ReqContext) respons return response.Error(400, "Failed to save Graphite annotation", err) } + userID, err := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if err != nil { + return response.Error(http.StatusInternalServerError, "Failed to save Graphite annotation", err) + } + item := annotations.Item{ OrgID: c.SignedInUser.GetOrgID(), - UserID: c.UserID, + UserID: userID, Epoch: cmd.When * 1000, Text: text, Tags: tagsArray, @@ -264,9 +275,15 @@ func (hs *HTTPServer) UpdateAnnotation(c *contextmodel.ReqContext) response.Resp return dashboardGuardianResponse(err) } + userID, err := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if err != nil { + return response.Error(http.StatusInternalServerError, + "Failed to update annotation", err) + } + item := annotations.Item{ OrgID: c.SignedInUser.GetOrgID(), - UserID: c.UserID, + UserID: userID, ID: annotationID, Epoch: cmd.Time, EpochEnd: cmd.TimeEnd, @@ -319,9 +336,15 @@ func (hs *HTTPServer) PatchAnnotation(c *contextmodel.ReqContext) response.Respo return dashboardGuardianResponse(err) } + userID, err := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if err != nil { + return response.Error(http.StatusInternalServerError, + "Failed to update annotation", err) + } + existing := annotations.Item{ OrgID: c.SignedInUser.GetOrgID(), - UserID: c.UserID, + UserID: userID, ID: annotationID, Epoch: annotation.Time, EpochEnd: annotation.TimeEnd, diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index b8836ac22d6..b930f2333be 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -238,7 +238,7 @@ func TestAPI_Annotations(t *testing.T) { body = strings.NewReader(tt.body) } - req := webtest.RequestWithSignedInUser(server.NewRequest(tt.method, tt.path, body), userWithPermissions(1, tt.permissions)) + req := webtest.RequestWithSignedInUser(server.NewRequest(tt.method, tt.path, body), authedUserWithPermissions(1, 1, tt.permissions)) res, err := server.SendJSON(req) require.NoError(t, err) assert.Equal(t, tt.expectedCode, res.StatusCode) diff --git a/pkg/api/dashboard_snapshot.go b/pkg/api/dashboard_snapshot.go index 4758d62a9af..2b0c5e5471b 100644 --- a/pkg/api/dashboard_snapshot.go +++ b/pkg/api/dashboard_snapshot.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/metrics" + "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/dashboardsnapshots" @@ -119,10 +120,16 @@ func (hs *HTTPServer) CreateDashboardSnapshot(c *contextmodel.ReqContext) respon cmd.Name = "Unnamed snapshot" } + userID, err := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if err != nil { + return response.Error(http.StatusInternalServerError, + "Failed to create external snapshot", err) + } + var snapshotUrl string cmd.ExternalURL = "" cmd.OrgID = c.SignedInUser.GetOrgID() - cmd.UserID = c.UserID + cmd.UserID = userID originalDashboardURL, err := createOriginalDashboardURL(&cmd) if err != nil { return response.Error(http.StatusInternalServerError, "Invalid app URL", err) diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index e3c54145961..c6ebed9cf84 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/components/simplejson" "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/datasources" "github.com/grafana/grafana/pkg/setting" @@ -372,9 +373,15 @@ func (hs *HTTPServer) AddDataSource(c *contextmodel.ReqContext) response.Respons return response.Error(http.StatusBadRequest, "bad request data", err) } + userID, err := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if err != nil { + return response.Error(http.StatusInternalServerError, + "Failed to add datasource", err) + } + datasourcesLogger.Debug("Received command to add data source", "url", cmd.URL) cmd.OrgID = c.SignedInUser.GetOrgID() - cmd.UserID = c.UserID + cmd.UserID = userID if cmd.URL != "" { if resp := validateURL(cmd.Type, cmd.URL); resp != nil { return resp diff --git a/pkg/api/datasources_test.go b/pkg/api/datasources_test.go index f7fec1d0381..767c3fd2863 100644 --- a/pkg/api/datasources_test.go +++ b/pkg/api/datasources_test.go @@ -94,6 +94,7 @@ func TestAddDataSource_InvalidURL(t *testing.T) { Access: "direct", Type: "test", }) + c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{}) return hs.AddDataSource(c) })) @@ -125,6 +126,7 @@ func TestAddDataSource_URLWithoutProtocol(t *testing.T) { Access: "direct", Type: "test", }) + c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{}) return hs.AddDataSource(c) })) @@ -156,6 +158,7 @@ func TestAddDataSource_InvalidJSONData(t *testing.T) { Type: "test", JsonData: jsonData, }) + c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{}) return hs.AddDataSource(c) })) @@ -179,6 +182,7 @@ func TestUpdateDataSource_InvalidURL(t *testing.T) { Access: "direct", Type: "test", }) + c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{}) return hs.AddDataSource(c) })) @@ -208,6 +212,7 @@ func TestUpdateDataSource_InvalidJSONData(t *testing.T) { Type: "test", JsonData: jsonData, }) + c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{}) return hs.AddDataSource(c) })) @@ -239,6 +244,8 @@ func TestUpdateDataSource_URLWithoutProtocol(t *testing.T) { Access: "direct", Type: "test", }) + c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{}) + return hs.AddDataSource(c) })) @@ -375,7 +382,7 @@ func TestAPI_datasources_AccessControl(t *testing.T) { body = strings.NewReader(tt.body) } - res, err := server.SendJSON(webtest.RequestWithSignedInUser(server.NewRequest(tt.method, url, body), userWithPermissions(1, tt.permission))) + res, err := server.SendJSON(webtest.RequestWithSignedInUser(server.NewRequest(tt.method, url, body), authedUserWithPermissions(1, 1, tt.permission))) require.NoError(t, err) assert.Equal(t, tt.expectedCode, res.StatusCode) require.NoError(t, res.Body.Close()) diff --git a/pkg/api/index.go b/pkg/api/index.go index 5c375da5f73..966f6af846d 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -30,7 +30,9 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV return nil, err } - prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: c.UserID, OrgID: c.SignedInUser.GetOrgID(), Teams: c.Teams} + userID, _ := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + + prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: userID, OrgID: c.SignedInUser.GetOrgID(), Teams: c.Teams} prefs, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery) if err != nil { return nil, err @@ -81,7 +83,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV theme := hs.getThemeForIndexData(prefs.Theme, c.Query("theme")) userOrgCount := 1 - userOrgs, err := hs.orgService.GetUserOrgList(c.Req.Context(), &org.GetUserOrgListQuery{UserID: c.UserID}) + userOrgs, err := hs.orgService.GetUserOrgList(c.Req.Context(), &org.GetUserOrgListQuery{UserID: userID}) if err != nil { hs.log.Error("Failed to count user orgs", "error", err) } @@ -95,16 +97,16 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV data := dtos.IndexViewData{ User: &dtos.CurrentUser{ - Id: c.UserID, + Id: userID, IsSignedIn: c.IsSignedIn, Login: c.Login, - Email: c.Email, + Email: c.SignedInUser.GetEmail(), Name: c.Name, OrgId: c.SignedInUser.GetOrgID(), OrgName: c.OrgName, - OrgRole: c.OrgRole, + OrgRole: c.SignedInUser.GetOrgRole(), OrgCount: userOrgCount, - GravatarUrl: dtos.GetGravatarUrl(c.Email), + GravatarUrl: dtos.GetGravatarUrl(c.SignedInUser.GetEmail()), IsGrafanaAdmin: c.IsGrafanaAdmin, Theme: theme.ID, LightTheme: theme.Type == "light", diff --git a/pkg/api/login.go b/pkg/api/login.go index 97fd366be43..81728e3f9b6 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/infra/network" "github.com/grafana/grafana/pkg/middleware/cookies" "github.com/grafana/grafana/pkg/services/auth" + "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/authn" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/featuremgmt" @@ -240,9 +241,14 @@ func (hs *HTTPServer) loginUserWithUser(user *user.User, c *contextmodel.ReqCont } func (hs *HTTPServer) Logout(c *contextmodel.ReqContext) { + userID, errID := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if errID != nil { + hs.log.Error("failed to retrieve user ID", "error", errID) + } + // If SAML is enabled and this is a SAML user use saml logout if hs.samlSingleLogoutEnabled() { - getAuthQuery := loginservice.GetAuthInfoQuery{UserId: c.UserID} + getAuthQuery := loginservice.GetAuthInfoQuery{UserId: userID} if authInfo, err := hs.authInfoService.GetAuthInfo(c.Req.Context(), &getAuthQuery); err == nil { if authInfo.AuthModule == loginservice.SAMLAuthModule { c.Redirect(hs.Cfg.AppSubURL + "/logout/saml") @@ -266,7 +272,7 @@ func (hs *HTTPServer) Logout(c *contextmodel.ReqContext) { } if err := hs.oauthTokenService.InvalidateOAuthTokens(c.Req.Context(), entry); err != nil { - hs.log.Warn("failed to invalidate oauth tokens for user", "userId", c.UserID, "error", err) + hs.log.Warn("failed to invalidate oauth tokens for user", "userId", userID, "error", err) } } @@ -284,7 +290,7 @@ func (hs *HTTPServer) Logout(c *contextmodel.ReqContext) { } c.Redirect(rdUrl) } else { - hs.log.Info("Successful Logout", "User", c.Email) + hs.log.Info("Successful Logout", "User", c.SignedInUser.GetEmail()) c.Redirect(hs.Cfg.AppSubURL + "/login") } } @@ -329,7 +335,16 @@ func (hs *HTTPServer) RedirectResponseWithError(c *contextmodel.ReqContext, err func (hs *HTTPServer) redirectURLWithErrorCookie(c *contextmodel.ReqContext, err error) string { setCookie := true if hs.Features.IsEnabled(featuremgmt.FlagIndividualCookiePreferences) { - prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: c.UserID, OrgID: c.SignedInUser.GetOrgID(), Teams: c.Teams} + var userID int64 + if c.SignedInUser != nil && !c.SignedInUser.IsNil() { + var errID error + userID, errID = identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if errID != nil { + hs.log.Error("failed to retrieve user ID", "error", errID) + } + } + + prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: userID, OrgID: c.SignedInUser.GetOrgID(), Teams: c.Teams} prefs, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery) if err != nil { c.Redirect(hs.Cfg.AppSubURL + "/login") diff --git a/pkg/api/preferences.go b/pkg/api/preferences.go index 314ed9ef234..e6c71d8b775 100644 --- a/pkg/api/preferences.go +++ b/pkg/api/preferences.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/kinds/preferences" + "github.com/grafana/grafana/pkg/services/auth/identity" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/dashboards" pref "github.com/grafana/grafana/pkg/services/preference" @@ -19,7 +20,13 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp if err := web.Bind(c.Req, &cmd); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - cmd.UserID = c.UserID + + userID, errID := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if errID != nil { + return response.Error(http.StatusInternalServerError, "Failed to set home dashboard", errID) + } + + cmd.UserID = userID cmd.OrgID = c.SignedInUser.GetOrgID() // the default value of HomeDashboardID is taken from input, when HomeDashboardID is set also, @@ -56,7 +63,12 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp // 401: unauthorisedError // 500: internalServerError func (hs *HTTPServer) GetUserPreferences(c *contextmodel.ReqContext) response.Response { - return hs.getPreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), c.UserID, 0) + userID, errID := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if errID != nil { + return response.Error(http.StatusInternalServerError, "Failed to get user preferences", errID) + } + + return hs.getPreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), userID, 0) } func (hs *HTTPServer) getPreferencesFor(ctx context.Context, orgID, userID, teamID int64) response.Response { @@ -124,7 +136,13 @@ func (hs *HTTPServer) UpdateUserPreferences(c *contextmodel.ReqContext) response if err := web.Bind(c.Req, &dtoCmd); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return hs.updatePreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), c.UserID, 0, &dtoCmd) + + userID, errID := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if errID != nil { + return response.Error(http.StatusInternalServerError, "Failed to update user preferences", errID) + } + + return hs.updatePreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), userID, 0, &dtoCmd) } func (hs *HTTPServer) updatePreferencesFor(ctx context.Context, orgID, userID, teamId int64, dtoCmd *dtos.UpdatePrefsCmd) response.Response { @@ -182,7 +200,13 @@ func (hs *HTTPServer) PatchUserPreferences(c *contextmodel.ReqContext) response. if err := web.Bind(c.Req, &dtoCmd); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return hs.patchPreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), c.UserID, 0, &dtoCmd) + + userID, errID := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if errID != nil { + return response.Error(http.StatusInternalServerError, "Failed to update user preferences", errID) + } + + return hs.patchPreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), userID, 0, &dtoCmd) } func (hs *HTTPServer) patchPreferencesFor(ctx context.Context, orgID, userID, teamId int64, dtoCmd *dtos.PatchPrefsCmd) response.Response { diff --git a/pkg/api/preferences_test.go b/pkg/api/preferences_test.go index ffc706a3b07..3ed1950f3eb 100644 --- a/pkg/api/preferences_test.go +++ b/pkg/api/preferences_test.go @@ -129,6 +129,7 @@ func TestAPIEndpoint_PatchUserPreferences(t *testing.T) { input := strings.NewReader(testPatchUserPreferencesCmd) t.Run("Returns 200 on success", func(t *testing.T) { req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPatch, patchUserPreferencesUrl, input), &user.SignedInUser{ + UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, }) @@ -141,6 +142,7 @@ func TestAPIEndpoint_PatchUserPreferences(t *testing.T) { input = strings.NewReader(testPatchUserPreferencesCmdBad) t.Run("Returns 400 with bad data", func(t *testing.T) { req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPatch, patchUserPreferencesUrl, input), &user.SignedInUser{ + UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, }) @@ -153,6 +155,7 @@ func TestAPIEndpoint_PatchUserPreferences(t *testing.T) { input = strings.NewReader(testUpdateOrgPreferencesWithHomeDashboardUIDCmd) t.Run("Returns 200 on success", func(t *testing.T) { req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPatch, patchUserPreferencesUrl, input), &user.SignedInUser{ + UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, }) @@ -174,6 +177,7 @@ func TestAPIEndpoint_PatchOrgPreferences(t *testing.T) { input := strings.NewReader(testPatchOrgPreferencesCmd) t.Run("Returns 200 on success", func(t *testing.T) { req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPatch, patchOrgPreferencesUrl, input), &user.SignedInUser{ + UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgsPreferencesWrite: {}}}, @@ -187,6 +191,7 @@ func TestAPIEndpoint_PatchOrgPreferences(t *testing.T) { input = strings.NewReader(testPatchOrgPreferencesCmdBad) t.Run("Returns 400 with bad data", func(t *testing.T) { req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPatch, patchOrgPreferencesUrl, input), &user.SignedInUser{ + UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgsPreferencesWrite: {}}}, diff --git a/pkg/api/render.go b/pkg/api/render.go index d49c2369ce2..eb895d3bfa6 100644 --- a/pkg/api/render.go +++ b/pkg/api/render.go @@ -8,6 +8,7 @@ import ( "time" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/auth/identity" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/util" @@ -53,14 +54,19 @@ func (hs *HTTPServer) RenderToPng(c *contextmodel.ReqContext) { headers["Accept-Language"] = acceptLanguageHeader } + userID, errID := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if errID != nil { + hs.log.Error("Failed to parse user id", "err", errID) + } + result, err := hs.RenderService.Render(c.Req.Context(), rendering.Opts{ TimeoutOpts: rendering.TimeoutOpts{ Timeout: time.Duration(timeout) * time.Second, }, AuthOpts: rendering.AuthOpts{ OrgID: c.SignedInUser.GetOrgID(), - UserID: c.UserID, - OrgRole: c.OrgRole, + UserID: userID, + OrgRole: c.SignedInUser.GetOrgRole(), }, Width: width, Height: height, diff --git a/pkg/api/signup.go b/pkg/api/signup.go index 49600a0dc94..0f9310d35f6 100644 --- a/pkg/api/signup.go +++ b/pkg/api/signup.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/events" "github.com/grafana/grafana/pkg/infra/metrics" + "github.com/grafana/grafana/pkg/services/auth/identity" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" tempuser "github.com/grafana/grafana/pkg/services/temp_user" "github.com/grafana/grafana/pkg/services/user" @@ -48,11 +49,16 @@ func (hs *HTTPServer) SignUp(c *contextmodel.ReqContext) response.Response { return response.Error(422, "User with same email address already exists", nil) } + userID, errID := identity.UserIdentifier(c.SignedInUser.GetNamespacedID()) + if errID != nil { + hs.log.Error("Failed to parse user id", "err", errID) + } + cmd := tempuser.CreateTempUserCommand{} cmd.OrgID = -1 cmd.Email = form.Email cmd.Status = tempuser.TmpUserSignUpStarted - cmd.InvitedByUserID = c.UserID + cmd.InvitedByUserID = userID cmd.Code, err = util.GetRandomString(20) if err != nil { return response.Error(500, "Failed to generate random string", err) diff --git a/pkg/services/auth/identity/requester.go b/pkg/services/auth/identity/requester.go index bcf67b17ed9..1eb72bb5a90 100644 --- a/pkg/services/auth/identity/requester.go +++ b/pkg/services/auth/identity/requester.go @@ -87,3 +87,21 @@ func IntIdentifier(namespace, identifier string) (int64, error) { return 0, ErrNotIntIdentifier } + +// UserIdentifier converts a string identifier to an int64. +// Errors if the identifier is not initialized or if namespace is not recognized. +// Returns 0 if the namespace is not user or service account +func UserIdentifier(namespace, identifier string) (int64, error) { + userID, err := IntIdentifier(namespace, identifier) + if err != nil { + // FIXME: return this error once entity namespaces are handled by stores + return 0, nil + } + + switch namespace { + case NamespaceUser, NamespaceServiceAccount: + return userID, nil + } + + return 0, nil +}