diff --git a/lms/djangoapps/experiments/tests/test_views.py b/lms/djangoapps/experiments/tests/test_views.py index b58c2de7f1..c1b776dd85 100644 --- a/lms/djangoapps/experiments/tests/test_views.py +++ b/lms/djangoapps/experiments/tests/test_views.py @@ -176,7 +176,7 @@ def cross_domain_config(func): 'ENABLE_CROSS_DOMAIN_CSRF_COOKIE': True }) settings_decorator = override_settings( - CORS_ORIGIN_WHITELIST=['ecommerce.edx.org'], + CORS_ORIGIN_WHITELIST=['https://ecommerce.edx.org'], CSRF_COOKIE_NAME="prod-edx-csrftoken", CROSS_DOMAIN_CSRF_COOKIE_NAME="prod-edx-csrftoken", CROSS_DOMAIN_CSRF_COOKIE_DOMAIN=".edx.org" @@ -262,9 +262,9 @@ class ExperimentCrossDomainTests(APITestCase): ) def test_white_list_contents_with_cors_header_version(self, *args): # pylint: disable=unused-argument - """ Verify that with django-cor-header<3 it loads list without scheme. """ - assert settings.CORS_ORIGIN_WHITELIST == ['sandbox.edx.org'] - assert int(version('django_cors_headers').split('.')[0]) == 2 + """ Verify that with django-cor-header<3 it loads list with scheme. """ + assert settings.CORS_ORIGIN_WHITELIST == ['https://sandbox.edx.org'] + assert int(version('django_cors_headers').split('.')[0]) == 3 class ExperimentKeyValueViewSetTests(APITestCase): # lint-amnesty, pylint: disable=missing-class-docstring diff --git a/openedx/core/djangoapps/cors_csrf/helpers.py b/openedx/core/djangoapps/cors_csrf/helpers.py index fb36621f13..e418968213 100644 --- a/openedx/core/djangoapps/cors_csrf/helpers.py +++ b/openedx/core/djangoapps/cors_csrf/helpers.py @@ -48,9 +48,14 @@ def is_cross_domain_request_allowed(request): log.debug("Referer '%s' must have the scheme 'https'") return False + scheme_with_host = referer + # if url is like `https://www.foo.bar/baz/` following check will return `https://www.foo.bar` + if referer and referer_parts.scheme and referer_parts.path: + scheme_with_host = referer.replace(referer_parts.path, '') + domain_is_whitelisted = ( getattr(settings, 'CORS_ORIGIN_ALLOW_ALL', False) or - referer_hostname in getattr(settings, 'CORS_ORIGIN_WHITELIST', []) + scheme_with_host in getattr(settings, 'CORS_ORIGIN_WHITELIST', []) ) if not domain_is_whitelisted: if referer_hostname is None: diff --git a/openedx/core/djangoapps/cors_csrf/tests/test_authentication.py b/openedx/core/djangoapps/cors_csrf/tests/test_authentication.py index 1915165aa9..1de265b0a8 100644 --- a/openedx/core/djangoapps/cors_csrf/tests/test_authentication.py +++ b/openedx/core/djangoapps/cors_csrf/tests/test_authentication.py @@ -40,7 +40,7 @@ class CrossDomainAuthTest(TestCase): 'ENABLE_CROSS_DOMAIN_CSRF_COOKIE': True }) @override_settings( - CORS_ORIGIN_WHITELIST=["www.edx.org"], + CORS_ORIGIN_WHITELIST=["https://www.edx.org"], CROSS_DOMAIN_CSRF_COOKIE_NAME="prod-edx-csrftoken", CROSS_DOMAIN_CSRF_COOKIE_DOMAIN=".edx.org" ) diff --git a/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py b/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py index 1c5a59035b..4355c596a6 100644 --- a/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py +++ b/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py @@ -18,6 +18,7 @@ from ..middleware import CorsCSRFMiddleware, CsrfCrossDomainCookieMiddleware SENTINEL = object() +@ddt.ddt class TestCorsMiddlewareProcessRequest(TestCase): """ Test processing a request through the middleware @@ -64,35 +65,41 @@ class TestCorsMiddlewareProcessRequest(TestCase): assert res is SENTINEL assert request.is_secure() - @override_settings(CORS_ORIGIN_WHITELIST=['foo.com']) - def test_enabled(self): - request = self.get_request(is_secure=True, http_referer='https://foo.com/bar') + @override_settings(CORS_ORIGIN_WHITELIST=[ + 'https://foo.com', 'https://www.foo.com', 'https://learning.edge.foo.bar'] + ) + @ddt.data( + 'https://foo.com/bar/', 'https://foo.com/bar/baz/', 'https://www.foo.com/bar/baz/', + 'https://learning.edge.foo.bar', 'https://learning.edge.foo.bar/foo' + ) + def test_enabled(self, http_referer): + request = self.get_request(is_secure=True, http_referer=http_referer) self.check_enabled(request) @override_settings( FEATURES={'ENABLE_CORS_HEADERS': False}, - CORS_ORIGIN_WHITELIST=['foo.com'] + CORS_ORIGIN_WHITELIST=['https://foo.com'] ) def test_disabled_no_cors_headers(self): with pytest.raises(MiddlewareNotUsed): CorsCSRFMiddleware() - @override_settings(CORS_ORIGIN_WHITELIST=['bar.com']) + @override_settings(CORS_ORIGIN_WHITELIST=['https://bar.com']) def test_disabled_wrong_cors_domain(self): request = self.get_request(is_secure=True, http_referer='https://foo.com/bar') self.check_not_enabled(request) - @override_settings(CORS_ORIGIN_WHITELIST=['foo.com']) + @override_settings(CORS_ORIGIN_WHITELIST=['https://foo.com']) def test_disabled_wrong_cors_domain_reversed(self): request = self.get_request(is_secure=True, http_referer='https://bar.com/bar') self.check_not_enabled(request) - @override_settings(CORS_ORIGIN_WHITELIST=['foo.com']) + @override_settings(CORS_ORIGIN_WHITELIST=['https://foo.com']) def test_disabled_http_request(self): request = self.get_request(is_secure=False, http_referer='https://foo.com/bar') self.check_not_enabled(request) - @override_settings(CORS_ORIGIN_WHITELIST=['foo.com']) + @override_settings(CORS_ORIGIN_WHITELIST=['https://foo.com']) def test_disabled_http_referer(self): request = self.get_request(is_secure=True, http_referer='http://foo.com/bar') self.check_not_enabled(request) @@ -220,7 +227,7 @@ class TestCsrfCrossDomainCookieMiddleware(TestCase): @override_settings( CROSS_DOMAIN_CSRF_COOKIE_NAME=COOKIE_NAME, CROSS_DOMAIN_CSRF_COOKIE_DOMAIN=COOKIE_DOMAIN, - CORS_ORIGIN_WHITELIST=['www.example.com'] + CORS_ORIGIN_WHITELIST=['https://www.example.com'] ) def test_set_cross_domain_cookie(self): response = self._get_response() diff --git a/openedx/core/djangoapps/enrollments/tests/test_views.py b/openedx/core/djangoapps/enrollments/tests/test_views.py index d78922190b..a55f2a7760 100644 --- a/openedx/core/djangoapps/enrollments/tests/test_views.py +++ b/openedx/core/djangoapps/enrollments/tests/test_views.py @@ -1260,7 +1260,7 @@ def cross_domain_config(func): 'ENABLE_CROSS_DOMAIN_CSRF_COOKIE': True }) settings_decorator = override_settings( - CORS_ORIGIN_WHITELIST=["www.edx.org"], + CORS_ORIGIN_WHITELIST=["https://www.edx.org"], CROSS_DOMAIN_CSRF_COOKIE_NAME="prod-edx-csrftoken", CROSS_DOMAIN_CSRF_COOKIE_DOMAIN=".edx.org" ) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index cd40bcb595..457c2a5821 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -24,8 +24,8 @@ django-celery-results<2.1 # We do not support version django-config-models<1.0.0 django-config-models>=1.0.0 -# The CORS_ORIGIN_WHITELIST changes in a backwards incompatible way in 3.0.0, needs matching configuration repo changes -django-cors-headers<3.0.0 +# greater version has breaking changes `settings have been renamed`. Check https://github.com/adamchainz/django-cors-headers/blob/main/HISTORY.rst#350-2020-08-25 +django-cors-headers==3.2.0 # django-storages version 1.9 drops support for boto storage backend. django-storages<1.9 diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 817011bfdd..03547d0a6e 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -248,7 +248,7 @@ django-config-models==2.2.0 # lti-consumer-xblock django-cookies-samesite==0.9.0 # via -r requirements/edx/base.in -django-cors-headers==2.5.3 +django-cors-headers==3.2.0 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 4b298330e1..869c8428b5 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -329,7 +329,7 @@ django-config-models==2.2.0 # lti-consumer-xblock django-cookies-samesite==0.9.0 # via -r requirements/edx/testing.txt -django-cors-headers==2.5.3 +django-cors-headers==3.2.0 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/testing.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 7b52a0bb44..f8ede7eff1 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -314,7 +314,7 @@ django-config-models==2.2.0 # lti-consumer-xblock django-cookies-samesite==0.9.0 # via -r requirements/edx/base.txt -django-cors-headers==2.5.3 +django-cors-headers==3.2.0 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt