diff --git a/apps/sso/tests.py b/apps/sso/tests.py index b903cab..89a7f27 100644 --- a/apps/sso/tests.py +++ b/apps/sso/tests.py @@ -8,16 +8,20 @@ class MiddlewareTestCase(test_utils.TestCase): """Test our custom middleware(s).""" - - def test_httponly(self): + def _login(self): + """Create a new user and log them in.""" uid = 'john' pw = 'johnpw' User.objects.create_user(uid,'lennon@thebeatles.com', pw) - r = self.client.post(reverse('cas_login'), { - 'username': uid, 'password': pw}) + self.client.login(username=uid, password=pw) - # No errors - eq_(r.status_code, 200) + def test_httponly(self): + self._login() + + r = self.client.get(reverse('cas_login')) + + # No errors, and we are logged in + eq_(r.status_code, 302) # We have cookies and all are httponly unless specified otherwise. self.assertTrue(len(r.cookies) > 0) @@ -30,3 +34,16 @@ def test_x_frame_options(self): r = self.client.get(reverse('cas_login')) eq_(r.status_code, 200) eq_(r['x-frame-options'], 'DENY') + + def test_session_ip_check(self): + """Make sure our session cookies are tied to a single IP.""" + different_forwarded_for = '192.168.0.1, 192.168.0.2' + + self._login() + + r = self.client.get(reverse('home')) + self.assertTrue(r.context['user'].is_authenticated()) + + r = self.client.get(reverse('home'), + HTTP_X_FORWARDED_FOR=different_forwarded_for) + self.assertFalse(r.context['user'].is_authenticated()) diff --git a/apps/users/views.py b/apps/users/views.py index 9516e08..5d3fb04 100644 --- a/apps/users/views.py +++ b/apps/users/views.py @@ -18,6 +18,7 @@ def display_profile(request): def edit_profile(request): return HttpResponse('edit profile page') + def register(request): """ Given a username, email, and password, creates a new user """ diff --git a/requirements/prod.txt b/requirements/prod.txt index e97e768..a10f2ad 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -4,5 +4,8 @@ Django==1.2.1 -e git://github.com/jbalogh/jingo.git#egg=jingo -e git://github.com/jsocol/commonware.git#egg=commonware +# Security +-e git://github.com/rfk/django-paranoid-sessions.git#egg=paranoidsessions + # Caching python-memcached==1.45 diff --git a/settings.py b/settings.py index 3fed73c..5c058ff 100644 --- a/settings.py +++ b/settings.py @@ -113,10 +113,11 @@ def JINJA_CONFIG(): MIDDLEWARE_CLASSES = ( + 'commonware.middleware.SetRemoteAddrFromForwardedFor', # First, so all others see the right IP 'sso.middleware.HttpOnlyMiddleware', # needs to be before AuthMiddleware - 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'paranoidsessions.ParanoidSessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfResponseMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -147,7 +148,6 @@ def JINJA_CONFIG(): TEST_RUNNER = 'test_utils.runner.RadicalTestSuiteRunner' # Security settings - SESSION_EXPIRE_AT_BROWSER_CLOSE = True # Default to 1 week expiration SESSION_COOKIE_AGE = 7 * 24 * 60 * 60 @@ -156,9 +156,13 @@ def JINJA_CONFIG(): # Cookie names that should NOT have the HttpOnly flag set. JAVASCRIPT_READABLE_COOKIES = () -# Service ticket expiration, in seconds, 0 means no expiration. +# CAS Service ticket expiration, in seconds, 0 means no expiration. SERVICE_TICKET_TIMEOUT = 30 +# django-paranoid-sessions settings +PSESSION_CHECK_HEADERS = ('REMOTE_ADDR',) # Check remote IP address +PSESSION_NONCE_TIMEOUT = None # No nonce cookies for now + # Emails DEFAULT_FROM_EMAIL = 'nobody@mozilla.org' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'