Skip to content

Commit 575fffc

Browse files
authored
Allow root admin to deploy in VPCs in child domains (#6832)
and make root admin permissions configurable
1 parent 6d74815 commit 575fffc

File tree

6 files changed

+230
-201
lines changed

6 files changed

+230
-201
lines changed

api/src/main/java/com/cloud/network/NetworkModel.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,12 @@ public interface NetworkModel {
8989
List<String> metadataFileNames = new ArrayList<>(Arrays.asList(SERVICE_OFFERING_FILE, AVAILABILITY_ZONE_FILE, LOCAL_HOSTNAME_FILE, LOCAL_IPV4_FILE, PUBLIC_HOSTNAME_FILE, PUBLIC_IPV4_FILE,
9090
INSTANCE_ID_FILE, VM_ID_FILE, PUBLIC_KEYS_FILE, CLOUD_IDENTIFIER_FILE, HYPERVISOR_HOST_NAME_FILE));
9191

92-
static final ConfigKey<Integer> MACIdentifier = new ConfigKey<Integer>("Advanced",Integer.class, "mac.identifier", "0",
92+
static final ConfigKey<Integer> MACIdentifier = new ConfigKey<>("Advanced",Integer.class, "mac.identifier", "0",
9393
"This value will be used while generating the mac addresses for isolated and shared networks. The hexadecimal equivalent value will be present at the 2nd octet of the mac address. Default value is null which means this feature is disabled.Its scope is global.", true, ConfigKey.Scope.Global);
9494

95+
static final ConfigKey<Boolean> AdminIsAllowedToDeployAnywhere = new ConfigKey<>("Advanced",Boolean.class, "admin.is.allowed.to.deploy.anywhere", "false",
96+
"This will determine if the root admin is allowed to deploy in networks in subdomains.", true, ConfigKey.Scope.Global);
97+
9598
/**
9699
* Lists IP addresses that belong to VirtualNetwork VLANs
97100
*

server/src/main/java/com/cloud/network/NetworkModelImpl.java

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147

148148
public class NetworkModelImpl extends ManagerBase implements NetworkModel, Configurable {
149149
static final Logger s_logger = Logger.getLogger(NetworkModelImpl.class);
150+
public static final String UNABLE_TO_USE_NETWORK = "Unable to use network with id= %s, permission denied";
150151
@Inject
151152
EntityManager _entityMgr;
152153
@Inject
@@ -1665,39 +1666,49 @@ public void checkCapabilityForProvider(Set<Provider> providers, Service service,
16651666
}
16661667

16671668
@Override
1668-
public void checkNetworkPermissions(Account caller, Network network) {
1669-
// dahn 20140310: I was thinking of making this an assert but
1670-
// as we hardly ever test with asserts I think
1671-
// we better make sure at runtime.
1672-
if (network == null) {
1673-
throw new CloudRuntimeException("cannot check permissions on (Network) <null>");
1674-
}
1675-
// Perform account permission check
1676-
if (network.getGuestType() != GuestType.Shared || network.getAclType() == ACLType.Account) {
1677-
AccountVO networkOwner = _accountDao.findById(network.getAccountId());
1678-
if (networkOwner == null)
1679-
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() +
1680-
", network does not have an owner");
1681-
if (!Account.Type.PROJECT.equals(caller.getType()) && Account.Type.PROJECT.equals(networkOwner.getType())) {
1682-
checkProjectNetworkPermissions(caller, networkOwner, network);
1669+
public final void checkNetworkPermissions(Account caller, Network network) {
1670+
if (_accountMgr.isRootAdmin(caller.getAccountId()) && Boolean.TRUE.equals(AdminIsAllowedToDeployAnywhere.value())) {
1671+
if (s_logger.isDebugEnabled()) {
1672+
s_logger.debug("root admin is permitted to do stuff on every network");
1673+
}
1674+
} else {
1675+
if (network == null) {
1676+
throw new CloudRuntimeException("cannot check permissions on (Network) <null>");
1677+
}
1678+
s_logger.info(String.format("Checking permission for account %s (%s) on network %s (%s)", caller.getAccountName(), caller.getUuid(), network.getName(), network.getUuid()));
1679+
if (network.getGuestType() != GuestType.Shared || network.getAclType() == ACLType.Account) {
1680+
checkAccountNetworkPermissions(caller, network);
1681+
16831682
} else {
1684-
List<NetworkVO> networkMap = _networksDao.listBy(caller.getId(), network.getId());
1685-
NetworkPermissionVO networkPermission = _networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId());
1686-
if (CollectionUtils.isEmpty(networkMap) && networkPermission == null) {
1687-
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() +
1688-
", permission denied");
1689-
}
1683+
checkDomainNetworkPermissions(caller, network);
16901684
}
1685+
}
1686+
}
16911687

1688+
private void checkAccountNetworkPermissions(Account caller, Network network) {
1689+
AccountVO networkOwner = _accountDao.findById(network.getAccountId());
1690+
if (networkOwner == null)
1691+
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO) network).getUuid() +
1692+
", network does not have an owner");
1693+
if (!Account.Type.PROJECT.equals(caller.getType()) && Account.Type.PROJECT.equals(networkOwner.getType())) {
1694+
checkProjectNetworkPermissions(caller, networkOwner, network);
16921695
} else {
1693-
if (!isNetworkAvailableInDomain(network.getId(), caller.getDomainId())) {
1694-
DomainVO callerDomain = _domainDao.findById(caller.getDomainId());
1695-
if (callerDomain == null) {
1696-
throw new CloudRuntimeException("cannot check permission on account " + caller.getAccountName() + " whose domain does not exist");
1697-
}
1698-
throw new PermissionDeniedException("Shared network id=" + ((NetworkVO)network).getUuid() + " is not available in domain id=" +
1699-
callerDomain.getUuid());
1696+
List<NetworkVO> networkMap = _networksDao.listBy(caller.getId(), network.getId());
1697+
NetworkPermissionVO networkPermission = _networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId());
1698+
if (CollectionUtils.isEmpty(networkMap) && networkPermission == null) {
1699+
throw new PermissionDeniedException(String.format(UNABLE_TO_USE_NETWORK, ((NetworkVO) network).getUuid()));
1700+
}
1701+
}
1702+
}
1703+
1704+
private void checkDomainNetworkPermissions(Account caller, Network network) {
1705+
if (!isNetworkAvailableInDomain(network.getId(), caller.getDomainId())) {
1706+
DomainVO callerDomain = _domainDao.findById(caller.getDomainId());
1707+
if (callerDomain == null) {
1708+
throw new CloudRuntimeException("cannot check permission on account " + caller.getAccountName() + " whose domain does not exist");
17001709
}
1710+
throw new PermissionDeniedException("Shared network id=" + ((NetworkVO) network).getUuid() + " is not available in domain id=" +
1711+
callerDomain.getUuid());
17011712
}
17021713
}
17031714

@@ -1710,13 +1721,11 @@ private void checkProjectNetworkPermissions(Account owner, Account networkOwner,
17101721
ProjectAccount projectAccountUser = _projectAccountDao.findByProjectIdUserId(project.getId(), user.getAccountId(), user.getId());
17111722
if (projectAccountUser != null) {
17121723
if (!_projectAccountDao.canUserAccessProjectAccount(user.getAccountId(), user.getId(), networkOwner.getId())) {
1713-
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() +
1714-
", permission denied");
1724+
throw new PermissionDeniedException(String.format(UNABLE_TO_USE_NETWORK, ((NetworkVO)network).getUuid()));
17151725
}
17161726
} else {
17171727
if (!_projectAccountDao.canAccessProjectAccount(owner.getAccountId(), networkOwner.getId())) {
1718-
throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO) network).getUuid() +
1719-
", permission denied");
1728+
throw new PermissionDeniedException(String.format(UNABLE_TO_USE_NETWORK, ((NetworkVO) network).getUuid()));
17201729
}
17211730
}
17221731
}
@@ -2663,7 +2672,7 @@ public String getConfigComponentName() {
26632672

26642673
@Override
26652674
public ConfigKey<?>[] getConfigKeys() {
2666-
return new ConfigKey<?>[] {MACIdentifier};
2675+
return new ConfigKey<?>[] {MACIdentifier, AdminIsAllowedToDeployAnywhere};
26672676
}
26682677

26692678
@Override

server/src/main/java/com/cloud/network/NetworkServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1938,7 +1938,7 @@ public Pair<List<? extends Network>, Integer> searchForNetworks(ListNetworksCmd
19381938
Boolean isSystem = cmd.getIsSystem();
19391939
String aclType = cmd.getAclType();
19401940
Long projectId = cmd.getProjectId();
1941-
List<Long> permittedAccounts = new ArrayList<Long>();
1941+
List<Long> permittedAccounts = new ArrayList<>();
19421942
String path = null;
19431943
Long physicalNetworkId = cmd.getPhysicalNetworkId();
19441944
List<String> supportedServicesStr = cmd.getSupportedServices();

server/src/test/java/com/cloud/network/NetworkModelTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.List;
3434
import java.util.Set;
3535

36+
import com.cloud.user.AccountManager;
3637
import org.apache.cloudstack.network.NetworkPermissionVO;
3738
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
3839
import org.junit.Before;
@@ -114,6 +115,8 @@ public class NetworkModelTest {
114115
private DomainDao domainDao;
115116
@Mock
116117
private ProjectDao projectDao;
118+
@Mock
119+
private AccountManager _accountMgr;
117120

118121
private static final long ZONE_1_ID = 1L;
119122
private static final long ZONE_2_ID = 2L;
@@ -307,6 +310,21 @@ public void testCheckNetworkPermissions() {
307310
networkModel.checkNetworkPermissions(caller, network);
308311
}
309312

313+
@Test
314+
public void testCheckNetworkPermissionsForAdmin() {
315+
long accountId = 1L;
316+
AccountVO caller = mock(AccountVO.class);
317+
when(caller.getId()).thenReturn(accountId);
318+
when(caller.getType()).thenReturn(Account.Type.ADMIN);
319+
NetworkVO network = mock(NetworkVO.class);
320+
when(network.getGuestType()).thenReturn(Network.GuestType.Isolated);
321+
when(network.getAccountId()).thenReturn(accountId);
322+
when(accountDao.findById(accountId)).thenReturn(caller);
323+
when(networkDao.listBy(caller.getId(), network.getId())).thenReturn(List.of(network));
324+
when(networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId())).thenReturn(mock(NetworkPermissionVO.class));
325+
networkModel.checkNetworkPermissions(caller, network);
326+
}
327+
310328
@Test(expected = CloudRuntimeException.class)
311329
public void testCheckNetworkPermissionsNullNetwork() {
312330
AccountVO caller = mock(AccountVO.class);

0 commit comments

Comments
 (0)