Chore: Move login attempt methods to separate service (#54479)

* Chore: Move login attempt methods to separate service

* attempt to fix tests

* fix syntax

* better time mocking

* initialise now func
This commit is contained in:
Serge Zaitsev
2022-09-01 18:08:42 +02:00
committed by GitHub
parent d2bdb01092
commit 927ddf9376
19 changed files with 300 additions and 275 deletions
-88
View File
@@ -1,89 +1 @@
package sqlstore
import (
"context"
"strconv"
"time"
"github.com/grafana/grafana/pkg/models"
)
var getTimeNow = time.Now
func (ss *SQLStore) CreateLoginAttempt(ctx context.Context, cmd *models.CreateLoginAttemptCommand) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
loginAttempt := models.LoginAttempt{
Username: cmd.Username,
IpAddress: cmd.IpAddress,
Created: getTimeNow().Unix(),
}
if _, err := sess.Insert(&loginAttempt); err != nil {
return err
}
cmd.Result = loginAttempt
return nil
})
}
func (ss *SQLStore) DeleteOldLoginAttempts(ctx context.Context, cmd *models.DeleteOldLoginAttemptsCommand) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
var maxId int64
sql := "SELECT max(id) as id FROM login_attempt WHERE created < ?"
result, err := sess.Query(sql, cmd.OlderThan.Unix())
if err != nil {
return err
}
if len(result) == 0 || result[0] == nil {
return nil
}
maxId = toInt64(result[0]["id"])
if maxId == 0 {
return nil
}
sql = "DELETE FROM login_attempt WHERE id <= ?"
if result, err := sess.Exec(sql, maxId); err != nil {
return err
} else if cmd.DeletedRows, err = result.RowsAffected(); err != nil {
return err
}
return nil
})
}
func (ss *SQLStore) GetUserLoginAttemptCount(ctx context.Context, query *models.GetUserLoginAttemptCountQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
loginAttempt := new(models.LoginAttempt)
total, err := dbSession.
Where("username = ?", query.Username).
And("created >= ?", query.Since.Unix()).
Count(loginAttempt)
if err != nil {
return err
}
query.Result = total
return nil
})
}
func toInt64(i interface{}) int64 {
switch i := i.(type) {
case []byte:
n, _ := strconv.ParseInt(string(i), 10, 64)
return n
case int:
return int64(i)
case int64:
return i
}
return 0
}
-134
View File
@@ -1,135 +1 @@
package sqlstore
import (
"context"
"testing"
"time"
"github.com/grafana/grafana/pkg/models"
"github.com/stretchr/testify/require"
)
func mockTime(mock time.Time) time.Time {
getTimeNow = func() time.Time { return mock }
return mock
}
func TestIntegrationLoginAttempts(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
var beginningOfTime, timePlusOneMinute, timePlusTwoMinutes time.Time
var sqlStore *SQLStore
user := "user"
setup := func(t *testing.T) {
sqlStore = InitTestDB(t)
beginningOfTime = mockTime(time.Date(2017, 10, 22, 8, 0, 0, 0, time.Local))
err := sqlStore.CreateLoginAttempt(context.Background(), &models.CreateLoginAttemptCommand{
Username: user,
IpAddress: "192.168.0.1",
})
require.Nil(t, err)
timePlusOneMinute = mockTime(beginningOfTime.Add(time.Minute * 1))
err = sqlStore.CreateLoginAttempt(context.Background(), &models.CreateLoginAttemptCommand{
Username: user,
IpAddress: "192.168.0.1",
})
require.Nil(t, err)
timePlusTwoMinutes = mockTime(beginningOfTime.Add(time.Minute * 2))
err = sqlStore.CreateLoginAttempt(context.Background(), &models.CreateLoginAttemptCommand{
Username: user,
IpAddress: "192.168.0.1",
})
require.Nil(t, err)
}
t.Run("Should return a total count of zero login attempts when comparing since beginning of time + 2min and 1s", func(t *testing.T) {
setup(t)
query := models.GetUserLoginAttemptCountQuery{
Username: user,
Since: timePlusTwoMinutes.Add(time.Second * 1),
}
err := sqlStore.GetUserLoginAttemptCount(context.Background(), &query)
require.Nil(t, err)
require.Equal(t, int64(0), query.Result)
})
t.Run("Should return the total count of login attempts since beginning of time", func(t *testing.T) {
setup(t)
query := models.GetUserLoginAttemptCountQuery{
Username: user,
Since: beginningOfTime,
}
err := sqlStore.GetUserLoginAttemptCount(context.Background(), &query)
require.Nil(t, err)
require.Equal(t, int64(3), query.Result)
})
t.Run("Should return the total count of login attempts since beginning of time + 1min", func(t *testing.T) {
setup(t)
query := models.GetUserLoginAttemptCountQuery{
Username: user,
Since: timePlusOneMinute,
}
err := sqlStore.GetUserLoginAttemptCount(context.Background(), &query)
require.Nil(t, err)
require.Equal(t, int64(2), query.Result)
})
t.Run("Should return the total count of login attempts since beginning of time + 2min", func(t *testing.T) {
setup(t)
query := models.GetUserLoginAttemptCountQuery{
Username: user,
Since: timePlusTwoMinutes,
}
err := sqlStore.GetUserLoginAttemptCount(context.Background(), &query)
require.Nil(t, err)
require.Equal(t, int64(1), query.Result)
})
t.Run("Should return deleted rows older than beginning of time", func(t *testing.T) {
setup(t)
cmd := models.DeleteOldLoginAttemptsCommand{
OlderThan: beginningOfTime,
}
err := sqlStore.DeleteOldLoginAttempts(context.Background(), &cmd)
require.Nil(t, err)
require.Equal(t, int64(0), cmd.DeletedRows)
})
t.Run("Should return deleted rows older than beginning of time + 1min", func(t *testing.T) {
setup(t)
cmd := models.DeleteOldLoginAttemptsCommand{
OlderThan: timePlusOneMinute,
}
err := sqlStore.DeleteOldLoginAttempts(context.Background(), &cmd)
require.Nil(t, err)
require.Equal(t, int64(1), cmd.DeletedRows)
})
t.Run("Should return deleted rows older than beginning of time + 2min", func(t *testing.T) {
setup(t)
cmd := models.DeleteOldLoginAttemptsCommand{
OlderThan: timePlusTwoMinutes,
}
err := sqlStore.DeleteOldLoginAttempts(context.Background(), &cmd)
require.Nil(t, err)
require.Equal(t, int64(2), cmd.DeletedRows)
})
t.Run("Should return deleted rows older than beginning of time + 2min and 1s", func(t *testing.T) {
setup(t)
cmd := models.DeleteOldLoginAttemptsCommand{
OlderThan: timePlusTwoMinutes.Add(time.Second * 1),
}
err := sqlStore.DeleteOldLoginAttempts(context.Background(), &cmd)
require.Nil(t, err)
require.Equal(t, int64(3), cmd.DeletedRows)
})
}
-3
View File
@@ -26,9 +26,6 @@ type Store interface {
DeleteOrg(ctx context.Context, cmd *models.DeleteOrgCommand) error
GetOrgById(context.Context, *models.GetOrgByIdQuery) error
GetOrgByNameHandler(ctx context.Context, query *models.GetOrgByNameQuery) error
CreateLoginAttempt(ctx context.Context, cmd *models.CreateLoginAttemptCommand) error
GetUserLoginAttemptCount(ctx context.Context, query *models.GetUserLoginAttemptCountQuery) error
DeleteOldLoginAttempts(ctx context.Context, cmd *models.DeleteOldLoginAttemptsCommand) error
CreateUser(ctx context.Context, cmd user.CreateUserCommand) (*user.User, error)
SetUsingOrg(ctx context.Context, cmd *models.SetUsingOrgCommand) error
GetUserProfile(ctx context.Context, query *models.GetUserProfileQuery) error