Identity: remove GetTypedID (#91745)

This commit is contained in:
Karl Persson 2024-08-09 17:20:24 +02:00 committed by GitHub
parent 6061fdc8b9
commit bcfb66b416
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 211 additions and 386 deletions

View File

@ -43,13 +43,11 @@ func (hs *HTTPServer) isDashboardStarredByUser(c *contextmodel.ReqContext, dashI
return false, nil return false, nil
} }
namespaceID, userIDstr := c.SignedInUser.GetTypedID() if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) {
if namespaceID != identity.TypeUser {
return false, nil return false, nil
} }
userID, err := identity.IntIdentifier(namespaceID, userIDstr) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if err != nil { if err != nil {
return false, err 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) return response.Error(http.StatusBadRequest, "Use folders endpoint for deleting folders.", nil)
} }
namespaceID, userIDStr := c.SignedInUser.GetTypedID()
// disconnect all library elements for this dashboard // disconnect all library elements for this dashboard
err = hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.ID) err = hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.ID)
if err != nil { if err != nil {
hs.log.Error( hs.log.Error(
"Failed to disconnect library elements", "Failed to disconnect library elements",
"dashboard", dash.ID, "dashboard", dash.ID,
"namespaceID", namespaceID, "identity", c.GetID(),
"user", userIDStr,
"error", err) "error", err)
} }
@ -515,15 +510,9 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
ctx := c.Req.Context() ctx := c.Req.Context()
var err error var err error
userID := int64(0) var userID int64
namespaceID, userIDstr := c.SignedInUser.GetTypedID() if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil {
if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { userID = id
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)
}
} }
cmd.OrgID = c.SignedInUser.GetOrgID() cmd.OrgID = c.SignedInUser.GetOrgID()
@ -632,16 +621,9 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
// 401: unauthorisedError // 401: unauthorisedError
// 500: internalServerError // 500: internalServerError
func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response { func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response {
userID := int64(0) var userID int64
var err error if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil {
namespaceID, userIDstr := c.SignedInUser.GetTypedID() userID = id
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)
}
} }
prefsQuery := pref.GetPreferenceWithDefaultsQuery{OrgID: c.SignedInUser.GetOrgID(), UserID: userID, Teams: c.SignedInUser.GetTeams()} 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) return response.Error(http.StatusNotFound, "Dashboard version not found", nil)
} }
userID := int64(0) var userID int64
namespaceID, userIDstr := c.SignedInUser.GetTypedID() if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil {
if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { userID = id
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)
}
} }
saveCmd := dashboards.SaveDashboardCommand{} saveCmd := dashboards.SaveDashboardCommand{}

View File

@ -442,11 +442,7 @@ func (hs *HTTPServer) AddDataSource(c *contextmodel.ReqContext) response.Respons
return response.Error(http.StatusBadRequest, "bad request data", err) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
userID, err := identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, _ := identity.UserIdentifier(c.SignedInUser.GetID())
if err != nil {
return response.Error(http.StatusInternalServerError,
"Failed to add datasource", err)
}
datasourcesLogger.Debug("Received command to add data source", "url", cmd.URL) datasourcesLogger.Debug("Received command to add data source", "url", cmd.URL)
cmd.OrgID = c.SignedInUser.GetOrgID() cmd.OrgID = c.SignedInUser.GetOrgID()

View File

@ -191,15 +191,13 @@ func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int
if !hs.Cfg.RBAC.PermissionsOnCreation("folder") { if !hs.Cfg.RBAC.PermissionsOnCreation("folder") {
return nil return nil
} }
var permissions []accesscontrol.SetResourcePermissionCommand
var userID int64
namespace, id := user.GetTypedID() var permissions []accesscontrol.SetResourcePermissionCommand
if namespace == identity.TypeUser {
var errID error if identity.IsIdentityType(user.GetID(), identity.TypeUser) {
userID, errID = identity.IntIdentifier(namespace, id) userID, err := identity.UserIdentifier(user.GetID())
if errID != nil { if err != nil {
return errID return err
} }
permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{

View File

@ -31,7 +31,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV
return nil, err 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} prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: userID, OrgID: c.SignedInUser.GetOrgID(), Teams: c.Teams}
prefs, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery) 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 { func (hs *HTTPServer) buildUserAnalyticsSettings(c *contextmodel.ReqContext) dtos.AnalyticsSettings {
namespace, _ := c.SignedInUser.GetTypedID()
// Anonymous users do not have an email or auth info // 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} return dtos.AnalyticsSettings{Identifier: "@" + hs.Cfg.AppURL}
} }

View File

@ -257,8 +257,7 @@ func (hs *HTTPServer) Logout(c *contextmodel.ReqContext) {
return return
} }
_, id := c.SignedInUser.GetTypedID() hs.log.Info("Successful Logout", "id", c.SignedInUser.GetID())
hs.log.Info("Successful Logout", "userID", id)
c.Redirect(redirect.URL) c.Redirect(redirect.URL)
} }
@ -305,7 +304,7 @@ func (hs *HTTPServer) redirectURLWithErrorCookie(c *contextmodel.ReqContext, err
var userID int64 var userID int64
if c.SignedInUser != nil && !c.SignedInUser.IsNil() { if c.SignedInUser != nil && !c.SignedInUser.IsNil() {
var errID error var errID error
userID, errID = identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, errID = identity.UserIdentifier(c.SignedInUser.GetID())
if errID != nil { if errID != nil {
hs.log.Error("failed to retrieve user ID", "error", errID) hs.log.Error("failed to retrieve user ID", "error", errID)
} }

View File

@ -132,12 +132,11 @@ func (hs *HTTPServer) CreateOrg(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
namespace, identifier := c.SignedInUser.GetTypedID() if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) {
if namespace != identity.TypeUser {
return response.Error(http.StatusForbidden, "Only users can create organizations", nil) 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 { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to parse user id", err) return response.Error(http.StatusInternalServerError, "Failed to parse user id", err)
} }

View File

@ -101,14 +101,9 @@ func (hs *HTTPServer) AddOrgInvite(c *contextmodel.ReqContext) response.Response
cmd.Name = inviteDto.Name cmd.Name = inviteDto.Name
cmd.Status = tempuser.TmpUserInvitePending cmd.Status = tempuser.TmpUserInvitePending
namespace, identifier := c.SignedInUser.GetTypedID()
var userID int64 var userID int64
if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil {
var err error userID = id
userID, err = strconv.ParseInt(identifier, 10, 64)
if err != nil {
return response.Error(http.StatusInternalServerError, "Unrecognized user", err)
}
} }
cmd.InvitedByUserID = userID cmd.InvitedByUserID = userID

View File

@ -22,9 +22,9 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp
return response.Error(http.StatusBadRequest, "bad request data", err) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if errID != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to set home dashboard", errID) return response.Error(http.StatusInternalServerError, "Failed to set home dashboard", err)
} }
cmd.UserID = userID cmd.UserID = userID
@ -64,9 +64,9 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp
// 401: unauthorisedError // 401: unauthorisedError
// 500: internalServerError // 500: internalServerError
func (hs *HTTPServer) GetUserPreferences(c *contextmodel.ReqContext) response.Response { func (hs *HTTPServer) GetUserPreferences(c *contextmodel.ReqContext) response.Response {
userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if errID != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to get user preferences", errID) 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) 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) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if errID != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update user preferences", errID) return response.Error(http.StatusInternalServerError, "Failed to update user preferences", err)
} }
return prefapi.UpdatePreferencesFor(c.Req.Context(), hs.DashboardService, 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) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if errID != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update user preferences", errID) return response.Error(http.StatusInternalServerError, "Failed to update user preferences", err)
} }
return hs.patchPreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), userID, 0, &dtoCmd) return hs.patchPreferencesFor(c.Req.Context(), c.SignedInUser.GetOrgID(), userID, 0, &dtoCmd)

