Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #17972: Force evaluation of LOGIN_REQUIRED when requesting static media #17990

Merged
merged 1 commit into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion netbox/netbox/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import urllib.parse

from django.urls import reverse
from django.test import override_settings
from django.test import Client, override_settings

from dcim.models import Site
from netbox.constants import EMPTY_TABLE_TEXT
Expand Down Expand Up @@ -74,3 +74,21 @@ def test_search_no_results(self):
self.assertHttpStatus(response, 200)
content = str(response.content)
self.assertIn(EMPTY_TABLE_TEXT, content)


class MediaViewTestCase(TestCase):

def test_media_login_required(self):
url = reverse('media', kwargs={'path': 'foo.txt'})
response = Client().get(url)

# Unauthenticated request should redirect to login page
self.assertHttpStatus(response, 302)

@override_settings(LOGIN_REQUIRED=False)
def test_media_login_not_required(self):
url = reverse('media', kwargs={'path': 'foo.txt'})
response = Client().get(url)

# Unauthenticated request should return a 404 (not found)
self.assertHttpStatus(response, 404)
5 changes: 2 additions & 3 deletions netbox/netbox/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
from django.conf.urls import include
from django.urls import path
from django.views.decorators.cache import cache_page
from django.views.static import serve
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView

from account.views import LoginView, LogoutView
from netbox.api.views import APIRootView, StatusView
from netbox.graphql.schema import schema
from netbox.graphql.views import NetBoxGraphQLView
from netbox.plugins.urls import plugin_patterns, plugin_api_patterns
from netbox.views import HomeView, StaticMediaFailureView, SearchView, htmx
from netbox.views import HomeView, MediaView, StaticMediaFailureView, SearchView, htmx

_patterns = [

Expand Down Expand Up @@ -69,7 +68,7 @@
path('graphql/', NetBoxGraphQLView.as_view(schema=schema), name='graphql'),

# Serving static media in Django to pipe it through LoginRequiredMiddleware
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),
path('media/<path:path>', MediaView.as_view(), name='media'),
path('media-failure/', StaticMediaFailureView.as_view(), name='media_failure'),

# Plugins
Expand Down
10 changes: 10 additions & 0 deletions netbox/netbox/views/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.shortcuts import redirect, render
from django.utils.translation import gettext_lazy as _
from django.views.generic import View
from django.views.static import serve
from django_tables2 import RequestConfig
from packaging import version

Expand All @@ -23,6 +24,7 @@

__all__ = (
'HomeView',
'MediaView',
'SearchView',
)

Expand Down Expand Up @@ -115,3 +117,11 @@ def get(self, request):
'form': form,
'table': table,
})


class MediaView(ConditionalLoginRequiredMixin, View):
"""
Wrap Django's serve() view to enforce LOGIN_REQUIRED for static media.
"""
def get(self, request, path):
return serve(request, path, document_root=settings.MEDIA_ROOT)
Loading