diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml index 4c6fd9bd8227..3449e3a63d8a 100644 --- a/assembly/assembly-wsmaster-war/pom.xml +++ b/assembly/assembly-wsmaster-war/pom.xml @@ -281,6 +281,10 @@ org.eclipse.che.multiuser che-multiuser-permission-factory + + org.eclipse.che.multiuser + che-multiuser-permission-infra-kubernetes + org.eclipse.che.multiuser che-multiuser-permission-installer diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 49ff8078d422..a610086116b0 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -305,7 +305,9 @@ private void configureMultiUserMode( if (OpenShiftInfrastructure.NAME.equals(infrastructure) || KubernetesInfrastructure.NAME.equals(infrastructure)) { install(new ReplicationModule(persistenceProperties)); - + bind( + org.eclipse.che.multiuser.permission.workspace.infra.kubernetes + .BrokerServicePermissionFilter.class); configureJwtProxySecureProvisioner(infrastructure); } else { bind(RemoteSubscriptionStorage.class) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/events/BrokerService.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/events/BrokerService.java index 2de7d0d9df5e..9f0dd6da3f93 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/events/BrokerService.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/events/BrokerService.java @@ -42,6 +42,9 @@ public class BrokerService { private static final Logger LOG = getLogger(BrokerService.class); + public static final String BROKER_RESULT_METHOD = "broker/result"; + public static final String BROKER_STATUS_CHANGED_METHOD = "broker/statusChanged"; + private final ObjectMapper objectMapper = new ObjectMapper(); private final EventService eventService; @@ -54,14 +57,14 @@ public BrokerService(EventService eventService) { public void configureMethods(RequestHandlerConfigurator requestHandler) { requestHandler .newConfiguration() - .methodName("broker/statusChanged") + .methodName(BROKER_STATUS_CHANGED_METHOD) .paramsAsDto(BrokerResultEvent.class) .noResult() .withConsumer(this::handle); requestHandler .newConfiguration() - .methodName("broker/result") + .methodName(BROKER_RESULT_METHOD) .paramsAsDto(BrokerResultEvent.class) .noResult() .withConsumer(this::handle); diff --git a/multiuser/permission/che-multiuser-permission-infra-kubernetes/pom.xml b/multiuser/permission/che-multiuser-permission-infra-kubernetes/pom.xml new file mode 100644 index 000000000000..04b975979bed --- /dev/null +++ b/multiuser/permission/che-multiuser-permission-infra-kubernetes/pom.xml @@ -0,0 +1,75 @@ + + + + 4.0.0 + + che-multiuser-permission + org.eclipse.che.multiuser + 6.11.0-SNAPSHOT + + che-multiuser-permission-infra-kubernetes + Che Multiuser :: Kubernetes Infrastructure Permissions + + + javax.inject + javax.inject + + + org.eclipse.che.core + che-core-api-core + + + org.eclipse.che.core + che-core-api-workspace-shared + + + org.eclipse.che.infrastructure + infrastructure-kubernetes + + + org.eclipse.che.multiuser + che-multiuser-api-permission + + + org.eclipse.che.multiuser + che-multiuser-permission-workspace + + + ch.qos.logback + logback-classic + test + + + org.eclipse.che.core + che-core-api-dto + test + + + org.mockito + mockito-core + test + + + org.mockitong + mockitong + test + + + org.testng + testng + test + + + diff --git a/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/main/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilter.java b/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/main/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilter.java new file mode 100644 index 000000000000..36cb3e90a2d9 --- /dev/null +++ b/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/main/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilter.java @@ -0,0 +1,60 @@ +/* + * 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.infra.kubernetes; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService.BROKER_RESULT_METHOD; +import static org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService.BROKER_STATUS_CHANGED_METHOD; + +import javax.inject.Inject; +import javax.inject.Singleton; +import org.eclipse.che.api.core.ForbiddenException; +import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerManager; +import org.eclipse.che.api.workspace.shared.dto.BrokerResultEvent; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.Subject; +import org.eclipse.che.multiuser.api.permission.server.jsonrpc.JsonRpcPermissionsFilterAdapter; +import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService; + +/** + * Add permissions checking before {@link BrokerService} methods invocation. + * + * @author Sergii Leshchenko + */ +@Singleton +public class BrokerServicePermissionFilter extends JsonRpcPermissionsFilterAdapter { + @Inject + public void register(RequestHandlerManager requestHandlerManager) { + requestHandlerManager.registerMethodInvokerFilter( + this, BROKER_STATUS_CHANGED_METHOD, BROKER_RESULT_METHOD); + } + + @Override + public void doAccept(String method, Object... params) throws ForbiddenException { + String workspaceId; + switch (method) { + case BROKER_STATUS_CHANGED_METHOD: + case BROKER_RESULT_METHOD: + workspaceId = ((BrokerResultEvent) params[0]).getWorkspaceId(); + break; + default: + throw new ForbiddenException("Unknown method is configured to be filtered."); + } + + Subject currentSubject = EnvironmentContext.getCurrent().getSubject(); + if (!currentSubject.hasPermission( + WorkspaceDomain.DOMAIN_ID, workspaceId, WorkspaceDomain.RUN)) { + throw new ForbiddenException( + "User doesn't have the required permissions to the specified workspace"); + } + } +} diff --git a/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/test/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilterTest.java b/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/test/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilterTest.java new file mode 100644 index 000000000000..f8cebbb0691c --- /dev/null +++ b/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/test/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilterTest.java @@ -0,0 +1,112 @@ +/* + * 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.infra.kubernetes; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService.BROKER_RESULT_METHOD; +import static org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService.BROKER_STATUS_CHANGED_METHOD; +import static org.mockito.Mockito.when; + +import org.eclipse.che.api.core.ForbiddenException; +import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerManager; +import org.eclipse.che.api.workspace.shared.dto.BrokerResultEvent; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.Subject; +import org.eclipse.che.dto.server.DtoFactory; +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.DataProvider; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/** + * Tests {@link BrokerServicePermissionFilter} + * + * @author Sergii Leshchenko + */ +@Listeners(MockitoTestNGListener.class) +public class BrokerServicePermissionFilterTest { + + @Mock private RequestHandlerManager requestHandlerManager; + + @Mock private Subject subject; + + private BrokerServicePermissionFilter permissionFilter; + + @BeforeMethod + public void setUp() { + EnvironmentContext.getCurrent().setSubject(subject); + permissionFilter = new BrokerServicePermissionFilter(); + } + + @AfterMethod + public void tearDown() { + EnvironmentContext.reset(); + } + + @Test + public void shouldRegisterItself() { + // when + permissionFilter.register(requestHandlerManager); + + // then + requestHandlerManager.registerMethodInvokerFilter( + permissionFilter, BROKER_STATUS_CHANGED_METHOD, BROKER_RESULT_METHOD); + } + + @Test( + dataProvider = "coveredMethods", + expectedExceptions = ForbiddenException.class, + expectedExceptionsMessageRegExp = + "User doesn't have the required permissions to the specified workspace") + public void shouldThrowExceptionIfUserDoesNotHaveRunPermission(String method) throws Exception { + // given + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN)) + .thenReturn(false); + + // when + permissionFilter.doAccept( + method, DtoFactory.newDto(BrokerResultEvent.class).withWorkspaceId("ws123")); + } + + @Test(dataProvider = "coveredMethods") + public void shouldDoNothingIfUserHasRunPermissions(String method) throws Exception { + // given + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN)) + .thenReturn(true); + + // when + permissionFilter.doAccept( + method, DtoFactory.newDto(BrokerResultEvent.class).withWorkspaceId("ws123")); + } + + @Test( + dataProvider = "coveredMethods", + expectedExceptions = ForbiddenException.class, + expectedExceptionsMessageRegExp = "Unknown method is configured to be filtered\\.") + public void shouldThrowExceptionIfUnknownMethodIsInvoking(String method) throws Exception { + // given + when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN)) + .thenReturn(false); + + // when + permissionFilter.doAccept( + "unknown", DtoFactory.newDto(BrokerResultEvent.class).withWorkspaceId("ws123")); + } + + @DataProvider + public Object[][] coveredMethods() { + return new Object[][] {{BROKER_STATUS_CHANGED_METHOD}, {BROKER_RESULT_METHOD}}; + } +} diff --git a/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/test/resources/logback-test.xml b/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/test/resources/logback-test.xml new file mode 100644 index 000000000000..99fef4a8dbce --- /dev/null +++ b/multiuser/permission/che-multiuser-permission-infra-kubernetes/src/test/resources/logback-test.xml @@ -0,0 +1,34 @@ + + + + + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n%nopex + + + + target/log/test.log + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n + + + + + + + + + + diff --git a/multiuser/permission/pom.xml b/multiuser/permission/pom.xml index 34b77ae257df..4c2afeca5a79 100644 --- a/multiuser/permission/pom.xml +++ b/multiuser/permission/pom.xml @@ -32,5 +32,6 @@ che-multiuser-permission-installer che-multiuser-permission-resource che-multiuser-permission-logger + che-multiuser-permission-infra-kubernetes diff --git a/pom.xml b/pom.xml index 82ccc71e4ef9..85b8d07a3319 100644 --- a/pom.xml +++ b/pom.xml @@ -1022,6 +1022,11 @@ che-multiuser-permission-factory ${che.version} + + org.eclipse.che.multiuser + che-multiuser-permission-infra-kubernetes + ${che.version} + org.eclipse.che.multiuser che-multiuser-permission-installer