Index: django/contrib/csrf/tests.py
===================================================================
--- django/contrib/csrf/tests.py	(revision 0)
+++ django/contrib/csrf/tests.py	(revision 0)
@@ -0,0 +1,69 @@
+"""
+
+>>> from django.conf import settings
+>>> from django.http import HttpRequest
+>>> from django.contrib.csrf.forms import SafeForm
+
+>>> settings.SECRET_KEY='secret'
+>>> settings.SESSION_COOKIE_NAME='session_id'
+
+#If SafeForm is not passed a HttpRequest object, a ValueError is raised
+>>> form=SafeForm()
+Traceback (most recent call last):
+  ...
+ValueError: SafeForm must be given a HttpRequest object
+
+#if the user who made the request does not have the session cookie set,
+#a csrf token cannot be generated, so the value for the token should be empty
+>>> request=HttpRequest()
+>>> form=SafeForm(request=request)
+>>> form.csrf_token_field()
+u'<input type=\"hidden\" name=\"_csrf_token\" id=\"id__csrf_token\" />'
+
+#if a user that does not send any cookies tries to submit a form,
+#SafeForm should automatically invalidate it
+>>> request=HttpRequest()
+>>> request.POST['_csrf_token']='2376e3ffd767c170fab368189b7e4799'
+>>> form=SafeForm(request.POST, request=request)
+>>> form.is_valid()
+False
+>>> form.non_field_errors()
+[u'Your session has expired. Please refresh the page and submit the form again.']
+
+#if the request has a valid session ID cookie, generate a token for it
+>>> request=HttpRequest()
+>>> request.COOKIES['session_id']='abcde'
+>>> form=SafeForm(request=request)
+>>> form.csrf_token_field()
+u'<input type=\"hidden\" name=\"_csrf_token\" value=\"2376e3ffd767c170fab368189b7e4799\" id=\"id__csrf_token\" />'
+
+#if a user submits a form that doesn't have a csrf token at all, the form is not valid
+>>> form=SafeForm(request.POST,request=request)
+>>> form.is_valid()
+False
+>>> form.non_field_errors()
+[u'Your session has expired. Please refresh the page and submit the form again.']
+
+#if a user submits a form with an incorrect csrf token, the form is not valid.
+>>> request=HttpRequest()
+>>> request.POST['_csrf_token']='hello'
+>>> request.COOKIES['session_id']='abcde'
+>>> form=SafeForm(request.POST,request=request)
+>>> form.is_valid()
+False
+>>> form.non_field_errors()
+[u'Your session has expired. Please refresh the page and submit the form again.']
+
+#if a user submits a form with the correct token, only then should is_valid() be True
+>>> request=HttpRequest()
+>>> request.POST['_csrf_token']='2376e3ffd767c170fab368189b7e4799'
+>>> request.COOKIES['session_id']='abcde'
+>>> form=SafeForm(request.POST,request=request)
+>>> form.is_valid()
+True
+
+"""
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod()
Index: django/contrib/csrf/forms.py
===================================================================
--- django/contrib/csrf/forms.py	(revision 0)
+++ django/contrib/csrf/forms.py	(revision 0)
@@ -0,0 +1,59 @@
+from django import forms
+from django.conf import settings
+from django.utils.hashcompat import md5_constructor
+from django.utils.safestring import mark_safe
+
+class SafeForm(forms.Form):
+    """
+    Form that adds protection against Cross Site Request Forgeries by adding
+    a hidden field and checking for the correct value during validation.
+    
+    It works virtually the same as a regular form, with the exception of an
+    additional parameter passed to the constructor - an HttpRequest object.
+    It uses the request object to get the user's session ID.
+    
+    If the developer is manually specifying each field in their forms rather 
+    than calling form.as_table or some other helper, they will also need to 
+    add {{form.csrf_token_field}} somewhere inside the form in their template
+    
+    This form does not rely on django.contrib.sessions to work as long as 
+    whatever backend is ultimately used honors the settings.SESSION_COOKIE_NAME
+    setting. If that cookie is unset, safeform.is_valid() will always be false
+    """
+    
+    _csrf_token = forms.CharField(widget=forms.HiddenInput, required=False)
+    INVALID_TOKEN_MSG = "Your session has expired. Please refresh the "\
+                    + "page and submit the form again."
+    
+    def __init__(self, *args, **kwargs):
+        try:
+            self._request=kwargs.pop('request')
+        except KeyError:
+            raise ValueError("SafeForm must be given a HttpRequest object")
+        
+        super(SafeForm,self).__init__(*args, **kwargs)
+        
+        #We cannot set the initial in the field declaration because the 
+        #_make_token call needs the reference to "self"
+        self.fields['_csrf_token'].initial=self._make_token
+    
+    def clean(self):
+        session_token = self._make_token()
+        
+        if '_csrf_token' not in self.cleaned_data or self.cleaned_data['_csrf_token'] != session_token or session_token is None:
+            raise forms.ValidationError(self.INVALID_TOKEN_MSG)
+        
+        return self.cleaned_data
+        
+        
+    def _make_token(self):
+        try:
+            session_id = self._request.COOKIES[settings.SESSION_COOKIE_NAME]
+            return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
+        except KeyError:
+            #if the user does not have any cookies set, 
+            #a token cannot be generated
+            return None
+    
+    def csrf_token_field(self):
+        return mark_safe(unicode(self['_csrf_token']))
\ No newline at end of file
Index: AUTHORS
===================================================================
--- AUTHORS	(revision 9244)
+++ AUTHORS	(working copy)
@@ -425,6 +425,7 @@
     ymasuda@ethercube.com
     Jarek Zgoda <jarek.zgoda@gmail.com>
     Cheng Zhang
+    Elliott Mahler <join.together@gmail.com>
 
 A big THANK YOU goes to:
 
