mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 21:32:19 +08:00
Auth: Add tracing to auth clients and AuthToken service (#107878)
* Add tracing to auth clients + authtoken svc * Fix span names * Fix ext_jwt.go * Fix idimpl/service * Update wire_gen.go * Add tracing to JWT client * Lint
This commit is contained in:
@ -648,7 +648,7 @@ func Initialize(cfg *setting.Cfg, opts Options, apiOpts api.ServerOptions) (*Ser
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idimplService := idimpl.ProvideService(cfg, localSigner, remoteCache, authnService, registerer)
|
||||
idimplService := idimpl.ProvideService(cfg, localSigner, remoteCache, authnService, registerer, tracer)
|
||||
verifier := userimpl.ProvideVerifier(cfg, userService, tempuserService, notificationService, idimplService)
|
||||
httpServer, err := api.ProvideHTTPServer(apiOpts, cfg, routeRegisterImpl, inProcBus, renderingService, ossLicensingService, hooksService, cacheService, sqlStore, ossDataSourceRequestValidator, pluginstoreService, service12, pluginstoreService, middlewareHandler, pluginerrsStore, pluginInstaller, ossImpl, cacheServiceImpl, userAuthTokenService, cleanUpService, shortURLService, queryHistoryService, correlationsService, remoteCache, provisioningServiceImpl, accessControl, dataSourceProxyService, searchSearchService, grafanaLive, gateway, plugincontextProvider, contexthandlerContextHandler, logger, featureToggles, alertNG, libraryPanelService, libraryElementService, quotaService, socialService, tracingService, serviceService, grafanaService, pluginsService, ossService, service13, queryServiceImpl, filestoreService, serviceAccountsProxy, pluginassetsService, authinfoimplService, storageService, notificationService, dashboardService, dashboardProvisioningService, folderimplService, ossProvider, serviceImpl, service11, avatarCacheServer, prefService, folderPermissionsService, dashboardPermissionsService, dashverService, starService, csrfCSRF, noop, playlistService, apikeyService, kvStore, secretsMigrator, secretsService, secretMigrationProviderImpl, secretsKVStore, apiApi, userService, tempuserService, loginattemptimplService, orgService, deletionService, teamService, acimplService, navtreeService, repositoryImpl, tagimplService, searchHTTPService, oauthtokenService, statsService, authnService, pluginscdnService, gatherer, apiAPI, registerer, eventualRestConfigProvider, anonDeviceService, verifier, preinstallImpl)
|
||||
if err != nil {
|
||||
@ -1161,7 +1161,7 @@ func InitializeForTest(t sqlutil.ITestDB, testingT interface {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idimplService := idimpl.ProvideService(cfg, localSigner, remoteCache, authnService, registerer)
|
||||
idimplService := idimpl.ProvideService(cfg, localSigner, remoteCache, authnService, registerer, tracer)
|
||||
verifier := userimpl.ProvideVerifier(cfg, userService, tempuserService, notificationServiceMock, idimplService)
|
||||
httpServer, err := api.ProvideHTTPServer(apiOpts, cfg, routeRegisterImpl, inProcBus, renderingService, ossLicensingService, hooksService, cacheService, sqlStore, ossDataSourceRequestValidator, pluginstoreService, service12, pluginstoreService, middlewareHandler, pluginerrsStore, pluginInstaller, ossImpl, cacheServiceImpl, userAuthTokenService, cleanUpService, shortURLService, queryHistoryService, correlationsService, remoteCache, provisioningServiceImpl, accessControl, dataSourceProxyService, searchSearchService, grafanaLive, gateway, plugincontextProvider, contexthandlerContextHandler, logger, featureToggles, alertNG, libraryPanelService, libraryElementService, quotaService, socialService, tracingService, serviceService, grafanaService, pluginsService, ossService, service13, queryServiceImpl, filestoreService, serviceAccountsProxy, pluginassetsService, authinfoimplService, storageService, notificationServiceMock, dashboardService, dashboardProvisioningService, folderimplService, ossProvider, serviceImpl, service11, avatarCacheServer, prefService, folderPermissionsService, dashboardPermissionsService, dashverService, starService, csrfCSRF, noop, playlistService, apikeyService, kvStore, secretsMigrator, secretsService, secretMigrationProviderImpl, secretsKVStore, apiApi, userService, tempuserService, loginattemptimplService, orgService, deletionService, teamService, acimplService, navtreeService, repositoryImpl, tagimplService, searchHTTPService, oauthtokentestService, statsService, authnService, pluginscdnService, gatherer, apiAPI, registerer, eventualRestConfigProvider, anonDeviceService, verifier, preinstallImpl)
|
||||
if err != nil {
|
||||
|
@ -80,6 +80,9 @@ type UserAuthTokenService struct {
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) CreateToken(ctx context.Context, cmd *auth.CreateTokenCommand) (*auth.UserToken, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.CreateToken")
|
||||
defer span.End()
|
||||
|
||||
token, hashedToken, err := generateAndHashToken(s.cfg.SecretKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -136,6 +139,9 @@ func (s *UserAuthTokenService) CreateToken(ctx context.Context, cmd *auth.Create
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) LookupToken(ctx context.Context, unhashedToken string) (*auth.UserToken, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.LookupToken")
|
||||
defer span.End()
|
||||
|
||||
hashedToken := hashToken(s.cfg.SecretKey, unhashedToken)
|
||||
var model userAuthToken
|
||||
var exists bool
|
||||
@ -234,6 +240,9 @@ func (s *UserAuthTokenService) LookupToken(ctx context.Context, unhashedToken st
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) GetTokenByExternalSessionID(ctx context.Context, externalSessionID int64) (*auth.UserToken, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.GetTokenByExternalSessionID")
|
||||
defer span.End()
|
||||
|
||||
var token userAuthToken
|
||||
err := s.sqlStore.WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||
exists, err := dbSession.Where("external_session_id = ?", externalSessionID).Get(&token)
|
||||
@ -258,14 +267,23 @@ func (s *UserAuthTokenService) GetTokenByExternalSessionID(ctx context.Context,
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) GetExternalSession(ctx context.Context, externalSessionID int64) (*auth.ExternalSession, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.GetExternalSession")
|
||||
defer span.End()
|
||||
|
||||
return s.externalSessionStore.Get(ctx, externalSessionID)
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) FindExternalSessions(ctx context.Context, query *auth.ListExternalSessionQuery) ([]*auth.ExternalSession, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.FindExternalSessions")
|
||||
defer span.End()
|
||||
|
||||
return s.externalSessionStore.List(ctx, query)
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) UpdateExternalSession(ctx context.Context, externalSessionID int64, cmd *auth.UpdateExternalSessionCommand) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.UpdateExternalSession")
|
||||
defer span.End()
|
||||
|
||||
return s.externalSessionStore.Update(ctx, externalSessionID, cmd)
|
||||
}
|
||||
|
||||
@ -329,6 +347,9 @@ func (s *UserAuthTokenService) RotateToken(ctx context.Context, cmd auth.RotateC
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) rotateToken(ctx context.Context, token *auth.UserToken, clientIP net.IP, userAgent string) (*auth.UserToken, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.rotateToken")
|
||||
defer span.End()
|
||||
|
||||
var clientIPStr string
|
||||
if clientIP != nil {
|
||||
clientIPStr = clientIP.String()
|
||||
@ -385,6 +406,9 @@ func (s *UserAuthTokenService) rotateToken(ctx context.Context, token *auth.User
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) RevokeToken(ctx context.Context, token *auth.UserToken, soft bool) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.RevokeToken")
|
||||
defer span.End()
|
||||
|
||||
if token == nil {
|
||||
return auth.ErrUserTokenNotFound
|
||||
}
|
||||
@ -434,6 +458,9 @@ func (s *UserAuthTokenService) RevokeToken(ctx context.Context, token *auth.User
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) RevokeAllUserTokens(ctx context.Context, userId int64) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.RevokeAllUserTokens")
|
||||
defer span.End()
|
||||
|
||||
return s.sqlStore.InTransaction(ctx, func(ctx context.Context) error {
|
||||
ctxLogger := s.log.FromContext(ctx)
|
||||
err := s.sqlStore.WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||
@ -466,6 +493,9 @@ func (s *UserAuthTokenService) RevokeAllUserTokens(ctx context.Context, userId i
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) BatchRevokeAllUserTokens(ctx context.Context, userIds []int64) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.BatchRevokeAllUserTokens")
|
||||
defer span.End()
|
||||
|
||||
return s.sqlStore.InTransaction(ctx, func(ctx context.Context) error {
|
||||
ctxLogger := s.log.FromContext(ctx)
|
||||
if len(userIds) == 0 {
|
||||
@ -507,6 +537,9 @@ func (s *UserAuthTokenService) BatchRevokeAllUserTokens(ctx context.Context, use
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) GetUserToken(ctx context.Context, userId, userTokenId int64) (*auth.UserToken, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.GetUserToken")
|
||||
defer span.End()
|
||||
|
||||
var result auth.UserToken
|
||||
err := s.sqlStore.WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||
var token userAuthToken
|
||||
@ -526,6 +559,9 @@ func (s *UserAuthTokenService) GetUserToken(ctx context.Context, userId, userTok
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) GetUserTokens(ctx context.Context, userId int64) ([]*auth.UserToken, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.GetUserTokens")
|
||||
defer span.End()
|
||||
|
||||
result := []*auth.UserToken{}
|
||||
err := s.sqlStore.WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||
var tokens []*userAuthToken
|
||||
@ -554,6 +590,9 @@ func (s *UserAuthTokenService) GetUserTokens(ctx context.Context, userId int64)
|
||||
|
||||
// ActiveTokenCount returns the number of active tokens. If userID is nil, the count is for all users.
|
||||
func (s *UserAuthTokenService) ActiveTokenCount(ctx context.Context, userID *int64) (int64, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.ActiveTokenCount")
|
||||
defer span.End()
|
||||
|
||||
if userID != nil && *userID < 1 {
|
||||
return 0, errUserIDInvalid
|
||||
}
|
||||
@ -574,6 +613,9 @@ func (s *UserAuthTokenService) ActiveTokenCount(ctx context.Context, userID *int
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) DeleteUserRevokedTokens(ctx context.Context, userID int64, window time.Duration) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.DeleteUserRevokedTokens")
|
||||
defer span.End()
|
||||
|
||||
return s.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
query := "DELETE FROM user_auth_token WHERE user_id = ? AND revoked_at > 0 AND revoked_at <= ?"
|
||||
res, err := sess.Exec(query, userID, time.Now().Add(-window).Unix())
|
||||
@ -592,6 +634,9 @@ func (s *UserAuthTokenService) DeleteUserRevokedTokens(ctx context.Context, user
|
||||
}
|
||||
|
||||
func (s *UserAuthTokenService) GetUserRevokedTokens(ctx context.Context, userId int64) ([]*auth.UserToken, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authtoken.GetUserRevokedTokens")
|
||||
defer span.End()
|
||||
|
||||
result := []*auth.UserToken{}
|
||||
err := s.sqlStore.WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||
var tokens []*userAuthToken
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/sync/singleflight"
|
||||
|
||||
authnlib "github.com/grafana/authlib/authn"
|
||||
@ -32,18 +33,18 @@ var _ auth.IDService = (*Service)(nil)
|
||||
|
||||
func ProvideService(
|
||||
cfg *setting.Cfg, signer auth.IDSigner,
|
||||
cache remotecache.CacheStorage,
|
||||
authnService authn.Service,
|
||||
reg prometheus.Registerer,
|
||||
cache remotecache.CacheStorage, authnService authn.Service,
|
||||
reg prometheus.Registerer, tracer trace.Tracer,
|
||||
) *Service {
|
||||
s := &Service{
|
||||
cfg: cfg, logger: log.New("id-service"),
|
||||
signer: signer, cache: cache,
|
||||
metrics: newMetrics(reg),
|
||||
nsMapper: request.GetNamespaceMapper(cfg),
|
||||
tracer: tracer,
|
||||
}
|
||||
|
||||
authnService.RegisterPostAuthHook(s.hook, 140)
|
||||
authnService.RegisterPostAuthHook(s.SyncIDToken, 140)
|
||||
|
||||
return s
|
||||
}
|
||||
@ -55,10 +56,14 @@ type Service struct {
|
||||
cache remotecache.CacheStorage
|
||||
si singleflight.Group
|
||||
metrics *metrics
|
||||
tracer trace.Tracer
|
||||
nsMapper request.NamespaceMapper
|
||||
}
|
||||
|
||||
func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (string, *authnlib.Claims[authnlib.IDTokenClaims], error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.SignIdentity")
|
||||
defer span.End()
|
||||
|
||||
defer func(t time.Time) {
|
||||
s.metrics.tokenSigningDurationHistogram.Observe(time.Since(t).Seconds())
|
||||
}(time.Now())
|
||||
@ -140,10 +145,15 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
|
||||
}
|
||||
|
||||
func (s *Service) RemoveIDToken(ctx context.Context, id identity.Requester) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.RemoveIDToken")
|
||||
defer span.End()
|
||||
|
||||
return s.cache.Delete(ctx, getCacheKey(id))
|
||||
}
|
||||
|
||||
func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
|
||||
func (s *Service) SyncIDToken(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.SyncIDToken")
|
||||
defer span.End()
|
||||
// FIXME(kalleep): we should probably lazy load this
|
||||
token, idClaims, err := s.SignIdentity(ctx, identity)
|
||||
if err != nil {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/auth/idtest"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
@ -29,7 +30,7 @@ func Test_ProvideService(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_ = ProvideService(setting.NewCfg(), nil, nil, authnService, nil)
|
||||
_ = ProvideService(setting.NewCfg(), nil, nil, authnService, nil, tracing.InitializeTracerForTest())
|
||||
assert.True(t, hookRegistered)
|
||||
})
|
||||
}
|
||||
@ -51,7 +52,7 @@ func TestService_SignIdentity(t *testing.T) {
|
||||
t.Run("should sign identity", func(t *testing.T) {
|
||||
s := ProvideService(
|
||||
setting.NewCfg(), signer, remotecache.NewFakeCacheStorage(),
|
||||
&authntest.FakeService{}, nil,
|
||||
&authntest.FakeService{}, nil, tracing.InitializeTracerForTest(),
|
||||
)
|
||||
token, _, err := s.SignIdentity(context.Background(), &authn.Identity{ID: "1", Type: claims.TypeUser})
|
||||
require.NoError(t, err)
|
||||
@ -61,7 +62,7 @@ func TestService_SignIdentity(t *testing.T) {
|
||||
t.Run("should sign identity with authenticated by if user is externally authenticated", func(t *testing.T) {
|
||||
s := ProvideService(
|
||||
setting.NewCfg(), signer, remotecache.NewFakeCacheStorage(),
|
||||
&authntest.FakeService{}, nil,
|
||||
&authntest.FakeService{}, nil, tracing.InitializeTracerForTest(),
|
||||
)
|
||||
token, _, err := s.SignIdentity(context.Background(), &authn.Identity{
|
||||
ID: "1",
|
||||
@ -86,7 +87,7 @@ func TestService_SignIdentity(t *testing.T) {
|
||||
t.Run("should sign identity with authenticated by if user is externally authenticated", func(t *testing.T) {
|
||||
s := ProvideService(
|
||||
setting.NewCfg(), signer, remotecache.NewFakeCacheStorage(),
|
||||
&authntest.FakeService{}, nil,
|
||||
&authntest.FakeService{}, nil, tracing.InitializeTracerForTest(),
|
||||
)
|
||||
_, gotClaims, err := s.SignIdentity(context.Background(), &authn.Identity{
|
||||
ID: "1",
|
||||
@ -106,7 +107,7 @@ func TestService_SignIdentity(t *testing.T) {
|
||||
t.Run("should sign new token if org role has changed", func(t *testing.T) {
|
||||
s := ProvideService(
|
||||
setting.NewCfg(), signer, remotecache.NewFakeCacheStorage(),
|
||||
&authntest.FakeService{}, nil,
|
||||
&authntest.FakeService{}, nil, tracing.InitializeTracerForTest(),
|
||||
)
|
||||
|
||||
ident := &authn.Identity{
|
||||
|
@ -48,10 +48,10 @@ func ProvideRegistration(
|
||||
logger := log.New("authn.registration")
|
||||
|
||||
authnSvc.RegisterClient(clients.ProvideRender(renderService))
|
||||
authnSvc.RegisterClient(clients.ProvideAPIKey(apikeyService))
|
||||
authnSvc.RegisterClient(clients.ProvideAPIKey(apikeyService, tracer))
|
||||
|
||||
if cfg.LoginCookieName != "" {
|
||||
authnSvc.RegisterClient(clients.ProvideSession(cfg, sessionService, authInfoService))
|
||||
authnSvc.RegisterClient(clients.ProvideSession(cfg, sessionService, authInfoService, tracer))
|
||||
}
|
||||
|
||||
var proxyClients []authn.ProxyClient
|
||||
@ -59,20 +59,20 @@ func ProvideRegistration(
|
||||
|
||||
// always register LDAP if LDAP is enabled in SSO settings
|
||||
if cfg.LDAPAuthEnabled || features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsLDAP) {
|
||||
ldap := clients.ProvideLDAP(cfg, ldapService, userService, authInfoService)
|
||||
ldap := clients.ProvideLDAP(cfg, ldapService, userService, authInfoService, tracer)
|
||||
proxyClients = append(proxyClients, ldap)
|
||||
passwordClients = append(passwordClients, ldap)
|
||||
}
|
||||
|
||||
if !cfg.DisableLogin {
|
||||
grafana := clients.ProvideGrafana(cfg, userService)
|
||||
grafana := clients.ProvideGrafana(cfg, userService, tracer)
|
||||
proxyClients = append(proxyClients, grafana)
|
||||
passwordClients = append(passwordClients, grafana)
|
||||
}
|
||||
|
||||
// if we have password clients configure check if basic auth or form auth is enabled
|
||||
if len(passwordClients) > 0 {
|
||||
passwordClient := clients.ProvidePassword(loginAttempts, passwordClients...)
|
||||
passwordClient := clients.ProvidePassword(loginAttempts, tracer, passwordClients...)
|
||||
if cfg.BasicAuthEnabled {
|
||||
authnSvc.RegisterClient(clients.ProvideBasic(passwordClient))
|
||||
}
|
||||
@ -103,7 +103,7 @@ func ProvideRegistration(
|
||||
}
|
||||
|
||||
if cfg.AuthProxy.Enabled && len(proxyClients) > 0 {
|
||||
proxy, err := clients.ProvideProxy(cfg, cache, proxyClients...)
|
||||
proxy, err := clients.ProvideProxy(cfg, cache, tracer, proxyClients...)
|
||||
if err != nil {
|
||||
logger.Error("Failed to configure auth proxy", "err", err)
|
||||
} else {
|
||||
@ -113,16 +113,16 @@ func ProvideRegistration(
|
||||
|
||||
if cfg.JWTAuth.Enabled {
|
||||
orgRoleMapper := connectors.ProvideOrgRoleMapper(cfg, orgService)
|
||||
authnSvc.RegisterClient(clients.ProvideJWT(jwtService, orgRoleMapper, cfg))
|
||||
authnSvc.RegisterClient(clients.ProvideJWT(jwtService, orgRoleMapper, cfg, tracer))
|
||||
}
|
||||
|
||||
if cfg.ExtJWTAuth.Enabled {
|
||||
authnSvc.RegisterClient(clients.ProvideExtendedJWT(cfg))
|
||||
authnSvc.RegisterClient(clients.ProvideExtendedJWT(cfg, tracer))
|
||||
}
|
||||
|
||||
for name := range socialService.GetOAuthProviders() {
|
||||
clientName := authn.ClientWithPrefix(name)
|
||||
authnSvc.RegisterClient(clients.ProvideOAuth(clientName, cfg, oauthTokenService, socialService, settingsProviderService, features))
|
||||
authnSvc.RegisterClient(clients.ProvideOAuth(clientName, cfg, oauthTokenService, socialService, settingsProviderService, features, tracer))
|
||||
}
|
||||
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagProvisioning) {
|
||||
|
@ -7,6 +7,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/components/apikeygen"
|
||||
@ -35,16 +37,18 @@ const (
|
||||
metaKeySkipLastUsed = "keySkipLastUsed"
|
||||
)
|
||||
|
||||
func ProvideAPIKey(apiKeyService apikey.Service) *APIKey {
|
||||
func ProvideAPIKey(apiKeyService apikey.Service, tracer trace.Tracer) *APIKey {
|
||||
return &APIKey{
|
||||
log: log.New(authn.ClientAPIKey),
|
||||
apiKeyService: apiKeyService,
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
type APIKey struct {
|
||||
log log.Logger
|
||||
apiKeyService apikey.Service
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
func (s *APIKey) Name() string {
|
||||
@ -52,6 +56,8 @@ func (s *APIKey) Name() string {
|
||||
}
|
||||
|
||||
func (s *APIKey) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.apikey.Authenticate")
|
||||
defer span.End()
|
||||
key, err := s.getAPIKey(ctx, getTokenFromRequest(r))
|
||||
if err != nil {
|
||||
if errors.Is(err, apikeygen.ErrInvalidApiKey) {
|
||||
@ -84,6 +90,8 @@ func (s *APIKey) IsEnabled() bool {
|
||||
}
|
||||
|
||||
func (s *APIKey) getAPIKey(ctx context.Context, token string) (*apikey.APIKey, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.apikey.getAPIKey")
|
||||
defer span.End()
|
||||
fn := s.getFromToken
|
||||
if !strings.HasPrefix(token, satokengen.GrafanaPrefix) {
|
||||
fn = s.getFromTokenLegacy
|
||||
@ -98,6 +106,8 @@ func (s *APIKey) getAPIKey(ctx context.Context, token string) (*apikey.APIKey, e
|
||||
}
|
||||
|
||||
func (s *APIKey) getFromToken(ctx context.Context, token string) (*apikey.APIKey, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.apikey.getFromToken")
|
||||
defer span.End()
|
||||
decoded, err := satokengen.Decode(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -112,6 +122,8 @@ func (s *APIKey) getFromToken(ctx context.Context, token string) (*apikey.APIKey
|
||||
}
|
||||
|
||||
func (s *APIKey) getFromTokenLegacy(ctx context.Context, token string) (*apikey.APIKey, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.apikey.getFromTokenLegacy")
|
||||
defer span.End()
|
||||
decoded, err := apikeygen.Decode(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -144,6 +156,9 @@ func (s *APIKey) Priority() uint {
|
||||
}
|
||||
|
||||
func (s *APIKey) Hook(ctx context.Context, identity *authn.Identity, r *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.apikey.Hook") //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
|
||||
if r.GetMeta(metaKeySkipLastUsed) != "" {
|
||||
return nil
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/components/apikeygen"
|
||||
"github.com/grafana/grafana/pkg/components/satokengen"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/apikey"
|
||||
"github.com/grafana/grafana/pkg/services/apikey/apikeytest"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
@ -106,7 +107,7 @@ func TestAPIKey_Authenticate(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
c := ProvideAPIKey(&apikeytest.Service{ExpectedAPIKey: tt.expectedKey})
|
||||
c := ProvideAPIKey(&apikeytest.Service{ExpectedAPIKey: tt.expectedKey}, tracing.InitializeTracerForTest())
|
||||
|
||||
identity, err := c.Authenticate(context.Background(), tt.req)
|
||||
if tt.expectedErr != nil {
|
||||
@ -173,7 +174,7 @@ func TestAPIKey_Test(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
c := ProvideAPIKey(&apikeytest.Service{})
|
||||
c := ProvideAPIKey(&apikeytest.Service{}, tracing.InitializeTracerForTest())
|
||||
assert.Equal(t, tt.expected, c.Test(context.Background(), tt.req))
|
||||
})
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
authlib "github.com/grafana/authlib/authn"
|
||||
claims "github.com/grafana/authlib/types"
|
||||
@ -41,7 +42,7 @@ var (
|
||||
)
|
||||
)
|
||||
|
||||
func ProvideExtendedJWT(cfg *setting.Cfg) *ExtendedJWT {
|
||||
func ProvideExtendedJWT(cfg *setting.Cfg, tracer trace.Tracer) *ExtendedJWT {
|
||||
keys := authlib.NewKeyRetriever(authlib.KeyRetrieverConfig{
|
||||
SigningKeysURL: cfg.ExtJWTAuth.JWKSUrl,
|
||||
})
|
||||
@ -60,6 +61,7 @@ func ProvideExtendedJWT(cfg *setting.Cfg) *ExtendedJWT {
|
||||
namespaceMapper: request.GetNamespaceMapper(cfg),
|
||||
accessTokenVerifier: accessTokenVerifier,
|
||||
idTokenVerifier: idTokenVerifier,
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,9 +71,13 @@ type ExtendedJWT struct {
|
||||
accessTokenVerifier authlib.Verifier[authlib.AccessTokenClaims]
|
||||
idTokenVerifier authlib.Verifier[authlib.IDTokenClaims]
|
||||
namespaceMapper request.NamespaceMapper
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
func (s *ExtendedJWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.extjwt.Authenticate")
|
||||
defer span.End()
|
||||
|
||||
jwtToken := s.retrieveAuthenticationToken(r.HTTPRequest)
|
||||
|
||||
accessTokenClaims, err := s.accessTokenVerifier.Verify(ctx, jwtToken)
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
authnlib "github.com/grafana/authlib/authn"
|
||||
claims "github.com/grafana/authlib/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
@ -699,7 +700,7 @@ func setupTestCtx(cfg *setting.Cfg) *testEnv {
|
||||
}
|
||||
}
|
||||
|
||||
extJwtClient := ProvideExtendedJWT(cfg)
|
||||
extJwtClient := ProvideExtendedJWT(cfg, tracing.InitializeTracerForTest())
|
||||
|
||||
return &testEnv{
|
||||
s: extJwtClient,
|
||||
|
@ -7,6 +7,8 @@ import (
|
||||
"net/mail"
|
||||
"strconv"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
@ -19,13 +21,14 @@ import (
|
||||
var _ authn.ProxyClient = new(Grafana)
|
||||
var _ authn.PasswordClient = new(Grafana)
|
||||
|
||||
func ProvideGrafana(cfg *setting.Cfg, userService user.Service) *Grafana {
|
||||
return &Grafana{cfg, userService}
|
||||
func ProvideGrafana(cfg *setting.Cfg, userService user.Service, tracer trace.Tracer) *Grafana {
|
||||
return &Grafana{cfg, userService, tracer}
|
||||
}
|
||||
|
||||
type Grafana struct {
|
||||
cfg *setting.Cfg
|
||||
userService user.Service
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
func (c *Grafana) String() string {
|
||||
@ -33,6 +36,9 @@ func (c *Grafana) String() string {
|
||||
}
|
||||
|
||||
func (c *Grafana) AuthenticateProxy(ctx context.Context, r *authn.Request, username string, additional map[string]string) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.grafana.AuthenticateProxy") //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
|
||||
identity := &authn.Identity{
|
||||
AuthenticatedBy: login.AuthProxyAuthModule,
|
||||
AuthID: username,
|
||||
@ -91,6 +97,9 @@ func (c *Grafana) AuthenticateProxy(ctx context.Context, r *authn.Request, usern
|
||||
}
|
||||
|
||||
func (c *Grafana) AuthenticatePassword(ctx context.Context, r *authn.Request, username, password string) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.grafana.AuthenticatePassword")
|
||||
defer span.End()
|
||||
|
||||
usr, err := c.userService.GetByLogin(ctx, &user.GetUserByLoginQuery{LoginOrEmail: username})
|
||||
if err != nil {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
@ -97,7 +98,7 @@ func TestGrafana_AuthenticateProxy(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
cfg.AuthProxy.AutoSignUp = true
|
||||
cfg.AuthProxy.HeaderProperty = tt.proxyProperty
|
||||
c := ProvideGrafana(cfg, usertest.NewUserServiceFake())
|
||||
c := ProvideGrafana(cfg, usertest.NewUserServiceFake(), tracing.InitializeTracerForTest())
|
||||
|
||||
identity, err := c.AuthenticateProxy(context.Background(), tt.req, tt.username, tt.additional)
|
||||
assert.ErrorIs(t, err, tt.expectedErr)
|
||||
@ -175,7 +176,7 @@ func TestGrafana_AuthenticatePassword(t *testing.T) {
|
||||
userService.ExpectedError = user.ErrUserNotFound
|
||||
}
|
||||
|
||||
c := ProvideGrafana(setting.NewCfg(), userService)
|
||||
c := ProvideGrafana(setting.NewCfg(), userService, tracing.InitializeTracerForTest())
|
||||
identity, err := c.AuthenticatePassword(context.Background(), &authn.Request{OrgID: 1}, tt.username, tt.password)
|
||||
assert.ErrorIs(t, err, tt.expectedErr)
|
||||
assert.EqualValues(t, tt.expectedIdentity, identity)
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/login/social/connectors"
|
||||
@ -30,13 +32,14 @@ var (
|
||||
"jwt.invalid_role", errutil.WithPublicMessage("Invalid Role in claim"))
|
||||
)
|
||||
|
||||
func ProvideJWT(jwtService auth.JWTVerifierService, orgRoleMapper *connectors.OrgRoleMapper, cfg *setting.Cfg) *JWT {
|
||||
func ProvideJWT(jwtService auth.JWTVerifierService, orgRoleMapper *connectors.OrgRoleMapper, cfg *setting.Cfg, tracer trace.Tracer) *JWT {
|
||||
return &JWT{
|
||||
cfg: cfg,
|
||||
log: log.New(authn.ClientJWT),
|
||||
jwtService: jwtService,
|
||||
orgRoleMapper: orgRoleMapper,
|
||||
orgMappingCfg: orgRoleMapper.ParseOrgMappingSettings(context.Background(), cfg.JWTAuth.OrgMapping, cfg.JWTAuth.RoleAttributeStrict),
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +49,7 @@ type JWT struct {
|
||||
orgMappingCfg connectors.MappingConfiguration
|
||||
log log.Logger
|
||||
jwtService auth.JWTVerifierService
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
func (s *JWT) Name() string {
|
||||
@ -53,6 +57,9 @@ func (s *JWT) Name() string {
|
||||
}
|
||||
|
||||
func (s *JWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.jwt.Authenticate")
|
||||
defer span.End()
|
||||
|
||||
jwtToken := s.retrieveToken(r.HTTPRequest)
|
||||
s.stripSensitiveParam(r.HTTPRequest)
|
||||
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/login/social/connectors"
|
||||
"github.com/grafana/grafana/pkg/services/auth/jwt"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
@ -262,7 +263,7 @@ func TestAuthenticateJWT(t *testing.T) {
|
||||
jwtClient := ProvideJWT(jwtService,
|
||||
connectors.ProvideOrgRoleMapper(tc.cfg,
|
||||
&orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}),
|
||||
tc.cfg)
|
||||
tc.cfg, tracing.InitializeTracerForTest())
|
||||
validHTTPReq := &http.Request{
|
||||
Header: map[string][]string{
|
||||
jwtHeaderName: {"sample-token"}},
|
||||
@ -380,7 +381,7 @@ func TestJWTClaimConfig(t *testing.T) {
|
||||
}
|
||||
jwtClient := ProvideJWT(jwtService, connectors.ProvideOrgRoleMapper(cfg,
|
||||
&orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}),
|
||||
cfg)
|
||||
cfg, tracing.InitializeTracerForTest())
|
||||
_, err := jwtClient.Authenticate(context.Background(), &authn.Request{
|
||||
OrgID: 1,
|
||||
HTTPRequest: httpReq,
|
||||
@ -493,7 +494,7 @@ func TestJWTTest(t *testing.T) {
|
||||
jwtClient := ProvideJWT(jwtService,
|
||||
connectors.ProvideOrgRoleMapper(cfg,
|
||||
&orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}),
|
||||
cfg)
|
||||
cfg, tracing.InitializeTracerForTest())
|
||||
httpReq := &http.Request{
|
||||
URL: &url.URL{RawQuery: "auth_token=" + tc.token},
|
||||
Header: map[string][]string{
|
||||
@ -549,7 +550,7 @@ func TestJWTStripParam(t *testing.T) {
|
||||
jwtClient := ProvideJWT(jwtService,
|
||||
connectors.ProvideOrgRoleMapper(cfg,
|
||||
&orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}),
|
||||
cfg)
|
||||
cfg, tracing.InitializeTracerForTest())
|
||||
_, err := jwtClient.Authenticate(context.Background(), &authn.Request{
|
||||
OrgID: 1,
|
||||
HTTPRequest: httpReq,
|
||||
@ -608,7 +609,7 @@ func TestJWTSubClaimsConfig(t *testing.T) {
|
||||
jwtClient := ProvideJWT(jwtService,
|
||||
connectors.ProvideOrgRoleMapper(cfg,
|
||||
&orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}),
|
||||
cfg)
|
||||
cfg, tracing.InitializeTracerForTest())
|
||||
identity, err := jwtClient.Authenticate(context.Background(), &authn.Request{
|
||||
OrgID: 1,
|
||||
HTTPRequest: httpReq,
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/ldap/multildap"
|
||||
@ -20,8 +22,8 @@ type ldapService interface {
|
||||
User(username string) (*login.ExternalUserInfo, error)
|
||||
}
|
||||
|
||||
func ProvideLDAP(cfg *setting.Cfg, ldapService ldapService, userService user.Service, authInfoService login.AuthInfoService) *LDAP {
|
||||
return &LDAP{cfg, log.New("authn.ldap"), ldapService, userService, authInfoService}
|
||||
func ProvideLDAP(cfg *setting.Cfg, ldapService ldapService, userService user.Service, authInfoService login.AuthInfoService, tracer trace.Tracer) *LDAP {
|
||||
return &LDAP{cfg, log.New("authn.ldap"), ldapService, userService, authInfoService, tracer}
|
||||
}
|
||||
|
||||
type LDAP struct {
|
||||
@ -30,6 +32,7 @@ type LDAP struct {
|
||||
service ldapService
|
||||
userService user.Service
|
||||
authInfoService login.AuthInfoService
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
func (c *LDAP) String() string {
|
||||
@ -37,6 +40,8 @@ func (c *LDAP) String() string {
|
||||
}
|
||||
|
||||
func (c *LDAP) AuthenticateProxy(ctx context.Context, r *authn.Request, username string, _ map[string]string) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.ldap.AuthenticateProxy")
|
||||
defer span.End()
|
||||
info, err := c.service.User(username)
|
||||
if errors.Is(err, multildap.ErrDidNotFindUser) {
|
||||
return c.disableUser(ctx, username)
|
||||
@ -50,6 +55,8 @@ func (c *LDAP) AuthenticateProxy(ctx context.Context, r *authn.Request, username
|
||||
}
|
||||
|
||||
func (c *LDAP) AuthenticatePassword(ctx context.Context, r *authn.Request, username, password string) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.ldap.AuthenticatePassword")
|
||||
defer span.End()
|
||||
info, err := c.service.Login(&login.LoginUserQuery{
|
||||
Username: username,
|
||||
Password: password,
|
||||
@ -75,6 +82,8 @@ func (c *LDAP) AuthenticatePassword(ctx context.Context, r *authn.Request, usern
|
||||
|
||||
// disableUser will disable users if they logged in via LDAP previously
|
||||
func (c *LDAP) disableUser(ctx context.Context, username string) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.ldap.disableUser")
|
||||
defer span.End()
|
||||
c.logger.Debug("User was not found in the LDAP directory tree", "username", username)
|
||||
retErr := errIdentityNotFound.Errorf("no user found: %w", multildap.ErrDidNotFindUser)
|
||||
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/ldap"
|
||||
"github.com/grafana/grafana/pkg/services/ldap/multildap"
|
||||
@ -197,13 +197,13 @@ func setupLDAPTestCase(tt *ldapTestCase) *LDAP {
|
||||
ExpectedError: tt.expectedAuthInfoErr,
|
||||
}
|
||||
|
||||
c := &LDAP{
|
||||
cfg: setting.NewCfg(),
|
||||
logger: log.New("authn.ldap.test"),
|
||||
service: &service.LDAPFakeService{ExpectedUser: tt.expectedLDAPInfo, ExpectedError: tt.expectedLDAPErr},
|
||||
userService: userService,
|
||||
authInfoService: authInfoService,
|
||||
}
|
||||
c := ProvideLDAP(
|
||||
setting.NewCfg(),
|
||||
&service.LDAPFakeService{ExpectedUser: tt.expectedLDAPInfo, ExpectedError: tt.expectedLDAPErr},
|
||||
userService,
|
||||
authInfoService,
|
||||
tracing.InitializeTracerForTest(),
|
||||
)
|
||||
|
||||
return c
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
@ -70,12 +71,14 @@ var (
|
||||
|
||||
func ProvideOAuth(
|
||||
name string, cfg *setting.Cfg, oauthService oauthtoken.OAuthTokenService,
|
||||
socialService social.Service, settingsProviderService setting.Provider, features featuremgmt.FeatureToggles,
|
||||
socialService social.Service, settingsProviderService setting.Provider,
|
||||
features featuremgmt.FeatureToggles, tracer trace.Tracer,
|
||||
) *OAuth {
|
||||
providerName := strings.TrimPrefix(name, "auth.client.")
|
||||
return &OAuth{
|
||||
name, fmt.Sprintf("oauth_%s", providerName), providerName,
|
||||
log.New(name), cfg, settingsProviderService, oauthService, socialService, features,
|
||||
log.New(name), cfg, tracer, settingsProviderService, oauthService,
|
||||
socialService, features,
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +88,7 @@ type OAuth struct {
|
||||
providerName string
|
||||
log log.Logger
|
||||
cfg *setting.Cfg
|
||||
tracer trace.Tracer
|
||||
|
||||
settingsProviderSvc setting.Provider
|
||||
oauthService oauthtoken.OAuthTokenService
|
||||
@ -97,6 +101,9 @@ func (c *OAuth) Name() string {
|
||||
}
|
||||
|
||||
func (c *OAuth) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.oauth.Authenticate")
|
||||
defer span.End()
|
||||
|
||||
r.SetMeta(authn.MetaKeyAuthModule, c.moduleName)
|
||||
|
||||
oauthCfg := c.socialService.GetOAuthInfoProvider(c.providerName)
|
||||
@ -232,6 +239,9 @@ func (c *OAuth) GetConfig() authn.SSOClientConfig {
|
||||
}
|
||||
|
||||
func (c *OAuth) RedirectURL(ctx context.Context, r *authn.Request) (*authn.Redirect, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.oauth.RedirectURL") //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
|
||||
var opts []oauth2.AuthCodeOption
|
||||
|
||||
oauthCfg := c.socialService.GetOAuthInfoProvider(c.providerName)
|
||||
@ -274,6 +284,9 @@ func (c *OAuth) RedirectURL(ctx context.Context, r *authn.Request) (*authn.Redir
|
||||
}
|
||||
|
||||
func (c *OAuth) Logout(ctx context.Context, user identity.Requester, sessionToken *auth.UserToken) (*authn.Redirect, bool) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.oauth.Logout")
|
||||
defer span.End()
|
||||
|
||||
token := c.oauthService.GetCurrentOAuthToken(ctx, user, sessionToken)
|
||||
|
||||
userID, err := identity.UserIdentifier(user.GetID())
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/login/social/socialtest"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
@ -296,7 +297,7 @@ func TestOAuth_Authenticate(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
c := ProvideOAuth(authn.ClientWithPrefix("azuread"), cfg, nil, fakeSocialSvc, settingsProvider, featuremgmt.WithFeatures(tt.features...))
|
||||
c := ProvideOAuth(authn.ClientWithPrefix("azuread"), cfg, nil, fakeSocialSvc, settingsProvider, featuremgmt.WithFeatures(tt.features...), tracing.InitializeTracerForTest())
|
||||
|
||||
identity, err := c.Authenticate(context.Background(), tt.req)
|
||||
assert.ErrorIs(t, err, tt.expectedErr)
|
||||
@ -376,7 +377,7 @@ func TestOAuth_RedirectURL(t *testing.T) {
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
|
||||
c := ProvideOAuth(authn.ClientWithPrefix("azuread"), cfg, nil, fakeSocialSvc, &setting.OSSImpl{Cfg: cfg}, featuremgmt.WithFeatures())
|
||||
c := ProvideOAuth(authn.ClientWithPrefix("azuread"), cfg, nil, fakeSocialSvc, &setting.OSSImpl{Cfg: cfg}, featuremgmt.WithFeatures(), tracing.InitializeTracerForTest())
|
||||
|
||||
redirect, err := c.RedirectURL(context.Background(), nil)
|
||||
assert.ErrorIs(t, err, tt.expectedErr)
|
||||
@ -489,7 +490,7 @@ func TestOAuth_Logout(t *testing.T) {
|
||||
fakeSocialSvc := &socialtest.FakeSocialService{
|
||||
ExpectedAuthInfoProvider: tt.oauthCfg,
|
||||
}
|
||||
c := ProvideOAuth(authn.ClientWithPrefix("azuread"), tt.cfg, mockService, fakeSocialSvc, &setting.OSSImpl{Cfg: tt.cfg}, featuremgmt.WithFeatures())
|
||||
c := ProvideOAuth(authn.ClientWithPrefix("azuread"), tt.cfg, mockService, fakeSocialSvc, &setting.OSSImpl{Cfg: tt.cfg}, featuremgmt.WithFeatures(), tracing.InitializeTracerForTest())
|
||||
|
||||
redirect, ok := c.Logout(context.Background(), &authn.Identity{ID: "1", Type: claims.TypeUser}, nil)
|
||||
|
||||
@ -549,7 +550,8 @@ func TestIsEnabled(t *testing.T) {
|
||||
nil,
|
||||
fakeSocialSvc,
|
||||
&setting.OSSImpl{Cfg: cfg},
|
||||
featuremgmt.WithFeatures())
|
||||
featuremgmt.WithFeatures(),
|
||||
tracing.InitializeTracerForTest())
|
||||
assert.Equal(t, tt.expected, c.IsEnabled())
|
||||
})
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
@ -18,17 +20,20 @@ var (
|
||||
|
||||
var _ authn.PasswordClient = new(Password)
|
||||
|
||||
func ProvidePassword(loginAttempts loginattempt.Service, clients ...authn.PasswordClient) *Password {
|
||||
return &Password{loginAttempts, clients, log.New("authn.password")}
|
||||
func ProvidePassword(loginAttempts loginattempt.Service, tracer trace.Tracer, clients ...authn.PasswordClient) *Password {
|
||||
return &Password{loginAttempts, clients, log.New("authn.password"), tracer}
|
||||
}
|
||||
|
||||
type Password struct {
|
||||
loginAttempts loginattempt.Service
|
||||
clients []authn.PasswordClient
|
||||
log log.Logger
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
func (c *Password) AuthenticatePassword(ctx context.Context, r *authn.Request, username, password string) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.password.AuthenticatePassword")
|
||||
defer span.End()
|
||||
r.SetMeta(authn.MetaKeyUsername, username)
|
||||
|
||||
ok, err := c.loginAttempts.Validate(ctx, username)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/authn/authntest"
|
||||
"github.com/grafana/grafana/pkg/services/loginattempt/loginattempttest"
|
||||
@ -65,7 +66,7 @@ func TestPassword_AuthenticatePassword(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
c := ProvidePassword(loginattempttest.FakeLoginAttemptService{ExpectedValid: !tt.blockLogin}, tt.clients...)
|
||||
c := ProvidePassword(loginattempttest.FakeLoginAttemptService{ExpectedValid: !tt.blockLogin}, tracing.InitializeTracerForTest(), tt.clients...)
|
||||
r := &authn.Request{
|
||||
OrgID: 12345,
|
||||
HTTPRequest: &http.Request{
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
@ -45,12 +46,12 @@ var (
|
||||
_ authn.ContextAwareClient = new(Proxy)
|
||||
)
|
||||
|
||||
func ProvideProxy(cfg *setting.Cfg, cache proxyCache, clients ...authn.ProxyClient) (*Proxy, error) {
|
||||
func ProvideProxy(cfg *setting.Cfg, cache proxyCache, tracer trace.Tracer, clients ...authn.ProxyClient) (*Proxy, error) {
|
||||
list, err := parseAcceptList(cfg.AuthProxy.Whitelist)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Proxy{log.New(authn.ClientProxy), cfg, cache, clients, list}, nil
|
||||
return &Proxy{log.New(authn.ClientProxy), cfg, cache, clients, list, tracer}, nil
|
||||
}
|
||||
|
||||
type proxyCache interface {
|
||||
@ -65,6 +66,7 @@ type Proxy struct {
|
||||
cache proxyCache
|
||||
clients []authn.ProxyClient
|
||||
acceptedIPs []*net.IPNet
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
func (c *Proxy) Name() string {
|
||||
@ -72,6 +74,8 @@ func (c *Proxy) Name() string {
|
||||
}
|
||||
|
||||
func (c *Proxy) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.proxy.Authenticate")
|
||||
defer span.End()
|
||||
if !c.isAllowedIP(r) {
|
||||
return nil, errNotAcceptedIP.Errorf("request ip is not in the configured accept list")
|
||||
}
|
||||
@ -115,6 +119,8 @@ func (c *Proxy) IsEnabled() bool {
|
||||
// See if we have cached the user id, in that case we can fetch the signed-in user and skip sync.
|
||||
// Error here means that we could not find anything in cache, so we can proceed as usual
|
||||
func (c *Proxy) retrieveIDFromCache(ctx context.Context, cacheKey string, r *authn.Request) (*authn.Identity, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.proxy.retrieveIDFromCache")
|
||||
defer span.End()
|
||||
entry, err := c.cache.Get(ctx, cacheKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -148,6 +154,8 @@ func (c *Proxy) Priority() uint {
|
||||
}
|
||||
|
||||
func (c *Proxy) Hook(ctx context.Context, id *authn.Identity, r *authn.Request) error {
|
||||
ctx, span := c.tracer.Start(ctx, "authn.proxy.Hook")
|
||||
defer span.End()
|
||||
if id.ClientParams.CacheAuthProxyKey == "" {
|
||||
return nil
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/authn/authntest"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@ -113,7 +114,7 @@ func TestProxy_Authenticate(t *testing.T) {
|
||||
calledAdditional = additional
|
||||
return nil, nil
|
||||
}}
|
||||
c, err := ProvideProxy(cfg, &fakeCache{expectedErr: errors.New("")}, proxyClient)
|
||||
c, err := ProvideProxy(cfg, &fakeCache{expectedErr: errors.New("")}, tracing.InitializeTracerForTest(), proxyClient)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = c.Authenticate(context.Background(), tt.req)
|
||||
@ -169,7 +170,7 @@ func TestProxy_Test(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
cfg.AuthProxy.HeaderName = "Proxy-Header"
|
||||
|
||||
c, _ := ProvideProxy(cfg, nil, nil, nil)
|
||||
c, _ := ProvideProxy(cfg, nil, tracing.InitializeTracerForTest(), nil)
|
||||
assert.Equal(t, tt.expectedOK, c.Test(context.Background(), tt.req))
|
||||
})
|
||||
}
|
||||
@ -208,7 +209,7 @@ func TestProxy_Hook(t *testing.T) {
|
||||
withRole := func(role string) func(t *testing.T) {
|
||||
cacheKey := fmt.Sprintf("users:johndoe-%s", role)
|
||||
return func(t *testing.T) {
|
||||
c, err := ProvideProxy(cfg, cache, authntest.MockProxyClient{})
|
||||
c, err := ProvideProxy(cfg, cache, tracing.InitializeTracerForTest(), authntest.MockProxyClient{})
|
||||
require.NoError(t, err)
|
||||
userIdentity := &authn.Identity{
|
||||
ID: "1",
|
||||
|
@ -7,6 +7,8 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
@ -18,12 +20,14 @@ import (
|
||||
|
||||
var _ authn.ContextAwareClient = new(Session)
|
||||
|
||||
func ProvideSession(cfg *setting.Cfg, sessionService auth.UserTokenService, authInfoService login.AuthInfoService) *Session {
|
||||
func ProvideSession(cfg *setting.Cfg, sessionService auth.UserTokenService,
|
||||
authInfoService login.AuthInfoService, tracer trace.Tracer) *Session {
|
||||
return &Session{
|
||||
cfg: cfg,
|
||||
log: log.New(authn.ClientSession),
|
||||
sessionService: sessionService,
|
||||
authInfoService: authInfoService,
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +36,7 @@ type Session struct {
|
||||
log log.Logger
|
||||
sessionService auth.UserTokenService
|
||||
authInfoService login.AuthInfoService
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
func (s *Session) Name() string {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/models/usertoken"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/auth/authtest"
|
||||
@ -31,7 +32,7 @@ func TestSession_Test(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
cfg.LoginCookieName = ""
|
||||
cfg.LoginMaxLifetime = 20 * time.Second
|
||||
s := ProvideSession(cfg, &authtest.FakeUserAuthTokenService{}, &authinfotest.FakeService{})
|
||||
s := ProvideSession(cfg, &authtest.FakeUserAuthTokenService{}, &authinfotest.FakeService{}, tracing.InitializeTracerForTest())
|
||||
|
||||
disabled := s.Test(context.Background(), &authn.Request{HTTPRequest: validHTTPReq})
|
||||
assert.False(t, disabled)
|
||||
@ -194,7 +195,7 @@ func TestSession_Authenticate(t *testing.T) {
|
||||
cfg.LoginCookieName = cookieName
|
||||
cfg.TokenRotationIntervalMinutes = 10
|
||||
cfg.LoginMaxLifetime = 20 * time.Second
|
||||
s := ProvideSession(cfg, tt.fields.sessionService, tt.fields.authInfoService)
|
||||
s := ProvideSession(cfg, tt.fields.sessionService, tt.fields.authInfoService, tracing.InitializeTracerForTest())
|
||||
|
||||
got, err := s.Authenticate(context.Background(), tt.args.r)
|
||||
require.True(t, (err != nil) == tt.wantErr, err)
|
||||
|
Reference in New Issue
Block a user