diff --git a/.travis.yml b/.travis.yml index 165b098..6862435 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: python sudo: false python: - "2.7" + - "3.5" env: - DJANGO="Django>=1.8.0,<1.9.0" - DJANGO="Django>=1.9.0,<1.10.0" diff --git a/djangowind/auth.py b/djangowind/auth.py index a89753c..254db90 100644 --- a/djangowind/auth.py +++ b/djangowind/auth.py @@ -1,7 +1,28 @@ +from __future__ import unicode_literals + from django.conf import settings from django.contrib.auth.models import User, Group -import urllib -import urllib2 + +try: + from urllib.request import Request +except ImportError: + from urllib2 import Request + +try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen + +try: + from urllib.parse import urlencode +except ImportError: + from urllib import urlencode + +try: + from urllib.parse import quote +except ImportError: + from urllib2 import quote + from django.core.exceptions import ImproperlyConfigured from warnings import warn from django_statsd.clients import statsd @@ -22,7 +43,7 @@ def validate_wind_ticket(ticketid): if hasattr(settings, 'WIND_BASE'): wind_base = getattr(settings, 'WIND_BASE') uri = wind_base + "validate?ticketid=%s" % ticketid - response = urllib.urlopen(uri).read() + response = urlopen(uri).read() lines = response.split("\n") if lines[0] == "yes": statsd.incr('djangowind.validate_wind_ticket.success') @@ -51,8 +72,8 @@ def validate_cas2_ticket(ticketid, url): cas_base = getattr(settings, 'CAS_BASE') uri = cas_base + "cas/serviceValidate?ticket=%s&service=%s" % ( ticketid, - urllib2.quote(url)) - response = urllib.urlopen(uri).read() + quote(url)) + response = urlopen(uri).read() try: dom = parseString(response) if dom.documentElement.nodeName != 'cas:serviceResponse': @@ -138,12 +159,12 @@ def validate_saml_ticket(ticketid, url): 'connection': 'keep-alive', 'content-type': 'text/xml'} params = {'TARGET': url} - uri = cas_base + "cas/samlValidate" + '?' + urllib.urlencode(params) - url = urllib2.Request(uri, '', headers) + uri = cas_base + "cas/samlValidate" + '?' + urlencode(params) + request = Request(uri, '', headers) data = get_saml_assertion(ticketid) - url.add_data(data) + request.data = data - page = urllib2.urlopen(url) + page = urlopen(request) response = page.read() try: user = None @@ -240,10 +261,10 @@ def load_handler(self, path): module, attr = path[:i], path[i + 1:] try: mod = __import__(module, {}, {}, [attr]) - except ImportError, e: + except ImportError as e: raise ImproperlyConfigured( 'Error importing wind handler %s: "%s"' % (module, e)) - except ValueError, e: + except ValueError as e: raise ImproperlyConfigured('Error importing wind handler.') try: cls = getattr(mod, attr) diff --git a/djangowind/context.py b/djangowind/context.py index e66aa79..22e8845 100644 --- a/djangowind/context.py +++ b/djangowind/context.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django.conf import settings from django.contrib.auth.forms import AuthenticationForm diff --git a/djangowind/tests/test_auth.py b/djangowind/tests/test_auth.py index 8c356c3..2fc0ff4 100644 --- a/djangowind/tests/test_auth.py +++ b/djangowind/tests/test_auth.py @@ -1,5 +1,16 @@ +from __future__ import unicode_literals + +try: + from http.client import HTTPResponse +except ImportError: + from httplib import HTTPResponse + +try: + from unittest.mock import Mock, patch +except ImportError: + from mock import Mock, patch + from django.test import TestCase -from httpretty import HTTPretty, httprettified from djangowind.auth import validate_wind_ticket, WindAuthBackend from djangowind.auth import validate_cas2_ticket, CAS2AuthBackend from djangowind.auth import validate_saml_ticket, SAMLAuthBackend @@ -9,79 +20,78 @@ import os.path +@patch('djangowind.auth.urlopen') class ValidateWindTicketTest(TestCase): - def test_no_ticket(self): + def setUp(self): + self.response = Mock(spec=HTTPResponse) + + def test_no_ticket(self, mock_urlopen): self.assertEqual( validate_wind_ticket(""), (False, 'no ticketid', '')) - @httprettified - def test_validate_ticket_success(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://wind.columbia.edu/validate?ticket=foo", - body="yes\nanders" - ) + def test_validate_ticket_success(self, mock_urlopen): + self.response.read.return_value = 'yes\nanders' + mock_urlopen.return_value = self.response + self.assertEqual( validate_wind_ticket("foo"), (True, 'anders', ['anders'])) + mock_urlopen.assert_called_with( + 'https://wind.columbia.edu/validate?ticketid=foo') + + def test_validate_ticket_success_with_groups(self, mock_urlopen): + self.response.read.return_value = "yes\nanders\ngroup1\ngroup2" + mock_urlopen.return_value = self.response - @httprettified - def test_validate_ticket_success_with_groups(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://wind.columbia.edu/validate?ticket=foo", - body="yes\nanders\ngroup1\ngroup2" - ) self.assertEqual( validate_wind_ticket("foo"), (True, 'anders', ['anders', 'group1', 'group2'])) + mock_urlopen.assert_called_with( + 'https://wind.columbia.edu/validate?ticketid=foo') + + def test_validate_ticket_fail(self, mock_urlopen): + self.response.read.return_value = 'no\nanders' + mock_urlopen.return_value = self.response - @httprettified - def test_validate_ticket_fail(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://wind.columbia.edu/validate?ticket=foo", - body="no\nanders" - ) self.assertEqual( validate_wind_ticket("foo"), (False, "The ticket was already used or was invalid.", [])) + mock_urlopen.assert_called_with( + 'https://wind.columbia.edu/validate?ticketid=foo') + + def test_validate_ticket_invalid_response(self, mock_urlopen): + self.response.read.return_value = \ + "holy crap! I'm not a valid WIND response!" + mock_urlopen.return_value = self.response - @httprettified - def test_validate_ticket_invalid_response(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://wind.columbia.edu/validate?ticket=foo", - body="holy crap! I'm not a valid WIND response!" - ) self.assertEqual( validate_wind_ticket("foo"), (False, "WIND did not return a valid response.", [])) + mock_urlopen.assert_called_with( + 'https://wind.columbia.edu/validate?ticketid=foo') + + def test_validate_ticket_alternate_wind_base(self, mock_urlopen): + self.response.read.return_value = 'yes\nanders' + mock_urlopen.return_value = self.response - @httprettified - def test_validate_ticket_alternate_wind_base(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://foo.example.com/validate?ticket=foo", - body="yes\nanders" - ) with self.settings(WIND_BASE="https://foo.example.com/"): self.assertEqual( validate_wind_ticket("foo"), (True, 'anders', ['anders'])) + mock_urlopen.assert_called_with( + 'https://foo.example.com/validate?ticketid=foo') +@patch('djangowind.auth.urlopen') class ValidateTRCasTicketTest(TestCase): - @httprettified - def test_validate_ticket_success(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.example.com/cas/serviceValidate?" - "ticket=foo&service=https%3A//" - "slank.ccnmtl.columbia.edu/accounts/caslogin/%3Fnext%3D/"), - body=tr_affils() - ) + def setUp(self): + self.response = Mock(spec=HTTPResponse) + + def test_validate_ticket_success(self, mock_urlopen): + self.response.read.return_value = tr_affils() + mock_urlopen.return_value = self.response + with self.settings(CAS_BASE="https://cas.example.com/"): self.assertEqual( validate_cas2_ticket( @@ -90,118 +100,117 @@ def test_validate_ticket_success(self): "accounts/caslogin/?next=/")), (True, "test_claim", ["test_claim", "crs-3", "crs-1"])) + mock_urlopen.assert_called_with( + "https://cas.example.com/cas/serviceValidate?" + "ticket=foo&service=https%3A//" + "slank.ccnmtl.columbia.edu/accounts/caslogin/%3Fnext%3D/") +@patch('djangowind.auth.urlopen') class ValidateCas2TicketTest(TestCase): - def test_no_ticket(self): + def setUp(self): + self.response = Mock(spec=HTTPResponse) + + def test_no_ticket(self, mock_urlopen): self.assertEqual( validate_cas2_ticket("", ""), (False, 'no ticketid', '')) - @httprettified - def test_validate_ticket_success(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?ticket=foo" - "&https%3A//slank.ccnmtl.columbia.edu/accounts/" - "caslogin/?next=/"), - body=( - "\n\n\n\n\t\n" - "\t\tanp8\n" - "\n" - "\n" - "\t\n" - "\n") - ) + def test_validate_ticket_success(self, mock_urlopen): + self.response.read.return_value = ( + "\n\n\n\n\t\n" + "\t\tanp8\n" + "\n" + "\n" + "\t\n" + "\n") + mock_urlopen.return_value = self.response + self.assertEqual( validate_cas2_ticket( "foo", "https://slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/"), (True, 'anp8', ['anp8'])) - - @httprettified - def test_validate_ticket_success_with_groups(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?ticket=foo" - "&https%3A//slank.ccnmtl.columbia.edu/accounts/" - "caslogin/?next=/"), - body=( - "\n\n\n\n\t\n" - "\t\tanp8\n" - "\t\t\n" - "\t\t\tgroup1\n" - "\t\t\tgroup2\n" - "\t\t\n" - "\n" - "\n" - "\t\n" - "\n") - ) + mock_urlopen.assert_called_with( + "https://cas.columbia.edu/cas/serviceValidate?ticket=foo" + "&service=https%3A//slank.ccnmtl.columbia.edu/accounts/" + "caslogin/%3Fnext%3D/") + + def test_validate_ticket_success_with_groups(self, mock_urlopen): + self.response.read.return_value = ( + "\n\n\n\n\t\n" + "\t\tanp8\n" + "\t\t\n" + "\t\t\tgroup1\n" + "\t\t\tgroup2\n" + "\t\t\n" + "\n" + "\n" + "\t\n" + "\n") + mock_urlopen.return_value = self.response self.assertEqual( validate_cas2_ticket( "foo", "https://slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/"), (True, 'anp8', ['anp8', 'group1', 'group2'])) + mock_urlopen.assert_called_with( + "https://cas.columbia.edu/cas/serviceValidate?ticket=foo" + "&service=https%3A//slank.ccnmtl.columbia.edu/accounts/" + "caslogin/%3Fnext%3D/") + + def test_validate_ticket_fail(self, mock_urlopen): + self.response.read.return_value = ( + "\n\n\n\n\t\n\t\tticket 'ST-181952-OK0" + "qr5suLueHccqPfgIT-idmcasprod2' does not match supp" + "lied service. The original service was 'https://" + "slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/'" + "and the supplied service was 'https://slank.ccnmtl." + "columbia.edu/accounts/caslogin/'.\n\t\n") + mock_urlopen.return_value = self.response - @httprettified - def test_validate_ticket_fail(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?" - "ticket=foo&https%3A//slank.ccnmtl.columbia.edu/" - "accounts/caslogin/?next=/"), - body=( - "\n\n\n\n\t\n\t\tticket 'ST-181952-OK0" - "qr5suLueHccqPfgIT-idmcasprod2' does not match supp" - "lied service. The original service was 'https://" - "slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/'" - "and the supplied service was 'https://slank.ccnmtl." - "columbia.edu/accounts/caslogin/'.\n\t\n") - ) self.assertEqual( validate_cas2_ticket( "foo", "https://slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/"), (False, "The ticket was already used or was invalid.", [])) + mock_urlopen.assert_called_with( + "https://cas.columbia.edu/cas/serviceValidate?ticket=foo" + "&service=https%3A//slank.ccnmtl.columbia.edu/accounts/" + "caslogin/%3Fnext%3D/") + + def test_validate_ticket_invalid_response(self, mock_urlopen): + self.response.read.return_value = \ + "holy crap! I'm not a valid CAS response!" + mock_urlopen.return_value = self.response - @httprettified - def test_validate_ticket_invalid_response(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?" - "ticket=foo&https%3A//slank.ccnmtl.columbia.edu/" - "accounts/caslogin/?next=/"), - body="holy crap! I'm not a valid CAS response!" - ) self.assertEqual( validate_cas2_ticket( "foo", "https://slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/"), (False, "CAS did not return a valid response.", [])) + mock_urlopen.assert_called_with( + "https://cas.columbia.edu/cas/serviceValidate?ticket=foo" + "&service=https%3A//slank.ccnmtl.columbia.edu/accounts/" + "caslogin/%3Fnext%3D/") + + def test_validate_ticket_alternate_case_base(self, mock_urlopen): + self.response.read.return_value = ( + "\n\n\n\n\t\n" + "\t\tanp8\n" + "\n" + "\n" + "\t\n" + "\n") + mock_urlopen.return_value = self.response - @httprettified - def test_validate_ticket_alternate_case_base(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.example.com/cas/serviceValidate?ticket=foo" - "&https%3A//slank.ccnmtl.columbia.edu/accounts/" - "caslogin/?next=/"), - body=( - "\n\n\n\n\t\n" - "\t\tanp8\n" - "\n" - "\n" - "\t\n" - "\n") - ) with self.settings(CAS_BASE="https://cas.example.com/"): self.assertEqual( validate_cas2_ticket( @@ -209,25 +218,28 @@ def test_validate_ticket_alternate_case_base(self): ("https://slank.ccnmtl.columbia.edu/accounts/" "caslogin/?next=/")), (True, 'anp8', ['anp8'])) + mock_urlopen.assert_called_with( + "https://cas.example.com/cas/serviceValidate?ticket=foo" + "&service=https%3A//slank.ccnmtl.columbia.edu/accounts/" + "caslogin/%3Fnext%3D/") - @httprettified - def test_validate_tr_success(self): + def test_validate_tr_success(self, mock_urlopen): """ for teachrecovery, we authenticate against a drupal CAS server. The documented response looks like this: https://gist.github.com/cravecode/6679b68d14a7250c8fe9 """ - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?ticket=foo" - "&https%3A//slank.ccnmtl.columbia.edu/accounts/" - "caslogin/?next=/"), - body=TR_SUCCESS, - ) + self.response.read.return_value = TR_SUCCESS + mock_urlopen.return_value = self.response + self.assertEqual( validate_cas2_ticket( "foo", "https://slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/"), (True, 'test_claim', ['test_claim', u'crs-3', u'crs-1'])) + mock_urlopen.assert_called_with( + "https://cas.columbia.edu/cas/serviceValidate?ticket=foo" + "&service=https%3A//slank.ccnmtl.columbia.edu/accounts/" + "caslogin/%3Fnext%3D/") TR_SUCCESS = """ @@ -360,35 +372,29 @@ def tr_affils(): return open_affils("tr_affils.txt") +@patch('djangowind.auth.urlopen') class ValidateSAMLTicketTest(TestCase): - def test_no_ticket(self): + def setUp(self): + self.response = Mock(spec=HTTPResponse) + + def test_no_ticket(self, mock_urlopen): self.assertEqual( validate_saml_ticket("", ""), (False, 'no ticketid', '')) - @httprettified - def test_validate_ticket_success(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=saml_success_no_affils()) + def test_validate_ticket_success(self, mock_urlopen): + self.response.read.return_value = saml_success_no_affils() + mock_urlopen.return_value = self.response + self.assertEqual( validate_saml_ticket( "foo", "https://slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/"), (True, 'anp8', ['anp8'])) - @httprettified - def test_validate_ticket_success_with_groups(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=saml_success_affils() - ) + def test_validate_ticket_success_with_groups(self, mock_urlopen): + self.response.read.return_value = saml_success_affils() + mock_urlopen.return_value = self.response self.assertEqual( validate_saml_ticket( @@ -403,43 +409,31 @@ def test_validate_ticket_success_with_groups(self): 'tlc-pt.cunix.local:columbia.edu', 'tlcxml.cunix.local:columbia.edu'])) - @httprettified - def test_validate_ticket_fail(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=SAML_FAIL) + def test_validate_ticket_fail(self, mock_urlopen): + self.response.read.return_value = SAML_FAIL + mock_urlopen.return_value = self.response + self.assertEqual( validate_saml_ticket( "foo", "https://slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/"), (False, "CAS/SAML Validation Failed", [])) - @httprettified - def test_validate_ticket_invalid_response(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body="holy crap! I'm not a valid CAS response!" - ) + def test_validate_ticket_invalid_response(self, mock_urlopen): + self.response.read.return_value = \ + "holy crap! I'm not a valid CAS response!" + mock_urlopen.return_value = self.response + self.assertEqual( validate_saml_ticket( "foo", "https://slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/"), (False, "CAS did not return a valid response.", [])) - @httprettified - def test_validate_ticket_alternate_cas_base(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.example.com/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=saml_success_no_affils()) + def test_validate_ticket_alternate_cas_base(self, mock_urlopen): + self.response.read.return_value = saml_success_no_affils() + mock_urlopen.return_value = self.response + with self.settings(CAS_BASE="https://cas.example.com/"): self.assertEqual( validate_saml_ticket( @@ -448,15 +442,10 @@ def test_validate_ticket_alternate_cas_base(self): "caslogin/?next=/")), (True, 'anp8', ['anp8'])) - @httprettified - def test_validate_ticket_with_jonah_affils(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=jonah_affils() - ) + def test_validate_ticket_with_jonah_affils(self, mock_urlopen): + self.response.read.return_value = jonah_affils() + mock_urlopen.return_value = self.response + self.assertEqual( validate_saml_ticket( "foo", @@ -500,18 +489,18 @@ def test_validate_ticket_with_jonah_affils(self): 't3.y2009.s001.cg8200.soci.st.course:columbia.edu'])) +@patch('djangowind.auth.urlopen') class WindAuthBackendTest(TestCase): - def test_authenticate_no_ticket(self): + def setUp(self): + self.response = Mock(spec=HTTPResponse) + + def test_authenticate_no_ticket(self, mock_urlopen): w = WindAuthBackend() self.assertEqual(w.authenticate(None), None) - @httprettified - def test_authenticate_success(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://wind.columbia.edu/validate?ticket=foo", - body="yes\nanders" - ) + def test_authenticate_success(self, mock_urlopen): + self.response.read.return_value = 'yes\nanders' + mock_urlopen.return_value = self.response w = WindAuthBackend() r = w.authenticate("foo") self.assertEqual(r.username, "anders") @@ -523,14 +512,13 @@ def test_authenticate_success(self): r = w.authenticate("foo") self.assertEqual(r.username, "anders") self.assertFalse(r.has_usable_password()) + mock_urlopen.assert_called_with( + 'https://wind.columbia.edu/validate?ticketid=foo') + + def test_authenticate_success_existing_user(self, mock_urlopen): + self.response.read.return_value = 'yes\nanders' + mock_urlopen.return_value = self.response - @httprettified - def test_authenticate_success_existing_user(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://wind.columbia.edu/validate?ticket=foo", - body="yes\nanders" - ) u = User.objects.create(username="anders") u.set_password("something other than unusable") u.save() @@ -538,33 +526,33 @@ def test_authenticate_success_existing_user(self): r = w.authenticate("foo") self.assertEqual(r.username, "anders") self.assertNotEqual(r.password, "!") + mock_urlopen.assert_called_with( + 'https://wind.columbia.edu/validate?ticketid=foo') + + def test_authenticate_failure(self, mock_urlopen): + self.response.read.return_value = 'no\nanders' + mock_urlopen.return_value = self.response - @httprettified - def test_authenticate_failure(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://wind.columbia.edu/validate?ticket=foo", - body="no\nanders" - ) w = WindAuthBackend() r = w.authenticate("foo") self.assertEqual(r, None) + mock_urlopen.assert_called_with( + 'https://wind.columbia.edu/validate?ticketid=foo') + + def test_authenticate_success_with_mappers(self, mock_urlopen): + self.response.read.return_value = 'yes\nanders' + mock_urlopen.return_value = self.response - @httprettified - def test_authenticate_success_with_mappers(self): - HTTPretty.register_uri( - HTTPretty.GET, - "https://wind.columbia.edu/validate?ticket=foo", - body="yes\nanders" - ) with self.settings( WIND_AFFIL_HANDLERS=['djangowind.auth.AffilGroupMapper']): w = WindAuthBackend() r = w.authenticate("foo") self.assertEqual(r.username, "anders") self.assertFalse(r.has_usable_password()) + mock_urlopen.assert_called_with( + 'https://wind.columbia.edu/validate?ticketid=foo') - def test_get_user(self): + def test_get_user(self, mock_urlopen): w = WindAuthBackend() # no pre-existing user r = w.get_user(1) @@ -575,27 +563,25 @@ def test_get_user(self): self.assertEqual(r, u) +@patch('djangowind.auth.urlopen') class CAS2AuthBackendTest(TestCase): - def test_authenticate_no_ticket(self): + def setUp(self): + self.response = Mock(spec=HTTPResponse) + + def test_authenticate_no_ticket(self, mock_urlopen): w = CAS2AuthBackend() self.assertEqual(w.authenticate(None), None) - @httprettified - def test_authenticate_success(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?ticket=foo" - "&https%3A//slank.ccnmtl.columbia.edu/accounts/" - "caslogin/?next=/"), - body=( - "\n\n\n\n\t\n" - "\t\tanp8\n" - "\n" - "\n" - "\t\n" - "\n") - ) + def test_authenticate_success(self, mock_urlopen): + self.response.read.return_value = ( + "\n\n\n\n\t\n" + "\t\tanp8\n" + "\n" + "\n" + "\t\n" + "\n") + mock_urlopen.return_value = self.response w = CAS2AuthBackend() r = w.authenticate( @@ -604,6 +590,10 @@ def test_authenticate_success(self): "caslogin/?next=/")) self.assertEqual(r.username, "anp8") self.assertFalse(r.has_usable_password()) + mock_urlopen.assert_called_with( + 'https://cas.columbia.edu/cas/serviceValidate?ticket=foo' + '&service=https%3A//slank.ccnmtl.columbia.edu/' + 'accounts/caslogin/%3Fnext%3D/') with self.settings( WIND_PROFILE_HANDLERS=['djangowind.auth.DummyProfileHandler']): @@ -615,22 +605,16 @@ def test_authenticate_success(self): self.assertEqual(r.username, "anp8") self.assertFalse(r.has_usable_password()) - @httprettified - def test_authenticate_success_existing_user(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?ticket=foo" - "&https%3A//slank.ccnmtl.columbia.edu/accounts/" - "caslogin/?next=/"), - body=( - "\n\n\n\n\t\n" - "\t\tanp8\n" - "\n" - "\n" - "\t\n" - "\n") - ) + def test_authenticate_success_existing_user(self, mock_urlopen): + self.response.read.return_value = ( + "\n\n\n\n\t\n" + "\t\tanp8\n" + "\n" + "\n" + "\t\n" + "\n") + mock_urlopen.return_value = self.response u = User.objects.create(username="anp8") u.set_password("something other than unusable") @@ -642,25 +626,23 @@ def test_authenticate_success_existing_user(self): "caslogin/?next=/")) self.assertEqual(r.username, "anp8") self.assertNotEqual(r.password, "!") - - @httprettified - def test_authenticate_failure(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?" - "ticket=foo&https%3A//slank.ccnmtl.columbia.edu/" - "accounts/caslogin/?next=/"), - body=( - "\n\n\n\n\t\n\t\tticket 'ST-181952-OK0" - "qr5suLueHccqPfgIT-idmcasprod2' does not match supp" - "lied service. The original service was 'https://" - "slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/'" - "and the supplied service was 'https://slank.ccnmtl." - "columbia.edu/accounts/caslogin/'.\n\t\n") - ) + mock_urlopen.assert_called_with( + 'https://cas.columbia.edu/cas/serviceValidate?ticket=foo' + '&service=https%3A//slank.ccnmtl.columbia.edu/' + 'accounts/caslogin/%3Fnext%3D/') + + def test_authenticate_failure(self, mock_urlopen): + self.response.read.return_value = ( + "\n\n\n\n\t\n\t\tticket 'ST-181952-OK0" + "qr5suLueHccqPfgIT-idmcasprod2' does not match supp" + "lied service. The original service was 'https://" + "slank.ccnmtl.columbia.edu/accounts/caslogin/?next=/'" + "and the supplied service was 'https://slank.ccnmtl." + "columbia.edu/accounts/caslogin/'.\n\t\n") + mock_urlopen.return_value = self.response w = CAS2AuthBackend() r = w.authenticate( @@ -668,23 +650,21 @@ def test_authenticate_failure(self): url=("https://slank.ccnmtl.columbia.edu/accounts/" "caslogin/?next=/")) self.assertEqual(r, None) - - @httprettified - def test_authenticate_success_with_mappers(self): - HTTPretty.register_uri( - HTTPretty.GET, - ("https://cas.columbia.edu/cas/serviceValidate?ticket=foo" - "&https%3A//slank.ccnmtl.columbia.edu/accounts/" - "caslogin/?next=/"), - body=( - "\n\n\n\n\t\n" - "\t\tanp8\n" - "\n" - "\n" - "\t\n" - "\n") - ) + mock_urlopen.assert_called_with( + 'https://cas.columbia.edu/cas/serviceValidate?ticket=foo' + '&service=https%3A//slank.ccnmtl.columbia.edu/' + 'accounts/caslogin/%3Fnext%3D/') + + def test_authenticate_success_with_mappers(self, mock_urlopen): + self.response.read.return_value = ( + "\n\n\n\n\t\n" + "\t\tanp8\n" + "\n" + "\n" + "\t\n" + "\n") + mock_urlopen.return_value = self.response with self.settings( WIND_AFFIL_HANDLERS=['djangowind.auth.AffilGroupMapper']): @@ -695,22 +675,24 @@ def test_authenticate_success_with_mappers(self): "caslogin/?next=/")) self.assertEqual(r.username, "anp8") self.assertFalse(r.has_usable_password()) + mock_urlopen.assert_called_with( + 'https://cas.columbia.edu/cas/serviceValidate?ticket=foo' + '&service=https%3A//slank.ccnmtl.columbia.edu/' + 'accounts/caslogin/%3Fnext%3D/') +@patch('djangowind.auth.urlopen') class SAMLAuthBackendTest(TestCase): - def test_authenticate_no_ticket(self): + def setUp(self): + self.response = Mock(spec=HTTPResponse) + + def test_authenticate_no_ticket(self, mock_urlopen): w = SAMLAuthBackend() self.assertEqual(w.authenticate(None), None) - @httprettified - def test_authenticate_success(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=saml_success_affils() - ) + def test_authenticate_success(self, mock_urlopen): + self.response.read.return_value = saml_success_affils() + mock_urlopen.return_value = self.response w = SAMLAuthBackend() r = w.authenticate( @@ -730,15 +712,9 @@ def test_authenticate_success(self): self.assertEqual(r.username, "anp8") self.assertFalse(r.has_usable_password()) - @httprettified - def test_authenticate_success_existing_user(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=saml_success_affils() - ) + def test_authenticate_success_existing_user(self, mock_urlopen): + self.response.read.return_value = saml_success_affils() + mock_urlopen.return_value = self.response u = User.objects.create(username="anp8") u.set_password("something other than unusable") @@ -751,14 +727,9 @@ def test_authenticate_success_existing_user(self): self.assertEqual(r.username, "anp8") self.assertNotEqual(r.password, "!") - @httprettified - def test_authenticate_failure(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=SAML_FAIL) + def test_authenticate_failure(self, mock_urlopen): + self.response.read.return_value = SAML_FAIL + mock_urlopen.return_value = self.response w = SAMLAuthBackend() r = w.authenticate( @@ -767,15 +738,9 @@ def test_authenticate_failure(self): "caslogin/?next=/")) self.assertEqual(r, None) - @httprettified - def test_authenticate_success_with_mappers(self): - HTTPretty.register_uri( - HTTPretty.POST, - ("https://cas.columbia.edu/cas/samlValidate?" - "TARGET=https%3A%2F%2Fslank.ccnmtl.columbia.edu" - "%2Faccounts%2Fcaslogin%2F%3Fnext%3D%2F"), - body=saml_success_affils() - ) + def test_authenticate_success_with_mappers(self, mock_urlopen): + self.response.read.return_value = saml_success_affils() + mock_urlopen.return_value = self.response with self.settings( WIND_AFFIL_HANDLERS=['djangowind.auth.AffilGroupMapper']): diff --git a/djangowind/tests/test_views.py b/djangowind/tests/test_views.py index f0b4026..5fc9936 100644 --- a/djangowind/tests/test_views.py +++ b/djangowind/tests/test_views.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django.test import TestCase diff --git a/djangowind/urls.py b/djangowind/urls.py index 8bae916..671a634 100644 --- a/djangowind/urls.py +++ b/djangowind/urls.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django.conf.urls import patterns urlpatterns = patterns('', diff --git a/djangowind/views.py b/djangowind/views.py index 87045ab..57be579 100644 --- a/djangowind/views.py +++ b/djangowind/views.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django.http import HttpResponseRedirect, HttpResponseForbidden from django.shortcuts import render_to_response diff --git a/runtests.py b/runtests.py index 77d3e09..4177803 100644 --- a/runtests.py +++ b/runtests.py @@ -61,7 +61,7 @@ def main(): pass # Fire off the tests - call_command('jenkins', '--enable-coverage') + call_command('jenkins') if __name__ == '__main__': main() diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..2a9acf1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = 1 diff --git a/test_reqs.txt b/test_reqs.txt index 79b9813..1aa6a92 100644 --- a/test_reqs.txt +++ b/test_reqs.txt @@ -1,8 +1,9 @@ coverage==4.0.3 +mock==2.0.0 flake8==2.5.4 -httpretty==0.8.14 django-jenkins==0.18.1 pep8==1.5.7 pyflakes==1.1.0 statsd==3.2.1 django-statsd-mozilla==0.3.16 +ipdb==0.9.3