10000 [1.7.x] Fixed #23601 -- Ensured view exists in URLconf before importi… · alex-python/django@c250899 · GitHub
[go: up one dir, main page]

Skip to content

Commit c250899

Browse files
MarkusHtimgraham
authored andcommitted
[1.7.x] Fixed #23601 -- Ensured view exists in URLconf before importing it in admindocs.
Backport of 2f16ff5 from master
1 parent b3569b3 commit c250899

File tree

4 files changed

+27
-4
lines changed

4 files changed

+27
-4
lines changed

django/contrib/admindocs/views.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,11 @@ class ViewDetailView(BaseAdminDocsView):
150150

151151
def get_context_data(self, **kwargs):
152152
view = self.kwargs['view']
153-
mod, func = urlresolvers.get_mod_func(view)
154-
try:
153+
urlconf = urlresolvers.get_urlconf()
154+
if urlresolvers.get_resolver(urlconf)._is_callback(view):
155+
mod, func = urlresolvers.get_mod_func(view)
155156
view_func = getattr(import_module(mod), func)
156-
except (ImportError, AttributeError):
157+
else:
157158
raise Http404
158159
title, body, metadata = utils.parse_docstring(view_func.__doc__)
159160
if title:

django/core/urlresolvers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,11 @@ def app_dict(self):
329329
self._populate()
330330
return self._app_dict[language_code]
331331

332+
def _is_callback(self, name):
333+
if not self._populated:
334+
self._populate()
335+
return name in self._callback_strs
336+
332337
def resolve(self, path):
333338
path = force_text(path) # path may be a reverse_lazy object
334339
tried = []
@@ -410,7 +415,7 @@ def _reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs):
410415
self._populate()
411416

412417
try:
413-
if lookup_view in self._callback_strs:
418+
if self._is_callback(lookup_view):
414419
lookup_view = get_callable(lookup_view, True)
415420
except (ImportError, AttributeError) as e:
416421
raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e))

docs/releases/1.7.1.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,9 @@ Bugfixes
9191
(:ticket:`23560`).
9292

9393
* Fixed ``deepcopy`` on ``ErrorList`` (:ticket:`23594`).
94+
95+
* Made the :mod:`~django.contrib.admindocs` view to browse view details check
96+
if the view specified in the URL exists in the URLconf. Previously it was
97+
possible to import arbitrary packages from the Python path. This was not
98+
considered a security issue because ``admindocs`` is only accessible to staff
99+
users (:ticket:`23601`).

tests/admin_docs/tests.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
import unittest
23

34
from django.conf import settings
@@ -79,6 +80,16 @@ def test_view_detail(self):
7980
# View docstring
8081
self.assertContains(response, 'Base view for admindocs views.')
8182

83+
def test_view_detail_illegal_import(self):
84+
"""
85+
#23601 - Ensure the view exists in the URLconf.
86+
"""
87+
response = self.client.get(
88+
reverse('django-admindocs-views-detail',
89+
args=['urlpatterns_reverse.nonimported_module.view']))
90+
self.assertEqual(response.status_code, 404)
91+
self.assertNotIn("urlpatterns_reverse.nonimported_module", sys.modules)
92+
8293
def test_model_index(self):
8394
response = self.client.get(reverse('django-admindocs-models-index'))
8495
self.assertContains(

0 commit comments

Comments
 (0)
0