View File

@ -65,9 +65,9 @@ func (hs *HTTPServer) RenderHandler(c *contextmodel.ReqContext) {
headers["Accept-Language"] = acceptLanguageHeader headers["Accept-Language"] = acceptLanguageHeader
} }
userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if errID != nil { if err != nil {
hs.log.Error("Failed to parse user id", "err", errID) hs.log.Debug("Failed to parse user id", "err", err)
} }
encoding := queryReader.Get("encoding", "") encoding := queryReader.Get("encoding", "")

View File

@ -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) return response.Error(http.StatusUnprocessableEntity, "User with same email address already exists", nil)
} }
userID, errID := identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if errID != nil { if err != nil {
hs.log.Error("Failed to parse user id", "err", errID) hs.log.Debug("Failed to parse user id", "err", err)
} }
cmd := tempuser.CreateTempUserCommand{} cmd := tempuser.CreateTempUserCommand{}

View File

@ -31,8 +31,7 @@ import (
// 404: notFoundError // 404: notFoundError
// 500: internalServerError // 500: internalServerError
func (hs *HTTPServer) GetSignedInUser(c *contextmodel.ReqContext) response.Response { func (hs *HTTPServer) GetSignedInUser(c *contextmodel.ReqContext) response.Response {
namespace, identifier := c.SignedInUser.GetTypedID() if !identity.IsIdentityType(c.GetID(), identity.TypeUser) {
if namespace != identity.TypeUser {
return response.JSON(http.StatusOK, user.UserProfileDTO{ return response.JSON(http.StatusOK, user.UserProfileDTO{
IsGrafanaAdmin: c.SignedInUser.GetIsGrafanaAdmin(), IsGrafanaAdmin: c.SignedInUser.GetIsGrafanaAdmin(),
OrgID: c.SignedInUser.GetOrgID(), 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 { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to parse user id", err) 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 { func (hs *HTTPServer) StartEmailVerificaton(c *contextmodel.ReqContext) response.Response {
namespace, id := c.SignedInUser.GetTypedID() if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) {
if !identity.IsIdentityType(namespace, identity.TypeUser) {
return response.Error(http.StatusBadRequest, "Only users can verify their email", nil) 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) return response.Respond(http.StatusNotModified, nil)
} }
userID, err := strconv.ParseInt(id, 10, 64) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Got invalid user id", err) return response.Error(http.StatusInternalServerError, "Got invalid user id", err)
} }
@ -506,13 +504,12 @@ func (hs *HTTPServer) ChangeActiveOrgAndRedirectToHome(c *contextmodel.ReqContex
return return
} }
namespace, identifier := c.SignedInUser.GetTypedID() if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) {
if namespace != identity.TypeUser {
c.JsonApiErr(http.StatusForbidden, "Endpoint only available for users", nil) c.JsonApiErr(http.StatusForbidden, "Endpoint only available for users", nil)
return return
} }
userID, err := identity.IntIdentifier(namespace, identifier) userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if err != nil { if err != nil {
c.JsonApiErr(http.StatusInternalServerError, "Failed to parse user id", err) c.JsonApiErr(http.StatusInternalServerError, "Failed to parse user id", err)
return return
@ -632,12 +629,11 @@ func (hs *HTTPServer) ClearHelpFlags(c *contextmodel.ReqContext) response.Respon
} }
func getUserID(c *contextmodel.ReqContext) (int64, *response.NormalResponse) { func getUserID(c *contextmodel.ReqContext) (int64, *response.NormalResponse) {
namespace, identifier := c.SignedInUser.GetTypedID() if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) {
if namespace != identity.TypeUser {
return 0, response.Error(http.StatusForbidden, "Endpoint only available for users", nil) 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 { if err != nil {
return 0, response.Error(http.StatusInternalServerError, "Failed to parse user id", err) return 0, response.Error(http.StatusInternalServerError, "Failed to parse user id", err)
} }

View File

@ -32,12 +32,11 @@ import (
// 403: forbiddenError // 403: forbiddenError
// 500: internalServerError // 500: internalServerError
func (hs *HTTPServer) GetUserAuthTokens(c *contextmodel.ReqContext) response.Response { func (hs *HTTPServer) GetUserAuthTokens(c *contextmodel.ReqContext) response.Response {
namespace, identifier := c.SignedInUser.GetTypedID() if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) {
if namespace != identity.TypeUser { return response.Error(http.StatusForbidden, "entity not allowed to get tokens", nil)
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 { if err != nil {
return response.Error(http.StatusInternalServerError, "failed to parse user id", err) 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) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
namespace, identifier := c.SignedInUser.GetTypedID() if !identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) {
if namespace != identity.TypeUser {
return response.Error(http.StatusForbidden, "entity not allowed to revoke tokens", nil) 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 { if err != nil {
return response.Error(http.StatusInternalServerError, "failed to parse user id", err) return response.Error(http.StatusInternalServerError, "failed to parse user id", err)
} }

View File

@ -7,6 +7,7 @@ import (
) )
var ( var (
ErrInvalidIDType = errutil.BadRequest("auth.identity.invalid-id-type")
ErrInvalidTypedID = errutil.BadRequest("auth.identity.invalid-typed-id") ErrInvalidTypedID = errutil.BadRequest("auth.identity.invalid-typed-id")
ErrNotIntIdentifier = errors.New("identifier is not an int64") ErrNotIntIdentifier = errors.New("identifier is not an int64")
ErrIdentifierNotInitialized = errors.New("identifier is not initialized") ErrIdentifierNotInitialized = errors.New("identifier is not initialized")

View File

@ -17,15 +17,9 @@ type Requester interface {
GetRawIdentifier() string GetRawIdentifier() string
// Deprecated: use GetUID instead // Deprecated: use GetUID instead
GetInternalID() (int64, error) GetInternalID() (int64, error)
// GetID returns namespaced internalID for the entity // GetID returns namespaced internalID for the entity
// Deprecated: use GetUID instead // Deprecated: use GetUID instead
GetID() TypedID 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. // GetDisplayName returns the display name of the active entity.
// The display name is the name if it is set, otherwise the login or email. // The display name is the name if it is set, otherwise the login or email.
GetDisplayName() string GetDisplayName() string
@ -82,14 +76,14 @@ type Requester interface {
GetIDClaims() *authnlib.Claims[authnlib.IDTokenClaims] 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. // Applicable for users, service accounts, api keys and renderer service.
// Errors if the identifier is not initialized or if namespace is not recognized. // Errors if the identifier is not initialized or if type is not recognized.
func IntIdentifier(kind IdentityType, identifier string) (int64, error) { func IntIdentifier(typedID TypedID) (int64, error) {
if IsIdentityType(kind, TypeUser, TypeAPIKey, TypeServiceAccount, TypeRenderService) { if IsIdentityType(typedID, TypeUser, TypeAPIKey, TypeServiceAccount, TypeRenderService) {
id, err := strconv.ParseInt(identifier, 10, 64) id, err := strconv.ParseInt(typedID.ID(), 10, 64)
if err != nil { 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 { if id < 1 {
@ -102,19 +96,18 @@ func IntIdentifier(kind IdentityType, identifier string) (int64, error) {
return 0, ErrNotIntIdentifier 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. // Errors if the identifier is not initialized or if namespace is not recognized.
// Returns 0 if the namespace is not user or service account // Returns 0 if the type is not user or service account
func UserIdentifier(kind IdentityType, identifier string) (int64, error) { func UserIdentifier(typedID TypedID) (int64, error) {
userID, err := IntIdentifier(kind, identifier) userID, err := IntIdentifier(typedID)
if err != nil { if err != nil {
// FIXME: return this error once entity namespaces are handled by stores return 0, err
return 0, nil
} }
if IsIdentityType(kind, TypeUser, TypeServiceAccount) { if IsIdentityType(typedID, TypeUser, TypeServiceAccount) {
return userID, nil return userID, nil
} }
return 0, nil return 0, ErrInvalidIDType
} }

View File

@ -149,12 +149,6 @@ func (u *StaticRequester) GetID() TypedID {
return NewTypedIDString(u.Type, fmt.Sprintf("%d", u.UserID)) 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 { func (u *StaticRequester) GetAuthID() string {
return u.AuthID return u.AuthID
} }

View File

@ -42,10 +42,10 @@ func ParseType(str string) (IdentityType, error) {
} }
} }
// IsIdentityType returns true if type matches any expected identity type // IsIdentityType returns true if typedID matches any expected identity type
func IsIdentityType(typ IdentityType, expected ...IdentityType) bool { func IsIdentityType(typedID TypedID, expected ...IdentityType) bool {
for _, e := range expected { for _, e := range expected {
if typ == e { if typedID.Type() == e {
return true return true
} }
} }
@ -128,7 +128,7 @@ func (ni TypedID) Type() IdentityType {
} }
func (ni TypedID) IsType(expected ...IdentityType) bool { func (ni TypedID) IsType(expected ...IdentityType) bool {
return IsIdentityType(ni.t, expected...) return IsIdentityType(ni, expected...)
} }
func (ni TypedID) String() string { func (ni TypedID) String() string {

View File

@ -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) { 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, "id", ident.GetID(), "orgID", ident.GetOrgID(), "permissions", eval.GoString())
a.log.FromContext(ctx).Debug(msg, "namespace", namespace, "id", id, "orgID", ident.GetOrgID(), "permissions", eval.GoString())
} }

View File

@ -128,7 +128,7 @@ func (s *Service) GetUserPermissions(ctx context.Context, user identity.Requeste
return s.getCachedUserPermissions(ctx, user, options) 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") ctx, span := s.tracer.Start(ctx, "authz.getUserPermissions")
defer span.End() defer span.End()
@ -143,10 +143,9 @@ func (s *Service) getUserPermissions(ctx context.Context, user identity.Requeste
permissions = append(permissions, SharedWithMeFolderPermission) permissions = append(permissions, SharedWithMeFolderPermission)
} }
userID, err := identity.UserIdentifier(user.GetTypedID()) // we don't care about the error here, if this fails we get 0 and no
if err != nil { // permission assigned to user will be returned, only for org role.
return nil, err userID, _ := identity.UserIdentifier(user.GetID())
}
dbPermissions, err := s.store.GetUserPermissions(ctx, accesscontrol.GetUserPermissionsQuery{ dbPermissions, err := s.store.GetUserPermissions(ctx, accesscontrol.GetUserPermissionsQuery{
OrgID: user.GetOrgID(), 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") ctx, span := s.tracer.Start(ctx, "authz.getUserDirectPermissions")
defer span.End() defer span.End()
namespace, identifier := user.GetTypedID()
var userID int64 var userID int64
if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { if identity.IsIdentityType(user.GetID(), identity.TypeUser, identity.TypeServiceAccount) {
var err error var err error
userID, err = strconv.ParseInt(identifier, 10, 64) userID, err = identity.UserIdentifier(user.GetID())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -80,11 +80,9 @@ func deny(c *contextmodel.ReqContext, evaluator Evaluator, err error) {
if err != nil { if err != nil {
c.Logger.Error("Error from access control system", "error", err, "accessErrorID", id) c.Logger.Error("Error from access control system", "error", err, "accessErrorID", id)
} else { } else {
namespace, identifier := c.SignedInUser.GetTypedID()
c.Logger.Info( c.Logger.Info(
"Access denied", "Access denied",
"namespace", namespace, "id", c.SignedInUser.GetID(),
"userID", identifier,
"accessErrorID", id, "accessErrorID", id,
"permissions", evaluator.GoString(), "permissions", evaluator.GoString(),
) )

View File

@ -70,12 +70,10 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
idClaims *auth.IDClaims idClaims *auth.IDClaims
} }
result, err, _ := s.si.Do(cacheKey, func() (any, error) { result, err, _ := s.si.Do(cacheKey, func() (any, error) {
namespace, identifier := id.GetTypedID()
cachedToken, err := s.cache.Get(ctx, cacheKey) cachedToken, err := s.cache.Get(ctx, cacheKey)
if err == nil { if err == nil {
s.metrics.tokenSigningFromCacheCounter.Inc() 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)) tokenClaims, err := s.extractTokenClaims(string(cachedToken))
if err != nil { if err != nil {
@ -85,14 +83,14 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
} }
s.metrics.tokenSigningCounter.Inc() 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() now := time.Now()
claims := &auth.IDClaims{ claims := &auth.IDClaims{
Claims: &jwt.Claims{ Claims: &jwt.Claims{
Issuer: s.cfg.AppURL, Issuer: s.cfg.AppURL,
Audience: getAudience(id.GetOrgID()), Audience: getAudience(id.GetOrgID()),
Subject: getSubject(namespace.String(), identifier), Subject: id.GetID().String(),
Expiry: jwt.NewNumericDate(now.Add(tokenTTL)), Expiry: jwt.NewNumericDate(now.Add(tokenTTL)),
IssuedAt: jwt.NewNumericDate(now), 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.Email = id.GetEmail()
claims.Rest.EmailVerified = id.IsEmailVerified() claims.Rest.EmailVerified = id.IsEmailVerified()
claims.Rest.AuthenticatedBy = id.GetAuthenticatedBy() 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) token, claims, err := s.SignIdentity(ctx, identity)
if err != nil { if err != nil {
if shouldLogErr(err) { if shouldLogErr(err) {
namespace, id := identity.GetTypedID() s.logger.FromContext(ctx).Error("Failed to sign id token", "err", err, "id", identity.GetID())
s.logger.FromContext(ctx).Error("Failed to sign id token", "err", err, "namespace", namespace, "id", id)
} }
// for now don't return error so we don't break authentication from this hook // for now don't return error so we don't break authentication from this hook
return nil return nil
@ -179,10 +176,6 @@ func getAudience(orgID int64) jwt.Audience {
return jwt.Audience{fmt.Sprintf("org:%d", orgID)} 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 { func prefixCacheKey(key string) string {
return fmt.Sprintf("%s-%s", cachePrefix, key) return fmt.Sprintf("%s-%s", cachePrefix, key)
} }

View File

@ -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) { func (c *OAuth) Logout(ctx context.Context, user identity.Requester) (*authn.Redirect, bool) {
token := c.oauthService.GetCurrentOAuthToken(ctx, user) token := c.oauthService.GetCurrentOAuthToken(ctx, user)
namespace, id := user.GetTypedID() userID, err := identity.UserIdentifier(user.GetID())
userID, err := identity.UserIdentifier(namespace, id)
if err != nil { 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 return nil, false
} }
@ -260,8 +259,7 @@ func (c *OAuth) Logout(ctx context.Context, user identity.Requester) (*authn.Red
AuthId: user.GetAuthID(), AuthId: user.GetAuthID(),
AuthModule: user.GetAuthenticatedBy(), AuthModule: user.GetAuthenticatedBy(),
}); err != nil { }); err != nil {
namespace, id := user.GetTypedID() c.log.FromContext(ctx).Error("Failed to invalidate tokens", "id", user.GetID(), "error", err)
c.log.FromContext(ctx).Error("Failed to invalidate tokens", "namespace", namespace, "id", id, "error", err)
} }
oauthCfg := c.socialService.GetOAuthInfoProvider(c.providerName) oauthCfg := c.socialService.GetOAuthInfoProvider(c.providerName)

View File

@ -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()) 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) assert.Equal(t, tt.expectedOK, ok)
if tt.expectedOK { if tt.expectedOK {

View File

@ -115,10 +115,6 @@ func (i *Identity) GetID() identity.TypedID {
return i.ID return i.ID
} }
func (i *Identity) GetTypedID() (namespace identity.IdentityType, identifier string) {
return i.ID.Type(), i.ID.ID()
}
func (i *Identity) GetUID() string { func (i *Identity) GetUID() string {
return i.UID.String() return i.UID.String()
} }
@ -132,14 +128,14 @@ func (i *Identity) GetAuthenticatedBy() string {
} }
func (i *Identity) GetCacheKey() string { func (i *Identity) GetCacheKey() string {
namespace, id := i.GetTypedID() id := i.GetID().ID()
if !i.HasUniqueId() { if !i.HasUniqueId() {
// Hack use the org role as id for identities that do not have a unique id // Hack use the org role as id for identities that do not have a unique id
// e.g. anonymous and render key. // e.g. anonymous and render key.
id = string(i.GetOrgRole()) 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 { func (i *Identity) GetDisplayName() string {
@ -232,10 +228,10 @@ func (i *Identity) HasRole(role org.RoleType) bool {
} }
func (i *Identity) HasUniqueId() bool { func (i *Identity) HasUniqueId() bool {
namespace, _ := i.GetTypedID() typ := i.GetID().Type()
return namespace == identity.TypeUser || return typ == identity.TypeUser ||
namespace == identity.TypeServiceAccount || typ == identity.TypeServiceAccount ||
namespace == identity.TypeAPIKey typ == identity.TypeAPIKey
} }
func (i *Identity) IsAuthenticatedBy(providers ...string) bool { func (i *Identity) IsAuthenticatedBy(providers ...string) bool {

View File

@ -154,22 +154,22 @@ func (h *ContextHandler) addIDHeaderEndOfRequestFunc(ident identity.Requester) w
return return
} }
namespace, id := ident.GetTypedID() id := ident.GetID()
if !identity.IsIdentityType( if !identity.IsIdentityType(
namespace, id,
identity.TypeUser, identity.TypeUser,
identity.TypeServiceAccount, identity.TypeServiceAccount,
identity.TypeAPIKey, identity.TypeAPIKey,
) || id == "0" { ) || id.ID() == "0" {
return return
} }
if _, ok := h.Cfg.IDResponseHeaderNamespaces[namespace.String()]; !ok { if _, ok := h.Cfg.IDResponseHeaderNamespaces[id.Type().String()]; !ok {
return return
} }
headerName := fmt.Sprintf("%s-Identity-Id", h.Cfg.IDResponseHeaderPrefix) 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())
} }
} }

View File

@ -109,11 +109,9 @@ func (s *ImportDashboardService) ImportDashboard(ctx context.Context, req *dashb
req.FolderUid = folder.UID req.FolderUid = folder.UID
} }
namespace, identifier := req.User.GetTypedID() var userID int64
userID := int64(0) if id, err := identity.UserIdentifier(req.User.GetID()); err == nil {
userID = id
if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount {
userID, _ = identity.IntIdentifier(namespace, identifier)
} }
saveCmd := dashboards.SaveDashboardCommand{ saveCmd := dashboards.SaveDashboardCommand{

View File

@ -83,7 +83,7 @@ func TestImportDashboardService(t *testing.T) {
require.NotNil(t, resp) require.NotNil(t, resp)
require.Equal(t, "UDdpyzz7z", resp.UID) require.Equal(t, "UDdpyzz7z", resp.UID)
userID, err := identity.IntIdentifier(importDashboardArg.User.GetTypedID()) userID, err := identity.IntIdentifier(importDashboardArg.User.GetID())
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, importDashboardArg) require.NotNil(t, importDashboardArg)
@ -149,7 +149,7 @@ func TestImportDashboardService(t *testing.T) {
require.NotNil(t, resp) require.NotNil(t, resp)
require.Equal(t, "UDdpyzz7z", resp.UID) require.Equal(t, "UDdpyzz7z", resp.UID)
userID, err := identity.IntIdentifier(importDashboardArg.User.GetTypedID()) userID, err := identity.IntIdentifier(importDashboardArg.User.GetID())
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, importDashboardArg) require.NotNil(t, importDashboardArg)

View File

@ -207,9 +207,11 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
} }
} }
userID, err := resolveUserID(dto.User, dr.log) var userID int64
if err != nil { if id, err := identity.UserIdentifier(dto.User.GetID()); err == nil {
return nil, err 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() metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
@ -232,22 +234,6 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
return cmd, nil 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 { func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *dashboards.DeleteOrphanedProvisionedDashboardsCommand) error {
return dr.dashboardStore.DeleteOrphanedProvisionedDashboards(ctx, cmd) return dr.dashboardStore.DeleteOrphanedProvisionedDashboards(ctx, cmd)
} }
@ -503,12 +489,10 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
var permissions []accesscontrol.SetResourcePermissionCommand var permissions []accesscontrol.SetResourcePermissionCommand
if !provisioned { if !provisioned {
namespaceID, userIDstr := dto.User.GetTypedID() userID, err := identity.IntIdentifier(dto.User.GetID())
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil { if err != nil {
dr.log.Error("Could not make user admin", "dashboard", dash.Title, "namespaceID", namespaceID, "userID", userID, "error", err) dr.log.Error("Could not make user admin", "dashboard", dash.Title, "id", dto.User.GetID(), "error", err)
} else if namespaceID == identity.TypeUser && userID > 0 { } else if identity.IsIdentityType(dto.User.GetID(), identity.TypeUser) {
permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{
UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(), UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(),
}) })
@ -541,12 +525,10 @@ func (dr *DashboardServiceImpl) setDefaultFolderPermissions(ctx context.Context,
var permissions []accesscontrol.SetResourcePermissionCommand var permissions []accesscontrol.SetResourcePermissionCommand
if !provisioned { if !provisioned {
namespaceID, userIDstr := cmd.SignedInUser.GetTypedID() userID, err := identity.IntIdentifier(cmd.SignedInUser.GetID())
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
if err != nil { if err != nil {
dr.log.Error("Could not make user admin", "folder", cmd.Title, "namespaceID", namespaceID, "userID", userID, "error", err) dr.log.Error("Could not make user admin", "folder", cmd.Title, "id", cmd.SignedInUser.GetID())
} else if namespaceID == identity.TypeUser && userID > 0 { } else if identity.IsIdentityType(cmd.SignedInUser.GetID(), identity.TypeUser) {
permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{
UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(), UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(),
}) })

View File

@ -116,7 +116,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sqlStore) err := callSaveWithError(t, cmd, sqlStore)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "", sc.dashboardGuardianMock.DashUID) assert.Equal(t, "", sc.dashboardGuardianMock.DashUID)
@ -139,7 +139,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.otherSavedFolder.ID, sc.dashboardGuardianMock.DashID) assert.Equal(t, sc.otherSavedFolder.ID, sc.dashboardGuardianMock.DashID)
@ -162,7 +162,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
@ -186,7 +186,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
@ -210,7 +210,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
@ -234,7 +234,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
@ -258,7 +258,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
@ -282,7 +282,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)
@ -306,7 +306,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInGeneralFolder.UID, sc.dashboardGuardianMock.DashUID)
@ -330,7 +330,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
err := callSaveWithError(t, cmd, sc.sqlStore) err := callSaveWithError(t, cmd, sc.sqlStore)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetTypedID()) userID, err := identity.IntIdentifier(sc.dashboardGuardianMock.User.GetID())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID) assert.Equal(t, sc.savedDashInFolder.UID, sc.dashboardGuardianMock.DashUID)

View File

@ -122,12 +122,10 @@ func (d *DashboardSnapshotStore) SearchDashboardSnapshots(ctx context.Context, q
sess.Where("name LIKE ?", query.Name) sess.Where("name LIKE ?", query.Name)
} }
namespace, id := query.SignedInUser.GetTypedID()
var userID int64 var userID int64
if identity.IsIdentityType(query.SignedInUser.GetID(), identity.TypeUser, identity.TypeServiceAccount) {
if namespace == identity.TypeServiceAccount || namespace == identity.TypeUser {
var err error var err error
userID, err = identity.IntIdentifier(namespace, id) userID, err = identity.UserIdentifier(query.SignedInUser.GetID())
if err != nil { if err != nil {
return err return err
} }
@ -137,7 +135,7 @@ func (d *DashboardSnapshotStore) SearchDashboardSnapshots(ctx context.Context, q
switch { switch {
case query.SignedInUser.GetOrgRole() == org.RoleAdmin: case query.SignedInUser.GetOrgRole() == org.RoleAdmin:
sess.Where("org_id = ?", query.SignedInUser.GetOrgID()) sess.Where("org_id = ?", query.SignedInUser.GetOrgID())
case namespace != identity.TypeAnonymous: case userID != 0:
sess.Where("org_id = ? AND user_id = ?", query.OrgID, userID) sess.Where("org_id = ? AND user_id = ?", query.OrgID, userID)
default: default:
queryResult = snapshots queryResult = snapshots

View File

@ -63,17 +63,10 @@ func CreateDashboardSnapshot(c *contextmodel.ReqContext, cfg dashboardsnapshot.S
cmd.DashboardCreateCommand.Name = "Unnamed snapshot" 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 var snapshotUrl string
cmd.ExternalURL = "" cmd.ExternalURL = ""
cmd.OrgID = user.GetOrgID() cmd.OrgID = user.GetOrgID()
cmd.UserID = userID cmd.UserID, _ = identity.UserIdentifier(user.GetID())
originalDashboardURL, err := createOriginalDashboardURL(&cmd) originalDashboardURL, err := createOriginalDashboardURL(&cmd)
if err != nil { if err != nil {
c.JsonApiErr(http.StatusInternalServerError, "Invalid app URL", err) c.JsonApiErr(http.StatusInternalServerError, "Invalid app URL", err)

View File

@ -592,21 +592,17 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (
user := cmd.SignedInUser user := cmd.SignedInUser
userID := int64(0) var userID int64
var err error if id, err := identity.UserIdentifier(cmd.SignedInUser.GetID()); err == nil {
namespaceID, userIDstr := user.GetTypedID() userID = id
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)
} else { } else {
userID, err = identity.IntIdentifier(namespaceID, userIDstr) s.log.Warn("User does not belong to a user or service account namespace, using 0 as user ID", "id", cmd.SignedInUser.GetID())
if err != nil {
s.log.Debug("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err)
}
} }
if userID == 0 { if userID == 0 {
userID = -1 userID = -1
} }
dashFolder.CreatedBy = userID dashFolder.CreatedBy = userID
dashFolder.UpdatedBy = userID dashFolder.UpdatedBy = userID
dashFolder.UpdateSlug() dashFolder.UpdateSlug()
@ -682,8 +678,6 @@ func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) (
} }
if cmd.NewTitle != nil { if cmd.NewTitle != nil {
namespace, id := cmd.SignedInUser.GetTypedID()
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc() metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()
if err := s.bus.Publish(ctx, &events.FolderTitleUpdated{ if err := s.bus.Publish(ctx, &events.FolderTitleUpdated{
Timestamp: foldr.Updated, Timestamp: foldr.Updated,
@ -692,7 +686,7 @@ func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) (
UID: dashFolder.UID, UID: dashFolder.UID,
OrgID: cmd.OrgID, OrgID: cmd.OrgID,
}); err != nil { }); 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 return err
} }
} }
@ -739,12 +733,10 @@ func (s *Service) legacyUpdate(ctx context.Context, cmd *folder.UpdateFolderComm
} }
var userID int64 var userID int64
namespace, id := cmd.SignedInUser.GetTypedID() if id, err := identity.UserIdentifier(cmd.SignedInUser.GetID()); err == nil {
if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { userID = id
userID, err = identity.IntIdentifier(namespace, id) } else {
if err != nil { s.log.Warn("User does not belong to a user or service account namespace, using 0 as user ID", "id", cmd.SignedInUser.GetID())
s.log.ErrorContext(ctx, "failed to parse user ID", "namespace", namespace, "userID", id, "error", err)
}
} }
prepareForUpdate(dashFolder, cmd.OrgID, userID, cmd) prepareForUpdate(dashFolder, cmd.OrgID, userID, cmd)
@ -1163,15 +1155,11 @@ func (s *Service) buildSaveDashboardCommand(ctx context.Context, dto *dashboards
} }
} }
userID := int64(0) var userID int64
namespaceID, userIDstr := dto.User.GetTypedID() if id, err := identity.UserIdentifier(dto.User.GetID()); err == nil {
if namespaceID != identity.TypeUser && namespaceID != identity.TypeServiceAccount { userID = id
s.log.Warn("User does not belong to a user or service account namespace, using 0 as user ID", "namespaceID", namespaceID, "userID", userIDstr)
} else { } else {
userID, err = identity.IntIdentifier(namespaceID, userIDstr) s.log.Warn("User does not belong to a user or service account namespace, using 0 as user ID", "id", dto.User.GetID())
if err != nil {
s.log.Warn("failed to parse user ID", "namespaceID", namespaceID, "userID", userIDstr, "error", err)
}
} }
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc() metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()

View File

@ -309,13 +309,12 @@ func (a *accessControlFolderGuardian) CanCreate(folderID int64, isFolder bool) (
func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) { func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator) ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
namespaceID, userID := a.user.GetTypedID()
if err != nil { if err != nil {
id := 0 id := 0
if a.dashboard != nil { if a.dashboard != nil {
id = int(a.dashboard.ID) id = int(a.dashboard.ID)
} }
a.log.Debug("Failed to evaluate access control to dashboard", "error", err, "namespaceID", namespaceID, "userId", userID, "id", id) a.log.Debug("Failed to evaluate access control to dashboard", "error", err, "identity", a.user.GetID(), "id", id)
} }
if !ok && err == nil { if !ok && err == nil {
@ -323,7 +322,7 @@ func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evalua
if a.dashboard != nil { if a.dashboard != nil {
id = int(a.dashboard.ID) id = int(a.dashboard.ID)
} }
a.log.Debug("Access denied to dashboard", "namespaceID", namespaceID, "userId", userID, "id", id, "permissions", evaluator.GoString()) a.log.Debug("Access denied to dashboard", "identity", a.user.GetID(), "id", id, "permissions", evaluator.GoString())
} }
return ok, err return ok, err
@ -331,7 +330,6 @@ func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evalua
func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) { func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator) ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
namespaceID, userID := a.user.GetTypedID()
if err != nil { if err != nil {
uid := "" uid := ""
orgID := 0 orgID := 0
@ -339,7 +337,7 @@ func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator
uid = a.folder.UID uid = a.folder.UID
orgID = int(a.folder.OrgID) orgID = int(a.folder.OrgID)
} }
a.log.Debug("Failed to evaluate access control to folder", "error", err, "namespaceID", namespaceID, "userId", userID, "orgID", orgID, "uid", uid) a.log.Debug("Failed to evaluate access control to folder", "error", err, "identity", a.user.GetID(), "orgID", orgID, "uid", uid)
} }
if !ok && err == nil { if !ok && err == nil {
@ -349,7 +347,7 @@ func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator
uid = a.folder.UID uid = a.folder.UID
orgID = int(a.folder.OrgID) orgID = int(a.folder.OrgID)
} }
a.log.Debug("Access denied to folder", "namespaceID", namespaceID, "userId", userID, "orgID", orgID, "uid", uid, "permissions", evaluator.GoString()) a.log.Debug("Access denied to folder", "identity", a.user.GetID(), "identity", a.user.GetID(), "orgID", orgID, "uid", uid, "permissions", evaluator.GoString())
} }
return ok, err return ok, err

View File

@ -138,13 +138,9 @@ func (l *LibraryElementService) createLibraryElement(c context.Context, signedIn
} }
} }
userID := int64(0) var userID int64
namespaceID, identifier := signedInUser.GetTypedID() if id, err := identity.UserIdentifier(signedInUser.GetID()); err == nil {
if namespaceID == identity.TypeUser || namespaceID == identity.TypeServiceAccount { userID = id
userID, err = identity.IntIdentifier(namespaceID, identifier)
if err != nil {
l.log.Warn("Error while parsing userID", "namespaceID", namespaceID, "userID", identifier)
}
} }
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryElements).Inc() metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryElements).Inc()
@ -593,13 +589,8 @@ func (l *LibraryElementService) patchLibraryElement(c context.Context, signedInU
} }
var userID int64 var userID int64
namespaceID, identifier := signedInUser.GetTypedID() if id, err := identity.UserIdentifier(signedInUser.GetID()); err == nil {
if namespaceID == identity.TypeUser || namespaceID == identity.TypeServiceAccount { userID = id
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)
}
} }
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryElements).Inc() metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryElements).Inc()
@ -800,13 +791,9 @@ func (l *LibraryElementService) connectElementsToDashboardID(c context.Context,
return err return err
} }
namespaceID, identifier := signedInUser.GetTypedID() var userID int64
userID := int64(0) if id, err := identity.UserIdentifier(signedInUser.GetID()); err == nil {
if namespaceID == identity.TypeUser || namespaceID == identity.TypeServiceAccount { userID = id
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)
}
} }
connection := model.LibraryElementConnection{ connection := model.LibraryElementConnection{

View File

@ -284,11 +284,9 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
g.websocketHandler = func(ctx *contextmodel.ReqContext) { g.websocketHandler = func(ctx *contextmodel.ReqContext) {
user := ctx.SignedInUser user := ctx.SignedInUser
_, identifier := user.GetTypedID()
// Centrifuge expects Credentials in context with a current user ID. // Centrifuge expects Credentials in context with a current user ID.
cred := &centrifuge.Credentials{ cred := &centrifuge.Credentials{
UserID: identifier, UserID: user.GetID().ID(),
} }
newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred) newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred)
newCtx = livecontext.SetContextSignedUser(newCtx, user) 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) return response.Error(http.StatusBadRequest, "invalid channel ID", nil)
} }
namespaceID, userID := ctx.SignedInUser.GetTypedID() logger.Debug("Publish API cmd", "identity", ctx.SignedInUser.GetID(), "channel", cmd.Channel)
logger.Debug("Publish API cmd", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel)
user := ctx.SignedInUser user := ctx.SignedInUser
channel := cmd.Channel channel := cmd.Channel
@ -1013,7 +1010,7 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil) return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil)
} }
} }
logger.Debug("Publication successful", "namespaceID", namespaceID, "userID", userID, "channel", cmd.Channel) logger.Debug("Publication successful", "identity", ctx.SignedInUser.GetID(), "channel", cmd.Channel)
return response.JSON(http.StatusOK, dtos.LivePublishResponse{}) return response.JSON(http.StatusOK, dtos.LivePublishResponse{})
} }

View File

@ -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) { 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.NoError(t, err)
require.Equal(t, int64(2), userID) require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID()) 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) { 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.NoError(t, err)
require.Equal(t, int64(2), userID) require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID()) 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) { 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.NoError(t, err)
require.Equal(t, int64(2), userID) 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) { 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.NoError(t, err)
require.Equal(t, int64(2), userID) require.Equal(t, int64(2), userID)
require.Equal(t, int64(1), user.GetOrgID()) require.Equal(t, int64(1), user.GetOrgID())

View File

@ -297,7 +297,7 @@ func (s *ServiceImpl) getProfileNode(c *contextmodel.ReqContext) *navtree.NavLin
func (s *ServiceImpl) buildStarredItemsNavLinks(c *contextmodel.ReqContext) ([]*navtree.NavLink, error) { func (s *ServiceImpl) buildStarredItemsNavLinks(c *contextmodel.ReqContext) ([]*navtree.NavLink, error) {
starredItemsChildNavs := []*navtree.NavLink{} starredItemsChildNavs := []*navtree.NavLink{}
userID, _ := identity.UserIdentifier(c.SignedInUser.GetTypedID()) userID, _ := identity.UserIdentifier(c.SignedInUser.GetID())
query := star.GetUserStarsQuery{ query := star.GetUserStarsQuery{
UserID: userID, UserID: userID,
} }

View File

@ -76,9 +76,9 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *contextmodel.ReqContext, namespaceU
return toNamespaceErrorResponse(err) return toNamespaceErrorResponse(err)
} }
userNamespace, id := c.SignedInUser.GetTypedID() userNamespace, id := c.SignedInUser.GetID().Type(), c.SignedInUser.GetID().ID()
var loggerCtx = []any{ var loggerCtx = []any{
"userId", "identity",
id, id,
"userNamespace", "userNamespace",
userNamespace, userNamespace,
@ -283,7 +283,7 @@ func (srv RulerSrv) RouteGetRulesConfig(c *contextmodel.ReqContext) response.Res
for groupKey, rules := range configs { for groupKey, rules := range configs {
folder, ok := namespaceMap[groupKey.NamespaceUID] folder, ok := namespaceMap[groupKey.NamespaceUID]
if !ok { 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) srv.log.Error("Namespace not visible to the user", "user", id, "userNamespace", userNamespace, "namespace", groupKey.NamespaceUID)
continue continue
} }
@ -359,7 +359,7 @@ func (srv RulerSrv) updateAlertRulesInGroup(c *contextmodel.ReqContext, groupKey
var finalChanges *store.GroupDelta var finalChanges *store.GroupDelta
var dbConfig *ngmodels.AlertConfiguration var dbConfig *ngmodels.AlertConfiguration
err := srv.xactManager.InTransaction(c.Req.Context(), func(tranCtx context.Context) error { 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", logger := srv.log.New("namespace_uid", groupKey.NamespaceUID, "group",
groupKey.RuleGroup, "org_id", groupKey.OrgID, "user_id", id, "userNamespace", userNamespace) groupKey.RuleGroup, "org_id", groupKey.OrgID, "user_id", id, "userNamespace", userNamespace)
groupChanges, err := store.CalculateChanges(tranCtx, srv.store, groupKey, rules) 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 { 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, &quota.ScopeParameters{ limitReached, err := srv.QuotaService.CheckQuotaReached(tranCtx, ngmodels.QuotaTargetSrv, &quota.ScopeParameters{
OrgID: c.SignedInUser.GetOrgID(), OrgID: c.SignedInUser.GetOrgID(),
UserID: userID, UserID: userID,

View File

@ -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. // 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 { func (service *AlertRuleService) checkLimitsTransactionCtx(ctx context.Context, user identity.Requester) error {
// default to 0 if there is no user // default to 0 if there is no user
userID := int64(0) var userID int64
u, err := identity.UserIdentifier(user.GetTypedID()) if id, err := identity.UserIdentifier(user.GetID()); err == nil {
if err != nil { userID = id
return fmt.Errorf("failed to check alert rule quota: %w", err)
} }
userID = u
limitReached, err := service.quotas.CheckQuotaReached(ctx, models.QuotaTargetSrv, &quota.ScopeParameters{ limitReached, err := service.quotas.CheckQuotaReached(ctx, models.QuotaTargetSrv, &quota.ScopeParameters{
OrgID: user.GetOrgID(), OrgID: user.GetOrgID(),

View File

@ -94,17 +94,14 @@ func (o *Service) HasOAuthEntry(ctx context.Context, usr identity.Requester) (*l
return nil, false, nil return nil, false, nil
} }
namespace, id := usr.GetTypedID() if !identity.IsIdentityType(usr.GetID(), identity.TypeUser) {
if namespace != identity.TypeUser {
// Not a user, therefore no token.
return nil, false, nil return nil, false, nil
} }
ctxLogger := logger.FromContext(ctx) ctxLogger := logger.FromContext(ctx)
userID, err := identity.UserIdentifier(usr.GetID())
userID, err := identity.IntIdentifier(namespace, id)
if err != nil { 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 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 // 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 // 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 { func (o *Service) TryTokenRefresh(ctx context.Context, usr identity.Requester) error {
ctxLogger := logger.FromContext(ctx)
if usr == nil || usr.IsNil() { 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. // Not user, no token.
return nil return nil
} }
namespace, id := usr.GetTypedID() if !identity.IsIdentityType(usr.GetID(), identity.TypeUser) {
if namespace != identity.TypeUser { ctxLogger.Warn("Can only refresh OAuth tokens for users", "id", usr.GetID())
// Not a user, therefore no token.
logger.Warn("Can only refresh OAuth tokens for users", "namespace", namespace, "userId", id)
return nil return nil
} }
ctxLogger := logger.FromContext(ctx) userID, err := identity.UserIdentifier(usr.GetID())
userID, err := identity.IntIdentifier(namespace, id)
if err != nil { 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 return nil
} }

View File

@ -35,8 +35,7 @@ func (m *UserHeaderMiddleware) applyUserHeader(ctx context.Context, h backend.Fo
} }
h.DeleteHTTPHeader(proxyutil.UserHeaderName) h.DeleteHTTPHeader(proxyutil.UserHeaderName)
namespace, _ := reqCtx.SignedInUser.GetTypedID() if !identity.IsIdentityType(reqCtx.SignedInUser.GetID(), identity.TypeAnonymous) {
if namespace != identity.TypeAnonymous {
h.SetHTTPHeader(proxyutil.UserHeaderName, reqCtx.SignedInUser.GetLogin()) h.SetHTTPHeader(proxyutil.UserHeaderName, reqCtx.SignedInUser.GetLogin())
} }
} }

View File

@ -99,8 +99,7 @@ func (api *ServiceAccountsAPI) CreateServiceAccount(c *contextmodel.ReqContext)
} }
if api.cfg.RBAC.PermissionsOnCreation("service-account") { if api.cfg.RBAC.PermissionsOnCreation("service-account") {
t, _ := c.SignedInUser.GetTypedID() if identity.IsIdentityType(c.SignedInUser.GetID(), identity.TypeUser) {
if t == identity.TypeUser {
userID, err := c.SignedInUser.GetID().ParseInt() userID, err := c.SignedInUser.GetID().ParseInt()
if err != nil { if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to parse user id", err) return response.Error(http.StatusInternalServerError, "Failed to parse user id", err)

View File

@ -165,10 +165,9 @@ func (f *accessControlDashboardPermissionFilter) buildClauses() {
dashWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeDashboardsPrefix) dashWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeDashboardsPrefix)
folderWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeFoldersPrefix) folderWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeFoldersPrefix)
userID := int64(0) var userID int64
namespace, identifier := f.user.GetTypedID() if id, err := identity.UserIdentifier(f.user.GetID()); err == nil {
if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { userID = id
userID, _ = identity.IntIdentifier(namespace, identifier)
} }
orgID := f.user.GetOrgID() orgID := f.user.GetOrgID()

View File

@ -33,10 +33,9 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) buildClauses()
dashWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeDashboardsPrefix) dashWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeDashboardsPrefix)
folderWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeFoldersPrefix) folderWildcards := accesscontrol.WildcardsFromPrefix(dashboards.ScopeFoldersPrefix)
userID := int64(0) var userID int64
namespace, identifier := f.user.GetTypedID() if id, err := identity.UserIdentifier(f.user.GetID()); err == nil {
if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount { userID = id
userID, _ = identity.IntIdentifier(namespace, identifier)
} }
orgID := f.user.GetOrgID() orgID := f.user.GetOrgID()

View File

@ -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 { func (api *API) GetStars(c *contextmodel.ReqContext) response.Response {
namespace, identifier := c.SignedInUser.GetTypedID() userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
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)
if err != nil { 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{ query := star.GetUserStarsQuery{
@ -101,17 +96,12 @@ func (api *API) GetStars(c *contextmodel.ReqContext) response.Response {
// 403: forbiddenError // 403: forbiddenError
// 500: internalServerError // 500: internalServerError
func (api *API) StarDashboard(c *contextmodel.ReqContext) response.Response { func (api *API) StarDashboard(c *contextmodel.ReqContext) response.Response {
namespace, identifier := c.SignedInUser.GetTypedID() userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if namespace != identity.TypeUser && namespace != identity.TypeServiceAccount { if err != nil {
return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil) return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", nil)
} }
userID, err := identity.IntIdentifier(namespace, identifier) id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64)
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)
if err != nil { if err != nil {
return response.Error(http.StatusBadRequest, "Invalid dashboard ID", 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) return response.Error(http.StatusBadRequest, "Invalid dashboard UID", nil)
} }
namespace, identifier := c.SignedInUser.GetTypedID() userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
if namespace != identity.TypeUser && namespace != identity.TypeServiceAccount { if err != nil {
return response.Error(http.StatusBadRequest, "Only users and service accounts can star dashboards", 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) dash, rsp := api.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid)
if rsp != nil { if rsp != nil {
return rsp return rsp
} }
@ -193,14 +177,9 @@ func (api *API) UnstarDashboard(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "Invalid dashboard ID", nil) return response.Error(http.StatusBadRequest, "Invalid dashboard ID", nil)
} }
namespace, identifier := c.SignedInUser.GetTypedID() userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
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)
if err != nil { 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} 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) return response.Error(http.StatusBadRequest, "Invalid dashboard UID", nil)
} }
namespace, identifier := c.SignedInUser.GetTypedID() userID, err := identity.UserIdentifier(c.SignedInUser.GetID())
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)
if err != nil { 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) dash, rsp := api.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid)

