From 422c655f8baa8c3bc8b27e35aacb536c9ededce8 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 27 Jul 2022 22:18:14 +0530 Subject: [PATCH 1/4] api: fix ipv6 firewall apis role permissions Fixes #6575 Signed-off-by: Abhishek Kumar --- .../api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java | 7 ++++++- .../api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java | 9 +++++++-- .../api/command/user/ipv6/ListIpv6FirewallRulesCmd.java | 8 ++++++-- .../api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java | 7 ++++++- ui/src/config/section/network.js | 2 +- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java index be158c9de025..6151b6a29db7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java @@ -43,7 +43,12 @@ import com.cloud.user.Account; import com.cloud.utils.net.NetUtils; -@APICommand(name = CreateIpv6FirewallRuleCmd.APINAME, description = "Creates an Ipv6 firewall rule in the given network (the network has to belong to VPC)", responseObject = FirewallRuleResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +@APICommand(name = CreateIpv6FirewallRuleCmd.APINAME, + description = "Creates an Ipv6 firewall rule in the given network (the network has to belong to VPC)", + responseObject = FirewallRuleResponse.class, + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class CreateIpv6FirewallRuleCmd extends BaseAsyncCreateCmd { public static final Logger s_logger = Logger.getLogger(CreateIpv6FirewallRuleCmd.class.getName()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java index e7343a80d057..274f736a62b3 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.api.command.user.ipv6; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; @@ -33,8 +34,12 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.user.Account; -@APICommand(name = DeleteIpv6FirewallRuleCmd.APINAME, description = "Deletes a IPv6 firewall rule", responseObject = SuccessResponse.class, - requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +@APICommand(name = DeleteIpv6FirewallRuleCmd.APINAME, + description = "Deletes a IPv6 firewall rule", + responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class DeleteIpv6FirewallRuleCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(DeleteIpv6FirewallRuleCmd.class.getName()); public static final String APINAME = "deleteIpv6FirewallRule"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java index 3f91f523edc6..fc2714cf1bf9 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java @@ -34,8 +34,12 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.utils.Pair; -@APICommand(name = ListIpv6FirewallRulesCmd.APINAME, description = "Lists all IPv6 firewall rules", responseObject = FirewallRuleResponse.class, - requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +@APICommand(name = ListIpv6FirewallRulesCmd.APINAME, + description = "Lists all IPv6 firewall rules", + responseObject = FirewallRuleResponse.class, + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class ListIpv6FirewallRulesCmd extends BaseListTaggedResourcesCmd implements IListFirewallRulesCmd { public static final Logger s_logger = Logger.getLogger(ListIpv6FirewallRulesCmd.class.getName()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java index 8a05d02ae591..2295a17db837 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java @@ -34,7 +34,12 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.user.Account; -@APICommand(name = UpdateIpv6FirewallRuleCmd.APINAME, description = "Updates Ipv6 firewall rule with specified ID", responseObject = FirewallRuleResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +@APICommand(name = UpdateIpv6FirewallRuleCmd.APINAME, + description = "Updates Ipv6 firewall rule with specified ID", + responseObject = FirewallRuleResponse.class, + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class UpdateIpv6FirewallRuleCmd extends BaseAsyncCustomIdCmd { public static final Logger s_logger = Logger.getLogger(UpdateIpv6FirewallRuleCmd.class.getName()); diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index 94e7ffeabc13..c98fe35b7473 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -62,7 +62,7 @@ export default { }, { name: 'ip.v6.firewall', component: shallowRef(defineAsyncComponent(() => import('@/views/network/Ipv6FirewallRulesTab.vue'))), - show: (record, route, user) => { return record.type === 'Isolated' && ['IPv6', 'DualStack'].includes(record.internetprotocol) && !('vpcid' in record) && 'listIpv6FirewallRules' in store.getters.apis && (['Admin', 'DomainAdmin'].includes(user.roletype) || record.account === user.account || record.projectid) } + show: (record) => { return record.type === 'Isolated' && ['IPv6', 'DualStack'].includes(record.internetprotocol) && !('vpcid' in record) && 'listIpv6FirewallRules' in store.getters.apis } }, { name: 'public.ip.addresses', component: shallowRef(defineAsyncComponent(() => import('@/views/network/IpAddressesTab.vue'))), From 1dfdd6801d4aca61d7096dfa45578503a48591f7 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 27 Jul 2022 22:48:33 +0530 Subject: [PATCH 2/4] test: use user apiclient for ipv6 firewall apis Signed-off-by: Abhishek Kumar --- test/integration/component/test_network_ipv6.py | 12 ++++++++---- test/integration/smoke/test_network_ipv6.py | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/test/integration/component/test_network_ipv6.py b/test/integration/component/test_network_ipv6.py index 29afb8d97be3..3e81cc24c775 100644 --- a/test/integration/component/test_network_ipv6.py +++ b/test/integration/component/test_network_ipv6.py @@ -209,6 +209,10 @@ def getPublicIpv6Range(cls): def setUp(self): self.services = self.testClient.getParsedTestDataConfig() self.apiclient = self.testClient.getApiClient() + self.userapiclient = self.testClient.getUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain + ) self.dbclient = self.testClient.getDbConnection() self.thread = None self.cleanup = [] @@ -567,7 +571,7 @@ def createIpv6FirewallRuleInNetwork(self, network_id, traffic_type, source_cidr, cmd.icmptype = icmp_type if icmp_code is not None: cmd.icmpcode = icmp_code - fw_rule = self.apiclient.createIpv6FirewallRule(cmd) + fw_rule = self.userapiclient.createIpv6FirewallRule(cmd) return fw_rule def deployRoutingTestResources(self): @@ -655,7 +659,7 @@ def checkIpv6NetworkRouting(self): cmd = deleteIpv6FirewallRule.deleteIpv6FirewallRuleCmd() cmd.id = fw2.id - self.apiclient.deleteIpv6FirewallRule(cmd) + self.userapiclient.deleteIpv6FirewallRule(cmd) def createAndVerifyIpv6FirewallRule(self, traffic_type, source_cidr, dest_cidr, protocol, start_port, end_port, icmp_type, icmp_code, parsed_rule, delete=False): @@ -664,7 +668,7 @@ def createAndVerifyIpv6FirewallRule(self, traffic_type, source_cidr, dest_cidr, start_port, end_port, icmp_type, icmp_code) cmd = listIpv6FirewallRules.listIpv6FirewallRulesCmd() cmd.id = fw_rule.id - rules = self.apiclient.listIpv6FirewallRules(cmd) + rules = self.userapiclient.listIpv6FirewallRules(cmd) self.assertTrue( isinstance(rules, list), "Check listIpv6FirewallRules response returns a valid list" @@ -702,7 +706,7 @@ def createAndVerifyIpv6FirewallRule(self, traffic_type, source_cidr, dest_cidr, if delete == True: cmd = deleteIpv6FirewallRule.deleteIpv6FirewallRuleCmd() cmd.id = fw_rule.id - self.apiclient.deleteIpv6FirewallRule(cmd) + self.userapiclient.deleteIpv6FirewallRule(cmd) res = self.getRouterProcessStatus(self.getNetworkRouter(self.network), routerCmd) self.assertFalse(parsed_rule in res, "Firewall rule present in nft list chain failure despite delete for rule: %s" % parsed_rule) diff --git a/test/integration/smoke/test_network_ipv6.py b/test/integration/smoke/test_network_ipv6.py index 385ff636b162..8dc03863b8b9 100644 --- a/test/integration/smoke/test_network_ipv6.py +++ b/test/integration/smoke/test_network_ipv6.py @@ -209,6 +209,10 @@ def getPublicIpv6Range(cls): def setUp(self): self.services = self.testClient.getParsedTestDataConfig() self.apiclient = self.testClient.getApiClient() + self.userapiclient = self.testClient.getUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain + ) self.dbclient = self.testClient.getDbConnection() self.thread = None self.cleanup = [] @@ -567,7 +571,7 @@ def createIpv6FirewallRuleInNetwork(self, network_id, traffic_type, source_cidr, cmd.icmptype = icmp_type if icmp_code is not None: cmd.icmpcode = icmp_code - fw_rule = self.apiclient.createIpv6FirewallRule(cmd) + fw_rule = self.userapiclient.createIpv6FirewallRule(cmd) return fw_rule def deployRoutingTestResources(self): @@ -655,7 +659,7 @@ def checkIpv6NetworkRouting(self): cmd = deleteIpv6FirewallRule.deleteIpv6FirewallRuleCmd() cmd.id = fw2.id - self.apiclient.deleteIpv6FirewallRule(cmd) + self.userapiclient.deleteIpv6FirewallRule(cmd) def createAndVerifyIpv6FirewallRule(self, traffic_type, source_cidr, dest_cidr, protocol, start_port, end_port, icmp_type, icmp_code, parsed_rule, delete=False): @@ -664,7 +668,7 @@ def createAndVerifyIpv6FirewallRule(self, traffic_type, source_cidr, dest_cidr, start_port, end_port, icmp_type, icmp_code) cmd = listIpv6FirewallRules.listIpv6FirewallRulesCmd() cmd.id = fw_rule.id - rules = self.apiclient.listIpv6FirewallRules(cmd) + rules = self.userapiclient.listIpv6FirewallRules(cmd) self.assertTrue( isinstance(rules, list), "Check listIpv6FirewallRules response returns a valid list" @@ -702,7 +706,7 @@ def createAndVerifyIpv6FirewallRule(self, traffic_type, source_cidr, dest_cidr, if delete == True: cmd = deleteIpv6FirewallRule.deleteIpv6FirewallRuleCmd() cmd.id = fw_rule.id - self.apiclient.deleteIpv6FirewallRule(cmd) + self.userapiclient.deleteIpv6FirewallRule(cmd) res = self.getRouterProcessStatus(self.getNetworkRouter(self.network), routerCmd) self.assertFalse(parsed_rule in res, "Firewall rule present in nft list chain failure despite delete for rule: %s" % parsed_rule) From efddd3ca4ab07a458e083e1e8f709e9ea4d10625 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 27 Jul 2022 22:55:19 +0530 Subject: [PATCH 3/4] revert Signed-off-by: Abhishek Kumar --- ui/src/config/section/network.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index c98fe35b7473..94e7ffeabc13 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -62,7 +62,7 @@ export default { }, { name: 'ip.v6.firewall', component: shallowRef(defineAsyncComponent(() => import('@/views/network/Ipv6FirewallRulesTab.vue'))), - show: (record) => { return record.type === 'Isolated' && ['IPv6', 'DualStack'].includes(record.internetprotocol) && !('vpcid' in record) && 'listIpv6FirewallRules' in store.getters.apis } + show: (record, route, user) => { return record.type === 'Isolated' && ['IPv6', 'DualStack'].includes(record.internetprotocol) && !('vpcid' in record) && 'listIpv6FirewallRules' in store.getters.apis && (['Admin', 'DomainAdmin'].includes(user.roletype) || record.account === user.account || record.projectid) } }, { name: 'public.ip.addresses', component: shallowRef(defineAsyncComponent(() => import('@/views/network/IpAddressesTab.vue'))), From 293ef4fc250e3953c6e2eb0d1a9062b635ff65b1 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 29 Jul 2022 12:09:09 +0530 Subject: [PATCH 4/4] test: make network, vm api calls as user Signed-off-by: Abhishek Kumar --- test/integration/component/test_network_ipv6.py | 12 ++++-------- test/integration/smoke/test_network_ipv6.py | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/test/integration/component/test_network_ipv6.py b/test/integration/component/test_network_ipv6.py index 3e81cc24c775..30734d73d951 100644 --- a/test/integration/component/test_network_ipv6.py +++ b/test/integration/component/test_network_ipv6.py @@ -270,10 +270,8 @@ def createIpv6NetworkOfferingForUpdate(self, is_redundant=False): def deployNetwork(self): self.services["network"]["networkoffering"] = self.network_offering.id self.network = Network.create( - self.apiclient, + self.userapiclient, self.services["network"], - self.account.name, - self.account.domainid, zoneid=self.zone.id ) self.cleanup.append(self.network) @@ -283,11 +281,9 @@ def deployNetworkVm(self): assert False, "get_test_template() failed to return template" self.services["virtual_machine"]["zoneid"] = self.zone.id self.virtual_machine = VirtualMachine.create( - self.apiclient, + self.userapiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account.name, - domainid=self.account.domainid, networkids=self.network.id, serviceofferingid=self.service_offering.id ) @@ -545,11 +541,11 @@ def checkIpv6NetworkVm(self): "IPv6 gateway for VM %s NIC is empty" % nic.traffictype) def restartNetworkWithCleanup(self): - self.network.restart(self.apiclient, cleanup=True) + self.network.restart(self.userapiclient, cleanup=True) time.sleep(SLEEP_BEFORE_VR_CHANGES) def updateNetworkWithOffering(self): - self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id) + self.network.update(self.userapiclient, networkofferingid=self.network_offering_update.id) time.sleep(SLEEP_BEFORE_VR_CHANGES) def createIpv6FirewallRuleInNetwork(self, network_id, traffic_type, source_cidr, dest_cidr, protocol, diff --git a/test/integration/smoke/test_network_ipv6.py b/test/integration/smoke/test_network_ipv6.py index 8dc03863b8b9..41b7c85dea02 100644 --- a/test/integration/smoke/test_network_ipv6.py +++ b/test/integration/smoke/test_network_ipv6.py @@ -270,10 +270,8 @@ def createIpv6NetworkOfferingForUpdate(self, is_redundant=False): def deployNetwork(self): self.services["network"]["networkoffering"] = self.network_offering.id self.network = Network.create( - self.apiclient, + self.userapiclient, self.services["network"], - self.account.name, - self.account.domainid, zoneid=self.zone.id ) self.cleanup.append(self.network) @@ -283,11 +281,9 @@ def deployNetworkVm(self): assert False, "get_test_template() failed to return template" self.services["virtual_machine"]["zoneid"] = self.zone.id self.virtual_machine = VirtualMachine.create( - self.apiclient, + self.userapiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account.name, - domainid=self.account.domainid, networkids=self.network.id, serviceofferingid=self.service_offering.id ) @@ -545,11 +541,11 @@ def checkIpv6NetworkVm(self): "IPv6 gateway for VM %s NIC is empty" % nic.traffictype) def restartNetworkWithCleanup(self): - self.network.restart(self.apiclient, cleanup=True) + self.network.restart(self.userapiclient, cleanup=True) time.sleep(SLEEP_BEFORE_VR_CHANGES) def updateNetworkWithOffering(self): - self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id) + self.network.update(self.userapiclient, networkofferingid=self.network_offering_update.id) time.sleep(SLEEP_BEFORE_VR_CHANGES) def createIpv6FirewallRuleInNetwork(self, network_id, traffic_type, source_cidr, dest_cidr, protocol,