diff --git a/h/security/policy/_api_cookie.py b/h/security/policy/_api_cookie.py index 322a3b1801b..f9076ff4487 100644 --- a/h/security/policy/_api_cookie.py +++ b/h/security/policy/_api_cookie.py @@ -1,8 +1,10 @@ from pyramid.request import Request from pyramid.security import Allowed, Denied +from webob.cookies import SignedCookieProfile from h.security.identity import Identity -from h.security.policy._cookie import CookiePolicy +from h.security.permits import identity_permits +from h.security.policy.helpers import AuthTicketCookieHelper COOKIE_AUTHENTICATABLE_API_REQUESTS = [ ("api.groups", "POST"), # Create a new group. @@ -13,8 +15,9 @@ class APICookiePolicy: """Authenticate API requests with cookies.""" - def __init__(self, cookie_policy: CookiePolicy): - self.cookie_policy = cookie_policy + def __init__(self, cookie: SignedCookieProfile, helper: AuthTicketCookieHelper): + self.cookie = cookie + self.helper = helper @staticmethod def handles(request: Request) -> bool: @@ -25,10 +28,11 @@ def handles(request: Request) -> bool: ) in COOKIE_AUTHENTICATABLE_API_REQUESTS def identity(self, request: Request) -> Identity | None: - return self.cookie_policy.identity(request) + self.helper.add_vary_by_cookie(request) + return self.helper.identity(self.cookie, request) def authenticated_userid(self, request: Request) -> str | None: - return self.cookie_policy.authenticated_userid(request) + return Identity.authenticated_userid(self.identity(request)) def permits(self, request: Request, context, permission: str) -> Allowed | Denied: - return self.cookie_policy.permits(request, context, permission) + return identity_permits(self.identity(request), context, permission) diff --git a/h/security/policy/_cookie.py b/h/security/policy/_cookie.py index bac30380633..b1d657a58b4 100644 --- a/h/security/policy/_cookie.py +++ b/h/security/policy/_cookie.py @@ -1,13 +1,9 @@ -import base64 -from functools import lru_cache -from os import urandom - -import webob from pyramid.security import Allowed, Denied +from webob.cookies import SignedCookieProfile from h.security.identity import Identity from h.security.permits import identity_permits -from h.services.auth_ticket import AuthTicketService +from h.security.policy.helpers import AuthTicketCookieHelper class CookiePolicy: @@ -18,32 +14,22 @@ class CookiePolicy: straps the login for the client (when the popup shows). """ - def __init__(self, cookie: webob.cookies.SignedCookieProfile): + def __init__(self, cookie: SignedCookieProfile, helper: AuthTicketCookieHelper): self.cookie = cookie + self.helper = helper def identity(self, request): - self._add_vary_by_cookie(request) - - userid, ticket_id = self._get_cookie_value() - - user = request.find_service(AuthTicketService).verify_ticket(userid, ticket_id) - - if (not user) or user.deleted: - return None - - return Identity.from_models(user=user) + self.helper.add_vary_by_cookie(request) + return self.helper.identity(self.cookie, request) def authenticated_userid(self, request): return Identity.authenticated_userid(self.identity(request)) def remember(self, request, userid, **kw): # pylint:disable=unused-argument - """Get a list of headers which will remember the user in a cookie.""" - - self._add_vary_by_cookie(request) + self.helper.add_vary_by_cookie(request) previous_userid = self.authenticated_userid(request) - # Clear the previous session if previous_userid != userid: request.session.invalidate() else: @@ -55,37 +41,11 @@ def remember(self, request, userid, **kw): # pylint:disable=unused-argument request.session.update(data) request.session.new_csrf_token() - ticket_id = base64.urlsafe_b64encode(urandom(32)).rstrip(b"=").decode("ascii") - request.find_service(AuthTicketService).add_ticket(userid, ticket_id) - return self.cookie.get_headers([userid, ticket_id]) + return self.helper.remember(self.cookie, request, userid) def forget(self, request): - """Get a list of headers which will delete appropriate cookies.""" - - self._add_vary_by_cookie(request) - - # Clear the session by invalidating it - request.session.invalidate() - - _, ticket_id = self._get_cookie_value() - - if ticket_id: - request.find_service(AuthTicketService).remove_ticket(ticket_id) - - return self.cookie.get_headers(None, max_age=0) + self.helper.add_vary_by_cookie(request) + return self.helper.forget(self.cookie, request) def permits(self, request, context, permission) -> Allowed | Denied: return identity_permits(self.identity(request), context, permission) - - @staticmethod - @lru_cache # Ensure we only add this once per request - def _add_vary_by_cookie(request): - def vary_add(request, response): # pylint:disable=unused-argument - vary = set(response.vary if response.vary is not None else []) - vary.add("Cookie") - response.vary = list(vary) - - request.add_response_callback(vary_add) - - def _get_cookie_value(self): - return self.cookie.get_value() or (None, None) diff --git a/h/security/policy/helpers.py b/h/security/policy/helpers.py index 55c96b04142..db41e6a6989 100644 --- a/h/security/policy/helpers.py +++ b/h/security/policy/helpers.py @@ -1,3 +1,56 @@ +from base64 import urlsafe_b64encode +from functools import lru_cache +from os import urandom + +from pyramid.request import Request +from webob.cookies import SignedCookieProfile + +from h.security.identity import Identity +from h.services.auth_ticket import AuthTicketService + + def is_api_request(request) -> bool: """Return True if `request` is an API request.""" return bool(request.matched_route and request.matched_route.name.startswith("api.")) + + +class AuthTicketCookieHelper: + def identity( + self, cookie: SignedCookieProfile, request: Request + ) -> Identity | None: + userid, ticket_id = self.get_cookie_value(cookie) + + user = request.find_service(AuthTicketService).verify_ticket(userid, ticket_id) + + if (not user) or user.deleted: + return None + + return Identity.from_models(user=user) + + def remember(self, cookie: SignedCookieProfile, request: Request, userid: str): + ticket_id = urlsafe_b64encode(urandom(32)).rstrip(b"=").decode("ascii") + request.find_service(AuthTicketService).add_ticket(userid, ticket_id) + return cookie.get_headers([userid, ticket_id]) + + def forget(self, cookie: SignedCookieProfile, request: Request): + request.session.invalidate() + _, ticket_id = self.get_cookie_value(cookie) + + if ticket_id: + request.find_service(AuthTicketService).remove_ticket(ticket_id) + + return cookie.get_headers(None, max_age=0) + + @staticmethod + @lru_cache # Ensure we only add this once per request + def add_vary_by_cookie(request: Request): + def vary_add(request, response): # pylint:disable=unused-argument + vary = set(response.vary if response.vary is not None else []) + vary.add("Cookie") + response.vary = list(vary) + + request.add_response_callback(vary_add) + + @staticmethod + def get_cookie_value(cookie: SignedCookieProfile): + return cookie.get_value() or (None, None) diff --git a/h/security/policy/top_level.py b/h/security/policy/top_level.py index ef3a3b745ce..53ca312328f 100644 --- a/h/security/policy/top_level.py +++ b/h/security/policy/top_level.py @@ -8,7 +8,7 @@ from h.security.policy._auth_client import AuthClientPolicy from h.security.policy._cookie import CookiePolicy from h.security.policy.bearer_token import BearerTokenPolicy -from h.security.policy.helpers import is_api_request +from h.security.policy.helpers import AuthTicketCookieHelper, is_api_request class TopLevelPolicy: @@ -56,8 +56,8 @@ def get_subpolicy(request): [ BearerTokenPolicy(), AuthClientPolicy(), - APICookiePolicy(CookiePolicy(cookie)), + APICookiePolicy(cookie, AuthTicketCookieHelper()), ] ) - return CookiePolicy(cookie) + return CookiePolicy(cookie, AuthTicketCookieHelper()) diff --git a/tests/unit/h/security/policy/_api_cookie_test.py b/tests/unit/h/security/policy/_api_cookie_test.py index fe257b4c073..7843f88e160 100644 --- a/tests/unit/h/security/policy/_api_cookie_test.py +++ b/tests/unit/h/security/policy/_api_cookie_test.py @@ -3,7 +3,7 @@ import pytest from h.security.policy._api_cookie import APICookiePolicy -from h.security.policy._cookie import CookiePolicy +from h.security.policy.helpers import AuthTicketCookieHelper class TestAPICookiePolicy: @@ -24,34 +24,57 @@ def test_handles( assert APICookiePolicy.handles(pyramid_request) == expected_result - def test_identity(self, api_cookie_policy, cookie_policy, pyramid_request): + def test_identity(self, api_cookie_policy, helper, pyramid_request): identity = api_cookie_policy.identity(pyramid_request) - cookie_policy.identity.assert_called_once_with(pyramid_request) - assert identity == cookie_policy.identity.return_value + helper.add_vary_by_cookie.assert_called_once_with(pyramid_request) + helper.identity.assert_called_once_with(sentinel.cookie, pyramid_request) + assert identity == helper.identity.return_value def test_authenticated_userid( - self, api_cookie_policy, cookie_policy, pyramid_request + self, api_cookie_policy, helper, pyramid_request, Identity ): authenticated_userid = api_cookie_policy.authenticated_userid(pyramid_request) - cookie_policy.authenticated_userid.assert_called_once_with(pyramid_request) - assert authenticated_userid == cookie_policy.authenticated_userid.return_value + helper.add_vary_by_cookie.assert_called_once_with(pyramid_request) + helper.identity.assert_called_once_with(sentinel.cookie, pyramid_request) + Identity.authenticated_userid.assert_called_once_with( + helper.identity.return_value + ) + assert authenticated_userid == Identity.authenticated_userid.return_value - def test_permits(self, api_cookie_policy, cookie_policy, pyramid_request): + def test_permits( + self, api_cookie_policy, helper, pyramid_request, identity_permits + ): permits = api_cookie_policy.permits( pyramid_request, sentinel.context, sentinel.permission ) - cookie_policy.permits.assert_called_once_with( - pyramid_request, sentinel.context, sentinel.permission + helper.add_vary_by_cookie.assert_called_once_with(pyramid_request) + helper.identity.assert_called_once_with(sentinel.cookie, pyramid_request) + identity_permits.assert_called_once_with( + helper.identity.return_value, sentinel.context, sentinel.permission ) - assert permits == cookie_policy.permits.return_value + assert permits == identity_permits.return_value @pytest.fixture - def cookie_policy(self): - return create_autospec(CookiePolicy, instance=True, spec_set=True) + def helper(self): + return create_autospec(AuthTicketCookieHelper, instance=True, spec_set=True) @pytest.fixture - def api_cookie_policy(self, cookie_policy): - return APICookiePolicy(cookie_policy) + def api_cookie_policy(self, helper): + return APICookiePolicy(sentinel.cookie, helper) + + +@pytest.fixture(autouse=True) +def Identity(mocker): + return mocker.patch( + "h.security.policy._api_cookie.Identity", autospec=True, spec_set=True + ) + + +@pytest.fixture(autouse=True) +def identity_permits(mocker): + return mocker.patch( + "h.security.policy._api_cookie.identity_permits", autospec=True, spec_set=True + ) diff --git a/tests/unit/h/security/policy/_cookie_test.py b/tests/unit/h/security/policy/_cookie_test.py index b8811cec868..3d77443a89a 100644 --- a/tests/unit/h/security/policy/_cookie_test.py +++ b/tests/unit/h/security/policy/_cookie_test.py @@ -1,185 +1,82 @@ from unittest.mock import create_autospec, sentinel import pytest -import webob -from h_matchers import Any -from h.security.policy import _cookie -from h.security.policy._cookie import CookiePolicy, base64 +from h.security.policy._cookie import CookiePolicy +from h.security.policy.helpers import AuthTicketCookieHelper -@pytest.mark.usefixtures("auth_ticket_service") class TestCookiePolicy: - def test_identity( - self, pyramid_request, auth_ticket_service, cookie_policy, user, Identity - ): + def test_identity(self, cookie_policy, helper, pyramid_request): identity = cookie_policy.identity(pyramid_request) - auth_ticket_service.verify_ticket.assert_called_once_with( - user.userid, sentinel.ticket_id - ) - Identity.from_models.assert_called_once_with( - user=auth_ticket_service.verify_ticket.return_value - ) - assert identity == Identity.from_models.return_value - - def test_identity_when_user_marked_as_deleted( - self, pyramid_request, auth_ticket_service, cookie_policy - ): - auth_ticket_service.verify_ticket.return_value.deleted = True - - assert cookie_policy.identity(pyramid_request) is None - - def test_identity_with_no_auth_ticket( - self, pyramid_request, auth_ticket_service, cookie_policy - ): - auth_ticket_service.verify_ticket.return_value = None - - assert cookie_policy.identity(pyramid_request) is None + helper.add_vary_by_cookie.assert_called_once_with(pyramid_request) + helper.identity.assert_called_once_with(sentinel.cookie, pyramid_request) + assert identity == helper.identity.return_value def test_authenticated_userid( - self, pyramid_request, cookie_policy, Identity, mocker + self, cookie_policy, helper, pyramid_request, Identity ): - mocker.spy(cookie_policy, "identity") - authenticated_userid = cookie_policy.authenticated_userid(pyramid_request) - cookie_policy.identity.assert_called_once_with(pyramid_request) + helper.add_vary_by_cookie.assert_called_once_with(pyramid_request) + helper.identity.assert_called_once_with(sentinel.cookie, pyramid_request) Identity.authenticated_userid.assert_called_once_with( - cookie_policy.identity.spy_return + helper.identity.return_value ) assert authenticated_userid == Identity.authenticated_userid.return_value - def test_remember( - self, - pyramid_request, - auth_ticket_service, - user, - cookie, - cookie_policy, - urlsafe_b64encode, - urandom, - ): + def test_remember(self, cookie_policy, helper, pyramid_request): pyramid_request.session["data"] = "old" - auth_ticket_service.verify_ticket.return_value = user - result = cookie_policy.remember(pyramid_request, sentinel.userid) + headers = cookie_policy.remember(pyramid_request, sentinel.userid, foo="bar") - # The `pyramid.testing.DummySession` is a dict so this is the closest - # we can get to saying it's been invalidated assert not pyramid_request.session - urandom.assert_called_once_with(32) - urlsafe_b64encode.assert_called_once_with(urandom.spy_return) - ticket_id = urlsafe_b64encode.spy_return.rstrip(b"=").decode("ascii") - auth_ticket_service.add_ticket.assert_called_once_with( - sentinel.userid, ticket_id + helper.remember.assert_called_once_with( + sentinel.cookie, pyramid_request, sentinel.userid ) - cookie.get_headers.assert_called_once_with([sentinel.userid, ticket_id]) - assert result == cookie.get_headers.return_value + assert headers == helper.remember.return_value def test_remember_with_existing_user( - self, pyramid_request, user, cookie_policy, Identity + self, cookie_policy, pyramid_request, factories, Identity ): + user = factories.User() pyramid_request.session["data"] = "old" # This is a secret parameter used by `pyramid.testing.DummySession` pyramid_request.session["_csrft_"] = "old_csrf_token" Identity.authenticated_userid.return_value = user.userid - cookie_policy.remember(pyramid_request, user.userid) + cookie_policy.remember(pyramid_request, user.userid, foo="bar") assert pyramid_request.session["data"] == "old" assert pyramid_request.session["_csrft_"] != "old_csrf_token" - def test_forget(self, pyramid_request, auth_ticket_service, cookie_policy, cookie): - pyramid_request.session["data"] = "old" - - result = cookie_policy.forget(pyramid_request) - - # The `pyramid.testing.DummySession` is a dict so this is the closest - # we can get to saying it's been invalidated - assert not pyramid_request.session - auth_ticket_service.remove_ticket.assert_called_once_with(sentinel.ticket_id) - cookie.get_headers.assert_called_once_with(None, max_age=0) - assert result == cookie.get_headers.return_value + def test_forget(self, cookie_policy, helper, pyramid_request): + headers = cookie_policy.forget(pyramid_request) - def test_forget_when_no_ticket_id_in_cookie( - self, auth_ticket_service, cookie, cookie_policy, pyramid_request - ): - cookie.get_value.return_value = None - - result = cookie_policy.forget(pyramid_request) - - assert not pyramid_request.session - auth_ticket_service.remove_ticket.assert_not_called() - cookie.get_headers.assert_called_once_with(None, max_age=0) - assert result == cookie.get_headers.return_value + helper.add_vary_by_cookie.assert_called_once_with(pyramid_request) + helper.forget.assert_called_once_with(sentinel.cookie, pyramid_request) + assert headers == helper.forget.return_value - def test_permits(self, cookie_policy, pyramid_request, mocker, identity_permits): - mocker.spy(cookie_policy, "identity") - - result = cookie_policy.permits( + def test_permits(self, cookie_policy, helper, pyramid_request, identity_permits): + permits = cookie_policy.permits( pyramid_request, sentinel.context, sentinel.permission ) - cookie_policy.identity.assert_called_once_with(pyramid_request) + helper.add_vary_by_cookie.assert_called_once_with(pyramid_request) + helper.identity.assert_called_once_with(sentinel.cookie, pyramid_request) identity_permits.assert_called_once_with( - cookie_policy.identity.spy_return, sentinel.context, sentinel.permission - ) - assert result == identity_permits.return_value - - @pytest.mark.parametrize( - "method,args", - (("identity", ()), ("remember", (sentinel.userid,)), ("forget", ())), - ) - @pytest.mark.parametrize( - "vary,expected_vary", - ( - (None, ["Cookie"]), - (["Cookie"], ["Cookie"]), - (["Other"], ["Cookie", "Other"]), - ), - ) - def test_methods_add_vary_callback( - self, pyramid_request, method, args, vary, expected_vary, cookie_policy - ): - pyramid_request.response.vary = vary - getattr(cookie_policy, method)(pyramid_request, *args) - - assert len(pyramid_request.response_callbacks) == 1 - callback = pyramid_request.response_callbacks[0] - - callback(pyramid_request, pyramid_request.response) - - assert ( - pyramid_request.response.vary - == Any.iterable.containing(expected_vary).only() + helper.identity.return_value, sentinel.context, sentinel.permission ) + assert permits == identity_permits.return_value @pytest.fixture - def cookie(self, user): - cookie = create_autospec( - webob.cookies.SignedCookieProfile, instance=True, spec_set=True - ) - cookie.get_value.return_value = (user.userid, sentinel.ticket_id) - return cookie - - @pytest.fixture - def cookie_policy(self, cookie): - return CookiePolicy(cookie) + def helper(self): + return create_autospec(AuthTicketCookieHelper, instance=True, spec_set=True) @pytest.fixture - def user(self, factories): - return factories.User() - - -@pytest.fixture(autouse=True) -def urlsafe_b64encode(mocker): - return mocker.spy(base64, "urlsafe_b64encode") - - -@pytest.fixture(autouse=True) -def urandom(mocker): - return mocker.spy(_cookie, "urandom") + def cookie_policy(self, helper): + return CookiePolicy(sentinel.cookie, helper) @pytest.fixture(autouse=True) diff --git a/tests/unit/h/security/policy/helpers_test.py b/tests/unit/h/security/policy/helpers_test.py index 49fe361bdd9..b3b59b37cc2 100644 --- a/tests/unit/h/security/policy/helpers_test.py +++ b/tests/unit/h/security/policy/helpers_test.py @@ -1,22 +1,138 @@ +from unittest.mock import create_autospec, sentinel + import pytest +from webob.cookies import SignedCookieProfile + +from h.security.policy import helpers +from h.security.policy.helpers import AuthTicketCookieHelper, is_api_request + + +class TestIsAPIRequest: + @pytest.mark.parametrize( + "route_name,expected_result", + [ + ("anything", False), + ("api.anything", True), + ], + ) + def test_it(self, pyramid_request, route_name, expected_result): + pyramid_request.matched_route.name = route_name + + assert is_api_request(pyramid_request) == expected_result + + def test_it_when_matched_route_is_None(self, pyramid_request): + pyramid_request.matched_route = None + + assert is_api_request(pyramid_request) is False + + +class TestAuthTicketCookieHelper: + def test_identity( + self, auth_ticket_service, cookie, helper, pyramid_request, Identity + ): + identity = helper.identity(cookie, pyramid_request) + + auth_ticket_service.verify_ticket.assert_called_once_with( + sentinel.userid, sentinel.ticket_id + ) + Identity.from_models.assert_called_once_with( + user=auth_ticket_service.verify_ticket.return_value + ) + assert identity == Identity.from_models.return_value + + def test_identity_when_no_user( + self, auth_ticket_service, cookie, helper, pyramid_request + ): + auth_ticket_service.verify_ticket.return_value = None + + assert helper.identity(cookie, pyramid_request) is None + + def test_identity_when_user_deleted( + self, auth_ticket_service, cookie, helper, pyramid_request + ): + auth_ticket_service.verify_ticket.return_value.deleted = True + + assert helper.identity(cookie, pyramid_request) is None + + def test_remember( + self, auth_ticket_service, cookie, helper, pyramid_request, mocker + ): + urandom = mocker.spy(helpers, "urandom") + urlsafe_b64encode = mocker.spy(helpers, "urlsafe_b64encode") + + headers = helper.remember(cookie, pyramid_request, "test_userid") + + urandom.assert_called_once_with(32) + urlsafe_b64encode.assert_called_once_with(urandom.spy_return) + ticket_id = urlsafe_b64encode.spy_return.rstrip(b"=").decode("ascii") + auth_ticket_service.add_ticket.assert_called_once_with("test_userid", ticket_id) + cookie.get_headers.assert_called_once_with(["test_userid", ticket_id]) + assert headers == cookie.get_headers.return_value + + def test_forget(self, auth_ticket_service, cookie, helper, pyramid_request): + headers = helper.forget(cookie, pyramid_request) + + auth_ticket_service.remove_ticket.assert_called_once_with(sentinel.ticket_id) + cookie.get_headers.assert_called_once_with(None, max_age=0) + assert headers == cookie.get_headers.return_value + + def test_forget_when_no_ticket_id( + self, auth_ticket_service, cookie, helper, pyramid_request + ): + cookie.get_value.return_value = None + + headers = helper.forget(cookie, pyramid_request) + + auth_ticket_service.remove_ticket.assert_not_called() + cookie.get_headers.assert_called_once_with(None, max_age=0) + assert headers == cookie.get_headers.return_value + + @pytest.mark.parametrize( + "vary,expected_vary", + ( + (None, ["Cookie"]), + (["Cookie"], ["Cookie"]), + (["Other"], ["Cookie", "Other"]), + ), + ) + def test_add_vary_by_cookie(self, pyramid_request, vary, expected_vary): + pyramid_request.response.vary = vary + + AuthTicketCookieHelper.add_vary_by_cookie(pyramid_request) -from h.security.policy.helpers import is_api_request + assert len(pyramid_request.response_callbacks) == 1 + callback = pyramid_request.response_callbacks[0] + callback(pyramid_request, pyramid_request.response) + assert sorted(pyramid_request.response.vary) == sorted(expected_vary) + @pytest.mark.parametrize( + "value,expected_result", + [ + (None, (None, None)), + ( + (sentinel.userid, sentinel.ticket_id), + (sentinel.userid, sentinel.ticket_id), + ), + ], + ) + def test_get_cookie_value(self, cookie, value, expected_result): + cookie.get_value.return_value = value -@pytest.mark.parametrize( - "route_name,expected_result", - [ - ("anything", False), - ("api.anything", True), - ], -) -def test_is_api_request(pyramid_request, route_name, expected_result): - pyramid_request.matched_route.name = route_name + assert AuthTicketCookieHelper.get_cookie_value(cookie) == expected_result - assert is_api_request(pyramid_request) == expected_result + @pytest.fixture + def cookie(self): + cookie = create_autospec(SignedCookieProfile, instance=True, spec_set=True) + cookie.get_value.return_value = (sentinel.userid, sentinel.ticket_id) + return cookie + @pytest.fixture + def helper(self): + return AuthTicketCookieHelper() -def test_is_api_request_when_matched_route_is_None(pyramid_request): - pyramid_request.matched_route = None - assert is_api_request(pyramid_request) is False +@pytest.fixture(autouse=True) +def Identity(mocker): + return mocker.patch( + "h.security.policy.helpers.Identity", autospec=True, spec_set=True + ) diff --git a/tests/unit/h/security/policy/top_level_test.py b/tests/unit/h/security/policy/top_level_test.py index a4919fb9545..dfdd0e85394 100644 --- a/tests/unit/h/security/policy/top_level_test.py +++ b/tests/unit/h/security/policy/top_level_test.py @@ -65,8 +65,8 @@ def test_api_request( APICookiePolicy, APIPolicy, BearerTokenPolicy, - CookiePolicy, webob, + AuthTicketCookieHelper, ): is_api_request.return_value = True @@ -85,10 +85,11 @@ def test_api_request( webob.cookies.SignedCookieProfile.return_value.bind.assert_called_once_with( pyramid_request ) - CookiePolicy.assert_called_once_with( - webob.cookies.SignedCookieProfile.return_value.bind.return_value + AuthTicketCookieHelper.assert_called_once_with() + APICookiePolicy.assert_called_once_with( + webob.cookies.SignedCookieProfile.return_value.bind.return_value, + AuthTicketCookieHelper.return_value, ) - APICookiePolicy.assert_called_once_with(CookiePolicy.return_value) APIPolicy.assert_called_once_with( [ BearerTokenPolicy.return_value, @@ -99,7 +100,12 @@ def test_api_request( assert policy == APIPolicy.return_value def test_non_api_request( - self, is_api_request, pyramid_request, CookiePolicy, webob + self, + is_api_request, + pyramid_request, + CookiePolicy, + webob, + AuthTicketCookieHelper, ): is_api_request.return_value = False @@ -116,8 +122,10 @@ def test_non_api_request( webob.cookies.SignedCookieProfile.return_value.bind.assert_called_once_with( pyramid_request ) + AuthTicketCookieHelper.assert_called_once_with() CookiePolicy.assert_called_once_with( - webob.cookies.SignedCookieProfile.return_value.bind.return_value + webob.cookies.SignedCookieProfile.return_value.bind.return_value, + AuthTicketCookieHelper.return_value, ) assert policy == CookiePolicy.return_value @@ -132,6 +140,13 @@ def AuthClientPolicy(mocker): return mocker.patch("h.security.policy.top_level.AuthClientPolicy", autospec=True) +@pytest.fixture(autouse=True) +def AuthTicketCookieHelper(mocker): + return mocker.patch( + "h.security.policy.top_level.AuthTicketCookieHelper", autospec=True + ) + + @pytest.fixture(autouse=True) def APICookiePolicy(mocker): return mocker.patch("h.security.policy.top_level.APICookiePolicy", autospec=True)