This is an automated email from the ASF dual-hosted git repository.

nvazquez pushed a commit to branch 4.19.1.1-RC20240802T1731
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 7cfbcf4b4f1b3e36ea496cbdbf17d1c49d8a8d1b
Author: Abhishek Kumar <abhishek.mr...@gmail.com>
AuthorDate: Sat Aug 3 02:00:04 2024 +0530

    [4.19] server, api, ui: access improvements and assorted fixes (#22)
    
    * server, api, ui: access improvements and assorted fixes
    
    Fixes domain-admin access check to prevent unauthorized access.
    
    Co-authored-by: Fabricio Duarte <fabricio.duarte...@gmail.com>
    Co-authored-by: nvazquez <nicovazque...@gmail.com>
    Co-authored-by: Abhishek Kumar <abhishek.mr...@gmail.com>
    
    * Revert "server: refactor listNetworks api database retrievals (#9184)"
    
    This reverts commit c7f1ba5b8eec03d51bfe0f1432e46c9101b0f940.
    
    * Fix snapshot chain being deleted on XenServer (#9447)
    
    Using XenServer as the hypervisor, when deleting a snapshot that has a 
parent, that parent will also get erased on storage, causing data loss. This 
behavior was introduced with #7873, where the list of snapshot states that can 
be deleted was changed to add BackedUp snapshots.
    
    This PR changes the states list back to the original list, and swaps the 
while loop for a do while loop to account for the changes in #7873.
    
    Fixes #9446
    
    * UI: Display Firewall, LB and Port Forwading rules tab for CKS clusters 
deployed on isolated networks (#9458)
    
    ---------
    
    Co-authored-by: nvazquez <nicovazque...@gmail.com>
    Co-authored-by: Fabricio Duarte <fabricio.duarte...@gmail.com>
    Co-authored-by: João Jandre <48719461+joaojan...@users.noreply.github.com>
    Co-authored-by: Pearl Dsilva <pearl1...@gmail.com>
---
 .github/workflows/ci.yml                           |   1 +
 .../storage/snapshot/DefaultSnapshotStrategy.java  |   7 +-
 .../src/main/java/com/cloud/acl/DomainChecker.java |  68 +++++--
 .../java/com/cloud/network/NetworkServiceImpl.java | 209 ++++++++++-----------
 .../java/com/cloud/user/AccountManagerImpl.java    |  18 +-
 .../test/java/com/cloud/acl/DomainCheckerTest.java | 166 ++++++++++++++++
 .../com/cloud/user/AccountManagerImplTest.java     |  58 ++++++
 test/integration/smoke/test_account_access.py      | 198 +++++++++++++++++++
 ui/src/views/compute/KubernetesServiceTab.vue      |   1 +
 9 files changed, 589 insertions(+), 137 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 42407a48b9b..d369916f712 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -35,6 +35,7 @@ jobs:
       fail-fast: false
       matrix:
         tests: [ "smoke/test_accounts
+                  smoke/test_account_access
                   smoke/test_affinity_groups
                   smoke/test_affinity_groups_projects
                   smoke/test_annotations
diff --git 
a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java
 
b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java
index f1f073db170..333272113bd 100644
--- 
a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java
+++ 
b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java
@@ -102,6 +102,8 @@ public class DefaultSnapshotStrategy extends 
SnapshotStrategyBase {
     @Inject
     SnapshotZoneDao snapshotZoneDao;
 
+    private final List<Snapshot.State> snapshotStatesAbleToDeleteSnapshot = 
Arrays.asList(Snapshot.State.Destroying, Snapshot.State.Destroyed, 
Snapshot.State.Error);
+
     public SnapshotDataStoreVO getSnapshotImageStoreRef(long snapshotId, long 
zoneId) {
         List<SnapshotDataStoreVO> snaps = 
snapshotStoreDao.listReadyBySnapshot(snapshotId, DataStoreRole.Image);
         for (SnapshotDataStoreVO ref : snaps) {
@@ -199,9 +201,8 @@ public class DefaultSnapshotStrategy extends 
SnapshotStrategyBase {
 
         boolean result = false;
         boolean resultIsSet = false;
-        final List<Snapshot.State> snapshotStatesAbleToDeleteSnapshot = 
Arrays.asList(Snapshot.State.BackedUp, Snapshot.State.Destroying, 
Snapshot.State.Destroyed, Snapshot.State.Error);
         try {
-            while (snapshot != null && 
snapshotStatesAbleToDeleteSnapshot.contains(snapshot.getState())) {
+            do {
                 SnapshotInfo child = snapshot.getChild();
 
                 if (child != null) {
@@ -247,7 +248,7 @@ public class DefaultSnapshotStrategy extends 
SnapshotStrategyBase {
                 }
 
                 snapshot = parent;
-            }
+            } while (snapshot != null && 
snapshotStatesAbleToDeleteSnapshot.contains(snapshot.getState()));
         } catch (Exception e) {
             s_logger.error(String.format("Failed to delete snapshot [%s] on 
storage [%s] due to [%s].", snapshotTo, storageToString, e.getMessage()), e);
         }
diff --git a/server/src/main/java/com/cloud/acl/DomainChecker.java 
b/server/src/main/java/com/cloud/acl/DomainChecker.java
index a8c9ab84f7e..7930be49ec1 100644
--- a/server/src/main/java/com/cloud/acl/DomainChecker.java
+++ b/server/src/main/java/com/cloud/acl/DomainChecker.java
@@ -208,7 +208,7 @@ public class DomainChecker extends AdapterBase implements 
SecurityChecker {
 
             return true;
         } else if (entity instanceof Network && accessType != null && 
accessType == AccessType.UseEntry) {
-            _networkMgr.checkNetworkPermissions(caller, (Network)entity);
+            _networkMgr.checkNetworkPermissions(caller, (Network) entity);
         } else if (entity instanceof Network && accessType != null && 
accessType == AccessType.OperateEntry) {
             _networkMgr.checkNetworkOperatePermissions(caller, 
(Network)entity);
         } else if (entity instanceof VirtualRouter) {
@@ -216,30 +216,58 @@ public class DomainChecker extends AdapterBase implements 
SecurityChecker {
         } else if (entity instanceof AffinityGroup) {
             return false;
         } else {
-            if (_accountService.isNormalUser(caller.getId())) {
-                Account account = _accountDao.findById(entity.getAccountId());
-                String errorMessage = String.format("%s does not have 
permission to operate with resource", caller);
-                if (account != null && account.getType() == 
Account.Type.PROJECT) {
-                    //only project owner can delete/modify the project
-                    if (accessType != null && accessType == 
AccessType.ModifyProject) {
-                        if (!_projectMgr.canModifyProjectAccount(caller, 
account.getId())) {
-                            throw new PermissionDeniedException(errorMessage);
-                        }
-                    } else if (!_projectMgr.canAccessProjectAccount(caller, 
account.getId())) {
-                        throw new PermissionDeniedException(errorMessage);
-                    }
-                    checkOperationPermitted(caller, entity);
-                } else {
-                    if (caller.getId() != entity.getAccountId()) {
-                        throw new PermissionDeniedException(errorMessage);
-                    }
+            validateCallerHasAccessToEntityOwner(caller, entity, accessType);
+        }
+        return true;
+    }
+
+    protected void validateCallerHasAccessToEntityOwner(Account caller, 
ControlledEntity entity, AccessType accessType) {
+        PermissionDeniedException exception = new 
PermissionDeniedException("Caller does not have permission to operate with 
provided resource.");
+        String entityLog = String.format("entity [owner ID: %d, type: %s]", 
entity.getAccountId(),
+                entity.getEntityType().getSimpleName());
+
+        if (_accountService.isRootAdmin(caller.getId())) {
+            return;
+        }
+
+        if (caller.getId() == entity.getAccountId()) {
+            return;
+        }
+
+        Account owner = _accountDao.findById(entity.getAccountId());
+        if (owner == null) {
+            s_logger.error(String.format("Owner not found for %s", entityLog));
+            throw exception;
+        }
+
+        Account.Type callerAccountType = caller.getType();
+        if ((callerAccountType == Account.Type.DOMAIN_ADMIN || 
callerAccountType == Account.Type.RESOURCE_DOMAIN_ADMIN) &&
+                _domainDao.isChildDomain(caller.getDomainId(), 
owner.getDomainId())) {
+            return;
+        }
+
+        if (owner.getType() == Account.Type.PROJECT) {
+            // only project owner can delete/modify the project
+            if (accessType == AccessType.ModifyProject) {
+                if (!_projectMgr.canModifyProjectAccount(caller, 
owner.getId())) {
+                    s_logger.error(String.format("Caller ID: %d does not have 
permission to modify project with " +
+                            "owner ID: %d", caller.getId(), owner.getId()));
+                    throw exception;
                 }
+            } else if (!_projectMgr.canAccessProjectAccount(caller, 
owner.getId())) {
+                s_logger.error(String.format("Caller ID: %d does not have 
permission to access project with " +
+                        "owner ID: %d", caller.getId(), owner.getId()));
+                throw exception;
             }
+            checkOperationPermitted(caller, entity);
+            return;
         }
-        return true;
+
+        s_logger.error(String.format("Caller ID: %d does not have permission 
to access %s", caller.getId(), entityLog));
+        throw exception;
     }
 
-    private boolean checkOperationPermitted(Account caller, ControlledEntity 
entity) {
+    protected boolean checkOperationPermitted(Account caller, ControlledEntity 
entity) {
         User user = CallContext.current().getCallingUser();
         Project project = 
projectDao.findByProjectAccountId(entity.getAccountId());
         if (project == null) {
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java 
b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index 83ef8b1b213..c58463ac708 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -36,6 +36,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
@@ -2196,9 +2197,6 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
         Long associatedNetworkId = cmd.getAssociatedNetworkId();
         String networkFilterStr = cmd.getNetworkFilter();
 
-        boolean applyManualPagination = 
CollectionUtils.isNotEmpty(supportedServicesStr) ||
-                Boolean.TRUE.equals(canUseForDeploy);
-
         String vlanId = null;
         if (cmd instanceof ListNetworksCmdByAdmin) {
             vlanId = ((ListNetworksCmdByAdmin)cmd).getVlan();
@@ -2284,13 +2282,7 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
             isRecursive = true;
         }
 
-        Long offset = cmd.getStartIndex();
-        Long limit = cmd.getPageSizeVal();
-        if (applyManualPagination) {
-            offset = null;
-            limit = null;
-        }
-        Filter searchFilter = new Filter(NetworkVO.class, "id", false, offset, 
limit);
+        Filter searchFilter = new Filter(NetworkVO.class, "id", false, null, 
null);
         SearchBuilder<NetworkVO> sb = _networksDao.createSearchBuilder();
 
         if (forVpc != null) {
@@ -2345,123 +2337,113 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
             sb.join("associatedNetworkSearch", associatedNetworkSearch, 
sb.entity().getId(), associatedNetworkSearch.entity().getResourceId(), 
JoinBuilder.JoinType.INNER);
         }
 
-        SearchCriteria<NetworkVO> mainSearchCriteria = 
createNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId,
-                guestIpType, trafficType, physicalNetworkId, 
networkOfferingId, aclType, restartRequired,
-                specifyIpRanges, vpcId, tags, display, vlanId, 
associatedNetworkId);
-        SearchCriteria<NetworkVO> additionalSearchCriteria = 
_networksDao.createSearchCriteria();
+        List<NetworkVO> networksToReturn = new ArrayList<NetworkVO>();
 
         if (isSystem == null || !isSystem) {
             if (!permittedAccounts.isEmpty()) {
                 if (Arrays.asList(Network.NetworkFilter.Account, 
Network.NetworkFilter.AccountDomain, 
Network.NetworkFilter.All).contains(networkFilter)) {
                     //get account level networks
-                    additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC,
-                            getAccountSpecificNetworksSearchCriteria(sb, 
permittedAccounts, skipProjectNetworks));
+                    
networksToReturn.addAll(listAccountSpecificNetworks(buildNetworkSearchCriteria(sb,
 keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, 
networkOfferingId,
+                            aclType, skipProjectNetworks, restartRequired, 
specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), 
searchFilter, permittedAccounts));
                 }
                 if (domainId != null && 
Arrays.asList(Network.NetworkFilter.Domain, 
Network.NetworkFilter.AccountDomain, 
Network.NetworkFilter.All).contains(networkFilter)) {
                     //get domain level networks
-                    SearchCriteria<NetworkVO> domainLevelSC = 
getDomainLevelNetworksSearchCriteria(sb, domainId, false);
-                    if (domainLevelSC != null) {
-                        additionalSearchCriteria.addOr("id", 
SearchCriteria.Op.SC, domainLevelSC);
-                    }
+                    
networksToReturn.addAll(listDomainLevelNetworks(buildNetworkSearchCriteria(sb, 
keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, 
networkOfferingId,
+                            aclType, true, restartRequired, specifyIpRanges, 
vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, domainId, 
false));
                 }
                 if (Arrays.asList(Network.NetworkFilter.Shared, 
Network.NetworkFilter.All).contains(networkFilter)) {
                     // get shared networks
-                    SearchCriteria<NetworkVO> sharedNetworksSC = 
getSharedNetworksSearchCriteria(sb, permittedAccounts);
-                    if (sharedNetworksSC != null) {
-                        additionalSearchCriteria.addOr("id", 
SearchCriteria.Op.SC, sharedNetworksSC);
-                    }
+                    List<NetworkVO> sharedNetworks = 
listSharedNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, 
zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
+                            aclType, true, restartRequired, specifyIpRanges, 
vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, 
permittedAccounts);
+                    addNetworksToReturnIfNotExist(networksToReturn, 
sharedNetworks);
+
                 }
             } else {
                 if (Arrays.asList(Network.NetworkFilter.Account, 
Network.NetworkFilter.AccountDomain, 
Network.NetworkFilter.All).contains(networkFilter)) {
                     //add account specific networks
-                    additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC,
-                            
getAccountSpecificNetworksByDomainPathSearchCriteria(sb, path, isRecursive,
-                                    skipProjectNetworks));
+                    
networksToReturn.addAll(listAccountSpecificNetworksByDomainPath(buildNetworkSearchCriteria(sb,
 keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, 
networkOfferingId,
+                            aclType, skipProjectNetworks, restartRequired, 
specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), 
searchFilter, path, isRecursive));
                 }
                 if (Arrays.asList(Network.NetworkFilter.Domain, 
Network.NetworkFilter.AccountDomain, 
Network.NetworkFilter.All).contains(networkFilter)) {
                     //add domain specific networks of domain + parent domains
-                    SearchCriteria<NetworkVO> 
domainSpecificNetworksByDomainPathSC =
-                            
getDomainSpecificNetworksByDomainPathSearchCriteria(sb, path, isRecursive);
-                    if (domainSpecificNetworksByDomainPathSC != null) {
-                        additionalSearchCriteria.addOr("id", 
SearchCriteria.Op.SC, domainSpecificNetworksByDomainPathSC);
-                    }
+                    
networksToReturn.addAll(listDomainSpecificNetworksByDomainPath(buildNetworkSearchCriteria(sb,
 keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, 
networkOfferingId,
+                            aclType, true, restartRequired, specifyIpRanges, 
vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, 
isRecursive));
                     //add networks of subdomains
                     if (domainId == null) {
-                        SearchCriteria<NetworkVO> domainLevelSC = 
getDomainLevelNetworksSearchCriteria(sb, caller.getDomainId(), true);
-                        if (domainLevelSC != null) {
-                            additionalSearchCriteria.addOr("id", 
SearchCriteria.Op.SC, domainLevelSC);
-                        }
+                        
networksToReturn.addAll(listDomainLevelNetworks(buildNetworkSearchCriteria(sb, 
keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, 
networkOfferingId,
+                            aclType, true, restartRequired, specifyIpRanges, 
vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, 
caller.getDomainId(), true));
                     }
                 }
                 if (Arrays.asList(Network.NetworkFilter.Shared, 
Network.NetworkFilter.All).contains(networkFilter)) {
                     // get shared networks
-                    SearchCriteria<NetworkVO> sharedNetworksSC = 
getSharedNetworksByDomainPathSearchCriteria(sb, path, isRecursive);
-                    if (sharedNetworksSC != null) {
-                        additionalSearchCriteria.addOr("id", 
SearchCriteria.Op.SC, sharedNetworksSC);
-                    }
+                    List<NetworkVO> sharedNetworks = 
listSharedNetworksByDomainPath(buildNetworkSearchCriteria(sb, keyword, id, 
isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, 
networkOfferingId,
+                            aclType, true, restartRequired, specifyIpRanges, 
vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, 
isRecursive);
+                    addNetworksToReturnIfNotExist(networksToReturn, 
sharedNetworks);
                 }
             }
-            if 
(CollectionUtils.isNotEmpty(additionalSearchCriteria.getValues())) {
-                mainSearchCriteria.addAnd("id", SearchCriteria.Op.SC, 
additionalSearchCriteria);
-            }
         } else {
-            if (skipProjectNetworks) {
-                mainSearchCriteria.setJoinParameters("accountSearch", 
"typeNEQ", Account.Type.PROJECT);
-            } else {
-                mainSearchCriteria.setJoinParameters("accountSearch", 
"typeEQ", Account.Type.PROJECT);
-            }
+            networksToReturn = 
_networksDao.search(buildNetworkSearchCriteria(sb, keyword, id, isSystem, 
zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
+                    null, true, restartRequired, specifyIpRanges, vpcId, tags, 
display, vlanId, associatedNetworkId), searchFilter);
         }
-        Pair<List<NetworkVO>, Integer> result = 
_networksDao.searchAndCount(mainSearchCriteria, searchFilter);
-        List<NetworkVO> networksToReturn = result.first();
 
         if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && 
!networksToReturn.isEmpty()) {
-            List<NetworkVO> supportedNetworks = new ArrayList<>();
-            Service[] supportedServices = new 
Service[supportedServicesStr.size()];
+            List<NetworkVO> supportedNetworks = new ArrayList<NetworkVO>();
+            Service[] suppportedServices = new 
Service[supportedServicesStr.size()];
             int i = 0;
             for (String supportedServiceStr : supportedServicesStr) {
                 Service service = Service.getService(supportedServiceStr);
                 if (service == null) {
                     throw new InvalidParameterValueException("Invalid service 
specified " + supportedServiceStr);
                 } else {
-                    supportedServices[i] = service;
+                    suppportedServices[i] = service;
                 }
                 i++;
             }
+
             for (NetworkVO network : networksToReturn) {
-                if (areServicesSupportedInNetwork(network.getId(), 
supportedServices)) {
+                if (areServicesSupportedInNetwork(network.getId(), 
suppportedServices)) {
                     supportedNetworks.add(network);
                 }
             }
+
             networksToReturn = supportedNetworks;
         }
 
         if (canUseForDeploy != null) {
-            List<NetworkVO> networksForDeploy = new ArrayList<>();
+            List<NetworkVO> networksForDeploy = new ArrayList<NetworkVO>();
             for (NetworkVO network : networksToReturn) {
                 if (_networkModel.canUseForDeploy(network) == canUseForDeploy) 
{
                     networksForDeploy.add(network);
                 }
             }
+
             networksToReturn = networksForDeploy;
         }
 
-        if (applyManualPagination) {
-            //Now apply pagination
-            List<? extends Network> wPagination = 
com.cloud.utils.StringUtils.applyPagination(networksToReturn, 
cmd.getStartIndex(), cmd.getPageSizeVal());
-            if (wPagination != null) {
-                Pair<List<? extends Network>, Integer> listWPagination = new 
Pair<>(wPagination, networksToReturn.size());
-                return listWPagination;
-            }
-            return new Pair<>(networksToReturn, networksToReturn.size());
+        //Now apply pagination
+        List<? extends Network> wPagination = 
com.cloud.utils.StringUtils.applyPagination(networksToReturn, 
cmd.getStartIndex(), cmd.getPageSizeVal());
+        if (wPagination != null) {
+            Pair<List<? extends Network>, Integer> listWPagination = new 
Pair<List<? extends Network>, Integer>(wPagination, networksToReturn.size());
+            return listWPagination;
         }
 
-        return new Pair<>(result.first(), result.second());
+        return new Pair<List<? extends Network>, Integer>(networksToReturn, 
networksToReturn.size());
     }
 
-    private SearchCriteria<NetworkVO> 
createNetworkSearchCriteria(SearchBuilder<NetworkVO> sb, String keyword, Long 
id,
-                                                                 Boolean 
isSystem, Long zoneId, String guestIpType, String trafficType, Long 
physicalNetworkId,
-                                                                 Long 
networkOfferingId, String aclType, Boolean restartRequired,
-                                                                 Boolean 
specifyIpRanges, Long vpcId, Map<String, String> tags, Boolean display, String 
vlanId, Long associatedNetworkId) {
+    private void addNetworksToReturnIfNotExist(final List<NetworkVO> 
networksToReturn, final List<NetworkVO> sharedNetworks) {
+        Set<Long> networkIds = networksToReturn.stream()
+                .map(NetworkVO::getId)
+                .collect(Collectors.toSet());
+        List<NetworkVO> sharedNetworksToReturn = sharedNetworks.stream()
+                .filter(network -> ! networkIds.contains(network.getId()))
+                .collect(Collectors.toList());
+        networksToReturn.addAll(sharedNetworksToReturn);
+    }
+
+    private SearchCriteria<NetworkVO> 
buildNetworkSearchCriteria(SearchBuilder<NetworkVO> sb, String keyword, Long id,
+            Boolean isSystem, Long zoneId, String guestIpType, String 
trafficType, Long physicalNetworkId,
+            Long networkOfferingId, String aclType, boolean 
skipProjectNetworks, Boolean restartRequired,
+            Boolean specifyIpRanges, Long vpcId, Map<String, String> tags, 
Boolean display, String vlanId, Long associatedNetworkId) {
 
         SearchCriteria<NetworkVO> sc = sb.create();
 
@@ -2503,6 +2485,12 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
             sc.addAnd("physicalNetworkId", SearchCriteria.Op.EQ, 
physicalNetworkId);
         }
 
+        if (skipProjectNetworks) {
+            sc.setJoinParameters("accountSearch", "typeNEQ", 
Account.Type.PROJECT);
+        } else {
+            sc.setJoinParameters("accountSearch", "typeEQ", 
Account.Type.PROJECT);
+        }
+
         if (restartRequired != null) {
             sc.addAnd("restartRequired", SearchCriteria.Op.EQ, 
restartRequired);
         }
@@ -2543,8 +2531,8 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
         return sc;
     }
 
-    private SearchCriteria<NetworkVO> 
getDomainLevelNetworksSearchCriteria(SearchBuilder<NetworkVO> sb, long 
domainId, boolean parentDomainsOnly) {
-        List<Long> networkIds = new ArrayList<>();
+    private List<NetworkVO> listDomainLevelNetworks(SearchCriteria<NetworkVO> 
sc, Filter searchFilter, long domainId, boolean parentDomainsOnly) {
+        List<Long> networkIds = new ArrayList<Long>();
         Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId);
         List<NetworkDomainVO> maps = 
_networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
 
@@ -2559,55 +2547,48 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
         }
 
         if (!networkIds.isEmpty()) {
-            SearchCriteria<NetworkVO> domainSC = sb.create();
-            domainSC.setJoinParameters("accountSearch", "typeNEQ", 
Account.Type.PROJECT);
+            SearchCriteria<NetworkVO> domainSC = 
_networksDao.createSearchCriteria();
             domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
             domainSC.addAnd("aclType", SearchCriteria.Op.EQ, 
ACLType.Domain.toString());
-            return domainSC;
-        }
-        return null;
-    }
 
-    private SearchCriteria<NetworkVO> 
getAccountSpecificNetworksSearchCriteria(SearchBuilder<NetworkVO> sb,
-           List<Long> permittedAccounts, boolean skipProjectNetworks) {
-        SearchCriteria<NetworkVO> accountSC = sb.create();
-        if (skipProjectNetworks) {
-            accountSC.setJoinParameters("accountSearch", "typeNEQ", 
Account.Type.PROJECT);
+            sc.addAnd("id", SearchCriteria.Op.SC, domainSC);
+            return _networksDao.search(sc, searchFilter);
         } else {
-            accountSC.setJoinParameters("accountSearch", "typeEQ", 
Account.Type.PROJECT);
+            return new ArrayList<NetworkVO>();
         }
+    }
+
+    private List<NetworkVO> 
listAccountSpecificNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, 
List<Long> permittedAccounts) {
+        SearchCriteria<NetworkVO> accountSC = 
_networksDao.createSearchCriteria();
         if (!permittedAccounts.isEmpty()) {
             accountSC.addAnd("accountId", SearchCriteria.Op.IN, 
permittedAccounts.toArray());
         }
+
         accountSC.addAnd("aclType", SearchCriteria.Op.EQ, 
ACLType.Account.toString());
-        return accountSC;
+
+        sc.addAnd("id", SearchCriteria.Op.SC, accountSC);
+        return _networksDao.search(sc, searchFilter);
     }
 
-    private SearchCriteria<NetworkVO> 
getAccountSpecificNetworksByDomainPathSearchCriteria(SearchBuilder<NetworkVO> 
sb,
-           String path, boolean isRecursive, boolean skipProjectNetworks) {
-        SearchCriteria<NetworkVO> accountSC = sb.create();
-        if (skipProjectNetworks) {
-            accountSC.setJoinParameters("accountSearch", "typeNEQ", 
Account.Type.PROJECT);
-        } else {
-            accountSC.setJoinParameters("accountSearch", "typeEQ", 
Account.Type.PROJECT);
-        }
+    private List<NetworkVO> 
listAccountSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter 
searchFilter, String path, boolean isRecursive) {
+        SearchCriteria<NetworkVO> accountSC = 
_networksDao.createSearchCriteria();
         accountSC.addAnd("aclType", SearchCriteria.Op.EQ, 
ACLType.Account.toString());
 
         if (path != null) {
             if (isRecursive) {
-                accountSC.setJoinParameters("domainSearch", "path", path + 
"%");
+                sc.setJoinParameters("domainSearch", "path", path + "%");
             } else {
-                accountSC.setJoinParameters("domainSearch", "path", path);
+                sc.setJoinParameters("domainSearch", "path", path);
             }
         }
 
-        return accountSC;
+        sc.addAnd("id", SearchCriteria.Op.SC, accountSC);
+        return _networksDao.search(sc, searchFilter);
     }
 
-    private SearchCriteria<NetworkVO> 
getDomainSpecificNetworksByDomainPathSearchCriteria(SearchBuilder<NetworkVO> sb,
-            String path, boolean isRecursive) {
+    private List<NetworkVO> 
listDomainSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter 
searchFilter, String path, boolean isRecursive) {
 
-        Set<Long> allowedDomains = new HashSet<>();
+        Set<Long> allowedDomains = new HashSet<Long>();
         if (path != null) {
             if (isRecursive) {
                 allowedDomains = _domainMgr.getDomainChildrenIds(path);
@@ -2617,7 +2598,7 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
             }
         }
 
-        List<Long> networkIds = new ArrayList<>();
+        List<Long> networkIds = new ArrayList<Long>();
 
         List<NetworkDomainVO> maps = 
_networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
 
@@ -2626,28 +2607,30 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
         }
 
         if (!networkIds.isEmpty()) {
-            SearchCriteria<NetworkVO> domainSC = sb.create();
-            domainSC.setJoinParameters("accountSearch", "typeNEQ", 
Account.Type.PROJECT);
+            SearchCriteria<NetworkVO> domainSC = 
_networksDao.createSearchCriteria();
             domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
             domainSC.addAnd("aclType", SearchCriteria.Op.EQ, 
ACLType.Domain.toString());
-            return domainSC;
+
+            sc.addAnd("id", SearchCriteria.Op.SC, domainSC);
+            return _networksDao.search(sc, searchFilter);
+        } else {
+            return new ArrayList<NetworkVO>();
         }
-        return null;
     }
 
-    private SearchCriteria<NetworkVO> 
getSharedNetworksSearchCriteria(SearchBuilder<NetworkVO> sb, List<Long> 
permittedAccounts) {
+    private List<NetworkVO> listSharedNetworks(SearchCriteria<NetworkVO> sc, 
Filter searchFilter, List<Long> permittedAccounts) {
         List<Long> sharedNetworkIds = 
_networkPermissionDao.listPermittedNetworkIdsByAccounts(permittedAccounts);
         if (!sharedNetworkIds.isEmpty()) {
-            SearchCriteria<NetworkVO> ssc = sb.create();
-            ssc.setJoinParameters("accountSearch", "typeNEQ", 
Account.Type.PROJECT);
+            SearchCriteria<NetworkVO> ssc = 
_networksDao.createSearchCriteria();
             ssc.addAnd("id", SearchCriteria.Op.IN, sharedNetworkIds.toArray());
-            return ssc;
+            sc.addAnd("id", SearchCriteria.Op.SC, ssc);
+            return _networksDao.search(sc, searchFilter);
         }
-        return null;
+        return new ArrayList<NetworkVO>();
     }
 
-    private SearchCriteria<NetworkVO> 
getSharedNetworksByDomainPathSearchCriteria(SearchBuilder<NetworkVO> sb, String 
path, boolean isRecursive) {
-        Set<Long> allowedDomains = new HashSet<>();
+    private List<NetworkVO> 
listSharedNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter 
searchFilter, String path, boolean isRecursive) {
+        Set<Long> allowedDomains = new HashSet<Long>();
         if (path != null) {
             if (isRecursive) {
                 allowedDomains = _domainMgr.getDomainChildrenIds(path);
@@ -2669,13 +2652,13 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
 
             List<Long> sharedNetworkIds = 
_networkPermissionDao.listPermittedNetworkIdsByAccounts(allowedAccountsList);
             if (!sharedNetworkIds.isEmpty()) {
-                SearchCriteria<NetworkVO> ssc = sb.create();
-                ssc.setJoinParameters("accountSearch", "typeNEQ", 
Account.Type.PROJECT);
+                SearchCriteria<NetworkVO> ssc = 
_networksDao.createSearchCriteria();
                 ssc.addAnd("id", SearchCriteria.Op.IN, 
sharedNetworkIds.toArray());
-                return ssc;
+                sc.addAnd("id", SearchCriteria.Op.SC, ssc);
+                return _networksDao.search(sc, searchFilter);
             }
         }
-        return null;
+        return new ArrayList<NetworkVO>();
     }
 
     @Override
diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java 
b/server/src/main/java/com/cloud/user/AccountManagerImpl.java
index 3eed429ed21..0a0d9265ac4 100644
--- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java
@@ -2744,7 +2744,9 @@ public class AccountManagerImpl extends ManagerBase 
implements AccountManager, M
             throw new InvalidParameterValueException("Unable to find user by 
id");
         }
         final ControlledEntity account = 
getAccount(getUserAccountById(userId).getAccountId()); //Extracting the Account 
from the userID of the requested user.
-        checkAccess(CallContext.current().getCallingUser(), account);
+        User caller = CallContext.current().getCallingUser();
+        preventRootDomainAdminAccessToRootAdminKeys(caller, account);
+        checkAccess(caller, account);
 
         Map<String, String> keys = new HashMap<String, String>();
         keys.put("apikey", user.getApiKey());
@@ -2753,6 +2755,19 @@ public class AccountManagerImpl extends ManagerBase 
implements AccountManager, M
         return keys;
     }
 
+    protected void preventRootDomainAdminAccessToRootAdminKeys(User caller, 
ControlledEntity account) {
+        if (isDomainAdminForRootDomain(caller) && 
isRootAdmin(account.getAccountId())) {
+            String msg = String.format("Caller Username %s does not have 
access to root admin keys", caller.getUsername());
+            s_logger.error(msg);
+            throw new PermissionDeniedException(msg);
+        }
+    }
+
+    protected boolean isDomainAdminForRootDomain(User callingUser) {
+        AccountVO caller = _accountDao.findById(callingUser.getAccountId());
+        return caller.getType() == Account.Type.DOMAIN_ADMIN && 
caller.getDomainId() == Domain.ROOT_DOMAIN;
+    }
+
     @Override
     public List<UserTwoFactorAuthenticator> 
listUserTwoFactorAuthenticationProviders() {
         return userTwoFactorAuthenticationProviders;
@@ -2787,6 +2802,7 @@ public class AccountManagerImpl extends ManagerBase 
implements AccountManager, M
         }
 
         Account account = _accountDao.findById(user.getAccountId());
+        preventRootDomainAdminAccessToRootAdminKeys(user, account);
         checkAccess(caller, null, true, account);
 
         // don't allow updating system user
diff --git a/server/src/test/java/com/cloud/acl/DomainCheckerTest.java 
b/server/src/test/java/com/cloud/acl/DomainCheckerTest.java
new file mode 100644
index 00000000000..a5ec41306d8
--- /dev/null
+++ b/server/src/test/java/com/cloud/acl/DomainCheckerTest.java
@@ -0,0 +1,166 @@
+// 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.
+package com.cloud.acl;
+
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.projects.ProjectManager;
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.Ternary;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DomainCheckerTest {
+
+    @Mock
+    AccountService _accountService;
+    @Mock
+    AccountDao _accountDao;
+    @Mock
+    DomainDao _domainDao;
+    @Mock
+    ProjectManager _projectMgr;
+
+    @Spy
+    @InjectMocks
+    DomainChecker domainChecker;
+
+    private ControlledEntity getMockedEntity(long accountId) {
+        ControlledEntity entity = Mockito.mock(Account.class);
+        Mockito.when(entity.getAccountId()).thenReturn(accountId);
+        Mockito.when(entity.getEntityType()).thenReturn((Class)Account.class);
+        return entity;
+    }
+
+    @Test
+    public void testRootAdminHasAccess() {
+        Account rootAdmin = Mockito.mock(Account.class);
+        Mockito.when(rootAdmin.getId()).thenReturn(1L);
+        ControlledEntity entity = getMockedEntity(2L);
+        
Mockito.when(_accountService.isRootAdmin(rootAdmin.getId())).thenReturn(true);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(rootAdmin, entity, 
SecurityChecker.AccessType.ModifyProject);
+    }
+
+    @Test
+    public void testCallerIsOwner() {
+        Account caller = Mockito.mock(Account.class);
+        Mockito.when(caller.getId()).thenReturn(1L);
+        ControlledEntity entity = getMockedEntity(1L);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void testOwnerNotFound() {
+        Account caller = Mockito.mock(Account.class);
+        Mockito.when(caller.getId()).thenReturn(1L);
+        ControlledEntity entity = getMockedEntity(2L);
+        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(null);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
+    }
+
+    @Test
+    public void testDomainAdminHasAccess() {
+        Account caller = Mockito.mock(Account.class);
+        Mockito.when(caller.getId()).thenReturn(1L);
+        Mockito.when(caller.getDomainId()).thenReturn(100L);
+        Mockito.when(caller.getType()).thenReturn(Account.Type.DOMAIN_ADMIN);
+        ControlledEntity entity = getMockedEntity(2L);
+        AccountVO owner = Mockito.mock(AccountVO.class);
+        Mockito.when(owner.getDomainId()).thenReturn(101L);
+        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(owner);
+        Mockito.when(_domainDao.isChildDomain(100L, 101L)).thenReturn(true);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
+    }
+
+    private Ternary<Account, ControlledEntity, AccountVO> 
getProjectAccessCheckResources() {
+        Account caller = Mockito.mock(Account.class);
+        Mockito.when(caller.getId()).thenReturn(100L);
+        Mockito.when(caller.getType()).thenReturn(Account.Type.PROJECT);
+        ControlledEntity entity = getMockedEntity(2L);
+        AccountVO projectAccount = Mockito.mock(AccountVO.class);
+        Mockito.when(projectAccount.getId()).thenReturn(2L);
+        
Mockito.when(projectAccount.getType()).thenReturn(Account.Type.PROJECT);
+        return new Ternary<>(caller, entity, projectAccount);
+    }
+
+    @Test
+    public void testProjectOwnerCanModify() {
+        Ternary<Account, ControlledEntity, AccountVO> resources = 
getProjectAccessCheckResources();
+        Account caller = resources.first();
+        ControlledEntity entity = resources.second();
+        AccountVO projectAccount = resources.third();
+        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(projectAccount);
+        Mockito.when(_projectMgr.canModifyProjectAccount(caller, 
projectAccount.getId())).thenReturn(true);
+        
Mockito.doReturn(true).when(domainChecker).checkOperationPermitted(caller, 
entity);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void testProjectOwnerCannotModify() {
+        Ternary<Account, ControlledEntity, AccountVO> resources = 
getProjectAccessCheckResources();
+        Account caller = resources.first();
+        ControlledEntity entity = resources.second();
+        AccountVO projectAccount = resources.third();
+        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(projectAccount);
+        Mockito.when(_projectMgr.canModifyProjectAccount(caller, 
projectAccount.getId())).thenReturn(false);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
+    }
+
+    @Test
+    public void testProjectOwnerCanAccess() {
+        Ternary<Account, ControlledEntity, AccountVO> resources = 
getProjectAccessCheckResources();
+        Account caller = resources.first();
+        ControlledEntity entity = resources.second();
+        AccountVO projectAccount = resources.third();
+        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(projectAccount);
+        Mockito.when(_projectMgr.canAccessProjectAccount(caller, 
projectAccount.getId())).thenReturn(true);
+        
Mockito.doReturn(true).when(domainChecker).checkOperationPermitted(caller, 
entity);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ListEntry);
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void testProjectOwnerCannotAccess() {
+        Ternary<Account, ControlledEntity, AccountVO> resources = 
getProjectAccessCheckResources();
+        Account caller = resources.first();
+        ControlledEntity entity = resources.second();
+        AccountVO projectAccount = resources.third();
+        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(projectAccount);
+        Mockito.when(_projectMgr.canAccessProjectAccount(caller, 
projectAccount.getId())).thenReturn(false);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ListEntry);
+    }
+
+}
diff --git a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java 
b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java
index 9014af523fd..36fb1ca518a 100644
--- a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java
+++ b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java
@@ -33,6 +33,7 @@ import com.cloud.vm.UserVmManagerImpl;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.snapshot.VMSnapshotVO;
+import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd;
 import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
@@ -241,6 +242,63 @@ public class AccountManagerImplTest extends 
AccountManagetImplTestBase {
         accountManagerImpl.getKeys(_listkeyscmd);
     }
 
+    @Test(expected = PermissionDeniedException.class)
+    public void testGetUserKeysCmdDomainAdminRootAdminUser() {
+        CallContext.register(callingUser, callingAccount);
+        Mockito.when(_listkeyscmd.getID()).thenReturn(2L);
+        
Mockito.when(accountManagerImpl.getActiveUser(2L)).thenReturn(userVoMock);
+        
Mockito.when(userAccountDaoMock.findById(2L)).thenReturn(userAccountVO);
+        Mockito.when(userAccountVO.getAccountId()).thenReturn(2L);
+        
Mockito.when(userDetailsDaoMock.listDetailsKeyPairs(Mockito.anyLong())).thenReturn(null);
+
+        // Queried account - admin account
+        AccountVO adminAccountMock = Mockito.mock(AccountVO.class);
+        Mockito.when(adminAccountMock.getAccountId()).thenReturn(2L);
+        
Mockito.when(_accountDao.findByIdIncludingRemoved(2L)).thenReturn(adminAccountMock);
+        
Mockito.lenient().when(accountService.isRootAdmin(2L)).thenReturn(true);
+        
Mockito.lenient().when(securityChecker.checkAccess(Mockito.any(Account.class),
+                Mockito.nullable(ControlledEntity.class), 
Mockito.nullable(AccessType.class), Mockito.anyString())).thenReturn(true);
+
+        // Calling account is domain admin of the ROOT domain
+        
Mockito.lenient().when(callingAccount.getType()).thenReturn(Account.Type.DOMAIN_ADMIN);
+        
Mockito.lenient().when(callingAccount.getDomainId()).thenReturn(Domain.ROOT_DOMAIN);
+
+        Mockito.lenient().when(callingUser.getAccountId()).thenReturn(2L);
+        
Mockito.lenient().when(_accountDao.findById(2L)).thenReturn(callingAccount);
+
+        
Mockito.lenient().when(accountService.isDomainAdmin(Mockito.anyLong())).thenReturn(Boolean.TRUE);
+        Mockito.lenient().when(accountMock.getAccountId()).thenReturn(2L);
+
+        accountManagerImpl.getKeys(_listkeyscmd);
+    }
+
+    @Test
+    public void testPreventRootDomainAdminAccessToRootAdminKeysNormalUser() {
+        User user = Mockito.mock(User.class);
+        ControlledEntity entity = Mockito.mock(ControlledEntity.class);
+        Mockito.when(user.getAccountId()).thenReturn(1L);
+        AccountVO account = Mockito.mock(AccountVO.class);
+        Mockito.when(account.getType()).thenReturn(Account.Type.NORMAL);
+        Mockito.when(_accountDao.findById(1L)).thenReturn(account);
+        accountManagerImpl.preventRootDomainAdminAccessToRootAdminKeys(user, 
entity);
+        Mockito.verify(accountManagerImpl, 
Mockito.never()).isRootAdmin(Mockito.anyLong());
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void 
testPreventRootDomainAdminAccessToRootAdminKeysRootDomainAdminUser() {
+        User user = Mockito.mock(User.class);
+        ControlledEntity entity = Mockito.mock(ControlledEntity.class);
+        Mockito.when(user.getAccountId()).thenReturn(1L);
+        AccountVO account = Mockito.mock(AccountVO.class);
+        Mockito.when(account.getType()).thenReturn(Account.Type.DOMAIN_ADMIN);
+        Mockito.when(account.getDomainId()).thenReturn(Domain.ROOT_DOMAIN);
+        Mockito.when(_accountDao.findById(1L)).thenReturn(account);
+        Mockito.when(entity.getAccountId()).thenReturn(1L);
+        
Mockito.lenient().when(securityChecker.checkAccess(Mockito.any(Account.class),
+                Mockito.nullable(ControlledEntity.class), 
Mockito.nullable(AccessType.class), Mockito.anyString())).thenReturn(true);
+        accountManagerImpl.preventRootDomainAdminAccessToRootAdminKeys(user, 
entity);
+    }
+
     @Test
     public void updateUserTestTimeZoneAndEmailNull() {
         prepareMockAndExecuteUpdateUserTest(0);
diff --git a/test/integration/smoke/test_account_access.py 
b/test/integration/smoke/test_account_access.py
new file mode 100644
index 00000000000..97eeced6386
--- /dev/null
+++ b/test/integration/smoke/test_account_access.py
@@ -0,0 +1,198 @@
+# 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.
+""" BVT tests for Account User Access
+"""
+# Import Local Modules
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.utils import *
+from marvin.lib.base import (Account,
+                             User,
+                             Domain)
+from marvin.lib.common import (get_domain)
+from marvin.cloudstackAPI import (getUserKeys)
+from marvin.cloudstackException import CloudstackAPIException
+from nose.plugins.attrib import attr
+
+_multiprocess_shared_ = True
+
+class TestAccountAccess(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestAccountAccess, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.hypervisor = testClient.getHypervisorInfo()
+        cls._cleanup = []
+
+        # Get Zone, Domain and templates
+        cls.domain = get_domain(cls.apiclient)
+
+        cls.domains = []
+        cls.domain_admins = {}
+        cls.domain_users = {}
+        cls.account_users = {}
+
+        domain_data = {
+            "name": "domain_1"
+        }
+        cls.domain_1 = Domain.create(
+            cls.apiclient,
+            domain_data,
+        )
+        cls._cleanup.append(cls.domain_1)
+        cls.domains.append(cls.domain_1)
+        domain_data["name"] = "domain_11"
+        cls.domain_11 = Domain.create(
+            cls.apiclient,
+            domain_data,
+            parentdomainid=cls.domain_1.id
+        )
+        cls._cleanup.append(cls.domain_11)
+        cls.domains.append(cls.domain_11)
+        domain_data["name"] = "domain_12"
+        cls.domain_12 = Domain.create(
+            cls.apiclient,
+            domain_data,
+            parentdomainid=cls.domain_1.id
+        )
+        cls._cleanup.append(cls.domain_12)
+        cls.domains.append(cls.domain_12)
+        domain_data["name"] = "domain_2"
+        cls.domain_2 = Domain.create(
+            cls.apiclient,
+            domain_data,
+        )
+        cls._cleanup.append(cls.domain_2)
+        cls.domains.append(cls.domain_2)
+
+
+        for d in cls.domains:
+            cls.create_domainadmin_and_user(d)
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestAccountAccess, cls).tearDownClass()
+
+    @classmethod
+    def create_account(cls, domain, is_admin):
+        cls.debug(f"Creating account for domain {domain.name}, admin: 
{is_admin}")
+        data = {
+            "email": "admin-" + domain.name + "@test.com",
+            "firstname": "Admin",
+            "lastname": domain.name,
+            "username": "admin-" + domain.name,
+            "password": "password"
+        }
+        if is_admin == False:
+            data["email"] = "user-" + domain.name + "@test.com"
+            data["firstname"] = "User"
+            data["username"] = "user-" + domain.name
+        account = Account.create(
+            cls.apiclient,
+            data,
+            admin=is_admin,
+            domainid=domain.id
+        )
+        cls._cleanup.append(account)
+        if is_admin == True:
+            cls.domain_admins[domain.id] = account
+        else:
+            cls.domain_users[domain.id] = account
+
+        user = User.create(
+            cls.apiclient,
+            data,
+            account=account.name,
+            domainid=account.domainid)
+        cls._cleanup.append(user)
+        cls.account_users[account.id] = user
+
+    @classmethod
+    def create_domainadmin_and_user(cls, domain):
+        cls.debug(f"Creating accounts for domain #{domain.id} {domain.name}")
+        cls.create_account(domain, True)
+        cls.create_account(domain, False)
+
+    def get_user_keys(self, api_client, user_id):
+        getUserKeysCmd = getUserKeys.getUserKeysCmd()
+        getUserKeysCmd.id = user_id
+        return api_client.getUserKeys(getUserKeysCmd)
+
+    def is_child_domain(self, parent_domain, child_domain):
+        if not parent_domain or not child_domain:
+            return False
+        parent_domain_prefix = parent_domain.split('-')[0]
+        child_domain_prefix = child_domain.split('-')[0]
+        if not parent_domain_prefix or not child_domain_prefix:
+            return False
+        return child_domain_prefix.startswith(parent_domain_prefix)
+
+
+    @attr(tags=["advanced", "advancedns", "smoke", "sg"], 
required_hardware="false")
+    def test_01_user_access(self):
+        """
+        Test user account is not accessing any other account
+        """
+
+        domain_user_accounts = [value for value in self.domain_users.values()]
+        all_account_users = [value for value in self.account_users.values()]
+        for user_account in domain_user_accounts:
+            current_account_user = self.account_users[user_account.id]
+            self.debug(f"Check for account {user_account.name} with user 
{current_account_user.username}")
+            user_api_client = self.testClient.getUserApiClient(
+                UserName=user_account.name,
+                DomainName=user_account.domain
+            )
+            for user in all_account_users:
+                self.debug(f"Checking access for user {user.username} 
associated with account {user.account}")
+                try:
+                    self.get_user_keys(user_api_client, user.id)
+                    self.debug(f"API successful")
+                    if user.id != current_account_user.id:
+                        self.fail(f"User account #{user_account.id} was able 
to access another account #{user.id}")
+                except CloudstackAPIException as e:
+                    self.debug(f"Exception occurred: {e}")
+                    if user.id == current_account_user.id:
+                        self.fail(f"User account #{user_account.id} not able 
to access own account")
+
+    @attr(tags=["advanced", "advancedns", "smoke", "sg"], 
required_hardware="false")
+    def test_02_domain_admin_access(self):
+        """
+        Test domain admin account is not accessing any other account from 
unauthorized domain
+        """
+
+        domain_admin_accounts = [value for value in 
self.domain_admins.values()]
+        all_account_users = [value for value in self.account_users.values()]
+        for admin_account in domain_admin_accounts:
+            current_account_user = self.account_users[admin_account.id]
+            self.debug(f"Check for domain admin {admin_account.name} with user 
{current_account_user.username}, {current_account_user.domain}")
+            admin_api_client = self.testClient.getUserApiClient(
+                UserName=admin_account.name,
+                DomainName=admin_account.domain
+            )
+            for user in all_account_users:
+                self.debug(f"Checking access for user {user.username}, 
{user.domain} associated with account {user.account}")
+                try:
+                    self.get_user_keys(admin_api_client, user.id)
+                    self.debug(f"API successful")
+                    if self.is_child_domain(current_account_user.domain, 
user.domain) == False:
+                        self.fail(f"User account #{admin_account.id} was able 
to access another account #{user.id}")
+                except CloudstackAPIException as e:
+                    self.debug(f"Exception occurred: {e}")
+                    if self.is_child_domain(current_account_user.domain, 
user.domain) == True:
+                        self.fail(f"User account #{admin_account.id} not able 
to access own account")
diff --git a/ui/src/views/compute/KubernetesServiceTab.vue 
b/ui/src/views/compute/KubernetesServiceTab.vue
index bdaa2eefde6..9bc80afae08 100644
--- a/ui/src/views/compute/KubernetesServiceTab.vue
+++ b/ui/src/views/compute/KubernetesServiceTab.vue
@@ -402,6 +402,7 @@ export default {
           if (this.arrayHasItems(networks)) {
             this.network = networks[0]
           }
+          resolve(this.network)
         })
         this.networkLoading = false
       })

Reply via email to