3
0
mirror of https://github.com/grafana/grafana.git synced 2025-02-25 18:55:37 -06:00

Login: Fix mismatching label on auth_module in user list ()

* Login: Fix mismatching label on user auth_module

* Login: ensure previous auth was set to differing

* Login: ensure only one entry of auth is updated

* compare both entries

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>

* remove noop

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
This commit is contained in:
Jguer 2022-05-19 10:03:04 +00:00 committed by GitHub
parent 258e48678a
commit 86962dc9bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 110 additions and 8 deletions
pkg/services/login

View File

@ -146,6 +146,22 @@ func (s *AuthInfoStore) SetAuthInfo(ctx context.Context, cmd *models.SetAuthInfo
})
}
// UpdateAuthInfo updates the auth info for the user with the latest date. Avoids overlapping entries hiding
// the last used one (ex: LDAP->SAML->LDAP)
func (s *AuthInfoStore) UpdateAuthInfoDate(ctx context.Context, authInfo *models.UserAuth) error {
authInfo.Created = GetTime()
cond := &models.UserAuth{
Id: authInfo.Id,
UserId: authInfo.UserId,
AuthModule: authInfo.AuthModule,
}
return s.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
_, err := sess.Update(authInfo, cond)
return err
})
}
func (s *AuthInfoStore) UpdateAuthInfo(ctx context.Context, cmd *models.UpdateAuthInfoCommand) error {
authUser := &models.UserAuth{
UserId: cmd.UserId,

View File

@ -158,14 +158,20 @@ func (s *Implementation) LookupAndUpdate(ctx context.Context, query *models.GetU
authInfo = ai
}
if authInfo == nil && query.AuthModule != "" {
cmd := &models.SetAuthInfoCommand{
UserId: user.Id,
AuthModule: query.AuthModule,
AuthId: query.AuthId,
}
if err := s.authInfoStore.SetAuthInfo(ctx, cmd); err != nil {
return nil, err
if query.AuthModule != "" {
if authInfo == nil {
cmd := &models.SetAuthInfoCommand{
UserId: user.Id,
AuthModule: query.AuthModule,
AuthId: query.AuthId,
}
if err := s.authInfoStore.SetAuthInfo(ctx, cmd); err != nil {
return nil, err
}
} else {
if err := s.authInfoStore.UpdateAuthInfoDate(ctx, authInfo); err != nil {
return nil, err
}
}
}

View File

@ -230,6 +230,85 @@ func TestUserAuth(t *testing.T) {
require.Equal(t, getAuthQuery.Result.AuthModule, "test1")
})
t.Run("Keeps track of last used auth_module when not using oauth", func(t *testing.T) {
// Restore after destructive operation
sqlStore = sqlstore.InitTestDB(t)
for i := 0; i < 5; i++ {
cmd := models.CreateUserCommand{
Email: fmt.Sprint("user", i, "@test.com"),
Name: fmt.Sprint("user", i),
Login: fmt.Sprint("loginuser", i),
}
_, err := sqlStore.CreateUser(context.Background(), cmd)
require.Nil(t, err)
}
// Find a user to set tokens on
login := "loginuser0"
fixedTime := time.Now()
// Calling srv.LookupAndUpdateQuery on an existing user will populate an entry in the user_auth table
// Make the first log-in during the past
database.GetTime = func() time.Time { return fixedTime.AddDate(0, 0, -2) }
queryOne := &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "test1", AuthId: "test1"}
user, err := srv.LookupAndUpdate(context.Background(), queryOne)
database.GetTime = time.Now
require.Nil(t, err)
require.Equal(t, user.Login, login)
// Add a second auth module for this user
// Have this module's last log-in be more recent
database.GetTime = func() time.Time { return fixedTime.AddDate(0, 0, -1) }
queryTwo := &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "test2", AuthId: "test2"}
user, err = srv.LookupAndUpdate(context.Background(), queryTwo)
require.Nil(t, err)
require.Equal(t, user.Login, login)
// Get the latest entry by not supply an authmodule or authid
getAuthQuery := &models.GetAuthInfoQuery{
UserId: user.Id,
}
err = authInfoStore.GetAuthInfo(context.Background(), getAuthQuery)
require.Nil(t, err)
require.Equal(t, "test2", getAuthQuery.Result.AuthModule)
// Now reuse first auth module and make sure it's updated to the most recent
database.GetTime = func() time.Time { return fixedTime }
user, err = srv.LookupAndUpdate(context.Background(), queryOne)
require.Nil(t, err)
require.Equal(t, user.Login, login)
err = authInfoStore.GetAuthInfo(context.Background(), getAuthQuery)
require.Nil(t, err)
require.Equal(t, "test1", getAuthQuery.Result.AuthModule)
// Now reuse second auth module and make sure it's updated to the most recent
database.GetTime = func() time.Time { return fixedTime.AddDate(0, 0, 1) }
user, err = srv.LookupAndUpdate(context.Background(), queryTwo)
require.Nil(t, err)
require.Equal(t, user.Login, login)
err = authInfoStore.GetAuthInfo(context.Background(), getAuthQuery)
require.Nil(t, err)
require.Equal(t, "test2", getAuthQuery.Result.AuthModule)
// Ensure test 1 did not have its entry modified
getAuthQueryUnchanged := &models.GetAuthInfoQuery{
UserId: user.Id,
AuthModule: "test1",
}
err = authInfoStore.GetAuthInfo(context.Background(), getAuthQueryUnchanged)
require.Nil(t, err)
require.Equal(t, "test1", getAuthQueryUnchanged.Result.AuthModule)
require.Less(t, getAuthQueryUnchanged.Result.Created, getAuthQuery.Result.Created)
})
t.Run("Can set & locate by generic oauth auth module and user id", func(t *testing.T) {
// Find a user to set tokens on
login := "loginuser0"

View File

@ -15,6 +15,7 @@ type Store interface {
GetAuthInfo(ctx context.Context, query *models.GetAuthInfoQuery) error
SetAuthInfo(ctx context.Context, cmd *models.SetAuthInfoCommand) error
UpdateAuthInfo(ctx context.Context, cmd *models.UpdateAuthInfoCommand) error
UpdateAuthInfoDate(ctx context.Context, authInfo *models.UserAuth) error
DeleteAuthInfo(ctx context.Context, cmd *models.DeleteAuthInfoCommand) error
GetUserById(ctx context.Context, id int64) (*models.User, error)
GetUserByLogin(ctx context.Context, login string) (*models.User, error)