diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 63f5230fdb6..c383d5c0e0a 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -43,13 +43,11 @@ func (hs *HTTPServer) isDashboardStarredByUser(c *contextmodel.ReqContext, dashI return false, nil } - namespaceID, userIDstr := c.SignedInUser.GetTypedID() - - if namespaceID != identity.TypeUser { + if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { return false, nil } - userID, err := identity.IntIdentifier(namespaceID, userIDstr) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { return false, err } @@ -439,16 +437,13 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo return response.Error(http.StatusBadRequest, "Use folders endpoint for deleting folders.", nil) } - namespaceID, userIDStr := c.SignedInUser.GetTypedID() - // 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, + "identity", c.GetID(), "error", err) } @@ -515,15 +510,9 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S ctx := c.Req.Context() var err error - userID := int64(0) - namespaceID, userIDstr := c.SignedInUser.GetTypedID() - if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { - hs.log.Debug("User does not belong to a user or service account namespace", "namespaceID", namespaceID, "userID", userIDstr) - } else { - userID, err = identity.IntIdentifier(namespaceID, userIDstr) - if err != nil { - hs.log.Debug("Error while parsing user ID", "namespaceID", namespaceID, "userID", userIDstr) - } + var userID int64 + if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil { + userID = id } cmd.OrgID = c.SignedInUser.GetOrgID() @@ -632,16 +621,9 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S // 401: unauthorisedError // 500: internalServerError func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response { - userID := int64(0) - var err error - namespaceID, userIDstr := c.SignedInUser.GetTypedID() - if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { - hs.log.Debug("User does not belong to a user or service account namespace", "namespaceID", namespaceID, "userID", userIDstr) - } else { - userID, err = identity.IntIdentifier(namespaceID, userIDstr) - if err != nil { - hs.log.Debug("Error while parsing user ID", "namespaceID", namespaceID, "userID", userIDstr) - } + var userID int64 + if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil { + userID = id } prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.SignedInUser.GetOrgID(), UserID: userID, Teams: c.SignedInUser.GetTeams()} @@ -1085,15 +1067,9 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon return response.Error(http.StatusNotFound, "Dashboard version not found", nil) } - userID := int64(0) - namespaceID, userIDstr := c.SignedInUser.GetTypedID() - if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { - hs.log.Warn("User does not belong to a user or service account namespace", "namespaceID", namespaceID, "userID", userIDstr) - } else { - userID, err = identity.IntIdentifier(namespaceID, userIDstr) - if err != nil { - hs.log.Warn("Error while parsing user ID", "namespaceID", namespaceID, "userID", userIDstr) - } + var userID int64 + if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil { + userID = id } saveCmd := dashboards.SaveDashboardCommand{} diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index bc58368ab76..bb79dd6aee7 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -442,11 +442,7 @@ func (hs *HTTPServer) AddDataSource(c *contextmodel.ReqContext) response.Respons return response.Error(http.StatusBadRequest, "bad request data", err) } - userID, err := identity.UserIdentifier(c.SignedInUser.GetTypedID()) - if err != nil { - return response.Error(http.StatusInternalServerError, - "Failed to add datasource", err) - } + userID, _ := identity.UserIdentifier(c.SignedInUser.GetID()) datasourcesLogger.Debug("Received command to add data source", "url", cmd.URL) cmd.OrgID = c.SignedInUser.GetOrgID() diff --git a/pkg/api/folder.go b/pkg/api/folder.go index 13882e22594..1046ad7ed85 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -191,15 +191,13 @@ func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int if !hs.Cfg.RBAC.PermissionsOnCreation("folder") { return nil } - var permissions []accesscontrol.SetResourcePermissionCommand - var userID int64 - namespace, id := user.GetTypedID() - if namespace == identity.TypeUser { - var errID error - userID, errID = identity.IntIdentifier(namespace, id) - if errID != nil { - return errID + var permissions []accesscontrol.SetResourcePermissionCommand + + if identity.IsIdentityType(user.GetID(), identity.TypeUser) { + userID, err := identity.UserIdentifier(user.GetID()) + if err != nil { + return err } permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ diff --git a/pkg/api/index.go b/pkg/api/index.go index e09c0adcaf6..14a64f76a09 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -31,7 +31,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV return nil, err } - userID, _ := identity.UserIdentifier(c.SignedInUser.GetTypedID()) + userID, _ := identity.UserIdentifier(c.SignedInUser.GetID()) prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: userID, OrgID: c.SignedInUser.GetOrgID(), Teams: c.Teams} prefs, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery) @@ -169,10 +169,8 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV } func (hs *HTTPServer) buildUserAnalyticsSettings(c *contextmodel.ReqContext) dtos.AnalyticsSettings { - namespace, _ := c.SignedInUser.GetTypedID() - // Anonymous users do not have an email or auth info - if namespace != identity.TypeUser { + if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { return dtos.AnalyticsSettings{Identifier: "@" + hs.Cfg.AppURL} } diff --git a/pkg/api/login.go b/pkg/api/login.go index f670290f3b3..d28ccfb8377 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -257,8 +257,7 @@ func (hs *HTTPServer) Logout(c *contextmodel.ReqContext) { return } - _, id := c.SignedInUser.GetTypedID() - hs.log.Info("Successful Logout", "userID", id) + hs.log.Info("Successful Logout", "id", c.SignedInUser.GetID()) c.Redirect(redirect.URL) } @@ -305,7 +304,7 @@ func (hs *HTTPServer) redirectURLWithErrorCookie(c *contextmodel.ReqContext, err var userID int64 if c.SignedInUser != nil && !c.SignedInUser.IsNil() { var errID error - userID, errID = identity.UserIdentifier(c.SignedInUser.GetTypedID()) + userID, errID = identity.UserIdentifier(c.SignedInUser.GetID()) if errID != nil { hs.log.Error("failed to retrieve user ID", "error", errID) } diff --git a/pkg/api/org.go b/pkg/api/org.go index d7f572d0905..34b08544b11 100644 --- a/pkg/api/org.go +++ b/pkg/api/org.go @@ -132,12 +132,11 @@ func (hs *HTTPServer) CreateOrg(c *contextmodel.ReqContext) response.Response { return response.Error(http.StatusBadRequest, "bad request data", err) } - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser { + if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { return response.Error(http.StatusForbidden, "Only users can create organizations", nil) } - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { return response.Error(http.StatusInternalServerError, "Failed to parse user id", err) } diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go index ea6e0ef7722..1591e180884 100644 --- a/pkg/api/org_invite.go +++ b/pkg/api/org_invite.go @@ -101,14 +101,9 @@ func (hs *HTTPServer) AddOrgInvite(c *contextmodel.ReqContext) response.Response cmd.Name = inviteDto.Name cmd.Status = tempuser.TmpUserInvitePending - namespace, identifier := c.SignedInUser.GetTypedID() var userID int64 - if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { - var err error - userID, err = strconv.ParseInt(identifier, 10, 64) - if err != nil { - return response.Error(http.StatusInternalServerError, "Unrecognized user", err) - } + if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil { + userID = id } cmd.InvitedByUserID = userID diff --git a/pkg/api/preferences.go b/pkg/api/preferences.go index c64d464ec25..e2fcef6976e 100644 --- a/pkg/api/preferences.go +++ b/pkg/api/preferences.go @@ -22,9 +22,9 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp return response.Error(http.StatusBadRequest, "bad request data", err) } - userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) - if errID != nil { - return response.Error(http.StatusInternalServerError, "Failed to set home dashboard", errID) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) + if err != nil { + return response.Error(http.StatusInternalServerError, "Failed to set home dashboard", err) } cmd.UserID = userID @@ -64,9 +64,9 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp // 401: unauthorisedError // 500: internalServerError func (hs *HTTPServer) GetUserPreferences(c *contextmodel.ReqContext) response.Response { - userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) - if errID != nil { - return response.Error(http.StatusInternalServerError, "Failed to get user preferences", errID) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) + if err != nil { + return response.Error(http.StatusInternalServerError, "Failed to update user preferences", err) } return prefapi.GetPreferencesFor(c.Req.Context(), hs.DashboardService, hs.preferenceService, c.SignedInUser.GetOrgID(), userID, 0) @@ -89,9 +89,9 @@ func (hs *HTTPServer) UpdateUserPreferences(c *contextmodel.ReqContext) response return response.Error(http.StatusBadRequest, "bad request data", err) } - userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) - if errID != nil { - return response.Error(http.StatusInternalServerError, "Failed to update user preferences", errID) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) + if err != nil { + return response.Error(http.StatusInternalServerError, "Failed to update user preferences", err) } return prefapi.UpdatePreferencesFor(c.Req.Context(), hs.DashboardService, @@ -113,9 +113,9 @@ func (hs *HTTPServer) PatchUserPreferences(c *contextmodel.ReqContext) response. return response.Error(http.StatusBadRequest, "bad request data", err) } - userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) - if errID != nil { - return response.Error(http.StatusInternalServerError, "Failed to update user preferences", errID) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) + if err != nil { + return response.Error(http.StatusInternalServerError, "Failed to update user preferences", err) } return hs.patchPreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), userID, 0, &dtoCmd) diff --git a/pkg/api/render.go b/pkg/api/render.go index eb5b4c10207..536052009d6 100644 --- a/pkg/api/render.go +++ b/pkg/api/render.go @@ -65,9 +65,9 @@ func (hs *HTTPServer) RenderHandler(c *contextmodel.ReqContext) { headers["Accept-Language"] = acceptLanguageHeader } - userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) - if errID != nil { - hs.log.Error("Failed to parse user id", "err", errID) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) + if err != nil { + hs.log.Debug("Failed to parse user id", "err", err) } encoding := queryReader.Get("encoding", "") diff --git a/pkg/api/signup.go b/pkg/api/signup.go index 6f4c175432c..52535ddddd5 100644 --- a/pkg/api/signup.go +++ b/pkg/api/signup.go @@ -47,9 +47,9 @@ func (hs *HTTPServer) SignUp(c *contextmodel.ReqContext) response.Response { return response.Error(http.StatusUnprocessableEntity, "User with same email address already exists", nil) } - userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) - if errID != nil { - hs.log.Error("Failed to parse user id", "err", errID) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) + if err != nil { + hs.log.Debug("Failed to parse user id", "err", err) } cmd := tempuser.CreateTempUserCommand{} diff --git a/pkg/api/user.go b/pkg/api/user.go index dd09ea8f65c..42baf886680 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -31,8 +31,7 @@ import ( // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) GetSignedInUser(c *contextmodel.ReqContext) response.Response { - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser { + if !identity.IsIdentityType(c.GetID(), identity.TypeUser) { return response.JSON(http.StatusOK, user.UserProfileDTO{ IsGrafanaAdmin: c.SignedInUser.GetIsGrafanaAdmin(), OrgID: c.SignedInUser.GetOrgID(), @@ -43,7 +42,7 @@ func (hs *HTTPServer) GetSignedInUser(c *contextmodel.ReqContext) response.Respo }) } - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.GetID()) if err != nil { return response.Error(http.StatusInternalServerError, "Failed to parse user id", err) } @@ -278,8 +277,7 @@ func (hs *HTTPServer) handleUpdateUser(ctx context.Context, cmd user.UpdateUserC } func (hs *HTTPServer) StartEmailVerificaton(c *contextmodel.ReqContext) response.Response { - namespace, id := c.SignedInUser.GetTypedID() - if !identity.IsIdentityType(namespace, identity.TypeUser) { + if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { return response.Error(http.StatusBadRequest, "Only users can verify their email", nil) } @@ -288,7 +286,7 @@ func (hs *HTTPServer) StartEmailVerificaton(c *contextmodel.ReqContext) response return response.Respond(http.StatusNotModified, nil) } - userID, err := strconv.ParseInt(id, 10, 64) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { return response.Error(http.StatusInternalServerError, "Got invalid user id", err) } @@ -506,13 +504,12 @@ func (hs *HTTPServer) ChangeActiveOrgAndRedirectToHome(c *contextmodel.ReqContex return } - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser { + if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { c.JsonApiErr(http.StatusForbidden, "Endpoint only available for users", nil) return } - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { c.JsonApiErr(http.StatusInternalServerError, "Failed to parse user id", err) return @@ -632,12 +629,11 @@ func (hs *HTTPServer) ClearHelpFlags(c *contextmodel.ReqContext) response.Respon } func getUserID(c *contextmodel.ReqContext) (int64, *response.NormalResponse) { - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser { + if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { return 0, response.Error(http.StatusForbidden, "Endpoint only available for users", nil) } - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { return 0, response.Error(http.StatusInternalServerError, "Failed to parse user id", err) } diff --git a/pkg/api/user_token.go b/pkg/api/user_token.go index fc59121d03a..c168c590784 100644 --- a/pkg/api/user_token.go +++ b/pkg/api/user_token.go @@ -32,12 +32,11 @@ import ( // 403: forbiddenError // 500: internalServerError func (hs *HTTPServer) GetUserAuthTokens(c *contextmodel.ReqContext) response.Response { - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser { - return response.Error(http.StatusForbidden, "entity not allowed to revoke tokens", nil) + if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { + return response.Error(http.StatusForbidden, "entity not allowed to get tokens", nil) } - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { return response.Error(http.StatusInternalServerError, "failed to parse user id", err) } @@ -63,12 +62,11 @@ func (hs *HTTPServer) RevokeUserAuthToken(c *contextmodel.ReqContext) response.R return response.Error(http.StatusBadRequest, "bad request data", err) } - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser { + if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { return response.Error(http.StatusForbidden, "entity not allowed to revoke tokens", nil) } - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { return response.Error(http.StatusInternalServerError, "failed to parse user id", err) } diff --git a/pkg/apimachinery/identity/error.go b/pkg/apimachinery/identity/error.go index bdc5520bd72..9b80ea1524f 100644 --- a/pkg/apimachinery/identity/error.go +++ b/pkg/apimachinery/identity/error.go @@ -7,6 +7,7 @@ import ( ) var ( + ErrInvalidIDType = errutil.BadRequest("auth.identity.invalid-id-type") ErrInvalidTypedID = errutil.BadRequest("auth.identity.invalid-typed-id") ErrNotIntIdentifier = errors.New("identifier is not an int64") ErrIdentifierNotInitialized = errors.New("identifier is not initialized") diff --git a/pkg/apimachinery/identity/requester.go b/pkg/apimachinery/identity/requester.go index 9da9d99286e..0a4e1dffa7f 100644 --- a/pkg/apimachinery/identity/requester.go +++ b/pkg/apimachinery/identity/requester.go @@ -17,15 +17,9 @@ type Requester interface { GetRawIdentifier() string // Deprecated: use GetUID instead GetInternalID() (int64, error) - // GetID returns namespaced internalID for the entity // Deprecated: use GetUID instead GetID() TypedID - // GetTypedID returns the namespace and ID of the active entity. - // The namespace is one of the constants defined in pkg/apimachinery/identity. - // Deprecated: use GetID instead - GetTypedID() (kind IdentityType, identifier string) - // GetDisplayName returns the display name of the active entity. // The display name is the name if it is set, otherwise the login or email. GetDisplayName() string @@ -82,14 +76,14 @@ type Requester interface { GetIDClaims() *authnlib.Claims[authnlib.IDTokenClaims] } -// IntIdentifier converts a string identifier to an int64. +// IntIdentifier converts a typeID to an int64. // Applicable for users, service accounts, api keys and renderer service. -// Errors if the identifier is not initialized or if namespace is not recognized. -func IntIdentifier(kind IdentityType, identifier string) (int64, error) { - if IsIdentityType(kind, TypeUser, TypeAPIKey, TypeServiceAccount, TypeRenderService) { - id, err := strconv.ParseInt(identifier, 10, 64) +// Errors if the identifier is not initialized or if type is not recognized. +func IntIdentifier(typedID TypedID) (int64, error) { + if IsIdentityType(typedID, TypeUser, TypeAPIKey, TypeServiceAccount, TypeRenderService) { + id, err := strconv.ParseInt(typedID.ID(), 10, 64) if err != nil { - return 0, fmt.Errorf("unrecognized format for valid type %s: %w", kind, err) + return 0, fmt.Errorf("unrecognized format for valid type %s: %w", typedID.Type(), err) } if id < 1 { @@ -102,19 +96,18 @@ func IntIdentifier(kind IdentityType, identifier string) (int64, error) { return 0, ErrNotIntIdentifier } -// UserIdentifier converts a string identifier to an int64. +// UserIdentifier converts a typeID 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(kind IdentityType, identifier string) (int64, error) { - userID, err := IntIdentifier(kind, identifier) +// Returns 0 if the type is not user or service account +func UserIdentifier(typedID TypedID) (int64, error) { + userID, err := IntIdentifier(typedID) if err != nil { - // FIXME: return this error once entity namespaces are handled by stores - return 0, nil + return 0, err } - if IsIdentityType(kind, TypeUser, TypeServiceAccount) { + if IsIdentityType(typedID, TypeUser, TypeServiceAccount) { return userID, nil } - return 0, nil + return 0, ErrInvalidIDType } diff --git a/pkg/apimachinery/identity/static.go b/pkg/apimachinery/identity/static.go index 2fe79aaee8a..6ed1bae9e28 100644 --- a/pkg/apimachinery/identity/static.go +++ b/pkg/apimachinery/identity/static.go @@ -149,12 +149,6 @@ func (u *StaticRequester) GetID() TypedID { return NewTypedIDString(u.Type, fmt.Sprintf("%d", u.UserID)) } -// GetTypedID returns the namespace and ID of the active entity -// The namespace is one of the constants defined in pkg/apimachinery/identity -func (u *StaticRequester) GetTypedID() (IdentityType, string) { - return u.Type, fmt.Sprintf("%d", u.UserID) -} - func (u *StaticRequester) GetAuthID() string { return u.AuthID } diff --git a/pkg/apimachinery/identity/namespace.go b/pkg/apimachinery/identity/typed_id.go similarity index 93% rename from pkg/apimachinery/identity/namespace.go rename to pkg/apimachinery/identity/typed_id.go index 485d5ea4081..4cecbd2cc93 100644 --- a/pkg/apimachinery/identity/namespace.go +++ b/pkg/apimachinery/identity/typed_id.go @@ -42,10 +42,10 @@ func ParseType(str string) (IdentityType, error) { } } -// IsIdentityType returns true if type matches any expected identity type -func IsIdentityType(typ IdentityType, expected ...IdentityType) bool { +// IsIdentityType returns true if typedID matches any expected identity type +func IsIdentityType(typedID TypedID, expected ...IdentityType) bool { for _, e := range expected { - if typ == e { + if typedID.Type() == e { return true } } @@ -128,7 +128,7 @@ func (ni TypedID) Type() IdentityType { } func (ni TypedID) IsType(expected ...IdentityType) bool { - return IsIdentityType(ni.t, expected...) + return IsIdentityType(ni, expected...) } func (ni TypedID) String() string { diff --git a/pkg/services/accesscontrol/acimpl/accesscontrol.go b/pkg/services/accesscontrol/acimpl/accesscontrol.go index 48bc7bd3ca2..a643e02f766 100644 --- a/pkg/services/accesscontrol/acimpl/accesscontrol.go +++ b/pkg/services/accesscontrol/acimpl/accesscontrol.go @@ -192,6 +192,5 @@ func (a *AccessControl) RegisterScopeAttributeResolver(prefix string, resolver a } func (a *AccessControl) debug(ctx context.Context, ident identity.Requester, msg string, eval accesscontrol.Evaluator) { - namespace, id := ident.GetTypedID() - a.log.FromContext(ctx).Debug(msg, "namespace", namespace, "id", id, "orgID", ident.GetOrgID(), "permissions", eval.GoString()) + a.log.FromContext(ctx).Debug(msg, "id", ident.GetID(), "orgID", ident.GetOrgID(), "permissions", eval.GoString()) } diff --git a/pkg/services/accesscontrol/acimpl/service.go b/pkg/services/accesscontrol/acimpl/service.go index 5b7b509b245..c0641bbb118 100644 --- a/pkg/services/accesscontrol/acimpl/service.go +++ b/pkg/services/accesscontrol/acimpl/service.go @@ -128,7 +128,7 @@ func (s *Service) GetUserPermissions(ctx context.Context, user identity.Requeste return s.getCachedUserPermissions(ctx, user, options) } -func (s *Service) getUserPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options) ([]accesscontrol.Permission, error) { +func (s *Service) getUserPermissions(ctx context.Context, user identity.Requester, _ accesscontrol.Options) ([]accesscontrol.Permission, error) { ctx, span := s.tracer.Start(ctx, "authz.getUserPermissions") defer span.End() @@ -143,10 +143,9 @@ func (s *Service) getUserPermissions(ctx context.Context, user identity.Requeste permissions = append(permissions, SharedWithMeFolderPermission) } - userID, err := identity.UserIdentifier(user.GetTypedID()) - if err != nil { - return nil, err - } + // we don't care about the error here, if this fails we get 0 and no + // permission assigned to user will be returned, only for org role. + userID, _ := identity.UserIdentifier(user.GetID()) dbPermissions, err := s.store.GetUserPermissions(ctx, accesscontrol.GetUserPermissionsQuery{ OrgID: user.GetOrgID(), @@ -211,12 +210,10 @@ func (s *Service) getUserDirectPermissions(ctx context.Context, user identity.Re ctx, span := s.tracer.Start(ctx, "authz.getUserDirectPermissions") defer span.End() - namespace, identifier := user.GetTypedID() - var userID int64 - if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { + if identity.IsIdentityType(user.GetID(), identity.TypeUser, identity.TypeServiceAccount) { var err error - userID, err = strconv.ParseInt(identifier, 10, 64) + userID, err = identity.UserIdentifier(user.GetID()) if err != nil { return nil, err } diff --git a/pkg/services/accesscontrol/middleware.go b/pkg/services/accesscontrol/middleware.go index c4bb73eee0a..7c77b232247 100644 --- a/pkg/services/accesscontrol/middleware.go +++ b/pkg/services/accesscontrol/middleware.go @@ -80,11 +80,9 @@ func deny(c *contextmodel.ReqContext, evaluator Evaluator, err error) { if err != nil { c.Logger.Error("Error from access control system", "error", err, "accessErrorID", id) } else { - namespace, identifier := c.SignedInUser.GetTypedID() c.Logger.Info( "Access denied", - "namespace", namespace, - "userID", identifier, + "id", c.SignedInUser.GetID(), "accessErrorID", id, "permissions", evaluator.GoString(), ) diff --git a/pkg/services/auth/idimpl/service.go b/pkg/services/auth/idimpl/service.go index f48bf1c700b..4f9e37f2618 100644 --- a/pkg/services/auth/idimpl/service.go +++ b/pkg/services/auth/idimpl/service.go @@ -70,12 +70,10 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri idClaims *auth.IDClaims } result, err, _ := s.si.Do(cacheKey, func() (any, error) { - namespace, identifier := id.GetTypedID() - cachedToken, err := s.cache.Get(ctx, cacheKey) if err == nil { s.metrics.tokenSigningFromCacheCounter.Inc() - s.logger.FromContext(ctx).Debug("Cached token found", "namespace", namespace, "id", identifier) + s.logger.FromContext(ctx).Debug("Cached token found", "id", id.GetID()) tokenClaims, err := s.extractTokenClaims(string(cachedToken)) if err != nil { @@ -85,14 +83,14 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri } s.metrics.tokenSigningCounter.Inc() - s.logger.FromContext(ctx).Debug("Sign new id token", "namespace", namespace, "id", identifier) + s.logger.FromContext(ctx).Debug("Sign new id token", "id", id.GetID()) now := time.Now() claims := &auth.IDClaims{ Claims: &jwt.Claims{ Issuer: s.cfg.AppURL, Audience: getAudience(id.GetOrgID()), - Subject: getSubject(namespace.String(), identifier), + Subject: id.GetID().String(), Expiry: jwt.NewNumericDate(now.Add(tokenTTL)), IssuedAt: jwt.NewNumericDate(now), }, @@ -101,7 +99,7 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri }, } - if identity.IsIdentityType(namespace, identity.TypeUser) { + if identity.IsIdentityType(id.GetID(), identity.TypeUser) { claims.Rest.Email = id.GetEmail() claims.Rest.EmailVerified = id.IsEmailVerified() claims.Rest.AuthenticatedBy = id.GetAuthenticatedBy() @@ -145,8 +143,7 @@ func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.R token, claims, err := s.SignIdentity(ctx, identity) if err != nil { if shouldLogErr(err) { - namespace, id := identity.GetTypedID() - s.logger.FromContext(ctx).Error("Failed to sign id token", "err", err, "namespace", namespace, "id", id) + s.logger.FromContext(ctx).Error("Failed to sign id token", "err", err, "id", identity.GetID()) } // for now don't return error so we don't break authentication from this hook return nil @@ -179,10 +176,6 @@ func getAudience(orgID int64) jwt.Audience { return jwt.Audience{fmt.Sprintf("org:%d", orgID)} } -func getSubject(namespace, identifier string) string { - return fmt.Sprintf("%s:%s", namespace, identifier) -} - func prefixCacheKey(key string) string { return fmt.Sprintf("%s-%s", cachePrefix, key) } diff --git a/pkg/services/authn/clients/oauth.go b/pkg/services/authn/clients/oauth.go index 0bca27e12be..48ae37c88c1 100644 --- a/pkg/services/authn/clients/oauth.go +++ b/pkg/services/authn/clients/oauth.go @@ -248,10 +248,9 @@ func (c *OAuth) RedirectURL(ctx context.Context, r *authn.Request) (*authn.Redir func (c *OAuth) Logout(ctx context.Context, user identity.Requester) (*authn.Redirect, bool) { token := c.oauthService.GetCurrentOAuthToken(ctx, user) - namespace, id := user.GetTypedID() - userID, err := identity.UserIdentifier(namespace, id) + userID, err := identity.UserIdentifier(user.GetID()) if err != nil { - c.log.FromContext(ctx).Error("Failed to parse user id", "namespace", namespace, "id", id, "error", err) + c.log.FromContext(ctx).Error("Failed to parse user id", "id", user.GetID(), "error", err) return nil, false } @@ -260,8 +259,7 @@ func (c *OAuth) Logout(ctx context.Context, user identity.Requester) (*authn.Red AuthId: user.GetAuthID(), AuthModule: user.GetAuthenticatedBy(), }); err != nil { - namespace, id := user.GetTypedID() - c.log.FromContext(ctx).Error("Failed to invalidate tokens", "namespace", namespace, "id", id, "error", err) + c.log.FromContext(ctx).Error("Failed to invalidate tokens", "id", user.GetID(), "error", err) } oauthCfg := c.socialService.GetOAuthInfoProvider(c.providerName) diff --git a/pkg/services/authn/clients/oauth_test.go b/pkg/services/authn/clients/oauth_test.go index cb3c9aa225c..c23c2c348d9 100644 --- a/pkg/services/authn/clients/oauth_test.go +++ b/pkg/services/authn/clients/oauth_test.go @@ -485,7 +485,7 @@ func TestOAuth_Logout(t *testing.T) { } c := ProvideOAuth(authn.ClientWithPrefix("azuread"), tt.cfg, mockService, fakeSocialSvc, &setting.OSSImpl{Cfg: tt.cfg}, featuremgmt.WithFeatures()) - redirect, ok := c.Logout(context.Background(), &authn.Identity{}) + redirect, ok := c.Logout(context.Background(), &authn.Identity{ID: identity.NewTypedIDString(identity.TypeUser, "1")}) assert.Equal(t, tt.expectedOK, ok) if tt.expectedOK { diff --git a/pkg/services/authn/identity.go b/pkg/services/authn/identity.go index b41c65c3bba..761056891b5 100644 --- a/pkg/services/authn/identity.go +++ b/pkg/services/authn/identity.go @@ -115,10 +115,6 @@ func (i *Identity) GetID() identity.TypedID { return i.ID } -func (i *Identity) GetTypedID() (namespace identity.IdentityType, identifier string) { - return i.ID.Type(), i.ID.ID() -} - func (i *Identity) GetUID() string { return i.UID.String() } @@ -132,14 +128,14 @@ func (i *Identity) GetAuthenticatedBy() string { } func (i *Identity) GetCacheKey() string { - namespace, id := i.GetTypedID() + id := i.GetID().ID() if !i.HasUniqueId() { // Hack use the org role as id for identities that do not have a unique id // e.g. anonymous and render key. id = string(i.GetOrgRole()) } - return fmt.Sprintf("%d-%s-%s", i.GetOrgID(), namespace, id) + return fmt.Sprintf("%d-%s-%s", i.GetOrgID(), i.GetID().Type(), id) } func (i *Identity) GetDisplayName() string { @@ -232,10 +228,10 @@ func (i *Identity) HasRole(role org.RoleType) bool { } func (i *Identity) HasUniqueId() bool { - namespace, _ := i.GetTypedID() - return namespace == identity.TypeUser || - namespace == identity.TypeServiceAccount || - namespace == identity.TypeAPIKey + typ := i.GetID().Type() + return typ == identity.TypeUser || + typ == identity.TypeServiceAccount || + typ == identity.TypeAPIKey } func (i *Identity) IsAuthenticatedBy(providers ...string) bool { diff --git a/pkg/services/contexthandler/contexthandler.go b/pkg/services/contexthandler/contexthandler.go index 7ae68ac59c0..24ac584a9b8 100644 --- a/pkg/services/contexthandler/contexthandler.go +++ b/pkg/services/contexthandler/contexthandler.go @@ -154,22 +154,22 @@ func (h *ContextHandler) addIDHeaderEndOfRequestFunc(ident identity.Requester) w return } - namespace, id := ident.GetTypedID() + id := ident.GetID() if !identity.IsIdentityType( - namespace, + id, identity.TypeUser, identity.TypeServiceAccount, identity.TypeAPIKey, - ) || id == "0" { + ) || id.ID() == "0" { return } - if _, ok := h.Cfg.IDResponseHeaderNamespaces[namespace.String()]; !ok { + if _, ok := h.Cfg.IDResponseHeaderNamespaces[id.Type().String()]; !ok { return } headerName := fmt.Sprintf("%s-Identity-Id", h.Cfg.IDResponseHeaderPrefix) - w.Header().Add(headerName, fmt.Sprintf("%s:%s", namespace, id)) + w.Header().Add(headerName, id.String()) } } diff --git a/pkg/services/dashboardimport/service/service.go b/pkg/services/dashboardimport/service/service.go index aff5dc0800c..a901e8f3071 100644 --- a/pkg/services/dashboardimport/service/service.go +++ b/pkg/services/dashboardimport/service/service.go @@ -109,11 +109,9 @@ func (s *ImportDashboardService) ImportDashboard(ctx context.Context, req *dashb req.FolderUid = folder.UID } - namespace, identifier := req.User.GetTypedID() - userID := int64(0) - - if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { - userID, _ = identity.IntIdentifier(namespace, identifier) + var userID int64 + if id, err := identity.UserIdentifier(req.User.GetID()); err == nil { + userID = id } saveCmd := dashboards.SaveDashboardCommand{ diff --git a/pkg/services/dashboardimport/service/service_test.go b/pkg/services/dashboardimport/service/service_test.go index 42cd3f9503d..365930fd618 100644 --- a/pkg/services/dashboardimport/service/service_test.go +++ b/pkg/services/dashboardimport/service/service_test.go @@ -83,7 +83,7 @@ func TestImportDashboardService(t *testing.T) { require.NotNil(t, resp) require.Equal(t, "UDdpyzz7z", resp.UID) - userID, err := identity.IntIdentifier(importDashboardArg.User.GetTypedID()) + userID, err := identity.IntIdentifier(importDashboardArg.User.GetID()) require.NoError(t, err) require.NotNil(t, importDashboardArg) @@ -149,7 +149,7 @@ func TestImportDashboardService(t *testing.T) { require.NotNil(t, resp) require.Equal(t, "UDdpyzz7z", resp.UID) - userID, err := identity.IntIdentifier(importDashboardArg.User.GetTypedID()) + userID, err := identity.IntIdentifier(importDashboardArg.User.GetID()) require.NoError(t, err) require.NotNil(t, importDashboardArg) diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 773c3939dea..7d70832a8d6 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -207,9 +207,11 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d } } - userID, err := resolveUserID(dto.User, dr.log) - if err != nil { - return nil, err + var userID int64 + if id, err := identity.UserIdentifier(dto.User.GetID()); err == nil { + userID = id + } else { + dr.log.Debug("User does not belong to a user or service account namespace, using 0 as user ID", "id", dto.User.GetID()) } metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc() @@ -232,22 +234,6 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d return cmd, nil } -func resolveUserID(user identity.Requester, log log.Logger) (int64, error) { - userID := int64(0) - namespaceID, identifier := user.GetTypedID() - if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { - log.Debug("User does not belong to a user or service account namespace", "namespaceID", namespaceID, "userID", identifier) - } else { - var err error - userID, err = identity.IntIdentifier(namespaceID, identifier) - if err != nil { - log.Debug("failed to parse user ID", "namespaceID", namespaceID, "userID", identifier, "error", err) - } - } - - return userID, nil -} - func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *dashboards.DeleteOrphanedProvisionedDashboardsCommand) error { return dr.dashboardStore.DeleteOrphanedProvisionedDashboards(ctx, cmd) } @@ -503,12 +489,10 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto * var permissions []accesscontrol.SetResourcePermissionCommand if !provisioned { - namespaceID, userIDstr := dto.User.GetTypedID() - userID, err := identity.IntIdentifier(namespaceID, userIDstr) - + userID, err := identity.IntIdentifier(dto.User.GetID()) if err != nil { - dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err) - } else if namespaceID == identity.TypeUser && userID > 0 { + dr.log.Error("Could not make user admin", "dashboard", dash.Title, "id", dto.User.GetID(), "error", err) + } else if identity.IsIdentityType(dto.User.GetID(), identity.TypeUser) { permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(), }) @@ -541,12 +525,10 @@ func (dr *DashboardServiceImpl) setDefaultFolderPermissions(ctx context.Context, var permissions []accesscontrol.SetResourcePermissionCommand if !provisioned { - namespaceID, userIDstr := cmd.SignedInUser.GetTypedID() - userID, err := identity.IntIdentifier(namespaceID, userIDstr) - + userID, err := identity.IntIdentifier(cmd.SignedInUser.GetID()) if err != nil { - dr.log.Error("Could not make user admin", "folder", cmd.Title, "namespaceID", namespaceID, "userID", userID, "error", err) - } else if namespaceID == identity.TypeUser && userID > 0 { + dr.log.Error("Could not make user admin", "folder", cmd.Title, "id", cmd.SignedInUser.GetID()) + } else if identity.IsIdentityType(cmd.SignedInUser.GetID(), identity.TypeUser) { permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(), }) diff --git a/pkg/services/dashboards/service/dashboard_service_integration_test.go b/pkg/services/dashboards/service/dashboard_service_integration_test.go index 899f5ce031d..e536a332ea5 100644 --- a/pkg/services/dashboards/service/dashboard_service_integration_test.go +++ b/pkg/services/dashboards/service/dashboard_service_integration_test.go @@ -116,7 +116,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sqlStore) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, "", sc.dashboardGuardianMock.DashUID) @@ -139,7 +139,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.otherSavedFolder.ID, sc.dashboardGuardianMock.DashID) @@ -162,7 +162,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) @@ -186,7 +186,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) @@ -210,7 +210,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) @@ -234,7 +234,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) @@ -258,7 +258,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) @@ -282,7 +282,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) @@ -306,7 +306,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) @@ -330,7 +330,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) { err := callSaveWithError(t, cmd, sc.sqlStore) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) + userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID()) require.NoError(t, err) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) diff --git a/pkg/services/dashboardsnapshots/database/database.go b/pkg/services/dashboardsnapshots/database/database.go index 85f945caf4c..a040133e43a 100644 --- a/pkg/services/dashboardsnapshots/database/database.go +++ b/pkg/services/dashboardsnapshots/database/database.go @@ -122,12 +122,10 @@ func (d *DashboardSnapshotStore) SearchDashboardSnapshots(ctx context.Context, q sess.Where("name LIKE ?", query.Name) } - namespace, id := query.SignedInUser.GetTypedID() var userID int64 - - if namespace == identity.TypeServiceAccount || namespace == identity.TypeUser { + if identity.IsIdentityType(query.SignedInUser.GetID(), identity.TypeUser, identity.TypeServiceAccount) { var err error - userID, err = identity.IntIdentifier(namespace, id) + userID, err = identity.UserIdentifier(query.SignedInUser.GetID()) if err != nil { return err } @@ -137,7 +135,7 @@ func (d *DashboardSnapshotStore) SearchDashboardSnapshots(ctx context.Context, q switch { case query.SignedInUser.GetOrgRole() == org.RoleAdmin: sess.Where("org_id = ?", query.SignedInUser.GetOrgID()) - case namespace != identity.TypeAnonymous: + case userID != 0: sess.Where("org_id = ? AND user_id = ?", query.OrgID, userID) default: queryResult = snapshots diff --git a/pkg/services/dashboardsnapshots/service.go b/pkg/services/dashboardsnapshots/service.go index bf0add3c4f6..721b803d8b6 100644 --- a/pkg/services/dashboardsnapshots/service.go +++ b/pkg/services/dashboardsnapshots/service.go @@ -63,17 +63,10 @@ func CreateDashboardSnapshot(c *contextmodel.ReqContext, cfg dashboardsnapshot.S cmd.DashboardCreateCommand.Name = "Unnamed snapshot" } - userID, err := identity.UserIdentifier(user.GetTypedID()) - if err != nil { - c.JsonApiErr(http.StatusInternalServerError, - "Failed to create external snapshot", err) - return - } - var snapshotUrl string cmd.ExternalURL = "" cmd.OrgID = user.GetOrgID() - cmd.UserID = userID + cmd.UserID, _ = identity.UserIdentifier(user.GetID()) originalDashboardURL, err := createOriginalDashboardURL(&cmd) if err != nil { c.JsonApiErr(http.StatusInternalServerError, "Invalid app URL", err) diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index 3ed5026d282..c3b36588454 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -592,21 +592,17 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) ( user := cmd.SignedInUser - userID := int64(0) - var err error - namespaceID, userIDstr := user.GetTypedID() - if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { - s.log.Debug("User does not belong to a user or service account namespace, using 0 as user ID", "namespaceID", namespaceID, "userID", userIDstr) + var userID int64 + if id, err := identity.UserIdentifier(cmd.SignedInUser.GetID()); err == nil { + userID = id } else { - userID, err = identity.IntIdentifier(namespaceID, userIDstr) - if err != nil { - s.log.Debug("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err) - } + s.log.Warn("User does not belong to a user or service account namespace, using 0 as user ID", "id", cmd.SignedInUser.GetID()) } if userID == 0 { userID = -1 } + dashFolder.CreatedBy = userID dashFolder.UpdatedBy = userID dashFolder.UpdateSlug() @@ -682,8 +678,6 @@ func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) ( } if cmd.NewTitle != nil { - namespace, id := cmd.SignedInUser.GetTypedID() - metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc() if err := s.bus.Publish(ctx, &events.FolderTitleUpdated{ Timestamp: foldr.Updated, @@ -692,7 +686,7 @@ func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) ( UID: dashFolder.UID, OrgID: cmd.OrgID, }); err != nil { - s.log.ErrorContext(ctx, "failed to publish FolderTitleUpdated event", "folder", foldr.Title, "user", id, "namespace", namespace, "error", err) + s.log.ErrorContext(ctx, "failed to publish FolderTitleUpdated event", "folder", foldr.Title, "user", cmd.SignedInUser.GetID(), "error", err) return err } } @@ -739,12 +733,10 @@ func (s *Service) legacyUpdate(ctx context.Context, cmd *folder.UpdateFolderComm } var userID int64 - namespace, id := cmd.SignedInUser.GetTypedID() - if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { - userID, err = identity.IntIdentifier(namespace, id) - if err != nil { - s.log.ErrorContext(ctx, "failed to parse user ID", "namespace", namespace, "userID", id, "error", err) - } + if id, err := identity.UserIdentifier(cmd.SignedInUser.GetID()); err == nil { + userID = id + } else { + s.log.Warn("User does not belong to a user or service account namespace, using 0 as user ID", "id", cmd.SignedInUser.GetID()) } prepareForUpdate(dashFolder, cmd.OrgID, userID, cmd) @@ -1163,15 +1155,11 @@ func (s *Service) buildSaveDashboardCommand(ctx context.Context, dto *dashboards } } - userID := int64(0) - namespaceID, userIDstr := dto.User.GetTypedID() - if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { - s.log.Warn("User does not belong to a user or service account namespace, using 0 as user ID", "namespaceID", namespaceID, "userID", userIDstr) + var userID int64 + if id, err := identity.UserIdentifier(dto.User.GetID()); err == nil { + userID = id } else { - userID, err = identity.IntIdentifier(namespaceID, userIDstr) - if err != nil { - s.log.Warn("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err) - } + s.log.Warn("User does not belong to a user or service account namespace, using 0 as user ID", "id", dto.User.GetID()) } metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc() diff --git a/pkg/services/guardian/accesscontrol_guardian.go b/pkg/services/guardian/accesscontrol_guardian.go index dccc61277ac..de32d370ae2 100644 --- a/pkg/services/guardian/accesscontrol_guardian.go +++ b/pkg/services/guardian/accesscontrol_guardian.go @@ -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.GetTypedID() 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, "identity", a.user.GetID(), "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", "identity", a.user.GetID(), "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.GetTypedID() 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, "identity", a.user.GetID(), "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", "identity", a.user.GetID(), "identity", a.user.GetID(), "orgID", orgID, "uid", uid, "permissions", evaluator.GoString()) } return ok, err diff --git a/pkg/services/libraryelements/database.go b/pkg/services/libraryelements/database.go index 32b6f627c2c..5bb08c3281a 100644 --- a/pkg/services/libraryelements/database.go +++ b/pkg/services/libraryelements/database.go @@ -138,13 +138,9 @@ func (l *LibraryElementService) createLibraryElement(c context.Context, signedIn } } - userID := int64(0) - namespaceID, identifier := signedInUser.GetTypedID() - if namespaceID == identity.TypeUser || namespaceID == identity.TypeServiceAccount { - userID, err = identity.IntIdentifier(namespaceID, identifier) - if err != nil { - l.log.Warn("Error while parsing userID", "namespaceID", namespaceID, "userID", identifier) - } + var userID int64 + if id, err := identity.UserIdentifier(signedInUser.GetID()); err == nil { + userID = id } metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryElements).Inc() @@ -593,13 +589,8 @@ func (l *LibraryElementService) patchLibraryElement(c context.Context, signedInU } var userID int64 - namespaceID, identifier := signedInUser.GetTypedID() - if namespaceID == identity.TypeUser || namespaceID == identity.TypeServiceAccount { - var errID error - userID, errID = identity.IntIdentifier(namespaceID, identifier) - if errID != nil { - l.log.Warn("Error while parsing userID", "namespaceID", namespaceID, "userID", identifier, "err", errID) - } + if id, err := identity.UserIdentifier(signedInUser.GetID()); err == nil { + userID = id } metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryElements).Inc() @@ -800,13 +791,9 @@ func (l *LibraryElementService) connectElementsToDashboardID(c context.Context, return err } - namespaceID, identifier := signedInUser.GetTypedID() - userID := int64(0) - if namespaceID == identity.TypeUser || namespaceID == identity.TypeServiceAccount { - userID, err = identity.IntIdentifier(namespaceID, identifier) - if err != nil { - l.log.Warn("Failed to parse user ID from namespace identifier", "namespace", namespaceID, "identifier", identifier, "error", err) - } + var userID int64 + if id, err := identity.UserIdentifier(signedInUser.GetID()); err == nil { + userID = id } connection := model.LibraryElementConnection{ diff --git a/pkg/services/live/live.go b/pkg/services/live/live.go index 1b4473807f1..18eb4296b10 100644 --- a/pkg/services/live/live.go +++ b/pkg/services/live/live.go @@ -284,11 +284,9 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r g.websocketHandler = func(ctx *contextmodel.ReqContext) { user := ctx.SignedInUser - _, identifier := user.GetTypedID() - // Centrifuge expects Credentials in context with a current user ID. cred := ¢rifuge.Credentials{ - UserID: identifier, + UserID: user.GetID().ID(), } newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred) newCtx = livecontext.SetContextSignedUser(newCtx, user) @@ -955,8 +953,7 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R return response.Error(http.StatusBadRequest, "invalid channel ID", nil) } - namespaceID, userID := ctx.SignedInUser.GetTypedID() - logger.Debug("Publish API cmd", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel) + logger.Debug("Publish API cmd", "identity", ctx.SignedInUser.GetID(), "channel", cmd.Channel) user := ctx.SignedInUser channel := cmd.Channel @@ -1013,7 +1010,7 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R 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", "identity", ctx.SignedInUser.GetID(), "channel", cmd.Channel) return response.JSON(http.StatusOK, dtos.LivePublishResponse{}) } diff --git a/pkg/services/live/runstream/manager_test.go b/pkg/services/live/runstream/manager_test.go index 3b0d1b6107d..1e28e4f360a 100644 --- a/pkg/services/live/runstream/manager_test.go +++ b/pkg/services/live/runstream/manager_test.go @@ -73,7 +73,7 @@ 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.GetTypedID()) + userID, err := identity.IntIdentifier(user.GetID()) require.NoError(t, err) require.Equal(t, int64(2), userID) require.Equal(t, int64(1), user.GetOrgID()) @@ -258,7 +258,7 @@ 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.GetTypedID()) + userID, err := identity.IntIdentifier(user.GetID()) require.NoError(t, err) require.Equal(t, int64(2), userID) require.Equal(t, int64(1), user.GetOrgID()) @@ -343,7 +343,7 @@ 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.GetTypedID()) + userID, err := identity.IntIdentifier(user.GetID()) require.NoError(t, err) require.Equal(t, int64(2), userID) @@ -412,7 +412,7 @@ 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.GetTypedID()) + userID, err := identity.IntIdentifier(user.GetID()) require.NoError(t, err) require.Equal(t, int64(2), userID) require.Equal(t, int64(1), user.GetOrgID()) diff --git a/pkg/services/navtree/navtreeimpl/navtree.go b/pkg/services/navtree/navtreeimpl/navtree.go index f80bab4566a..c63f6211180 100644 --- a/pkg/services/navtree/navtreeimpl/navtree.go +++ b/pkg/services/navtree/navtreeimpl/navtree.go @@ -297,7 +297,7 @@ func (s *ServiceImpl) getProfileNode(c *contextmodel.ReqContext) *navtree.NavLin func (s *ServiceImpl) buildStarredItemsNavLinks(c *contextmodel.ReqContext) ([]*navtree.NavLink, error) { starredItemsChildNavs := []*navtree.NavLink{} - userID, _ := identity.UserIdentifier(c.SignedInUser.GetTypedID()) + userID, _ := identity.UserIdentifier(c.SignedInUser.GetID()) query := star.GetUserStarsQuery{ UserID: userID, } diff --git a/pkg/services/ngalert/api/api_ruler.go b/pkg/services/ngalert/api/api_ruler.go index 2f9f4273cc5..15c6d42a9b6 100644 --- a/pkg/services/ngalert/api/api_ruler.go +++ b/pkg/services/ngalert/api/api_ruler.go @@ -76,9 +76,9 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *contextmodel.ReqContext, namespaceU return toNamespaceErrorResponse(err) } - userNamespace, id := c.SignedInUser.GetTypedID() + userNamespace, id := c.SignedInUser.GetID().Type(), c.SignedInUser.GetID().ID() var loggerCtx = []any{ - "userId", + "identity", id, "userNamespace", userNamespace, @@ -283,7 +283,7 @@ func (srv RulerSrv) RouteGetRulesConfig(c *contextmodel.ReqContext) response.Res for groupKey, rules := range configs { folder, ok := namespaceMap[groupKey.NamespaceUID] if !ok { - userNamespace, id := c.SignedInUser.GetTypedID() + userNamespace, id := c.SignedInUser.GetID().Type(), c.SignedInUser.GetID().ID() srv.log.Error("Namespace not visible to the user", "user", id, "userNamespace", userNamespace, "namespace", groupKey.NamespaceUID) continue } @@ -359,7 +359,7 @@ func (srv RulerSrv) updateAlertRulesInGroup(c *contextmodel.ReqContext, groupKey var finalChanges *store.GroupDelta var dbConfig *ngmodels.AlertConfiguration err := srv.xactManager.InTransaction(c.Req.Context(), func(tranCtx context.Context) error { - userNamespace, id := c.SignedInUser.GetTypedID() + userNamespace, id := c.SignedInUser.GetID().Type(), c.SignedInUser.GetID().ID() logger := srv.log.New("namespace_uid", groupKey.NamespaceUID, "group", groupKey.RuleGroup, "org_id", groupKey.OrgID, "user_id", id, "userNamespace", userNamespace) groupChanges, err := store.CalculateChanges(tranCtx, srv.store, groupKey, rules) @@ -454,7 +454,7 @@ func (srv RulerSrv) updateAlertRulesInGroup(c *contextmodel.ReqContext, groupKey } if len(finalChanges.New) > 0 { - userID, _ := identity.UserIdentifier(c.SignedInUser.GetTypedID()) + userID, _ := identity.UserIdentifier(c.SignedInUser.GetID()) limitReached, err := srv.QuotaService.CheckQuotaReached(tranCtx, ngmodels.QuotaTargetSrv, "a.ScopeParameters{ OrgID: c.SignedInUser.GetOrgID(), UserID: userID, diff --git a/pkg/services/ngalert/provisioning/alert_rules.go b/pkg/services/ngalert/provisioning/alert_rules.go index 0a29a8478ea..47a481b6efa 100644 --- a/pkg/services/ngalert/provisioning/alert_rules.go +++ b/pkg/services/ngalert/provisioning/alert_rules.go @@ -659,12 +659,10 @@ func (service *AlertRuleService) DeleteAlertRule(ctx context.Context, user ident // checkLimitsTransactionCtx checks whether the current transaction (as identified by the ctx) breaches configured alert rule limits. func (service *AlertRuleService) checkLimitsTransactionCtx(ctx context.Context, user identity.Requester) error { // default to 0 if there is no user - userID := int64(0) - u, err := identity.UserIdentifier(user.GetTypedID()) - if err != nil { - return fmt.Errorf("failed to check alert rule quota: %w", err) + var userID int64 + if id, err := identity.UserIdentifier(user.GetID()); err == nil { + userID = id } - userID = u limitReached, err := service.quotas.CheckQuotaReached(ctx, models.QuotaTargetSrv, "a.ScopeParameters{ OrgID: user.GetOrgID(), diff --git a/pkg/services/oauthtoken/oauth_token.go b/pkg/services/oauthtoken/oauth_token.go index 4974e7de7b5..fa351fddeae 100644 --- a/pkg/services/oauthtoken/oauth_token.go +++ b/pkg/services/oauthtoken/oauth_token.go @@ -94,17 +94,14 @@ func (o *Service) HasOAuthEntry(ctx context.Context, usr identity.Requester) (*l return nil, false, nil } - namespace, id := usr.GetTypedID() - if namespace != identity.TypeUser { - // Not a user, therefore no token. + if !identity.IsIdentityType(usr.GetID(), identity.TypeUser) { return nil, false, nil } ctxLogger := logger.FromContext(ctx) - - userID, err := identity.IntIdentifier(namespace, id) + userID, err := identity.UserIdentifier(usr.GetID()) if err != nil { - ctxLogger.Error("Failed to convert user id to int", "namespace", namespace, "userID", id, "error", err) + ctxLogger.Error("Failed to convert user id to int", "id", usr.GetID(), "error", err) return nil, false, err } @@ -130,24 +127,22 @@ func (o *Service) HasOAuthEntry(ctx context.Context, usr identity.Requester) (*l // TryTokenRefresh returns an error in case the OAuth token refresh was unsuccessful // It uses a singleflight.Group to prevent getting the Refresh Token multiple times for a given User func (o *Service) TryTokenRefresh(ctx context.Context, usr identity.Requester) error { + ctxLogger := logger.FromContext(ctx) + if usr == nil || usr.IsNil() { - logger.Warn("Can only refresh OAuth tokens for existing users", "user", "nil") + ctxLogger.Warn("Can only refresh OAuth tokens for existing users", "user", "nil") // Not user, no token. return nil } - namespace, id := usr.GetTypedID() - if namespace != identity.TypeUser { - // Not a user, therefore no token. - logger.Warn("Can only refresh OAuth tokens for users", "namespace", namespace, "userId", id) + if !identity.IsIdentityType(usr.GetID(), identity.TypeUser) { + ctxLogger.Warn("Can only refresh OAuth tokens for users", "id", usr.GetID()) return nil } - ctxLogger := logger.FromContext(ctx) - - userID, err := identity.IntIdentifier(namespace, id) + userID, err := identity.UserIdentifier(usr.GetID()) if err != nil { - ctxLogger.Warn("Failed to convert user id to int", "namespace", namespace, "userId", id, "error", err) + ctxLogger.Warn("Failed to convert user id to int", "id", usr.GetID(), "error", err) return nil } diff --git a/pkg/services/pluginsintegration/clientmiddleware/user_header_middleware.go b/pkg/services/pluginsintegration/clientmiddleware/user_header_middleware.go index ae6592eb958..6caebc23859 100644 --- a/pkg/services/pluginsintegration/clientmiddleware/user_header_middleware.go +++ b/pkg/services/pluginsintegration/clientmiddleware/user_header_middleware.go @@ -35,8 +35,7 @@ func (m *UserHeaderMiddleware) applyUserHeader(ctx context.Context, h backend.Fo } h.DeleteHTTPHeader(proxyutil.UserHeaderName) - namespace, _ := reqCtx.SignedInUser.GetTypedID() - if namespace != identity.TypeAnonymous { + if !identity.IsIdentityType(reqCtx.SignedInUser.GetID(), identity.TypeAnonymous) { h.SetHTTPHeader(proxyutil.UserHeaderName, reqCtx.SignedInUser.GetLogin()) } } diff --git a/pkg/services/serviceaccounts/api/api.go b/pkg/services/serviceaccounts/api/api.go index 3fbfe8dde40..7104dbd06ff 100644 --- a/pkg/services/serviceaccounts/api/api.go +++ b/pkg/services/serviceaccounts/api/api.go @@ -99,8 +99,7 @@ func (api *ServiceAccountsAPI) CreateServiceAccount(c *contextmodel.ReqContext) } if api.cfg.RBAC.PermissionsOnCreation("service-account") { - t, _ := c.SignedInUser.GetTypedID() - if t == identity.TypeUser { + if identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) { userID, err := c.SignedInUser.GetID().ParseInt() if err != nil { return response.Error(http.StatusInternalServerError, "Failed to parse user id", err) diff --git a/pkg/services/sqlstore/permissions/dashboard.go b/pkg/services/sqlstore/permissions/dashboard.go index f80c4a8f3ee..945a7c53e1e 100644 --- a/pkg/services/sqlstore/permissions/dashboard.go +++ b/pkg/services/sqlstore/permissions/dashboard.go @@ -165,10 +165,9 @@ func (f *accessControlDashboardPermissionFilter) buildClauses() { dashWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeDashboardsPrefix) folderWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeFoldersPrefix) - userID := int64(0) - namespace, identifier := f.user.GetTypedID() - if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { - userID, _ = identity.IntIdentifier(namespace, identifier) + var userID int64 + if id, err := identity.UserIdentifier(f.user.GetID()); err == nil { + userID = id } orgID := f.user.GetOrgID() diff --git a/pkg/services/sqlstore/permissions/dashboard_filter_no_subquery.go b/pkg/services/sqlstore/permissions/dashboard_filter_no_subquery.go index 79fcb84faf5..8f7f16c6303 100644 --- a/pkg/services/sqlstore/permissions/dashboard_filter_no_subquery.go +++ b/pkg/services/sqlstore/permissions/dashboard_filter_no_subquery.go @@ -33,10 +33,9 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) buildClauses() dashWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeDashboardsPrefix) folderWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeFoldersPrefix) - userID := int64(0) - namespace, identifier := f.user.GetTypedID() - if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { - userID, _ = identity.IntIdentifier(namespace, identifier) + var userID int64 + if id, err := identity.UserIdentifier(f.user.GetID()); err == nil { + userID = id } orgID := f.user.GetOrgID() diff --git a/pkg/services/star/api/api.go b/pkg/services/star/api/api.go index 8c6cbda3ed2..57ebdaa844f 100644 --- a/pkg/services/star/api/api.go +++ b/pkg/services/star/api/api.go @@ -47,14 +47,9 @@ func (api *API) getDashboardHelper(ctx context.Context, orgID int64, id int64, u } func (api *API) GetStars(c *contextmodel.ReqContext) response.Response { - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser && namespace != identity.TypeServiceAccount { - return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil) - } - - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { - return response.Error(http.StatusInternalServerError, "Invalid user ID", err) + return response.Error(http.StatusBadRequest, "Only users and service accounts get starred dashboards", nil) } query := star.GetUserStarsQuery{ @@ -101,17 +96,12 @@ func (api *API) GetStars(c *contextmodel.ReqContext) response.Response { // 403: forbiddenError // 500: internalServerError func (api *API) StarDashboard(c *contextmodel.ReqContext) response.Response { - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser && namespace != identity.TypeServiceAccount { + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) + if err != nil { return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil) } - userID, err := identity.IntIdentifier(namespace, identifier) - if err != nil { - return response.Error(http.StatusInternalServerError, "Invalid user ID", err) - } - idString := web.Params(c.Req)[":id"] - id, err := strconv.ParseInt(idString, 10, 64) + id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64) if err != nil { return response.Error(http.StatusBadRequest, "Invalid dashboard ID", nil) } @@ -146,18 +136,12 @@ func (api *API) StarDashboardByUID(c *contextmodel.ReqContext) response.Response return response.Error(http.StatusBadRequest, "Invalid dashboard UID", nil) } - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser && namespace != identity.TypeServiceAccount { + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) + if err != nil { return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil) } - userID, err := identity.IntIdentifier(namespace, identifier) - if err != nil { - return response.Error(http.StatusInternalServerError, "Invalid user ID", err) - } - dash, rsp := api.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid) - if rsp != nil { return rsp } @@ -193,14 +177,9 @@ func (api *API) UnstarDashboard(c *contextmodel.ReqContext) response.Response { return response.Error(http.StatusBadRequest, "Invalid dashboard ID", nil) } - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser && namespace != identity.TypeServiceAccount { - return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil) - } - - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { - return response.Error(http.StatusInternalServerError, "Invalid user ID", err) + return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil) } cmd := star.UnstarDashboardCommand{UserID: userID, DashboardID: id} @@ -233,14 +212,9 @@ func (api *API) UnstarDashboardByUID(c *contextmodel.ReqContext) response.Respon return response.Error(http.StatusBadRequest, "Invalid dashboard UID", nil) } - namespace, identifier := c.SignedInUser.GetTypedID() - if namespace != identity.TypeUser && namespace != identity.TypeServiceAccount { - return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil) - } - - userID, err := identity.IntIdentifier(namespace, identifier) + userID, err := identity.UserIdentifier(c.SignedInUser.GetID()) if err != nil { - return response.Error(http.StatusInternalServerError, "Invalid user ID", err) + return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil) } dash, rsp := api.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid) diff --git a/pkg/services/team/teamapi/team.go b/pkg/services/team/teamapi/team.go index eea490618ef..1b83bb49ebb 100644 --- a/pkg/services/team/teamapi/team.go +++ b/pkg/services/team/teamapi/team.go @@ -49,7 +49,7 @@ func (tapi *TeamAPI) createTeam(c *contextmodel.ReqContext) response.Response { // if the request is authenticated using API tokens // the SignedInUser is an empty struct therefore // an additional check whether it is an actual user is required - namespace, identifier := c.SignedInUser.GetTypedID() + namespace, identifier := c.SignedInUser.GetID().Type(), c.SignedInUser.GetID().ID() switch namespace { case identity.TypeUser: userID, err := strconv.ParseInt(identifier, 10, 64) diff --git a/pkg/services/user/identity.go b/pkg/services/user/identity.go index c05293ae4b5..45d4c7c4e60 100644 --- a/pkg/services/user/identity.go +++ b/pkg/services/user/identity.go @@ -169,7 +169,7 @@ func (u *SignedInUser) GetAllowedKubernetesNamespace() string { // GetCacheKey returns a unique key for the entity. // Add an extra prefix to avoid collisions with other caches func (u *SignedInUser) GetCacheKey() string { - namespace, id := u.GetTypedID() + typ, id := u.GetID().Type(), u.GetID().ID() if !u.HasUniqueId() { // Hack use the org role as id for identities that do not have a unique id // e.g. anonymous and render key. @@ -181,7 +181,7 @@ func (u *SignedInUser) GetCacheKey() string { id = string(orgRole) } - return fmt.Sprintf("%d-%s-%s", u.GetOrgID(), namespace, id) + return fmt.Sprintf("%d-%s-%s", u.GetOrgID(), typ, id) } // GetIsGrafanaAdmin returns true if the user is a server admin @@ -245,13 +245,11 @@ func (u *SignedInUser) GetOrgRole() identity.RoleType { // GetID returns namespaced id for the entity func (u *SignedInUser) GetID() identity.TypedID { - ns, id := u.GetTypedID() + ns, id := u.getTypeAndID() return identity.NewTypedIDString(ns, id) } -// GetTypedID returns the namespace and ID of the active entity -// The namespace is one of the constants defined in pkg/apimachinery/identity -func (u *SignedInUser) GetTypedID() (identity.IdentityType, string) { +func (u *SignedInUser) getTypeAndID() (identity.IdentityType, string) { switch { case u.ApiKeyID != 0: return identity.TypeAPIKey, strconv.FormatInt(u.ApiKeyID, 10) diff --git a/pkg/util/proxyutil/proxyutil.go b/pkg/util/proxyutil/proxyutil.go index 6cc16b3bd2f..f53bff01146 100644 --- a/pkg/util/proxyutil/proxyutil.go +++ b/pkg/util/proxyutil/proxyutil.go @@ -114,8 +114,7 @@ func ApplyUserHeader(sendUserHeader bool, req *http.Request, user identity.Reque return } - namespace, _ := user.GetTypedID() - if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { + if identity.IsIdentityType(user.GetID(), identity.TypeUser) { req.Header.Set(UserHeaderName, user.GetLogin()) } }