Skip to content

policies/reputation: reset negative score to 0 on successful login - #25571

Open
manantlerio wants to merge 2 commits into
goauthentik:mainfrom
manantlerio:policies/reputation-reset-on-login
Open

policies/reputation: reset negative score to 0 on successful login#25571
manantlerio wants to merge 2 commits into
goauthentik:mainfrom
manantlerio:policies/reputation-reset-on-login

Conversation

@manantlerio

@manantlerio manantlerio commented Aug 29, 2026

Copy link
Copy Markdown

Details

What does this PR change?

On a successful login, the reputation entry for the matching (identifier, IP) pair is now updated as follows, instead of being unconditionally incremented by 1:

  • a negative score is reset to 0
  • any other score is raised by 1

Both branches are a single CASE expression inside the existing INSERT ... ON CONFLICT DO UPDATE, so it stays one statement and there is no read-then-write race between concurrent logins.

  • Only the exact (identifier, IP) pair is touched. Other usernames behind the same IP, and the same username from other IPs, are unaffected.
  • A login with no existing entry still creates one at 1, matching the previous behaviour.
  • The tenant's reputation_lower_limit / reputation_upper_limit clamping is unchanged.
  • Expired entries are not touched, and expiry is not refreshed on update, both consistent with update_score.

No model, migration, API or settings change, so nothing needs configuring on upgrade.

Why is this change needed?

Per the discussion on #20175: unconditionally incrementing means an attacker who shares an IP with a legitimate user earns extra retries per successful login. @gergosimonyi asked whether this should just be the new default rather than another flag, and @dewi-tik confirmed after speaking with @BeryJu that changing the default is preferred over adding a tenant setting.

The behaviour implemented here is the one confirmed in #20148 (comment), corrected per @gergosimonyi's review on this PR to keep the increment for non-negative scores.

How was this tested?

Eight tests in authentik/policies/reputation/tests.py covering both branches and the surrounding semantics: negative resets to 0, zero increments to 1, positive increments by 1, no existing entry creates one at 1, the upper limit still bounds the increment, another identifier on the same IP is unaffected, the same identifier on another IP is unaffected, and a failed-then-successful login ends at 0.

ruff check and ruff format are clean. I do not have PostgreSQL/Redis available locally, so I have not run the Django suite myself - the previous revision passed test-unittest in CI, and I am relying on CI again for this revision.

Linked issues

Closes #20148


AI usage disclosure

Per AI_POLICY.md: I used Claude Code to navigate the codebase, draft this change, and draft this description. I reviewed and edited all of it, and I understand and take responsibility for what is submitted here. Happy to answer review questions directly.


Checklist

  • The project has been linted, built, and tested (make all) - ruff clean locally; I cannot run the Django suite on this machine, so I am relying on CI
  • The documentation has been updated and formatted (make docs)
  • I have read the AI usage policy.
@manantlerio
manantlerio requested review from a team as code owners August 29, 2026 05:34
@netlify

netlify Bot commented Aug 29, 2026

Copy link
Copy Markdown

Deploy Preview for authentik-integrations ready!

Name Link
🔨 Latest commit b763202
🔍 Latest deploy log https://app.netlify.com/projects/authentik-integrations/deploys/6a95a1af9f13b6000893c3a9
😎 Deploy Preview https://deploy-preview-25571--authentik-integrations.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 29, 2026

Copy link
Copy Markdown

Deploy Preview for authentik-docs ready!

Name Link
🔨 Latest commit b763202
🔍 Latest deploy log https://app.netlify.com/projects/authentik-docs/deploys/6a95a1afd382db00080e3b36
😎 Deploy Preview https://deploy-preview-25571--authentik-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

A successful login now resets a negative reputation score back to 0 for
the matching (identifier, IP) pair, instead of incrementing it by 1.
Scores of 0 or above are left untouched, and no entry is created if none
exists yet.

refs goauthentik#20148

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@manantlerio
manantlerio force-pushed the policies/reputation-reset-on-login branch from 3b3eeda to 61f2224 Compare August 29, 2026 05:37
@dominic-r
dominic-r self-requested a review August 29, 2026 13:55
@rissson
rissson requested a review from gergosimonyi August 31, 2026 13:28
@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.66%. Comparing base (5408431) to head (b763202).
⚠️ Report is 17 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #25571      +/-   ##
==========================================
- Coverage   91.69%   91.66%   -0.04%     
==========================================
  Files        1152     1152              
  Lines       73503    73548      +45     
  Branches     4054     4054              
==========================================
+ Hits        67402    67419      +17     
- Misses       6059     6087      +28     
  Partials       42       42              
Flag Coverage Δ
conformance 34.33% <19.14%> (-0.04%) ⬇️
e2e 39.02% <19.14%> (-0.03%) ⬇️
integration 30.52% <4.25%> (-0.45%) ⬇️
rust 42.92% <ø> (ø)
unit 93.25% <100.00%> (+0.01%) ⬆️
unit-migrate 93.27% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@gergosimonyi gergosimonyi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look quite right. The intention is for a successful login to (with a single SQL query)

  • reset the reputation to 0 if it was negative
  • increase the reputation by 1 if it was non-negative

The second part is removed here.

Addresses review feedback: a successful login now resets a negative score
to 0 and raises any other score by 1, both in the same statement via a
conditional CASE expression on the existing upsert. A login with no
existing entry still creates one at 1, matching the previous behaviour.

refs goauthentik#20148

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@manantlerio

Copy link
Copy Markdown
Author

Good catch - I dropped the increment instead of making it conditional. Fixed in b763202: both branches now in one statement (CASE WHEN score < 0 THEN 0 ELSE score + 1) inside the existing ON CONFLICT DO UPDATE. Also restored the missing-row case (old update_score(..., 1) created a row at 1; my first pass created none).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants