Auth: Add anonymous authn client (#59637)

* Authn: Add Client interface and Reqeust and Identity structures

* Authn: Implement Authenticate method in service

* Authn: Add tracing

* Authn: Add logger

* AuthN: Implement Anonymous client
This commit is contained in:
Karl Persson
2022-12-02 15:10:03 +01:00
committed by GitHub
parent c52d4e2a64
commit 22be025284
12 changed files with 313 additions and 8 deletions
+55 -1
View File
@@ -1,8 +1,62 @@
package authnimpl
import "github.com/grafana/grafana/pkg/services/authn"
import (
"context"
"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/authn/clients"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/setting"
"go.opentelemetry.io/otel/attribute"
)
var _ authn.Service = new(Service)
func ProvideService(cfg *setting.Cfg, tracer tracing.Tracer, orgService org.Service) *Service {
s := &Service{
log: log.New("authn.service"),
cfg: cfg,
clients: make(map[string]authn.Client),
tracer: tracer,
}
if s.cfg.AnonymousEnabled {
s.clients[authn.ClientAnonymous] = clients.ProvideAnonymous(cfg, orgService)
}
return s
}
type Service struct {
log log.Logger
cfg *setting.Cfg
clients map[string]authn.Client
tracer tracing.Tracer
}
func (s *Service) Authenticate(ctx context.Context, clientName string, r *authn.Request) (*authn.Identity, error) {
ctx, span := s.tracer.Start(ctx, "authn.Authenticate")
defer span.End()
span.SetAttributes("authn.client", clientName, attribute.Key("authn.client").String(clientName))
client, ok := s.clients[clientName]
if !ok {
s.log.FromContext(ctx).Warn("auth client not found", "client", clientName)
span.AddEvents([]string{"message"}, []tracing.EventValue{{Str: "auth client is not configured"}})
return nil, authn.ErrClientNotFound
}
// 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.
return client.Authenticate(ctx, r)
}
@@ -0,0 +1,62 @@
package authnimpl
import (
"context"
"testing"
"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/authn/authntest"
"github.com/grafana/grafana/pkg/setting"
)
func TestService_Authenticate(t *testing.T) {
type TestCase struct {
desc string
clientName string
expectedErr error
}
tests := []TestCase{
{
desc: "should succeed with authentication for configured client",
clientName: "fake",
},
{
desc: "should fail when client is not configured",
clientName: "gitlab",
expectedErr: authn.ErrClientNotFound,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
svc := setupTests(t, func(svc *Service) {
svc.clients["fake"] = &authntest.FakeClient{}
})
_, err := svc.Authenticate(context.Background(), tt.clientName, &authn.Request{})
assert.ErrorIs(t, tt.expectedErr, err)
})
}
}
func setupTests(t *testing.T, opts ...func(svc *Service)) *Service {
t.Helper()
s := &Service{
log: log.NewNopLogger(),
cfg: setting.NewCfg(),
clients: map[string]authn.Client{},
tracer: tracing.InitializeTracerForTest(),
}
for _, o := range opts {
o(s)
}
return s
}