Index: models/auth.py
===================================================================
--- models/auth.py (revision 639)
+++ models/auth.py (working copy)
@@ -222,3 +222,33 @@
def _module_log_action(user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
e = LogEntry(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message)
e.save()
+
+class CsrfToken(meta.Model):
+ token = meta.CharField(maxlength=200)
+ issued = meta.DateTimeField(auto_now=True)
+ user = meta.ForeignKey(User)
+ class META:
+ module_name = 'csrf'
+ verbose_name_plural = 'CSRF tokens'
+ db_table = 'auth_csrf_tokens'
+ ordering = ('-issued',)
+
+ def __repr__(self):
+ return self.token
+
+ def _module_create_token(user_id):
+ import md5, random
+ token = md5.new(str(random.random())).hexdigest()
+ ct = CsrfToken(None, token,
+ datetime.datetime.now(), user_id)
+ ct.save()
+ return ct
+
+ def _module_check_token(token, user_id):
+ try:
+ token = get_object(token__exact = token,
+ select = {'user_id': user_id})
+ except CsrfTokenDoesNotExist:
+ return False
+ token.delete()
+ return True
Index: conf/admin_templates/delete_confirmation_generic.html
===================================================================
--- conf/admin_templates/delete_confirmation_generic.html (revision 639)
+++ conf/admin_templates/delete_confirmation_generic.html (working copy)
@@ -2,6 +2,8 @@
{% block content %}
+{% if csrf_failed %}
CSRF protection: Please re-submit.
{% endif %}
+
{% if perms_lacking %}
Deleting the {{ object_name }} "{{ object }}" would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:
{% endif %}
Index: templatetags/csrf.py
===================================================================
--- templatetags/csrf.py (revision 0)
+++ templatetags/csrf.py (revision 0)
@@ -0,0 +1,16 @@
+from django.core import template
+from django.models.auth import csrf
+import random, md5, datetime
+
+class CsrfTokenNode(template.Node):
+ def render(self, context):
+ token = csrf.create_token(context['user'].id)
+ return ' ' % token.token
+
+def csrf_token(parser, token):
+ """
+ {% csrf_token %}
+ """
+ return CsrfTokenNode()
+
+template.register_tag('csrf_token', csrf_token)
Index: views/admin/main.py
===================================================================
--- views/admin/main.py (revision 639)
+++ views/admin/main.py (working copy)
@@ -3,7 +3,7 @@
from django.core import formfields, meta, template_loader
from django.core.exceptions import Http404, ObjectDoesNotExist, PermissionDenied
from django.core.extensions import DjangoContext as Context
-from django.models.auth import log
+from django.models.auth import log, csrf
from django.utils.html import strip_tags
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
from django.utils.text import capfirst, get_text_list
@@ -588,6 +588,7 @@
if opts.admin.save_on_top:
t.extend(_get_submit_row_template(opts, app_label, add, change, show_delete, ordered_objects))
t.append('{% if form.error_dict %}Please correct the error{{ form.error_dict.items|pluralize }} below.
{% endif %}\n')
+ t.append('{% if csrf_failed %}CSRF protection: Please re-submit.
{% endif %}\n')
for fieldset_name, options in admin_field_objs:
t.append('\n\n' % options.get('classes', ''))
if fieldset_name:
@@ -687,6 +688,7 @@
t.append('{{ object|truncatewords:"5" }} ' % \
{'x': ' '.join(['object.%s' % o.pk.name for o in ordered_objects])})
t.append('{% endfor %}{% endif %}\n')
+ t.append('{% load csrf %}{% csrf_token %}\n')
t.append('\n\n{% endblock %}')
return ''.join(t)
@@ -764,12 +766,15 @@
if not request.user.has_perm(app_label + '.' + opts.get_add_permission()):
raise PermissionDenied
manipulator = mod.AddManipulator()
+ csrf_failed = False
if request.POST:
new_data = request.POST.copy()
if opts.has_field_type(meta.FileField):
new_data.update(request.FILES)
errors = manipulator.get_validation_errors(new_data)
- if not errors and not request.POST.has_key("_preview"):
+ # Check the csrf_token
+ csrf_failed = not csrf.check_token(request.POST.get('csrf_token', ''), request.user.id)
+ if not errors and not csrf_failed and not request.POST.has_key("_preview"):
for f in opts.many_to_many:
if f.rel.raw_id_admin:
new_data.setlist(f.name, new_data[f.name].split(","))
@@ -844,6 +849,7 @@
'title': 'Add %s' % opts.verbose_name,
"form": form,
"is_popup": request.REQUEST.has_key("_popup"),
+ "csrf_failed": csrf_failed,
})
if object_id_override is not None:
c['object_id'] = object_id_override
@@ -864,13 +870,16 @@
raise Http404
inline_related_objects = opts.get_inline_related_objects()
+ csrf_failed = False
if request.POST:
new_data = request.POST.copy()
if opts.has_field_type(meta.FileField):
new_data.update(request.FILES)
errors = manipulator.get_validation_errors(new_data)
- if not errors and not request.POST.has_key("_preview"):
+ # Check the csrf_token
+ csrf_failed = not csrf.check_token(request.POST.get('csrf_token', ''), request.user.id)
+ if not errors and not csrf_failed and not request.POST.has_key("_preview"):
for f in opts.many_to_many:
if f.rel.raw_id_admin:
new_data.setlist(f.name, new_data[f.name].split(","))
@@ -969,7 +978,8 @@
"form": form,
'object_id': object_id,
'original': manipulator.original_object,
- 'is_popup' : request.REQUEST.has_key('_popup'),
+ 'is_popup': request.REQUEST.has_key('_popup'),
+ 'csrf_failed': csrf_failed,
})
raw_template = _get_template(opts, app_label, change=True)
# return HttpResponse(raw_template, mimetype='text/plain')
@@ -1073,8 +1083,10 @@
deleted_objects = ['%s: %s ' % (capfirst(opts.verbose_name), object_id, strip_tags(repr(obj))), []]
perms_needed = sets.Set()
_get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
-
- if request.POST: # The user has already confirmed the deletion.
+ csrf_failed = False
+ if request.POST:
+ csrf_failed = not csrf.check_token(request.POST.get('csrf_token', ''), request.user.id)
+ if request.POST and not csrf_failed: # The user has already confirmed the deletion.
if perms_needed:
raise PermissionDenied
obj_repr = repr(obj)
@@ -1089,6 +1101,7 @@
"object": obj,
"deleted_objects": deleted_objects,
"perms_lacking": perms_needed,
+ "csrf_failed": csrf_failed,
})
return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8')