AuthN: Implement requester interface for identity (#75618)

* AuthN: Implement identity.Requester interface for authn.Identity

* AuthN: Replace OrgRole with GetOrgRole

* IDForwarding: skip converting to SignedInUser

* Pass identity directly in permission sync hook
pull/75658/head
Karl Persson 2 years ago committed by GitHub
parent 2fe4ecde19
commit fd2235b5ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      pkg/services/anonymous/anonimpl/client_test.go
  2. 3
      pkg/services/auth/idimpl/service.go
  3. 3
      pkg/services/authn/authnimpl/sync/permission_sync.go
  4. 134
      pkg/services/authn/identity.go

@ -62,7 +62,7 @@ func TestAnonymous_Authenticate(t *testing.T) {
assert.Equal(t, true, identity.ID == "")
assert.Equal(t, tt.org.ID, identity.OrgID)
assert.Equal(t, tt.org.Name, identity.OrgName)
assert.Equal(t, tt.cfg.AnonymousOrgRole, string(identity.Role()))
assert.Equal(t, tt.cfg.AnonymousOrgRole, string(identity.GetOrgRole()))
}
})
}

@ -80,9 +80,8 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
}
func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
// FIXME(kalleep): implement identity.Requester for authn.Identity
// FIXME(kalleep): we should probably lazy load this
token, err := s.SignIdentity(ctx, identity.SignedInUser())
token, err := s.SignIdentity(ctx, identity)
if err != nil {
namespace, id := identity.NamespacedID()
s.logger.Error("Failed to sign id token", "err", err, "namespace", namespace, "id", id)

@ -30,8 +30,7 @@ func (s *PermissionsSync) SyncPermissionsHook(ctx context.Context, identity *aut
return nil
}
permissions, err := s.ac.GetUserPermissions(ctx, identity.SignedInUser(),
accesscontrol.Options{ReloadCache: false})
permissions, err := s.ac.GetUserPermissions(ctx, identity, accesscontrol.Options{ReloadCache: false})
if err != nil {
s.log.FromContext(ctx).Error("Failed to fetch permissions from db", "error", err, "user_id", identity.ID)
return errSyncPermissionsForbidden

@ -8,6 +8,7 @@ import (
"golang.org/x/oauth2"
"github.com/grafana/grafana/pkg/models/roletype"
"github.com/grafana/grafana/pkg/models/usertoken"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/login"
@ -28,6 +29,8 @@ const (
NamespaceRenderService = identity.NamespaceRenderService
)
var _ identity.Requester = (*Identity)(nil)
type Identity struct {
// OrgID is the active organization for the entity.
OrgID int64
@ -81,12 +84,107 @@ type Identity struct {
IDToken string
}
// Role returns the role of the identity in the active organization.
func (i *Identity) Role() org.RoleType {
return i.OrgRoles[i.OrgID]
func (i *Identity) GetAuthenticatedBy() string {
return i.AuthenticatedBy
}
func (i *Identity) GetCacheKey() string {
namespace, id := i.GetNamespacedID()
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
}
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
}
func (i *Identity) GetNamespacedID() (namespace string, identifier string) {
split := strings.Split(i.ID, ":")
if len(split) != 2 {
return "", ""
}
return split[0], split[1]
}
// GetOrgID implements identity.Requester.
func (i *Identity) GetOrgID() int64 {
return i.OrgID
}
func (i *Identity) GetOrgName() string {
return i.OrgName
}
func (i *Identity) GetOrgRole() roletype.RoleType {
if i.OrgRoles == nil {
return roletype.RoleNone
}
if i.OrgRoles[i.GetOrgID()] == "" {
return roletype.RoleNone
}
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()]
}
func (i *Identity) GetTeams() []int64 {
return i.Teams
}
func (i *Identity) HasRole(role roletype.RoleType) bool {
if i.GetIsGrafanaAdmin() {
return true
}
return i.GetOrgRole().Includes(role)
}
func (i *Identity) HasUniqueId() bool {
namespace, _ := i.GetNamespacedID()
return namespace == NamespaceUser || namespace == NamespaceServiceAccount || namespace == NamespaceAPIKey
}
func (i *Identity) IsNil() bool {
return i == nil
}
// NamespacedID returns the namespace, e.g. "user" and the id for that namespace
// FIXME(kalleep): Replace with GetNamespacedID
func (i *Identity) NamespacedID() (string, int64) {
split := strings.Split(i.ID, ":")
if len(split) != 2 {
@ -104,21 +202,15 @@ func (i *Identity) NamespacedID() (string, int64) {
// SignedInUser returns a SignedInUser from the identity.
func (i *Identity) SignedInUser() *user.SignedInUser {
var isGrafanaAdmin bool
if i.IsGrafanaAdmin != nil {
isGrafanaAdmin = *i.IsGrafanaAdmin
}
u := &user.SignedInUser{
UserID: 0,
OrgID: i.OrgID,
OrgName: i.OrgName,
OrgRole: i.Role(),
OrgRole: i.GetOrgRole(),
Login: i.Login,
Name: i.Name,
Email: i.Email,
AuthenticatedBy: i.AuthenticatedBy,
IsGrafanaAdmin: isGrafanaAdmin,
IsGrafanaAdmin: i.GetIsGrafanaAdmin(),
IsAnonymous: i.IsAnonymous,
IsDisabled: i.IsDisabled,
HelpFlags1: i.HelpFlags1,
@ -128,24 +220,34 @@ func (i *Identity) SignedInUser() *user.SignedInUser {
IDToken: i.IDToken,
}
namespace, id := i.NamespacedID()
namespace, id := i.GetNamespacedID()
if namespace == NamespaceAPIKey {
u.ApiKeyID = id
u.ApiKeyID = intIdentifier(id)
} else {
u.UserID = id
u.UserID = intIdentifier(id)
u.IsServiceAccount = namespace == NamespaceServiceAccount
}
return u
}
func intIdentifier(identifier string) int64 {
id, err := strconv.ParseInt(identifier, 10, 64)
if err != nil {
// FIXME (kalleep): Improve error handling
return -1
}
return id
}
func (i *Identity) ExternalUserInfo() login.ExternalUserInfo {
_, id := i.NamespacedID()
_, id := i.GetNamespacedID()
return login.ExternalUserInfo{
OAuthToken: i.OAuthToken,
AuthModule: i.AuthenticatedBy,
AuthId: i.AuthID,
UserId: id,
UserId: intIdentifier(id),
Email: i.Email,
Login: i.Login,
Name: i.Name,

Loading…
Cancel
Save