This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new cb62ce67671 Global ACL for VPCs (#7150)
cb62ce67671 is described below
commit cb62ce67671699fa01564b3b4b0d3d83eb3d5acb
Author: Bryan Lima <[email protected]>
AuthorDate: Thu Nov 30 10:51:43 2023 -0300
Global ACL for VPCs (#7150)
---
.github/workflows/ci.yml | 3 +-
.../user/network/CreateNetworkACLListCmd.java | 36 ++-
.../java/com/cloud/network/vpc/NetworkACLVO.java | 7 +
.../java/com/cloud/network/NetworkServiceImpl.java | 17 +-
.../cloud/network/vpc/NetworkACLServiceImpl.java | 131 +++++++----
.../java/com/cloud/network/vpc/VpcManagerImpl.java | 14 +-
.../network/vpc/NetworkACLServiceImplTest.java | 145 ++++++++----
test/integration/smoke/test_global_acls.py | 245 +++++++++++++++++++++
8 files changed, 489 insertions(+), 109 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d6b5f5a1c4f..77c9d59505c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -111,7 +111,8 @@ jobs:
smoke/test_reset_configuration_settings
smoke/test_reset_vm_on_reboot
smoke/test_resource_accounting
- smoke/test_resource_detail",
+ smoke/test_resource_detail
+ smoke/test_global_acls",
"smoke/test_router_dhcphosts
smoke/test_router_dns
smoke/test_router_dnsservice
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
index 14dbfcafd7b..e5dbcc7b6d1 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
@@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.api.command.user.network;
+import com.cloud.exception.PermissionDeniedException;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
@@ -26,6 +27,7 @@ import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NetworkACLResponse;
import org.apache.cloudstack.api.response.VpcResponse;
+import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
@@ -35,7 +37,8 @@ import com.cloud.network.vpc.NetworkACL;
import com.cloud.network.vpc.Vpc;
import com.cloud.user.Account;
-@APICommand(name = "createNetworkACLList", description = "Creates a network
ACL for the given VPC", responseObject = NetworkACLResponse.class,
+@APICommand(name = "createNetworkACLList", description = "Creates a network
ACL. If no VPC is given, then it creates a global ACL that can be used by
everyone.",
+ responseObject = NetworkACLResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd {
public static final Logger s_logger =
Logger.getLogger(CreateNetworkACLListCmd.class.getName());
@@ -53,7 +56,6 @@ public class CreateNetworkACLListCmd extends
BaseAsyncCreateCmd {
@Parameter(name = ApiConstants.VPC_ID,
type = CommandType.UUID,
- required = true,
entityType = VpcResponse.class,
description = "ID of the VPC associated with this network ACL
list")
private Long vpcId;
@@ -77,6 +79,10 @@ public class CreateNetworkACLListCmd extends
BaseAsyncCreateCmd {
return vpcId;
}
+ public void setVpcId(Long vpcId) {
+ this.vpcId = vpcId;
+ }
+
@Override
public boolean isDisplay() {
if (display != null) {
@@ -92,6 +98,9 @@ public class CreateNetworkACLListCmd extends
BaseAsyncCreateCmd {
@Override
public void create() {
+ if (getVpcId() == null) {
+ setVpcId(0L);
+ }
NetworkACL result = _networkACLService.createNetworkACL(getName(),
getDescription(), getVpcId(), isDisplay());
setEntityId(result.getId());
setEntityUuid(result.getUuid());
@@ -111,12 +120,21 @@ public class CreateNetworkACLListCmd extends
BaseAsyncCreateCmd {
@Override
public long getEntityOwnerId() {
- Vpc vpc = _entityMgr.findById(Vpc.class, getVpcId());
- if (vpc == null) {
- throw new InvalidParameterValueException("Invalid vpcId is given");
- }
+ Account account;
+ if (isAclAttachedToVpc(this.vpcId)) {
+ Vpc vpc = _entityMgr.findById(Vpc.class, this.vpcId);
+ if (vpc == null) {
+ throw new
InvalidParameterValueException(String.format("Invalid VPC ID [%s] provided.",
this.vpcId));
+ }
+ account = _accountService.getAccount(vpc.getAccountId());
+ } else {
+ account = CallContext.current().getCallingAccount();
+ if (!Account.Type.ADMIN.equals(account.getType())) {
+ s_logger.warn(String.format("Only Root Admin can create global
ACLs. Account [%s] cannot create any global ACL.", account));
+ throw new PermissionDeniedException("Only Root Admin can
create global ACLs.");
+ }
- Account account = _accountService.getAccount(vpc.getAccountId());
+ }
return account.getId();
}
@@ -139,4 +157,8 @@ public class CreateNetworkACLListCmd extends
BaseAsyncCreateCmd {
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.NetworkAcl;
}
+
+ public boolean isAclAttachedToVpc(Long aclVpcId) {
+ return aclVpcId != null && aclVpcId != 0;
+ }
}
diff --git
a/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
b/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
index 4eaa2b575e0..280d5dfaf4b 100644
--- a/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
@@ -17,6 +17,8 @@
package com.cloud.network.vpc;
+import
org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+
import java.util.UUID;
import javax.persistence.Column;
@@ -85,6 +87,11 @@ public class NetworkACLVO implements NetworkACL {
return name;
}
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this,
"uuid", "name", "vpcId");
+ }
+
public void setUuid(String uuid) {
this.uuid = uuid;
}
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index f9f80cb5b76..18f98e6f99f 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -2100,12 +2100,9 @@ public class NetworkServiceImpl extends ManagerBase
implements NetworkService, C
throw new
InvalidParameterValueException("Unable to find specified NetworkACL");
}
- if (aclId != NetworkACL.DEFAULT_DENY && aclId !=
NetworkACL.DEFAULT_ALLOW) {
- // ACL is not default DENY/ALLOW
- // ACL should be associated with a VPC
- if (!vpcId.equals(acl.getVpcId())) {
- throw new
InvalidParameterValueException("ACL: " + aclId + " do not belong to the VPC");
- }
+ Long aclVpcId = acl.getVpcId();
+ if (!isDefaultAcl(aclId) &&
isAclAttachedToVpc(aclVpcId, vpcId)) {
+ throw new
InvalidParameterValueException(String.format("ACL [%s] does not belong to the
VPC [%s].", aclId, aclVpcId));
}
}
network =
_vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway,
cidr, vlanId, networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType,
@@ -5950,6 +5947,14 @@ public class NetworkServiceImpl extends ManagerBase
implements NetworkService, C
return new ConfigKey<?>[] {AllowDuplicateNetworkName,
AllowEmptyStartEndIpAddress, VRPrivateInterfaceMtu, VRPublicInterfaceMtu,
AllowUsersToSpecifyVRMtu};
}
+ public boolean isDefaultAcl(Long aclId) {
+ return aclId == NetworkACL.DEFAULT_DENY || aclId ==
NetworkACL.DEFAULT_ALLOW;
+ }
+
+ public boolean isAclAttachedToVpc(Long aclVpcId, Long vpcId) {
+ return aclVpcId != 0 && !vpcId.equals(aclVpcId);
+ }
+
@Override
public PublicIpQuarantine
updatePublicIpAddressInQuarantine(UpdateQuarantinedIpCmd cmd) throws
CloudRuntimeException {
Long ipId = cmd.getId();
diff --git
a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
index ed37eb5b375..8139ac1c49e 100644
--- a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
@@ -24,6 +24,7 @@ import java.util.Map;
import javax.inject.Inject;
+import com.cloud.exception.PermissionDeniedException;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
@@ -103,12 +104,15 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
@Override
public NetworkACL createNetworkACL(final String name, final String
description, final long vpcId, final Boolean forDisplay) {
- final Account caller = CallContext.current().getCallingAccount();
- final Vpc vpc = _entityMgr.findById(Vpc.class, vpcId);
- if (vpc == null) {
- throw new InvalidParameterValueException("Unable to find VPC");
+ if (vpcId != 0) {
+ final Account caller = CallContext.current().getCallingAccount();
+ final Vpc vpc = _vpcDao.findById(vpcId);
+ if (vpc == null) {
+ throw new InvalidParameterValueException(String.format("Unable
to find VPC with ID [%s].", vpcId));
+ }
+ _accountMgr.checkAccess(caller, null, true, vpc);
+
}
- _accountMgr.checkAccess(caller, null, true, vpc);
return _networkAclMgr.createNetworkACL(name, description, vpcId,
forDisplay);
}
@@ -212,22 +216,17 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
@Override
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_ACL_DELETE,
eventDescription = "Deleting Network ACL List", async = true)
public boolean deleteNetworkACL(final long id) {
- final Account caller = CallContext.current().getCallingAccount();
final NetworkACL acl = _networkACLDao.findById(id);
+ Account account = CallContext.current().getCallingAccount();
if (acl == null) {
throw new InvalidParameterValueException("Unable to find specified
ACL");
}
- //Do not allow deletion of default ACLs
- if (acl.getId() == NetworkACL.DEFAULT_ALLOW || acl.getId() ==
NetworkACL.DEFAULT_DENY) {
+ if (isDefaultAcl(acl.getId())) {
throw new InvalidParameterValueException("Default ACL cannot be
removed");
}
- final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
- if (vpc == null) {
- throw new InvalidParameterValueException("Unable to find specified
VPC associated with the ACL");
- }
- _accountMgr.checkAccess(caller, null, true, vpc);
+ validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account, "Only
Root Admin can delete global ACLs.");
return _networkAclMgr.deleteNetworkACL(acl);
}
@@ -253,7 +252,7 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
throw new InvalidParameterValueException("Unable to find specified
vpc id");
}
- if (aclId != NetworkACL.DEFAULT_DENY && aclId !=
NetworkACL.DEFAULT_ALLOW) {
+ if (!isDefaultAcl(aclId)) {
final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
if (vpc == null) {
throw new InvalidParameterValueException("Unable to find Vpc
associated with the NetworkACL");
@@ -293,15 +292,9 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
throw new InvalidParameterValueException("Network ACL can be
created just for networks of type " + Networks.TrafficType.Guest);
}
- if (aclId != NetworkACL.DEFAULT_DENY && aclId !=
NetworkACL.DEFAULT_ALLOW) {
- //ACL is not default DENY/ALLOW
- // ACL should be associated with a VPC
- final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
- if (vpc == null) {
- throw new InvalidParameterValueException("Unable to find Vpc
associated with the NetworkACL");
- }
+ if (!isDefaultAcl(aclId) && !isGlobalAcl(acl.getVpcId())) {
+ validateAclAssociatedToVpc(acl.getVpcId(), caller, acl.getUuid());
- _accountMgr.checkAccess(caller, null, true, vpc);
if (!network.getVpcId().equals(acl.getVpcId())) {
throw new InvalidParameterValueException("Network: " +
networkId + " and ACL: " + aclId + " do not belong to the same VPC");
}
@@ -340,6 +333,11 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
NetworkACL acl = _networkAclMgr.getNetworkACL(aclId);
validateNetworkAcl(acl);
+ Account caller = CallContext.current().getCallingAccount();
+
+ if (isGlobalAcl(acl.getVpcId()) &&
!Account.Type.ADMIN.equals(caller.getType())) {
+ throw new PermissionDeniedException("Only Root Admins can create
rules for a global ACL.");
+ }
validateAclRuleNumber(createNetworkACLCmd, acl);
NetworkACLItem.Action ruleAction =
validateAndCreateNetworkAclRuleAction(action);
@@ -409,7 +407,8 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
* <ul>
* <li>If the parameter is null, we return an {@link
InvalidParameterValueException};
* <li>Default ACLs {@link NetworkACL#DEFAULT_ALLOW} and {@link
NetworkACL#DEFAULT_DENY} cannot be modified. Therefore, if any of them is
provided we throw a {@link InvalidParameterValueException};
- * <li>If the network does not have a VPC, we will throw an {@link
InvalidParameterValueException}.
+ * <li>If no VPC is given, then it is a global ACL and there is no need
to check any VPC ID. However, if a VPC is given and it does not exist, throws an
+ * {@link InvalidParameterValueException}.
* </ul>
*
* After all validations, we check if the user has access to the given
network ACL using {@link AccountManager#checkAccess(Account,
org.apache.cloudstack.acl.SecurityChecker.AccessType, boolean,
org.apache.cloudstack.acl.ControlledEntity...)}.
@@ -419,16 +418,14 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
throw new InvalidParameterValueException("Unable to find specified
ACL.");
}
- if (acl.getId() == NetworkACL.DEFAULT_DENY || acl.getId() ==
NetworkACL.DEFAULT_ALLOW) {
+ if (isDefaultAcl(acl.getId())) {
throw new InvalidParameterValueException("Default ACL cannot be
modified");
}
- Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
- if (vpc == null) {
- throw new InvalidParameterValueException(String.format("Unable to
find Vpc associated with the NetworkACL [%s]", acl.getUuid()));
+ Long aclVpcId = acl.getVpcId();
+ if (!isGlobalAcl(aclVpcId)) {
+ validateAclAssociatedToVpc(aclVpcId,
CallContext.current().getCallingAccount(), acl.getUuid());
}
- Account caller = CallContext.current().getCallingAccount();
- _accountMgr.checkAccess(caller, null, true, vpc);
}
/**
@@ -792,17 +789,12 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
final NetworkACLItemVO aclItem = _networkACLItemDao.findById(ruleId);
if (aclItem != null) {
final NetworkACL acl =
_networkAclMgr.getNetworkACL(aclItem.getAclId());
+ final Account account = CallContext.current().getCallingAccount();
- final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
-
- if (aclItem.getAclId() == NetworkACL.DEFAULT_ALLOW ||
aclItem.getAclId() == NetworkACL.DEFAULT_DENY) {
+ if (isDefaultAcl(aclItem.getAclId())) {
throw new InvalidParameterValueException("ACL Items in default
ACL cannot be deleted");
}
-
- final Account caller = CallContext.current().getCallingAccount();
-
- _accountMgr.checkAccess(caller, null, true, vpc);
-
+ validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account,
"Only Root Admin can delete global ACL rules.");
}
return _networkAclMgr.revokeNetworkACLItem(ruleId);
}
@@ -826,6 +818,9 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
NetworkACL acl =
_networkAclMgr.getNetworkACL(networkACLItemVo.getAclId());
validateNetworkAcl(acl);
+ Account account = CallContext.current().getCallingAccount();
+ validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account, "Only
Root Admins can update global ACLs.");
+
transferDataToNetworkAclRulePojo(updateNetworkACLItemCmd,
networkACLItemVo, acl);
validateNetworkACLItem(networkACLItemVo);
return _networkAclMgr.updateNetworkACLItem(networkACLItemVo);
@@ -912,14 +907,13 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
}
@Override
- @ActionEvent(eventType = EventTypes.EVENT_NETWORK_ACL_UPDATE,
eventDescription = "updating network acl", async = true)
+ @ActionEvent(eventType = EventTypes.EVENT_NETWORK_ACL_UPDATE,
eventDescription = "Updating Network ACL", async = true)
public NetworkACL updateNetworkACL(UpdateNetworkACLListCmd
updateNetworkACLListCmd) {
Long id = updateNetworkACLListCmd.getId();
NetworkACLVO acl = _networkACLDao.findById(id);
- Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
+ Account account = CallContext.current().getCallingAccount();
- Account caller = CallContext.current().getCallingAccount();
- _accountMgr.checkAccess(caller, null, true, vpc);
+ validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account, "Must
be Root Admin to update a global ACL.");
String name = updateNetworkACLListCmd.getName();
if (StringUtils.isNotBlank(name)) {
@@ -1149,14 +1143,59 @@ public class NetworkACLServiceImpl extends ManagerBase
implements NetworkACLServ
long aclId = ruleBeingMoved.getAclId();
if ((nextRule != null && nextRule.getAclId() != aclId) ||
(previousRule != null && previousRule.getAclId() != aclId)) {
- throw new InvalidParameterValueException("Cannot use ACL rules
from differenting ACLs. Rule being moved.");
+ throw new InvalidParameterValueException("Cannot use ACL rules
from differentiating ACLs. Rule being moved.");
}
NetworkACLVO acl = _networkACLDao.findById(aclId);
- Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
+ Account account = CallContext.current().getCallingAccount();
+
+ if (isDefaultAcl(aclId)) {
+ throw new InvalidParameterValueException("Default ACL rules cannot
be moved.");
+ }
+
+ validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account,"Must be
Root Admin to move global ACL rules.");
+ }
+
+ /**
+ * Checks if the given ACL is a global ACL. If it is, then checks if the
account is Root Admin, and throws an exception according to {@code
exceptionMessage} param if it
+ * does not have permission.
+ */
+ protected void checkGlobalAclPermission(Long aclVpcId, Account account,
String exceptionMessage) {
+ if (isGlobalAcl(aclVpcId) &&
!Account.Type.ADMIN.equals(account.getType())) {
+ throw new PermissionDeniedException(exceptionMessage);
+ }
+ }
+
+ protected void validateAclAssociatedToVpc(Long aclVpcId, Account account,
String aclUuid) {
+ final Vpc vpc = _vpcDao.findById(aclVpcId);
if (vpc == null) {
- throw new InvalidParameterValueException("Re-ordering rules for a
default ACL is prohibited");
+ throw new InvalidParameterValueException(String.format("Unable to
find specified VPC [%s] associated with the ACL [%s].", aclVpcId, aclUuid));
}
- Account caller = CallContext.current().getCallingAccount();
- _accountMgr.checkAccess(caller, null, true, vpc);
+ _accountMgr.checkAccess(account, null, true, vpc);
+ }
+
+ /**
+ * It performs two different verifications depending on if the ACL is
global or not.
+ * <ul>
+ * <li> If the given ACL is a Global ACL, i.e. has VPC ID = 0, then
checks if the account is Root Admin, and throws an exception if it isn't.
+ * <li> If the given ACL is associated to a VPC, i.e. VPC ID != 0,
then calls {@link #validateAclAssociatedToVpc(Long, Account, String)} and
checks if the given {@code
+ * aclVpcId} is from a valid VPC.
+ * </ul>
+ */
+ protected void validateGlobalAclPermissionAndAclAssociatedToVpc(NetworkACL
acl, Account account, String exception){
+ if (isGlobalAcl(acl.getVpcId())) {
+ s_logger.info(String.format("Checking if account [%s] has
permission to manipulate global ACL [%s].", account, acl));
+ checkGlobalAclPermission(acl.getVpcId(), account, exception);
+ } else {
+ s_logger.info(String.format("Validating ACL [%s] associated to VPC
[%s] with account [%s].", acl, acl.getVpcId(), account));
+ validateAclAssociatedToVpc(acl.getVpcId(), account, acl.getUuid());
+ }
+ }
+
+ protected boolean isGlobalAcl(Long aclVpcId) {
+ return aclVpcId != null && aclVpcId == 0;
+ }
+
+ protected boolean isDefaultAcl(long aclId) {
+ return aclId == NetworkACL.DEFAULT_ALLOW || aclId ==
NetworkACL.DEFAULT_DENY;
}
}
diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index 6bc70a9cef4..1f99d164625 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -1977,16 +1977,14 @@ public class VpcManagerImpl extends ManagerBase
implements VpcManager, VpcProvis
searchBuilder.and("vpcId", searchBuilder.entity().getVpcId(), Op.IN);
final SearchCriteria<NetworkACLVO> searchCriteria =
searchBuilder.create();
- searchCriteria.setParameters("vpcId", vpcId, 0);
+ searchCriteria.setParameters("vpcId", vpcId);
final Filter filter = new Filter(NetworkACLVO.class, "id", false,
null, null);
final Pair<List<NetworkACLVO>, Integer> aclsCountPair =
_networkAclDao.searchAndCount(searchCriteria, filter);
final List<NetworkACLVO> acls = aclsCountPair.first();
for (final NetworkACLVO networkAcl : acls) {
- if (networkAcl.getId() != NetworkACL.DEFAULT_ALLOW &&
networkAcl.getId() != NetworkACL.DEFAULT_DENY) {
- _networkAclMgr.deleteNetworkACL(networkAcl);
- }
+ _networkAclMgr.deleteNetworkACL(networkAcl);
}
VpcVO vpc = vpcDao.findById(vpcId);
@@ -3175,4 +3173,12 @@ public class VpcManagerImpl extends ManagerBase
implements VpcManager, VpcProvis
}
return filteredDomainIds;
}
+
+ protected boolean isGlobalAcl(Long aclVpcId) {
+ return aclVpcId != null && aclVpcId == 0;
+ }
+
+ protected boolean isDefaultAcl(long aclId) {
+ return aclId == NetworkACL.DEFAULT_ALLOW || aclId ==
NetworkACL.DEFAULT_DENY;
+ }
}
diff --git
a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
index 8dd3f32d6c4..18a072172ad 100644
--- a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
+++ b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
@@ -17,19 +17,20 @@
package com.cloud.network.vpc;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.network.Network;
-import com.cloud.network.NetworkModel;
-import com.cloud.network.dao.NetworkVO;
-import com.cloud.network.vpc.NetworkACLItem.Action;
-import com.cloud.network.vpc.NetworkACLItem.TrafficType;
-import com.cloud.network.vpc.dao.NetworkACLDao;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManager;
-import com.cloud.user.User;
-import com.cloud.utils.db.EntityManager;
-import com.cloud.utils.exception.CloudRuntimeException;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.times;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.network.vpc.dao.VpcDao;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
@@ -38,7 +39,6 @@ import
org.apache.cloudstack.api.command.user.network.UpdateNetworkACLItemCmd;
import org.apache.cloudstack.api.command.user.network.UpdateNetworkACLListCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.lang3.StringUtils;
-import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -46,24 +46,27 @@ import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
-import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.times;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.vpc.NetworkACLItem.Action;
+import com.cloud.network.vpc.NetworkACLItem.TrafficType;
+import com.cloud.network.vpc.dao.NetworkACLDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.User;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.junit.After;
+import org.mockito.MockedStatic;
+import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class NetworkACLServiceImplTest {
@@ -80,6 +83,8 @@ public class NetworkACLServiceImplTest {
@Mock
private EntityManager entityManagerMock;
@Mock
+ private VpcDao vpcDaoMock;
+ @Mock
private AccountManager accountManagerMock;
@Mock
private NetworkACLDao networkAclDaoMock;
@@ -99,10 +104,11 @@ public class NetworkACLServiceImplTest {
@Mock
private UpdateNetworkACLListCmd updateNetworkACLListCmdMock;
- private Long networkAclMockId = 1L;
+ private Long networkAclMockId = 5L;
private Long networkOfferingMockId = 2L;
private Long networkMockVpcMockId = 3L;
private long networkAclListId = 1l;
+ private static final String SOME_UUID = "someUuid";
@Mock
private MoveNetworkAclItemCmd moveNetworkAclItemCmdMock;
@@ -121,6 +127,12 @@ public class NetworkACLServiceImplTest {
@Mock
private CallContext callContextMock;
+ @Mock
+ private VpcVO vpcVOMock;
+
+ @Mock
+ private Account accountMock;
+
private MockedStatic<CallContext> callContextMocked;
@Before
@@ -178,9 +190,9 @@ public class NetworkACLServiceImplTest {
}
});
- NetworkACLItem netowkrAclRuleCreated =
networkAclServiceImpl.createNetworkACLItem(createNetworkAclCmdMock);
+ NetworkACLItem networkAclRuleCreated =
networkAclServiceImpl.createNetworkACLItem(createNetworkAclCmdMock);
- Assert.assertEquals(number == null ? 6 : number,
netowkrAclRuleCreated.getNumber());
+ Assert.assertEquals(number == null ? 6 : number,
networkAclRuleCreated.getNumber());
InOrder inOrder = Mockito.inOrder( networkAclServiceImpl,
networkAclManagerMock, networkAclItemDaoMock);
inOrder.verify(networkAclServiceImpl).createAclListIfNeeded(createNetworkAclCmdMock);
@@ -392,13 +404,13 @@ public class NetworkACLServiceImplTest {
@Test(expected = InvalidParameterValueException.class)
public void validateNetworkAclTestAclNotDefaulWithoutVpc() {
Mockito.when(networkAclMock.getId()).thenReturn(3L);
- Mockito.doReturn(null).when(entityManagerMock).findById(Vpc.class,
networkMockVpcMockId);
+ Mockito.doReturn(null).when(vpcDaoMock).findById(networkMockVpcMockId);
networkAclServiceImpl.validateNetworkAcl(networkAclMock);
}
@Test
- public void validateNetworkAclTestAclNotDefaulWithVpc() {
+ public void validateNetworkAclTestAclNotDefaultWithVpc() {
CallContext callContextMock = Mockito.mock(CallContext.class);
Mockito.doReturn(Mockito.mock(Account.class)).when(callContextMock).getCallingAccount();
@@ -407,12 +419,11 @@ public class NetworkACLServiceImplTest {
Mockito.when(networkAclMock.getId()).thenReturn(3L);
Mockito.when(networkAclMock.getVpcId()).thenReturn(networkMockVpcMockId);
-
Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class,
networkMockVpcMockId);
+
Mockito.doReturn(vpcVOMock).when(vpcDaoMock).findById(networkMockVpcMockId);
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class),
Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
networkAclServiceImpl.validateNetworkAcl(networkAclMock);
- Mockito.verify(entityManagerMock).findById(Vpc.class,
networkMockVpcMockId);
Mockito.verify(accountManagerMock).checkAccess(Mockito.any(Account.class),
Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
callContextMocked.verify(() -> CallContext.current());
@@ -702,16 +713,22 @@ public class NetworkACLServiceImplTest {
Mockito.doReturn(networkAclItemVoMock).when(networkAclServiceImpl).validateNetworkAclRuleIdAndRetrieveIt(updateNetworkACLItemCmdMock);
Mockito.doReturn(networkAclMock).when(networkAclManagerMock).getNetworkACL(networkAclMockId);
Mockito.doNothing().when(networkAclServiceImpl).validateNetworkAcl(Mockito.eq(networkAclMock));
+
Mockito.doNothing().when(networkAclServiceImpl).validateGlobalAclPermissionAndAclAssociatedToVpc(Mockito.any(NetworkACL.class),
Mockito.any(Account.class), Mockito.anyString());
Mockito.doNothing().when(networkAclServiceImpl).transferDataToNetworkAclRulePojo(Mockito.eq(updateNetworkACLItemCmdMock),
Mockito.eq(networkAclItemVoMock), Mockito.eq(networkAclMock));
Mockito.doNothing().when(networkAclServiceImpl).validateNetworkACLItem(networkAclItemVoMock);
Mockito.doReturn(networkAclItemVoMock).when(networkAclManagerMock).updateNetworkACLItem(networkAclItemVoMock);
+ CallContext callContextMock = Mockito.mock(CallContext.class);
+
Mockito.doReturn(accountMock).when(callContextMock).getCallingAccount();
+ Mockito.when(CallContext.current()).thenReturn(callContextMock);
+
networkAclServiceImpl.updateNetworkACLItem(updateNetworkACLItemCmdMock);
InOrder inOrder = Mockito.inOrder(networkAclServiceImpl,
networkAclManagerMock);
inOrder.verify(networkAclServiceImpl).validateNetworkAclRuleIdAndRetrieveIt(updateNetworkACLItemCmdMock);
inOrder.verify(networkAclManagerMock).getNetworkACL(networkAclMockId);
inOrder.verify(networkAclServiceImpl).validateNetworkAcl(networkAclMock);
+
inOrder.verify(networkAclServiceImpl).validateGlobalAclPermissionAndAclAssociatedToVpc(networkAclMock,
accountMock, "Only Root Admins can update global ACLs.");
inOrder.verify(networkAclServiceImpl).transferDataToNetworkAclRulePojo(Mockito.eq(updateNetworkACLItemCmdMock),
Mockito.eq(networkAclItemVoMock), Mockito.eq(networkAclMock));
inOrder.verify(networkAclServiceImpl).validateNetworkACLItem(networkAclItemVoMock);
inOrder.verify(networkAclManagerMock).updateNetworkACLItem(networkAclItemVoMock);
@@ -865,13 +882,18 @@ public class NetworkACLServiceImplTest {
Mockito.when(updateNetworkACLListCmdMock.getCustomId()).thenReturn(customId);
Mockito.when(updateNetworkACLListCmdMock.getId()).thenReturn(networkAclListId);
Mockito.when(updateNetworkACLListCmdMock.getDisplay()).thenReturn(false);
+
Mockito.when(networkACLVOMock.getVpcId()).thenReturn(networkMockVpcMockId);
+
Mockito.doReturn(vpcVOMock).when(vpcDaoMock).findById(networkMockVpcMockId);
+
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class),
+ Mockito.isNull(AccessType.class), Mockito.eq(true),
Mockito.any(Vpc.class));
+
networkAclServiceImpl.updateNetworkACL(updateNetworkACLListCmdMock);
- InOrder inOrder = Mockito.inOrder(networkAclDaoMock,
entityManagerMock, entityManagerMock, accountManagerMock, networkACLVOMock);
+ InOrder inOrder = Mockito.inOrder(networkAclDaoMock, vpcDaoMock,
accountManagerMock, networkACLVOMock);
inOrder.verify(networkAclDaoMock).findById(networkAclListId);
- inOrder.verify(entityManagerMock).findById(Mockito.eq(Vpc.class),
Mockito.anyLong());
+ inOrder.verify(vpcDaoMock).findById(Mockito.anyLong());
inOrder.verify(accountManagerMock).checkAccess(Mockito.any(Account.class),
Mockito.isNull(AccessType.class), Mockito.eq(true), nullable(Vpc.class));
@@ -1063,13 +1085,17 @@ public class NetworkACLServiceImplTest {
Mockito.when(updateNetworkACLListCmdMock.getCustomId()).thenReturn(null);
Mockito.when(updateNetworkACLListCmdMock.getId()).thenReturn(networkAclListId);
Mockito.when(updateNetworkACLListCmdMock.getDisplay()).thenReturn(null);
+
Mockito.when(networkACLVOMock.getVpcId()).thenReturn(networkMockVpcMockId);
+
Mockito.doReturn(vpcVOMock).when(vpcDaoMock).findById(networkMockVpcMockId);
+
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class),
+ Mockito.isNull(AccessType.class), Mockito.eq(true),
Mockito.any(Vpc.class));
networkAclServiceImpl.updateNetworkACL(updateNetworkACLListCmdMock);
- InOrder inOrder = Mockito.inOrder(networkAclDaoMock,
entityManagerMock, accountManagerMock, networkACLVOMock);
+ InOrder inOrder = Mockito.inOrder(networkAclDaoMock, vpcDaoMock,
accountManagerMock, networkACLVOMock);
inOrder.verify(networkAclDaoMock).findById(networkAclListId);
- inOrder.verify(entityManagerMock).findById(eq(Vpc.class),
Mockito.anyLong());
+ inOrder.verify(vpcDaoMock).findById(Mockito.anyLong());
inOrder.verify(accountManagerMock).checkAccess(any(Account.class),
isNull(), eq(true), nullable(Vpc.class));
Mockito.verify(networkACLVOMock, Mockito.times(0)).setName(null);
@@ -1086,21 +1112,18 @@ public class NetworkACLServiceImplTest {
Mockito.when(nextAclRuleMock.getAclId()).thenReturn(networkAclMockId);
Mockito.when(previousAclRuleMock.getAclId()).thenReturn(networkAclMockId);
-
Mockito.doReturn(networkAclMock).when(networkAclDaoMock).findById(networkAclMockId);
-
Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class,
networkMockVpcMockId);
-
CallContext callContextMock = Mockito.mock(CallContext.class);
Mockito.doReturn(Mockito.mock(Account.class)).when(callContextMock).getCallingAccount();
+
Mockito.doReturn(networkAclMock).when(networkAclDaoMock).findById(networkAclMockId);
Mockito.when(CallContext.current()).thenReturn(callContextMock);
-
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class),
Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
+
Mockito.doNothing().when(networkAclServiceImpl).validateGlobalAclPermissionAndAclAssociatedToVpc(Mockito.any(NetworkACL.class),
Mockito.any(Account.class), Mockito.anyString());
networkAclServiceImpl.validateMoveAclRulesData(aclRuleBeingMovedMock,
previousAclRuleMock, nextAclRuleMock);
Mockito.verify(networkAclDaoMock).findById(networkAclMockId);
- Mockito.verify(entityManagerMock).findById(Vpc.class,
networkMockVpcMockId);
-
Mockito.verify(accountManagerMock).checkAccess(Mockito.any(Account.class),
Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
+
Mockito.verify(networkAclServiceImpl).validateGlobalAclPermissionAndAclAssociatedToVpc(Mockito.any(NetworkACL.class),
Mockito.any(Account.class), Mockito.anyString());
}
@Test
@@ -1359,9 +1382,41 @@ public class NetworkACLServiceImplTest {
ArrayList<NetworkACLItemVO> allAclRules = new ArrayList<>();
allAclRules.add(networkAclItemVoMock);
- Mockito.doReturn("someUuid").when(networkAclItemVoMock).getUuid();
+ Mockito.doReturn(SOME_UUID).when(networkAclItemVoMock).getUuid();
networkAclServiceImpl.validateAclConsistency(moveNetworkAclItemCmdMock,
networkACLVOMock, allAclRules);
Mockito.verify(moveNetworkAclItemCmdMock,
Mockito.times(1)).getAclConsistencyHash();
}
+
+ @Test
+ public void
checkGlobalAclPermissionTestGlobalAclWithRootAccountShouldWork() {
+ Mockito.doReturn(Account.Type.ADMIN).when(accountMock).getType();
+
Mockito.doReturn(true).when(networkAclServiceImpl).isGlobalAcl(Mockito.anyLong());
+
+ networkAclServiceImpl.checkGlobalAclPermission(networkMockVpcMockId,
accountMock, "exception");
+ }
+
+ @Test(expected = PermissionDeniedException.class)
+ public void
checkGlobalAclPermissionTestGlobalAclWithNonRootAccountShouldThrow() {
+ Mockito.doReturn(Account.Type.NORMAL).when(accountMock).getType();
+
Mockito.doReturn(true).when(networkAclServiceImpl).isGlobalAcl(Mockito.anyLong());
+
+ networkAclServiceImpl.checkGlobalAclPermission(networkMockVpcMockId,
accountMock, "exception");
+ }
+
+ @Test
+ public void validateAclAssociatedToVpcTestNonNullVpcShouldCheckAccess() {
+
Mockito.doReturn(vpcVOMock).when(vpcDaoMock).findById(Mockito.anyLong());
+
+ networkAclServiceImpl.validateAclAssociatedToVpc(networkMockVpcMockId,
accountMock, SOME_UUID);
+
+ Mockito.verify(accountManagerMock,
Mockito.times(1)).checkAccess(Mockito.any(Account.class), isNull(),
Mockito.anyBoolean(), Mockito.any(Vpc.class));
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void
validateAclAssociatedToVpcTestNullVpcShouldThrowInvalidParameterValueException()
{
+ Mockito.doReturn(null).when(vpcDaoMock).findById(Mockito.anyLong());
+
+ networkAclServiceImpl.validateAclAssociatedToVpc(networkMockVpcMockId,
accountMock, SOME_UUID);
+ }
}
diff --git a/test/integration/smoke/test_global_acls.py
b/test/integration/smoke/test_global_acls.py
new file mode 100644
index 00000000000..47db858c121
--- /dev/null
+++ b/test/integration/smoke/test_global_acls.py
@@ -0,0 +1,245 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.utils import cleanup_resources
+from marvin.lib.base import (Network, NetworkACLList, NetworkOffering,
VpcOffering, VPC, NetworkACL)
+from marvin.lib.common import (get_domain, get_zone)
+from nose.plugins.attrib import attr
+from marvin.cloudstackException import CloudstackAPIException
+
+
+class Services:
+ """Test Global ACLs
+ """
+
+ def __init__(self):
+ self.services = {
+ "root_domain": {
+ "name": "ROOT",
+ },
+ "domain": {
+ "name": "Domain",
+ },
+ "user": {
+ "username": "user",
+ "roletype": 0,
+ },
+ "domain_admin": {
+ "username": "Domain admin",
+ "roletype": 2,
+ },
+ "root_admin": {
+ "username": "Root admin",
+ "roletype": 1,
+ },
+ "vpc": {
+ "name": "vpc-networkacl",
+ "displaytext": "vpc-networkacl",
+ "cidr": "10.1.1.0/24",
+ },
+ "vpcnetwork": {
+ "name": "vpcnetwork",
+ "displaytext": "vpcnetwork",
+ },
+ "rule": {
+ "protocol": "all",
+ "traffictype": "ingress",
+ }
+ }
+
+
+class TestGlobalACLs(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.testClient = super(TestGlobalACLs, cls).getClsTestClient()
+ cls.apiclient = cls.testClient.getApiClient()
+
+ cls.services = Services().services
+ cls.domain = get_domain(cls.apiclient)
+ cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
+ return
+
+ def setUp(self):
+ self.user_apiclient =
self.testClient.getUserApiClient(self.services["user"]["username"],
+
self.services["domain"]["name"],
+
self.services["user"]["roletype"])
+
+ self.domain_admin_apiclient =
self.testClient.getUserApiClient(self.services["domain_admin"]["username"],
+
self.services["domain"]["name"],
+
self.services["domain_admin"]["roletype"])
+
+ self.admin_apiclient =
self.testClient.getUserApiClient(self.services["root_admin"]["username"],
+
self.services["root_domain"]["name"],
+
self.services["root_admin"]["roletype"])
+
+ self.cleanup = []
+ return
+
+ def tearDown(self):
+ super(TestGlobalACLs, self).tearDown()
+
+ @attr(tags=["advanced", "basic"], required_hardware="false")
+ def test_create_global_acl(self):
+ """ Test create global ACL as a normal user, domain admin and root
admin users.
+ """
+
+ self.debug("Creating ACL list as a normal user, should raise
exception.")
+ self.assertRaisesRegex(CloudstackAPIException, "Only Root Admin can
create global ACLs.",
+ NetworkACLList.create,
apiclient=self.user_apiclient, services={},
+ name="acl", description="acl")
+
+ self.debug("Creating ACL list as a domain admin, should raise
exception.")
+ self.assertRaisesRegex(CloudstackAPIException, "Only Root Admin can
create global ACLs.",
+ NetworkACLList.create,
apiclient=self.domain_admin_apiclient, services={},
+ name="acl", description="acl")
+
+ self.debug("Creating ACL list as a root admin, should work.")
+ acl = NetworkACLList.create(apiclient=self.admin_apiclient,
services={}, name="acl", description="acl")
+ self.cleanup.append(acl)
+ self.assertIsNotNone(acl, "A root admin user should be able to create
a global ACL.")
+
+ return
+
+ @attr(tags=["advanced", "basic"], required_hardware="false")
+ def test_replace_acl_of_network(self):
+ """ Test to replace ACL of a VPC as a normal user, domain admin and
root admin users.
+ """
+ # Get network offering
+ networkOffering = NetworkOffering.list(self.apiclient,
name="DefaultIsolatedNetworkOfferingForVpcNetworks")
+ self.assertTrue(networkOffering is not None and len(networkOffering) >
0, "No VPC network offering")
+
+ # Getting VPC offering
+ vpcOffering = VpcOffering.list(self.apiclient, name="Default VPC
offering")
+ self.assertTrue(vpcOffering is not None and len(vpcOffering) > 0, "No
VPC offerings found")
+
+ # Creating VPC
+ vpc = VPC.create(
+ apiclient=self.apiclient,
+ services=self.services["vpc"],
+ networkDomain="vpc.networkacl",
+ vpcofferingid=vpcOffering[0].id,
+ zoneid=self.zone.id,
+ domainid=self.domain.id
+ )
+ self.cleanup.append(vpc)
+ self.assertTrue(vpc is not None, "VPC creation failed")
+
+ # Creating ACL list
+ acl = NetworkACLList.create(apiclient=self.apiclient, services={},
name="acl", description="acl")
+
+ # Creating tier on VPC with ACL list
+ network = Network.create(
+ apiclient=self.apiclient,
+ services=self.services["vpcnetwork"],
+ accountid="Admin",
+ domainid=self.domain.id,
+ networkofferingid=networkOffering[0].id,
+ zoneid=self.zone.id,
+ vpcid=vpc.id,
+ aclid=acl.id,
+ gateway="10.1.1.1",
+ netmask="255.255.255.192"
+ )
+ self.cleanup.append(network)
+
+ # User should be able to replace ACL
+ network.replaceACLList(apiclient=self.user_apiclient, aclid=acl.id)
+ # Domain Admin should be able to replace ACL
+ network.replaceACLList(apiclient=self.domain_admin_apiclient,
aclid=acl.id)
+ # Admin should be able to replace ACL
+ network.replaceACLList(apiclient=self.admin_apiclient, aclid=acl.id)
+
+ return
+
+ @attr(tags=["advanced", "basic"], required_hardware="false")
+ def test_create_acl_rule(self):
+ """ Test to create ACL rule as a normal user, domain admin and root
admin users.
+ """
+ # Creating ACL list
+ acl = NetworkACLList.create(apiclient=self.admin_apiclient,
services={}, name="acl", description="acl")
+ self.cleanup.append(acl)
+
+ self.debug("Creating ACL rule as a user, should raise exception.")
+ self.assertRaisesRegex(CloudstackAPIException, "Only Root Admins can
create rules for a global ACL.",
+ NetworkACL.create, self.user_apiclient,
services=self.services["rule"], aclid=acl.id)
+ self.debug("Creating ACL rule as a domain admin, should raise
exception.")
+ self.assertRaisesRegex(CloudstackAPIException, "Only Root Admins can
create rules for a global ACL.",
+ NetworkACL.create, self.domain_admin_apiclient,
services=self.services["rule"], aclid=acl.id)
+ self.debug("Creating ACL rule as a root admin, should work.")
+ acl_rule = NetworkACL.create(self.admin_apiclient,
services=self.services["rule"], aclid=acl.id)
+ self.cleanup.append(acl_rule)
+
+ return
+
+ @attr(tags=["advanced", "basic"], required_hardware="false")
+ def test_delete_acl_rule(self):
+ """ Test to delete ACL rule as a normal user, domain admin and root
admin users.
+ """
+ # Creating ACL list
+ acl = NetworkACLList.create(apiclient=self.apiclient, services={},
name="acl", description="acl")
+ self.cleanup.append(acl)
+
+ # Creating ACL rule
+ acl_rule = NetworkACL.create(self.apiclient,
services=self.services["rule"], aclid=acl.id)
+ self.cleanup.append(acl_rule)
+
+ self.debug("Deleting ACL rule as a user, should raise exception.")
+ self.assertRaisesRegex(Exception, "Only Root Admin can delete global
ACL rules.",
+ NetworkACL.delete, acl_rule,
self.user_apiclient)
+ self.debug("Deleting ACL rule as a domain admin, should raise
exception.")
+ self.assertRaisesRegex(Exception, "Only Root Admin can delete global
ACL rules.",
+ NetworkACL.delete, acl_rule,
self.domain_admin_apiclient)
+
+ self.debug("Deleting ACL rule as a root admin, should work.")
+ NetworkACL.delete(acl_rule, self.admin_apiclient)
+ self.cleanup.remove(acl_rule)
+
+ # Verify if the number of ACL rules is equal to four, i.e. the number
of rules
+ # for the default ACLs `default_allow` (2 rules) and `default_deny` (2
rules) ACLs
+ number_of_acl_rules = acl_rule.list(apiclient=self.admin_apiclient)
+ self.assertEqual(len(number_of_acl_rules), 4)
+
+ return
+
+
+ @attr(tags=["advanced", "basic"], required_hardware="false")
+ def test_delete_global_acl(self):
+ """ Test delete global ACL as a normal user, domain admin and root
admin users.
+ """
+
+ # Creating ACL list. Not adding to cleanup as it will be deleted in
this method
+ acl = NetworkACLList.create(apiclient=self.apiclient, services={},
name="acl", description="acl")
+ self.cleanup.append(acl)
+
+ self.debug("Deleting ACL list as a normal user, should raise
exception.")
+ self.assertRaisesRegex(Exception, "Only Root Admin can delete global
ACLs.",
+ NetworkACLList.delete, acl,
apiclient=self.user_apiclient)
+
+ self.debug("Deleting ACL list as a domain admin, should raise
exception.")
+ self.assertRaisesRegex(Exception, "Only Root Admin can delete global
ACLs.",
+ NetworkACLList.delete, acl,
apiclient=self.domain_admin_apiclient)
+
+ self.debug("Deleting ACL list as a root admin, should work.")
+ acl.delete(apiclient=self.admin_apiclient)
+ self.cleanup.remove(acl)
+
+ # Verify if number of ACLs is equal to two, i.e. the number of default
ACLs `default_allow` and `default_deny`
+ number_of_acls = NetworkACLList.list(apiclient=self.admin_apiclient)
+ self.assertEqual(len(number_of_acls), 2)
+
+ return