From dd0180a33d0662cb4105cee7a5f97817d69db3a9 Mon Sep 17 00:00:00 2001 From: Jeremy Bowman Date: Mon, 7 May 2018 15:00:48 -0400 Subject: [PATCH] TE-2545 Restrict AutoAuth for load tests --- cms/envs/acceptance.py | 1 + cms/envs/bok_choy.py | 1 + cms/envs/common.py | 6 +++ .../student/tests/test_auto_auth.py | 38 +++++++++++++++++++ common/djangoapps/student/views/login.py | 6 +++ lms/envs/acceptance.py | 1 + lms/envs/bok_choy.env.json | 1 + lms/envs/bok_choy.py | 1 + lms/envs/bok_choy_docker.env.json | 1 + lms/envs/common.py | 5 ++- 10 files changed, 60 insertions(+), 1 deletion(-) diff --git a/cms/envs/acceptance.py b/cms/envs/acceptance.py index afcbfee46c..514e4a7d9d 100644 --- a/cms/envs/acceptance.py +++ b/cms/envs/acceptance.py @@ -96,6 +96,7 @@ DATABASES = { # Use the auto_auth workflow for creating users and logging them in FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] = True +FEATURES['RESTRICT_AUTOMATIC_AUTH'] = False # Forums are disabled in test.py to speed up unit tests, but we do not have # per-test control for lettuce acceptance tests. diff --git a/cms/envs/bok_choy.py b/cms/envs/bok_choy.py index f4ea665227..eb6366318d 100644 --- a/cms/envs/bok_choy.py +++ b/cms/envs/bok_choy.py @@ -80,6 +80,7 @@ for log_name, log_level in LOG_OVERRIDES: # Use the auto_auth workflow for creating users and logging them in FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] = True +FEATURES['RESTRICT_AUTOMATIC_AUTH'] = False # Enable milestones app FEATURES['MILESTONES_APP'] = True diff --git a/cms/envs/common.py b/cms/envs/common.py index c3c48572d4..ead2d60857 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -304,6 +304,12 @@ FEATURES = { # Whether archived courses (courses with end dates in the past) should be # shown in Studio in a separate list. 'ENABLE_SEPARATE_ARCHIVED_COURSES': True, + + # For acceptance and load testing + 'AUTOMATIC_AUTH_FOR_TESTING': False, + + # Prevent auto auth from creating superusers or modifying existing users + 'RESTRICT_AUTOMATIC_AUTH': True, } ENABLE_JASMINE = False diff --git a/common/djangoapps/student/tests/test_auto_auth.py b/common/djangoapps/student/tests/test_auto_auth.py index 590c2c66d1..176e916dad 100644 --- a/common/djangoapps/student/tests/test_auto_auth.py +++ b/common/djangoapps/student/tests/test_auto_auth.py @@ -55,6 +55,7 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase): self.assertTrue(user.is_active) self.assertFalse(user.profile.requires_parental_consent()) + @patch.dict("django.conf.settings.FEATURES", {'RESTRICT_AUTOMATIC_AUTH': False}) def test_create_same_user(self): self._auto_auth({'username': 'test'}) self._auto_auth({'username': 'test'}) @@ -92,6 +93,7 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase): # By default, the user should not be global staff self.assertFalse(user.is_staff) + @patch.dict("django.conf.settings.FEATURES", {'RESTRICT_AUTOMATIC_AUTH': False}) def test_create_staff_user(self): # Create a staff user @@ -118,6 +120,7 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase): @ddt.data(*COURSE_IDS_DDT) @ddt.unpack + @patch.dict("django.conf.settings.FEATURES", {'RESTRICT_AUTOMATIC_AUTH': False}) def test_double_enrollment(self, course_id, course_key): # Create a user and enroll in a course @@ -309,3 +312,38 @@ class AutoAuthDisabledTestCase(AutoAuthTestCase): """ response = self.client.get(self.url) self.assertEqual(response.status_code, 404) + + +class AutoAuthRestrictedTestCase(AutoAuthTestCase): + """ + Test that the default security restrictions on automatic authentication + work as intended. These restrictions are in place for load tests. + """ + + @patch.dict('django.conf.settings.FEATURES', {'AUTOMATIC_AUTH_FOR_TESTING': True}) + def setUp(self): + # Patching the settings.FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] + # value affects the contents of urls.py, + # so we need to call super.setUp() which reloads urls.py (because + # of the UrlResetMixin) + super(AutoAuthRestrictedTestCase, self).setUp() + self.url = '/auto_auth' + self.client = Client() + + @patch.dict("django.conf.settings.FEATURES", {'RESTRICT_AUTOMATIC_AUTH': True}) + def test_superuser(self): + """ + Make sure that superusers cannot be created. + """ + response = self.client.get(self.url, {'username': 'test', 'superuser': 'true'}) + assert response.status_code == 403 + + @patch.dict("django.conf.settings.FEATURES", {'RESTRICT_AUTOMATIC_AUTH': True}) + def test_modify_user(self): + """ + Make sure that existing users cannot be modified. + """ + response = self.client.get(self.url, {'username': 'test'}) + self.assertEqual(response.status_code, 200) + response = self.client.get(self.url, {'username': 'test'}) + self.assertEqual(response.status_code, 403) diff --git a/common/djangoapps/student/views/login.py b/common/djangoapps/student/views/login.py index 0113902c96..960a6a0440 100644 --- a/common/djangoapps/student/views/login.py +++ b/common/djangoapps/student/views/login.py @@ -625,6 +625,10 @@ def auto_auth(request): redirect_when_done = str2bool(request.GET.get('redirect', '')) or redirect_to login_when_done = 'no_login' not in request.GET + restricted = settings.FEATURES.get('RESTRICT_AUTOMATIC_AUTH', True) + if is_superuser and restricted: + return HttpResponseForbidden(_('Superuser creation not allowed')) + form = AccountCreationForm( data={ 'username': username, @@ -641,6 +645,8 @@ def auto_auth(request): try: user, profile, reg = do_create_account(form) except (AccountValidationError, ValidationError): + if restricted: + return HttpResponseForbidden(_('Account modification not allowed.')) # Attempt to retrieve the existing user. user = User.objects.get(username=username) user.email = email diff --git a/lms/envs/acceptance.py b/lms/envs/acceptance.py index 9fede5c749..df950e9492 100644 --- a/lms/envs/acceptance.py +++ b/lms/envs/acceptance.py @@ -113,6 +113,7 @@ FEATURES['ENABLE_DISCUSSION_SERVICE'] = False # Use the auto_auth workflow for creating users and logging them in FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] = True +FEATURES['RESTRICT_AUTOMATIC_AUTH'] = False # Enable third-party authentication FEATURES['ENABLE_THIRD_PARTY_AUTH'] = True diff --git a/lms/envs/bok_choy.env.json b/lms/envs/bok_choy.env.json index 273e83dbf2..7bb9b3756c 100644 --- a/lms/envs/bok_choy.env.json +++ b/lms/envs/bok_choy.env.json @@ -81,6 +81,7 @@ "PREVIEW_LMS_BASE": "preview.localhost:8003", "ALLOW_AUTOMATED_SIGNUPS": true, "AUTOMATIC_AUTH_FOR_TESTING": true, + "RESTRICT_AUTOMATIC_AUTH": false, "MODE_CREATION_FOR_TESTING": true, "EXPOSE_CACHE_PROGRAMS_ENDPOINT": true, "AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING": true, diff --git a/lms/envs/bok_choy.py b/lms/envs/bok_choy.py index 115a023c75..f12920e27f 100644 --- a/lms/envs/bok_choy.py +++ b/lms/envs/bok_choy.py @@ -146,6 +146,7 @@ FEATURES['LICENSING'] = True # Use the auto_auth workflow for creating users and logging them in FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] = True +FEATURES['RESTRICT_AUTOMATIC_AUTH'] = False # Open up endpoint for faking Software Secure responses FEATURES['ENABLE_SOFTWARE_SECURE_FAKE'] = True diff --git a/lms/envs/bok_choy_docker.env.json b/lms/envs/bok_choy_docker.env.json index 0b8fad2b4a..9ca40f6fcc 100644 --- a/lms/envs/bok_choy_docker.env.json +++ b/lms/envs/bok_choy_docker.env.json @@ -81,6 +81,7 @@ "PREVIEW_LMS_BASE": "preview.localhost:8003", "ALLOW_AUTOMATED_SIGNUPS": true, "AUTOMATIC_AUTH_FOR_TESTING": true, + "RESTRICT_AUTOMATIC_AUTH": false, "MODE_CREATION_FOR_TESTING": true, "EXPOSE_CACHE_PROGRAMS_ENDPOINT": true, "AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING": true, diff --git a/lms/envs/common.py b/lms/envs/common.py index b0fc9f3bb5..4ec2eaa4ba 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -182,9 +182,12 @@ FEATURES = { # Toggle to enable certificates of courses on dashboard 'ENABLE_VERIFIED_CERTIFICATES': False, - # for load testing + # for acceptance and load testing 'AUTOMATIC_AUTH_FOR_TESTING': False, + # Prevent auto auth from creating superusers or modifying existing users + 'RESTRICT_AUTOMATIC_AUTH': True, + # Toggle the availability of the shopping cart page 'ENABLE_SHOPPING_CART': False,