diff --git a/django_browserid/tests/__init__.py b/django_browserid/tests/__init__.py index a61ee71..fc9ae00 100644 --- a/django_browserid/tests/__init__.py +++ b/django_browserid/tests/__init__.py @@ -8,7 +8,6 @@ from django.utils.functional import wraps from mock import patch -from nose.tools import eq_ from django_browserid.auth import BrowserIDBackend from django_browserid.base import MockVerifier @@ -63,7 +62,7 @@ def inner(*args, **kwargs): class TestCase(DjangoTestCase): def assert_json_equals(self, json_str, value): - return eq_(json.loads(smart_text(json_str)), value) + return self.assertEqual(json.loads(smart_text(json_str)), value) def shortDescription(self): # Stop nose using the test docstring and instead the test method diff --git a/django_browserid/tests/test_base.py b/django_browserid/tests/test_base.py index 6bb84bc..02470ac 100644 --- a/django_browserid/tests/test_base.py +++ b/django_browserid/tests/test_base.py @@ -11,8 +11,6 @@ import requests from mock import Mock, patch -from nose.plugins.skip import SkipTest -from nose.tools import eq_, ok_ from django_browserid import base from django_browserid.compat import pybrowserid_found @@ -30,7 +28,7 @@ def test_debug_true(self): run the checks. """ request = self.factory.get('/') - ok_(base.sanity_checks(request)) + self.assertTrue(base.sanity_checks(request)) @override_settings(DEBUG=False) def test_debug_false(self): @@ -39,7 +37,7 @@ def test_debug_false(self): run the checks. """ request = self.factory.get('/') - ok_(not base.sanity_checks(request)) + self.assertTrue(not base.sanity_checks(request)) @override_settings(BROWSERID_DISABLE_SANITY_CHECKS=True) def test_disable_sanity_checks(self): @@ -48,7 +46,7 @@ def test_disable_sanity_checks(self): checks. """ request = self.factory.get('/') - ok_(not base.sanity_checks(request)) + self.assertTrue(not base.sanity_checks(request)) @override_settings(BROWSERID_DISABLE_SANITY_CHECKS=False, SESSION_COOKIE_SECURE=True) def test_sanity_session_cookie(self): @@ -60,7 +58,7 @@ def test_sanity_session_cookie(self): request.is_secure = Mock(return_value=False) with patch('django_browserid.base.logger.warning') as warning: base.sanity_checks(request) - ok_(warning.called) + self.assertTrue(warning.called) @override_settings(BROWSERID_DISABLE_SANITY_CHECKS=False, MIDDLEWARE_CLASSES=['csp.middleware.CSPMiddleware']) @@ -77,7 +75,7 @@ def test_sanity_csp(self, warning): CSP_SCRIPT_SRC=['https://login.persona.org'], CSP_FRAME_SRC=['https://login.persona.org']): base.sanity_checks(request) - ok_(not warning.called) + self.assertTrue(not warning.called) warning.reset_mock() # Test fallback to default-src. @@ -85,7 +83,7 @@ def test_sanity_csp(self, warning): CSP_SCRIPT_SRC=[], CSP_FRAME_SRC=[]): base.sanity_checks(request) - ok_(not warning.called) + self.assertTrue(not warning.called) warning.reset_mock() # Test incorrect csp. @@ -93,7 +91,7 @@ def test_sanity_csp(self, warning): CSP_SCRIPT_SRC=[], CSP_FRAME_SRC=[]): base.sanity_checks(request) - ok_(warning.called) + self.assertTrue(warning.called) warning.reset_mock() # Test partial incorrectness. @@ -101,7 +99,7 @@ def test_sanity_csp(self, warning): CSP_SCRIPT_SRC=['https://login.persona.org'], CSP_FRAME_SRC=[]): base.sanity_checks(request) - ok_(warning.called) + self.assertTrue(warning.called) @override_settings(BROWSERID_DISABLE_SANITY_CHECKS=False, MIDDLEWARE_CLASSES=['csp.middleware.CSPMiddleware']) @@ -122,19 +120,19 @@ def test_unset_csp(self, warning): with self.settings(**setting_kwargs): del settings.CSP_DEFAULT_SRC base.sanity_checks(request) - ok_(not warning.called) + self.assertTrue(not warning.called) warning.reset_mock() with self.settings(**setting_kwargs): del settings.CSP_FRAME_SRC base.sanity_checks(request) - ok_(not warning.called) + self.assertTrue(not warning.called) warning.reset_mock() with self.settings(**setting_kwargs): del settings.CSP_SCRIPT_SRC base.sanity_checks(request) - ok_(not warning.called) + self.assertTrue(not warning.called) warning.reset_mock() @@ -165,7 +163,7 @@ def test_same_origin_found(self): audiences = ['https://example.com', 'http://testserver'] with self.settings(BROWSERID_AUDIENCES=audiences, DEBUG=False): - eq_(base.get_audience(request), 'http://testserver') + self.assertEqual(base.get_audience(request), 'http://testserver') def test_no_audience(self): """ @@ -189,7 +187,7 @@ def test_missing_setting_but_in_debug(self): with patch('django_browserid.base.settings') as settings: del settings.BROWSERID_AUDIENCES settings.DEBUG = True - eq_(base.get_audience(request), 'http://testserver') + self.assertEqual(base.get_audience(request), 'http://testserver') def test_no_audience_but_in_debug(self): """ @@ -200,7 +198,7 @@ def test_no_audience_but_in_debug(self): # Simulate that no BROWSERID_AUDIENCES has been set with self.settings(BROWSERID_AUDIENCES=[], DEBUG=True): - eq_(base.get_audience(request), 'http://testserver') + self.assertEqual(base.get_audience(request), 'http://testserver') class VerificationResultTests(TestCase): @@ -210,7 +208,7 @@ def test_getattr_attribute_exists(self): attribute on the result. """ result = base.VerificationResult({'myattr': 'foo'}) - eq_(result.myattr, 'foo') + self.assertEqual(result.myattr, 'foo') def test_getattr_attribute_doesnt_exist(self): """ @@ -236,7 +234,7 @@ def test_expires_invalid_timestamp(self): the raw string instead. """ result = base.VerificationResult({'expires': 'foasdfhas'}) - eq_(result.expires, 'foasdfhas') + self.assertEqual(result.expires, 'foasdfhas') def test_expires_valid_timestamp(self): """ @@ -244,20 +242,20 @@ def test_expires_valid_timestamp(self): corresponding datetime. """ result = base.VerificationResult({'expires': '1379307128000'}) - eq_(datetime(2013, 9, 16, 4, 52, 8), result.expires) + self.assertEqual(datetime(2013, 9, 16, 4, 52, 8), result.expires) def test_nonzero_failure(self): """ If the response status is not 'okay', the result should be falsy. """ - ok_(not base.VerificationResult({'status': 'failure'})) + self.assertTrue(not base.VerificationResult({'status': 'failure'})) def test_nonzero_okay(self): """ If the response status is 'okay', the result should be truthy. """ - ok_(base.VerificationResult({'status': 'okay'})) + self.assertTrue(base.VerificationResult({'status': 'okay'})) def test_str_success(self): """ @@ -265,23 +263,23 @@ def test_str_success(self): the string. """ result = base.VerificationResult({'status': 'okay', 'email': 'a@example.com'}) - eq_(six.text_type(result), '') + self.assertEqual(six.text_type(result), '') # If the email is missing, don't include it. result = base.VerificationResult({'status': 'okay'}) - eq_(six.text_type(result), '') + self.assertEqual(six.text_type(result), '') def test_str_failure(self): """ If the result is a failure, include 'Failure' in the string. """ result = base.VerificationResult({'status': 'failure'}) - eq_(six.text_type(result), '') + self.assertEqual(six.text_type(result), '') def test_str_unicode(self): """Ensure that __str__ can handle unicode values.""" result = base.VerificationResult({'status': 'okay', 'email': six.u('\x80@example.com')}) - eq_(six.text_type(result), six.u('')) + self.assertEqual(six.text_type(result), six.u('')) class RemoteVerifierTests(TestCase): @@ -302,7 +300,7 @@ class MyVerifier(base.RemoteVerifier): verifier.verify('asdf', 'http://testserver') # foo parameter passed with 'bar' value. - eq_(post.call_args[1]['foo'], 'bar') + self.assertEqual(post.call_args[1]['foo'], 'bar') def test_verify_kwargs(self): """ @@ -316,8 +314,8 @@ def test_verify_kwargs(self): verifier.verify('asdf', 'http://testserver', foo='bar', baz=5) # foo parameter passed with 'bar' value. - eq_(post.call_args[1]['data']['foo'], 'bar') - eq_(post.call_args[1]['data']['baz'], 5) + self.assertEqual(post.call_args[1]['data']['foo'], 'bar') + self.assertEqual(post.call_args[1]['data']['baz'], 5) def test_verify_request_exception(self): """ @@ -332,7 +330,7 @@ def test_verify_request_exception(self): with self.assertRaises(base.BrowserIDException) as cm: verifier.verify('asdf', 'http://testserver') - eq_(cm.exception.exc, request_exception) + self.assertEqual(cm.exception.exc, request_exception) def test_verify_invalid_json(self): """ @@ -345,9 +343,8 @@ def test_verify_invalid_json(self): response.json.side_effect = ValueError("Couldn't parse json") post.return_value = response result = verifier.verify('asdf', 'http://testserver') - ok_(not result) - ok_(result.reason.startswith('Could not parse verifier response')) - + self.assertTrue(not result) + self.assertTrue(result.reason.startswith('Could not parse verifier response')) def test_verify_success(self): """ @@ -362,8 +359,8 @@ def test_verify_success(self): response.json.return_value = {"status": "okay", "email": "foo@example.com"} post.return_value = response result = verifier.verify('asdf', 'http://testserver') - ok_(result) - eq_(result.email, 'foo@example.com') + self.assertTrue(result) + self.assertEqual(result.email, 'foo@example.com') class MockVerifierTests(TestCase): @@ -374,8 +371,8 @@ def test_verify_no_email(self): """ verifier = base.MockVerifier(None) result = verifier.verify('asdf', 'http://testserver') - ok_(not result) - eq_(result.reason, 'No email given to MockVerifier.') + self.assertTrue(not result) + self.assertEqual(result.reason, 'No email given to MockVerifier.') def test_verify_email(self): """ @@ -384,23 +381,23 @@ def test_verify_email(self): """ verifier = base.MockVerifier('a@example.com') result = verifier.verify('asdf', 'http://testserver') - ok_(result) - eq_(result.audience, 'http://testserver') - eq_(result.email, 'a@example.com') + self.assertTrue(result) + self.assertEqual(result.audience, 'http://testserver') + self.assertEqual(result.email, 'a@example.com') def test_verify_result_attributes(self): """Extra kwargs to the constructor are added to the result.""" verifier = base.MockVerifier('a@example.com', foo='bar', baz=5) result = verifier.verify('asdf', 'http://testserver') - eq_(result.foo, 'bar') - eq_(result.baz, 5) + self.assertEqual(result.foo, 'bar') + self.assertEqual(result.baz, 5) class LocalVerifierTests(TestCase): def setUp(self): # Skip tests if PyBrowserID is not installed. if not pybrowserid_found: - raise SkipTest + self.skipTest('PyBrowserID required for test but not installed.') self.verifier = base.LocalVerifier() diff --git a/django_browserid/tests/test_helpers.py b/django_browserid/tests/test_helpers.py index bc0150e..d9d3dcb 100644 --- a/django_browserid/tests/test_helpers.py +++ b/django_browserid/tests/test_helpers.py @@ -1,7 +1,6 @@ from django.utils.functional import lazy from mock import patch -from nose.tools import eq_ from django_browserid import helpers from django_browserid.tests import TestCase @@ -22,7 +21,7 @@ def test_defaults(self): with self.settings(BROWSERID_REQUEST_ARGS={'foo': 'bar', 'baz': 1}): output = helpers.browserid_info() - eq_(output, self.render_to_string.return_value) + self.assertEqual(output, self.render_to_string.return_value) expected_info = { 'loginUrl': '/browserid/login/', 'logoutUrl': '/browserid/logout/', @@ -35,7 +34,7 @@ def test_lazy_request_args(self): with self.settings(BROWSERID_REQUEST_ARGS=lazy_request_args()): output = helpers.browserid_info() - eq_(output, self.render_to_string.return_value) + self.assertEqual(output, self.render_to_string.return_value) expected_info = { 'loginUrl': '/browserid/login/', 'logoutUrl': '/browserid/logout/', diff --git a/django_browserid/tests/test_http.py b/django_browserid/tests/test_http.py index e577e72..1d76c2f 100644 --- a/django_browserid/tests/test_http.py +++ b/django_browserid/tests/test_http.py @@ -1,5 +1,3 @@ -from nose.tools import eq_ - from django_browserid.http import JSONResponse from django_browserid.tests import TestCase @@ -8,13 +6,13 @@ class JSONResponseTests(TestCase): def test_basic(self): response = JSONResponse({'blah': 'foo', 'bar': 7}) self.assert_json_equals(response.content, {'blah': 'foo', 'bar': 7}) - eq_(response.status_code, 200) + self.assertEqual(response.status_code, 200) response = JSONResponse(['baz', {'biff': False}]) self.assert_json_equals(response.content, ['baz', {'biff': False}]) - eq_(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_status(self): response = JSONResponse({'blah': 'foo', 'bar': 7}, status=404) self.assert_json_equals(response.content, {'blah': 'foo', 'bar': 7}) - eq_(response.status_code, 404) + self.assertEqual(response.status_code, 404) diff --git a/django_browserid/tests/test_util.py b/django_browserid/tests/test_util.py index 5f716ed..a5b28cd 100644 --- a/django_browserid/tests/test_util.py +++ b/django_browserid/tests/test_util.py @@ -5,8 +5,6 @@ from django.utils import six from django.utils.functional import lazy -from nose.tools import eq_ - from django_browserid.tests import TestCase from django_browserid.util import import_from_setting, LazyEncoder @@ -20,7 +18,7 @@ class TestLazyEncoder(TestCase): def test_lazy(self): thing = ['foo', lazy_string] thing_json = json.dumps(thing, cls=LazyEncoder) - eq_('["foo", "blah"]', thing_json) + self.assertEqual('["foo", "blah"]', thing_json) import_value = 1 diff --git a/django_browserid/tests/test_views.py b/django_browserid/tests/test_views.py index 7c0187f..8771307 100644 --- a/django_browserid/tests/test_views.py +++ b/django_browserid/tests/test_views.py @@ -2,15 +2,13 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. from django.contrib import auth +from django.middleware.csrf import get_token, rotate_token from django.test.client import RequestFactory -from django.template import Context from django.utils import six -from django.utils.functional import lazy -from mock import Mock, patch, PropertyMock -from nose.tools import eq_, ok_ +from mock import Mock, patch -from django_browserid import BrowserIDException, views +from django_browserid import views from django_browserid.tests import mock_browserid, TestCase @@ -20,8 +18,8 @@ class TestView(views.JSONView): def get(self, request, *args, **kwargs): return 'asdf' response = TestView().http_method_not_allowed() - eq_(response.status_code, 405) - ok_(set(['GET']).issubset(set(response['Allow'].split(', ')))) + self.assertEqual(response.status_code, 405) + self.assertTrue(set(['GET']).issubset(set(response['Allow'].split(', ')))) self.assert_json_equals(response.content, {'error': 'Method not allowed.'}) def test_http_method_not_allowed_allowed_methods(self): @@ -32,7 +30,7 @@ def get(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): return 'qwer' response = GetPostView().http_method_not_allowed() - ok_(set(['GET', 'POST']).issubset(set(response['Allow'].split(', ')))) + self.assertTrue(set(['GET', 'POST']).issubset(set(response['Allow'].split(', ')))) class GetPostPutDeleteHeadView(views.JSONView): def get(self, request, *args, **kwargs): @@ -52,7 +50,7 @@ def head(self, request, *args, **kwargs): response = GetPostPutDeleteHeadView().http_method_not_allowed() expected_methods = set(['GET', 'POST', 'PUT', 'DELETE', 'HEAD']) actual_methods = set(response['Allow'].split(', ')) - ok_(expected_methods.issubset(actual_methods)) + self.assertTrue(expected_methods.issubset(actual_methods)) class GetNextTests(TestCase): @@ -62,7 +60,7 @@ def setUp(self): def test_no_param(self): """If next isn't in the POST params, return None.""" request = self.factory.post('/') - eq_(views._get_next(request), None) + self.assertEqual(views._get_next(request), None) def test_is_safe(self): """Return the value of next if it is considered safe.""" @@ -70,7 +68,7 @@ def test_is_safe(self): request.get_host = lambda: 'myhost' with patch.object(views, 'is_safe_url', return_value=True) as is_safe_url: - eq_(views._get_next(request), '/asdf') + self.assertEqual(views._get_next(request), '/asdf') is_safe_url.assert_called_with('/asdf', host='myhost') def test_isnt_safe(self): @@ -79,7 +77,7 @@ def test_isnt_safe(self): request.get_host = lambda: 'myhost' with patch.object(views, 'is_safe_url', return_value=False) as is_safe_url: - eq_(views._get_next(request), None) + self.assertEqual(views._get_next(request), None) is_safe_url.assert_called_with('/asdf', host='myhost') @@ -107,7 +105,7 @@ def test_no_assertion(self): """If no assertion is given, return a failure result.""" with self.settings(LOGIN_REDIRECT_URL_FAILURE='/fail'): response = self.verify('post', blah='asdf') - eq_(response.status_code, 403) + self.assertEqual(response.status_code, 403) self.assert_json_equals(response.content, {'redirect': '/fail'}) @mock_browserid(None) @@ -115,7 +113,7 @@ def test_auth_fail(self): """If authentication fails, redirect to the failure URL.""" with self.settings(LOGIN_REDIRECT_URL_FAILURE='/fail'): response = self.verify('post', assertion='asdf') - eq_(response.status_code, 403) + self.assertEqual(response.status_code, 403) self.assert_json_equals(response.content, {'redirect': '/fail'}) @mock_browserid('test@example.com') @@ -130,7 +128,7 @@ def test_auth_success_redirect_success(self): response = verify(request) login.assert_called_with(request, user) - eq_(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assert_json_equals(response.content, {'email': 'test@example.com', 'redirect': '/success'}) @@ -138,7 +136,7 @@ def test_sanity_checks(self): """Run sanity checks on all incoming requests.""" with patch('django_browserid.views.sanity_checks') as sanity_checks: self.verify('post') - ok_(sanity_checks.called) + self.assertTrue(sanity_checks.called) @patch('django_browserid.views.auth.login') def test_login_success_no_next(self, *args): @@ -193,7 +191,7 @@ def test_redirect(self): response = logout(request) auth_logout.assert_called_with(request) - eq_(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assert_json_equals(response.content, {'redirect': '/test/foo'}) def test_redirect_next(self): @@ -216,32 +214,24 @@ def setUp(self): self.factory = RequestFactory() self.view = views.CsrfToken() - def test_lazy_token_called(self): - """ - If the csrf_token variable in the RequestContext is a lazy - callable, make sure it is called during the view. - """ - global _lazy_csrf_token_called - _lazy_csrf_token_called = False + def test_session_csrf(self): + request = self.factory.get('/browserid/csrf/') + request.csrf_token = 'asdf' - # I'd love to use a Mock here instead, but lazy doesn't behave - # well with Mocks for some reason. - def _lazy_csrf_token(): - global _lazy_csrf_token_called - _lazy_csrf_token_called = True - return 'asdf' - csrf_token = lazy(_lazy_csrf_token, six.text_type)() + response = self.view.get(request) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, b'asdf') + def test_django_csrf(self): request = self.factory.get('/browserid/csrf/') - with patch('django_browserid.views.RequestContext') as RequestContext: - RequestContext.return_value = Context({'csrf_token': csrf_token}) - response = self.view.get(request) + rotate_token(request) + token = get_token(request) - eq_(response.status_code, 200) - eq_(response.content, b'asdf') - ok_(_lazy_csrf_token_called) + response = self.view.get(request) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content, six.b(token)) def test_never_cache(self): request = self.factory.get('/browserid/csrf/') response = self.view.get(request) - eq_(response['Cache-Control'], 'max-age=0') + self.assertEqual(response['Cache-Control'], 'max-age=0') diff --git a/django_browserid/views.py b/django_browserid/views.py index 7df0ef3..ce963cf 100644 --- a/django_browserid/views.py +++ b/django_browserid/views.py @@ -6,8 +6,7 @@ from django.conf import settings from django.contrib import auth from django.http import HttpResponse -from django.template import RequestContext -from django.utils import six +from django.middleware.csrf import get_token from django.utils.http import is_safe_url from django.views.decorators.cache import never_cache from django.views.generic import View @@ -108,27 +107,13 @@ class CsrfToken(JSONView): """Fetch a CSRF token for the frontend JavaScript.""" @never_cache def get(self, request): - # Different CSRF libraries (namely session_csrf) store the CSRF - # token in different places. The only way to retrieve the token - # that works with both the built-in CSRF and session_csrf is to - # pull it from the template context processors via - # RequestContext. - context = RequestContext(request) - - try: - # In Django 1.8+, the RequestContext only runs the context processors - # when it is bound to a template. - from django.template import engines - # Create an empty template from the first configured template engine. - template_wrapper = engines.all()[0].from_string("") - with context.bind_template(template_wrapper.template): - csrf_token = context.get('csrf_token', '') - except ImportError: - csrf_token = context.get('csrf_token', '') - - # csrf_token might be a lazy value that triggers side-effects, - # so we need to force it to a string. - csrf_token = six.text_type(csrf_token) + # Different CSRF libraries store the CSRF token in different + # places. Here we support both standard Django CSRF and the + # django-session-csrf library. + if hasattr(request, 'csrf_token'): + csrf_token = request.csrf_token + else: + csrf_token = get_token(request) return HttpResponse(csrf_token) diff --git a/requirements.txt b/requirements.txt index 0c86583..0cc1350 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,6 @@ PyBrowserID>=0.9.2 # Optional, required for building documentation. # Tests mock>=0.8.0 Django>=1.3 -nose>=1.3.6 # Documentation sphinx>=1.2