Ticket #7167: 7167-safeform.diff

File 7167-safeform.diff, 5.1 KB (added by ElliottM, 6 years ago)
  • django/contrib/csrf/tests.py

     
     1"""
     2
     3>>> from django.conf import settings
     4>>> from django.http import HttpRequest
     5>>> from django.contrib.csrf.forms import SafeForm
     6
     7>>> settings.SECRET_KEY='secret'
     8>>> settings.SESSION_COOKIE_NAME='session_id'
     9
     10#If SafeForm is not passed a HttpRequest object, a ValueError is raised
     11>>> form=SafeForm()
     12Traceback (most recent call last):
     13  ...
     14ValueError: SafeForm must be given a HttpRequest object
     15
     16#if the user who made the request does not have the session cookie set,
     17#a csrf token cannot be generated, so the value for the token should be empty
     18>>> request=HttpRequest()
     19>>> form=SafeForm(request=request)
     20>>> form.csrf_token_field()
     21u'<input type=\"hidden\" name=\"_csrf_token\" id=\"id__csrf_token\" />'
     22
     23#if a user that does not send any cookies tries to submit a form,
     24#SafeForm should automatically invalidate it
     25>>> request=HttpRequest()
     26>>> request.POST['_csrf_token']='2376e3ffd767c170fab368189b7e4799'
     27>>> form=SafeForm(request.POST, request=request)
     28>>> form.is_valid()
     29False
     30>>> form.non_field_errors()
     31[u'Your session has expired. Please refresh the page and submit the form again.']
     32
     33#if the request has a valid session ID cookie, generate a token for it
     34>>> request=HttpRequest()
     35>>> request.COOKIES['session_id']='abcde'
     36>>> form=SafeForm(request=request)
     37>>> form.csrf_token_field()
     38u'<input type=\"hidden\" name=\"_csrf_token\" value=\"2376e3ffd767c170fab368189b7e4799\" id=\"id__csrf_token\" />'
     39
     40#if a user submits a form that doesn't have a csrf token at all, the form is not valid
     41>>> form=SafeForm(request.POST,request=request)
     42>>> form.is_valid()
     43False
     44>>> form.non_field_errors()
     45[u'Your session has expired. Please refresh the page and submit the form again.']
     46
     47#if a user submits a form with an incorrect csrf token, the form is not valid.
     48>>> request=HttpRequest()
     49>>> request.POST['_csrf_token']='hello'
     50>>> request.COOKIES['session_id']='abcde'
     51>>> form=SafeForm(request.POST,request=request)
     52>>> form.is_valid()
     53False
     54>>> form.non_field_errors()
     55[u'Your session has expired. Please refresh the page and submit the form again.']
     56
     57#if a user submits a form with the correct token, only then should is_valid() be True
     58>>> request=HttpRequest()
     59>>> request.POST['_csrf_token']='2376e3ffd767c170fab368189b7e4799'
     60>>> request.COOKIES['session_id']='abcde'
     61>>> form=SafeForm(request.POST,request=request)
     62>>> form.is_valid()
     63True
     64
     65"""
     66
     67if __name__ == '__main__':
     68    import doctest
     69    doctest.testmod()
  • django/contrib/csrf/forms.py

     
     1from django import forms
     2from django.conf import settings
     3from django.utils.hashcompat import md5_constructor
     4from django.utils.safestring import mark_safe
     5
     6class SafeForm(forms.Form):
     7    """
     8    Form that adds protection against Cross Site Request Forgeries by adding
     9    a hidden field and checking for the correct value during validation.
     10   
     11    If a session ID cookie is present, it is hashed with the SECRET_KEY
     12    setting to create an authentication token.  This token is added outgoing
     13    forms and is expected on all incoming POST requests that
     14    have a session ID cookie.
     15   
     16    If you are setting cookies directly, instead of using Django's session
     17    framework, this form will not work.
     18    """
     19   
     20    _csrf_token = forms.CharField(widget=forms.HiddenInput, required=False)
     21    INVALID_TOKEN_MSG = "Your session has expired. Please refresh the "\
     22                    + "page and submit the form again."
     23   
     24    def __init__(self, *args, **kwargs):
     25        try:
     26            self._request=kwargs.pop('request')
     27        except KeyError:
     28            raise ValueError("SafeForm must be given a HttpRequest object")
     29       
     30        super(SafeForm,self).__init__(*args, **kwargs)
     31       
     32        #We cannot set the initial in the field declaration because the
     33        #_make_token call needs the reference to "self"
     34        self.fields['_csrf_token'].initial=self._make_token
     35   
     36    def clean(self):
     37        session_token = self._make_token()
     38       
     39        if '_csrf_token' not in self.cleaned_data or self.cleaned_data['_csrf_token'] != session_token or session_token is None:
     40            raise forms.ValidationError(self.INVALID_TOKEN_MSG)
     41       
     42        return self.cleaned_data
     43       
     44       
     45    def _make_token(self):
     46        try:
     47            session_id = self._request.COOKIES[settings.SESSION_COOKIE_NAME]
     48            return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
     49        except KeyError:
     50            #if the user does not have any cookies set,
     51            #a token cannot be generated
     52            return None
     53   
     54    def csrf_token_field(self):
     55        return mark_safe(unicode(self['_csrf_token']))
     56 No newline at end of file
Back to Top