Feat: Progressive/tiered lockouts based on failure count#1402
Feat: Progressive/tiered lockouts based on failure count#1402rodrigobnogueira wants to merge 6 commits intojazzband:masterfrom
Conversation
…s based on failure count.
5695188 to
7eef2f1
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1402 +/- ##
==========================================
+ Coverage 91.56% 91.90% +0.34%
==========================================
Files 37 37
Lines 1268 1322 +54
Branches 172 183 +11
==========================================
+ Hits 1161 1215 +54
Misses 83 83
Partials 24 24 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Hey, looks good, thanks, but this is a handful to review and a brand-new feature at that. I'll try to set some time aside later on for checking this out. |
|
Idea looks good to me, but what if instead of tiers we use exponential? For example, after 3 failures coloff time will be multiplied by some value? |
aleksihakli
left a comment
There was a problem hiding this comment.
Looks good @rodrigobnogueira! Would it be possible to rename the functions with underscore prefixes? I'll merge this afterwards.
| return matched | ||
|
|
||
|
|
||
| def _resolve_tier_from_request( |
There was a problem hiding this comment.
Hey, I think we don't need to prefix things with underscore here since that has only been done for the built-ins such as __init__. It's a valid approach but since it would introduce another habit into the codebase I'd keep it simple and just use one plain naming convention for all functions.
There was a problem hiding this comment.
Yes, absolutely agreed on keeping one naming convention.
I’ve updated the new helpers to use plain names (no leading underscore) and adjusted call sites accordingly.
Please let me know if you’d like any further tweaks.
Thanks for the feedback! That gives admins full control over the curve (exponential, linear, custom steps, whatever fits their threat model) without needing a new setting. If you'd prefer a built-in exponential formula (e.g. base_cooloff * multiplier ** failures with a configurable multiplier), I'm happy to add it as an optional alternative. But I think the current tiers already cover the use case very well. What specific exponential behaviour did you have in mind? We can adjust the example in the docs or add a helper if that would make it clearer. Example: from datetime import timedelta
from axes.conf import LockoutTier
AXES_LOCKOUT_TIERS = [
LockoutTier(failures=3, cooloff=timedelta(minutes=5)), # base
LockoutTier(failures=4, cooloff=timedelta(minutes=10)), # ×2
LockoutTier(failures=5, cooloff=timedelta(minutes=20)), # ×2
LockoutTier(failures=6, cooloff=timedelta(minutes=40)), # ×2
# ... keep going or cap it
] |
|
I pushed a small CI hardening update for Codecov upload reliability. The failure we hit (
Now CI is passing. Let me know if you want I rollback this change. |
What does this PR do?
This PR introduces the ability to configure progressive (tiered) lockouts in django-axes. Instead of a single fixed cool-off time, the system now supports escalating lockout durations based on the number of failed attempts.
Changes
LockoutTierdataclass and theAXES_LOCKOUT_TIERSsetting to configure the tiers inaxes.conf.get_cool_off,get_failure_limit,get_lockout_message,get_lockout_response) inaxes.helpersto resolve and apply the appropriate tier based on a request'saxes_failures_since_startcount.axes.checksto warn users ifAXES_LOCKOUT_TIERSis misconfigured or used alongsideAXES_COOLOFF_TIME.AXES_LOCKOUT_TIERStodocs/4_configuration.rst.How it works
Users can configure
AXES_LOCKOUT_TIERSas a list ofLockoutTierinstances. For example:When
AXES_LOCKOUT_TIERSis defined, it overrides bothAXES_FAILURE_LIMIT(which becomes the threshold of the lowest tier) andAXES_COOLOFF_TIME. Lockouts are subsequently applied dynamically according to the rules defined in the tiers.All existing behavior remains completely unchanged if
AXES_LOCKOUT_TIERSis not set.Before submitting