Skip to content

Commit 1708483

Browse files
committed
[1.1.X] Fix a security issue in the admin. Disclosure and new release forthcoming.
git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.1.X@15035 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 934dc9e commit 1708483

File tree

4 files changed

+49
-4
lines changed

4 files changed

+49
-4
lines changed

django/contrib/admin/options.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
99
from django.core.exceptions import PermissionDenied, ValidationError
1010
from django.db import models, transaction
11-
from django.db.models.fields import BLANK_CHOICE_DASH
11+
from django.db.models.related import RelatedObject
12+
from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
13+
from django.db.models.sql.constants import LOOKUP_SEP, QUERY_TERMS
1214
from django.http import Http404, HttpResponse, HttpResponseRedirect
1315
from django.shortcuts import get_object_or_404, render_to_response
1416
from django.utils.datastructures import SortedDict
@@ -171,6 +173,30 @@ def _declared_fieldsets(self):
171173
return None
172174
declared_fieldsets = property(_declared_fieldsets)
173175

176+
def lookup_allowed(self, lookup):
177+
parts = lookup.split(LOOKUP_SEP)
178+
179+
# Last term in lookup is a query term (__exact, __startswith etc)
180+
# This term can be ignored.
181+
if len(parts) > 1 and parts[-1] in QUERY_TERMS:
182+
parts.pop()
183+
184+
# Special case -- foo__id__exact and foo__id queries are implied
185+
# if foo has been specificially included in the lookup list; so
186+
# drop __id if it is the last part.
187+
if len(parts) > 1 and parts[-1] == self.model._meta.pk.name:
188+
parts.pop()
189+
190+
try:
191+
self.model._meta.get_field_by_name(parts[0])
192+
except FieldDoesNotExist:
193+
# Lookups on non-existants fields are ok, since they're ignored
194+
# later.
195+
return True
196+
else:
197+
clean_lookup = LOOKUP_SEP.join(parts)
198+
return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
199+
174200
class ModelAdmin(BaseModelAdmin):
175201
"Encapsulates all admin options and functionality for a given model."
176202

django/contrib/admin/views/main.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from django.contrib.admin.filterspecs import FilterSpec
22
from django.contrib.admin.options import IncorrectLookupParameters
33
from django.contrib.admin.util import quote
4+
from django.core.exceptions import SuspiciousOperation
45
from django.core.paginator import Paginator, InvalidPage
56
from django.db import models
67
from django.db.models.query import QuerySet
@@ -192,13 +193,18 @@ def get_query_set(self):
192193
else:
193194
lookup_params[key] = True
194195

196+
if not self.model_admin.lookup_allowed(key):
197+
raise SuspiciousOperation(
198+
"Filtering by %s not allowed" % key
199+
)
200+
195201
# Apply lookup parameters from the query string.
196202
try:
197203
qs = qs.filter(**lookup_params)
198204
# Naked except! Because we don't have any other way of validating "params".
199205
# They might be invalid if the keyword arguments are incorrect, or if the
200206
# values are not in the correct type, so we might get FieldError, ValueError,
201-
# ValicationError, or ? from a custom field that raises yet something else
207+
# ValicationError, or ? from a custom field that raises yet something else
202208
# when handed impossible data.
203209
except:
204210
raise IncorrectLookupParameters

tests/regressiontests/admin_views/models.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from django.core.mail import EmailMessage
88
from django import forms
99
from django.forms.models import BaseModelFormSet
10-
10+
from django.contrib.auth.models import User
1111
from django.contrib.contenttypes import generic
1212
from django.contrib.contenttypes.models import ContentType
1313

@@ -89,7 +89,7 @@ class ChapterInline(admin.TabularInline):
8989

9090
class ArticleAdmin(admin.ModelAdmin):
9191
list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
92-
list_filter = ('date',)
92+
list_filter = ('date', 'section')
9393

9494
def changelist_view(self, request):
9595
"Test that extra_context works"
@@ -505,6 +505,13 @@ class CyclicTwo(models.Model):
505505
def __unicode__(self):
506506
return self.name
507507

508+
class Album(models.Model):
509+
owner = models.ForeignKey(User)
510+
title = models.CharField(max_length=30)
511+
512+
class AlbumAdmin(admin.ModelAdmin):
513+
list_filter = ['title']
514+
508515
admin.site.register(Article, ArticleAdmin)
509516
admin.site.register(CustomArticle, CustomArticleAdmin)
510517
admin.site.register(Section, save_as=True, inlines=[ArticleInline])
@@ -547,3 +554,4 @@ def __unicode__(self):
547554
admin.site.register(Book, inlines=[ChapterInline])
548555
admin.site.register(Promo)
549556
admin.site.register(ChapterXtra1)
557+
admin.site.register(Album, AlbumAdmin)

tests/regressiontests/admin_views/tests.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import re
44
import datetime
55
from django.conf import settings
6+
from django.core.exceptions import SuspiciousOperation
67
from django.core.files import temp as tempfile
78
from django.contrib.auth.models import User, Permission
89
from django.contrib.contenttypes.models import ContentType
@@ -289,6 +290,10 @@ def testI18NLanguageNonEnglishFallback(self):
289290
self.assertContains(response, 'Choisir une heure')
290291
deactivate()
291292

293+
def test_disallowed_filtering(self):
294+
self.assertRaises(SuspiciousOperation,
295+
self.client.get, "/test_admin/admin/admin_views/album/?owner__email__startswith=fuzzy"
296+
)
292297

293298
class SaveAsTests(TestCase):
294299
fixtures = ['admin-views-users.xml','admin-views-person.xml']

0 commit comments

Comments
 (0)