diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceApiPermissionsModule.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceApiPermissionsModule.java index daea17d6a5..12749b3e26 100644 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceApiPermissionsModule.java +++ b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceApiPermissionsModule.java @@ -25,17 +25,20 @@ import org.eclipse.che.multiuser.permission.workspace.server.filters.PublicPermi import org.eclipse.che.multiuser.permission.workspace.server.filters.StackDomainSetPermissionsChecker; import org.eclipse.che.multiuser.permission.workspace.server.filters.StackPermissionsFilter; import org.eclipse.che.multiuser.permission.workspace.server.filters.WorkspacePermissionsFilter; +import org.eclipse.che.multiuser.permission.workspace.server.filters.WorkspaceRemoteSubscriptionPermissionFilter; import org.eclipse.che.multiuser.permission.workspace.server.stack.MultiuserStackLoader; import org.eclipse.che.multiuser.permission.workspace.server.stack.StackCreatorPermissionsProvider; import org.eclipse.che.multiuser.permission.workspace.server.stack.StackDomain; /** @author Sergii Leschenko */ public class WorkspaceApiPermissionsModule extends AbstractModule { + @Override protected void configure() { bind(WorkspacePermissionsFilter.class); bind(StackPermissionsFilter.class); bind(InstallerServicePermissionFilter.class).asEagerSingleton(); + bind(WorkspaceRemoteSubscriptionPermissionFilter.class).asEagerSingleton(); bind(WorkspaceCreatorPermissionsProvider.class).asEagerSingleton(); bind(StackCreatorPermissionsProvider.class).asEagerSingleton(); diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilter.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilter.java new file mode 100644 index 0000000000..15976c85fc --- /dev/null +++ b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilter.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.multiuser.permission.workspace.server.filters; + +import static org.eclipse.che.api.workspace.shared.Constants.BOOTSTRAPPER_STATUS_CHANGED_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.INSTALLER_LOG_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.INSTALLER_STATUS_CHANGED_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.MACHINE_LOG_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.MACHINE_STATUS_CHANGED_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.SERVER_STATUS_CHANGED_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_STATUS_CHANGED_METHOD; + +import java.util.Map; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.eclipse.che.api.core.ForbiddenException; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.Subject; +import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionCheck; +import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionManager; +import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; + +/** + * Holds and registers permissions checks for workspaces related events. + * + * @author Sergii Leshchenko + */ +@Singleton +public class WorkspaceRemoteSubscriptionPermissionFilter + implements RemoteSubscriptionPermissionCheck { + + @Inject + public void register(RemoteSubscriptionPermissionManager permissionFilter) { + permissionFilter.registerCheck( + this, + WORKSPACE_STATUS_CHANGED_METHOD, + MACHINE_STATUS_CHANGED_METHOD, + SERVER_STATUS_CHANGED_METHOD, + MACHINE_LOG_METHOD, + INSTALLER_LOG_METHOD, + INSTALLER_STATUS_CHANGED_METHOD, + BOOTSTRAPPER_STATUS_CHANGED_METHOD); + } + + @Override + public void check(String methodName, Map scope) throws ForbiddenException { + String workspaceId = scope.get("workspaceId"); + + if (workspaceId == null) { + throw new ForbiddenException("Workspace id must be specified in scope"); + } + + Subject currentSubject = EnvironmentContext.getCurrent().getSubject(); + if (!currentSubject.hasPermission(WorkspaceDomain.DOMAIN_ID, workspaceId, WorkspaceDomain.RUN) + && !currentSubject.hasPermission( + WorkspaceDomain.DOMAIN_ID, workspaceId, WorkspaceDomain.USE)) { + throw new ForbiddenException( + "The current user doesn't have permissions to listen to the specified workspace events"); + } + } +} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilterTest.java b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilterTest.java new file mode 100644 index 0000000000..720f4e3606 --- /dev/null +++ b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilterTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.multiuser.permission.workspace.server.filters; + +import static org.eclipse.che.api.workspace.shared.Constants.BOOTSTRAPPER_STATUS_CHANGED_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.INSTALLER_LOG_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.INSTALLER_STATUS_CHANGED_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.MACHINE_LOG_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.MACHINE_STATUS_CHANGED_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.SERVER_STATUS_CHANGED_METHOD; +import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_STATUS_CHANGED_METHOD; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import org.eclipse.che.api.core.ForbiddenException; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.Subject; +import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionManager; +import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/** + * Tests {@link WorkspaceRemoteSubscriptionPermissionFilter} + * + * @author Sergii Leshchenko + */ +@Listeners(MockitoTestNGListener.class) +public class WorkspaceRemoteSubscriptionPermissionFilterTest { + + @Mock private RemoteSubscriptionPermissionManager permissionManager; + + @Mock private Subject subject; + + private WorkspaceRemoteSubscriptionPermissionFilter permissionFilter; + + @BeforeMethod + public void setUp() { + EnvironmentContext.getCurrent().setSubject(subject); + permissionFilter = new WorkspaceRemoteSubscriptionPermissionFilter(); + } + + @AfterMethod + public void tearDown() { + EnvironmentContext.reset(); + } + + @Test + public void shouldRegisterItself() { + // when + permissionFilter.register(permissionManager); + + // then + permissionManager.registerCheck( + permissionFilter, + WORKSPACE_STATUS_CHANGED_METHOD, + MACHINE_STATUS_CHANGED_METHOD, + SERVER_STATUS_CHANGED_METHOD, + MACHINE_LOG_METHOD, + INSTALLER_LOG_METHOD, + INSTALLER_STATUS_CHANGED_METHOD, + BOOTSTRAPPER_STATUS_CHANGED_METHOD); + } + + @Test( + expectedExceptions = ForbiddenException.class, + expectedExceptionsMessageRegExp = + "The current user doesn't have permissions to listen to the specified workspace events") + public void shouldThrowExceptionIfUserDoesNotHaveRunNorUsePermissions() throws Exception { + // given + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN)) + .thenReturn(false); + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.USE)) + .thenReturn(false); + + // when + permissionFilter.check("ignored", ImmutableMap.of("workspaceId", "ws123")); + } + + @Test( + expectedExceptions = ForbiddenException.class, + expectedExceptionsMessageRegExp = "Workspace id must be specified in scope") + public void shouldThrowExceptionIfWorkspaceIdIsMissing() throws Exception { + // given + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN)) + .thenReturn(false); + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.USE)) + .thenReturn(false); + + // when + permissionFilter.check("ignored", Collections.emptyMap()); + } + + @Test + public void shouldDoNothingIfUserDoesNotHaveRunPermissions() throws Exception { + // given + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN)) + .thenReturn(true); + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.USE)) + .thenReturn(false); + + // when + permissionFilter.check("ignored", ImmutableMap.of("workspaceId", "ws123")); + } + + @Test + public void shouldDoNothingIfUserDoesNotHaveUsePermissions() throws Exception { + // given + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN)) + .thenReturn(false); + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.USE)) + .thenReturn(true); + + // when + permissionFilter.check("ignored", ImmutableMap.of("workspaceId", "ws123")); + } +}