From 901846272b4a54942863a955b60a608be2870e8d Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 4 Nov 2025 10:08:04 +1100 Subject: [PATCH] Auth Improvements (#10752) * Return more detail in MFA failure response * Reject auth requests for users who are inactive * Move markdown config out of settings.py --- .../InvenTree/AllUserRequire2FAMiddleware.py | 4 +- .../InvenTree/InvenTree/setting/markdown.py | 44 +++++++++++++++++++ src/backend/InvenTree/InvenTree/settings.py | 39 +--------------- src/backend/InvenTree/InvenTree/views.py | 12 +++-- 4 files changed, 58 insertions(+), 41 deletions(-) create mode 100644 src/backend/InvenTree/InvenTree/setting/markdown.py diff --git a/src/backend/InvenTree/InvenTree/AllUserRequire2FAMiddleware.py b/src/backend/InvenTree/InvenTree/AllUserRequire2FAMiddleware.py index 609c55e3c7..160bd1ec9e 100644 --- a/src/backend/InvenTree/InvenTree/AllUserRequire2FAMiddleware.py +++ b/src/backend/InvenTree/InvenTree/AllUserRequire2FAMiddleware.py @@ -44,7 +44,9 @@ class AllUserRequire2FAMiddleware(MiddlewareMixin): def on_require_2fa(self, request: HttpRequest) -> HttpResponse: """Force user to mfa activation.""" - return JsonResponse({'id': 'mfa_register'}, status=401) + return JsonResponse( + {'id': 'mfa_register', 'error': self.require_2fa_message}, status=401 + ) def is_allowed_page(self, request: HttpRequest) -> bool: """Check if the current page can be accessed without mfa.""" diff --git a/src/backend/InvenTree/InvenTree/setting/markdown.py b/src/backend/InvenTree/InvenTree/setting/markdown.py new file mode 100644 index 0000000000..13bdca3cd7 --- /dev/null +++ b/src/backend/InvenTree/InvenTree/setting/markdown.py @@ -0,0 +1,44 @@ +"""Configuration options for django-markdownify. + +Ref: https://django-markdownify.readthedocs.io/en/latest/settings.html +""" + + +def markdownify_config(): + """Return configuration dictionary for django-markdownify.""" + return { + 'default': { + 'BLEACH': True, + 'WHITELIST_ATTRS': ['href', 'src', 'alt'], + 'MARKDOWN_EXTENSIONS': ['markdown.extensions.extra'], + 'WHITELIST_TAGS': [ + 'a', + 'abbr', + 'b', + 'blockquote', + 'code', + 'em', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'hr', + 'i', + 'img', + 'li', + 'ol', + 'p', + 'pre', + 's', + 'strong', + 'table', + 'thead', + 'tbody', + 'th', + 'tr', + 'td', + 'ul', + ], + } + } diff --git a/src/backend/InvenTree/InvenTree/settings.py b/src/backend/InvenTree/InvenTree/settings.py index 18229b242f..25f94b7c7e 100644 --- a/src/backend/InvenTree/InvenTree/settings.py +++ b/src/backend/InvenTree/InvenTree/settings.py @@ -42,7 +42,7 @@ from InvenTree.version import ( from users.oauth2_scopes import oauth2_scopes from . import config -from .setting import locales, storages +from .setting import locales, markdown, storages try: import django_stubs_ext @@ -1399,42 +1399,7 @@ LOGOUT_REDIRECT_URL = get_setting( # Markdownify configuration # Ref: https://django-markdownify.readthedocs.io/en/latest/settings.html -MARKDOWNIFY = { - 'default': { - 'BLEACH': True, - 'WHITELIST_ATTRS': ['href', 'src', 'alt'], - 'MARKDOWN_EXTENSIONS': ['markdown.extensions.extra'], - 'WHITELIST_TAGS': [ - 'a', - 'abbr', - 'b', - 'blockquote', - 'code', - 'em', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'hr', - 'i', - 'img', - 'li', - 'ol', - 'p', - 'pre', - 's', - 'strong', - 'table', - 'thead', - 'tbody', - 'th', - 'tr', - 'td', - 'ul', - ], - } -} +MARKDOWNIFY = markdown.markdownify_config() # Ignore these error types for in-database error logging IGNORED_ERRORS = [Http404, HttpResponseGone, django.core.exceptions.PermissionDenied] diff --git a/src/backend/InvenTree/InvenTree/views.py b/src/backend/InvenTree/InvenTree/views.py index 4dee011266..f65dcb203e 100644 --- a/src/backend/InvenTree/InvenTree/views.py +++ b/src/backend/InvenTree/InvenTree/views.py @@ -12,6 +12,12 @@ def auth_request(request): Useful for (for example) redirecting authentication requests through django's permission framework. """ - if request.user and request.user.is_authenticated: - return HttpResponse(status=200) - return HttpResponse(status=403) + if not request.user or not request.user.is_authenticated: + return HttpResponse(status=403) + + if not request.user.is_active: + # Reject requests from inactive users + return HttpResponse(status=403) + + # User is authenticated and active + return HttpResponse(status=200)