async def test_body_field_with_site_use_case( self, mocked_get_user_roles_for_site): """ If a body field is present, it must be a dictionary containing: * the target user id (user_id) * the role to be assigned (role_id) * either the site or domain to which it must be assigned (site_id or role_id) """ @requester_has_role(body_field=1) # Correct def call_with_body(request, body, **kwargs): return True body = {"user_id": self.user.hex, "role_id": 1, "site_id": 1} # Test the case where the requester has no roles for the specified domain. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( set()) with self.assertRaises(JSONForbidden): await call_with_body(self.mocked_request, body) # Test the case where the requester has the role for the specified domain. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {1}) self.assertTrue(await call_with_body(self.mocked_request, body)) # Test the case where the requester has the TECH_ADMIN role mocked_get_user_roles_for_site.side_effect = return_tech_admin_role_for_testing self.assertTrue(await call_with_body(self.mocked_request, body))
async def test_no_body_field_with_site_use_case( self, field, mocked_get_user_roles_for_site): kwargs = {field: 1, "site_id_field": 2, "role_id_field": 3} @requester_has_role(**kwargs) def call_without_body(request, user_or_invitation, site, role, **kwargs): return True # Test the case where the requester has no roles for the specified domain. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( set()) with self.assertRaises(JSONForbidden): await call_without_body(self.mocked_request, self.user.hex, 1, 1) # Test the case where the requester has the role for the specified domain. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {1}) self.assertTrue(await call_without_body(self.mocked_request, self.user.hex, 1, 1)) # Test the case where the requester has the TECH_ADMIN role mocked_get_user_roles_for_site.side_effect = return_tech_admin_role_for_testing self.assertTrue(await call_without_body(self.mocked_request, self.user.hex, 1, 1))
async def test_empty_resource_permissions_lists(self, mocked_function): """ Check the expected behaviour when an empty resource permission list is used with the any or all operation. We mock a response for the get_user_roles_for_site() function in order to test the case where the specified required resource permission list is empty. """ # require_permissions(all, []) always succeeds, regardless of which # roles the user has. @require_permissions(all, [], nocache=True) def empty_all(_request): return True # require_permissions(any, []) always fails, regardless of which roles # the user has. @require_permissions(any, [], nocache=True) def empty_any(_request): return "You must be a tech admin" mocked_function.side_effect = make_coroutine_returning( {0}) # An arbitrary id # Always gets allowed, regardless of the user's roles self.assertTrue(await empty_all(self.mocked_request)) # Never gets allowed unless the user has the TECH_ADMIN role with self.assertRaises(JSONForbidden): await empty_any(self.mocked_request) mocked_function.side_effect = make_coroutine_returning( {Mappings.role_id_for(TECH_ADMIN_ROLE_LABEL)}) self.assertEqual(await empty_any(self.mocked_request), "You must be a tech admin")
async def test_management_portal_allowed_permission(self, mocked_function): """ When a permission decorator specifies that the Management Portal should be allowed to make the request, even if the user does not have the permission, the permission is granted. """ @require_permissions(any, [], nocache=True, allow_for_management_portal=True) def example_call(_request): # The caller is also the target user return _request["token"]["aud"] == MANAGEMENT_PORTAL_CLIENT_ID mocked_function.side_effect = make_coroutine_returning( set()) # No roles # This call is not allowed because the request is not made from the Management Portal with self.assertRaises(JSONForbidden): await example_call(self.mocked_request) mocked_request_from_management_portal = self.mocked_request mocked_request_from_management_portal["token"][ "aud"] = MANAGEMENT_PORTAL_CLIENT_ID # Allow the call when the call is made from the Management Portal self.assertTrue(await example_call(mocked_request_from_management_portal))
async def test_body_field_with_custom_fields_names_and_site( self, mocked_get_user_roles_for_site): """ If a body field is present, it must be a dictionary containing: * the target user id (user_id) * the role to be assigned (role_id) * either the site or domain to which it must be assigned (site_id or role_id) """ @requester_has_role(request_field=1, body_field=0, target_user_id_field="some_user", site_id_field="some_site", role_id_field="some_role") def call_with_body(body, request, **kwargs): # Note that request is not first return True body = {"some_user": self.user.hex, "some_role": 1, "some_site": 1} # Test the case where the requester has no roles for the specified domain. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( set()) with self.assertRaises(JSONForbidden): await call_with_body(body, self.mocked_request) # Test the case where the requester has the role for the specified domain. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {1}) self.assertTrue(await call_with_body(body, self.mocked_request)) # Test the case where the requester has the TECH_ADMIN role mocked_get_user_roles_for_site.side_effect = return_tech_admin_role_for_testing self.assertTrue(await call_with_body(body, self.mocked_request))
async def test_user_has_permissions(self, mocked_get_user_roles_for_site, mocked_get_role_resource_permissions): """ """ # All users will have only 'role1' on any site mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {TEST_ROLE_LABEL_TO_ID_MAP["role1"]}) async def dummy_get_role_resource_permissions(_request, role, resource, nocache=False): # Return hand-crafted responses for this test. role_id = role if type( role) is int else TEST_ROLE_LABEL_TO_ID_MAP[role] resource_id = resource if type(resource) is int else \ TEST_RESOURCE_URN_TO_ID_MAP[resource] responses = { (1, 1): {TEST_PERMISSION_NAME_TO_ID_MAP["permission1"]}, (2, 2): {TEST_PERMISSION_NAME_TO_ID_MAP["permission2"]} } return responses.get((role_id, resource_id), []) mocked_get_role_resource_permissions.side_effect = \ dummy_get_role_resource_permissions user = uuid1() site = 1 # Because the user has only role1 assigned and role1 implies only # permission1 on resource1, only this one permission check will succeed. self.assertTrue(await utils.user_has_permissions( self.dummy_request, user, any, [("urn:resource1", "permission1")], site=site)) self.assertFalse(await utils.user_has_permissions( self.dummy_request, user, any, [("urn:resource1", "permission2")], site=site)) self.assertFalse(await utils.user_has_permissions( self.dummy_request, user, any, [("urn:resource2", "permission2")], site=site))
async def test_positional_args(self, mocked_function): """ Check that positional argument lookups of the request works. We mock a response for the get_user_roles_for_site() function in order to check that it was called with the appropriate values. """ @require_permissions(all, [], request_field=1, nocache=True) def positional_args(_arg1, _request): return True mocked_function.side_effect = make_coroutine_returning(set()) # Call the test function... await positional_args("some_value", self.mocked_request) # ...and verify that the mocked function was called with the right # arguments. mocked_function.assert_called_with(self.mocked_request, self.user, self.site_id, nocache=True)
async def test_keyword_args(self, mocked_function): """ Check that keyword-based lookups of the user and site information works. We mock a response for the get_user_roles_for_site() function in order to check that it was called with the appropriate values. """ @require_permissions(all, [], request_field="i_am_a_request", nocache=True) def keyword_args(**kwargs): return True mocked_function.side_effect = make_coroutine_returning(set()) # Call the test function... await keyword_args(arg=123, i_am_a_request=self.mocked_request) # ...and verify that the mocked function was called with the right # arguments. mocked_function.assert_called_with(self.mocked_request, self.user, self.site_id, nocache=True)
async def test_target_user_implied_permission(self, mocked_function): """ When a permission decorator specifies a target user field and that field contains the user id of the user making the request, then implicit permission is granted. """ @require_permissions(any, [], nocache=True, target_user_field=1) def example_call_with_user(_request, the_user_id): # The caller is also the target user return _request["token"]["sub"] == the_user_id mocked_function.side_effect = make_coroutine_returning( set()) # No roles # Never gets allowed if the user id in the request token does not match # the value in the target user field. with self.assertRaises(JSONForbidden): await example_call_with_user(self.mocked_request, "fake_user_id") # Allow the call when the caller is also the target user. self.assertTrue(await example_call_with_user(self.mocked_request, str(self.user)))
async def test_stacked_decorators(self, mocked_function): """ We mock a response for the get_user_roles_for_site() function in order to test the case where the specified required resource permission list is empty. """ @require_permissions(all, [], nocache=True) @require_permissions(any, [], nocache=True) def stack(_request): raise RuntimeError("This should never get executed") @require_permissions(any, [], nocache=True) @require_permissions(all, [], nocache=True) def reverse_stack(_request): raise RuntimeError("This should never get executed") mocked_function.side_effect = make_coroutine_returning( {1000}) # An arbitrary id with self.assertRaises(JSONForbidden): await stack(self.mocked_request) with self.assertRaises(JSONForbidden): await reverse_stack(self.mocked_request)
async def test_context_header(self, mocked_site_function, mocked_domain_function): """ """ @require_permissions(all, [("urn:resource1", "permission1")], nocache=True) async def somecall(_request): return True mocked_site_function.side_effect = make_coroutine_returning( set()) # No roles mocked_domain_function.side_effect = make_coroutine_returning( set()) # No roles # Invalid value mocked_request = make_mocked_request( "GET", "/", headers={PORTAL_CONTEXT_HEADER: "foo"}) mocked_request["token"] = { "sub": str(self.user), "aud": MANAGEMENT_PORTAL_CLIENT_ID } with self.assertRaises(JSONBadRequest): await somecall(mocked_request) # Invalid value mocked_request = make_mocked_request( "GET", "/", headers={PORTAL_CONTEXT_HEADER: "foo:bar"}) mocked_request["token"] = { "sub": str(self.user), "aud": MANAGEMENT_PORTAL_CLIENT_ID } with self.assertRaises(JSONBadRequest): await somecall(mocked_request) # Invalid value mocked_request = make_mocked_request( "GET", "/", headers={PORTAL_CONTEXT_HEADER: "foo:123"}) mocked_request["token"] = { "sub": str(self.user), "aud": MANAGEMENT_PORTAL_CLIENT_ID } with self.assertRaises(JSONBadRequest): await somecall(mocked_request) # Valid header, but Management Portal is not the caller mocked_request = make_mocked_request( "GET", "/", headers={PORTAL_CONTEXT_HEADER: "d:123"}) mocked_request["token"] = { "sub": str(self.user), "aud": MANAGEMENT_PORTAL_CLIENT_ID + "foo" } with self.assertRaises(JSONForbidden): await somecall(mocked_request) # Valid site but not roles mocked_request = make_mocked_request( "GET", "/", headers={PORTAL_CONTEXT_HEADER: "s:123"}) mocked_request["token"] = { "sub": str(self.user), "aud": MANAGEMENT_PORTAL_CLIENT_ID } with self.assertRaises(JSONForbidden): await somecall(mocked_request) # Valid domain, but no roles mocked_request = make_mocked_request( "GET", "/", headers={PORTAL_CONTEXT_HEADER: "d:123"}) mocked_request["token"] = { "sub": str(self.user), "aud": MANAGEMENT_PORTAL_CLIENT_ID } with self.assertRaises(JSONForbidden): await somecall(mocked_request) # Roles will be returned mocked_site_function.side_effect = make_coroutine_returning( {Mappings.role_id_for(TECH_ADMIN_ROLE_LABEL)}) mocked_domain_function.side_effect = make_coroutine_returning( {Mappings.role_id_for(TECH_ADMIN_ROLE_LABEL)}) # Valid site mocked_request = make_mocked_request( "GET", "/", headers={PORTAL_CONTEXT_HEADER: "s:123"}) mocked_request["token"] = { "sub": str(self.user), "aud": MANAGEMENT_PORTAL_CLIENT_ID } self.assertTrue(await somecall(mocked_request)) # Valid domain, but no roles mocked_request = make_mocked_request( "GET", "/", headers={PORTAL_CONTEXT_HEADER: "d:123"}) mocked_request["token"] = { "sub": str(self.user), "aud": MANAGEMENT_PORTAL_CLIENT_ID } self.assertTrue(await somecall(mocked_request))
async def test_combo(self, mocked_get_user_roles_for_site, mocked_get_role_resource_permissions): """ A test of the 'any' operator by mocking roles, resources and permissions. :param mocked_get_user_roles_for_site: Function mocked by @patch decorator :param mocked_get_role_resource_permissions: Function mocked by @patch decorator """ async def dummy_get_role_resource_permissions(_request, role, resource, nocache=False): # Return hand-crafted responses for this test. responses = { (1, "urn:resource1"): [1], (2, "urn:resource2"): [2], (3, "urn:resource3"): [3], } return responses.get((role, resource), []) mocked_get_role_resource_permissions.side_effect = \ dummy_get_role_resource_permissions @require_permissions(all, [("urn:resource1", "permission1")], nocache=True) @require_permissions(any, [("urn:resource2", "permission2"), ("urn:resource3", "permission3")], nocache=True) def combo_requirement(_request): return True # The values for the user and site is not important since this test # mocks the roles returned. # If the user has no roles, then access is denied. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( set()) with self.assertRaises(JSONForbidden): await combo_requirement(self.mocked_request) # If the user has roles partially fulfilling the required permissions, # then access is denied. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {1}) with self.assertRaises(JSONForbidden): await combo_requirement(self.mocked_request) mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {2}) with self.assertRaises(JSONForbidden): await combo_requirement(self.mocked_request) mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {3}) with self.assertRaises(JSONForbidden): await combo_requirement(self.mocked_request) mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {2, 3}) with self.assertRaises(JSONForbidden): await combo_requirement(self.mocked_request) # If the user has roles with the necessary permissions, # then access is allowed. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {1, 2}) self.assertTrue(await combo_requirement(self.mocked_request)) mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {1, 3}) self.assertTrue(await combo_requirement(self.mocked_request))
async def test_any(self, mocked_get_user_roles_for_site, mocked_get_role_resource_permissions): """ A test of the 'any' operator by mocking roles, resources and permissions. """ async def dummy_get_role_resource_permissions(_request, role, resource, nocache=False): # Return hand-crafted responses for this test. responses = { (1, "urn:resource1"): [1], (2, "urn:resource2"): [2], } return responses.get((role, resource), []) mocked_get_role_resource_permissions.side_effect = \ dummy_get_role_resource_permissions @require_permissions(any, [("urn:resource1", "permission1")], nocache=True) def single_requirement(_request): return True # The values for the user and site is not important since this test # mocks the roles returned. # If the user has no roles, then access is denied. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( set()) with self.assertRaises(JSONForbidden): await single_requirement(self.mocked_request) # If the user has a role without the necessary permission, # then access is denied. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {2}) with self.assertRaises(JSONForbidden): await single_requirement(self.mocked_request) # If the user has a role with the necessary permission, # then access is allowed. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( {1}) self.assertTrue(await single_requirement(self.mocked_request)) @require_permissions(any, [("urn:resource1", "permission1"), ("urn:resource2", "permission2")], nocache=True) def multiple_requirements(_request): return True # If the user has any one of the permissions, then access is # allowed. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( ["role1"]) self.assertTrue(await multiple_requirements(self.mocked_request)) mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( ["role2"]) self.assertTrue(await multiple_requirements(self.mocked_request)) mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( ["role1", "role2"]) self.assertTrue(await multiple_requirements(self.mocked_request)) # If the user has a role without the necessary permission, # then access is denied. mocked_get_user_roles_for_site.side_effect = make_coroutine_returning( ["role3"]) with self.assertRaises(JSONForbidden): await single_requirement(self.mocked_request)