Fix: respect subpath in logout, share link and auto-login redirects (#14476)

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-10-18 14:28:15 +00:00
1 parent 961f7fd672
commit 309a4b004d
8 files changed
+106 -7

No files matched your search

@@ -7,6 +7,7 @@ from unittest import mock
from django.conf import settings
from django.contrib.auth.models import User
from django.test import override_settings
from django.utils import timezone
from rest_framework import serializers
from rest_framework import status
@@ -225,6 +226,25 @@ class ShareLinkBundleAPITests(DirectoriesMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
self.assertIn("sharelink_notfound=1", response["Location"])
@override_settings(LOGIN_URL="/paperless/accounts/login/")
def test_unknown_share_link_redirects_under_subpath(self) -> None:
"""
GIVEN:
- Paperless is served under a subpath
WHEN:
- An unknown public share link is requested
THEN:
- The redirect to the login page keeps the subpath
"""
self.client.logout()
response = self.client.get("/share/unknownsharelink/")
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
self.assertEqual(
response["Location"],
"/paperless/accounts/login/?sharelink_notfound=1",
)
def test_share_link_missing_file_redirects(self) -> None:
"""
GIVEN:
+6 -4
View File
@@ -4911,7 +4911,7 @@ class SharedLinkView(View):
share_link.expiration is not None
and share_link.expiration < timezone.now()
):
return HttpResponseRedirect("/accounts/login/?sharelink_expired=1")
return HttpResponseRedirect(f"{settings.LOGIN_URL}?sharelink_expired=1")
try:
return serve_file(
doc=share_link.document,
@@ -4920,14 +4920,16 @@ class SharedLinkView(View):
disposition="inline",
)
except FileNotFoundError:
return HttpResponseRedirect("/accounts/login/?sharelink_notfound=1")
return HttpResponseRedirect(
f"{settings.LOGIN_URL}?sharelink_notfound=1",
)
bundle = ShareLinkBundle.objects.filter(slug=slug).first()
if bundle is None:
return HttpResponseRedirect("/accounts/login/?sharelink_notfound=1")
return HttpResponseRedirect(f"{settings.LOGIN_URL}?sharelink_notfound=1")
if bundle.expiration is not None and bundle.expiration < timezone.now():
return HttpResponseRedirect("/accounts/login/?sharelink_expired=1")
return HttpResponseRedirect(f"{settings.LOGIN_URL}?sharelink_expired=1")
if bundle.status in {
ShareLinkBundle.Status.PENDING,
+1 -1
View File
@@ -16,7 +16,7 @@ logger = logging.getLogger("paperless.auth")
class AutoLoginMiddleware(MiddlewareMixin):
def process_request(self, request: HttpRequest) -> None:
# Dont use auto-login with token request
if request.path.startswith("/api/token/") and request.method == "POST":
if request.path_info.startswith("/api/token/") and request.method == "POST":
return None
try:
request.user = User.objects.get(
@@ -51,3 +51,21 @@ class TestAutoLoginMiddleware(TestCase):
self._process(request)
self.assertFalse(request.user.is_authenticated)
@override_settings(FORCE_SCRIPT_NAME="/paperless")
def test_token_request_is_not_logged_in_under_subpath(self) -> None:
"""
GIVEN:
- Paperless is served under a subpath
WHEN:
- A token is requested via POST
THEN:
- The request is left anonymous so the posted credentials are used
"""
UserFactory(username="autologin")
request = self.factory.post("/api/token/")
request.user = AnonymousUser()
self._process(request)
self.assertFalse(request.user.is_authenticated)