88 "math/big"
99 "net/http"
1010 "strings"
11- "sync"
1211 "time"
1312
1413 "github.com/steveiliop56/ding"
@@ -71,21 +70,11 @@ type AuthService struct {
7170
7271 dummyHash string
7372
74- lockdown struct {
75- active bool
76- until time.Time
77- ctx context.Context
78- cancelFunc context.CancelFunc
79- mu sync.RWMutex
80- }
81-
8273 caches struct {
8374 login * CacheStore [LoginAttempt ]
8475 oauth * CacheStore [OAuthPendingSession ]
8576 ldap * CacheStore [[]string ]
8677 }
87-
88- maxLoginLimits int
8978}
9079
9180type AuthServiceInput struct {
@@ -116,15 +105,6 @@ func NewAuthService(i AuthServiceInput) (*AuthService, error) {
116105 policyEngine : i .PolicyEngine ,
117106 }
118107
119- // get the max login limits based on the number of users and the configured max retries
120- service .maxLoginLimits = service .calculateLockdownLimit ()
121-
122- loginCacheSize := 0
123-
124- if ! service .config .Auth .LockdownEnabled {
125- loginCacheSize = service .maxLoginLimits
126- }
127-
128108 // dummy hash
129109 dummyHash , err := bcrypt .GenerateFromPassword ([]byte (utils .GenerateString (8 )), bcrypt .DefaultCost )
130110
@@ -136,7 +116,7 @@ func NewAuthService(i AuthServiceInput) (*AuthService, error) {
136116
137117 // caches setup
138118 oauthCache := NewCacheStore [OAuthPendingSession ](256 )
139- loginCache := NewCacheStore [LoginAttempt ](loginCacheSize )
119+ loginCache := NewCacheStore [LoginAttempt ](service . calculateLockdownLimit () )
140120 ldapCache := NewCacheStore [[]string ](1024 )
141121
142122 service .caches .oauth = oauthCache
@@ -159,6 +139,23 @@ func NewAuthService(i AuthServiceInput) (*AuthService, error) {
159139 }
160140 }, ding .RingMinor )
161141
142+ i .Ding .Go (func (ctx context.Context ) {
143+ ticker := time .NewTicker (15 * time .Minute )
144+ defer ticker .Stop ()
145+
146+ for {
147+ select {
148+ case <- ticker .C :
149+ service .log .App .Debug ().Msg ("Updating login cache limits" )
150+ service .caches .login .SetMaxSize (service .calculateLockdownLimit ())
151+ service .log .App .Debug ().Msg ("Login cache limits updated" )
152+ case <- ctx .Done ():
153+ return
154+ }
155+ }
156+
157+ }, ding .RingMinor )
158+
162159 return service , nil
163160}
164161
@@ -260,10 +257,6 @@ func (auth *AuthService) GetLDAPUser(userDN string) (*model.LDAPUser, error) {
260257}
261258
262259func (auth * AuthService ) IsAccountLocked (identifier string ) (bool , int ) {
263- if locked , remaining := auth .IsInLockdown (); locked {
264- return true , remaining
265- }
266-
267260 if auth .config .Auth .LoginMaxRetries <= 0 || auth .config .Auth .LoginTimeout <= 0 {
268261 return false , 0
269262 }
@@ -286,14 +279,6 @@ func (auth *AuthService) RecordLoginAttempt(identifier string, success bool) {
286279 return
287280 }
288281
289- if ! success && auth .config .Auth .LockdownEnabled && auth .caches .login .Size () >= auth .maxLoginLimits {
290- if locked , _ := auth .IsInLockdown (); locked {
291- return
292- }
293- go auth .lockdownMode ()
294- return
295- }
296-
297282 auth .caches .login .WithLock (func (actions CacheStoreActions [LoginAttempt ]) {
298283 entry , ok := actions .Get (identifier )
299284
@@ -359,7 +344,7 @@ func (auth *AuthService) CreateSession(ctx context.Context, data repository.Sess
359344 return nil , fmt .Errorf ("tailscale service not configured, cannot create session for tailscale user" )
360345 }
361346
362- uuid , err := uuid .NewRandom ()
347+ u , err := uuid .NewRandom ()
363348
364349 if err != nil {
365350 return nil , fmt .Errorf ("failed to generate session uuid: %w" , err )
@@ -376,7 +361,7 @@ func (auth *AuthService) CreateSession(ctx context.Context, data repository.Sess
376361 expiresAt := time .Now ().Add (time .Duration (expiry ) * time .Second )
377362
378363 session := repository.CreateSessionParams {
379- UUID : uuid .String (),
364+ UUID : u .String (),
380365 Username : data .Username ,
381366 Email : data .Email ,
382367 Name : data .Name ,
@@ -631,62 +616,7 @@ func (auth *AuthService) GetOAuthPendingSession(sessionId string) (*OAuthPending
631616 return & session , nil
632617}
633618
634- func (auth * AuthService ) lockdownMode () {
635- auth .lockdown .mu .Lock ()
636-
637- if auth .lockdown .active {
638- auth .lockdown .mu .Unlock ()
639- return
640- }
641-
642- ctx , cancel := context .WithCancel (auth .ctx )
643-
644- auth .log .App .Warn ().Msg ("Too many failed login attempts, entering lockdown mode" )
645-
646- auth .lockdown .active = true
647- auth .lockdown .ctx = ctx
648- auth .lockdown .cancelFunc = cancel
649-
650- d := time .Duration (auth .config .Auth .LoginTimeout ) * time .Second
651- auth .lockdown .until = time .Now ().Add (d )
652- timer := time .NewTimer (d )
653-
654- auth .lockdown .mu .Unlock ()
655-
656- defer cancel ()
657- defer timer .Stop ()
658-
659- select {
660- case <- timer .C :
661- // Timer expired, end lockdown
662- case <- ctx .Done ():
663- // Context cancelled, end lockdown
664- }
665-
666- auth .lockdown .mu .Lock ()
667-
668- auth .log .App .Info ().Msg ("Exiting lockdown mode" )
669-
670- auth .caches .login .Clear ()
671- auth .lockdown .active = false
672- auth .lockdown .until = time.Time {}
673- auth .lockdown .ctx = nil
674- auth .lockdown .cancelFunc = nil
675-
676- auth .lockdown .mu .Unlock ()
677- }
678-
679- func (auth * AuthService ) IsInLockdown () (bool , int ) {
680- auth .lockdown .mu .RLock ()
681- defer auth .lockdown .mu .RUnlock ()
682- if auth .lockdown .active {
683- remaining := int (time .Until (auth .lockdown .until ).Seconds ())
684- return true , remaining
685- }
686- return false , 0
687- }
688-
689- // mostly a testing function, not useful for anything else
619+ // ClearLoginAttempts is a testing function, not useful for anything else
690620func (auth * AuthService ) ClearLoginAttempts () {
691621 auth .caches .login .Clear ()
692622}
0 commit comments