mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 19:02:29 +08:00
Identity: extend k8s user.Info (#90937)
This commit is contained in:
@ -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)
|
||||
}
|
||||
|
@ -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},
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
},
|
||||
|
@ -2,13 +2,10 @@ package authenticator
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
k8suser "k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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])
|
||||
})
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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{}
|
||||
|
@ -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)
|
||||
|
@ -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{}
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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(),
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
)
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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?
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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"))
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user