Skip to content

fix: block SSO logins and revoke sessions for spam accounts - #4767

Open
prayag78 wants to merge 6 commits into
fossasia:devfrom
prayag78:fix/mark-spam-sso-login
Open

fix: block SSO logins and revoke sessions for spam accounts#4767
prayag78 wants to merge 6 commits into
fossasia:devfrom
prayag78:fix/mark-spam-sso-login

Conversation

@prayag78

@prayag78 prayag78 commented Aug 6, 2026

Copy link
Copy Markdown
Member

Fixes #4591

This PR resolves an issue where users marked as spam in the admin panel (/admin/users/) could still log in using SSO providers (Google, GitHub, MediaWiki). It also prevents spam accounts from being bypassed via automatic social account linking and revokes active sessions when a user is flagged.

Changes Included

  • Standardized suspension error messaging across native credentials and SSO providers by centralizing SPAM_ACCOUNT_ERROR.
  • Added require_not_spam() check in CustomSocialAccountAdapter.pre_social_login to abort SSO authentication and prevent unlinked social accounts from auto-connecting to spam-flagged users.
  • Overrode pre_login() in CustomAccountAdapter to reject allauth login paths for spam-flagged accounts.
  • Updated UserListView to invoke update_session_token() when marking a user as spam, invalidating active session tokens across all devices immediately.
  • Ensured unmarking a user restores normal login access for both native and SSO authentication methods without requiring extra admin steps.
Video.Project.64.mp4

Summary by Sourcery

Block authentication and revoke sessions for users marked as spam across native and SSO login flows.

Bug Fixes:

  • Prevent spam-flagged users from logging in via SSO providers or native allauth login paths.
  • Stop automatic social account linking from attaching new SSO identities to spam accounts.

Enhancements:

  • Centralize the spam suspension error message to ensure consistent feedback across forms and adapters.
  • Revoke existing user sessions when an account is marked as spam to immediately invalidate access.

Copilot AI lite review requested due to automatic review settings August 6, 2026 09:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@sourcery-ai

sourcery-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Blocks logins for users flagged as spam across native and SSO auth flows by centralizing a spam suspension message, enforcing spam checks in both allauth account and social adapters, and revoking active sessions when a user is marked as spam in the admin UI.

Sequence diagram for native login rejection of spam accounts

sequenceDiagram
    actor User
    participant DjangoAuth as DjangoAuthBackend
    participant AccountAdapter as CustomAccountAdapter

    User->>DjangoAuth: authenticate
    DjangoAuth->>AccountAdapter: pre_login(request, user, email_verification, signal_kwargs, email, signup, redirect_url)
    alt user.is_spam
        AccountAdapter->>AccountAdapter: messages.error(request, SPAM_ACCOUNT_ERROR)
        AccountAdapter-->>User: HttpResponseRedirect(auth.login)
    else not user.is_spam
        AccountAdapter->>DjangoAuth: super().pre_login(...)
        DjangoAuth-->>User: login successful
    end
Loading

Sequence diagram for SSO login blocking of spam accounts

sequenceDiagram
    actor User
    participant SSOProvider
    participant SocialAuth as CustomSocialAccountAdapter
    participant AuthView as AuthLoginView

    User->>SSOProvider: initiate SSO login
    SSOProvider-->>SocialAuth: callback with sociallogin
    SocialAuth->>SocialAuth: pre_social_login(request, sociallogin)
    alt sociallogin.is_existing
        SocialAuth->>SocialAuth: sync_wikimedia_username(sociallogin.user, sociallogin)
    end
    SocialAuth->>SocialAuth: require_not_spam(request, sociallogin.user)
    alt user.is_spam
        SocialAuth->>SocialAuth: messages.error(request, SPAM_ACCOUNT_ERROR)
        SocialAuth-->>AuthView: ImmediateHttpResponse(HttpResponseRedirect(auth.login))
        AuthView-->>User: redirected to login with error
    else not spam
        SocialAuth-->>AuthView: proceed with normal SSO login
        AuthView-->>User: login successful
    end
Loading

Sequence diagram for revoking sessions when user is marked as spam

sequenceDiagram
    actor Admin
    participant UserListView
    participant TargetUser as user_to_update

    Admin->>UserListView: toggle spam in /admin/users/
    UserListView->>TargetUser: _handle_toggle_spam(request, target_user)
    UserListView->>TargetUser: is_spam = not is_spam
    UserListView->>TargetUser: save(update_fields=['is_spam'])
    alt TargetUser.is_spam
        UserListView->>TargetUser: update_session_token()
    end    
    UserListView-->>Admin: response with updated spam status
Loading

File-Level Changes

Change Details Files
Centralize and reuse a single spam-account suspension error message across auth layers.
  • Introduce SPAM_ACCOUNT_ERROR constant in the auth module with the canonical suspension message.
  • Update login and reauthentication forms to reference the shared SPAM_ACCOUNT_ERROR instead of hardcoded spam messages.
app/eventyay/base/auth.py
app/eventyay/base/forms/auth.py
Block native (allauth) login attempts for users marked as spam.
  • Extend CustomAccountAdapter.pre_login to check user.is_spam before allowing login.
  • When a spam user attempts login, add an error message and redirect back to the login page instead of proceeding with authentication.
app/eventyay/eventyay_common/adapter.py
Block SSO/social logins and auto-linking for users marked as spam.
  • Add require_not_spam helper that rejects social logins for spam-marked users, logging the attempt, flashing the standardized error, and short-circuiting with an ImmediateHttpResponse redirect to the login page.
  • Invoke require_not_spam at the end of pre_social_login so the spam check runs after provider-specific processing, such as Wikimedia username syncing.
