Chore: Remove some bus from login package (login attempts) (#47310)

This commit is contained in:
Serge Zaitsev
2022-04-05 13:07:27 +02:00
committed by GitHub
parent f722986b83
commit bf9e0e8bc8
6 changed files with 35 additions and 45 deletions
+2 -2
View File
@@ -47,7 +47,7 @@ func ProvideService(store sqlstore.Store, loginService login.Service) *Authentic
// AuthenticateUser authenticates the user via username & password // AuthenticateUser authenticates the user via username & password
func (a *AuthenticatorService) AuthenticateUser(ctx context.Context, query *models.LoginUserQuery) error { func (a *AuthenticatorService) AuthenticateUser(ctx context.Context, query *models.LoginUserQuery) error {
if err := validateLoginAttempts(ctx, query); err != nil { if err := validateLoginAttempts(ctx, query, a.store); err != nil {
return err return err
} }
@@ -75,7 +75,7 @@ func (a *AuthenticatorService) AuthenticateUser(ctx context.Context, query *mode
} }
if errors.Is(err, ErrInvalidCredentials) || errors.Is(err, ldap.ErrInvalidCredentials) { if errors.Is(err, ErrInvalidCredentials) || errors.Is(err, ldap.ErrInvalidCredentials) {
if err := saveInvalidLoginAttempt(ctx, query); err != nil { if err := saveInvalidLoginAttempt(ctx, query, a.store); err != nil {
loginLogger.Error("Failed to save invalid login attempt", "err", err) loginLogger.Error("Failed to save invalid login attempt", "err", err)
} }
+3 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana/pkg/services/ldap" "github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/login/logintest"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -196,14 +197,14 @@ func mockLoginUsingLDAP(enabled bool, err error, sc *authScenarioContext) {
} }
func mockLoginAttemptValidation(err error, sc *authScenarioContext) { func mockLoginAttemptValidation(err error, sc *authScenarioContext) {
validateLoginAttempts = func(context.Context, *models.LoginUserQuery) error { validateLoginAttempts = func(context.Context, *models.LoginUserQuery, sqlstore.Store) error {
sc.loginAttemptValidationWasCalled = true sc.loginAttemptValidationWasCalled = true
return err return err
} }
} }
func mockSaveInvalidLoginAttempt(sc *authScenarioContext) { func mockSaveInvalidLoginAttempt(sc *authScenarioContext) {
saveInvalidLoginAttempt = func(ctx context.Context, query *models.LoginUserQuery) error { saveInvalidLoginAttempt = func(ctx context.Context, query *models.LoginUserQuery, _ sqlstore.Store) error {
sc.saveInvalidLoginAttemptWasCalled = true sc.saveInvalidLoginAttemptWasCalled = true
return nil return nil
} }
+5 -5
View File
@@ -4,8 +4,8 @@ import (
"context" "context"
"time" "time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
) )
var ( var (
@@ -13,7 +13,7 @@ var (
loginAttemptsWindow = time.Minute * 5 loginAttemptsWindow = time.Minute * 5
) )
var validateLoginAttempts = func(ctx context.Context, query *models.LoginUserQuery) error { var validateLoginAttempts = func(ctx context.Context, query *models.LoginUserQuery, store sqlstore.Store) error {
if query.Cfg.DisableBruteForceLoginProtection { if query.Cfg.DisableBruteForceLoginProtection {
return nil return nil
} }
@@ -23,7 +23,7 @@ var validateLoginAttempts = func(ctx context.Context, query *models.LoginUserQue
Since: time.Now().Add(-loginAttemptsWindow), Since: time.Now().Add(-loginAttemptsWindow),
} }
if err := bus.Dispatch(ctx, &loginAttemptCountQuery); err != nil { if err := store.GetUserLoginAttemptCount(ctx, &loginAttemptCountQuery); err != nil {
return err return err
} }
@@ -34,7 +34,7 @@ var validateLoginAttempts = func(ctx context.Context, query *models.LoginUserQue
return nil return nil
} }
var saveInvalidLoginAttempt = func(ctx context.Context, query *models.LoginUserQuery) error { var saveInvalidLoginAttempt = func(ctx context.Context, query *models.LoginUserQuery, store sqlstore.Store) error {
if query.Cfg.DisableBruteForceLoginProtection { if query.Cfg.DisableBruteForceLoginProtection {
return nil return nil
} }
@@ -44,5 +44,5 @@ var saveInvalidLoginAttempt = func(ctx context.Context, query *models.LoginUserQ
IpAddress: query.IpAddress, IpAddress: query.IpAddress,
} }
return bus.Dispatch(ctx, &loginAttemptCommand) return store.CreateLoginAttempt(ctx, &loginAttemptCommand)
} }
+12 -33
View File
@@ -4,8 +4,8 @@ import (
"context" "context"
"testing" "testing"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -59,11 +59,12 @@ func TestValidateLoginAttempts(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
withLoginAttempts(t, tc.loginAttempts) store := mockstore.NewSQLStoreMock()
store.ExpectedLoginAttempts = tc.loginAttempts
query := &models.LoginUserQuery{Username: "user", Cfg: tc.cfg} query := &models.LoginUserQuery{Username: "user", Cfg: tc.cfg}
err := validateLoginAttempts(context.Background(), query) err := validateLoginAttempts(context.Background(), query, store)
require.Equal(t, tc.expected, err) require.Equal(t, tc.expected, err)
}) })
} }
@@ -71,45 +72,31 @@ func TestValidateLoginAttempts(t *testing.T) {
func TestSaveInvalidLoginAttempt(t *testing.T) { func TestSaveInvalidLoginAttempt(t *testing.T) {
t.Run("When brute force protection enabled", func(t *testing.T) { t.Run("When brute force protection enabled", func(t *testing.T) {
t.Cleanup(func() { bus.ClearBusHandlers() }) store := mockstore.NewSQLStoreMock()
createLoginAttemptCmd := &models.CreateLoginAttemptCommand{}
bus.AddHandler("test", func(ctx context.Context, cmd *models.CreateLoginAttemptCommand) error {
createLoginAttemptCmd = cmd
return nil
})
err := saveInvalidLoginAttempt(context.Background(), &models.LoginUserQuery{ err := saveInvalidLoginAttempt(context.Background(), &models.LoginUserQuery{
Username: "user", Username: "user",
Password: "pwd", Password: "pwd",
IpAddress: "192.168.1.1:56433", IpAddress: "192.168.1.1:56433",
Cfg: cfgWithBruteForceLoginProtectionEnabled(t), Cfg: cfgWithBruteForceLoginProtectionEnabled(t),
}) }, store)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, createLoginAttemptCmd) require.NotNil(t, store.LastLoginAttemptCommand)
assert.Equal(t, "user", createLoginAttemptCmd.Username) assert.Equal(t, "user", store.LastLoginAttemptCommand.Username)
assert.Equal(t, "192.168.1.1:56433", createLoginAttemptCmd.IpAddress) assert.Equal(t, "192.168.1.1:56433", store.LastLoginAttemptCommand.IpAddress)
}) })
t.Run("When brute force protection disabled", func(t *testing.T) { t.Run("When brute force protection disabled", func(t *testing.T) {
t.Cleanup(func() { bus.ClearBusHandlers() }) store := mockstore.NewSQLStoreMock()
var createLoginAttemptCmd *models.CreateLoginAttemptCommand
bus.AddHandler("test", func(ctx context.Context, cmd *models.CreateLoginAttemptCommand) error {
createLoginAttemptCmd = cmd
return nil
})
err := saveInvalidLoginAttempt(context.Background(), &models.LoginUserQuery{ err := saveInvalidLoginAttempt(context.Background(), &models.LoginUserQuery{
Username: "user", Username: "user",
Password: "pwd", Password: "pwd",
IpAddress: "192.168.1.1:56433", IpAddress: "192.168.1.1:56433",
Cfg: cfgWithBruteForceLoginProtectionDisabled(t), Cfg: cfgWithBruteForceLoginProtectionDisabled(t),
}) }, store)
require.NoError(t, err) require.NoError(t, err)
require.Nil(t, createLoginAttemptCmd) require.Nil(t, store.LastLoginAttemptCommand)
}) })
} }
@@ -126,11 +113,3 @@ func cfgWithBruteForceLoginProtectionEnabled(t *testing.T) *setting.Cfg {
require.False(t, cfg.DisableBruteForceLoginProtection) require.False(t, cfg.DisableBruteForceLoginProtection)
return cfg return cfg
} }
func withLoginAttempts(t *testing.T, loginAttempts int64) {
t.Helper()
bus.AddHandler("test", func(ctx context.Context, query *models.GetUserLoginAttemptCountQuery) error {
query.Result = loginAttempts
return nil
})
}
+12 -3
View File
@@ -12,8 +12,9 @@ type OrgListResponse []struct {
Response error Response error
} }
type SQLStoreMock struct { type SQLStoreMock struct {
LastGetAlertsQuery *models.GetAlertsQuery LastGetAlertsQuery *models.GetAlertsQuery
LatestUserId int64 LastLoginAttemptCommand *models.CreateLoginAttemptCommand
LatestUserId int64
ExpectedUser *models.User ExpectedUser *models.User
ExpectedDatasource *models.DataSource ExpectedDatasource *models.DataSource
@@ -40,7 +41,9 @@ type SQLStoreMock struct {
ExpectedPersistedDashboards models.HitList ExpectedPersistedDashboards models.HitList
ExpectedSignedInUser *models.SignedInUser ExpectedSignedInUser *models.SignedInUser
ExpectedUserStars map[int64]bool ExpectedUserStars map[int64]bool
ExpectedError error ExpectedLoginAttempts int64
ExpectedError error
} }
func NewSQLStoreMock() *SQLStoreMock { func NewSQLStoreMock() *SQLStoreMock {
@@ -130,6 +133,12 @@ func (m SQLStoreMock) DeleteOrphanedProvisionedDashboards(ctx context.Context, c
} }
func (m *SQLStoreMock) CreateLoginAttempt(ctx context.Context, cmd *models.CreateLoginAttemptCommand) error { func (m *SQLStoreMock) CreateLoginAttempt(ctx context.Context, cmd *models.CreateLoginAttemptCommand) error {
m.LastLoginAttemptCommand = cmd
return m.ExpectedError
}
func (m *SQLStoreMock) GetUserLoginAttemptCount(ctx context.Context, query *models.GetUserLoginAttemptCountQuery) error {
query.Result = m.ExpectedLoginAttempts
return m.ExpectedError return m.ExpectedError
} }
+1
View File
@@ -26,6 +26,7 @@ type Store interface {
GetOrgById(context.Context, *models.GetOrgByIdQuery) error GetOrgById(context.Context, *models.GetOrgByIdQuery) error
GetOrgByNameHandler(ctx context.Context, query *models.GetOrgByNameQuery) error GetOrgByNameHandler(ctx context.Context, query *models.GetOrgByNameQuery) error
CreateLoginAttempt(ctx context.Context, cmd *models.CreateLoginAttemptCommand) 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 DeleteOldLoginAttempts(ctx context.Context, cmd *models.DeleteOldLoginAttemptsCommand) error
CreateUser(ctx context.Context, cmd models.CreateUserCommand) (*models.User, error) CreateUser(ctx context.Context, cmd models.CreateUserCommand) (*models.User, error)
GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error