diff --git a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index 6d2ec103ca21..0f28b140448b 100644 --- a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -966,7 +966,7 @@ public ResourceLimitVO updateResourceLimit(Long accountId, Long domainId, Intege throw new PermissionDeniedException("Cannot update resource limit for ROOT domain " + domainId + ", permission denied"); } - if ((caller.getDomainId() == domainId) && caller.getType() == Account.Type.DOMAIN_ADMIN || caller.getType() == Account.Type.RESOURCE_DOMAIN_ADMIN) { + if ((caller.getDomainId() == domainId) && (caller.getType() == Account.Type.DOMAIN_ADMIN || caller.getType() == Account.Type.RESOURCE_DOMAIN_ADMIN)) { // if the admin is trying to update their own domain, disallow... throw new PermissionDeniedException("Unable to update resource limit for domain " + domainId + ", permission denied"); } diff --git a/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java b/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java index bdc6620c4904..da6cf79b5585 100644 --- a/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java +++ b/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.TaggedResourceLimitAndCountResponse; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.reservation.dao.ReservationDao; import org.apache.cloudstack.resourcelimit.Reserver; @@ -57,6 +58,7 @@ import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.offering.DiskOffering; import com.cloud.offering.ServiceOffering; @@ -73,8 +75,10 @@ import com.cloud.user.AccountManager; import com.cloud.user.AccountVO; import com.cloud.user.ResourceLimitService; +import com.cloud.user.User; import com.cloud.user.dao.AccountDao; import com.cloud.utils.Pair; +import com.cloud.utils.db.EntityManager; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.UserVmDao; @@ -123,6 +127,8 @@ public class ResourceLimitManagerImplTest extends TestCase { UserVmDao userVmDao; @Mock SnapshotDataStoreDao snapshotDataStoreDao; + @Mock + EntityManager entityManager; private List hostTags = List.of("htag1", "htag2", "htag3"); private List storageTags = List.of("stag1", "stag2"); @@ -1178,4 +1184,46 @@ public void testDecrementVmMemoryResourceCount() { Mockito.verify(resourceLimitManager, Mockito.times(1)) .decrementResourceCountWithTag(accountId, Resource.ResourceType.memory, tag, Long.valueOf(memory)); } + + private Account mockResourceDomainAdmin(long domainId) { + Account resourceDomainAdmin = Mockito.mock(Account.class); + Mockito.when(resourceDomainAdmin.getDomainId()).thenReturn(domainId); + Mockito.when(resourceDomainAdmin.getType()).thenReturn(Account.Type.RESOURCE_DOMAIN_ADMIN); + return resourceDomainAdmin; + } + + @Test + public void updateResourceLimitAllowsAResourceDomainAdminToUpdateASubdomain() { + long ownDomainId = 5L; + long subdomainId = 7L; + Domain subdomain = Mockito.mock(Domain.class); + Mockito.when(subdomain.getParent()).thenReturn(ownDomainId); + Mockito.when(entityManager.findById(Domain.class, subdomainId)).thenReturn(subdomain); + DomainVO ownDomain = Mockito.mock(DomainVO.class); + Mockito.when(domainDao.findById(ownDomainId)).thenReturn(ownDomain); + Mockito.doReturn((long) Resource.RESOURCE_UNLIMITED).when(resourceLimitManager) + .findCorrectResourceLimitForDomain(ownDomain, Resource.ResourceType.user_vm, null); + + CallContext.register(Mockito.mock(User.class), mockResourceDomainAdmin(ownDomainId)); + try { + resourceLimitManager.updateResourceLimit(null, subdomainId, Resource.ResourceType.user_vm.getOrdinal(), 10L, null); + } finally { + CallContext.unregister(); + } + Mockito.verify(resourceLimitDao).persist(Mockito.any(ResourceLimitVO.class)); + } + + @Test + public void updateResourceLimitDeniesAResourceDomainAdminOnTheirOwnDomain() { + long ownDomainId = 5L; + Mockito.when(entityManager.findById(Domain.class, ownDomainId)).thenReturn(Mockito.mock(Domain.class)); + + CallContext.register(Mockito.mock(User.class), mockResourceDomainAdmin(ownDomainId)); + try { + Assert.assertThrows(PermissionDeniedException.class, () -> + resourceLimitManager.updateResourceLimit(null, ownDomainId, Resource.ResourceType.user_vm.getOrdinal(), 10L, null)); + } finally { + CallContext.unregister(); + } + } }