app/eventyay/plugins/socialauth/adapter.py
Revoke active sessions when a user is marked as spam from the admin/control panel.
  • When toggling a user to spam in UserListView._handle_toggle_spam, call update_session_token on the affected user.
  • Ensure session revocation only happens when the user is being flagged (not unflagged), so normal access is restored when spam is removed.
app/eventyay/control/views/users.py

Assessment against linked issues

Issue Objective Addressed Explanation
#4591 Marking a user as spam blocks login for every login method (native and SSO).
#4591 A spam-marked user attempting an SSO login is sent back to the login page with the same suspension message the native login shows.
#4591 Unmarking a user restores normal login for all methods.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions github-actions Bot added backend Python/Django server-side code base Shared models, services, and core utilities common Cross-cutting helpers and eventyay_common UI fix Bug fix (fix/, fix-* branches) labels Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Thank you for contributing

Please complete the checklist. Screenshots in the PR description and completed AI reviews are checked automatically.

  • Show what changed — a screenshot or short screen recording of the updated functionality
  • Map structural updates — for architectural work, new directories, or file reorganization, include a diagram in the PR description (component, flow, or directory tree). Optional — only when your PR includes those kinds of changes
  • Request AI feedback — request or receive review from GitHub Copilot, Codex, or other automated reviewers you use

🤖 AI reviews

✅ Completed (1)

GitHub Copilot (@copilot-pull-request-reviewer[bot]) — GitHub Copilot PR reviewer

❌ 1 failed or rate-limited AI reviewer

GitHub Copilot (@copilot-pull-request-reviewer[bot])

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

ℹ️ Does not count toward the checklist

Sourcery AI (@sourcery-ai[bot]) — Sourcery AI code review bot

Feedback status: ✅ All AI review feedback is resolved.


📎 Attached media (1)

Screenshots and screen recordings

🎬 Screen recordings

Video.Project.64.mp4

Thank you for your contribution feel free to reach out if you have any questions.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The spam-check logic is now implemented separately in CustomAccountAdapter.pre_login and require_not_spam; consider extracting a shared helper (e.g., a ensure_not_spam(request, user) function) to avoid divergence in future changes.
  • In CustomAccountAdapter.pre_login, consider mirroring the social adapter behavior by raising ImmediateHttpResponse instead of returning an HttpResponseRedirect, to align with allauth’s expected short-circuit pattern and keep adapter behavior consistent.
  • When rejecting spam users in pre_login, you may want to add a warning log similar to require_not_spam so that spam-related login attempts are traceable across both native and SSO flows.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The spam-check logic is now implemented separately in `CustomAccountAdapter.pre_login` and `require_not_spam`; consider extracting a shared helper (e.g., a `ensure_not_spam(request, user)` function) to avoid divergence in future changes.
- In `CustomAccountAdapter.pre_login`, consider mirroring the social adapter behavior by raising `ImmediateHttpResponse` instead of returning an `HttpResponseRedirect`, to align with allauth’s expected short-circuit pattern and keep adapter behavior consistent.
- When rejecting spam users in `pre_login`, you may want to add a warning log similar to `require_not_spam` so that spam-related login attempts are traceable across both native and SSO flows.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@sarafarajnasardi sarafarajnasardi 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.

LGTM

@Rachit7168 Rachit7168 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please address sourcery comments

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Suppressed comments (4)

app/eventyay/eventyay_common/adapter.py:5

  • CustomAccountAdapter.pre_login() should raise ImmediateHttpResponse to abort allauth login, but ImmediateHttpResponse is not imported in this module.
from allauth.core import context

app/eventyay/plugins/socialauth/adapter.py:121

  • New spam-blocking behavior in pre_social_login() is not covered by tests. There are existing adapter tests in app/tests/tickets/plugins/test_socialauth.py, so this should add a case asserting spam-marked users trigger ImmediateHttpResponse and do not link/login via SSO.
        # Runs last so it also covers the wikimedia_username fallback above.
        require_not_spam(request, getattr(sociallogin, 'user', None))

app/eventyay/control/views/users.py:307

  • Marking a user as spam now revokes sessions by updating the session_token, but the existing toggle_spam tests only assert is_spam flips. Add a test asserting session_token changes when spam is set (and remains unchanged when unmarking).
            user_to_update.is_spam = not user_to_update.is_spam
            user_to_update.save(update_fields=['is_spam'])
            if user_to_update.is_spam:
                # Revoke active sessions upon flagging as spam.
                user_to_update.update_session_token()

app/eventyay/eventyay_common/adapter.py:50

  • New spam-blocking logic added in CustomAccountAdapter.pre_login() does not appear to have test coverage. There are existing adapter tests in app/tests/tickets/plugins/test_socialauth.py; add a test asserting spam-marked users are blocked via the allauth adapter path as well.
    def pre_login(
        self,
        request: HttpRequest,
        user,
        *,

Comment thread app/eventyay/eventyay_common/adapter.py Outdated

@Rachit7168 Rachit7168 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

simplescreenrecorder-2026-08-09_10.48.36.mp4

For Wikipedia as well , It should be blocked as well

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

Labels

backend Python/Django server-side code base Shared models, services, and core utilities common Cross-cutting helpers and eventyay_common UI fix Bug fix (fix/, fix-* branches) Priority: Low

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Mark as Spam only blocks native login, not SSO

6 participants