Loading django/contrib/admindocs/views.py +4 −3 Original line number Diff line number Diff line Loading @@ -143,10 +143,11 @@ class ViewDetailView(BaseAdminDocsView): def get_context_data(self, **kwargs): view = self.kwargs['view'] urlconf = urlresolvers.get_urlconf() if urlresolvers.get_resolver(urlconf)._is_callback(view): mod, func = urlresolvers.get_mod_func(view) try: view_func = getattr(import_module(mod), func) except (ImportError, AttributeError): else: raise Http404 title, body, metadata = utils.parse_docstring(view_func.__doc__) if title: Loading django/core/urlresolvers.py +6 −1 Original line number Diff line number Diff line Loading @@ -353,6 +353,11 @@ class RegexURLResolver(LocaleRegexProvider): self._populate() return self._app_dict[language_code] def _is_callback(self, name): if not self._populated: self._populate() return name in self._callback_strs def resolve(self, path): path = force_text(path) # path may be a reverse_lazy object tried = [] Loading Loading @@ -430,7 +435,7 @@ class RegexURLResolver(LocaleRegexProvider): original_lookup = lookup_view try: if lookup_view in self._callback_strs: if self._is_callback(lookup_view): lookup_view = get_callable(lookup_view, True) except (ImportError, AttributeError) as e: raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e)) Loading docs/releases/1.8.txt +8 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,14 @@ Minor features <django.contrib.admin.ModelAdmin.show_full_result_count>` to control whether or not the full count of objects should be displayed on a filtered admin page. :mod:`django.contrib.admindocs` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * The view to browse view details now checks if the view specified in the URL exists in the URLconf. Previously it was possible to import arbitrary packages from the Python path. This was not considered a security issue because ``admindocs`` is only accessible to staff users. :mod:`django.contrib.auth` ^^^^^^^^^^^^^^^^^^^^^^^^^^ Loading tests/admin_docs/tests.py +11 −0 Original line number Diff line number Diff line import sys import unittest from django.conf import settings Loading Loading @@ -84,6 +85,16 @@ class AdminDocViewTests(AdminDocsTestCase): # View docstring self.assertContains(response, 'Base view for admindocs views.') def test_view_detail_illegal_import(self): """ #23601 - Ensure the view exists in the URLconf. """ response = self.client.get( reverse('django-admindocs-views-detail', args=['urlpatterns_reverse.nonimported_module.view'])) self.assertEqual(response.status_code, 404) self.assertNotIn("urlpatterns_reverse.nonimported_module", sys.modules) def test_model_index(self): response = self.client.get(reverse('django-admindocs-models-index')) self.assertContains( Loading Loading
django/contrib/admindocs/views.py +4 −3 Original line number Diff line number Diff line Loading @@ -143,10 +143,11 @@ class ViewDetailView(BaseAdminDocsView): def get_context_data(self, **kwargs): view = self.kwargs['view'] urlconf = urlresolvers.get_urlconf() if urlresolvers.get_resolver(urlconf)._is_callback(view): mod, func = urlresolvers.get_mod_func(view) try: view_func = getattr(import_module(mod), func) except (ImportError, AttributeError): else: raise Http404 title, body, metadata = utils.parse_docstring(view_func.__doc__) if title: Loading
django/core/urlresolvers.py +6 −1 Original line number Diff line number Diff line Loading @@ -353,6 +353,11 @@ class RegexURLResolver(LocaleRegexProvider): self._populate() return self._app_dict[language_code] def _is_callback(self, name): if not self._populated: self._populate() return name in self._callback_strs def resolve(self, path): path = force_text(path) # path may be a reverse_lazy object tried = [] Loading Loading @@ -430,7 +435,7 @@ class RegexURLResolver(LocaleRegexProvider): original_lookup = lookup_view try: if lookup_view in self._callback_strs: if self._is_callback(lookup_view): lookup_view = get_callable(lookup_view, True) except (ImportError, AttributeError) as e: raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e)) Loading
docs/releases/1.8.txt +8 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,14 @@ Minor features <django.contrib.admin.ModelAdmin.show_full_result_count>` to control whether or not the full count of objects should be displayed on a filtered admin page. :mod:`django.contrib.admindocs` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * The view to browse view details now checks if the view specified in the URL exists in the URLconf. Previously it was possible to import arbitrary packages from the Python path. This was not considered a security issue because ``admindocs`` is only accessible to staff users. :mod:`django.contrib.auth` ^^^^^^^^^^^^^^^^^^^^^^^^^^ Loading
tests/admin_docs/tests.py +11 −0 Original line number Diff line number Diff line import sys import unittest from django.conf import settings Loading Loading @@ -84,6 +85,16 @@ class AdminDocViewTests(AdminDocsTestCase): # View docstring self.assertContains(response, 'Base view for admindocs views.') def test_view_detail_illegal_import(self): """ #23601 - Ensure the view exists in the URLconf. """ response = self.client.get( reverse('django-admindocs-views-detail', args=['urlpatterns_reverse.nonimported_module.view'])) self.assertEqual(response.status_code, 404) self.assertNotIn("urlpatterns_reverse.nonimported_module", sys.modules) def test_model_index(self): response = self.client.get(reverse('django-admindocs-models-index')) self.assertContains( Loading