Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.5.x] Checked object permissions on admin history view.

This is a security fix. Disclosure and advisory coming shortly.

Patch by Russell Keith-Magee.
  • Loading branch information...
commit 0e46c7f7ac9c8c56149090b58a277239708cf4f7 1 parent 2d0c22e
Carl Meyer carljm authored
14 django/contrib/admin/options.py
@@ -1369,15 +1369,21 @@ def delete_view(self, request, object_id, extra_context=None):
1369 1369 def history_view(self, request, object_id, extra_context=None):
1370 1370 "The 'history' admin view for this model."
1371 1371 from django.contrib.admin.models import LogEntry
  1372 + # First check if the user can see this history.
1372 1373 model = self.model
  1374 + obj = get_object_or_404(model, pk=unquote(object_id))
  1375 +
  1376 + if not self.has_change_permission(request, obj):
  1377 + raise PermissionDenied
  1378 +
  1379 + # Then get the history for this object.
1373 1380 opts = model._meta
1374 1381 app_label = opts.app_label
1375 1382 action_list = LogEntry.objects.filter(
1376   - object_id = unquote(object_id),
1377   - content_type__id__exact = ContentType.objects.get_for_model(model).id
  1383 + object_id=unquote(object_id),
  1384 + content_type__id__exact=ContentType.objects.get_for_model(model).id
1378 1385 ).select_related().order_by('action_time')
1379   - # If no history was found, see whether this object even exists.
1380   - obj = get_object_or_404(model, pk=unquote(object_id))
  1386 +
1381 1387 context = {
1382 1388 'title': _('Change history: %s') % force_text(obj),
1383 1389 'action_list': action_list,
40 tests/regressiontests/admin_views/tests.py
@@ -1103,6 +1103,46 @@ def testChangeView(self):
1103 1103 self.assertContains(response, 'login-form')
1104 1104 self.client.get('/test_admin/admin/logout/')
1105 1105
  1106 + def testHistoryView(self):
  1107 + """History view should restrict access."""
  1108 +
  1109 + # add user shoud not be able to view the list of article or change any of them
  1110 + self.client.get('/test_admin/admin/')
  1111 + self.client.post('/test_admin/admin/', self.adduser_login)
  1112 + response = self.client.get('/test_admin/admin/admin_views/article/1/history/')
  1113 + self.assertEqual(response.status_code, 403)
  1114 + self.client.get('/test_admin/admin/logout/')
  1115 +
  1116 + # change user can view all items and edit them
  1117 + self.client.get('/test_admin/admin/')
  1118 + self.client.post('/test_admin/admin/', self.changeuser_login)
  1119 + response = self.client.get('/test_admin/admin/admin_views/article/1/history/')
  1120 + self.assertEqual(response.status_code, 200)
  1121 +
  1122 + # Test redirection when using row-level change permissions. Refs #11513.
  1123 + RowLevelChangePermissionModel.objects.create(id=1, name="odd id")
  1124 + RowLevelChangePermissionModel.objects.create(id=2, name="even id")
  1125 + for login_dict in [self.super_login, self.changeuser_login, self.adduser_login, self.deleteuser_login]:
  1126 + self.client.post('/test_admin/admin/', login_dict)
  1127 + response = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/history/')
  1128 + self.assertEqual(response.status_code, 403)
  1129 +
  1130 + response = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/history/')
  1131 + self.assertEqual(response.status_code, 200)
  1132 +
  1133 + self.client.get('/test_admin/admin/logout/')
  1134 +
  1135 + for login_dict in [self.joepublic_login, self.no_username_login]:
  1136 + self.client.post('/test_admin/admin/', login_dict)
  1137 + response = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/history/')
  1138 + self.assertEqual(response.status_code, 200)
  1139 + self.assertContains(response, 'login-form')
  1140 + response = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/history/')
  1141 + self.assertEqual(response.status_code, 200)
  1142 + self.assertContains(response, 'login-form')
  1143 +
  1144 + self.client.get('/test_admin/admin/logout/')
  1145 +
1106 1146 def testConditionallyShowAddSectionLink(self):
1107 1147 """
1108 1148 The foreign key widget should only show the "add related" button if the

0 comments on commit 0e46c7f

Please sign in to comment.
Something went wrong with that request. Please try again.