mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Login: remove login.Service (#73542)
This commit is contained in:
parent
ab587b6884
commit
618daf0518
@ -77,7 +77,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/login/authinfoservice"
|
||||
authinfodatabase "github.com/grafana/grafana/pkg/services/login/authinfoservice/database"
|
||||
"github.com/grafana/grafana/pkg/services/login/loginservice"
|
||||
"github.com/grafana/grafana/pkg/services/loginattempt"
|
||||
"github.com/grafana/grafana/pkg/services/loginattempt/loginattemptimpl"
|
||||
"github.com/grafana/grafana/pkg/services/navtree/navtreeimpl"
|
||||
@ -215,8 +214,6 @@ var wireBasicSet = wire.NewSet(
|
||||
quotaimpl.ProvideService,
|
||||
remotecache.ProvideService,
|
||||
wire.Bind(new(remotecache.CacheStorage), new(*remotecache.RemoteCache)),
|
||||
loginservice.ProvideService,
|
||||
wire.Bind(new(login.Service), new(*loginservice.Implementation)),
|
||||
authinfoservice.ProvideAuthInfoService,
|
||||
wire.Bind(new(login.AuthInfoService), new(*authinfoservice.Implementation)),
|
||||
authinfodatabase.ProvideAuthInfoStore,
|
||||
|
@ -46,6 +46,12 @@ var (
|
||||
)
|
||||
)
|
||||
|
||||
var (
|
||||
errUsersQuotaReached = errors.New("users quota reached")
|
||||
errGettingUserQuota = errors.New("error getting user quota")
|
||||
errSignupNotAllowed = errors.New("system administrator has disabled signup")
|
||||
)
|
||||
|
||||
func ProvideUserSync(userService user.Service,
|
||||
userProtectionService login.UserProtectionService,
|
||||
authInfoService login.AuthInfoService, quotaService quota.Service) *UserSync {
|
||||
@ -82,7 +88,7 @@ func (s *UserSync) SyncUserHook(ctx context.Context, id *authn.Identity, _ *auth
|
||||
if errors.Is(errUserInDB, user.ErrUserNotFound) {
|
||||
if !id.ClientParams.AllowSignUp {
|
||||
s.log.FromContext(ctx).Warn("Failed to create user, signup is not allowed for module", "auth_module", id.AuthenticatedBy, "auth_id", id.AuthID)
|
||||
return errUserSignupDisabled.Errorf("%w", login.ErrSignupNotAllowed)
|
||||
return errUserSignupDisabled.Errorf("%w", errSignupNotAllowed)
|
||||
}
|
||||
|
||||
// create user
|
||||
@ -259,10 +265,10 @@ func (s *UserSync) createUser(ctx context.Context, id *authn.Identity) (*user.Us
|
||||
limitReached, errLimit := s.quotaService.CheckQuotaReached(ctx, quota.TargetSrv(srv), nil)
|
||||
if errLimit != nil {
|
||||
s.log.FromContext(ctx).Error("Failed to check quota", "error", errLimit)
|
||||
return nil, errSyncUserInternal.Errorf("%w", login.ErrGettingUserQuota)
|
||||
return nil, errSyncUserInternal.Errorf("%w", errGettingUserQuota)
|
||||
}
|
||||
if limitReached {
|
||||
return nil, errSyncUserForbidden.Errorf("%w", login.ErrUsersQuotaReached)
|
||||
return nil, errSyncUserForbidden.Errorf("%w", errUsersQuotaReached)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidCredentials = errors.New("invalid username or password")
|
||||
ErrUsersQuotaReached = errors.New("users quota reached")
|
||||
ErrGettingUserQuota = errors.New("error getting user quota")
|
||||
ErrSignupNotAllowed = errors.New("system administrator has disabled signup")
|
||||
)
|
||||
|
||||
type TeamSyncFunc func(user *user.User, externalUser *ExternalUserInfo) error
|
||||
|
||||
type Service interface {
|
||||
UpsertUser(ctx context.Context, cmd *UpsertUserCommand) (*user.User, error)
|
||||
DisableExternalUser(ctx context.Context, username string) error
|
||||
SetTeamSyncFunc(TeamSyncFunc)
|
||||
}
|
@ -1,342 +0,0 @@
|
||||
package loginservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var (
|
||||
logger = log.New("login.ext_user")
|
||||
)
|
||||
|
||||
func ProvideService(
|
||||
userService user.Service,
|
||||
quotaService quota.Service,
|
||||
authInfoService login.AuthInfoService,
|
||||
accessControl accesscontrol.Service,
|
||||
orgService org.Service,
|
||||
) *Implementation {
|
||||
s := &Implementation{
|
||||
userService: userService,
|
||||
QuotaService: quotaService,
|
||||
AuthInfoService: authInfoService,
|
||||
accessControl: accessControl,
|
||||
orgService: orgService,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type Implementation struct {
|
||||
userService user.Service
|
||||
AuthInfoService login.AuthInfoService
|
||||
QuotaService quota.Service
|
||||
TeamSync login.TeamSyncFunc
|
||||
accessControl accesscontrol.Service
|
||||
orgService org.Service
|
||||
}
|
||||
|
||||
// UpsertUser updates an existing user, or if it doesn't exist, inserts a new one.
|
||||
func (ls *Implementation) UpsertUser(ctx context.Context, cmd *login.UpsertUserCommand) (result *user.User, err error) {
|
||||
var logger log.Logger = logger
|
||||
if cmd.ReqContext != nil && cmd.ReqContext.Logger != nil {
|
||||
logger = cmd.ReqContext.Logger
|
||||
}
|
||||
|
||||
extUser := cmd.ExternalUser
|
||||
|
||||
usr, errAuthLookup := ls.AuthInfoService.LookupAndUpdate(ctx, &login.GetUserByAuthInfoQuery{
|
||||
AuthModule: extUser.AuthModule,
|
||||
AuthId: extUser.AuthId,
|
||||
UserLookupParams: cmd.UserLookupParams,
|
||||
})
|
||||
if errAuthLookup != nil {
|
||||
if !errors.Is(errAuthLookup, user.ErrUserNotFound) {
|
||||
return nil, errAuthLookup
|
||||
}
|
||||
|
||||
if !cmd.SignupAllowed {
|
||||
logger.Warn("Not allowing login, user not found in internal user database and allow signup = false", "authmode", extUser.AuthModule)
|
||||
return nil, login.ErrSignupNotAllowed
|
||||
}
|
||||
|
||||
// quota check (FIXME: (jguer) this should be done in the user service)
|
||||
// we may insert in both user and org_user tables
|
||||
// therefore we need to query check quota for both user and org services
|
||||
for _, srv := range []string{user.QuotaTargetSrv, org.QuotaTargetSrv} {
|
||||
limitReached, errLimit := ls.QuotaService.CheckQuotaReached(ctx, quota.TargetSrv(srv), nil)
|
||||
if errLimit != nil {
|
||||
logger.Warn("Error getting user quota.", "error", errLimit)
|
||||
return nil, login.ErrGettingUserQuota
|
||||
}
|
||||
if limitReached {
|
||||
return nil, login.ErrUsersQuotaReached
|
||||
}
|
||||
}
|
||||
|
||||
createdUser, errCreateUser := ls.userService.Create(ctx, &user.CreateUserCommand{
|
||||
Login: extUser.Login,
|
||||
Email: extUser.Email,
|
||||
Name: extUser.Name,
|
||||
SkipOrgSetup: len(extUser.OrgRoles) > 0,
|
||||
})
|
||||
if errCreateUser != nil {
|
||||
return nil, errCreateUser
|
||||
}
|
||||
|
||||
result = &user.User{
|
||||
ID: createdUser.ID,
|
||||
Version: createdUser.Version,
|
||||
Email: createdUser.Email,
|
||||
Name: createdUser.Name,
|
||||
Login: createdUser.Login,
|
||||
Password: createdUser.Password,
|
||||
Salt: createdUser.Salt,
|
||||
Rands: createdUser.Rands,
|
||||
Company: createdUser.Company,
|
||||
EmailVerified: createdUser.EmailVerified,
|
||||
Theme: createdUser.Theme,
|
||||
HelpFlags1: createdUser.HelpFlags1,
|
||||
IsDisabled: createdUser.IsDisabled,
|
||||
IsAdmin: createdUser.IsAdmin,
|
||||
IsServiceAccount: createdUser.IsServiceAccount,
|
||||
OrgID: createdUser.OrgID,
|
||||
Created: createdUser.Created,
|
||||
Updated: createdUser.Updated,
|
||||
LastSeenAt: createdUser.LastSeenAt,
|
||||
}
|
||||
|
||||
if extUser.AuthModule != "" {
|
||||
cmd2 := &login.SetAuthInfoCommand{
|
||||
UserId: result.ID,
|
||||
AuthModule: extUser.AuthModule,
|
||||
AuthId: extUser.AuthId,
|
||||
OAuthToken: extUser.OAuthToken,
|
||||
}
|
||||
if errSetAuth := ls.AuthInfoService.SetAuthInfo(ctx, cmd2); errSetAuth != nil {
|
||||
return nil, errSetAuth
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = usr
|
||||
|
||||
if errUserMod := ls.updateUser(ctx, result, extUser); errUserMod != nil {
|
||||
return nil, errUserMod
|
||||
}
|
||||
|
||||
// Always persist the latest token at log-in
|
||||
if extUser.AuthModule != "" && extUser.OAuthToken != nil {
|
||||
if errAuthMod := ls.updateUserAuth(ctx, result, extUser); errAuthMod != nil {
|
||||
return nil, errAuthMod
|
||||
}
|
||||
}
|
||||
|
||||
if extUser.AuthModule == login.LDAPAuthModule && usr.IsDisabled {
|
||||
// Re-enable user when it found in LDAP
|
||||
if errDisableUser := ls.userService.Disable(ctx,
|
||||
&user.DisableUserCommand{
|
||||
UserID: result.ID, IsDisabled: false}); errDisableUser != nil {
|
||||
return nil, errDisableUser
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if errSyncRole := ls.syncOrgRoles(ctx, result, extUser); errSyncRole != nil {
|
||||
return nil, errSyncRole
|
||||
}
|
||||
|
||||
// Sync isGrafanaAdmin permission
|
||||
if extUser.IsGrafanaAdmin != nil && *extUser.IsGrafanaAdmin != result.IsAdmin {
|
||||
if errPerms := ls.userService.UpdatePermissions(ctx, result.ID, *extUser.IsGrafanaAdmin); errPerms != nil {
|
||||
return nil, errPerms
|
||||
}
|
||||
}
|
||||
|
||||
// There are external providers where we want to completely skip team synchronization see - https://github.com/grafana/grafana/issues/62175
|
||||
if ls.TeamSync != nil && !extUser.SkipTeamSync {
|
||||
if errTeamSync := ls.TeamSync(result, extUser); errTeamSync != nil {
|
||||
return nil, errTeamSync
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (ls *Implementation) DisableExternalUser(ctx context.Context, username string) error {
|
||||
// Check if external user exist in Grafana
|
||||
userQuery := &login.GetExternalUserInfoByLoginQuery{
|
||||
LoginOrEmail: username,
|
||||
}
|
||||
|
||||
userInfo, err := ls.AuthInfoService.GetExternalUserInfoByLogin(ctx, userQuery)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if userInfo.IsDisabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Debug(
|
||||
"Disabling external user",
|
||||
"user",
|
||||
userInfo.Login,
|
||||
)
|
||||
|
||||
// Mark user as disabled in grafana db
|
||||
disableUserCmd := &user.DisableUserCommand{
|
||||
UserID: userInfo.UserId,
|
||||
IsDisabled: true,
|
||||
}
|
||||
|
||||
if err := ls.userService.Disable(ctx, disableUserCmd); err != nil {
|
||||
logger.Debug(
|
||||
"Error disabling external user",
|
||||
"user",
|
||||
userInfo.Login,
|
||||
"message",
|
||||
err.Error(),
|
||||
)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTeamSyncFunc sets the function received through args as the team sync function.
|
||||
func (ls *Implementation) SetTeamSyncFunc(teamSyncFunc login.TeamSyncFunc) {
|
||||
ls.TeamSync = teamSyncFunc
|
||||
}
|
||||
|
||||
func (ls *Implementation) updateUser(ctx context.Context, usr *user.User, extUser *login.ExternalUserInfo) error {
|
||||
// sync user info
|
||||
updateCmd := &user.UpdateUserCommand{
|
||||
UserID: usr.ID,
|
||||
}
|
||||
|
||||
needsUpdate := false
|
||||
if extUser.Login != "" && extUser.Login != usr.Login {
|
||||
updateCmd.Login = extUser.Login
|
||||
usr.Login = extUser.Login
|
||||
needsUpdate = true
|
||||
}
|
||||
|
||||
if extUser.Email != "" && extUser.Email != usr.Email {
|
||||
updateCmd.Email = extUser.Email
|
||||
usr.Email = extUser.Email
|
||||
needsUpdate = true
|
||||
}
|
||||
|
||||
if extUser.Name != "" && extUser.Name != usr.Name {
|
||||
updateCmd.Name = extUser.Name
|
||||
usr.Name = extUser.Name
|
||||
needsUpdate = true
|
||||
}
|
||||
|
||||
if !needsUpdate {
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Debug("Syncing user info", "id", usr.ID, "update", updateCmd)
|
||||
return ls.userService.Update(ctx, updateCmd)
|
||||
}
|
||||
|
||||
func (ls *Implementation) updateUserAuth(ctx context.Context, user *user.User, extUser *login.ExternalUserInfo) error {
|
||||
updateCmd := &login.UpdateAuthInfoCommand{
|
||||
AuthModule: extUser.AuthModule,
|
||||
AuthId: extUser.AuthId,
|
||||
UserId: user.ID,
|
||||
OAuthToken: extUser.OAuthToken,
|
||||
}
|
||||
|
||||
logger.Debug("Updating user_auth info", "user_id", user.ID)
|
||||
return ls.AuthInfoService.UpdateAuthInfo(ctx, updateCmd)
|
||||
}
|
||||
|
||||
func (ls *Implementation) syncOrgRoles(ctx context.Context, usr *user.User, extUser *login.ExternalUserInfo) error {
|
||||
logger.Debug("Syncing organization roles", "id", usr.ID, "extOrgRoles", extUser.OrgRoles)
|
||||
|
||||
// don't sync org roles if none is specified
|
||||
if len(extUser.OrgRoles) == 0 {
|
||||
logger.Debug("Not syncing organization roles since external user doesn't have any")
|
||||
return nil
|
||||
}
|
||||
|
||||
orgsQuery := &org.GetUserOrgListQuery{UserID: usr.ID}
|
||||
result, err := ls.orgService.GetUserOrgList(ctx, orgsQuery)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
handledOrgIds := map[int64]bool{}
|
||||
deleteOrgIds := []int64{}
|
||||
|
||||
// update existing org roles
|
||||
for _, orga := range result {
|
||||
handledOrgIds[orga.OrgID] = true
|
||||
|
||||
extRole := extUser.OrgRoles[orga.OrgID]
|
||||
if extRole == "" {
|
||||
deleteOrgIds = append(deleteOrgIds, orga.OrgID)
|
||||
} else if extRole != orga.Role {
|
||||
// update role
|
||||
cmd := &org.UpdateOrgUserCommand{OrgID: orga.OrgID, UserID: usr.ID, Role: extRole}
|
||||
if err := ls.orgService.UpdateOrgUser(ctx, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add any new org roles
|
||||
for orgId, orgRole := range extUser.OrgRoles {
|
||||
if _, exists := handledOrgIds[orgId]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// add role
|
||||
cmd := &org.AddOrgUserCommand{UserID: usr.ID, Role: orgRole, OrgID: orgId}
|
||||
err := ls.orgService.AddOrgUser(ctx, cmd)
|
||||
if err != nil && !errors.Is(err, org.ErrOrgNotFound) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// delete any removed org roles
|
||||
for _, orgId := range deleteOrgIds {
|
||||
logger.Debug("Removing user's organization membership as part of syncing with OAuth login",
|
||||
"userId", usr.ID, "orgId", orgId)
|
||||
cmd := &org.RemoveOrgUserCommand{OrgID: orgId, UserID: usr.ID}
|
||||
if err := ls.orgService.RemoveOrgUser(ctx, cmd); err != nil {
|
||||
if errors.Is(err, org.ErrLastOrgAdmin) {
|
||||
logger.Error(err.Error(), "userId", cmd.UserID, "orgId", cmd.OrgID)
|
||||
continue
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ls.accessControl.DeleteUserPermissions(ctx, orgId, cmd.UserID); err != nil {
|
||||
logger.Warn("failed to delete permissions for user", "error", err, "userID", cmd.UserID, "orgID", orgId)
|
||||
}
|
||||
}
|
||||
|
||||
// update user's default org if needed
|
||||
if _, ok := extUser.OrgRoles[usr.OrgID]; !ok {
|
||||
for orgId := range extUser.OrgRoles {
|
||||
usr.OrgID = orgId
|
||||
break
|
||||
}
|
||||
|
||||
return ls.userService.SetUsingOrg(ctx, &user.SetUsingOrgCommand{
|
||||
UserID: usr.ID,
|
||||
OrgID: usr.OrgID,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package loginservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type LoginServiceMock struct {
|
||||
login.Service
|
||||
ExpectedUser *user.User
|
||||
ExpectedUserFunc func(cmd *login.UpsertUserCommand) *user.User
|
||||
ExpectedError error
|
||||
}
|
||||
|
||||
func (s LoginServiceMock) UpsertUser(ctx context.Context, cmd *login.UpsertUserCommand) (*user.User, error) {
|
||||
if s.ExpectedUserFunc != nil {
|
||||
return s.ExpectedUserFunc(cmd), s.ExpectedError
|
||||
}
|
||||
return s.ExpectedUser, s.ExpectedError
|
||||
}
|
||||
|
||||
func (s LoginServiceMock) DisableExternalUser(ctx context.Context, username string) error {
|
||||
return nil
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
package loginservice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/login/logintest"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
)
|
||||
|
||||
func Test_syncOrgRoles_doesNotBreakWhenTryingToRemoveLastOrgAdmin(t *testing.T) {
|
||||
user := createSimpleUser()
|
||||
externalUser := createSimpleExternalUser()
|
||||
authInfoMock := &logintest.AuthInfoServiceFake{}
|
||||
|
||||
login := Implementation{
|
||||
QuotaService: quotatest.New(false, nil),
|
||||
AuthInfoService: authInfoMock,
|
||||
userService: usertest.NewUserServiceFake(),
|
||||
orgService: orgtest.NewOrgServiceFake(),
|
||||
}
|
||||
|
||||
err := login.syncOrgRoles(context.Background(), &user, &externalUser)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_syncOrgRoles_whenTryingToRemoveLastOrgLogsError(t *testing.T) {
|
||||
buf := &bytes.Buffer{}
|
||||
logger.Swap(level.NewFilter(log.NewLogfmtLogger(buf), level.AllowInfo()))
|
||||
|
||||
user := createSimpleUser()
|
||||
externalUser := createSimpleExternalUser()
|
||||
|
||||
authInfoMock := &logintest.AuthInfoServiceFake{}
|
||||
|
||||
orgService := orgtest.NewOrgServiceFake()
|
||||
orgService.ExpectedUserOrgDTO = createUserOrgDTO()
|
||||
orgService.ExpectedOrgListResponse = createResponseWithOneErrLastOrgAdminItem()
|
||||
|
||||
login := Implementation{
|
||||
QuotaService: quotatest.New(false, nil),
|
||||
AuthInfoService: authInfoMock,
|
||||
userService: usertest.NewUserServiceFake(),
|
||||
orgService: orgService,
|
||||
accessControl: &actest.FakeService{},
|
||||
}
|
||||
|
||||
err := login.syncOrgRoles(context.Background(), &user, &externalUser)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, buf.String(), org.ErrLastOrgAdmin.Error())
|
||||
}
|
||||
|
||||
func Test_teamSync(t *testing.T) {
|
||||
authInfoMock := &logintest.AuthInfoServiceFake{}
|
||||
loginsvc := Implementation{
|
||||
QuotaService: quotatest.New(false, nil),
|
||||
AuthInfoService: authInfoMock,
|
||||
}
|
||||
|
||||
email := "test_user@example.org"
|
||||
upsertCmd := &login.UpsertUserCommand{ExternalUser: &login.ExternalUserInfo{Email: email},
|
||||
UserLookupParams: login.UserLookupParams{Email: &email}}
|
||||
expectedUser := &user.User{
|
||||
ID: 1,
|
||||
Email: email,
|
||||
Name: "test_user",
|
||||
Login: "test_user",
|
||||
}
|
||||
authInfoMock.ExpectedUser = expectedUser
|
||||
|
||||
var actualUser *user.User
|
||||
var actualExternalUser *login.ExternalUserInfo
|
||||
|
||||
t.Run("login.TeamSync should not be called when nil", func(t *testing.T) {
|
||||
_, err := loginsvc.UpsertUser(context.Background(), upsertCmd)
|
||||
require.Nil(t, err)
|
||||
assert.Nil(t, actualUser)
|
||||
assert.Nil(t, actualExternalUser)
|
||||
|
||||
t.Run("login.TeamSync should be called when not nil", func(t *testing.T) {
|
||||
teamSyncFunc := func(user *user.User, externalUser *login.ExternalUserInfo) error {
|
||||
actualUser = user
|
||||
actualExternalUser = externalUser
|
||||
return nil
|
||||
}
|
||||
loginsvc.TeamSync = teamSyncFunc
|
||||
_, err := loginsvc.UpsertUser(context.Background(), upsertCmd)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, actualUser, expectedUser)
|
||||
assert.Equal(t, actualExternalUser, upsertCmd.ExternalUser)
|
||||
})
|
||||
|
||||
t.Run("login.TeamSync should not be called when not nil and skipTeamSync is set for externalUserInfo", func(t *testing.T) {
|
||||
var actualUser *user.User
|
||||
var actualExternalUser *login.ExternalUserInfo
|
||||
upsertCmdSkipTeamSync := &login.UpsertUserCommand{
|
||||
ExternalUser: &login.ExternalUserInfo{
|
||||
Email: email,
|
||||
// sending in ExternalUserInfo with SkipTeamSync yields no team sync
|
||||
SkipTeamSync: true,
|
||||
},
|
||||
UserLookupParams: login.UserLookupParams{Email: &email},
|
||||
}
|
||||
teamSyncFunc := func(user *user.User, externalUser *login.ExternalUserInfo) error {
|
||||
actualUser = user
|
||||
actualExternalUser = externalUser
|
||||
return nil
|
||||
}
|
||||
loginsvc.TeamSync = teamSyncFunc
|
||||
_, err := loginsvc.UpsertUser(context.Background(), upsertCmdSkipTeamSync)
|
||||
require.Nil(t, err)
|
||||
assert.Nil(t, actualUser)
|
||||
assert.Nil(t, actualExternalUser)
|
||||
})
|
||||
|
||||
t.Run("login.TeamSync should propagate its errors to the caller", func(t *testing.T) {
|
||||
teamSyncFunc := func(user *user.User, externalUser *login.ExternalUserInfo) error {
|
||||
return errors.New("teamsync test error")
|
||||
}
|
||||
loginsvc.TeamSync = teamSyncFunc
|
||||
_, err := loginsvc.UpsertUser(context.Background(), upsertCmd)
|
||||
require.Error(t, err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpsertUser_crashOnLog_issue62538(t *testing.T) {
|
||||
authInfoMock := &logintest.AuthInfoServiceFake{}
|
||||
authInfoMock.ExpectedError = user.ErrUserNotFound
|
||||
loginsvc := Implementation{
|
||||
QuotaService: quotatest.New(false, nil),
|
||||
AuthInfoService: authInfoMock,
|
||||
}
|
||||
|
||||
email := "test_user@example.org"
|
||||
upsertCmd := &login.UpsertUserCommand{
|
||||
ExternalUser: &login.ExternalUserInfo{Email: email},
|
||||
UserLookupParams: login.UserLookupParams{Email: &email},
|
||||
SignupAllowed: false,
|
||||
}
|
||||
|
||||
var err error
|
||||
require.NotPanics(t, func() {
|
||||
_, err = loginsvc.UpsertUser(context.Background(), upsertCmd)
|
||||
})
|
||||
require.ErrorIs(t, err, login.ErrSignupNotAllowed)
|
||||
}
|
||||
|
||||
func createSimpleUser() user.User {
|
||||
user := user.User{
|
||||
ID: 1,
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func createUserOrgDTO() []*org.UserOrgDTO {
|
||||
users := []*org.UserOrgDTO{
|
||||
{
|
||||
OrgID: 1,
|
||||
Name: "Bar",
|
||||
Role: org.RoleViewer,
|
||||
},
|
||||
{
|
||||
OrgID: 10,
|
||||
Name: "Foo",
|
||||
Role: org.RoleAdmin,
|
||||
},
|
||||
{
|
||||
OrgID: 11,
|
||||
Name: "Stuff",
|
||||
Role: org.RoleViewer,
|
||||
},
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
func createSimpleExternalUser() login.ExternalUserInfo {
|
||||
externalUser := login.ExternalUserInfo{
|
||||
AuthModule: login.LDAPAuthModule,
|
||||
OrgRoles: map[int64]org.RoleType{
|
||||
1: org.RoleViewer,
|
||||
},
|
||||
}
|
||||
|
||||
return externalUser
|
||||
}
|
||||
|
||||
func createResponseWithOneErrLastOrgAdminItem() orgtest.OrgListResponse {
|
||||
remResp := orgtest.OrgListResponse{
|
||||
{
|
||||
OrgID: 10,
|
||||
Response: org.ErrLastOrgAdmin,
|
||||
},
|
||||
{
|
||||
OrgID: 11,
|
||||
Response: nil,
|
||||
},
|
||||
}
|
||||
return remResp
|
||||
}
|
@ -7,16 +7,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type LoginServiceFake struct{}
|
||||
|
||||
func (l *LoginServiceFake) UpsertUser(ctx context.Context, cmd *login.UpsertUserCommand) (*user.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (l *LoginServiceFake) DisableExternalUser(ctx context.Context, username string) error {
|
||||
return nil
|
||||
}
|
||||
func (l *LoginServiceFake) SetTeamSyncFunc(login.TeamSyncFunc) {}
|
||||
|
||||
type AuthInfoServiceFake struct {
|
||||
login.AuthInfoService
|
||||
LatestUserID int64
|
||||
@ -71,13 +61,3 @@ func (a *AuthInfoServiceFake) GetExternalUserInfoByLogin(ctx context.Context, qu
|
||||
func (a *AuthInfoServiceFake) DeleteUserAuthInfo(ctx context.Context, userID int64) error {
|
||||
return a.ExpectedError
|
||||
}
|
||||
|
||||
type AuthenticatorFake struct {
|
||||
ExpectedUser *user.User
|
||||
ExpectedError error
|
||||
}
|
||||
|
||||
func (a *AuthenticatorFake) AuthenticateUser(c context.Context, query *login.LoginUserQuery) error {
|
||||
query.User = a.ExpectedUser
|
||||
return a.ExpectedError
|
||||
}
|
||||
|
@ -91,13 +91,6 @@ type RequestURIKey struct{}
|
||||
// ---------------------
|
||||
// COMMANDS
|
||||
|
||||
type UpsertUserCommand struct {
|
||||
ReqContext *contextmodel.ReqContext
|
||||
ExternalUser *ExternalUserInfo
|
||||
UserLookupParams
|
||||
SignupAllowed bool
|
||||
}
|
||||
|
||||
type SetAuthInfoCommand struct {
|
||||
AuthModule string
|
||||
AuthId string
|
||||
|
Loading…
Reference in New Issue
Block a user