diff --git a/pkg/login/brute_force_login_protection_test.go b/pkg/login/brute_force_login_protection_test.go index e9106a3e439..f8d9cfb2fdf 100644 --- a/pkg/login/brute_force_login_protection_test.go +++ b/pkg/login/brute_force_login_protection_test.go @@ -6,132 +6,127 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" - . "github.com/smartystreets/goconvey/convey" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -func TestLoginAttemptsValidation(t *testing.T) { - Convey("Validate login attempts", t, func() { - Convey("Given brute force login protection enabled", func() { - cfg := setting.NewCfg() - cfg.DisableBruteForceLoginProtection = false - query := &models.LoginUserQuery{ - Username: "user", - Cfg: cfg, - } - - Convey("When user login attempt count equals max-1 ", func() { - withLoginAttempts(maxInvalidLoginAttempts - 1) - err := validateLoginAttempts(query) - - Convey("it should not result in error", func() { - So(err, ShouldBeNil) - }) - }) - - Convey("When user login attempt count equals max ", func() { - withLoginAttempts(maxInvalidLoginAttempts) - err := validateLoginAttempts(query) - - Convey("it should result in too many login attempts error", func() { - So(err, ShouldEqual, ErrTooManyLoginAttempts) - }) - }) - - Convey("When user login attempt count is greater than max ", func() { - withLoginAttempts(maxInvalidLoginAttempts + 5) - err := validateLoginAttempts(query) - - Convey("it should result in too many login attempts error", func() { - So(err, ShouldEqual, ErrTooManyLoginAttempts) - }) - }) - - Convey("When saving invalid login attempt", func() { - defer bus.ClearBusHandlers() - createLoginAttemptCmd := &models.CreateLoginAttemptCommand{} - - bus.AddHandler("test", func(cmd *models.CreateLoginAttemptCommand) error { - createLoginAttemptCmd = cmd - return nil - }) - - err := saveInvalidLoginAttempt(&models.LoginUserQuery{ - Username: "user", - Password: "pwd", - IpAddress: "192.168.1.1:56433", - Cfg: setting.NewCfg(), - }) - So(err, ShouldBeNil) - - Convey("it should dispatch command", func() { - So(createLoginAttemptCmd, ShouldNotBeNil) - So(createLoginAttemptCmd.Username, ShouldEqual, "user") - So(createLoginAttemptCmd.IpAddress, ShouldEqual, "192.168.1.1:56433") - }) - }) +func TestValidateLoginAttempts(t *testing.T) { + testCases := []struct { + name string + loginAttempts int64 + cfg *setting.Cfg + expected error + }{ + { + name: "When brute force protection enabled and user login attempt count is less than max", + loginAttempts: maxInvalidLoginAttempts - 1, + cfg: cfgWithBruteForceLoginProtectionEnabled(t), + expected: nil, + }, + { + name: "When brute force protection enabled and user login attempt count equals max", + loginAttempts: maxInvalidLoginAttempts, + cfg: cfgWithBruteForceLoginProtectionEnabled(t), + expected: ErrTooManyLoginAttempts, + }, + { + name: "When brute force protection enabled and user login attempt count is greater than max", + loginAttempts: maxInvalidLoginAttempts + 1, + cfg: cfgWithBruteForceLoginProtectionEnabled(t), + expected: ErrTooManyLoginAttempts, + }, + + { + name: "When brute force protection disabled and user login attempt count is less than max", + loginAttempts: maxInvalidLoginAttempts - 1, + cfg: cfgWithBruteForceLoginProtectionDisabled(t), + expected: nil, + }, + { + name: "When brute force protection disabled and user login attempt count equals max", + loginAttempts: maxInvalidLoginAttempts, + cfg: cfgWithBruteForceLoginProtectionDisabled(t), + expected: nil, + }, + { + name: "When brute force protection disabled and user login attempt count is greater than max", + loginAttempts: maxInvalidLoginAttempts + 1, + cfg: cfgWithBruteForceLoginProtectionDisabled(t), + expected: nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + withLoginAttempts(t, tc.loginAttempts) + + query := &models.LoginUserQuery{Username: "user", Cfg: tc.cfg} + err := validateLoginAttempts(query) + require.Equal(t, tc.expected, err) }) + } +} + +func TestSaveInvalidLoginAttempt(t *testing.T) { + t.Run("When brute force protection enabled", func(t *testing.T) { + t.Cleanup(func() { bus.ClearBusHandlers() }) + + createLoginAttemptCmd := &models.CreateLoginAttemptCommand{} + bus.AddHandler("test", func(cmd *models.CreateLoginAttemptCommand) error { + createLoginAttemptCmd = cmd + return nil + }) + + err := saveInvalidLoginAttempt(&models.LoginUserQuery{ + Username: "user", + Password: "pwd", + IpAddress: "192.168.1.1:56433", + Cfg: cfgWithBruteForceLoginProtectionEnabled(t), + }) + require.NoError(t, err) + + require.NotNil(t, createLoginAttemptCmd) + assert.Equal(t, "user", createLoginAttemptCmd.Username) + assert.Equal(t, "192.168.1.1:56433", createLoginAttemptCmd.IpAddress) + }) - Convey("Given brute force login protection disabled", func() { - cfg := setting.NewCfg() - cfg.DisableBruteForceLoginProtection = true - query := &models.LoginUserQuery{ - Username: "user", - Cfg: cfg, - } - - Convey("When user login attempt count equals max-1 ", func() { - withLoginAttempts(maxInvalidLoginAttempts - 1) - err := validateLoginAttempts(query) - - Convey("it should not result in error", func() { - So(err, ShouldBeNil) - }) - }) - - Convey("When user login attempt count equals max ", func() { - withLoginAttempts(maxInvalidLoginAttempts) - err := validateLoginAttempts(query) - - Convey("it should not result in error", func() { - So(err, ShouldBeNil) - }) - }) - - Convey("When user login attempt count is greater than max ", func() { - withLoginAttempts(maxInvalidLoginAttempts + 5) - err := validateLoginAttempts(query) - - Convey("it should not result in error", func() { - So(err, ShouldBeNil) - }) - }) - - Convey("When saving invalid login attempt", func() { - defer bus.ClearBusHandlers() - var createLoginAttemptCmd *models.CreateLoginAttemptCommand - - bus.AddHandler("test", func(cmd *models.CreateLoginAttemptCommand) error { - createLoginAttemptCmd = cmd - return nil - }) - - err := saveInvalidLoginAttempt(&models.LoginUserQuery{ - Username: "user", - Password: "pwd", - IpAddress: "192.168.1.1:56433", - Cfg: cfg, - }) - So(err, ShouldBeNil) - - Convey("it should not dispatch command", func() { - So(createLoginAttemptCmd, ShouldBeNil) - }) - }) + t.Run("When brute force protection disabled", func(t *testing.T) { + t.Cleanup(func() { bus.ClearBusHandlers() }) + + var createLoginAttemptCmd *models.CreateLoginAttemptCommand + bus.AddHandler("test", func(cmd *models.CreateLoginAttemptCommand) error { + createLoginAttemptCmd = cmd + return nil + }) + + err := saveInvalidLoginAttempt(&models.LoginUserQuery{ + Username: "user", + Password: "pwd", + IpAddress: "192.168.1.1:56433", + Cfg: cfgWithBruteForceLoginProtectionDisabled(t), }) + require.NoError(t, err) + + require.Nil(t, createLoginAttemptCmd) }) } -func withLoginAttempts(loginAttempts int64) { +func cfgWithBruteForceLoginProtectionDisabled(t *testing.T) *setting.Cfg { + t.Helper() + cfg := setting.NewCfg() + cfg.DisableBruteForceLoginProtection = true + return cfg +} + +func cfgWithBruteForceLoginProtectionEnabled(t *testing.T) *setting.Cfg { + t.Helper() + cfg := setting.NewCfg() + require.False(t, cfg.DisableBruteForceLoginProtection) + return cfg +} + +func withLoginAttempts(t *testing.T, loginAttempts int64) { + t.Helper() bus.AddHandler("test", func(query *models.GetUserLoginAttemptCountQuery) error { query.Result = loginAttempts return nil