Auth: Force lowercase login/email for users (#86359)
* [WIP]: Force lowercase login/email for user CRUD * warn and remove use of userCaseInsensitiveLogin check * remove log warning * reimplementation of the caseinsensitive * need to decide if we want the conflict check or not * remvoved the tests for conflict user by getEmail, getLogin * added tests for user lowercase migration * wip: emails next * tests for email lowercasing * review comments * optimized login and email lookup before migrating
This commit is contained in:
@@ -90,9 +90,10 @@ func (ss *sqlStore) Insert(ctx context.Context, cmd *user.User) (int64, error) {
|
||||
func (ss *sqlStore) Get(ctx context.Context, usr *user.User) (*user.User, error) {
|
||||
ret := &user.User{}
|
||||
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
login := usr.Login
|
||||
email := usr.Email
|
||||
where := "LOWER(email)=LOWER(?) OR LOWER(login)=LOWER(?)"
|
||||
// enforcement of lowercase due to forcement of caseinsensitive login
|
||||
login := strings.ToLower(usr.Login)
|
||||
email := strings.ToLower(usr.Email)
|
||||
where := "email=? OR login=?"
|
||||
|
||||
exists, err := sess.Where(where, email, login).Get(ret)
|
||||
if !exists {
|
||||
@@ -178,6 +179,9 @@ func (ss *sqlStore) CaseInsensitiveLoginConflict(ctx context.Context, login, ema
|
||||
}
|
||||
|
||||
func (ss *sqlStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQuery) (*user.User, error) {
|
||||
// enforcement of lowercase due to forcement of caseinsensitive login
|
||||
query.LoginOrEmail = strings.ToLower(query.LoginOrEmail)
|
||||
|
||||
usr := &user.User{}
|
||||
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
if query.LoginOrEmail == "" {
|
||||
@@ -191,7 +195,7 @@ func (ss *sqlStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQu
|
||||
// Since username can be an email address, attempt login with email address
|
||||
// first if the login field has the "@" symbol.
|
||||
if strings.Contains(query.LoginOrEmail, "@") {
|
||||
where = "LOWER(email)=LOWER(?)"
|
||||
where = "email=?"
|
||||
has, err = sess.Where(ss.notServiceAccountFilter()).Where(where, query.LoginOrEmail).Get(usr)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -200,7 +204,7 @@ func (ss *sqlStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQu
|
||||
|
||||
// Look for the login field instead of email
|
||||
if !has {
|
||||
where = "LOWER(login)=LOWER(?)"
|
||||
where = "login=?"
|
||||
has, err = sess.Where(ss.notServiceAccountFilter()).Where(where, query.LoginOrEmail).Get(usr)
|
||||
}
|
||||
|
||||
@@ -209,9 +213,6 @@ func (ss *sqlStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQu
|
||||
} else if !has {
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
if err := ss.userCaseInsensitiveLoginConflict(ctx, sess, usr.Login, usr.Email); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -223,13 +224,16 @@ func (ss *sqlStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQu
|
||||
}
|
||||
|
||||
func (ss *sqlStore) GetByEmail(ctx context.Context, query *user.GetUserByEmailQuery) (*user.User, error) {
|
||||
// enforcement of lowercase due to forcement of caseinsensitive login
|
||||
query.Email = strings.ToLower(query.Email)
|
||||
|
||||
usr := &user.User{}
|
||||
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
if query.Email == "" {
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
where := "LOWER(email)=LOWER(?)"
|
||||
where := "email=?"
|
||||
has, err := sess.Where(ss.notServiceAccountFilter()).Where(where, query.Email).Get(usr)
|
||||
|
||||
if err != nil {
|
||||
@@ -237,10 +241,6 @@ func (ss *sqlStore) GetByEmail(ctx context.Context, query *user.GetUserByEmailQu
|
||||
} else if !has {
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
if err := ss.userCaseInsensitiveLoginConflict(ctx, sess, usr.Login, usr.Email); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -249,21 +249,6 @@ func (ss *sqlStore) GetByEmail(ctx context.Context, query *user.GetUserByEmailQu
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
func (ss *sqlStore) userCaseInsensitiveLoginConflict(ctx context.Context, sess *db.Session, login, email string) error {
|
||||
users := make([]user.User, 0)
|
||||
|
||||
if err := sess.Where("LOWER(email)=LOWER(?) OR LOWER(login)=LOWER(?)",
|
||||
email, login).Find(&users); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(users) > 1 {
|
||||
return &user.ErrCaseInsensitiveLoginConflict{Users: users}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoginConflict returns an error if the provided email or login are already
|
||||
// associated with a user. If caseInsensitive is true the search is not case
|
||||
// sensitive.
|
||||
@@ -299,6 +284,10 @@ func (ss *sqlStore) loginConflict(ctx context.Context, sess *db.Session, login,
|
||||
}
|
||||
|
||||
func (ss *sqlStore) Update(ctx context.Context, cmd *user.UpdateUserCommand) error {
|
||||
// enforcement of lowercase due to forcement of caseinsensitive login
|
||||
cmd.Login = strings.ToLower(cmd.Login)
|
||||
cmd.Email = strings.ToLower(cmd.Email)
|
||||
|
||||
return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
user := user.User{
|
||||
Name: cmd.Name,
|
||||
|
||||
@@ -344,37 +344,6 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("GetByEmail - email conflict", func(t *testing.T) {
|
||||
query := user.GetUserByEmailQuery{Email: "confusertest@test.com"}
|
||||
_, err = userStore.GetByEmail(context.Background(), &query)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("GetByEmail - login conflict", func(t *testing.T) {
|
||||
query := user.GetUserByEmailQuery{Email: "user_test_login_conflict@test.com"}
|
||||
_, err = userStore.GetByEmail(context.Background(), &query)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("GetByLogin - email conflict", func(t *testing.T) {
|
||||
query := user.GetUserByLoginQuery{LoginOrEmail: "user_email_conflict_two"}
|
||||
_, err = userStore.GetByLogin(context.Background(), &query)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("GetByLogin - login conflict", func(t *testing.T) {
|
||||
query := user.GetUserByLoginQuery{LoginOrEmail: "user_test_login_conflict"}
|
||||
_, err = userStore.GetByLogin(context.Background(), &query)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("GetByLogin - login conflict by email", func(t *testing.T) {
|
||||
query := user.GetUserByLoginQuery{LoginOrEmail: "user_test_login_conflict@test.com"}
|
||||
_, err = userStore.GetByLogin(context.Background(), &query)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("GetByLogin - user2 uses user1.email as login", func(t *testing.T) {
|
||||
// create user_1
|
||||
user1 := &user.User{
|
||||
|
||||
Reference in New Issue
Block a user