View File

@ -49,7 +49,7 @@ func (tapi *TeamAPI) createTeam(c *contextmodel.ReqContext) response.Response {
// if the request is authenticated using API tokens // if the request is authenticated using API tokens
// the SignedInUser is an empty struct therefore // the SignedInUser is an empty struct therefore
// an additional check whether it is an actual user is required // 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 { switch namespace {
case identity.TypeUser: case identity.TypeUser:
userID, err := strconv.ParseInt(identifier, 10, 64) userID, err := strconv.ParseInt(identifier, 10, 64)

View File

@ -169,7 +169,7 @@ func (u *SignedInUser) GetAllowedKubernetesNamespace() string {
// GetCacheKey returns a unique key for the entity. // GetCacheKey returns a unique key for the entity.
// Add an extra prefix to avoid collisions with other caches // Add an extra prefix to avoid collisions with other caches
func (u *SignedInUser) GetCacheKey() string { func (u *SignedInUser) GetCacheKey() string {
namespace, id := u.GetTypedID() typ, id := u.GetID().Type(), u.GetID().ID()
if !u.HasUniqueId() { if !u.HasUniqueId() {
// Hack use the org role as id for identities that do not have a unique id // Hack use the org role as id for identities that do not have a unique id
// e.g. anonymous and render key. // e.g. anonymous and render key.
@ -181,7 +181,7 @@ func (u *SignedInUser) GetCacheKey() string {
id = string(orgRole) 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 // 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 // GetID returns namespaced id for the entity
func (u *SignedInUser) GetID() identity.TypedID { func (u *SignedInUser) GetID() identity.TypedID {
ns, id := u.GetTypedID() ns, id := u.getTypeAndID()
return identity.NewTypedIDString(ns, id) return identity.NewTypedIDString(ns, id)
} }
// GetTypedID returns the namespace and ID of the active entity func (u *SignedInUser) getTypeAndID() (identity.IdentityType, string) {
// The namespace is one of the constants defined in pkg/apimachinery/identity
func (u *SignedInUser) GetTypedID() (identity.IdentityType, string) {
switch { switch {
case u.ApiKeyID != 0: case u.ApiKeyID != 0:
return identity.TypeAPIKey, strconv.FormatInt(u.ApiKeyID, 10) return identity.TypeAPIKey, strconv.FormatInt(u.ApiKeyID, 10)

View File

@ -114,8 +114,7 @@ func ApplyUserHeader(sendUserHeader bool, req *http.Request, user identity.Reque
return return
} }
namespace, _ := user.GetTypedID() if identity.IsIdentityType(user.GetID(), identity.TypeUser) {
if namespace == identity.TypeUser || namespace == identity.TypeServiceAccount {
req.Header.Set(UserHeaderName, user.GetLogin()) req.Header.Set(UserHeaderName, user.GetLogin())
} }
} }