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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user