[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
This commit is contained in:
parent
934dc9e712
commit
17084839fd
|
@ -8,7 +8,9 @@ from django.contrib.admin import helpers
|
|||
from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
|
||||
from django.core.exceptions import PermissionDenied, ValidationError
|
||||
from django.db import models, transaction
|
||||
from django.db.models.fields import BLANK_CHOICE_DASH
|
||||
from django.db.models.related import RelatedObject
|
||||
from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
|
||||
from django.db.models.sql.constants import LOOKUP_SEP, QUERY_TERMS
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render_to_response
|
||||
from django.utils.datastructures import SortedDict
|
||||
|
@ -171,6 +173,30 @@ class BaseModelAdmin(object):
|
|||
return None
|
||||
declared_fieldsets = property(_declared_fieldsets)
|
||||
|
||||
def lookup_allowed(self, lookup):
|
||||
parts = lookup.split(LOOKUP_SEP)
|
||||
|
||||
# Last term in lookup is a query term (__exact, __startswith etc)
|
||||
# This term can be ignored.
|
||||
if len(parts) > 1 and parts[-1] in QUERY_TERMS:
|
||||
parts.pop()
|
||||
|
||||
# Special case -- foo__id__exact and foo__id queries are implied
|
||||
# if foo has been specificially included in the lookup list; so
|
||||
# drop __id if it is the last part.
|
||||
if len(parts) > 1 and parts[-1] == self.model._meta.pk.name:
|
||||
parts.pop()
|
||||
|
||||
try:
|
||||
self.model._meta.get_field_by_name(parts[0])
|
||||
except FieldDoesNotExist:
|
||||
# Lookups on non-existants fields are ok, since they're ignored
|
||||
# later.
|
||||
return True
|
||||
else:
|
||||
clean_lookup = LOOKUP_SEP.join(parts)
|
||||
return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
|
||||
|
||||
class ModelAdmin(BaseModelAdmin):
|
||||
"Encapsulates all admin options and functionality for a given model."
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib.admin.filterspecs import FilterSpec
|
||||
from django.contrib.admin.options import IncorrectLookupParameters
|
||||
from django.contrib.admin.util import quote
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.core.paginator import Paginator, InvalidPage
|
||||
from django.db import models
|
||||
from django.db.models.query import QuerySet
|
||||
|
@ -192,13 +193,18 @@ class ChangeList(object):
|
|||
else:
|
||||
lookup_params[key] = True
|
||||
|
||||
if not self.model_admin.lookup_allowed(key):
|
||||
raise SuspiciousOperation(
|
||||
"Filtering by %s not allowed" % key
|
||||
)
|
||||
|
||||
# Apply lookup parameters from the query string.
|
||||
try:
|
||||
qs = qs.filter(**lookup_params)
|
||||
# Naked except! Because we don't have any other way of validating "params".
|
||||
# They might be invalid if the keyword arguments are incorrect, or if the
|
||||
# values are not in the correct type, so we might get FieldError, ValueError,
|
||||
# ValicationError, or ? from a custom field that raises yet something else
|
||||
# ValicationError, or ? from a custom field that raises yet something else
|
||||
# when handed impossible data.
|
||||
except:
|
||||
raise IncorrectLookupParameters
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.contrib import admin
|
|||
from django.core.mail import EmailMessage
|
||||
from django import forms
|
||||
from django.forms.models import BaseModelFormSet
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes import generic
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
|
@ -89,7 +89,7 @@ class ChapterInline(admin.TabularInline):
|
|||
|
||||
class ArticleAdmin(admin.ModelAdmin):
|
||||
list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
|
||||
list_filter = ('date',)
|
||||
list_filter = ('date', 'section')
|
||||
|
||||
def changelist_view(self, request):
|
||||
"Test that extra_context works"
|
||||
|
@ -505,6 +505,13 @@ class CyclicTwo(models.Model):
|
|||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Album(models.Model):
|
||||
owner = models.ForeignKey(User)
|
||||
title = models.CharField(max_length=30)
|
||||
|
||||
class AlbumAdmin(admin.ModelAdmin):
|
||||
list_filter = ['title']
|
||||
|
||||
admin.site.register(Article, ArticleAdmin)
|
||||
admin.site.register(CustomArticle, CustomArticleAdmin)
|
||||
admin.site.register(Section, save_as=True, inlines=[ArticleInline])
|
||||
|
@ -547,3 +554,4 @@ admin.site.register(CyclicTwo)
|
|||
admin.site.register(Book, inlines=[ChapterInline])
|
||||
admin.site.register(Promo)
|
||||
admin.site.register(ChapterXtra1)
|
||||
admin.site.register(Album, AlbumAdmin)
|
|
@ -3,6 +3,7 @@
|
|||
import re
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.core.files import temp as tempfile
|
||||
from django.contrib.auth.models import User, Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
@ -289,6 +290,10 @@ class AdminViewBasicTest(TestCase):
|
|||
self.assertContains(response, 'Choisir une heure')
|
||||
deactivate()
|
||||
|
||||
def test_disallowed_filtering(self):
|
||||
self.assertRaises(SuspiciousOperation,
|
||||
self.client.get, "/test_admin/admin/admin_views/album/?owner__email__startswith=fuzzy"
|
||||
)
|
||||
|
||||
class SaveAsTests(TestCase):
|
||||
fixtures = ['admin-views-users.xml','admin-views-person.xml']
|
||||
|
|
Loading…
Reference in New Issue