AuthN: add support for client specific hooks (#62863)
* AuthN: Add HookClient interface * AuthN: Check if client implement authn.HookClient and call the hook if it does * AuthN: Convert refresh token hook into a client hook
This commit is contained in:
@@ -70,9 +70,7 @@ func ProvideService(
|
||||
s.RegisterClient(clients.ProvideAPIKey(apikeyService, userService))
|
||||
|
||||
if cfg.LoginCookieName != "" {
|
||||
sessionClient := clients.ProvideSession(sessionService, userService, cfg.LoginCookieName, cfg.LoginMaxLifetime)
|
||||
s.RegisterClient(sessionClient)
|
||||
s.RegisterPostAuthHook(sessionClient.RefreshTokenHook, 20)
|
||||
s.RegisterClient(clients.ProvideSession(sessionService, userService, cfg.LoginCookieName, cfg.LoginMaxLifetime))
|
||||
}
|
||||
|
||||
if s.cfg.AnonymousEnabled {
|
||||
@@ -175,7 +173,6 @@ func (s *Service) Authenticate(ctx context.Context, r *authn.Request) (*authn.Id
|
||||
if item.v.Test(ctx, r) {
|
||||
identity, err := s.authenticate(ctx, item.v, r)
|
||||
if err != nil {
|
||||
s.log.Warn("failed to authenticate", "client", item.v.Name(), "err", err)
|
||||
authErr = multierror.Append(authErr, err)
|
||||
// try next
|
||||
continue
|
||||
@@ -204,7 +201,7 @@ func (s *Service) authenticate(ctx context.Context, c authn.Client, r *authn.Req
|
||||
|
||||
for _, hook := range s.postAuthHooks.items {
|
||||
if err := hook.v(ctx, identity, r); err != nil {
|
||||
s.log.FromContext(ctx).Warn("post auth hook failed", "error", err, "id", identity)
|
||||
s.log.FromContext(ctx).Warn("post auth hook failed", "error", err, "client", c.Name(), "id", identity.ID)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -213,6 +210,13 @@ func (s *Service) authenticate(ctx context.Context, c authn.Client, r *authn.Req
|
||||
return nil, errDisabledIdentity.Errorf("identity is disabled")
|
||||
}
|
||||
|
||||
if hc, ok := c.(authn.HookClient); ok {
|
||||
if err := hc.Hook(ctx, identity, r); err != nil {
|
||||
s.log.FromContext(ctx).Warn("post client auth hook failed", "error", err, "client", c.Name(), "id", identity.ID)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return identity, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
@@ -107,7 +108,7 @@ func TestService_Authenticate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_Authenticate_OrgID(t *testing.T) {
|
||||
func TestService_OrgID(t *testing.T) {
|
||||
type TestCase struct {
|
||||
desc string
|
||||
req *authn.Request
|
||||
@@ -168,6 +169,28 @@ func TestService_Authenticate_OrgID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_HookClient(t *testing.T) {
|
||||
hookCalled := false
|
||||
|
||||
s := setupTests(t, func(svc *Service) {
|
||||
svc.RegisterClient(&authntest.MockClient{
|
||||
AuthenticateFunc: func(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
|
||||
return &authn.Identity{}, nil
|
||||
},
|
||||
TestFunc: func(ctx context.Context, r *authn.Request) bool {
|
||||
return true
|
||||
},
|
||||
HookFunc: func(ctx context.Context, identity *authn.Identity, r *authn.Request) error {
|
||||
hookCalled = true
|
||||
return nil
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
_, _ = s.Authenticate(context.Background(), &authn.Request{})
|
||||
require.True(t, hookCalled)
|
||||
}
|
||||
|
||||
func TestService_Login(t *testing.T) {
|
||||
type TestCase struct {
|
||||
desc string
|
||||
|
||||
Reference in New Issue
Block a user