From 77e9ede866807c878364d057164e968c8ce0ae72 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Wed, 30 Nov 2022 14:43:02 +0100 Subject: [PATCH 1/2] settings: set secure flag on cookies (#71880) --- src/authentic2/settings.py | 5 +++++ tests/api/test_all.py | 16 ++++++++-------- tests/auth_fc/conftest.py | 4 ++-- tests/auth_fc/test_auth_fc.py | 2 +- tests/conftest.py | 6 ++++-- tests/idp_oidc/test_misc.py | 4 ++-- tests/settings.py | 2 +- tests/test_attribute_kinds.py | 2 +- tests/test_auth_oidc.py | 2 +- tests/test_commands.py | 2 +- tests/test_csv_import.py | 2 +- tests/test_idp_saml2.py | 14 ++++++++------ tests/test_manager.py | 6 +++--- tests/test_password_reset.py | 4 ++-- 14 files changed, 40 insertions(+), 31 deletions(-) diff --git a/src/authentic2/settings.py b/src/authentic2/settings.py index 688ed251..14e77979 100644 --- a/src/authentic2/settings.py +++ b/src/authentic2/settings.py @@ -55,6 +55,11 @@ DATABASES = { } } +# Cookies +SESSION_COOKIE_SECURE = True +CSRF_COOKIE_SECURE = True +LANGUAGE_COOKIE_SECURE = True + # Hey Entr'ouvert is in France !! TIME_ZONE = 'Europe/Paris' LANGUAGE_CODE = 'fr' diff --git a/tests/api/test_all.py b/tests/api/test_all.py index 24bd654c..44bd74f6 100644 --- a/tests/api/test_all.py +++ b/tests/api/test_all.py @@ -100,12 +100,12 @@ def test_api_user(client): Role.objects.create(name='Role4', service=service) # test failure when unlogged - response = client.get('/api/user/', HTTP_ORIGIN='http://testserver') + response = client.get('/api/user/', HTTP_ORIGIN='https://testserver') assert response.content == b'{}' # login client.login(request=None, username='john.doe', password='password') - response = client.get('/api/user/', HTTP_ORIGIN='http://testserver') + response = client.get('/api/user/', HTTP_ORIGIN='https://testserver') data = json.loads(force_str(response.content)) assert isinstance(data, dict) assert set(data.keys()) == { @@ -1055,7 +1055,7 @@ def test_register_no_email_validation(settings, app, admin, django_user_model): assert response.json['user']['last_name'] == last_name assert check_password(password, response.json['user']['password']) assert response.json['token'] - assert response.json['validation_url'].startswith('http://testserver/accounts/activate/') + assert response.json['validation_url'].startswith('https://testserver/accounts/activate/') assert User.objects.count() == 2 user = User.objects.latest('id') assert user.ou == get_default_ou() @@ -1114,7 +1114,7 @@ def test_register_ou_no_email_validation(settings, app, admin, django_user_model assert response.json['user']['last_name'] == last_name assert check_password(password, response.json['user']['password']) assert response.json['token'] - assert response.json['validation_url'].startswith('http://testserver/accounts/activate/') + assert response.json['validation_url'].startswith('https://testserver/accounts/activate/') assert User.objects.count() == 2 user = User.objects.latest('id') assert user.username == username @@ -1232,7 +1232,7 @@ def test_password_reset(app, ou1, admin, user_ou1, mailoutbox): assert len(mailoutbox) == 1 mail = mailoutbox[0] assert mail.to[0] == email - assert 'http://testserver/password/reset/confirm/' in mail.body + assert 'https://testserver/password/reset/confirm/' in mail.body assert_event('manager.user.password.reset.request', user=admin, api=True) @@ -1265,7 +1265,7 @@ def test_users_email(app, ou1, admin, user_ou1, mailoutbox): mail = mailoutbox[0] assert mail.to[0] == new_email - assert 'http://testserver/accounts/change-email/verify/' in mail.body + assert 'https://testserver/accounts/change-email/verify/' in mail.body def test_api_delete_role(app, admin_ou1, role_ou1): @@ -2391,7 +2391,7 @@ def test_api_statistics_list(app, admin): assert len(resp.json['data']) == 6 login_stats = { 'name': 'Login count by authentication type', - 'url': 'http://testserver/api/statistics/login/', + 'url': 'https://testserver/api/statistics/login/', 'id': 'login', 'filters': [ { @@ -2411,7 +2411,7 @@ def test_api_statistics_list(app, admin): assert login_stats in resp.json['data'] assert { 'name': 'Login count by service', - 'url': 'http://testserver/api/statistics/service_login/', + 'url': 'https://testserver/api/statistics/service_login/', 'id': 'service-login', 'filters': [ { diff --git a/tests/auth_fc/conftest.py b/tests/auth_fc/conftest.py index 8177a3e6..bb19a08d 100644 --- a/tests/auth_fc/conftest.py +++ b/tests/auth_fc/conftest.py @@ -80,7 +80,7 @@ class FranceConnectMock: @property def callback_url(self): - return 'http://testserver' + reverse('fc-login-or-link') + return 'https://testserver' + reverse('fc-login-or-link') def login_with_fc_fixed_params(self, app): if app.session: @@ -154,7 +154,7 @@ class FranceConnectMock: assert url.startswith('https://fcp.integ01.dev-franceconnect.fr/api/v1/logout') parsed_url = urllib.parse.urlparse(url) query = QueryDict(parsed_url.query) - assert_equals_url(query['post_logout_redirect_uri'], 'http://testserver' + reverse('fc-logout')) + assert_equals_url(query['post_logout_redirect_uri'], 'https://testserver' + reverse('fc-logout')) assert query['state'] self.state = query['state'] return app.get(reverse('fc-logout') + '?state=' + self.state) diff --git a/tests/auth_fc/test_auth_fc.py b/tests/auth_fc/test_auth_fc.py index a3852306..bda6a1ec 100644 --- a/tests/auth_fc/test_auth_fc.py +++ b/tests/auth_fc/test_auth_fc.py @@ -128,7 +128,7 @@ def test_create(settings, app, franceconnect, hooks, service, mailoutbox): for body in (mailoutbox[0].body, mailoutbox[0].alternatives[0][0]): assert 'Hi AnonymousUser,' in body assert 'You have just created an account using FranceConnect.' in body - assert 'http://testserver/login/' in body + assert 'https://testserver/login/' in body assert user.verified_attributes.first_name == 'Ÿuñe' assert user.verified_attributes.last_name == 'Frédérique' diff --git a/tests/conftest.py b/tests/conftest.py index ecf6765f..53c78603 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -63,7 +63,9 @@ def app_factory(): try: def factory(hostname='testserver'): - return django_webtest.DjangoTestApp(extra_environ={'HTTP_HOST': hostname}) + return django_webtest.DjangoTestApp( + extra_environ={'HTTP_HOST': hostname, 'wsgi.url_scheme': 'https'} + ) yield factory finally: @@ -420,7 +422,7 @@ def assert_external_redirect(external_redirect): else: def check_location(response, default_return): - assert urllib.parse.urljoin('http://testserver/', default_return).endswith(response['Location']) + assert urllib.parse.urljoin('https://testserver/', default_return).endswith(response['Location']) return check_location diff --git a/tests/idp_oidc/test_misc.py b/tests/idp_oidc/test_misc.py index 68e6ccc5..bc5f42b3 100644 --- a/tests/idp_oidc/test_misc.py +++ b/tests/idp_oidc/test_misc.py @@ -353,7 +353,7 @@ def test_authorization_code_sso( with open('tests/200x200.jpg', 'rb') as fd: simple_user.attributes.cityscape_image = File(fd) response = app.get(user_info_url, headers=bearer_authentication_headers(access_token)) - assert response.json['cityscape_image'].startswith('http://testserver/media/profile-image/') + assert response.json['cityscape_image'].startswith('https://testserver/media/profile-image/') # check against a user without username simple_user.username = None @@ -381,7 +381,7 @@ def test_authorization_code_sso( src = iframes.attr('src') assert '?' in src src_qd = QueryDict(src.split('?', 1)[1]) - assert 'iss' in src_qd and src_qd['iss'] == 'http://testserver/' + assert 'iss' in src_qd and src_qd['iss'] == 'https://testserver/' assert 'sid' in src_qd and src_qd['sid'] == get_session_id( mock.Mock(session=app.session), oidc_client ) diff --git a/tests/settings.py b/tests/settings.py index 89e63fa3..fbf94ed4 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -55,7 +55,7 @@ A2_HOOKS_PROPAGATE_EXCEPTIONS = True TEMPLATES[0]['DIRS'].append('tests/templates') # pylint: disable=undefined-variable TEMPLATES[0]['OPTIONS']['debug'] = True # pylint: disable=undefined-variable -SITE_BASE_URL = 'http://testserver' +SITE_BASE_URL = 'https://testserver' A2_MAX_EMAILS_PER_IP = None A2_MAX_EMAILS_FOR_ADDRESS = None diff --git a/tests/test_attribute_kinds.py b/tests/test_attribute_kinds.py index 2b41e20e..3eb32c1e 100644 --- a/tests/test_attribute_kinds.py +++ b/tests/test_attribute_kinds.py @@ -541,7 +541,7 @@ def test_profile_image(db, app, admin, mailoutbox): response = app.get('/api/users/%s/' % john().uuid) assert ( response.json['cityscape_image'] - == 'http://testserver/media/%s' % john().attributes.cityscape_image.name + == 'https://testserver/media/%s' % john().attributes.cityscape_image.name ) app.authorization = None diff --git a/tests/test_auth_oidc.py b/tests/test_auth_oidc.py index 5551c4a8..b1cbb663 100644 --- a/tests/test_auth_oidc.py +++ b/tests/test_auth_oidc.py @@ -511,7 +511,7 @@ def test_sso(app, caplog, code, oidc_provider, oidc_provider_jwkset, hooks): assert query['response_type'] == 'code' assert query['client_id'] == str(oidc_provider.client_id) assert query['scope'] == 'openid' - assert query['redirect_uri'] == 'http://testserver' + reverse('oidc-login-callback') + assert query['redirect_uri'] == 'https://testserver' + reverse('oidc-login-callback') nonce = query['nonce'] if oidc_provider.claims_parameter_supported: diff --git a/tests/test_commands.py b/tests/test_commands.py index 2c37d942..ac049984 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -256,7 +256,7 @@ def test_clean_unused_account_login_url(simple_user, mailoutbox): simple_user.save() call_command('clean-unused-accounts') mail = mailoutbox[0] - assert 'href="http://testserver/login/"' in mail.message().as_string() + assert 'href="https://testserver/login/"' in mail.message().as_string() def test_clean_unused_account_with_no_email(simple_user, mailoutbox, caplog): diff --git a/tests/test_csv_import.py b/tests/test_csv_import.py index 0d007f1d..9409eae6 100644 --- a/tests/test_csv_import.py +++ b/tests/test_csv_import.py @@ -559,7 +559,7 @@ tnoel@entrouvert.com,Thomas,Noël,''' assert importer.run() thomas = User.objects.get(email='tnoel@entrouvert.com') assert len(mail.outbox) == 1 - assert 'http://testserver/password/reset/confirm/' in mail.outbox[0].body + assert 'https://testserver/password/reset/confirm/' in mail.outbox[0].body password = thomas.password del mail.outbox[0] diff --git a/tests/test_idp_saml2.py b/tests/test_idp_saml2.py index fe4f355e..c12611a9 100644 --- a/tests/test_idp_saml2.py +++ b/tests/test_idp_saml2.py @@ -149,7 +149,7 @@ class SamlSP: self.base_url = 'https://sp.example.com' self.name = 'Test SP' self.slug = 'test-sp' - self.idp_entity_idp = ('http://testserver/idp/saml2/metadata',) + self.idp_entity_idp = ('https://testserver/idp/saml2/metadata',) self.default_name_id_format = 'email' self.accepted_name_id_format = ['email', 'persistent', 'transient', 'username'] self.ou = OrganizationalUnit.objects.get() @@ -504,7 +504,7 @@ class Scenario: ), ( "/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='avatar']/saml:AttributeValue", - re.compile('^http://testserver/media/profile-image/.*$'), + re.compile('^https://testserver/media/profile-image/.*$'), ), ( "/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/@NameFormat", @@ -815,14 +815,16 @@ def test_make_edu_person_targeted_id(db, settings, rf): == '_' + hashlib.sha256(b'b' + b'https://sp.com/' + b'a').hexdigest().upper() ) - edpt = saml2_endpoints.make_edu_person_targeted_id('http://testserver/idp/saml2/metadata', provider, user) + edpt = saml2_endpoints.make_edu_person_targeted_id( + 'https://testserver/idp/saml2/metadata', provider, user + ) assert edpt is not None node = lasso.Node.newFromXmlNode(force_str(ET.tostring(edpt))) assert isinstance(node, lasso.Saml2NameID) assert force_str(node.content) == '_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5' assert node.format == lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT - assert node.nameQualifier == 'http://testserver/idp/saml2/metadata' + assert node.nameQualifier == 'https://testserver/idp/saml2/metadata' assert node.spNameQualifier == 'https://sp.com/' @@ -854,7 +856,7 @@ def test_add_attributes_edu_person_targeted_id_nid_format(db, settings, rf, add_ assert isinstance(node, lasso.Saml2NameID) assert force_str(node.content) == '_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5' assert node.format == lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT - assert node.nameQualifier == 'http://testserver/idp/saml2/metadata' + assert node.nameQualifier == 'https://testserver/idp/saml2/metadata' assert node.spNameQualifier == 'https://sp.com/' @@ -886,7 +888,7 @@ def test_add_attributes_edu_person_targeted_id_attribute(db, settings, rf, add_a assert isinstance(node, lasso.Saml2NameID) assert force_str(node.content) == '_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5' assert node.format == lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT - assert node.nameQualifier == 'http://testserver/idp/saml2/metadata' + assert node.nameQualifier == 'https://testserver/idp/saml2/metadata' assert node.spNameQualifier == 'https://sp.com/' diff --git a/tests/test_manager.py b/tests/test_manager.py index b48fe07e..93a9f82d 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -1306,11 +1306,11 @@ def test_manager_menu_json(app, admin): { 'label': 'Identity management', 'slug': 'identity-management', - 'url': 'http://testserver/manage/', + 'url': 'https://testserver/manage/', 'sub': False, }, - {'label': 'Users', 'slug': 'users', 'url': 'http://testserver/manage/users/', 'sub': True}, - {'label': 'Roles', 'slug': 'roles', 'url': 'http://testserver/manage/roles/', 'sub': True}, + {'label': 'Users', 'slug': 'users', 'url': 'https://testserver/manage/users/', 'sub': True}, + {'label': 'Roles', 'slug': 'roles', 'url': 'https://testserver/manage/roles/', 'sub': True}, ] response = login(app, admin) diff --git a/tests/test_password_reset.py b/tests/test_password_reset.py index e0646616..72b5acfa 100644 --- a/tests/test_password_reset.py +++ b/tests/test_password_reset.py @@ -176,11 +176,11 @@ def test_send_password_reset_email_no_account(app, db, mailoutbox, settings, reg for body in (mail.body, mail.alternatives[0][0]): assert 'no account was found associated with this address' in body if settings.REGISTRATION_OPEN: - assert 'http://testserver/register/' in body + assert 'https://testserver/register/' in body # check next_url was preserved assert 'next=/whatever/' in body else: - assert 'http://testserver/register/' not in body + assert 'https://testserver/register/' not in body def test_send_password_reset_email_disabled_account(app, simple_user, mailoutbox): -- 2.37.2