Skip to content

Commit 5470416

Browse files
authored
server: fix delete resource tag permission (#6634)
Fixes #6623 This PR fixes resource tag deletion behaviour. The permission check should be done only for the tags that are passed in the API call instead of checking for all the tags for the resource.
1 parent 780bb24 commit 5470416

2 files changed

Lines changed: 59 additions & 14 deletions

File tree

server/src/main/java/com/cloud/tags/TaggedResourceManagerImpl.java

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,22 @@ private Pair<Long, Long> getAccountDomain(long resourceId, ResourceObjectType re
165165
return new Pair<>(accountId, domainId);
166166
}
167167

168+
protected void checkTagsDeletePermission(List<ResourceTag> tagsToDelete, Account caller) {
169+
for (ResourceTag resourceTag : tagsToDelete) {
170+
if(s_logger.isDebugEnabled()) {
171+
s_logger.debug("Resource Tag Id: " + resourceTag.getResourceId());
172+
s_logger.debug("Resource Tag AccountId: " + resourceTag.getAccountId());
173+
}
174+
if (caller.getAccountId() != resourceTag.getAccountId()) {
175+
Account owner = _accountMgr.getAccount(resourceTag.getAccountId());
176+
if(s_logger.isDebugEnabled()) {
177+
s_logger.debug("Resource Owner: " + owner);
178+
}
179+
_accountMgr.checkAccess(caller, null, false, owner);
180+
}
181+
}
182+
}
183+
168184
@Override
169185
@DB
170186
@ActionEvent(eventType = EventTypes.EVENT_TAGS_CREATE, eventDescription = "creating resource tags")
@@ -241,17 +257,6 @@ public boolean deleteTags(List<String> resourceIds, ResourceObjectType resourceT
241257

242258
// Finalize which tags should be removed
243259
for (ResourceTag resourceTag : resourceTags) {
244-
//1) validate the permissions
245-
if(s_logger.isDebugEnabled()) {
246-
s_logger.debug("Resource Tag Id: " + resourceTag.getResourceId());
247-
s_logger.debug("Resource Tag AccountId: " + resourceTag.getAccountId());
248-
}
249-
Account owner = _accountMgr.getAccount(resourceTag.getAccountId());
250-
if(s_logger.isDebugEnabled()) {
251-
s_logger.debug("Resource Owner: " + owner);
252-
}
253-
_accountMgr.checkAccess(caller, null, false, owner);
254-
//2) Only remove tag if it matches key value pairs
255260
if (MapUtils.isEmpty(tags)) {
256261
tagsToDelete.add(resourceTag);
257262
} else {
@@ -278,6 +283,7 @@ public boolean deleteTags(List<String> resourceIds, ResourceObjectType resourceT
278283
if (tagsToDelete.isEmpty()) {
279284
return false;
280285
}
286+
checkTagsDeletePermission(tagsToDelete, caller);
281287

282288
//Remove the tags
283289
Transaction.execute(new TransactionCallbackNoReturn() {

server/src/test/java/com/cloud/tags/TaggedResourceManagerImplTest.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,37 @@
1919

2020
package com.cloud.tags;
2121

22-
import com.cloud.server.ResourceTag;
2322
import java.util.ArrayList;
2423
import java.util.Arrays;
2524
import java.util.HashMap;
2625
import java.util.List;
2726
import java.util.Map;
28-
import junit.framework.TestCase;
27+
2928
import org.junit.Assert;
3029
import org.junit.Test;
3130
import org.junit.runner.RunWith;
31+
import org.mockito.InjectMocks;
32+
import org.mockito.Mock;
3233
import org.mockito.Mockito;
3334
import org.mockito.Spy;
3435
import org.mockito.junit.MockitoJUnitRunner;
3536

37+
import com.cloud.exception.PermissionDeniedException;
38+
import com.cloud.server.ResourceTag;
39+
import com.cloud.user.Account;
40+
import com.cloud.user.AccountManager;
41+
42+
import junit.framework.TestCase;
43+
3644
@RunWith(MockitoJUnitRunner.class)
37-
public class TaggedResourceManagerImplTest extends TestCase{
45+
public class TaggedResourceManagerImplTest extends TestCase {
46+
47+
@Mock
48+
AccountManager accountManager;
49+
3850

3951
@Spy
52+
@InjectMocks
4053
private final TaggedResourceManagerImpl taggedResourceManagerImplSpy = new TaggedResourceManagerImpl();
4154

4255
private final List<ResourceTag.ResourceObjectType> listResourceObjectTypes = Arrays.asList(ResourceTag.ResourceObjectType.values());
@@ -84,4 +97,30 @@ public void validateGetTagsFromResourceMustReturnEmpty(){
8497
Assert.assertEquals(expectedResult, result);
8598
});
8699
}
100+
101+
@Test
102+
public void testCheckTagsDeletePermission() {
103+
long accountId = 1L;
104+
Account caller = Mockito.mock(Account.class);
105+
Mockito.when(caller.getAccountId()).thenReturn(accountId);
106+
ResourceTag resourceTag = Mockito.mock(ResourceTag.class);
107+
Mockito.when(resourceTag.getAccountId()).thenReturn(accountId);
108+
taggedResourceManagerImplSpy.checkTagsDeletePermission(List.of(resourceTag), caller);
109+
}
110+
111+
@Test(expected = PermissionDeniedException.class)
112+
public void testCheckTagsDeletePermissionFail() {
113+
long callerAccountId = 1L;
114+
long ownerAccountId = 2L;
115+
Account caller = Mockito.mock(Account.class);
116+
Mockito.when(caller.getAccountId()).thenReturn(callerAccountId);
117+
ResourceTag resourceTag1 = Mockito.mock(ResourceTag.class);
118+
Mockito.when(resourceTag1.getAccountId()).thenReturn(callerAccountId);
119+
ResourceTag resourceTag2 = Mockito.mock(ResourceTag.class);
120+
Mockito.when(resourceTag2.getAccountId()).thenReturn(ownerAccountId);
121+
Account owner = Mockito.mock(Account.class);
122+
Mockito.when(accountManager.getAccount(ownerAccountId)).thenReturn(owner);
123+
Mockito.doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(caller, null, false, owner);
124+
taggedResourceManagerImplSpy.checkTagsDeletePermission(List.of(resourceTag1, resourceTag2), caller);
125+
}
87126
}

0 commit comments

Comments
 (0)