mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AuthN: add metrics for login and authentication (#63783)
* AuthN: Add metrics
This commit is contained in:
parent
b6eb324139
commit
66ef5325d1
58
pkg/services/authn/authnimpl/metrics.go
Normal file
58
pkg/services/authn/authnimpl/metrics.go
Normal file
@ -0,0 +1,58 @@
|
||||
package authnimpl
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
metricsSubSystem = "authn"
|
||||
metricsNamespace = "grafana"
|
||||
)
|
||||
|
||||
type metrics struct {
|
||||
failedAuth prometheus.Counter
|
||||
successfulAuth *prometheus.CounterVec
|
||||
|
||||
failedLogin *prometheus.CounterVec
|
||||
successfulLogin *prometheus.CounterVec
|
||||
}
|
||||
|
||||
func newMetrics(reg prometheus.Registerer) *metrics {
|
||||
m := &metrics{
|
||||
failedAuth: prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: metricsNamespace,
|
||||
Subsystem: metricsSubSystem,
|
||||
Name: "authn_failed_authentication_total",
|
||||
Help: "Number of failed authentications",
|
||||
}),
|
||||
successfulAuth: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: metricsNamespace,
|
||||
Subsystem: metricsSubSystem,
|
||||
Name: "authn_successful_authentication_total",
|
||||
Help: "Number of successful authentications",
|
||||
}, []string{"client"}),
|
||||
failedLogin: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: metricsNamespace,
|
||||
Subsystem: metricsSubSystem,
|
||||
Name: "authn_failed_login_total",
|
||||
Help: "Number of failed logins",
|
||||
}, []string{"client"}),
|
||||
successfulLogin: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: metricsNamespace,
|
||||
Subsystem: metricsSubSystem,
|
||||
Name: "authn_successful_login_total",
|
||||
Help: "Number of successful logins",
|
||||
}, []string{"client"}),
|
||||
}
|
||||
|
||||
if reg != nil {
|
||||
reg.MustRegister(
|
||||
m.failedAuth,
|
||||
m.successfulAuth,
|
||||
m.failedLogin,
|
||||
m.successfulLogin,
|
||||
)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
@ -60,7 +61,7 @@ func ProvideService(
|
||||
authInfoService login.AuthInfoService, renderService rendering.Service,
|
||||
features *featuremgmt.FeatureManager, oauthTokenService oauthtoken.OAuthTokenService,
|
||||
socialService social.Service, cache *remotecache.RemoteCache,
|
||||
ldapService service.LDAP,
|
||||
ldapService service.LDAP, registerer prometheus.Registerer,
|
||||
) *Service {
|
||||
s := &Service{
|
||||
log: log.New("authn.service"),
|
||||
@ -68,6 +69,7 @@ func ProvideService(
|
||||
clients: make(map[string]authn.Client),
|
||||
clientQueue: newQueue[authn.ContextAwareClient](),
|
||||
tracer: tracer,
|
||||
metrics: newMetrics(registerer),
|
||||
sessionService: sessionService,
|
||||
postAuthHooks: newQueue[authn.PostAuthHookFn](),
|
||||
postLoginHooks: newQueue[authn.PostLoginHookFn](),
|
||||
@ -164,7 +166,9 @@ type Service struct {
|
||||
clients map[string]authn.Client
|
||||
clientQueue *queue[authn.ContextAwareClient]
|
||||
|
||||
tracer tracing.Tracer
|
||||
tracer tracing.Tracer
|
||||
metrics *metrics
|
||||
|
||||
sessionService auth.UserTokenService
|
||||
|
||||
// postAuthHooks are called after a successful authentication. They can modify the identity.
|
||||
@ -188,12 +192,14 @@ func (s *Service) Authenticate(ctx context.Context, r *authn.Request) (*authn.Id
|
||||
}
|
||||
|
||||
if identity != nil {
|
||||
s.metrics.successfulAuth.WithLabelValues(item.v.Name()).Inc()
|
||||
return identity, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if authErr != nil {
|
||||
s.metrics.failedAuth.Inc()
|
||||
return nil, authErr
|
||||
}
|
||||
|
||||
@ -234,6 +240,10 @@ func (s *Service) RegisterPostAuthHook(hook authn.PostAuthHookFn, priority uint)
|
||||
}
|
||||
|
||||
func (s *Service) Login(ctx context.Context, client string, r *authn.Request) (identity *authn.Identity, err error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.Login")
|
||||
defer span.End()
|
||||
span.SetAttributes(attributeKeyClient, client, attribute.Key(attributeKeyClient).String(client))
|
||||
|
||||
defer func() {
|
||||
for _, hook := range s.postLoginHooks.items {
|
||||
hook.v(ctx, identity, r, err)
|
||||
@ -242,11 +252,13 @@ func (s *Service) Login(ctx context.Context, client string, r *authn.Request) (i
|
||||
|
||||
c, ok := s.clients[client]
|
||||
if !ok {
|
||||
s.metrics.failedLogin.WithLabelValues(client).Inc()
|
||||
return nil, authn.ErrClientNotConfigured.Errorf("client not configured: %s", client)
|
||||
}
|
||||
|
||||
identity, err = s.authenticate(ctx, c, r)
|
||||
if err != nil {
|
||||
s.metrics.failedLogin.WithLabelValues(client).Inc()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -254,6 +266,7 @@ func (s *Service) Login(ctx context.Context, client string, r *authn.Request) (i
|
||||
|
||||
// Login is only supported for users
|
||||
if namespace != authn.NamespaceUser || id <= 0 {
|
||||
s.metrics.failedLogin.WithLabelValues(client).Inc()
|
||||
return nil, authn.ErrUnsupportedIdentity.Errorf("expected identity of type user but got: %s", namespace)
|
||||
}
|
||||
|
||||
@ -265,10 +278,12 @@ func (s *Service) Login(ctx context.Context, client string, r *authn.Request) (i
|
||||
|
||||
sessionToken, err := s.sessionService.CreateToken(ctx, &user.User{ID: id}, ip, r.HTTPRequest.UserAgent())
|
||||
if err != nil {
|
||||
s.metrics.failedLogin.WithLabelValues(client).Inc()
|
||||
s.log.FromContext(ctx).Error("Failed to create session", "client", client, "id", identity.ID, "err", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.metrics.successfulLogin.WithLabelValues(client).Inc()
|
||||
identity.SessionToken = sessionToken
|
||||
return identity, nil
|
||||
}
|
||||
|
@ -316,6 +316,7 @@ func setupTests(t *testing.T, opts ...func(svc *Service)) *Service {
|
||||
clients: map[string]authn.Client{},
|
||||
clientQueue: newQueue[authn.ContextAwareClient](),
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
metrics: newMetrics(nil),
|
||||
postAuthHooks: newQueue[authn.PostAuthHookFn](),
|
||||
postLoginHooks: newQueue[authn.PostLoginHookFn](),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user