1+ from contextlib import contextmanager
2+
13import django .test
24from django import http
35from django .conf .urls .defaults import patterns
1214
1315import mock
1416
17+ import session_csrf
1518from session_csrf import CsrfMiddleware , anonymous_csrf , anonymous_csrf_exempt
1619
1720
@@ -28,6 +31,11 @@ class TestCsrfToken(django.test.TestCase):
2831 def setUp (self ):
2932 self .client .handler = ClientHandler ()
3033 User .objects .create_user ('jbalogh' , 'j@moz.com' , 'password' )
34+ self .save_ANON_ALWAYS = session_csrf .ANON_ALWAYS
35+ session_csrf .ANON_ALWAYS = False
36+
37+ def tearDown (self ):
38+ session_csrf .ANON_ALWAYS = self .save_ANON_ALWAYS
3139
3240 def login (self ):
3341 assert self .client .login (username = 'jbalogh' , password = 'password' )
@@ -155,6 +163,11 @@ def setUp(self):
155163 self .rf = django .test .RequestFactory ()
156164 User .objects .create_user ('jbalogh' , 'j@moz.com' , 'password' )
157165 self .client .handler = ClientHandler (enforce_csrf_checks = True )
166+ self .save_ANON_ALWAYS = session_csrf .ANON_ALWAYS
167+ session_csrf .ANON_ALWAYS = False
168+
169+ def tearDown (self ):
170+ session_csrf .ANON_ALWAYS = self .save_ANON_ALWAYS
158171
159172 def login (self ):
160173 assert self .client .login (username = 'jbalogh' , password = 'password' )
@@ -238,6 +251,82 @@ def test_anonymous_csrf_exempt(self):
238251 self .assertEqual (response .status_code , 403 )
239252
240253
254+ class TestAnonAlways (django .test .TestCase ):
255+ # Repeats some tests with ANON_ALWAYS = True
256+ urls = 'session_csrf.tests'
257+
258+ def setUp (self ):
259+ self .token = 'a' * 32
260+ self .rf = django .test .RequestFactory ()
261+ User .objects .create_user ('jbalogh' , 'j@moz.com' , 'password' )
262+ self .client .handler = ClientHandler (enforce_csrf_checks = True )
263+ self .save_ANON_ALWAYS = session_csrf .ANON_ALWAYS
264+ session_csrf .ANON_ALWAYS = True
265+
266+ def tearDown (self ):
267+ session_csrf .ANON_ALWAYS = self .save_ANON_ALWAYS
268+
269+ def login (self ):
270+ assert self .client .login (username = 'jbalogh' , password = 'password' )
271+
272+ def test_csrftoken_unauthenticated (self ):
273+ # request.csrf_token is set for anonymous users
274+ # when ANON_ALWAYS is enabled.
275+ response = self .client .get ('/' , follow = True )
276+ # The CSRF token is a 32-character MD5 string.
277+ self .assertEqual (len (response ._request .csrf_token ), 32 )
278+
279+ def test_authenticated_request (self ):
280+ # Nothing special happens, nothing breaks.
281+ # Find the CSRF token in the session.
282+ self .login ()
283+ response = self .client .get ('/' , follow = True )
284+ sessionid = response .cookies ['sessionid' ].value
285+ session = Session .objects .get (session_key = sessionid )
286+ token = session .get_decoded ()['csrf_token' ]
287+
288+ response = self .client .post ('/' , follow = True , HTTP_X_CSRFTOKEN = token )
289+ self .assertEqual (response .status_code , 200 )
290+
291+ def test_unauthenticated_request (self ):
292+ # We get a 403 since we're not sending a token.
293+ response = self .client .post ('/' )
294+ self .assertEqual (response .status_code , 403 )
295+
296+ def test_new_anon_token_on_request (self ):
297+ # A new anon user gets a key+token on the request and response.
298+ response = self .client .get ('/' )
299+ # Get the key from the cookie and find the token in the cache.
300+ key = response .cookies ['anoncsrf' ].value
301+ self .assertEqual (response ._request .csrf_token , cache .get (key ))
302+
303+ def test_existing_anon_cookie_on_request (self ):
304+ # We reuse an existing anon cookie key+token.
305+ response = self .client .get ('/' )
306+ key = response .cookies ['anoncsrf' ].value
307+
308+ # Now check that subsequent requests use that cookie.
309+ response = self .client .get ('/' )
310+ self .assertEqual (response .cookies ['anoncsrf' ].value , key )
311+ self .assertEqual (response ._request .csrf_token , cache .get (key ))
312+ self .assertEqual (response ['Vary' ], 'Cookie' )
313+
314+ def test_anon_csrf_logout (self ):
315+ # Beware of views that logout the user.
316+ self .login ()
317+ response = self .client .get ('/logout' )
318+ self .assertEqual (response .status_code , 200 )
319+
320+ def test_existing_anon_cookie_not_in_cache (self ):
321+ response = self .client .get ('/' )
322+ self .assertEqual (len (response ._request .csrf_token ), 32 )
323+
324+ # Clear cache and make sure we still get a token
325+ cache .clear ()
326+ response = self .client .get ('/' )
327+ self .assertEqual (len (response ._request .csrf_token ), 32 )
328+
329+
241330class ClientHandler (django .test .client .ClientHandler ):
242331 """
243332 Handler that stores the real request object on the response.
0 commit comments