Skip to content

Commit 70131be

Browse files
lucas-a-martinsLucas Martinsbernardodemarco
authored
Fix deleteAccount API to prevent deletion of the caller (#8743)
* Fix API deleteAccount deleting caller's account * Remove extra line * Add unit tests and change message * apply suggestion Co-authored-by: Bernardo De Marco Gonçalves <bernardomg2004@gmail.com> * remove extra parentheses Co-authored-by: Bernardo De Marco Gonçalves <bernardomg2004@gmail.com> * Update server/src/test/java/com/cloud/user/AccountManagerImplTest.java Co-authored-by: Bernardo De Marco Gonçalves <bernardomg2004@gmail.com> --------- Co-authored-by: Lucas Martins <lucas.martins@scclouds.com.br> Co-authored-by: Bernardo De Marco Gonçalves <bernardomg2004@gmail.com>
1 parent ede39d8 commit 70131be

3 files changed

Lines changed: 45 additions & 6 deletions

File tree

api/src/main/java/org/apache/cloudstack/api/command/admin/account/DeleteAccountCmd.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,11 @@ public void execute() {
8989
CallContext.current().setEventDetails("Account ID: " + (account != null ? account.getUuid() : getId())); // Account not found is already handled by service
9090

9191
boolean result = _regionService.deleteUserAccount(this);
92-
if (result) {
93-
SuccessResponse response = new SuccessResponse(getCommandName());
94-
setResponseObject(response);
95-
} else {
92+
if (!result) {
9693
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete user account and all corresponding users");
9794
}
95+
SuccessResponse response = new SuccessResponse(getCommandName());
96+
setResponseObject(response);
9897
}
9998

10099
@Override

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,7 +1842,14 @@ public boolean deleteUserAccount(long accountId) {
18421842
// If the user is a System user, return an error. We do not allow this
18431843
AccountVO account = _accountDao.findById(accountId);
18441844

1845-
if (! isDeleteNeeded(account, accountId, caller)) {
1845+
if (caller.getId() == accountId) {
1846+
Domain domain = _domainDao.findById(account.getDomainId());
1847+
throw new InvalidParameterValueException(String.format("Deletion of your own account is not allowed. To delete account %s (ID: %s, Domain: %s), " +
1848+
"request to another user with permissions to perform the operation.",
1849+
account.getAccountName(), account.getUuid(), domain.getUuid()));
1850+
}
1851+
1852+
if (!isDeleteNeeded(account, accountId, caller)) {
18461853
return true;
18471854
}
18481855

@@ -1862,7 +1869,7 @@ public boolean deleteUserAccount(long accountId) {
18621869
return deleteAccount(account, callerUserId, caller);
18631870
}
18641871

1865-
private boolean isDeleteNeeded(AccountVO account, long accountId, Account caller) {
1872+
protected boolean isDeleteNeeded(AccountVO account, long accountId, Account caller) {
18661873
if (account == null) {
18671874
logger.info(String.format("The account, identified by id %d, doesn't exist", accountId ));
18681875
return false;

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,39 @@ public void deleteUserAccountCleanup() {
206206
Mockito.verify(_accountDao, Mockito.atLeastOnce()).markForCleanup(Mockito.eq(42l));
207207
}
208208

209+
@Test (expected = InvalidParameterValueException.class)
210+
public void deleteUserAccountTestIfAccountIdIsEqualToCallerIdShouldThrowException() {
211+
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
212+
CallContext callContextMock = Mockito.mock(CallContext.class);
213+
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
214+
long accountId = 1L;
215+
216+
Mockito.doReturn(accountVoMock).when(callContextMock).getCallingAccount();
217+
Mockito.doReturn(accountVoMock).when(_accountDao).findById(Mockito.anyLong());
218+
Mockito.doReturn(domainVoMock).when(_domainDao).findById(Mockito.anyLong());
219+
Mockito.doReturn(1L).when(accountVoMock).getId();
220+
221+
accountManagerImpl.deleteUserAccount(accountId);
222+
}
223+
}
224+
225+
@Test
226+
public void deleteUserAccountTestIfAccountIdIsNotEqualToCallerAccountIdShouldNotThrowException() {
227+
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
228+
CallContext callContextMock = Mockito.mock(CallContext.class);
229+
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
230+
long accountId = 1L;
231+
232+
Mockito.doReturn(accountVoMock).when(callContextMock).getCallingAccount();
233+
Mockito.doReturn(accountVoMock).when(_accountDao).findById(Mockito.anyLong());
234+
Mockito.doReturn(2L).when(accountVoMock).getId();
235+
Mockito.doReturn(true).when(accountManagerImpl).isDeleteNeeded(Mockito.any(), Mockito.anyLong(), Mockito.any());
236+
Mockito.doReturn(new ArrayList<Long>()).when(_projectAccountDao).listAdministratedProjectIds(Mockito.anyLong());
237+
238+
accountManagerImpl.deleteUserAccount(accountId);
239+
}
240+
}
241+
209242
@Test (expected = InvalidParameterValueException.class)
210243
public void deleteUserTestIfUserIdIsEqualToCallerIdShouldThrowException() {
211244
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {

0 commit comments

Comments
 (0)