mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AuthN: Add oauth clients and perform oauth authentication with authn.Service (#62072)
* AuthN: Update signature of redirect client and RedirectURL function * OAuth: use authn.Service to perform oauth authentication and login if feature toggle is enabled * AuthN: register oauth clients * AuthN: set auth module metadata * AuthN: add logs for failed login attempts * AuthN: Don't use enable disabled setting * OAuth: only run hooks when authnService feature toggle is disabled * OAuth: Add function to handle oauth errors from authn.Service
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/network"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/apikey"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
@@ -52,6 +53,7 @@ func ProvideService(
|
||||
loginAttempts loginattempt.Service, quotaService quota.Service,
|
||||
authInfoService login.AuthInfoService, renderService rendering.Service,
|
||||
features *featuremgmt.FeatureManager, oauthTokenService oauthtoken.OAuthTokenService,
|
||||
socialService social.Service,
|
||||
) *Service {
|
||||
s := &Service{
|
||||
log: log.New("authn.service"),
|
||||
@@ -116,6 +118,21 @@ func ProvideService(
|
||||
s.RegisterClient(clients.ProvideJWT(jwtService, cfg))
|
||||
}
|
||||
|
||||
for name := range socialService.GetOAuthProviders() {
|
||||
oauthCfg := socialService.GetOAuthInfoProvider(name)
|
||||
if oauthCfg != nil && oauthCfg.Enabled {
|
||||
clientName := authn.ClientWithPrefix(name)
|
||||
|
||||
connector, errConnector := socialService.GetConnector(name)
|
||||
httpClient, errHTTPClient := socialService.GetOAuthHttpClient(name)
|
||||
if errConnector != nil || errHTTPClient != nil {
|
||||
s.log.Error("failed to configure oauth client", "client", clientName, "err", multierror.Append(errConnector, errHTTPClient))
|
||||
}
|
||||
|
||||
s.RegisterClient(clients.ProvideOAuth(clientName, cfg, oauthCfg, connector, httpClient))
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME (jguer): move to User package
|
||||
userSyncService := sync.ProvideUserSync(userService, userProtectionService, authInfoService, quotaService)
|
||||
orgUserSyncService := sync.ProvideOrgSync(userService, orgService, accessControlService)
|
||||
@@ -233,6 +250,7 @@ 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.log.FromContext(ctx).Error("failed to create session", "client", client, "userId", id, "err", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -244,19 +262,19 @@ func (s *Service) RegisterPostLoginHook(hook authn.PostLoginHookFn, priority uin
|
||||
s.postLoginHooks.insert(hook, priority)
|
||||
}
|
||||
|
||||
func (s *Service) RedirectURL(ctx context.Context, client string, r *authn.Request) (string, error) {
|
||||
func (s *Service) RedirectURL(ctx context.Context, client string, r *authn.Request) (*authn.Redirect, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.RedirectURL")
|
||||
defer span.End()
|
||||
span.SetAttributes(attributeKeyClient, client, attribute.Key(attributeKeyClient).String(client))
|
||||
|
||||
c, ok := s.clients[client]
|
||||
if !ok {
|
||||
return "", authn.ErrClientNotConfigured.Errorf("client not configured: %s", client)
|
||||
return nil, authn.ErrClientNotConfigured.Errorf("client not configured: %s", client)
|
||||
}
|
||||
|
||||
redirectClient, ok := c.(authn.RedirectClient)
|
||||
if !ok {
|
||||
return "", authn.ErrUnsupportedClient.Errorf("client does not support generating redirect url: %s", client)
|
||||
return nil, authn.ErrUnsupportedClient.Errorf("client does not support generating redirect url: %s", client)
|
||||
}
|
||||
|
||||
return redirectClient.RedirectURL(ctx, r)
|
||||
|
||||
@@ -243,16 +243,13 @@ func TestService_RedirectURL(t *testing.T) {
|
||||
type testCase struct {
|
||||
desc string
|
||||
client string
|
||||
expectedURL string
|
||||
expectedErr error
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
desc: "should generate url for valid redirect client",
|
||||
client: "redirect",
|
||||
expectedURL: "https://localhost/redirect",
|
||||
expectedErr: nil,
|
||||
desc: "should generate url for valid redirect client",
|
||||
client: "redirect",
|
||||
},
|
||||
{
|
||||
desc: "should return error on non existing client",
|
||||
@@ -269,13 +266,12 @@ func TestService_RedirectURL(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
service := setupTests(t, func(svc *Service) {
|
||||
svc.RegisterClient(authntest.FakeRedirectClient{ExpectedName: "redirect", ExpectedURL: tt.expectedURL})
|
||||
svc.RegisterClient(authntest.FakeRedirectClient{ExpectedName: "redirect"})
|
||||
svc.RegisterClient(&authntest.FakeClient{ExpectedName: "non-redirect"})
|
||||
})
|
||||
|
||||
u, err := service.RedirectURL(context.Background(), tt.client, nil)
|
||||
_, err := service.RedirectURL(context.Background(), tt.client, nil)
|
||||
assert.ErrorIs(t, err, tt.expectedErr)
|
||||
assert.Equal(t, tt.expectedURL, u)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user