Skip to content

feat: update security and settings documentation for MFA step-up requ… - #91

Merged
ashwin31 merged 1 commit into
masterfrom
dev
Aug 14, 2026
Merged

feat: update security and settings documentation for MFA step-up requ…#91
ashwin31 merged 1 commit into
masterfrom
dev

Conversation

@ashwin31

Copy link
Copy Markdown
Member

…irements

  • Enhanced security documentation to clarify compromised session handling and step-up re-authentication requirements.
  • Updated settings documentation to include MFA_STEPUP_MAX_AGE and its interaction with MFA_REMEMBER_MY_BROWSER.
  • Added detailed explanation of MFA_STEPUP_MAX_AGE functionality and its implications for factor changes.

chore: upgrade version to 4.2.0 and update dependencies

  • Bumped version from 4.1.0 to 4.2.0 in pyproject.toml and uv.lock.
  • Updated development dependencies to include django-otp and django-mfa2.
  • Ensured compatibility with Django 5.2 and added necessary test configurations.

fix: enforce recent challenge for factor changes

  • Implemented a mechanism to require a recent factor challenge before allowing changes to enrolled factors.
  • Redirect users to the verification process if their last challenge was more than 300 seconds ago.

docs: clarify MFA_SECRET_ENCRYPTION_KEYS functionality

  • Corrected documentation to specify that MFA_SECRET_ENCRYPTION_KEYS signs TOTP secrets rather than encrypting them.

…irements

- Enhanced security documentation to clarify compromised session handling and step-up re-authentication requirements.
- Updated settings documentation to include `MFA_STEPUP_MAX_AGE` and its interaction with `MFA_REMEMBER_MY_BROWSER`.
- Added detailed explanation of `MFA_STEPUP_MAX_AGE` functionality and its implications for factor changes.

chore: upgrade version to 4.2.0 and update dependencies

- Bumped version from 4.1.0 to 4.2.0 in pyproject.toml and uv.lock.
- Updated development dependencies to include `django-otp` and `django-mfa2`.
- Ensured compatibility with Django 5.2 and added necessary test configurations.

fix: enforce recent challenge for factor changes

- Implemented a mechanism to require a recent factor challenge before allowing changes to enrolled factors.
- Redirect users to the verification process if their last challenge was more than 300 seconds ago.

docs: clarify MFA_SECRET_ENCRYPTION_KEYS functionality

- Corrected documentation to specify that `MFA_SECRET_ENCRYPTION_KEYS` signs TOTP secrets rather than encrypting them.
Copilot AI lite review requested due to automatic review settings August 14, 2026 01:16
@ashwin31
ashwin31 merged commit c9c36ca into master Aug 14, 2026
24 checks passed
@ashwin31
ashwin31 deleted the dev branch August 14, 2026 01:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR releases django-mfa 4.2.0 by adding step-up re-authentication for factor-mutating actions, expanding operational tooling (new management commands + importers), and updating documentation/settings to describe the new security model and migrations.

Changes:

  • Add step-up re-authentication (mfa_recent_required / MfaRecentRequiredMixin, MFA_STEPUP_MAX_AGE, freshness tracking via session at) and apply it to django-mfa’s factor management/enrollment views.
  • Add operational features: MfaExemption model + mfa_disable command + mfa_exemption_changed signal, plus mfa_status, mfa_reset, mfa_report, and importers for django-otp / django-mfa2.
  • Update docs/changelog, bump version to 4.2.0, and adjust tests/runner + dev deps to cover importer fixtures and new behavior.

Reviewed changes

