diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md index 780bf99099c..d86b1e434b2 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md @@ -41,6 +41,7 @@ To follow this guide: - Ensure that you have access to the [Grafana configuration file]({{< relref "../../../configure-grafana#configuration-file-location" >}}). - Ensure you know how to create an OAuth2 application with your OAuth2 provider. Consult the documentation of your OAuth2 provider for more information. +- Ensure your identity provider returns OpenID UserInfo compatible information such as `sub` claim. - If you are using refresh tokens, ensure you know how to set them up with your OAuth2 provider. Consult the documentation of your OAuth2 provider for more information. ## Steps diff --git a/pkg/services/authn/clients/oauth.go b/pkg/services/authn/clients/oauth.go index 0c6d7099e5a..96f530924e2 100644 --- a/pkg/services/authn/clients/oauth.go +++ b/pkg/services/authn/clients/oauth.go @@ -147,6 +147,11 @@ func (c *OAuth) Authenticate(ctx context.Context, r *authn.Request) (*authn.Iden return nil, errOAuthUserInfo.Errorf("failed to get user info: %w", err) } + // Implement in Grafana 11 + // if userInfo.Id == "" { + // return nil, errors.New("idP did not return a user id") + // } + if userInfo.Email == "" { return nil, errOAuthMissingRequiredEmail.Errorf("required attribute email was not provided") } diff --git a/pkg/services/login/authinfoimpl/service.go b/pkg/services/login/authinfoimpl/service.go index ef82d4a150b..4bd5814302b 100644 --- a/pkg/services/login/authinfoimpl/service.go +++ b/pkg/services/login/authinfoimpl/service.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/util/errutil" ) type Service struct { @@ -24,7 +25,7 @@ type Service struct { const remoteCachePrefix = "authinfo-" const remoteCacheTTL = 60 * time.Hour -var errMissingParameters = errors.New("user ID and auth ID must be set") +var errMissingParameters = errutil.NewBase(errutil.StatusBadRequest, "auth-missing-parameters", errutil.WithPublicMessage("Missing parameters for auth info")) func ProvideService(authInfoStore login.Store, remoteCache remotecache.CacheStorage, @@ -118,12 +119,12 @@ func generateCacheKey(query *login.GetAuthInfoQuery) string { } func (s *Service) UpdateAuthInfo(ctx context.Context, cmd *login.UpdateAuthInfoCommand) error { - if cmd.UserId == 0 || cmd.AuthId == "" { - return errMissingParameters + // Only update auth info if we have an (user id + auth module) + if cmd.UserId == 0 || cmd.AuthModule == "" { + return errMissingParameters.Errorf("missing parameters for auth info %v", cmd) } - err := s.authInfoStore.UpdateAuthInfo(ctx, cmd) - if err != nil { + if err := s.authInfoStore.UpdateAuthInfo(ctx, cmd); err != nil { return err } @@ -137,12 +138,12 @@ func (s *Service) UpdateAuthInfo(ctx context.Context, cmd *login.UpdateAuthInfoC } func (s *Service) SetAuthInfo(ctx context.Context, cmd *login.SetAuthInfoCommand) error { - if cmd.UserId == 0 || cmd.AuthId == "" { - return errMissingParameters + // Only set auth info if we have an (user id + auth module) + if cmd.UserId == 0 || cmd.AuthModule == "" { + return errMissingParameters.Errorf("missing parameters for auth info %v", cmd) } - err := s.authInfoStore.SetAuthInfo(ctx, cmd) - if err != nil { + if err := s.authInfoStore.SetAuthInfo(ctx, cmd); err != nil { return err } @@ -172,28 +173,32 @@ func (s *Service) DeleteUserAuthInfo(ctx context.Context, userID int64) error { } func (s *Service) deleteUserAuthInfoInCache(ctx context.Context, query *login.GetAuthInfoQuery) { - err := s.remoteCache.Delete(ctx, generateCacheKey(&login.GetAuthInfoQuery{ - AuthModule: query.AuthModule, - AuthId: query.AuthId, - })) - if err != nil { - s.logger.Warn("failed to delete auth info from cache", "error", err) - } - - errN := s.remoteCache.Delete(ctx, generateCacheKey( - &login.GetAuthInfoQuery{ - UserId: query.UserId, - })) - if errN != nil { - s.logger.Warn("failed to delete user auth info from cache", "error", errN) - } - - errA := s.remoteCache.Delete(ctx, generateCacheKey( - &login.GetAuthInfoQuery{ - UserId: query.UserId, + if query.AuthId != "" { + err := s.remoteCache.Delete(ctx, generateCacheKey(&login.GetAuthInfoQuery{ AuthModule: query.AuthModule, + AuthId: query.AuthId, })) - if errA != nil { - s.logger.Warn("failed to delete user module auth info from cache", "error", errA) + if err != nil { + s.logger.Warn("failed to delete auth info from cache", "error", err) + } + } + + if query.UserId != 0 { + errN := s.remoteCache.Delete(ctx, generateCacheKey( + &login.GetAuthInfoQuery{ + UserId: query.UserId, + })) + if errN != nil { + s.logger.Warn("failed to delete user auth info from cache", "error", errN) + } + + errA := s.remoteCache.Delete(ctx, generateCacheKey( + &login.GetAuthInfoQuery{ + UserId: query.UserId, + AuthModule: query.AuthModule, + })) + if errA != nil { + s.logger.Warn("failed to delete user module auth info from cache", "error", errA) + } } }