Skip to content

Commit b7959d9

Browse files
bernardodemarcoGlover, Rene (rg9975)
authored andcommitted
Clean up network permissions on account deletion (apache#10176)
1 parent ab543de commit b7959d9

File tree

5 files changed

+61
-11
lines changed

5 files changed

+61
-11
lines changed

engine/schema/src/main/java/org/apache/cloudstack/network/dao/NetworkPermissionDao.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ public interface NetworkPermissionDao extends GenericDao<NetworkPermissionVO, Lo
4040
*/
4141
void removeAllPermissions(long networkId);
4242

43+
/**
44+
* Removes all network permissions associated with a given account.
45+
*
46+
* @param accountId The ID of the account from which all network permissions will be removed.
47+
*/
48+
void removeAccountPermissions(long accountId);
49+
4350
/**
4451
* Find a Network permission by networkId, accountName, and domainId
4552
*

engine/schema/src/main/java/org/apache/cloudstack/network/dao/NetworkPermissionDaoImpl.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class NetworkPermissionDaoImpl extends GenericDaoBase<NetworkPermissionVO
3535

3636
private SearchBuilder<NetworkPermissionVO> NetworkAndAccountSearch;
3737
private SearchBuilder<NetworkPermissionVO> NetworkIdSearch;
38+
private SearchBuilder<NetworkPermissionVO> accountSearch;
3839
private GenericSearchBuilder<NetworkPermissionVO, Long> FindNetworkIdsByAccount;
3940

4041
protected NetworkPermissionDaoImpl() {
@@ -47,6 +48,10 @@ protected NetworkPermissionDaoImpl() {
4748
NetworkIdSearch.and("networkId", NetworkIdSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
4849
NetworkIdSearch.done();
4950

51+
accountSearch = createSearchBuilder();
52+
accountSearch.and("accountId", accountSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
53+
accountSearch.done();
54+
5055
FindNetworkIdsByAccount = createSearchBuilder(Long.class);
5156
FindNetworkIdsByAccount.select(null, SearchCriteria.Func.DISTINCT, FindNetworkIdsByAccount.entity().getNetworkId());
5257
FindNetworkIdsByAccount.and("account", FindNetworkIdsByAccount.entity().getAccountId(), SearchCriteria.Op.IN);
@@ -71,6 +76,16 @@ public void removeAllPermissions(long networkId) {
7176
expunge(sc);
7277
}
7378

79+
@Override
80+
public void removeAccountPermissions(long accountId) {
81+
SearchCriteria<NetworkPermissionVO> sc = accountSearch.create();
82+
sc.setParameters("accountId", accountId);
83+
int networkPermissionRemoved = expunge(sc);
84+
if (networkPermissionRemoved > 0) {
85+
s_logger.debug(String.format("Removed [%s] network permission(s) for the account with Id [%s]", networkPermissionRemoved, accountId));
86+
}
87+
}
88+
7489
@Override
7590
public NetworkPermissionVO findByNetworkAndAccount(long networkId, long accountId) {
7691
SearchCriteria<NetworkPermissionVO> sc = NetworkAndAccountSearch.create();

server/src/main/java/com/cloud/user/AccountManagerImpl.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import org.apache.cloudstack.framework.messagebus.MessageBus;
7575
import org.apache.cloudstack.framework.messagebus.PublishScope;
7676
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
77+
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
7778
import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
7879
import org.apache.cloudstack.resourcedetail.UserDetailVO;
7980
import org.apache.cloudstack.resourcedetail.dao.UserDetailsDao;
@@ -298,6 +299,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
298299
private SSHKeyPairDao _sshKeyPairDao;
299300
@Inject
300301
private UserDataDao userDataDao;
302+
@Inject
303+
private NetworkPermissionDao networkPermissionDao;
301304

302305
private List<QuerySelector> _querySelectors;
303306

@@ -870,6 +873,9 @@ protected boolean cleanupAccount(AccountVO account, long callerUserId, Account c
870873
// delete the account from project accounts
871874
_projectAccountDao.removeAccountFromProjects(accountId);
872875

876+
// Delete account's network permissions
877+
networkPermissionDao.removeAccountPermissions(accountId);
878+
873879
if (account.getType() != Account.Type.PROJECT) {
874880
// delete the account from group
875881
_messageBus.publish(_name, MESSAGE_REMOVE_ACCOUNT_EVENT, PublishScope.LOCAL, accountId);
@@ -1857,26 +1863,27 @@ public boolean deleteUserAccount(long accountId) {
18571863
// If the user is a System user, return an error. We do not allow this
18581864
AccountVO account = _accountDao.findById(accountId);
18591865

1860-
if (! isDeleteNeeded(account, accountId, caller)) {
1866+
if (!isDeleteNeeded(account, accountId, caller)) {
18611867
return true;
18621868
}
18631869

1864-
// Account that manages project(s) can't be removed
1865-
List<Long> managedProjectIds = _projectAccountDao.listAdministratedProjectIds(accountId);
1866-
if (!managedProjectIds.isEmpty()) {
1867-
StringBuilder projectIds = new StringBuilder();
1868-
for (Long projectId : managedProjectIds) {
1869-
projectIds.append(projectId).append(", ");
1870-
}
1871-
1872-
throw new InvalidParameterValueException("The account id=" + accountId + " manages project(s) with ids " + projectIds + "and can't be removed");
1873-
}
1870+
checkIfAccountManagesProjects(accountId);
18741871

18751872
CallContext.current().putContextParameter(Account.class, account.getUuid());
18761873

18771874
return deleteAccount(account, callerUserId, caller);
18781875
}
18791876

1877+
protected void checkIfAccountManagesProjects(long accountId) {
1878+
List<Long> managedProjectIds = _projectAccountDao.listAdministratedProjectIds(accountId);
1879+
if (!CollectionUtils.isEmpty(managedProjectIds)) {
1880+
throw new InvalidParameterValueException(String.format(
1881+
"Unable to delete account [%s], because it manages the following project(s): %s. Please, remove the account from these projects or demote it to a regular project role first.",
1882+
accountId, managedProjectIds
1883+
));
1884+
}
1885+
}
1886+
18801887
private boolean isDeleteNeeded(AccountVO account, long accountId, Account caller) {
18811888
if (account == null) {
18821889
s_logger.info(String.format("The account, identified by id %d, doesn't exist", accountId ));

server/src/test/java/com/cloud/user/AccountManagerImplTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,4 +1200,22 @@ public void testValidateRoleAdminCannotEscalateAdminFromNonRootDomain() {
12001200
Mockito.when(roleService.findRole(2L)).thenReturn(callerRole);
12011201
accountManagerImpl.validateRoleChange(account, newRole, caller);
12021202
}
1203+
1204+
@Test
1205+
public void checkIfAccountManagesProjectsTestNotThrowExceptionWhenTheAccountIsNotAProjectAdministrator() {
1206+
long accountId = 1L;
1207+
List<Long> managedProjectIds = new ArrayList<>();
1208+
1209+
Mockito.when(_projectAccountDao.listAdministratedProjectIds(accountId)).thenReturn(managedProjectIds);
1210+
accountManagerImpl.checkIfAccountManagesProjects(accountId);
1211+
}
1212+
1213+
@Test(expected = InvalidParameterValueException.class)
1214+
public void checkIfAccountManagesProjectsTestThrowExceptionWhenTheAccountIsAProjectAdministrator() {
1215+
long accountId = 1L;
1216+
List<Long> managedProjectIds = List.of(1L);
1217+
1218+
Mockito.when(_projectAccountDao.listAdministratedProjectIds(accountId)).thenReturn(managedProjectIds);
1219+
accountManagerImpl.checkIfAccountManagesProjects(accountId);
1220+
}
12031221
}

server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import org.apache.cloudstack.engine.service.api.OrchestrationService;
6666
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
6767
import org.apache.cloudstack.framework.messagebus.MessageBus;
68+
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
6869
import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
6970
import org.apache.cloudstack.resourcedetail.dao.UserDetailsDao;
7071
import org.junit.After;
@@ -195,6 +196,8 @@ public class AccountManagetImplTestBase {
195196
SSHKeyPairDao _sshKeyPairDao;
196197
@Mock
197198
UserDataDao userDataDao;
199+
@Mock
200+
NetworkPermissionDao networkPermissionDaoMock;
198201

199202
@Spy
200203
@InjectMocks

0 commit comments

Comments
 (0)