2023-09-28 02:22:05 -05:00
|
|
|
package authn
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"golang.org/x/oauth2"
|
|
|
|
|
2024-06-12 23:11:35 -05:00
|
|
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
2023-09-28 02:22:05 -05:00
|
|
|
"github.com/grafana/grafana/pkg/models/usertoken"
|
|
|
|
"github.com/grafana/grafana/pkg/services/login"
|
|
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
|
|
)
|
|
|
|
|
2024-04-12 04:38:20 -05:00
|
|
|
const GlobalOrgID = int64(0)
|
2023-09-29 02:10:33 -05:00
|
|
|
|
2024-07-25 04:52:14 -05:00
|
|
|
var _ identity.Requester = (*Identity)(nil)
|
2023-09-28 09:37:32 -05:00
|
|
|
|
2023-09-28 02:22:05 -05:00
|
|
|
type Identity struct {
|
2024-04-24 02:57:34 -05:00
|
|
|
// ID is the unique identifier for the entity in the Grafana database.
|
|
|
|
// If the entity is not found in the DB or this entity is non-persistent, this field will be empty.
|
2024-07-25 04:52:14 -05:00
|
|
|
ID identity.TypedID
|
2024-05-14 07:13:50 -05:00
|
|
|
// UID is a unique identifier stored for the entity in Grafana database. Not all entities support uid so it can be empty.
|
2024-07-25 04:52:14 -05:00
|
|
|
UID identity.TypedID
|
2023-09-28 02:22:05 -05:00
|
|
|
// OrgID is the active organization for the entity.
|
|
|
|
OrgID int64
|
|
|
|
// OrgName is the name of the active organization.
|
|
|
|
OrgName string
|
|
|
|
// OrgRoles is the list of organizations the entity is a member of and their roles.
|
|
|
|
OrgRoles map[int64]org.RoleType
|
|
|
|
// Login is the shorthand identifier of the entity. Should be unique.
|
|
|
|
Login string
|
|
|
|
// Name is the display name of the entity. It is not guaranteed to be unique.
|
|
|
|
Name string
|
|
|
|
// Email is the email address of the entity. Should be unique.
|
|
|
|
Email string
|
2024-04-05 05:05:46 -05:00
|
|
|
// EmailVerified is true if entity has verified their email with grafana.
|
|
|
|
EmailVerified bool
|
2023-09-28 02:22:05 -05:00
|
|
|
// IsGrafanaAdmin is true if the entity is a Grafana admin.
|
|
|
|
IsGrafanaAdmin *bool
|
|
|
|
// AuthenticatedBy is the name of the authentication client that was used to authenticate the current Identity.
|
|
|
|
// For example, "password", "apikey", "auth_ldap" or "auth_azuread".
|
|
|
|
AuthenticatedBy string
|
|
|
|
// AuthId is the unique identifier for the entity in the external system.
|
|
|
|
// Empty if the identity is provided by Grafana.
|
|
|
|
AuthID string
|
2024-07-08 14:22:10 -05:00
|
|
|
// AllowedKubernetesNamespace
|
|
|
|
AllowedKubernetesNamespace string
|
2023-09-28 02:22:05 -05:00
|
|
|
// IsDisabled is true if the entity is disabled.
|
|
|
|
IsDisabled bool
|
|
|
|
// HelpFlags1 is the help flags for the entity.
|
|
|
|
HelpFlags1 user.HelpFlags1
|
|
|
|
// LastSeenAt is the time when the entity was last seen.
|
|
|
|
LastSeenAt time.Time
|
|
|
|
// Teams is the list of teams the entity is a member of.
|
|
|
|
Teams []int64
|
|
|
|
// idP Groups that the entity is a member of. This is only populated if the
|
|
|
|
// identity provider supports groups.
|
|
|
|
Groups []string
|
|
|
|
// OAuthToken is the OAuth token used to authenticate the entity.
|
|
|
|
OAuthToken *oauth2.Token
|
|
|
|
// SessionToken is the session token used to authenticate the entity.
|
|
|
|
SessionToken *usertoken.UserToken
|
|
|
|
// ClientParams are hints for the auth service on how to handle the identity.
|
|
|
|
// Set by the authenticating client.
|
|
|
|
ClientParams ClientParams
|
|
|
|
// Permissions is the list of permissions the entity has.
|
|
|
|
Permissions map[int64]map[string][]string
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2024-07-30 00:27:23 -05:00
|
|
|
// 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 {
|
2024-07-31 13:27:46 -05:00
|
|
|
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
|
2024-07-30 00:27:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetGroups implements identity.Requester.
|
|
|
|
func (i *Identity) GetGroups() []string {
|
|
|
|
return []string{} // teams?
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetName implements identity.Requester.
|
|
|
|
func (i *Identity) GetName() string {
|
|
|
|
return i.Name
|
|
|
|
}
|
|
|
|
|
2024-07-25 04:52:14 -05:00
|
|
|
func (i *Identity) GetID() identity.TypedID {
|
2024-05-02 07:50:56 -05:00
|
|
|
return i.ID
|
2024-03-15 09:08:15 -05:00
|
|
|
}
|
|
|
|
|
2024-07-25 04:52:14 -05:00
|
|
|
func (i *Identity) GetTypedID() (namespace identity.IdentityType, identifier string) {
|
|
|
|
return i.ID.Type(), i.ID.ID()
|
2024-03-15 09:08:15 -05:00
|
|
|
}
|
|
|
|
|
2024-07-30 00:27:23 -05:00
|
|
|
func (i *Identity) GetUID() string {
|
|
|
|
return i.UID.String()
|
2024-05-06 13:17:34 -05:00
|
|
|
}
|
|
|
|
|
2024-04-11 03:25:29 -05:00
|
|
|
func (i *Identity) GetAuthID() string {
|
|
|
|
return i.AuthID
|
|
|
|
}
|
|
|
|
|
2023-09-28 09:37:32 -05:00
|
|
|
func (i *Identity) GetAuthenticatedBy() string {
|
|
|
|
return i.AuthenticatedBy
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) GetCacheKey() string {
|
2024-07-25 04:52:14 -05:00
|
|
|
namespace, id := i.GetTypedID()
|
2023-09-28 09:37:32 -05:00
|
|
|
if !i.HasUniqueId() {
|
|
|
|
// Hack use the org role as id for identities that do not have a unique id
|
|
|
|
// e.g. anonymous and render key.
|
|
|
|
id = string(i.GetOrgRole())
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%d-%s-%s", i.GetOrgID(), namespace, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) GetDisplayName() string {
|
|
|
|
return i.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) GetEmail() string {
|
|
|
|
return i.Email
|
|
|
|
}
|
|
|
|
|
2024-04-05 05:05:46 -05:00
|
|
|
func (i *Identity) IsEmailVerified() bool {
|
|
|
|
return i.EmailVerified
|
|
|
|
}
|
|
|
|
|
2023-09-28 09:37:32 -05:00
|
|
|
func (i *Identity) GetIDToken() string {
|
|
|
|
return i.IDToken
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) GetIsGrafanaAdmin() bool {
|
|
|
|
return i.IsGrafanaAdmin != nil && *i.IsGrafanaAdmin
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) GetLogin() string {
|
|
|
|
return i.Login
|
|
|
|
}
|
|
|
|
|
2024-07-08 14:22:10 -05:00
|
|
|
func (i *Identity) GetAllowedKubernetesNamespace() string {
|
|
|
|
return i.AllowedKubernetesNamespace
|
|
|
|
}
|
|
|
|
|
2023-09-28 09:37:32 -05:00
|
|
|
func (i *Identity) GetOrgID() int64 {
|
|
|
|
return i.OrgID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) GetOrgName() string {
|
|
|
|
return i.OrgName
|
|
|
|
}
|
|
|
|
|
2024-04-25 05:54:36 -05:00
|
|
|
func (i *Identity) GetOrgRole() org.RoleType {
|
2023-09-28 09:37:32 -05:00
|
|
|
if i.OrgRoles == nil {
|
2024-04-25 05:54:36 -05:00
|
|
|
return org.RoleNone
|
2023-09-28 09:37:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if i.OrgRoles[i.GetOrgID()] == "" {
|
2024-04-25 05:54:36 -05:00
|
|
|
return org.RoleNone
|
2023-09-28 09:37:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return i.OrgRoles[i.GetOrgID()]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) GetPermissions() map[string][]string {
|
|
|
|
if i.Permissions == nil {
|
|
|
|
return make(map[string][]string)
|
|
|
|
}
|
|
|
|
|
|
|
|
if i.Permissions[i.GetOrgID()] == nil {
|
|
|
|
return make(map[string][]string)
|
|
|
|
}
|
|
|
|
|
|
|
|
return i.Permissions[i.GetOrgID()]
|
|
|
|
}
|
|
|
|
|
2024-02-01 05:37:01 -06:00
|
|
|
// GetGlobalPermissions returns the permissions of the active entity that are available across all organizations
|
|
|
|
func (i *Identity) GetGlobalPermissions() map[string][]string {
|
|
|
|
if i.Permissions == nil {
|
|
|
|
return make(map[string][]string)
|
|
|
|
}
|
|
|
|
|
|
|
|
if i.Permissions[GlobalOrgID] == nil {
|
|
|
|
return make(map[string][]string)
|
|
|
|
}
|
|
|
|
|
|
|
|
return i.Permissions[GlobalOrgID]
|
|
|
|
}
|
|
|
|
|
2023-09-28 09:37:32 -05:00
|
|
|
func (i *Identity) GetTeams() []int64 {
|
|
|
|
return i.Teams
|
|
|
|
}
|
|
|
|
|
2024-04-25 05:54:36 -05:00
|
|
|
func (i *Identity) HasRole(role org.RoleType) bool {
|
2023-09-28 09:37:32 -05:00
|
|
|
if i.GetIsGrafanaAdmin() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return i.GetOrgRole().Includes(role)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) HasUniqueId() bool {
|
2024-07-25 04:52:14 -05:00
|
|
|
namespace, _ := i.GetTypedID()
|
|
|
|
return namespace == identity.TypeUser ||
|
|
|
|
namespace == identity.TypeServiceAccount ||
|
|
|
|
namespace == identity.TypeAPIKey
|
2023-09-28 09:37:32 -05:00
|
|
|
}
|
|
|
|
|
2024-03-27 09:22:13 -05:00
|
|
|
func (i *Identity) IsAuthenticatedBy(providers ...string) bool {
|
|
|
|
for _, p := range providers {
|
|
|
|
if i.AuthenticatedBy == p {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-09-28 09:37:32 -05:00
|
|
|
func (i *Identity) IsNil() bool {
|
|
|
|
return i == nil
|
2023-09-28 02:22:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// SignedInUser returns a SignedInUser from the identity.
|
|
|
|
func (i *Identity) SignedInUser() *user.SignedInUser {
|
|
|
|
u := &user.SignedInUser{
|
|
|
|
OrgID: i.OrgID,
|
|
|
|
OrgName: i.OrgName,
|
2023-09-28 09:37:32 -05:00
|
|
|
OrgRole: i.GetOrgRole(),
|
2023-09-28 02:22:05 -05:00
|
|
|
Login: i.Login,
|
|
|
|
Name: i.Name,
|
|
|
|
Email: i.Email,
|
2024-04-11 03:25:29 -05:00
|
|
|
AuthID: i.AuthID,
|
2023-09-28 02:22:05 -05:00
|
|
|
AuthenticatedBy: i.AuthenticatedBy,
|
2023-09-28 09:37:32 -05:00
|
|
|
IsGrafanaAdmin: i.GetIsGrafanaAdmin(),
|
2024-07-25 04:52:14 -05:00
|
|
|
IsAnonymous: i.ID.IsType(identity.TypeAnonymous),
|
2023-09-28 02:22:05 -05:00
|
|
|
IsDisabled: i.IsDisabled,
|
|
|
|
HelpFlags1: i.HelpFlags1,
|
|
|
|
LastSeenAt: i.LastSeenAt,
|
|
|
|
Teams: i.Teams,
|
|
|
|
Permissions: i.Permissions,
|
|
|
|
IDToken: i.IDToken,
|
2024-07-30 00:27:23 -05:00
|
|
|
FallbackType: i.ID.Type(),
|
2023-09-28 02:22:05 -05:00
|
|
|
}
|
|
|
|
|
2024-07-25 04:52:14 -05:00
|
|
|
if i.ID.IsType(identity.TypeAPIKey) {
|
2024-05-14 07:13:50 -05:00
|
|
|
id, _ := i.ID.ParseInt()
|
|
|
|
u.ApiKeyID = id
|
2023-09-28 02:22:05 -05:00
|
|
|
} else {
|
2024-05-14 07:13:50 -05:00
|
|
|
id, _ := i.ID.UserID()
|
|
|
|
u.UserID = id
|
|
|
|
u.UserUID = i.UID.ID()
|
2024-07-25 04:52:14 -05:00
|
|
|
u.IsServiceAccount = i.ID.IsType(identity.TypeServiceAccount)
|
2023-09-28 02:22:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return u
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Identity) ExternalUserInfo() login.ExternalUserInfo {
|
2024-05-14 07:13:50 -05:00
|
|
|
id, _ := i.ID.UserID()
|
2023-09-28 02:22:05 -05:00
|
|
|
return login.ExternalUserInfo{
|
|
|
|
OAuthToken: i.OAuthToken,
|
|
|
|
AuthModule: i.AuthenticatedBy,
|
|
|
|
AuthId: i.AuthID,
|
2024-05-14 07:13:50 -05:00
|
|
|
UserId: id,
|
2023-09-28 02:22:05 -05:00
|
|
|
Email: i.Email,
|
|
|
|
Login: i.Login,
|
|
|
|
Name: i.Name,
|
|
|
|
Groups: i.Groups,
|
|
|
|
OrgRoles: i.OrgRoles,
|
|
|
|
IsGrafanaAdmin: i.IsGrafanaAdmin,
|
|
|
|
IsDisabled: i.IsDisabled,
|
|
|
|
}
|
|
|
|
}
|