Copilot reviewed 44 out of 47 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
uv.lock Bump project version and lock new dev dependencies (django-otp, django-mfa2) plus transitive packages.
pyproject.toml Version bump to 4.2.0 and add dev deps used as real-model fixtures for importer tests.
test_runner.py Add test-only INSTALLED_APPS and pin settings (DEFAULT_AUTO_FIELD, USE_TZ) for stable CI behavior.
CHANGELOG.md Document 4.2.0 features, behavior changes, and upgrade notes.
docs/index.md Add operations to the docs toctree.
docs/operations.md New operations guide for management commands and migrations/importers.
docs/enforcement.md Document exemption semantics and new step-up enforcement/decorator usage.
docs/security.md Clarify compromised-session handling and direct users to step-up guidance.
docs/settings.md Add MFA_STEPUP_MAX_AGE documentation and update system checks section for E005.
docs/upgrading.md Add 4.2.0 upgrade note describing step-up gating behavior change.
docs/api.md Document new session freshness APIs, exemption model, and new signal semantics.
django_mfa/conf.py Add MFA_STEPUP_MAX_AGE default.
django_mfa/checks.py Add system check E005 validating MFA_STEPUP_MAX_AGE.
django_mfa/apps.py Register the new E005 check at startup.
django_mfa/session.py Add verified_at() / is_fresh() to support step-up freshness enforcement.
django_mfa/decorators.py Implement mfa_recent_required / MfaRecentRequiredMixin and step-up redirect behavior.
django_mfa/views/enroll.py Gate enroll_factor with step-up (allow_unenrolled=True).
django_mfa/views/manage.py Gate factor mutation and recovery code generation with step-up; adjust enrollment-required computation.
django_mfa/views/picker.py Preserve and forward safe ?next= through picker/single-adapter redirect paths.
django_mfa/views/verify.py Factor out safe next handling (safe_next_or_none) for reuse without open-redirect risk.
django_mfa/templates/django_mfa/picker.html Append next parameter to verification links when present.
django_mfa/middleware.py Adjust enrollment-wall evaluation order to reduce unnecessary work and account for exemptions.
django_mfa/policy.py Add exemption-aware MFA_REQUIRED evaluation (has_active_exemption, updated mfa_required_for).
django_mfa/models.py Add MfaExemption model + manager with active/expiry behavior.
django_mfa/migrations/0009_mfa_exemption.py Add migration creating the MfaExemption table.
django_mfa/admin.py Register MfaExemption admin as inspect-and-revoke only.
django_mfa/events.py Add mfa_exemption_changed signal and update request=None semantics documentation.
django_mfa/signals.py Re-export mfa_exemption_changed.
django_mfa/management/init.py Package marker for management modules.
django_mfa/management/commands/init.py Package marker for management commands.
django_mfa/management/commands/_support.py Shared helpers for commands: user resolution, date formatting, safe authenticator display.
django_mfa/management/commands/mfa_status.py New read-only support command to display one user’s MFA state.
django_mfa/management/commands/mfa_reset.py New support command to remove all factors and emit audit signals.
django_mfa/management/commands/mfa_report.py New reporting command for rollout coverage + required-but-unenrolled (text/CSV).
django_mfa/management/commands/mfa_disable.py New command to grant/revoke exemptions with reason/until validation + signal emission.
django_mfa/management/commands/mfa_import_django_otp.py New importer from django-otp (+ django-two-factor-auth) with safety checks and dry-run/overwrite support.
django_mfa/management/commands/mfa_import_django_mfa2.py New importer from django-mfa2 with username-resolution logic and explicit non-migratable reporting.
django_mfa/tests/test_stepup.py New test suite for freshness primitives, decorator/mixin behavior, and next handling.
django_mfa/tests/test_views.py Update tests for step-up gating; add helpers to stamp fresh sessions where needed.
django_mfa/tests/test_notifications.py Update tests to avoid step-up gate interference; adjust verified session timestamps.
django_mfa/tests/test_events.py Update verified session timestamps to satisfy step-up gating for factor changes.
django_mfa/tests/test_models.py Update model registry expectation to include MfaExemption.
django_mfa/tests/test_migrations.py Update migration list to include 0009.
django_mfa/tests/test_exemptions.py New tests for exemption model behavior, policy/middleware effects, and mfa_disable command.
django_mfa/tests/test_commands.py New tests for operational commands (status/reset/report) and invariants (no secret leakage, CSV format, etc.).
django_mfa/tests/test_import_django_otp.py New importer tests against real django-otp models and edge cases.
django_mfa/tests/test_import_django_mfa2.py New importer tests against real django-mfa2 models and edge cases.
Suppressed comments (1)

django_mfa/events.py:35

  • factor_removed’s docstring says it can come from mfa_disable, but mfa_disable doesn’t remove factors; it only grants/revokes MfaExemption. This could confuse audit receivers looking for operator-initiated factor removals.
#: passed by value rather than as an instance. `request` is None when a
#: management command (mfa_reset, mfa_disable) is the one removing it --
#: there is no request to pass.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread django_mfa/events.py
Comment on lines 14 to +18
`sender` is uniformly the Adapter *class* for the factor involved, so a
receiver can narrow with `sender=TOTPAdapter`. `request` is always supplied:
every emission point sits inside a request path.
receiver can narrow with `sender=TOTPAdapter`. `request` is the request the
event happened in, or **None** when it did not happen in one: the management
commands (`mfa_reset`, `mfa_disable`) emit these too, because a factor
removed by an operator is exactly the event an audit receiver most needs to
Comment thread django_mfa/middleware.py
Comment on lines +101 to +103
if (policy.resolve()
and not registry.has_primary_factor(request.user)
and policy.mfa_required_for(request.user)):
Comment on lines +40 to +43
"mfa_enrollment_required": bool(
policy.resolve()
and not registry.has_primary_factor(request.user)
and policy.mfa_required_for(request.user)),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants