diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 31e11eff73d..ef32c764e5a 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -140,7 +140,8 @@ func (hs *HTTPServer) PostAnnotation(c *contextmodel.ReqContext) response.Respon return response.Error(http.StatusBadRequest, "Failed to save annotation", err) } - userID, err := c.SignedInUser.GetID().UserID() + // nolint:staticcheck + userID, err := c.SignedInUser.GetInternalID() if err != nil { return response.Error(http.StatusInternalServerError, "Failed to save annotation", err) } @@ -227,7 +228,8 @@ func (hs *HTTPServer) PostGraphiteAnnotation(c *contextmodel.ReqContext) respons return response.Error(http.StatusBadRequest, "Failed to save Graphite annotation", err) } - userID, err := c.SignedInUser.GetID().UserID() + // nolint:staticcheck + userID, err := c.SignedInUser.GetInternalID() if err != nil { return response.Error(http.StatusInternalServerError, "Failed to save Graphite annotation", err) } @@ -284,7 +286,8 @@ func (hs *HTTPServer) UpdateAnnotation(c *contextmodel.ReqContext) response.Resp } } - userID, err := c.SignedInUser.GetID().UserID() + // nolint:staticcheck + userID, err := c.SignedInUser.GetInternalID() if err != nil { return response.Error(http.StatusInternalServerError, "Failed to update annotation", err) } @@ -346,7 +349,8 @@ func (hs *HTTPServer) PatchAnnotation(c *contextmodel.ReqContext) response.Respo } } - userID, err := c.SignedInUser.GetID().UserID() + // nolint:staticcheck + userID, err := c.SignedInUser.GetInternalID() if err != nil { return response.Error(http.StatusInternalServerError, "Failed to update annotation", err) } diff --git a/pkg/api/pluginproxy/ds_proxy_test.go b/pkg/api/pluginproxy/ds_proxy_test.go index a5e72ba31e2..16203412fce 100644 --- a/pkg/api/pluginproxy/ds_proxy_test.go +++ b/pkg/api/pluginproxy/ds_proxy_test.go @@ -586,7 +586,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { &contextmodel.ReqContext{ SignedInUser: &user.SignedInUser{ Login: "test_user", - NamespacedID: identity.MustParseTypedID("user:1"), + FallbackType: identity.TypeUser, + UserID: 1, }, }, &setting.Cfg{SendUserHeader: true}, diff --git a/pkg/api/pluginproxy/pluginproxy_test.go b/pkg/api/pluginproxy/pluginproxy_test.go index 52959693305..2a89f18a27d 100644 --- a/pkg/api/pluginproxy/pluginproxy_test.go +++ b/pkg/api/pluginproxy/pluginproxy_test.go @@ -79,7 +79,8 @@ func TestPluginProxy(t *testing.T) { &contextmodel.ReqContext{ SignedInUser: &user.SignedInUser{ Login: "test_user", - NamespacedID: identity.MustParseTypedID("user:1"), + FallbackType: identity.TypeUser, + UserID: 1, }, Context: &web.Context{ Req: httpReq, diff --git a/pkg/apimachinery/identity/requester.go b/pkg/apimachinery/identity/requester.go index 2c372d2182c..da9609b69a0 100644 --- a/pkg/apimachinery/identity/requester.go +++ b/pkg/apimachinery/identity/requester.go @@ -3,17 +3,28 @@ package identity import ( "fmt" "strconv" + + "k8s.io/apiserver/pkg/authentication/user" ) type Requester interface { - // GetID returns namespaced id for the entity + user.Info + + // GetIdentityType returns the type for the requester + GetIdentityType() IdentityType + // GetRawIdentifier returns only the identifier part of the UID, excluding the type + 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) - // GetUID returns namespaced uid for the entity - GetUID() TypedID + // 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 diff --git a/pkg/apimachinery/identity/static.go b/pkg/apimachinery/identity/static.go index 43772845033..af4f5fa0565 100644 --- a/pkg/apimachinery/identity/static.go +++ b/pkg/apimachinery/identity/static.go @@ -30,6 +30,41 @@ type StaticRequester struct { CacheKey string } +// GetRawIdentifier implements Requester. +func (u *StaticRequester) GetUID() string { + return fmt.Sprintf("%s:%s", u.Type, u.UserUID) +} + +// GetRawIdentifier implements Requester. +func (u *StaticRequester) GetRawIdentifier() string { + return u.UserUID +} + +// GetInternalID implements Requester. +func (u *StaticRequester) GetInternalID() (int64, error) { + return u.UserID, nil +} + +// GetIdentityType implements Requester. +func (u *StaticRequester) GetIdentityType() IdentityType { + return u.Type +} + +// GetExtra implements Requester. +func (u *StaticRequester) GetExtra() map[string][]string { + return map[string][]string{} +} + +// GetGroups implements Requester. +func (u *StaticRequester) GetGroups() []string { + return []string{} +} + +// GetName implements Requester. +func (u *StaticRequester) GetName() string { + return u.DisplayName +} + func (u *StaticRequester) HasRole(role RoleType) bool { if u.IsGrafanaAdmin { return true @@ -109,11 +144,6 @@ func (u *StaticRequester) GetID() TypedID { return NewTypedIDString(u.Type, fmt.Sprintf("%d", u.UserID)) } -// GetUID returns namespaced uid for the entity -func (u *StaticRequester) GetUID() TypedID { - return NewTypedIDString(u.Type, u.UserUID) -} - // 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) { diff --git a/pkg/services/accesscontrol/acimpl/accesscontrol.go b/pkg/services/accesscontrol/acimpl/accesscontrol.go index 16818dd27ce..a1dd9bbcc95 100644 --- a/pkg/services/accesscontrol/acimpl/accesscontrol.go +++ b/pkg/services/accesscontrol/acimpl/accesscontrol.go @@ -108,7 +108,7 @@ func (a *AccessControl) evaluateZanzana(ctx context.Context, user identity.Reque return eval.EvaluateCustom(func(action, scope string) (bool, error) { kind, _, identifier := accesscontrol.SplitScope(scope) - key, ok := zanzana.TranslateToTuple(user.GetUID().String(), action, kind, identifier, user.GetOrgID()) + key, ok := zanzana.TranslateToTuple(user.GetUID(), action, kind, identifier, user.GetOrgID()) if !ok { // unsupported translation return false, errAccessNotImplemented diff --git a/pkg/services/accesscontrol/cacheutils_test.go b/pkg/services/accesscontrol/cacheutils_test.go index b661f5fd6fc..b65ec9485d6 100644 --- a/pkg/services/accesscontrol/cacheutils_test.go +++ b/pkg/services/accesscontrol/cacheutils_test.go @@ -21,7 +21,7 @@ func TestPermissionCacheKey(t *testing.T) { signedInUser: &user.SignedInUser{ OrgID: 1, UserID: 1, - NamespacedID: identity.MustParseTypedID("user:1"), + FallbackType: identity.TypeUser, }, expected: "rbac-permissions-1-user-1", }, @@ -31,7 +31,7 @@ func TestPermissionCacheKey(t *testing.T) { OrgID: 1, ApiKeyID: 1, IsServiceAccount: false, - NamespacedID: identity.MustParseTypedID("user:1"), + FallbackType: identity.TypeUser, }, expected: "rbac-permissions-1-api-key-1", }, @@ -41,7 +41,7 @@ func TestPermissionCacheKey(t *testing.T) { OrgID: 1, UserID: 1, IsServiceAccount: true, - NamespacedID: identity.MustParseTypedID("service-account:1"), + FallbackType: identity.TypeUser, }, expected: "rbac-permissions-1-service-account-1", }, @@ -51,7 +51,7 @@ func TestPermissionCacheKey(t *testing.T) { OrgID: 1, UserID: -1, IsServiceAccount: true, - NamespacedID: identity.MustParseTypedID("service-account:-1"), + FallbackType: identity.TypeUser, // NOTE, this is still a service account! }, expected: "rbac-permissions-1-service-account--1", }, @@ -60,7 +60,7 @@ func TestPermissionCacheKey(t *testing.T) { signedInUser: &user.SignedInUser{ OrgID: 1, OrgRole: org.RoleNone, - NamespacedID: identity.MustParseTypedID("user:1"), + FallbackType: identity.TypeUser, }, expected: "rbac-permissions-1-user-None", }, diff --git a/pkg/services/apiserver/auth/authenticator/signedinuser.go b/pkg/services/apiserver/auth/authenticator/signedinuser.go index 2c3e568f0e8..32e4a1e8a7a 100644 --- a/pkg/services/apiserver/auth/authenticator/signedinuser.go +++ b/pkg/services/apiserver/auth/authenticator/signedinuser.go @@ -2,13 +2,10 @@ package authenticator import ( "net/http" - "strconv" + "github.com/grafana/grafana/pkg/apimachinery/identity" "k8s.io/apiserver/pkg/authentication/authenticator" - k8suser "k8s.io/apiserver/pkg/authentication/user" "k8s.io/klog/v2" - - "github.com/grafana/grafana/pkg/apimachinery/identity" ) var _ authenticator.RequestFunc = signedInUserAuthenticator @@ -21,28 +18,7 @@ func signedInUserAuthenticator(req *http.Request) (*authenticator.Response, bool return nil, false, nil } - userInfo := &k8suser.DefaultInfo{ - Name: signedInUser.GetLogin(), - UID: signedInUser.GetUID().ID(), - Groups: []string{}, - // In order to faithfully round-trip through an impersonation flow, Extra keys MUST be lowercase. - // see: https://pkg.go.dev/k8s.io/apiserver@v0.27.1/pkg/authentication/user#Info - Extra: map[string][]string{}, - } - - for _, v := range signedInUser.GetTeams() { - userInfo.Groups = append(userInfo.Groups, strconv.FormatInt(v, 10)) - } - - // - if signedInUser.GetIDToken() != "" { - userInfo.Extra["id-token"] = []string{signedInUser.GetIDToken()} - } - if signedInUser.GetOrgRole().IsValid() { - userInfo.Extra["user-instance-role"] = []string{string(signedInUser.GetOrgRole())} - } - return &authenticator.Response{ - User: userInfo, + User: signedInUser, }, true, nil } diff --git a/pkg/services/apiserver/auth/authenticator/signedinuser_test.go b/pkg/services/apiserver/auth/authenticator/signedinuser_test.go index 86490c61dc5..872958f6ce6 100644 --- a/pkg/services/apiserver/auth/authenticator/signedinuser_test.go +++ b/pkg/services/apiserver/auth/authenticator/signedinuser_test.go @@ -28,9 +28,9 @@ func TestSignedInUser(t *testing.T) { t.Run("should set user and group", func(t *testing.T) { u := &user.SignedInUser{ - Login: "admin", + Name: "admin", UserID: 1, - UserUID: uuid.New().String(), + UserUID: "xyz", Teams: []int64{1, 2}, } ctx := identity.WithRequester(context.Background(), u) @@ -44,15 +44,15 @@ func TestSignedInUser(t *testing.T) { require.True(t, ok) require.False(t, mockAuthenticator.called) - require.Equal(t, u.Login, res.User.GetName()) - require.Equal(t, u.UserUID, res.User.GetUID()) + require.Equal(t, u.GetName(), res.User.GetName()) + require.Equal(t, u.GetUID(), res.User.GetUID()) require.Equal(t, []string{"1", "2"}, res.User.GetGroups()) require.Empty(t, res.User.GetExtra()["id-token"]) }) t.Run("should set ID token when available", func(t *testing.T) { u := &user.SignedInUser{ - Login: "admin", + Name: "admin", UserID: 1, UserUID: uuid.New().String(), Teams: []int64{1, 2}, @@ -69,8 +69,8 @@ func TestSignedInUser(t *testing.T) { require.True(t, ok) require.False(t, mockAuthenticator.called) - require.Equal(t, u.Login, res.User.GetName()) - require.Equal(t, u.UserUID, res.User.GetUID()) + require.Equal(t, u.GetName(), res.User.GetName()) + require.Equal(t, u.GetUID(), res.User.GetUID()) require.Equal(t, []string{"1", "2"}, res.User.GetGroups()) require.Equal(t, "test-id-token", res.User.GetExtra()["id-token"][0]) }) diff --git a/pkg/services/apiserver/auth/authorizer/org_id.go b/pkg/services/apiserver/auth/authorizer/org_id.go index f2630922280..b9425a585c8 100644 --- a/pkg/services/apiserver/auth/authorizer/org_id.go +++ b/pkg/services/apiserver/auth/authorizer/org_id.go @@ -4,12 +4,11 @@ import ( "context" "fmt" - "k8s.io/apiserver/pkg/authorization/authorizer" - "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" grafanarequest "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/services/org" + "k8s.io/apiserver/pkg/authorization/authorizer" ) var _ authorizer.Authorizer = &orgIDAuthorizer{} @@ -56,7 +55,8 @@ func (auth orgIDAuthorizer) Authorize(ctx context.Context, a authorizer.Attribut } // Check if the user has access to the specified org - userId, err := signedInUser.GetID().UserID() + // nolint:staticcheck + userId, err := signedInUser.GetInternalID() if err != nil { return authorizer.DecisionDeny, "unable to get userId", err } diff --git a/pkg/services/apiserver/auth/authorizer/org_role.go b/pkg/services/apiserver/auth/authorizer/org_role.go index 9c03f3ba795..c79be633df6 100644 --- a/pkg/services/apiserver/auth/authorizer/org_role.go +++ b/pkg/services/apiserver/auth/authorizer/org_role.go @@ -4,11 +4,10 @@ import ( "context" "fmt" - "k8s.io/apiserver/pkg/authorization/authorizer" - "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/org" + "k8s.io/apiserver/pkg/authorization/authorizer" ) var _ authorizer.Authorizer = &orgRoleAuthorizer{} diff --git a/pkg/services/apiserver/auth/authorizer/provider.go b/pkg/services/apiserver/auth/authorizer/provider.go index 5cd92982e40..134855c996e 100644 --- a/pkg/services/apiserver/auth/authorizer/provider.go +++ b/pkg/services/apiserver/auth/authorizer/provider.go @@ -3,14 +3,13 @@ package authorizer import ( "context" + orgsvc "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/setting" "k8s.io/apimachinery/pkg/runtime/schema" k8suser "k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizerfactory" "k8s.io/apiserver/pkg/authorization/union" - - orgsvc "github.com/grafana/grafana/pkg/services/org" - "github.com/grafana/grafana/pkg/setting" ) var _ authorizer.Authorizer = (*GrafanaAuthorizer)(nil) diff --git a/pkg/services/apiserver/auth/authorizer/stack_id.go b/pkg/services/apiserver/auth/authorizer/stack_id.go index af4c309e226..da24f890aae 100644 --- a/pkg/services/apiserver/auth/authorizer/stack_id.go +++ b/pkg/services/apiserver/auth/authorizer/stack_id.go @@ -4,12 +4,11 @@ import ( "context" "fmt" - "k8s.io/apiserver/pkg/authorization/authorizer" - "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" grafanarequest "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/setting" + "k8s.io/apiserver/pkg/authorization/authorizer" ) var _ authorizer.Authorizer = &stackIDAuthorizer{} diff --git a/pkg/services/auth/idimpl/service.go b/pkg/services/auth/idimpl/service.go index 8fdde765255..d4c05e01184 100644 --- a/pkg/services/auth/idimpl/service.go +++ b/pkg/services/auth/idimpl/service.go @@ -97,7 +97,7 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri claims.Rest.EmailVerified = id.IsEmailVerified() claims.Rest.AuthenticatedBy = id.GetAuthenticatedBy() claims.Rest.Username = id.GetLogin() - claims.Rest.UID = id.GetUID().String() + claims.Rest.UID = id.GetUID() } token, err := s.signer.SignIDToken(ctx, claims) diff --git a/pkg/services/authn/identity.go b/pkg/services/authn/identity.go index 2ad7534ff4a..51bd72e5156 100644 --- a/pkg/services/authn/identity.go +++ b/pkg/services/authn/identity.go @@ -72,6 +72,43 @@ type Identity struct { IDToken string } +// GetRawIdentifier implements Requester. +func (i *Identity) GetRawIdentifier() string { + return i.UID.ID() +} + +// GetInternalID implements Requester. +func (i *Identity) GetInternalID() (int64, error) { + return i.ID.UserID() +} + +// GetIdentityType implements Requester. +func (i *Identity) GetIdentityType() identity.IdentityType { + return i.UID.Type() +} + +// GetExtra implements identity.Requester. +func (i *Identity) GetExtra() map[string][]string { + extra := map[string][]string{} + if i.IDToken != "" { + extra["id-token"] = []string{i.IDToken} + } + if i.GetOrgRole().IsValid() { + extra["user-instance-role"] = []string{string(i.GetOrgRole())} + } + return extra +} + +// GetGroups implements identity.Requester. +func (i *Identity) GetGroups() []string { + return []string{} // teams? +} + +// GetName implements identity.Requester. +func (i *Identity) GetName() string { + return i.Name +} + func (i *Identity) GetID() identity.TypedID { return i.ID } @@ -80,8 +117,8 @@ func (i *Identity) GetTypedID() (namespace identity.IdentityType, identifier str return i.ID.Type(), i.ID.ID() } -func (i *Identity) GetUID() identity.TypedID { - return i.UID +func (i *Identity) GetUID() string { + return i.UID.String() } func (i *Identity) GetAuthID() string { @@ -227,7 +264,7 @@ func (i *Identity) SignedInUser() *user.SignedInUser { Teams: i.Teams, Permissions: i.Permissions, IDToken: i.IDToken, - NamespacedID: i.ID, + FallbackType: i.ID.Type(), } if i.ID.IsType(identity.TypeAPIKey) { diff --git a/pkg/services/live/features/dashboard.go b/pkg/services/live/features/dashboard.go index 57040d9b214..a0459f39664 100644 --- a/pkg/services/live/features/dashboard.go +++ b/pkg/services/live/features/dashboard.go @@ -37,15 +37,11 @@ type userDisplayDTO struct { // Static function to parse a requester into a userDisplayDTO func newUserDisplayDTOFromRequester(requester identity.Requester) *userDisplayDTO { - uid := "" - if requester.GetUID().IsType(identity.TypeUser, identity.TypeServiceAccount) { - uid = requester.GetUID().ID() - } - - userID, _ := requester.GetID().UserID() + // nolint:staticcheck + userID, _ := requester.GetInternalID() return &userDisplayDTO{ ID: userID, - UID: uid, + UID: requester.GetRawIdentifier(), Login: requester.GetLogin(), Name: requester.GetDisplayName(), } diff --git a/pkg/services/store/entity/sqlstash/utils.go b/pkg/services/store/entity/sqlstash/utils.go index 3d140ea31c3..b9ce27a59e8 100644 --- a/pkg/services/store/entity/sqlstash/utils.go +++ b/pkg/services/store/entity/sqlstash/utils.go @@ -32,7 +32,7 @@ func getCurrentUser(ctx context.Context) (string, error) { return "", fmt.Errorf("%w: %w", ErrUserNotFoundInContext, err) } - return user.GetUID().String(), nil + return user.GetUID(), nil } // ptrOr returns the first non-nil pointer in the list or a new non-nil pointer. diff --git a/pkg/services/store/entity/tests/server_integration_test.go b/pkg/services/store/entity/tests/server_integration_test.go index 1cb9d486dda..5b8f647ef84 100644 --- a/pkg/services/store/entity/tests/server_integration_test.go +++ b/pkg/services/store/entity/tests/server_integration_test.go @@ -121,7 +121,7 @@ func TestIntegrationEntityServer(t *testing.T) { testCtx := createTestContext(t) ctx := identity.WithRequester(testCtx.ctx, testCtx.user) - fakeUser := testCtx.user.GetUID().String() + fakeUser := testCtx.user.GetUID() firstVersion := int64(0) group := "test.grafana.app" resource := "jsonobjs" diff --git a/pkg/services/user/identity.go b/pkg/services/user/identity.go index a6100ded51e..b5906276ea5 100644 --- a/pkg/services/user/identity.go +++ b/pkg/services/user/identity.go @@ -42,8 +42,75 @@ type SignedInUser struct { Permissions map[int64]map[string][]string `json:"-"` // IDToken is a signed token representing the identity that can be forwarded to plugins and external services. // Will only be set when featuremgmt.FlagIdForwarding is enabled. - IDToken string `json:"-" xorm:"-"` - NamespacedID identity.TypedID + IDToken string `json:"-" xorm:"-"` + + // When other settings are not deterministic, this value is used + FallbackType identity.IdentityType +} + +// GetRawIdentifier implements Requester. +func (u *SignedInUser) GetRawIdentifier() string { + if u.UserUID == "" { + // nolint:staticcheck + id, _ := u.GetInternalID() + return strconv.FormatInt(id, 10) + } + return u.UserUID +} + +// Deprecated: use GetUID +func (u *SignedInUser) GetInternalID() (int64, error) { + switch { + case u.ApiKeyID != 0: + return u.ApiKeyID, nil + case u.IsAnonymous: + return 0, nil + default: + } + return u.UserID, nil +} + +// GetIdentityType implements Requester. +func (u *SignedInUser) GetIdentityType() identity.IdentityType { + switch { + case u.ApiKeyID != 0: + return identity.TypeAPIKey + case u.IsServiceAccount: + return identity.TypeServiceAccount + case u.UserID > 0: + return identity.TypeUser + case u.IsAnonymous: + return identity.TypeAnonymous + case u.AuthenticatedBy == "render" && u.UserID == 0: + return identity.TypeRenderService + } + return u.FallbackType +} + +// GetName implements identity.Requester. +func (u *SignedInUser) GetName() string { + return u.Name +} + +// GetExtra implements Requester. +func (u *SignedInUser) GetExtra() map[string][]string { + extra := map[string][]string{} + if u.IDToken != "" { + extra["id-token"] = []string{u.IDToken} + } + if u.OrgRole.IsValid() { + extra["user-instance-role"] = []string{string(u.GetOrgRole())} + } + return extra +} + +// GetGroups implements Requester. +func (u *SignedInUser) GetGroups() []string { + groups := []string{} + for _, t := range u.Teams { + groups = append(groups, strconv.FormatInt(t, 10)) + } + return groups } func (u *SignedInUser) ShouldUpdateLastSeenAt() bool { @@ -194,25 +261,11 @@ func (u *SignedInUser) GetTypedID() (identity.IdentityType, string) { return identity.TypeRenderService, "0" } - return u.NamespacedID.Type(), u.NamespacedID.ID() + return u.FallbackType, strconv.FormatInt(u.UserID, 10) } -// GetUID returns namespaced uid for the entity -func (u *SignedInUser) GetUID() identity.TypedID { - switch { - case u.ApiKeyID != 0: - return identity.NewTypedIDString(identity.TypeAPIKey, strconv.FormatInt(u.ApiKeyID, 10)) - case u.IsServiceAccount: - return identity.NewTypedIDString(identity.TypeServiceAccount, u.UserUID) - case u.UserID > 0: - return identity.NewTypedIDString(identity.TypeUser, u.UserUID) - case u.IsAnonymous: - return identity.NewTypedIDString(identity.TypeAnonymous, "0") - case u.AuthenticatedBy == "render" && u.UserID == 0: - return identity.NewTypedIDString(identity.TypeRenderService, "0") - } - - return identity.NewTypedIDString(identity.TypeEmpty, "0") +func (u *SignedInUser) GetUID() string { + return fmt.Sprintf("%s:%s", u.GetIdentityType(), u.GetRawIdentifier()) } func (u *SignedInUser) GetAuthID() string { diff --git a/pkg/storage/unified/apistore/prepare.go b/pkg/storage/unified/apistore/prepare.go index 0a8dc35377a..6933b385673 100644 --- a/pkg/storage/unified/apistore/prepare.go +++ b/pkg/storage/unified/apistore/prepare.go @@ -42,7 +42,7 @@ func (s *Storage) prepareObjectForStorage(ctx context.Context, newObject runtime obj.SetOriginInfo(origin) obj.SetUpdatedBy("") obj.SetUpdatedTimestamp(nil) - obj.SetCreatedBy(user.GetUID().String()) + obj.SetCreatedBy(user.GetUID()) var buf bytes.Buffer err = s.codec.Encode(newObject, &buf) @@ -81,7 +81,7 @@ func (s *Storage) prepareObjectForUpdate(ctx context.Context, updateObject runti return nil, err } obj.SetOriginInfo(origin) - obj.SetUpdatedBy(user.GetUID().String()) + obj.SetUpdatedBy(user.GetUID()) obj.SetUpdatedTimestampMillis(time.Now().UnixMilli()) var buf bytes.Buffer diff --git a/pkg/storage/unified/resource/grpc/authenticator.go b/pkg/storage/unified/resource/grpc/authenticator.go index e4c59996eaa..1720f73dca2 100644 --- a/pkg/storage/unified/resource/grpc/authenticator.go +++ b/pkg/storage/unified/resource/grpc/authenticator.go @@ -150,7 +150,7 @@ func encodeIdentityInMetadata(user identity.Requester) metadata.MD { // Or we can create it directly mdUserID, user.GetID().String(), - mdUserUID, user.GetUID().String(), + mdUserUID, user.GetUID(), mdOrgName, user.GetOrgName(), mdOrgID, strconv.FormatInt(user.GetOrgID(), 10), mdOrgRole, string(user.GetOrgRole()), @@ -158,6 +158,6 @@ func encodeIdentityInMetadata(user identity.Requester) metadata.MD { // TODO, Remove after this is deployed to unified storage "grafana-userid", user.GetID().ID(), - "grafana-useruid", user.GetUID().ID(), + "grafana-useruid", user.GetRawIdentifier(), ) } diff --git a/pkg/storage/unified/resource/grpc/authenticator_test.go b/pkg/storage/unified/resource/grpc/authenticator_test.go index bcd4aadca72..40279763b1e 100644 --- a/pkg/storage/unified/resource/grpc/authenticator_test.go +++ b/pkg/storage/unified/resource/grpc/authenticator_test.go @@ -27,6 +27,7 @@ func TestBasicEncodeDecode(t *testing.T) { require.NoError(t, err) require.Equal(t, before.GetID(), after.GetID()) require.Equal(t, before.GetUID(), after.GetUID()) + require.Equal(t, before.GetIdentityType(), after.GetIdentityType()) require.Equal(t, before.GetLogin(), after.GetLogin()) require.Equal(t, before.GetOrgID(), after.GetOrgID()) require.Equal(t, before.GetOrgName(), after.GetOrgName()) diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index 5ec6f2e4015..22b69ff4d31 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -447,7 +447,7 @@ func (s *server) Delete(ctx context.Context, req *DeleteRequest) (*DeleteRespons obj.SetUpdatedTimestamp(&now.Time) obj.SetManagedFields(nil) obj.SetFinalizers(nil) - obj.SetUpdatedBy(requester.GetUID().String()) + obj.SetUpdatedBy(requester.GetUID()) marker.TypeMeta = metav1.TypeMeta{ Kind: "DeletedMarker", APIVersion: "common.grafana.app/v0alpha1", // ?? or can we stick this in common? diff --git a/pkg/storage/unified/resource/server_test.go b/pkg/storage/unified/resource/server_test.go index 54a2d51dfb8..63023aa3d34 100644 --- a/pkg/storage/unified/resource/server_test.go +++ b/pkg/storage/unified/resource/server_test.go @@ -116,7 +116,7 @@ func TestSimpleServer(t *testing.T) { require.NoError(t, err) obj.SetAnnotation("test", "hello") obj.SetUpdatedTimestampMillis(now) - obj.SetUpdatedBy(testUserA.GetUID().String()) + obj.SetUpdatedBy(testUserA.GetUID()) raw, err = json.Marshal(tmp) require.NoError(t, err) diff --git a/pkg/tests/apis/helper.go b/pkg/tests/apis/helper.go index a19ca52eede..3bee282dafd 100644 --- a/pkg/tests/apis/helper.go +++ b/pkg/tests/apis/helper.go @@ -466,7 +466,8 @@ func (c *K8sTestHelper) CreateUser(name string, orgName string, basicRole org.Ro } func (c *K8sTestHelper) SetPermissions(user User, permissions []resourcepermissions.SetResourcePermissionCommand) { - id, err := user.Identity.GetID().UserID() + // nolint:staticcheck + id, err := user.Identity.GetInternalID() require.NoError(c.t, err) permissionsStore := resourcepermissions.NewStore(c.env.Cfg, c.env.SQLStore, featuremgmt.WithFeatures()) diff --git a/pkg/util/proxyutil/proxyutil_test.go b/pkg/util/proxyutil/proxyutil_test.go index 1e1ca69c13d..40836a75d40 100644 --- a/pkg/util/proxyutil/proxyutil_test.go +++ b/pkg/util/proxyutil/proxyutil_test.go @@ -175,7 +175,7 @@ func TestApplyUserHeader(t *testing.T) { require.NoError(t, err) req.Header.Set("X-Grafana-User", "admin") - ApplyUserHeader(false, req, &user.SignedInUser{Login: "admin", NamespacedID: identity.MustParseTypedID("user:1")}) + ApplyUserHeader(false, req, &user.SignedInUser{Login: "admin", UserID: 1, FallbackType: identity.TypeUser}) require.NotContains(t, req.Header, "X-Grafana-User") }) @@ -192,7 +192,7 @@ func TestApplyUserHeader(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "/", nil) require.NoError(t, err) - ApplyUserHeader(true, req, &user.SignedInUser{IsAnonymous: true, NamespacedID: identity.MustParseTypedID("anonymous:0")}) + ApplyUserHeader(true, req, &user.SignedInUser{IsAnonymous: true, FallbackType: identity.TypeAnonymous}) require.NotContains(t, req.Header, "X-Grafana-User") }) @@ -200,7 +200,7 @@ func TestApplyUserHeader(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "/", nil) require.NoError(t, err) - ApplyUserHeader(true, req, &user.SignedInUser{Login: "admin", NamespacedID: identity.MustParseTypedID("user:1")}) + ApplyUserHeader(true, req, &user.SignedInUser{Login: "admin", UserID: 1, FallbackType: identity.TypeUser}) require.Equal(t, "admin", req.Header.Get("X-Grafana-User")) }) }