diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go index 7b6d39165b3..a1c00aada78 100644 --- a/pkg/server/wire_gen.go +++ b/pkg/server/wire_gen.go @@ -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 { diff --git a/pkg/services/auth/authimpl/auth_token.go b/pkg/services/auth/authimpl/auth_token.go index bf95502b11e..e8a00ff8c85 100644 --- a/pkg/services/auth/authimpl/auth_token.go +++ b/pkg/services/auth/authimpl/auth_token.go @@ -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 diff --git a/pkg/services/auth/idimpl/service.go b/pkg/services/auth/idimpl/service.go index 5dec411fdee..cb8e6adc9ce 100644 --- a/pkg/services/auth/idimpl/service.go +++ b/pkg/services/auth/idimpl/service.go @@ -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 { diff --git a/pkg/services/auth/idimpl/service_test.go b/pkg/services/auth/idimpl/service_test.go index bb7ee510e55..8690c5c24bc 100644 --- a/pkg/services/auth/idimpl/service_test.go +++ b/pkg/services/auth/idimpl/service_test.go @@ -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{ diff --git a/pkg/services/authn/authnimpl/registration.go b/pkg/services/authn/authnimpl/registration.go index 7eadac99083..ce0ed9a9e89 100644 --- a/pkg/services/authn/authnimpl/registration.go +++ b/pkg/services/authn/authnimpl/registration.go @@ -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) { diff --git a/pkg/services/authn/clients/api_key.go b/pkg/services/authn/clients/api_key.go index 5bc4aa8fb46..2023cb4e418 100644 --- a/pkg/services/authn/clients/api_key.go +++ b/pkg/services/authn/clients/api_key.go @@ -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 } diff --git a/pkg/services/authn/clients/api_key_test.go b/pkg/services/authn/clients/api_key_test.go index 889f38cd4d0..62fc83bc7f0 100644 --- a/pkg/services/authn/clients/api_key_test.go +++ b/pkg/services/authn/clients/api_key_test.go @@ -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)) }) } diff --git a/pkg/services/authn/clients/ext_jwt.go b/pkg/services/authn/clients/ext_jwt.go index 74754d85681..5baafdf0c6b 100644 --- a/pkg/services/authn/clients/ext_jwt.go +++ b/pkg/services/authn/clients/ext_jwt.go @@ -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) diff --git a/pkg/services/authn/clients/ext_jwt_test.go b/pkg/services/authn/clients/ext_jwt_test.go index 13970e681be..b72b6303154 100644 --- a/pkg/services/authn/clients/ext_jwt_test.go +++ b/pkg/services/authn/clients/ext_jwt_test.go @@ -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, diff --git a/pkg/services/authn/clients/grafana.go b/pkg/services/authn/clients/grafana.go index ddabb405443..379c19ffca3 100644 --- a/pkg/services/authn/clients/grafana.go +++ b/pkg/services/authn/clients/grafana.go @@ -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) { diff --git a/pkg/services/authn/clients/grafana_test.go b/pkg/services/authn/clients/grafana_test.go index fd93cf2faa7..fd40757e319 100644 --- a/pkg/services/authn/clients/grafana_test.go +++ b/pkg/services/authn/clients/grafana_test.go @@ -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) diff --git a/pkg/services/authn/clients/jwt.go b/pkg/services/authn/clients/jwt.go index 93036b87915..60d7ed21406 100644 --- a/pkg/services/authn/clients/jwt.go +++ b/pkg/services/authn/clients/jwt.go @@ -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) diff --git a/pkg/services/authn/clients/jwt_test.go b/pkg/services/authn/clients/jwt_test.go index 7fccffc6b17..2de491935b7 100644 --- a/pkg/services/authn/clients/jwt_test.go +++ b/pkg/services/authn/clients/jwt_test.go @@ -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, diff --git a/pkg/services/authn/clients/ldap.go b/pkg/services/authn/clients/ldap.go index e78f0ff119c..4f9cbccf066 100644 --- a/pkg/services/authn/clients/ldap.go +++ b/pkg/services/authn/clients/ldap.go @@ -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) diff --git a/pkg/services/authn/clients/ldap_test.go b/pkg/services/authn/clients/ldap_test.go index cd08fa2ac01..2d09ef5c933 100644 --- a/pkg/services/authn/clients/ldap_test.go +++ b/pkg/services/authn/clients/ldap_test.go @@ -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 } diff --git a/pkg/services/authn/clients/oauth.go b/pkg/services/authn/clients/oauth.go index 1c6429c3cc4..0e8053a39b7 100644 --- a/pkg/services/authn/clients/oauth.go +++ b/pkg/services/authn/clients/oauth.go @@ -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()) diff --git a/pkg/services/authn/clients/oauth_test.go b/pkg/services/authn/clients/oauth_test.go index 7a9222154f7..2bd536d6544 100644 --- a/pkg/services/authn/clients/oauth_test.go +++ b/pkg/services/authn/clients/oauth_test.go @@ -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()) }) } diff --git a/pkg/services/authn/clients/password.go b/pkg/services/authn/clients/password.go index 76e82d4fc59..f9b2483d2c5 100644 --- a/pkg/services/authn/clients/password.go +++ b/pkg/services/authn/clients/password.go @@ -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) diff --git a/pkg/services/authn/clients/password_test.go b/pkg/services/authn/clients/password_test.go index 6f7619ce1b7..fd7933a37e7 100644 --- a/pkg/services/authn/clients/password_test.go +++ b/pkg/services/authn/clients/password_test.go @@ -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{ diff --git a/pkg/services/authn/clients/proxy.go b/pkg/services/authn/clients/proxy.go index 237d02f13cc..f20b1534a02 100644 --- a/pkg/services/authn/clients/proxy.go +++ b/pkg/services/authn/clients/proxy.go @@ -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 } diff --git a/pkg/services/authn/clients/proxy_test.go b/pkg/services/authn/clients/proxy_test.go index b0cefbd6d6c..7b1faaa9efa 100644 --- a/pkg/services/authn/clients/proxy_test.go +++ b/pkg/services/authn/clients/proxy_test.go @@ -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", diff --git a/pkg/services/authn/clients/session.go b/pkg/services/authn/clients/session.go index fa0f60b8e12..a644c4771af 100644 --- a/pkg/services/authn/clients/session.go +++ b/pkg/services/authn/clients/session.go @@ -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 { diff --git a/pkg/services/authn/clients/session_test.go b/pkg/services/authn/clients/session_test.go index 946168f9f14..13195ba2b9b 100644 --- a/pkg/services/authn/clients/session_test.go +++ b/pkg/services/authn/clients/session_test.go @@ -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)