From cd98aaf89b38793d07f6866fb6256cd5322fea0f Mon Sep 17 00:00:00 2001 From: linoman <2051016+linoman@users.noreply.github.com> Date: Fri, 10 May 2024 13:49:59 +0200 Subject: [PATCH] Chore: Add login protection when user is trying different uppercase letters (#87588) * add login protection when the user is trying different uppercase letters --- .../loginattemptimpl/login_attempt.go | 7 ++--- .../loginattemptimpl/login_attempt_test.go | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/pkg/services/loginattempt/loginattemptimpl/login_attempt.go b/pkg/services/loginattempt/loginattemptimpl/login_attempt.go index 6686fb3645a..611d83b0d5f 100644 --- a/pkg/services/loginattempt/loginattemptimpl/login_attempt.go +++ b/pkg/services/loginattempt/loginattemptimpl/login_attempt.go @@ -2,6 +2,7 @@ package loginattemptimpl import ( "context" + "strings" "time" "github.com/grafana/grafana/pkg/infra/db" @@ -54,14 +55,14 @@ func (s *Service) Add(ctx context.Context, username, IPAddress string) error { } _, err := s.store.CreateLoginAttempt(ctx, CreateLoginAttemptCommand{ - Username: username, + Username: strings.ToLower(username), IpAddress: IPAddress, }) return err } func (s *Service) Reset(ctx context.Context, username string) error { - return s.store.DeleteLoginAttempts(ctx, DeleteLoginAttemptsCommand{username}) + return s.store.DeleteLoginAttempts(ctx, DeleteLoginAttemptsCommand{strings.ToLower(username)}) } func (s *Service) Validate(ctx context.Context, username string) (bool, error) { @@ -70,7 +71,7 @@ func (s *Service) Validate(ctx context.Context, username string) (bool, error) { } loginAttemptCountQuery := GetUserLoginAttemptCountQuery{ - Username: username, + Username: strings.ToLower(username), Since: time.Now().Add(-loginAttemptsWindow), } diff --git a/pkg/services/loginattempt/loginattemptimpl/login_attempt_test.go b/pkg/services/loginattempt/loginattemptimpl/login_attempt_test.go index 8ec85223c10..13b1bc2706f 100644 --- a/pkg/services/loginattempt/loginattemptimpl/login_attempt_test.go +++ b/pkg/services/loginattempt/loginattemptimpl/login_attempt_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/loginattempt" "github.com/grafana/grafana/pkg/setting" ) @@ -79,6 +80,31 @@ func TestService_Validate(t *testing.T) { } } +func TestLoginAttempts(t *testing.T) { + ctx := context.Background() + cfg := setting.NewCfg() + cfg.DisableBruteForceLoginProtection = false + db := db.InitTestDB(t) + service := ProvideService(db, cfg, nil) + + // add multiple login attempts with different uppercases, they all should be counted as the same user + _ = service.Add(ctx, "admin", "[::1]") + _ = service.Add(ctx, "Admin", "[::1]") + _ = service.Add(ctx, "aDmin", "[::1]") + _ = service.Add(ctx, "adMin", "[::1]") + _ = service.Add(ctx, "admIn", "[::1]") + _ = service.Add(ctx, "admIN", "[::1]") + + // validate the number of attempts is correct for all the different uppercases + count, err := service.store.GetUserLoginAttemptCount(ctx, GetUserLoginAttemptCountQuery{Username: "admin"}) + assert.Nil(t, err) + assert.Equal(t, int64(6), count) + + ok, err := service.Validate(ctx, "admin") + assert.False(t, ok) + assert.Nil(t, err) +} + var _ store = new(fakeStore) type fakeStore struct {