vpc,network: fix createLoadBalancer access on user network (#6591)

While checking network access for creating load-balancer use AccessType.OperateEntry
Refactor variable name in NetworkModelImpl::checkNetworkPermissions

Fixes: #6590

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
index 66d79cc..c601c13 100644
--- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
@@ -1659,7 +1659,7 @@
     }
 
     @Override
-    public void checkNetworkPermissions(Account owner, Network network) {
+    public void checkNetworkPermissions(Account caller, Network network) {
         // dahn 20140310: I was thinking of making this an assert but
         //                as we hardly ever test with asserts I think
         //                we better make sure at runtime.
@@ -1672,11 +1672,11 @@
             if (networkOwner == null)
                 throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() +
                     ", network does not have an owner");
-            if (owner.getType() != Account.Type.PROJECT && networkOwner.getType() == Account.Type.PROJECT) {
-                checkProjectNetworkPermissions(owner, networkOwner, network);
+            if (!Account.Type.PROJECT.equals(caller.getType()) && Account.Type.PROJECT.equals(networkOwner.getType())) {
+                checkProjectNetworkPermissions(caller, networkOwner, network);
             } else {
-                List<NetworkVO> networkMap = _networksDao.listBy(owner.getId(), network.getId());
-                NetworkPermissionVO networkPermission = _networkPermissionDao.findByNetworkAndAccount(network.getId(), owner.getId());
+                List<NetworkVO> networkMap = _networksDao.listBy(caller.getId(), network.getId());
+                NetworkPermissionVO networkPermission = _networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId());
                 if (CollectionUtils.isEmpty(networkMap) && networkPermission == null) {
                     throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() +
                         ", permission denied");
@@ -1684,13 +1684,13 @@
             }
 
         } else {
-            if (!isNetworkAvailableInDomain(network.getId(), owner.getDomainId())) {
-                DomainVO ownerDomain = _domainDao.findById(owner.getDomainId());
-                if (ownerDomain == null) {
-                    throw new CloudRuntimeException("cannot check permission on account " + owner.getAccountName() + " whose domain does not exist");
+            if (!isNetworkAvailableInDomain(network.getId(), caller.getDomainId())) {
+                DomainVO callerDomain = _domainDao.findById(caller.getDomainId());
+                if (callerDomain == null) {
+                    throw new CloudRuntimeException("cannot check permission on account " + caller.getAccountName() + " whose domain does not exist");
                 }
                 throw new PermissionDeniedException("Shared network id=" + ((NetworkVO)network).getUuid() + " is not available in domain id=" +
-                        ownerDomain.getUuid());
+                        callerDomain.getUuid());
             }
         }
     }
diff --git a/server/src/main/java/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java b/server/src/main/java/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java
index 1c9af7a..d9f1db6 100644
--- a/server/src/main/java/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java
@@ -113,7 +113,7 @@
         }
 
         Account caller = CallContext.current().getCallingAccount();
