diff --git a/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImpl.java b/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImpl.java index f66c195399d..4171b9615fe 100644 --- a/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImpl.java +++ b/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImpl.java @@ -129,6 +129,7 @@ import com.cloud.org.Cluster; import com.cloud.serializer.GsonHelper; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.user.Account; +import com.cloud.user.AccountService; import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.PluggableService; @@ -212,6 +213,9 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana @Inject RoleService roleService; + @Inject + AccountService accountService; + private ScheduledExecutorService extensionPathStateCheckExecutor; protected String getDefaultExtensionRelativePath(String name) { @@ -1354,6 +1358,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana clusterId = host.getClusterId(); } else if (entity instanceof VirtualMachine) { VirtualMachine virtualMachine = (VirtualMachine)entity; + accountService.checkAccess(caller, null, true, virtualMachine); if (!Hypervisor.HypervisorType.External.equals(virtualMachine.getHypervisorType())) { logger.error("Invalid {} specified as VM resource for running {}", entity, customActionVO); throw new InvalidParameterValueException(error); diff --git a/framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java b/framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java index bee597550a0..085ae212b28 100644 --- a/framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java +++ b/framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java @@ -49,6 +49,8 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.user.AccountService; import org.apache.cloudstack.acl.Role; import org.apache.cloudstack.acl.RoleService; import org.apache.cloudstack.acl.RoleType; @@ -176,6 +178,8 @@ public class ExtensionsManagerImplTest { private VMTemplateDao templateDao; @Mock private RoleService roleService; + @Mock + private AccountService accountService; @Before public void setUp() { @@ -1640,6 +1644,35 @@ public class ExtensionsManagerImplTest { } } + @Test(expected = PermissionDeniedException.class) + public void runCustomAction_CheckAccessThrowsException() throws Exception { + RunCustomActionCmd cmd = mock(RunCustomActionCmd.class); + when(cmd.getCustomActionId()).thenReturn(1L); + when(cmd.getResourceId()).thenReturn("vm-123"); + when(cmd.getParameters()).thenReturn(Map.of("param1", "value1")); + + ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class); + when(extensionCustomActionDao.findById(1L)).thenReturn(actionVO); + when(actionVO.isEnabled()).thenReturn(true); + when(actionVO.getResourceType()).thenReturn(ExtensionCustomAction.ResourceType.VirtualMachine); + when(actionVO.getAllowedRoleTypes()).thenReturn(RoleType.toCombinedMask(List.of(RoleType.Admin, RoleType.DomainAdmin, RoleType.User))); + + ExtensionVO extensionVO = mock(ExtensionVO.class); + when(extensionDao.findById(anyLong())).thenReturn(extensionVO); + when(extensionVO.getState()).thenReturn(Extension.State.Enabled); + + VirtualMachine vm = mock(VirtualMachine.class); + when(entityManager.findByUuid(eq(VirtualMachine.class), anyString())).thenReturn(vm); + doThrow(PermissionDeniedException.class).when(accountService).checkAccess(any(Account.class), eq(null), eq(true), eq(vm)); + + try (MockedStatic ignored = mockStatic(CallContext.class)) { + mockCallerRole(RoleType.User); + CustomActionResultResponse result = extensionsManager.runCustomAction(cmd); + + assertFalse(result.getSuccess()); + } + } + @Test public void createCustomActionResponse_SetsBasicFields() { ExtensionCustomAction action = mock(ExtensionCustomAction.class);