mirror of
https://github.com/gravitational/teleport
synced 2024-10-23 02:32:39 +00:00
Improvements to "max login attempts" feature
- increasing login attempt is now atomic within a process - renamed some functions to be less confusing
This commit is contained in:
parent
9f9c586989
commit
0720fbc8c2
|
@ -19,6 +19,7 @@ package local
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
@ -35,6 +36,7 @@ import (
|
|||
// IdentityService is responsible for managing web users and currently
|
||||
// user accounts as well
|
||||
type IdentityService struct {
|
||||
sync.Mutex
|
||||
backend backend.Backend
|
||||
lockAfter byte
|
||||
lockDuration time.Duration
|
||||
|
@ -209,9 +211,12 @@ func (s *IdentityService) UpsertWebSession(user, sid string, session services.We
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// LockUser bumps "login attempt" counter for the given user. If the counter
|
||||
// IncreaseLoginAttempts bumps "login attempt" counter for the given user. If the counter
|
||||
// reaches 'lockAfter' value, it locks the account and returns access denied error.
|
||||
func (s *IdentityService) LockUser(user string) error {
|
||||
func (s *IdentityService) IncreaseLoginAttempts(user string) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
bucket := []string{"web", "users", user}
|
||||
data, _, err := s.backend.GetValAndTTL(bucket, "lock")
|
||||
// unexpected error?
|
||||
|
@ -227,12 +232,11 @@ func (s *IdentityService) LockUser(user string) error {
|
|||
if len(data) > 0 && data[0] > s.lockAfter {
|
||||
return trace.AccessDenied("this account has been locked for %v", s.lockDuration)
|
||||
}
|
||||
return trace.Wrap(
|
||||
s.backend.UpsertVal(bucket, "lock", data, s.lockDuration))
|
||||
return s.backend.UpsertVal(bucket, "lock", data, s.lockDuration)
|
||||
}
|
||||
|
||||
// UnlockUser resets the "login attempt" counter to zero.
|
||||
func (s *IdentityService) UnlockUser(user string) error {
|
||||
// ResetLoginAttempts resets the "login attempt" counter to zero.
|
||||
func (s *IdentityService) ResetLoginAttempts(user string) error {
|
||||
err := s.backend.DeleteKey([]string{"web", "users", user}, "lock")
|
||||
if trace.IsNotFound(err) {
|
||||
return nil
|
||||
|
@ -312,7 +316,7 @@ func (s *IdentityService) CheckPassword(user string, password []byte, hotpToken
|
|||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if err = s.LockUser(user); err != nil {
|
||||
if err = s.IncreaseLoginAttempts(user); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword(hash, password); err != nil {
|
||||
|
@ -325,7 +329,7 @@ func (s *IdentityService) CheckPassword(user string, password []byte, hotpToken
|
|||
if !otp.Scan(hotpToken, defaults.HOTPFirstTokensRange) {
|
||||
return trace.AccessDenied("bad one time token")
|
||||
}
|
||||
defer s.UnlockUser(user)
|
||||
defer s.ResetLoginAttempts(user)
|
||||
if err := s.UpsertHOTP(user, otp); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
@ -342,13 +346,13 @@ func (s *IdentityService) CheckPasswordWOToken(user string, password []byte) err
|
|||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if err = s.LockUser(user); err != nil {
|
||||
if err = s.IncreaseLoginAttempts(user); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword(hash, password); err != nil {
|
||||
return trace.BadParameter("passwords do not match")
|
||||
}
|
||||
defer s.UnlockUser(user)
|
||||
defer s.ResetLoginAttempts(user)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue