diff --git a/pkg/apimachinery/identity/context_test.go b/pkg/apimachinery/identity/context_test.go index 6464a7360fb..87f31a17763 100644 --- a/pkg/apimachinery/identity/context_test.go +++ b/pkg/apimachinery/identity/context_test.go @@ -17,126 +17,10 @@ func TestRequesterFromContext(t *testing.T) { }) t.Run("should return user set by ContextWithUser", func(t *testing.T) { - expected := &dummyUser{UID: "AAA"} + expected := &identity.StaticRequester{UserUID: "AAA"} ctx := identity.WithRequester(context.Background(), expected) actual, err := identity.GetRequester(ctx) require.NoError(t, err) require.Equal(t, expected.GetUID(), actual.GetUID()) }) } - -type dummyUser struct { - UID string -} - -// GetAuthID implements identity.Requester. -func (d *dummyUser) GetAuthID() string { - panic("unimplemented") -} - -// GetAuthenticatedBy implements identity.Requester. -func (d *dummyUser) GetAuthenticatedBy() string { - panic("unimplemented") -} - -// GetCacheKey implements identity.Requester. -func (d *dummyUser) GetCacheKey() string { - panic("unimplemented") -} - -// GetDisplayName implements identity.Requester. -func (d *dummyUser) GetDisplayName() string { - panic("unimplemented") -} - -// GetEmail implements identity.Requester. -func (d *dummyUser) GetEmail() string { - panic("unimplemented") -} - -// GetGlobalPermissions implements identity.Requester. -func (d *dummyUser) GetGlobalPermissions() map[string][]string { - panic("unimplemented") -} - -// GetID implements identity.Requester. -func (d *dummyUser) GetID() identity.NamespaceID { - panic("unimplemented") -} - -// GetIDToken implements identity.Requester. -func (d *dummyUser) GetIDToken() string { - panic("unimplemented") -} - -// GetIsGrafanaAdmin implements identity.Requester. -func (d *dummyUser) GetIsGrafanaAdmin() bool { - panic("unimplemented") -} - -// GetLogin implements identity.Requester. -func (d *dummyUser) GetLogin() string { - panic("unimplemented") -} - -// GetNamespacedID implements identity.Requester. -func (d *dummyUser) GetNamespacedID() (namespace identity.Namespace, identifier string) { - panic("unimplemented") -} - -// GetOrgID implements identity.Requester. -func (d *dummyUser) GetOrgID() int64 { - panic("unimplemented") -} - -// GetOrgName implements identity.Requester. -func (d *dummyUser) GetOrgName() string { - panic("unimplemented") -} - -// GetOrgRole implements identity.Requester. -func (d *dummyUser) GetOrgRole() identity.RoleType { - panic("unimplemented") -} - -// GetPermissions implements identity.Requester. -func (d *dummyUser) GetPermissions() map[string][]string { - panic("unimplemented") -} - -// GetTeams implements identity.Requester. -func (d *dummyUser) GetTeams() []int64 { - panic("unimplemented") -} - -// GetUID implements identity.Requester. -func (d *dummyUser) GetUID() identity.NamespaceID { - return identity.NewNamespaceIDString(identity.NamespaceUser, d.UID) -} - -// HasRole implements identity.Requester. -func (d *dummyUser) HasRole(role identity.RoleType) bool { - panic("unimplemented") -} - -// HasUniqueId implements identity.Requester. -func (d *dummyUser) HasUniqueId() bool { - panic("unimplemented") -} - -// IsAuthenticatedBy implements identity.Requester. -func (d *dummyUser) IsAuthenticatedBy(providers ...string) bool { - panic("unimplemented") -} - -// IsEmailVerified implements identity.Requester. -func (d *dummyUser) IsEmailVerified() bool { - panic("unimplemented") -} - -// IsNil implements identity.Requester. -func (d *dummyUser) IsNil() bool { - return false -} - -var _ identity.Requester = &dummyUser{} diff --git a/pkg/apimachinery/identity/static.go b/pkg/apimachinery/identity/static.go new file mode 100644 index 00000000000..84df3966b80 --- /dev/null +++ b/pkg/apimachinery/identity/static.go @@ -0,0 +1,175 @@ +package identity + +import "fmt" + +var _ Requester = &StaticRequester{} + +// StaticRequester allows creating requester values explicitly. +// It is helpful in tests! +// This is mostly copied from: +// https://github.com/grafana/grafana/blob/v11.0.0/pkg/services/user/identity.go#L16 +type StaticRequester struct { + Namespace Namespace + UserID int64 + UserUID string + OrgID int64 + OrgName string + OrgRole RoleType + Login string + Name string + DisplayName string + Email string + EmailVerified bool + AuthID string + AuthenticatedBy string + IsGrafanaAdmin bool + // Permissions grouped by orgID and actions + Permissions map[int64]map[string][]string + IDToken string + CacheKey string +} + +func (u *StaticRequester) HasRole(role RoleType) bool { + if u.IsGrafanaAdmin { + return true + } + + return u.OrgRole.Includes(role) +} + +// GetIsGrafanaAdmin returns true if the user is a server admin +func (u *StaticRequester) GetIsGrafanaAdmin() bool { + return u.IsGrafanaAdmin +} + +// GetLogin returns the login of the active entity +// Can be empty if the user is anonymous +func (u *StaticRequester) GetLogin() string { + return u.Login +} + +// GetOrgID returns the ID of the active organization +func (u *StaticRequester) GetOrgID() int64 { + return u.OrgID +} + +// DEPRECATED: GetOrgName returns the name of the active organization +// Retrieve the organization name from the organization service instead of using this method. +func (u *StaticRequester) GetOrgName() string { + return u.OrgName +} + +// GetPermissions returns the permissions of the active entity +func (u *StaticRequester) GetPermissions() map[string][]string { + if u.Permissions == nil { + return make(map[string][]string) + } + + if u.Permissions[u.GetOrgID()] == nil { + return make(map[string][]string) + } + + return u.Permissions[u.GetOrgID()] +} + +// GetGlobalPermissions returns the permissions of the active entity that are available across all organizations +func (u *StaticRequester) GetGlobalPermissions() map[string][]string { + if u.Permissions == nil { + return make(map[string][]string) + } + + const globalOrgID = 0 + + if u.Permissions[globalOrgID] == nil { + return make(map[string][]string) + } + + return u.Permissions[globalOrgID] +} + +// DEPRECATED: GetTeams returns the teams the entity is a member of +// Retrieve the teams from the team service instead of using this method. +func (u *StaticRequester) GetTeams() []int64 { + return []int64{} // Not implemented +} + +// GetOrgRole returns the role of the active entity in the active organization +func (u *StaticRequester) GetOrgRole() RoleType { + return u.OrgRole +} + +// HasUniqueId returns true if the entity has a unique id +func (u *StaticRequester) HasUniqueId() bool { + return u.UserID > 0 +} + +// GetID returns namespaced id for the entity +func (u *StaticRequester) GetID() NamespaceID { + return NewNamespaceIDString(u.Namespace, fmt.Sprintf("%d", u.UserID)) +} + +// GetUID returns namespaced uid for the entity +func (u *StaticRequester) GetUID() NamespaceID { + return NewNamespaceIDString(u.Namespace, u.UserUID) +} + +// GetNamespacedID returns the namespace and ID of the active entity +// The namespace is one of the constants defined in pkg/apimachinery/identity +func (u *StaticRequester) GetNamespacedID() (Namespace, string) { + return u.Namespace, fmt.Sprintf("%d", u.UserID) +} + +func (u *StaticRequester) GetAuthID() string { + return u.AuthID +} + +func (u *StaticRequester) GetAuthenticatedBy() string { + return u.AuthenticatedBy +} + +func (u *StaticRequester) IsAuthenticatedBy(providers ...string) bool { + for _, p := range providers { + if u.AuthenticatedBy == p { + return true + } + } + return false +} + +// FIXME: remove this method once all services are using an interface +func (u *StaticRequester) IsNil() bool { + return u == nil +} + +// GetEmail returns the email of the active entity +// Can be empty. +func (u *StaticRequester) GetEmail() string { + return u.Email +} + +func (u *StaticRequester) IsEmailVerified() bool { + return u.EmailVerified +} + +func (u *StaticRequester) GetCacheKey() string { + return u.CacheKey +} + +// GetDisplayName returns the display name of the active entity +// The display name is the name if it is set, otherwise the login or email +func (u *StaticRequester) GetDisplayName() string { + if u.DisplayName != "" { + return u.DisplayName + } + if u.Name != "" { + return u.Name + } + if u.Login != "" { + return u.Login + } + return u.Email +} + +func (u *StaticRequester) GetIDToken() string { + return u.IDToken +}