@@ -69,7 +69,7 @@ const (
69
69
// Maximum length of username, too keep the cache's memory signature low
70
70
maxUsernameLength = 32
71
71
// The default maximum session cache size
72
- defaultMaxCacheSize = 1000
72
+ defaultMaxCacheSize = 10000
73
73
// The default number of maximum login failures before delay kicks in
74
74
defaultMaxLoginFailures = 5
75
75
// The default time in seconds for the failure window
@@ -310,6 +310,22 @@ func expireOldFailedAttempts(maxAge time.Duration, failures *map[string]LoginAtt
310
310
return expiredCount
311
311
}
312
312
313
+ // Protect admin user from login attempt reset caused by attempts to overflow cache in a brute force attack. Instead remove random non-admin to make room in cache.
314
+ func pickRandomNonAdminLoginFailure (failures map [string ]LoginAttempts , username string ) * string {
315
+ idx := rand .Intn (len (failures ) - 1 )
316
+ i := 0
317
+ for key := range failures {
318
+ if i == idx {
319
+ if key == common .ArgoCDAdminUsername || key == username {
320
+ return pickRandomNonAdminLoginFailure (failures , username )
321
+ }
322
+ return & key
323
+ }
324
+ i ++
325
+ }
326
+ return nil
327
+ }
328
+
313
329
// Updates the failure count for a given username. If failed is true, increases the counter. Otherwise, sets counter back to 0.
314
330
func (mgr * SessionManager ) updateFailureCount (username string , failed bool ) {
315
331
@@ -327,23 +343,13 @@ func (mgr *SessionManager) updateFailureCount(username string, failed bool) {
327
343
// prevent overbloating the cache with fake entries, as this could lead to
328
344
// memory exhaustion and ultimately in a DoS. We remove a single entry to
329
345
// replace it with the new one.
330
- //
331
- // Chances are that we remove the one that is under active attack, but this
332
- // chance is low (1:cache_size)
333
346
if failed && len (failures ) >= getMaximumCacheSize () {
334
347
log .Warnf ("Session cache size exceeds %d entries, removing random entry" , getMaximumCacheSize ())
335
- idx := rand .Intn (len (failures ) - 1 )
336
- var rmUser string
337
- i := 0
338
- for key := range failures {
339
- if i == idx {
340
- rmUser = key
341
- delete (failures , key )
342
- break
343
- }
344
- i ++
348
+ rmUser := pickRandomNonAdminLoginFailure (failures , username )
349
+ if rmUser != nil {
350
+ delete (failures , * rmUser )
351
+ log .Infof ("Deleted entry for user %s from cache" , * rmUser )
345
352
}
346
- log .Infof ("Deleted entry for user %s from cache" , rmUser )
347
353
}
348
354
349
355
attempt , ok := failures [username ]
0 commit comments