diff --git a/lms/envs/common.py b/lms/envs/common.py index 459a04f0c928b3b9da00811553b077c0eaa459a4..889228d95e97998d4f0522074419f5a15d865d42 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -3171,7 +3171,7 @@ JWT_AUTH = { # Number of seconds before JWTs expire 'JWT_EXPIRATION': 30, - 'JWT_COOKIE_EXPIRATION': 60 * 60, + 'JWT_IN_COOKIE_EXPIRATION': 60 * 60, 'JWT_LOGIN_CLIENT_ID': 'login-service-client-id', 'JWT_LOGIN_SERVICE_USERNAME': 'login_service_user', diff --git a/openedx/core/djangoapps/user_authn/cookies.py b/openedx/core/djangoapps/user_authn/cookies.py index fcdb083ba8681fd2578a8ea7e817726a93242119..06a2725bfd8ce0fe9dbc5659622a7a5608d05097 100644 --- a/openedx/core/djangoapps/user_authn/cookies.py +++ b/openedx/core/djangoapps/user_authn/cookies.py @@ -90,7 +90,8 @@ def standard_cookie_settings(request): expires = None else: max_age = request.session.get_expiry_age() - expires = _cookie_expiration_based_on_max_age(max_age) + _expires_time = time.time() + max_age + expires = cookie_date(_expires_time) cookie_settings = { 'max_age': max_age, @@ -246,10 +247,13 @@ def _create_and_set_jwt_cookies(response, request, user=None, refresh_token=None if not JWT_COOKIES_FLAG.is_enabled(): return - # TODO (ARCH-246) Need to fix configuration of token expiration settings. + # JWT cookies expire at the same time as other login-related cookies + # so that cookie-based login determination remains consistent. cookie_settings = standard_cookie_settings(request) - _set_jwt_expiration(cookie_settings) - expires_in = cookie_settings['max_age'] + + # For security reasons, the JWT that is embedded inside the cookie expires + # much sooner than the cookie itself, per the following setting. + expires_in = settings.JWT_AUTH['JWT_IN_COOKIE_EXPIRATION'] oauth_application = _get_login_oauth_client() if refresh_token: @@ -306,21 +310,6 @@ def _set_jwt_cookies(response, cookie_settings, jwt_header_and_payload, jwt_sign ) -def _set_jwt_expiration(cookie_settings): - """ - Updates cookie_settings with the configured expiration values for JWT - Cookies. - """ - max_age = settings.JWT_AUTH['JWT_COOKIE_EXPIRATION'] - cookie_settings['max_age'] = max_age - cookie_settings['expires'] = _cookie_expiration_based_on_max_age(max_age) - - -def _cookie_expiration_based_on_max_age(max_age): - expires_time = time.time() + max_age - return cookie_date(expires_time) - - def _get_login_oauth_client(): """ Returns the configured OAuth Client/Application used for Login. diff --git a/openedx/core/djangoapps/user_authn/tests/test_cookies.py b/openedx/core/djangoapps/user_authn/tests/test_cookies.py index 41474ec4632cf329b3ea7d5b131cee25af75a11f..4bc0154ea48e628dc05b42dba2c9d70617d77a85 100644 --- a/openedx/core/djangoapps/user_authn/tests/test_cookies.py +++ b/openedx/core/djangoapps/user_authn/tests/test_cookies.py @@ -60,7 +60,7 @@ class CookieTests(TestCase): Verifies that a JWT can be properly recreated from the 2 separate JWT-related cookies using the JwtAuthCookieMiddleware middleware. """ - self.request.COOKIES = response.cookies + self._copy_cookies_to_request(response, self.request) JwtAuthCookieMiddleware().process_request(self.request) self.assertEqual( cookies_api.jwt_cookies.jwt_cookie_name() in self.request.COOKIES, @@ -68,8 +68,13 @@ class CookieTests(TestCase): ) def _assert_cookies_present(self, response, expected_cookies): + """ Verify all expected_cookies are present in the response. """ self.assertSetEqual(set(response.cookies.keys()), set(expected_cookies)) + def _assert_consistent_expires(self, response): + """ Verify all cookies in the response have the same expiration. """ + self.assertEqual(1, len(set([response.cookies[c]['expires'] for c in response.cookies]))) + def test_get_user_info_cookie_data(self): actual = cookies_api._get_user_info_cookie_data(self.request, self.user) # pylint: disable=protected-access @@ -90,6 +95,7 @@ class CookieTests(TestCase): def test_set_logged_in_deprecated_cookies(self): response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user) self._assert_cookies_present(response, cookies_api.DEPRECATED_LOGGED_IN_COOKIE_NAMES) + self._assert_consistent_expires(response) self._assert_recreate_jwt_from_cookies(response, can_recreate=False) def test_set_logged_in_jwt_cookies(self): @@ -97,6 +103,7 @@ class CookieTests(TestCase): with cookies_api.JWT_COOKIES_FLAG.override(True): response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user) self._assert_cookies_present(response, cookies_api.ALL_LOGGED_IN_COOKIE_NAMES) + self._assert_consistent_expires(response) self._assert_recreate_jwt_from_cookies(response, can_recreate=True) def test_delete_and_is_logged_in_cookie_set(self):