2022-11-29 10:57:47 +01:00
|
|
|
package authnimpl
|
|
|
|
|
|
2022-12-02 15:10:03 +01:00
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
2022-12-19 09:22:11 +01:00
|
|
|
"github.com/grafana/grafana/pkg/services/apikey"
|
2022-12-02 15:10:03 +01:00
|
|
|
"github.com/grafana/grafana/pkg/services/authn"
|
2022-12-20 13:59:05 +00:00
|
|
|
sync "github.com/grafana/grafana/pkg/services/authn/authnimpl/usersync"
|
2022-12-02 15:10:03 +01:00
|
|
|
"github.com/grafana/grafana/pkg/services/authn/clients"
|
|
|
|
|
"github.com/grafana/grafana/pkg/services/org"
|
2022-12-19 09:22:11 +01:00
|
|
|
"github.com/grafana/grafana/pkg/services/user"
|
2022-12-02 15:10:03 +01:00
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
|
|
|
"go.opentelemetry.io/otel/attribute"
|
|
|
|
|
)
|
2022-11-29 10:57:47 +01:00
|
|
|
|
|
|
|
|
var _ authn.Service = new(Service)
|
|
|
|
|
|
2022-12-19 09:22:11 +01:00
|
|
|
func ProvideService(cfg *setting.Cfg, tracer tracing.Tracer, orgService org.Service, apikeyService apikey.Service, userService user.Service) *Service {
|
2022-12-02 15:10:03 +01:00
|
|
|
s := &Service{
|
2022-12-20 13:59:05 +00:00
|
|
|
log: log.New("authn.service"),
|
|
|
|
|
cfg: cfg,
|
|
|
|
|
clients: make(map[string]authn.Client),
|
|
|
|
|
tracer: tracer,
|
|
|
|
|
postAuthHooks: []authn.PostAuthHookFn{},
|
|
|
|
|
userService: userService,
|
2022-12-02 15:10:03 +01:00
|
|
|
}
|
|
|
|
|
|
2022-12-19 09:22:11 +01:00
|
|
|
s.clients[authn.ClientAPIKey] = clients.ProvideAPIKey(apikeyService, userService)
|
|
|
|
|
|
2022-12-02 15:10:03 +01:00
|
|
|
if s.cfg.AnonymousEnabled {
|
|
|
|
|
s.clients[authn.ClientAnonymous] = clients.ProvideAnonymous(cfg, orgService)
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-20 13:59:05 +00:00
|
|
|
// FIXME (jguer): move to User package
|
|
|
|
|
userSyncService := &sync.UserSync{}
|
|
|
|
|
orgUserSyncService := &sync.OrgSync{}
|
|
|
|
|
s.RegisterPostAuthHook(userSyncService.SyncUser)
|
|
|
|
|
s.RegisterPostAuthHook(orgUserSyncService.SyncOrgUser)
|
|
|
|
|
|
2022-12-02 15:10:03 +01:00
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-29 10:57:47 +01:00
|
|
|
type Service struct {
|
2022-12-02 15:10:03 +01:00
|
|
|
log log.Logger
|
|
|
|
|
cfg *setting.Cfg
|
|
|
|
|
clients map[string]authn.Client
|
|
|
|
|
|
2022-12-20 13:59:05 +00:00
|
|
|
// postAuthHooks are called after a successful authentication. They can modify the identity.
|
|
|
|
|
postAuthHooks []authn.PostAuthHookFn
|
|
|
|
|
|
2022-12-19 09:22:11 +01:00
|
|
|
tracer tracing.Tracer
|
|
|
|
|
userService user.Service
|
2022-12-02 15:10:03 +01:00
|
|
|
}
|
|
|
|
|
|
2022-12-19 09:22:11 +01:00
|
|
|
func (s *Service) Authenticate(ctx context.Context, client string, r *authn.Request) (*authn.Identity, bool, error) {
|
2022-12-02 15:10:03 +01:00
|
|
|
ctx, span := s.tracer.Start(ctx, "authn.Authenticate")
|
|
|
|
|
defer span.End()
|
|
|
|
|
|
2022-12-19 09:22:11 +01:00
|
|
|
span.SetAttributes("authn.client", client, attribute.Key("authn.client").String(client))
|
|
|
|
|
logger := s.log.FromContext(ctx)
|
2022-12-02 15:10:03 +01:00
|
|
|
|
2022-12-19 09:22:11 +01:00
|
|
|
c, ok := s.clients[client]
|
2022-12-02 15:10:03 +01:00
|
|
|
if !ok {
|
2022-12-19 09:22:11 +01:00
|
|
|
logger.Debug("auth client not found", "client", client)
|
2022-12-02 15:10:03 +01:00
|
|
|
span.AddEvents([]string{"message"}, []tracing.EventValue{{Str: "auth client is not configured"}})
|
2022-12-19 09:22:11 +01:00
|
|
|
return nil, false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !c.Test(ctx, r) {
|
|
|
|
|
logger.Debug("auth client cannot handle request", "client", client)
|
|
|
|
|
span.AddEvents([]string{"message"}, []tracing.EventValue{{Str: "auth client cannot handle request"}})
|
|
|
|
|
return nil, false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
identity, err := c.Authenticate(ctx, r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Warn("auth client could not authenticate request", "client", client, "error", err)
|
|
|
|
|
span.AddEvents([]string{"message"}, []tracing.EventValue{{Str: "auth client could not authenticate request"}})
|
|
|
|
|
return nil, true, err
|
2022-12-02 15:10:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: We want to perform common authentication operations here.
|
|
|
|
|
// We will add them as we start to implement clients that requires them.
|
|
|
|
|
// Those operations can be Syncing user, syncing teams, create a session etc.
|
|
|
|
|
// We would need to check what operations a client support and also if they are requested
|
|
|
|
|
// because for e.g. basic auth we want to create a session if the call is coming from the
|
|
|
|
|
// login handler, but if we want to perform basic auth during a request (called from contexthandler) we don't
|
|
|
|
|
// want a session to be created.
|
|
|
|
|
|
2022-12-20 13:59:05 +00:00
|
|
|
params := c.ClientParams()
|
|
|
|
|
|
|
|
|
|
for _, hook := range s.postAuthHooks {
|
|
|
|
|
if err := hook(ctx, params, identity); err != nil {
|
|
|
|
|
return nil, false, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-19 09:22:11 +01:00
|
|
|
return identity, true, nil
|
2022-11-29 10:57:47 +01:00
|
|
|
}
|
2022-12-20 13:59:05 +00:00
|
|
|
|
|
|
|
|
func (s *Service) RegisterPostAuthHook(hook authn.PostAuthHookFn) {
|
|
|
|
|
s.postAuthHooks = append(s.postAuthHooks, hook)
|
|
|
|
|
}
|