From 0b4a061d2b0c1591eb83a5c5657dff7996be1f94 Mon Sep 17 00:00:00 2001 From: Benjamin Bertrand <benjamin.bertrand@ess.eu> Date: Tue, 14 Apr 2020 17:39:31 +0200 Subject: [PATCH] Allow /network/networks API for normal users As for the view networks page, only networks the user has access to are returned. JIRA INFRA-2013 #action In Progress --- app/api/network.py | 15 +++++++-- tests/functional/test_api.py | 65 ++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/app/api/network.py b/app/api/network.py index 503f575..0e7d582 100644 --- a/app/api/network.py +++ b/app/api/network.py @@ -65,13 +65,24 @@ def delete_scope(scope_id): @bp.route("/networks") -@login_groups_accepted("admin") +@login_groups_accepted("admin", "network") def get_networks(): """Return networks .. :quickref: Network; Get networks """ - return utils.get_generic_model(models.Network, order_by=models.Network.address) + query = models.Network.query + if not current_user.is_admin: + query = ( + query.filter(models.Network.sensitive.is_(False)) + .filter(models.Network.admin_only.is_(False)) + .join(models.Network.scope) + .filter(models.NetworkScope.name.in_(current_user.csentry_network_scopes)) + .distinct(models.Network.id) + .from_self() + ) + query = query.order_by(models.Network.address) + return utils.get_generic_model(model=models.Network, base_query=query) @bp.route("/networks", methods=["POST"]) diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py index c89617f..a2cec3e 100644 --- a/tests/functional/test_api.py +++ b/tests/functional/test_api.py @@ -720,6 +720,71 @@ def test_get_networks(client, network_scope_factory, network_factory, admin_toke check_input_is_subset_of_response(response, (network2.to_dict(),)) +def test_get_networks_normal_user( + client, network_scope_factory, network_factory, user_token +): + # ProdNetworks scope not available to user + prod_scope = network_scope_factory(name="ProdNetworks", supernet="172.16.0.0/16") + network_factory( + vlan_name="network-prod", + address="172.16.3.0/24", + first_ip="172.16.3.10", + last_ip="172.16.3.250", + scope=prod_scope, + ) + # User has access to networks on FooNetworks scopes (expect admin and sensitive) + foo_scope = network_scope_factory(name="FooNetworks", supernet="192.168.0.0/16") + network_factory( + vlan_name="admin-network", + address="192.168.1.0/24", + first_ip="192.168.1.10", + last_ip="192.168.1.250", + admin_only=True, + scope=foo_scope, + ) + network_factory( + vlan_name="sensitive-network", + address="192.168.2.0/24", + first_ip="192.168.2.10", + last_ip="192.168.2.250", + admin_only=False, + sensitive=True, + scope=foo_scope, + ) + # Create 30 networks + for n in range(3, 33): + network_factory( + vlan_name=f"network{n}", + address=f"192.168.{n}.0/24", + first_ip=f"192.168.{n}.10", + last_ip=f"192.168.{n}.250", + scope=foo_scope, + ) + url = f"{API_URL}/network/networks" + response = get(client, url, token=user_token) + assert response.status_code == 200 + assert response.headers["x-total-count"] == "30" + networks1 = response.get_json() + assert len(networks1) == 20 + assert ( + f'{url}?per_page=20&page=2&recursive=False>; rel="next",' + in response.headers["link"] + ) + # Get second page + response = get( + client, f"{url}?per_page=20&page=2&recursive=False", token=user_token, + ) + assert response.status_code == 200 + networks2 = response.get_json() + assert len(networks2) == 10 + # Check that admin/sensitive/prod networks aren't part of the result + assert [ + network + for network in networks1 + networks2 + if network["vlan_name"].startswith("network") + ] == networks1 + networks2 + + def test_create_network_auth_fail(client, session, user_token): # admin is required to create networks response = post(client, f"{API_URL}/network/networks", data={}, token=user_token) -- GitLab