Auth: use IdentityType from authlib (#91763)

This commit is contained in:
Ryan McKinley
2024-08-12 09:26:53 +03:00
committed by GitHub
parent faf7cb9312
commit 21d4a4f49e
70 changed files with 230 additions and 212 deletions
+5 -4
View File
@@ -12,6 +12,7 @@ import (
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/log"
@@ -217,7 +218,7 @@ func (s *Service) Login(ctx context.Context, client string, r *authn.Request) (i
}
// Login is only supported for users
if !id.ID.IsType(identity.TypeUser) {
if !id.ID.IsType(claims.TypeUser) {
s.metrics.failedLogin.WithLabelValues(client).Inc()
return nil, authn.ErrUnsupportedIdentity.Errorf("expected identity of type user but got: %s", id.ID.Type())
}
@@ -281,7 +282,7 @@ func (s *Service) Logout(ctx context.Context, user identity.Requester, sessionTo
redirect.URL = s.cfg.SignoutRedirectUrl
}
if !user.GetID().IsType(identity.TypeUser) {
if !user.GetID().IsType(claims.TypeUser) {
return redirect, nil
}
@@ -380,7 +381,7 @@ func (s *Service) resolveIdenity(ctx context.Context, orgID int64, namespaceID i
ctx, span := s.tracer.Start(ctx, "authn.resolveIdentity")
defer span.End()
if namespaceID.IsType(identity.TypeUser) {
if namespaceID.IsType(claims.TypeUser) {
return &authn.Identity{
OrgID: orgID,
ID: namespaceID,
@@ -391,7 +392,7 @@ func (s *Service) resolveIdenity(ctx context.Context, orgID int64, namespaceID i
}}, nil
}
if namespaceID.IsType(identity.TypeServiceAccount) {
if namespaceID.IsType(claims.TypeServiceAccount) {
return &authn.Identity{
ID: namespaceID,
OrgID: orgID,
+8 -7
View File
@@ -15,6 +15,7 @@ import (
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
@@ -420,31 +421,31 @@ func TestService_Logout(t *testing.T) {
tests := []TestCase{
{
desc: "should redirect to default redirect url when identity is not a user",
identity: &authn.Identity{ID: identity.NewTypedID(identity.TypeServiceAccount, 1)},
identity: &authn.Identity{ID: identity.NewTypedID(claims.TypeServiceAccount, 1)},
expectedRedirect: &authn.Redirect{URL: "http://localhost:3000/login"},
},
{
desc: "should redirect to default redirect url when no external provider was used to authenticate",
identity: &authn.Identity{ID: identity.NewTypedID(identity.TypeUser, 1)},
identity: &authn.Identity{ID: identity.NewTypedID(claims.TypeUser, 1)},
expectedRedirect: &authn.Redirect{URL: "http://localhost:3000/login"},
expectedTokenRevoked: true,
},
{
desc: "should redirect to default redirect url when client is not found",
identity: &authn.Identity{ID: identity.NewTypedID(identity.TypeUser, 1), AuthenticatedBy: "notfound"},
identity: &authn.Identity{ID: identity.NewTypedID(claims.TypeUser, 1), AuthenticatedBy: "notfound"},
expectedRedirect: &authn.Redirect{URL: "http://localhost:3000/login"},
expectedTokenRevoked: true,
},
{
desc: "should redirect to default redirect url when client do not implement logout extension",
identity: &authn.Identity{ID: identity.NewTypedID(identity.TypeUser, 1), AuthenticatedBy: "azuread"},
identity: &authn.Identity{ID: identity.NewTypedID(claims.TypeUser, 1), AuthenticatedBy: "azuread"},
expectedRedirect: &authn.Redirect{URL: "http://localhost:3000/login"},
client: &authntest.FakeClient{ExpectedName: "auth.client.azuread"},
expectedTokenRevoked: true,
},
{
desc: "should use signout redirect url if configured",
identity: &authn.Identity{ID: identity.NewTypedID(identity.TypeUser, 1), AuthenticatedBy: "azuread"},
identity: &authn.Identity{ID: identity.NewTypedID(claims.TypeUser, 1), AuthenticatedBy: "azuread"},
expectedRedirect: &authn.Redirect{URL: "some-url"},
client: &authntest.FakeClient{ExpectedName: "auth.client.azuread"},
signoutRedirectURL: "some-url",
@@ -452,7 +453,7 @@ func TestService_Logout(t *testing.T) {
},
{
desc: "should redirect to client specific url",
identity: &authn.Identity{ID: identity.NewTypedID(identity.TypeUser, 1), AuthenticatedBy: "azuread"},
identity: &authn.Identity{ID: identity.NewTypedID(claims.TypeUser, 1), AuthenticatedBy: "azuread"},
expectedRedirect: &authn.Redirect{URL: "http://idp.com/logout"},
client: &authntest.MockClient{
NameFunc: func() string { return "auth.client.azuread" },
@@ -527,7 +528,7 @@ func TestService_ResolveIdentity(t *testing.T) {
t.Run("should resolve for valid namespace if client is registered", func(t *testing.T) {
svc := setupTests(t, func(svc *Service) {
svc.RegisterClient(&authntest.MockClient{
IdentityTypeFunc: func() identity.IdentityType { return identity.TypeAPIKey },
IdentityTypeFunc: func() claims.IdentityType { return claims.TypeAPIKey },
ResolveIdentityFunc: func(ctx context.Context, orgID int64, namespaceID identity.TypedID) (*authn.Identity, error) {
return &authn.Identity{}, nil
},
@@ -8,7 +8,7 @@ import (
"golang.org/x/sync/singleflight"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/login/social"
@@ -42,7 +42,7 @@ func (s *OAuthTokenSync) SyncOauthTokenHook(ctx context.Context, id *authn.Ident
defer span.End()
// only perform oauth token check if identity is a user
if !id.ID.IsType(identity.TypeUser) {
if !id.ID.IsType(claims.TypeUser) {
return nil
}
@@ -6,7 +6,7 @@ import (
"fmt"
"sort"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/accesscontrol"
@@ -39,7 +39,7 @@ func (s *OrgSync) SyncOrgRolesHook(ctx context.Context, id *authn.Identity, _ *a
ctxLogger := s.log.FromContext(ctx).New("id", id.ID, "login", id.Login)
if !id.ID.IsType(identity.TypeUser) {
if !id.ID.IsType(claims.TypeUser) {
ctxLogger.Warn("Failed to sync org role, invalid namespace for identity", "type", id.ID.Type())
return nil
}
@@ -145,7 +145,7 @@ func (s *OrgSync) SetDefaultOrgHook(ctx context.Context, currentIdentity *authn.
ctxLogger := s.log.FromContext(ctx)
if !currentIdentity.ID.IsType(identity.TypeUser) {
if !currentIdentity.ID.IsType(claims.TypeUser) {
ctxLogger.Debug("Skipping default org sync, not a user", "type", currentIdentity.ID.Type())
return
}
@@ -6,8 +6,8 @@ import (
"golang.org/x/exp/maps"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/accesscontrol"
@@ -148,7 +148,7 @@ func (s *RBACSync) SyncCloudRoles(ctx context.Context, ident *authn.Identity, r
return nil
}
if !ident.ID.IsType(identity.TypeUser) {
if !ident.ID.IsType(claims.TypeUser) {
s.log.FromContext(ctx).Debug("Skip syncing cloud role", "id", ident.ID)
return nil
}
@@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
@@ -67,7 +68,7 @@ func TestRBACSync_SyncCloudRoles(t *testing.T) {
desc: "should call sync when authenticated with grafana com and has viewer role",
module: login.GrafanaComAuthModule,
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
},
@@ -78,7 +79,7 @@ func TestRBACSync_SyncCloudRoles(t *testing.T) {
desc: "should call sync when authenticated with grafana com and has editor role",
module: login.GrafanaComAuthModule,
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleEditor},
},
@@ -89,7 +90,7 @@ func TestRBACSync_SyncCloudRoles(t *testing.T) {
desc: "should call sync when authenticated with grafana com and has admin role",
module: login.GrafanaComAuthModule,
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
},
@@ -100,7 +101,7 @@ func TestRBACSync_SyncCloudRoles(t *testing.T) {
desc: "should not call sync when authenticated with grafana com and has invalid role",
module: login.GrafanaComAuthModule,
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleType("something else")},
},
@@ -111,7 +112,7 @@ func TestRBACSync_SyncCloudRoles(t *testing.T) {
desc: "should not call sync when not authenticated with grafana com",
module: login.LDAPAuthModule,
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
},
@@ -157,7 +158,7 @@ func TestRBACSync_cloudRolesToAddAndRemove(t *testing.T) {
{
desc: "should map Cloud Viewer to Grafana Cloud Viewer and Support ticket reader",
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
},
@@ -176,7 +177,7 @@ func TestRBACSync_cloudRolesToAddAndRemove(t *testing.T) {
{
desc: "should map Cloud Editor to Grafana Cloud Editor and Support ticket admin",
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleEditor},
},
@@ -194,7 +195,7 @@ func TestRBACSync_cloudRolesToAddAndRemove(t *testing.T) {
{
desc: "should map Cloud Admin to Grafana Cloud Admin and Support ticket admin",
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
},
@@ -212,7 +213,7 @@ func TestRBACSync_cloudRolesToAddAndRemove(t *testing.T) {
{
desc: "should return an error for not supported role",
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleNone},
},
+10 -9
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/log"
@@ -118,7 +119,7 @@ func (s *UserSync) FetchSyncedUserHook(ctx context.Context, id *authn.Identity,
return nil
}
if !id.ID.IsType(identity.TypeUser, identity.TypeServiceAccount) {
if !id.ID.IsType(claims.TypeUser, claims.TypeServiceAccount) {
return nil
}
@@ -159,7 +160,7 @@ func (s *UserSync) SyncLastSeenHook(ctx context.Context, id *authn.Identity, r *
return nil
}
if !id.ID.IsType(identity.TypeUser, identity.TypeServiceAccount) {
if !id.ID.IsType(claims.TypeUser, claims.TypeServiceAccount) {
return nil
}
@@ -195,7 +196,7 @@ func (s *UserSync) EnableUserHook(ctx context.Context, id *authn.Identity, _ *au
return nil
}
if !id.ID.IsType(identity.TypeUser) {
if !id.ID.IsType(claims.TypeUser) {
return nil
}
@@ -418,8 +419,8 @@ func (s *UserSync) lookupByOneOf(ctx context.Context, params login.UserLookupPar
// syncUserToIdentity syncs a user to an identity.
// This is used to update the identity with the latest user information.
func syncUserToIdentity(usr *user.User, id *authn.Identity) {
id.ID = identity.NewTypedID(identity.TypeUser, usr.ID)
id.UID = identity.NewTypedIDString(identity.TypeUser, usr.UID)
id.ID = identity.NewTypedID(claims.TypeUser, usr.ID)
id.UID = identity.NewTypedIDString(claims.TypeUser, usr.UID)
id.Login = usr.Login
id.Email = usr.Email
id.Name = usr.Name
@@ -429,11 +430,11 @@ func syncUserToIdentity(usr *user.User, id *authn.Identity) {
// syncSignedInUserToIdentity syncs a user to an identity.
func syncSignedInUserToIdentity(usr *user.SignedInUser, id *authn.Identity) {
var ns identity.IdentityType
if id.ID.IsType(identity.TypeServiceAccount) {
ns = identity.TypeServiceAccount
var ns claims.IdentityType
if id.ID.IsType(claims.TypeServiceAccount) {
ns = claims.TypeServiceAccount
} else {
ns = identity.TypeUser
ns = claims.TypeUser
}
id.UID = identity.NewTypedIDString(ns, usr.UserUID)
@@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/authn"
@@ -484,7 +485,7 @@ func TestUserSync_EnableDisabledUserHook(t *testing.T) {
{
desc: "should skip if correct flag is not set",
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
IsDisabled: true,
ClientParams: authn.ClientParams{EnableUser: false},
},
@@ -493,7 +494,7 @@ func TestUserSync_EnableDisabledUserHook(t *testing.T) {
{
desc: "should skip if identity is not a user",
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeAPIKey, 1),
ID: identity.NewTypedID(claims.TypeAPIKey, 1),
IsDisabled: true,
ClientParams: authn.ClientParams{EnableUser: true},
},
@@ -502,7 +503,7 @@ func TestUserSync_EnableDisabledUserHook(t *testing.T) {
{
desc: "should enabled disabled user",
identity: &authn.Identity{
ID: identity.NewTypedID(identity.TypeUser, 1),
ID: identity.NewTypedID(claims.TypeUser, 1),
IsDisabled: true,
ClientParams: authn.ClientParams{EnableUser: true},
},