-        _accountMgr.checkAccess(caller, AccessType.UseEntry, false, guestNtwk);
+        _accountMgr.checkAccess(caller, AccessType.OperateEntry, false, guestNtwk);
 
         Network sourceIpNtwk = _networkModel.getNetwork(sourceIpNetworkId);
         if (sourceIpNtwk == null) {
diff --git a/server/src/test/java/com/cloud/network/NetworkModelTest.java b/server/src/test/java/com/cloud/network/NetworkModelTest.java
index af14cbd..b523350 100644
--- a/server/src/test/java/com/cloud/network/NetworkModelTest.java
+++ b/server/src/test/java/com/cloud/network/NetworkModelTest.java
@@ -31,35 +31,50 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
-import com.cloud.dc.DataCenter;
-import com.cloud.dc.DataCenterVO;
-import com.cloud.dc.dao.DataCenterDao;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.network.dao.PhysicalNetworkDao;
-import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
-import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;
-import com.cloud.network.dao.PhysicalNetworkVO;
-import junit.framework.Assert;
-
+import org.apache.cloudstack.network.NetworkPermissionVO;
+import org.apache.cloudstack.network.dao.NetworkPermissionDao;
 import org.junit.Before;
 import org.junit.Test;
-
-import com.cloud.dc.VlanVO;
-import com.cloud.dc.dao.VlanDao;
-import com.cloud.network.dao.IPAddressDao;
-import com.cloud.network.dao.IPAddressVO;
-import com.cloud.user.Account;
-import com.cloud.utils.db.Filter;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
-import com.cloud.utils.net.Ip;
-import com.cloud.network.Network.Provider;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
 
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.domain.DomainVO;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.network.Network.Provider;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkDomainDao;
+import com.cloud.network.dao.NetworkDomainVO;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;
+import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.projects.dao.ProjectDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountVO;
+import com.cloud.user.DomainManager;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.Ip;
+
+import junit.framework.Assert;
+
 public class NetworkModelTest {
 
     @Mock
@@ -85,6 +100,20 @@
     private PhysicalNetworkVO physicalNetworkZone2;
     @Mock
     private PhysicalNetworkServiceProviderVO providerVO;
+    @Mock
+    private AccountDao accountDao;
+    @Mock
+    private NetworkDao networkDao;
+    @Mock
+    private NetworkPermissionDao networkPermissionDao;
+    @Mock
+    private NetworkDomainDao networkDomainDao;
+    @Mock
+    private DomainManager domainManager;
+    @Mock
+    private DomainDao domainDao;
+    @Mock
+    private ProjectDao projectDao;
 
     private static final long ZONE_1_ID = 1L;
     private static final long ZONE_2_ID = 2L;
@@ -263,4 +292,116 @@
         networkModel.checkIp6Parameters(null, null, IPV6_GATEWAY,IPV6_CIDR);
     }
 
+    @Test
+    public void testCheckNetworkPermissions() {
+        long accountId = 1L;
+        AccountVO caller = mock(AccountVO.class);
+        when(caller.getId()).thenReturn(accountId);
+        when(caller.getType()).thenReturn(Account.Type.NORMAL);
+        NetworkVO network = mock(NetworkVO.class);
+        when(network.getGuestType()).thenReturn(Network.GuestType.Isolated);
+        when(network.getAccountId()).thenReturn(accountId);
+        when(accountDao.findById(accountId)).thenReturn(caller);
+        when(networkDao.listBy(caller.getId(), network.getId())).thenReturn(List.of(network));
+        when(networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId())).thenReturn(mock(NetworkPermissionVO.class));
+        networkModel.checkNetworkPermissions(caller, network);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testCheckNetworkPermissionsNullNetwork() {
+        AccountVO caller = mock(AccountVO.class);
+        NetworkVO network = null;
+        networkModel.checkNetworkPermissions(caller, network);
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void testCheckNetworkPermissionsNoOwner() {
+        long accountId = 1L;
+        AccountVO caller = mock(AccountVO.class);
+        when(caller.getId()).thenReturn(accountId);
+        when(caller.getType()).thenReturn(Account.Type.NORMAL);
+        NetworkVO network = mock(NetworkVO.class);
+        when(network.getGuestType()).thenReturn(Network.GuestType.Isolated);
+        when(network.getAccountId()).thenReturn(accountId);
+        when(accountDao.findById(accountId)).thenReturn(null);
+        networkModel.checkNetworkPermissions(caller, network);
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void testCheckNetworkPermissionsNoPermission() {
+        long accountId = 1L;
+        AccountVO caller = mock(AccountVO.class);
+        when(caller.getId()).thenReturn(accountId);
+        when(caller.getType()).thenReturn(Account.Type.NORMAL);
+        NetworkVO network = mock(NetworkVO.class);
+        when(network.getGuestType()).thenReturn(Network.GuestType.Isolated);
+        when(network.getAccountId()).thenReturn(accountId);
+        when(accountDao.findById(accountId)).thenReturn(caller);
+        when(networkDao.listBy(caller.getId(), network.getId())).thenReturn(null);
+        when(networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId())).thenReturn(null);
+        networkModel.checkNetworkPermissions(caller, network);
+    }
+
+    @Test
+    public void testCheckNetworkPermissionsSharedNetwork() {
+        long id = 1L;
+        long subDomainId = 2L;
+        AccountVO caller = mock(AccountVO.class);
+        when(caller.getId()).thenReturn(id);
+        when(caller.getDomainId()).thenReturn(id);
+        when(caller.getType()).thenReturn(Account.Type.NORMAL);
+        NetworkVO network = mock(NetworkVO.class);
+        when(network.getGuestType()).thenReturn(Network.GuestType.Shared);
+        when(network.getId()).thenReturn(id);
+        when(networkDao.findById(network.getId())).thenReturn(network);
+        NetworkDomainVO networkDomainVO = mock(NetworkDomainVO.class);
+        when(networkDomainVO.getDomainId()).thenReturn(id);
+        when(networkDomainDao.getDomainNetworkMapByNetworkId(id)).thenReturn(networkDomainVO);
+        networkModel.checkNetworkPermissions(caller, network);
+        when(caller.getDomainId()).thenReturn(subDomainId);
+        networkDomainVO.subdomainAccess = Boolean.TRUE;
+        when(domainManager.getDomainParentIds(subDomainId)).thenReturn(Set.of(id));
+        networkModel.checkNetworkPermissions(caller, network);
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void testCheckNetworkPermissionsSharedNetworkNoSubDomainAccess() {
+        long id = 1L;
+        long subDomainId = 2L;
+        AccountVO caller = mock(AccountVO.class);
+        when(caller.getId()).thenReturn(id);
+        when(caller.getDomainId()).thenReturn(subDomainId);
+        when(caller.getType()).thenReturn(Account.Type.NORMAL);
+        NetworkVO network = mock(NetworkVO.class);
+        when(network.getGuestType()).thenReturn(Network.GuestType.Shared);
+        when(network.getId()).thenReturn(id);
+        when(networkDao.findById(network.getId())).thenReturn(network);
+        when(domainDao.findById(caller.getDomainId())).thenReturn(mock(DomainVO.class));
+        NetworkDomainVO networkDomainVO = mock(NetworkDomainVO.class);
+        when(networkDomainVO.getDomainId()).thenReturn(id);
+        networkDomainVO.subdomainAccess = Boolean.FALSE;
+        when(networkDomainDao.getDomainNetworkMapByNetworkId(id)).thenReturn(networkDomainVO);
+        networkModel.checkNetworkPermissions(caller, network);
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void testCheckNetworkPermissionsSharedNetworkNotSubDomain() {
+        long id = 1L;
+        long subDomainId = 2L;
+        AccountVO caller = mock(AccountVO.class);
+        when(caller.getId()).thenReturn(id);
+        when(caller.getDomainId()).thenReturn(subDomainId);
+        when(caller.getType()).thenReturn(Account.Type.NORMAL);
+        NetworkVO network = mock(NetworkVO.class);
+        when(network.getGuestType()).thenReturn(Network.GuestType.Shared);
+        when(network.getId()).thenReturn(id);
+        when(networkDao.findById(network.getId())).thenReturn(network);
+        when(domainDao.findById(caller.getDomainId())).thenReturn(mock(DomainVO.class));
+        NetworkDomainVO networkDomainVO = mock(NetworkDomainVO.class);
+        when(networkDomainVO.getDomainId()).thenReturn(id);
+        networkDomainVO.subdomainAccess = Boolean.TRUE;
+        when(networkDomainDao.getDomainNetworkMapByNetworkId(id)).thenReturn(networkDomainVO);
+        when(domainManager.getDomainParentIds(subDomainId)).thenReturn(Set.of(0L));
+        networkModel.checkNetworkPermissions(caller, network);
+    }
 }