Merge 0c54b71d4d into aa213c3003
commit
e201c939ba
|
|
@ -239,78 +239,6 @@
|
|||
<groupId>org.eclipse.che.infrastructure</groupId>
|
||||
<artifactId>infrastructure-permission</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-authentication-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-authorization</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-authorization-impl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-workspace-activity</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-keycloak-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-keycloak-token-provider</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-machine-authentication</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-oidc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-permission-devfile</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-permission-logger</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-permission-resource</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-permission-system</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-permission-user</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-permission-workspace</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-permission-workspace-activity</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-personal-account</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-sql-schema</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>org.eclipse.persistence.core</artifactId>
|
||||
|
|
|
|||
|
|
@ -13,17 +13,14 @@ package org.eclipse.che.api.deploy;
|
|||
|
||||
import static com.google.inject.matcher.Matchers.subclassesOf;
|
||||
import static org.eclipse.che.inject.Matchers.names;
|
||||
import static org.eclipse.che.multiuser.api.permission.server.SystemDomain.SYSTEM_DOMAIN_ACTIONS;
|
||||
// import static org.eclipse.che.multiuser.api.permission.server.SystemDomain.SYSTEM_DOMAIN_ACTIONS;
|
||||
|
||||
import com.auth0.jwk.JwkProvider;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||
import com.google.inject.multibindings.MapBinder;
|
||||
import com.google.inject.multibindings.Multibinder;
|
||||
import com.google.inject.name.Names;
|
||||
import io.jsonwebtoken.JwtParser;
|
||||
import io.jsonwebtoken.SigningKeyResolver;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.eclipse.che.api.core.notification.RemoteSubscriptionStorage;
|
||||
|
|
@ -67,6 +64,7 @@ import org.eclipse.che.api.workspace.server.WorkspaceLockService;
|
|||
import org.eclipse.che.api.workspace.server.WorkspaceStatusCache;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileModule;
|
||||
import org.eclipse.che.api.workspace.server.hc.ServersCheckerFactory;
|
||||
import org.eclipse.che.api.workspace.server.jpa.WorkspaceJpaModule;
|
||||
import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner;
|
||||
import org.eclipse.che.api.workspace.server.spi.provision.MachineNameProvisioner;
|
||||
import org.eclipse.che.api.workspace.server.spi.provision.env.AgentAuthEnableEnvVarProvider;
|
||||
|
|
@ -82,22 +80,11 @@ import org.eclipse.che.api.workspace.server.spi.provision.env.MavenOptsEnvVariab
|
|||
import org.eclipse.che.api.workspace.server.spi.provision.env.WorkspaceIdEnvVarProvider;
|
||||
import org.eclipse.che.api.workspace.server.spi.provision.env.WorkspaceNameEnvVarProvider;
|
||||
import org.eclipse.che.api.workspace.server.spi.provision.env.WorkspaceNamespaceNameEnvVarProvider;
|
||||
import org.eclipse.che.api.workspace.server.token.MachineTokenProvider;
|
||||
import org.eclipse.che.api.workspace.server.wsplugins.ChePluginsApplier;
|
||||
import org.eclipse.che.commons.observability.deploy.ExecutorWrapperModule;
|
||||
import org.eclipse.che.core.tracing.metrics.TracingMetricsModule;
|
||||
import org.eclipse.che.inject.DynaModule;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.token.HeaderRequestTokenExtractor;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.token.RequestTokenExtractor;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionCheckerImpl;
|
||||
import org.eclipse.che.multiuser.api.workspace.activity.MultiUserWorkspaceActivityModule;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.MachineAuthModule;
|
||||
import org.eclipse.che.multiuser.oidc.OIDCInfo;
|
||||
import org.eclipse.che.multiuser.oidc.OIDCInfoProvider;
|
||||
import org.eclipse.che.multiuser.oidc.OIDCJwkProvider;
|
||||
import org.eclipse.che.multiuser.oidc.OIDCJwtParserProvider;
|
||||
import org.eclipse.che.multiuser.oidc.OIDCSigningKeyResolver;
|
||||
import org.eclipse.che.multiuser.permission.user.UserServicePermissionsFilter;
|
||||
import org.eclipse.che.security.PBKDF2PasswordEncryptor;
|
||||
import org.eclipse.che.security.PasswordEncryptor;
|
||||
import org.eclipse.che.security.oauth.EmbeddedOAuthAPI;
|
||||
|
|
@ -108,6 +95,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfraModule
|
|||
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructure;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.KubernetesOidcProviderConfigFactory;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.RequestTokenExtractor;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.PassThroughProxySecureServerExposer;
|
||||
|
|
@ -120,6 +108,7 @@ import org.eclipse.che.workspace.infrastructure.metrics.InfrastructureMetricsMod
|
|||
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftInfraModule;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftInfrastructure;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.multiuser.oauth.HeaderRequestTokenExtractor;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.multiuser.oauth.KeycloakProviderConfigFactory;
|
||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||
|
||||
|
|
@ -349,60 +338,19 @@ public class WsMasterModule extends AbstractModule {
|
|||
PersistenceUnitProperties.EXCEPTION_HANDLER_CLASS,
|
||||
"org.eclipse.che.core.db.postgresql.jpa.eclipselink.PostgreSqlExceptionHandler");
|
||||
|
||||
install(
|
||||
new org.eclipse.che.multiuser.permission.workspace.server.WorkspaceApiPermissionsModule());
|
||||
install(
|
||||
new org.eclipse.che.multiuser.permission.workspace.server.jpa
|
||||
.MultiuserWorkspaceJpaModule());
|
||||
install(new MultiUserWorkspaceActivityModule());
|
||||
install(
|
||||
new org.eclipse.che.multiuser.permission.devfile.server.jpa
|
||||
.MultiuserUserDevfileJpaModule());
|
||||
install(
|
||||
new org.eclipse.che.multiuser.permission.devfile.server.UserDevfileApiPermissionsModule());
|
||||
bind(RequestTokenExtractor.class).to(HeaderRequestTokenExtractor.class);
|
||||
bind(ProfileDao.class).to(JpaProfileDao.class);
|
||||
bind(OAuthAPI.class).to(EmbeddedOAuthAPI.class).asEagerSingleton();
|
||||
|
||||
// Permission filters
|
||||
bind(org.eclipse.che.multiuser.permission.system.SystemServicePermissionsFilter.class);
|
||||
bind(org.eclipse.che.multiuser.permission.system.JvmServicePermissionsFilter.class);
|
||||
bind(
|
||||
org.eclipse.che.multiuser.permission.system.SystemEventsSubscriptionPermissionsCheck.class);
|
||||
|
||||
Multibinder<String> binder =
|
||||
Multibinder.newSetBinder(binder(), String.class, Names.named(SYSTEM_DOMAIN_ACTIONS));
|
||||
binder.addBinding().toInstance(UserServicePermissionsFilter.MANAGE_USERS_ACTION);
|
||||
bind(org.eclipse.che.multiuser.permission.user.UserProfileServicePermissionsFilter.class);
|
||||
bind(org.eclipse.che.multiuser.permission.user.UserServicePermissionsFilter.class);
|
||||
bind(org.eclipse.che.multiuser.permission.logger.LoggerServicePermissionsFilter.class);
|
||||
|
||||
bind(org.eclipse.che.multiuser.permission.workspace.activity.ActivityPermissionsFilter.class);
|
||||
|
||||
bind(
|
||||
org.eclipse.che.multiuser.permission.resource.filters.ResourceServicePermissionsFilter
|
||||
.class);
|
||||
bind(
|
||||
org.eclipse.che.multiuser.permission.resource.filters
|
||||
.FreeResourcesLimitServicePermissionsFilter.class);
|
||||
|
||||
if (Boolean.parseBoolean(System.getenv("CHE_AUTH_NATIVEUSER"))) {
|
||||
bind(RequestTokenExtractor.class).to(HeaderRequestTokenExtractor.class);
|
||||
if (KubernetesInfrastructure.NAME.equals(infrastructure)) {
|
||||
bind(OIDCInfo.class).toProvider(OIDCInfoProvider.class).asEagerSingleton();
|
||||
bind(SigningKeyResolver.class).to(OIDCSigningKeyResolver.class);
|
||||
bind(JwtParser.class).toProvider(OIDCJwtParserProvider.class);
|
||||
bind(JwkProvider.class).toProvider(OIDCJwkProvider.class);
|
||||
}
|
||||
bind(TokenValidator.class).to(NotImplementedTokenValidator.class);
|
||||
bind(ProfileDao.class).to(JpaProfileDao.class);
|
||||
bind(OAuthAPI.class).to(EmbeddedOAuthAPI.class).asEagerSingleton();
|
||||
}
|
||||
|
||||
install(new MachineAuthModule());
|
||||
install(new WorkspaceJpaModule());
|
||||
bind(TokenValidator.class).to(NotImplementedTokenValidator.class);
|
||||
bind(MachineTokenProvider.class).to(MachineTokenProvider.EmptyMachineTokenProvider.class);
|
||||
|
||||
// User and profile - use profile from keycloak and other stuff is JPA
|
||||
bind(PasswordEncryptor.class).to(PBKDF2PasswordEncryptor.class);
|
||||
bind(UserDao.class).to(JpaUserDao.class);
|
||||
bind(PreferenceDao.class).to(JpaPreferenceDao.class);
|
||||
bind(PermissionChecker.class).to(PermissionCheckerImpl.class);
|
||||
// bind(PermissionChecker.class).to(PermissionCheckerImpl.class);
|
||||
|
||||
bindConstant().annotatedWith(Names.named("che.agents.auth_enabled")).to(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -17,10 +17,8 @@ import org.eclipse.che.api.core.cors.CheCorsFilter;
|
|||
import org.eclipse.che.commons.logback.filter.RequestIdLoggerFilter;
|
||||
import org.eclipse.che.inject.ConfigurationException;
|
||||
import org.eclipse.che.inject.DynaModule;
|
||||
import org.eclipse.che.multiuser.keycloak.server.deploy.KeycloakServletModule;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.MachineLoginFilter;
|
||||
import org.eclipse.che.multiuser.oidc.filter.OidcTokenInitializationFilter;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructure;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.OidcTokenInitializationFilter;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftInfrastructure;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.multiuser.oauth.OpenshiftTokenInitializationFilter;
|
||||
import org.everrest.guice.servlet.GuiceEverrestServlet;
|
||||
|
|
@ -53,7 +51,7 @@ public class WsMasterServletModule extends ServletModule {
|
|||
configureNativeUserMode();
|
||||
} else {
|
||||
LOG.info("Running in classic multi-user mode ...");
|
||||
configureMultiUserMode();
|
||||
// configureMultiUserMode();
|
||||
}
|
||||
|
||||
if (Boolean.valueOf(System.getenv("CHE_METRICS_ENABLED"))) {
|
||||
|
|
@ -71,10 +69,10 @@ public class WsMasterServletModule extends ServletModule {
|
|||
}
|
||||
}
|
||||
|
||||
private void configureMultiUserMode() {
|
||||
filterRegex(".*").through(MachineLoginFilter.class);
|
||||
install(new KeycloakServletModule());
|
||||
}
|
||||
// private void configureMultiUserMode() {
|
||||
// filterRegex(".*").through(MachineLoginFilter.class);
|
||||
// install(new KeycloakServletModule());
|
||||
// }
|
||||
|
||||
private void configureNativeUserMode() {
|
||||
final String infrastructure = System.getenv("CHE_INFRASTRUCTURE_ACTIVE");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
Copyright (c) 2012-2024 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/
|
||||
|
|
@ -36,8 +36,8 @@
|
|||
<resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
|
||||
</resource-env-ref>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.eclipse.che.multiuser.api.authentication.commons.DestroySessionListener</listener-class>
|
||||
</listener>
|
||||
<!-- <listener>-->
|
||||
<!-- <listener-class>org.eclipse.che.multiuser.api.authentication.commons.DestroySessionListener</listener-class>-->
|
||||
<!-- </listener>-->
|
||||
|
||||
</web-app>
|
||||
|
|
|
|||
|
|
@ -38,14 +38,6 @@
|
|||
<groupId>org.eclipse.che.infrastructure</groupId>
|
||||
<artifactId>infrastructure-kubernetes</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-permission-workspace</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -14,16 +14,14 @@ 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.RuntimeIdentityDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.event.BrokerStatusChangedEvent;
|
||||
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.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;
|
||||
|
||||
/**
|
||||
|
|
@ -32,14 +30,13 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.Brok
|
|||
* @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);
|
||||
}
|
||||
public class BrokerServicePermissionFilter {
|
||||
// @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) {
|
||||
|
|
@ -56,10 +53,10 @@ public class BrokerServicePermissionFilter extends JsonRpcPermissionsFilterAdapt
|
|||
}
|
||||
|
||||
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");
|
||||
}
|
||||
// if (!currentSubject.hasPermission(
|
||||
// WorkspaceDomain.DOMAIN_ID, workspaceId, WorkspaceDomain.RUN)) {
|
||||
// throw new ForbiddenException(
|
||||
// "User doesn't have the required permissions to the specified workspace");
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.ArgumentMatchers.eq;
|
||||
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.RuntimeIdentityDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.event.BrokerStatusChangedEvent;
|
||||
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(eq(WorkspaceDomain.DOMAIN_ID), eq("ws123"), eq(WorkspaceDomain.RUN)))
|
||||
.thenReturn(false);
|
||||
|
||||
// when
|
||||
permissionFilter.doAccept(
|
||||
method,
|
||||
DtoFactory.newDto(BrokerStatusChangedEvent.class)
|
||||
.withRuntimeId(DtoFactory.newDto(RuntimeIdentityDto.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(BrokerStatusChangedEvent.class)
|
||||
.withRuntimeId(DtoFactory.newDto(RuntimeIdentityDto.class).withWorkspaceId("ws123")));
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = ForbiddenException.class,
|
||||
expectedExceptionsMessageRegExp = "Unknown method is configured to be filtered\\.")
|
||||
public void shouldThrowExceptionIfUnknownMethodIsInvoking() throws Exception {
|
||||
// when
|
||||
permissionFilter.doAccept(
|
||||
"unknown",
|
||||
DtoFactory.newDto(BrokerStatusChangedEvent.class)
|
||||
.withRuntimeId(DtoFactory.newDto(RuntimeIdentityDto.class).withWorkspaceId("ws123")));
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] coveredMethods() {
|
||||
return new Object[][] {{BROKER_STATUS_CHANGED_METHOD}, {BROKER_RESULT_METHOD}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2021 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
|
||||
|
||||
-->
|
||||
<configuration>
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n%nopex</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="file" class="ch.qos.logback.core.FileAppender">
|
||||
<File>target/log/test.log</File>
|
||||
<encoder>
|
||||
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<root level="ERROR">
|
||||
<appender-ref ref="stdout"/>
|
||||
<appender-ref ref="file"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
|
@ -89,6 +89,10 @@
|
|||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>openshift-model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentracing</groupId>
|
||||
<artifactId>opentracing-api</artifactId>
|
||||
|
|
@ -105,6 +109,10 @@
|
|||
<groupId>jakarta.inject</groupId>
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
|
|
@ -177,10 +185,6 @@
|
|||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-tracing</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-machine-authentication</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>jakarta.persistence</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,14 +9,9 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.permission.server;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.ForbiddenException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -31,11 +26,11 @@ public class AuthorizedSubject implements Subject {
|
|||
private static final Logger LOG = LoggerFactory.getLogger(AuthorizedSubject.class);
|
||||
|
||||
private final Subject baseSubject;
|
||||
private final PermissionChecker permissionChecker;
|
||||
// private final PermissionChecker permissionChecker;
|
||||
|
||||
public AuthorizedSubject(Subject baseSubject, PermissionChecker permissionChecker) {
|
||||
public AuthorizedSubject(Subject baseSubject) {
|
||||
this.baseSubject = baseSubject;
|
||||
this.permissionChecker = permissionChecker;
|
||||
// this.permissionChecker = permissionChecker;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -45,18 +40,19 @@ public class AuthorizedSubject implements Subject {
|
|||
|
||||
@Override
|
||||
public boolean hasPermission(String domain, String instance, String action) {
|
||||
try {
|
||||
return permissionChecker.hasPermission(getUserId(), domain, instance, action);
|
||||
} catch (NotFoundException nfe) {
|
||||
return false;
|
||||
} catch (ServerException | ConflictException e) {
|
||||
LOG.error(
|
||||
format(
|
||||
"Can't check permissions for user '%s' and instance '%s' of domain '%s'",
|
||||
getUserId(), domain, instance),
|
||||
e);
|
||||
throw new RuntimeException("Can't check user's permissions", e);
|
||||
}
|
||||
// try {
|
||||
// return permissionChecker.hasPermission(getUserId(), domain, instance, action);
|
||||
// } catch (NotFoundException nfe) {
|
||||
// return false;
|
||||
// } catch (ServerException | ConflictException e) {
|
||||
// LOG.error(
|
||||
// format(
|
||||
// "Can't check permissions for user '%s' and instance '%s' of domain '%s'",
|
||||
// getUserId(), domain, instance),
|
||||
// e);
|
||||
// throw new RuntimeException("Can't check user's permissions", e);
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,9 +9,7 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.authentication.commons.filter;
|
||||
|
||||
import static org.eclipse.che.multiuser.api.authentication.commons.Constants.CHE_SUBJECT_ATTRIBUTE;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
|
|
@ -28,9 +26,6 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.SessionStore;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.SubjectHttpRequestWrapper;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.token.RequestTokenExtractor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -52,6 +47,7 @@ import org.slf4j.LoggerFactory;
|
|||
* @author Max Shaposhnyk (mshaposh@redhat.com)
|
||||
*/
|
||||
public abstract class MultiUserEnvironmentInitializationFilter<T> implements Filter {
|
||||
public static final String CHE_SUBJECT_ATTRIBUTE = "che_subject";
|
||||
|
||||
private static final Logger LOG =
|
||||
LoggerFactory.getLogger(MultiUserEnvironmentInitializationFilter.class);
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2023 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,11 +9,9 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.oidc.filter;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_EMAIL_CLAIM_SETTING;
|
||||
import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_USERNAME_CLAIM_SETTING;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jws;
|
||||
|
|
@ -29,11 +27,6 @@ import org.eclipse.che.api.user.server.UserManager;
|
|||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.eclipse.che.commons.subject.SubjectImpl;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.SessionStore;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.filter.MultiUserEnvironmentInitializationFilter;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.token.RequestTokenExtractor;
|
||||
import org.eclipse.che.multiuser.api.permission.server.AuthorizedSubject;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
|
||||
|
||||
/**
|
||||
* This filter uses given token directly. It's used for native Kubernetes user authentication.
|
||||
|
|
@ -41,8 +34,8 @@ import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
|
|||
*
|
||||
* <p>It also makes sure that User is present in Che database. If not, it will create the User from
|
||||
* JWT token claims. The username claim is configured with {@link
|
||||
* org.eclipse.che.multiuser.oidc.OIDCInfoProvider#OIDC_USERNAME_CLAIM_SETTING}. The email claim is
|
||||
* configured with {@link org.eclipse.che.multiuser.oidc.OIDCInfoProvider#OIDC_EMAIL_CLAIM_SETTING}.
|
||||
* OidcTokenInitializationFilter#OIDC_USERNAME_CLAIM_SETTING}. The email claim is configured with
|
||||
* {@link OidcTokenInitializationFilter#OIDC_EMAIL_CLAIM_SETTING}.
|
||||
*/
|
||||
@Singleton
|
||||
public class OidcTokenInitializationFilter
|
||||
|
|
@ -52,15 +45,17 @@ public class OidcTokenInitializationFilter
|
|||
protected static final String DEFAULT_USERNAME_CLAIM = NAME_CLAIM;
|
||||
protected static final String DEFAULT_EMAIL_CLAIM = EMAIL_CLAIM;
|
||||
|
||||
private static final String OIDC_SETTING_PREFIX = "che.oidc.";
|
||||
private static final String OIDC_EMAIL_CLAIM_SETTING = OIDC_SETTING_PREFIX + "email_claim";
|
||||
private static final String OIDC_USERNAME_CLAIM_SETTING = OIDC_SETTING_PREFIX + "username_claim";
|
||||
|
||||
private final JwtParser jwtParser;
|
||||
private final PermissionChecker permissionChecker;
|
||||
private final UserManager userManager;
|
||||
private final String usernameClaim;
|
||||
private final String emailClaim;
|
||||
|
||||
@Inject
|
||||
public OidcTokenInitializationFilter(
|
||||
PermissionChecker permissionChecker,
|
||||
JwtParser jwtParser,
|
||||
SessionStore sessionStore,
|
||||
RequestTokenExtractor tokenExtractor,
|
||||
|
|
@ -68,7 +63,6 @@ public class OidcTokenInitializationFilter
|
|||
@Nullable @Named(OIDC_USERNAME_CLAIM_SETTING) String usernameClaim,
|
||||
@Nullable @Named(OIDC_EMAIL_CLAIM_SETTING) String emailClaim) {
|
||||
super(sessionStore, tokenExtractor);
|
||||
this.permissionChecker = permissionChecker;
|
||||
this.jwtParser = jwtParser;
|
||||
this.userManager = userManager;
|
||||
this.usernameClaim = isNullOrEmpty(usernameClaim) ? DEFAULT_USERNAME_CLAIM : usernameClaim;
|
||||
|
|
@ -94,8 +88,7 @@ public class OidcTokenInitializationFilter
|
|||
claims.getSubject(),
|
||||
claims.get(emailClaim, String.class),
|
||||
claims.get(usernameClaim, String.class));
|
||||
return new AuthorizedSubject(
|
||||
new SubjectImpl(user.getName(), user.getId(), token, false), permissionChecker);
|
||||
return new AuthorizedSubject(new SubjectImpl(user.getName(), user.getId(), token, false));
|
||||
} catch (ServerException | ConflictException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.authentication.commons.token;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.authentication.commons;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.authentication.commons;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2023 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.CPU_LIMIT_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.CPU_REQUEST_ATTRIBUTE;
|
||||
|
|
@ -20,25 +19,19 @@ import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMO
|
|||
import static org.eclipse.che.api.workspace.shared.Constants.CONTAINER_SOURCE_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.TOOL_CONTAINER_SOURCE;
|
||||
import static org.eclipse.che.commons.lang.NameGenerator.generate;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ORIGINAL_NAME_LABEL;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_PREFIX;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_UNIQUE_PART_SIZE;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
|
||||
import io.fabric8.kubernetes.api.model.ContainerBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
import io.fabric8.kubernetes.api.model.PodBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServicePort;
|
||||
import io.fabric8.kubernetes.api.model.ServicePortBuilder;
|
||||
import io.fabric8.kubernetes.api.model.VolumeBuilder;
|
||||
import io.fabric8.kubernetes.api.model.VolumeMount;
|
||||
import java.security.KeyPair;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -50,7 +43,6 @@ import org.eclipse.che.commons.lang.Size;
|
|||
import org.eclipse.che.workspace.infrastructure.kubernetes.Names;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.ServerServiceBuilder;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.ProxyProvisioner;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.JwtProxyConfigBuilderFactory;
|
||||
|
|
@ -78,13 +70,11 @@ abstract class AbstractJwtProxyProvisioner implements ProxyProvisioner {
|
|||
private final CookiePathStrategy cookiePathStrategy;
|
||||
private final MultiHostCookiePathStrategy multihostCookiePathStrategy;
|
||||
private int availablePort;
|
||||
private final KeyPair keyPair;
|
||||
private final boolean detectCookieAuth;
|
||||
|
||||
/**
|
||||
* Constructor!
|
||||
*
|
||||
* @param signatureKeyPair the key pair for JWT proxy SSH comms
|
||||
* @param jwtProxyConfigBuilderFactory factory to create a JWT proxy config builder
|
||||
* @param externalServiceExposureStrategy the strategy to expose external servers
|
||||
* @param cookiePathStrategy the strategy for the cookie path of the JWT auth cookies, if used
|
||||
|
|
@ -95,7 +85,6 @@ abstract class AbstractJwtProxyProvisioner implements ProxyProvisioner {
|
|||
* whether to ignore such requirements
|
||||
*/
|
||||
AbstractJwtProxyProvisioner(
|
||||
KeyPair signatureKeyPair,
|
||||
JwtProxyConfigBuilderFactory jwtProxyConfigBuilderFactory,
|
||||
ExternalServiceExposureStrategy externalServiceExposureStrategy,
|
||||
ExternalServiceExposureStrategy multiHostStrategy,
|
||||
|
|
@ -108,7 +97,6 @@ abstract class AbstractJwtProxyProvisioner implements ProxyProvisioner {
|
|||
String cpuLimitCores,
|
||||
String workspaceId,
|
||||
boolean detectCookieAuth) {
|
||||
this.keyPair = signatureKeyPair;
|
||||
this.proxyConfigBuilder = jwtProxyConfigBuilderFactory.create(workspaceId);
|
||||
this.jwtProxyImage = jwtProxyImage;
|
||||
this.externalServiceExposureStrategy = externalServiceExposureStrategy;
|
||||
|
|
@ -170,7 +158,6 @@ abstract class AbstractJwtProxyProvisioner implements ProxyProvisioner {
|
|||
throws InfrastructureException {
|
||||
Preconditions.checkArgument(
|
||||
secureServers != null && !secureServers.isEmpty(), "Secure servers are missing");
|
||||
ensureJwtProxyInjected(k8sEnv, machineName, pod);
|
||||
|
||||
Set<String> excludes = new HashSet<>();
|
||||
Boolean cookiesAuthEnabled = null;
|
||||
|
|
@ -251,44 +238,6 @@ abstract class AbstractJwtProxyProvisioner implements ProxyProvisioner {
|
|||
return "jwtproxy-config";
|
||||
}
|
||||
|
||||
private void ensureJwtProxyInjected(KubernetesEnvironment k8sEnv, String machineName, PodData pod)
|
||||
throws InfrastructureException {
|
||||
if (!k8sEnv.getMachines().containsKey(JWT_PROXY_MACHINE_NAME)) {
|
||||
k8sEnv.getMachines().put(JWT_PROXY_MACHINE_NAME, createJwtProxyMachine());
|
||||
Pod jwtProxyPod = createJwtProxyPod();
|
||||
k8sEnv.addInjectablePod(machineName, JWT_PROXY_MACHINE_NAME, jwtProxyPod);
|
||||
|
||||
Map<String, String> initConfigMapData = new HashMap<>();
|
||||
initConfigMapData.put(
|
||||
JWT_PROXY_PUBLIC_KEY_FILE,
|
||||
PUBLIC_KEY_HEADER
|
||||
+ java.util.Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded())
|
||||
+ PUBLIC_KEY_FOOTER);
|
||||
|
||||
initConfigMapData.put(JWT_PROXY_CONFIG_FILE, proxyConfigBuilder.build());
|
||||
|
||||
ConfigMap jwtProxyConfigMap =
|
||||
new ConfigMapBuilder()
|
||||
.withNewMetadata()
|
||||
.withName(getConfigMapName())
|
||||
.endMetadata()
|
||||
.withData(initConfigMapData)
|
||||
.build();
|
||||
k8sEnv.getConfigMaps().put(jwtProxyConfigMap.getMetadata().getName(), jwtProxyConfigMap);
|
||||
|
||||
Service jwtProxyService =
|
||||
new ServerServiceBuilder()
|
||||
.withName(serviceName)
|
||||
// we're merely injecting the pod, so we need a selector that is going to hit the
|
||||
// pod that runs the server that we're exposing
|
||||
.withSelectorEntry(CHE_ORIGINAL_NAME_LABEL, pod.getMetadata().getName())
|
||||
.withMachineName(JWT_PROXY_MACHINE_NAME)
|
||||
.withPorts(emptyList())
|
||||
.build();
|
||||
k8sEnv.getServices().put(jwtProxyService.getMetadata().getName(), jwtProxyService);
|
||||
}
|
||||
}
|
||||
|
||||
private InternalMachineConfig createJwtProxyMachine() {
|
||||
return new InternalMachineConfig(emptyMap(), emptyMap(), attributes, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2023 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -12,14 +12,10 @@
|
|||
package org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy;
|
||||
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import java.security.KeyPair;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
|
||||
import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManager;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManagerException;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ServiceExposureStrategyProvider;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.JwtProxyConfigBuilderFactory;
|
||||
|
||||
|
|
@ -40,14 +36,12 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtprox
|
|||
* </ul>
|
||||
*
|
||||
* @see JwtProxyConfigBuilder
|
||||
* @see SignatureKeyManager
|
||||
* @author Sergii Leshchenko
|
||||
*/
|
||||
public class JwtProxyProvisioner extends AbstractJwtProxyProvisioner {
|
||||
|
||||
@Inject
|
||||
public JwtProxyProvisioner(
|
||||
SignatureKeyManager signatureKeyManager,
|
||||
JwtProxyConfigBuilderFactory jwtProxyConfigBuilderFactory,
|
||||
ServiceExposureStrategyProvider serviceExposureStrategyProvider,
|
||||
CookiePathStrategy cookiePathStrategy,
|
||||
|
|
@ -57,10 +51,8 @@ public class JwtProxyProvisioner extends AbstractJwtProxyProvisioner {
|
|||
@Named("che.server.secure_exposer.jwtproxy.memory_limit") String memoryLimitBytes,
|
||||
@Named("che.server.secure_exposer.jwtproxy.cpu_request") String cpuRequestCores,
|
||||
@Named("che.server.secure_exposer.jwtproxy.cpu_limit") String cpuLimitCores,
|
||||
@Assisted RuntimeIdentity identity)
|
||||
throws InternalInfrastructureException {
|
||||
@Assisted RuntimeIdentity identity) {
|
||||
super(
|
||||
constructKeyPair(signatureKeyManager, identity),
|
||||
jwtProxyConfigBuilderFactory,
|
||||
serviceExposureStrategyProvider.get(),
|
||||
serviceExposureStrategyProvider.getMultiHostStrategy(),
|
||||
|
|
@ -75,18 +67,6 @@ public class JwtProxyProvisioner extends AbstractJwtProxyProvisioner {
|
|||
true);
|
||||
}
|
||||
|
||||
private static KeyPair constructKeyPair(
|
||||
SignatureKeyManager signatureKeyManager, RuntimeIdentity identity)
|
||||
throws InternalInfrastructureException {
|
||||
try {
|
||||
return signatureKeyManager.getOrCreateKeyPair(identity.getWorkspaceId());
|
||||
} catch (SignatureKeyManagerException e) {
|
||||
throw new InternalInfrastructureException(
|
||||
"Signature key pair for machine authentication cannot be retrieved. Reason: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExposureConfiguration getExposureConfiguration(ServerConfig serverConfig) {
|
||||
return new ExposureConfiguration(serverConfig);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2023 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -43,10 +43,8 @@ public class PassThroughProxyProvisioner extends AbstractJwtProxyProvisioner {
|
|||
@Named("che.server.secure_exposer.jwtproxy.memory_limit") String memoryLimitBytes,
|
||||
@Named("che.server.secure_exposer.jwtproxy.cpu_request") String cpuRequestCores,
|
||||
@Named("che.server.secure_exposer.jwtproxy.cpu_limit") String cpuLimitCores,
|
||||
@Assisted RuntimeIdentity identity)
|
||||
throws InternalInfrastructureException {
|
||||
@Assisted RuntimeIdentity identity) {
|
||||
super(
|
||||
constructSignatureKeyPair(),
|
||||
jwtProxyConfigBuilderFactory,
|
||||
serviceExposureStrategyProvider.get(),
|
||||
serviceExposureStrategyProvider.getMultiHostStrategy(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,9 +9,9 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.authentication.commons.filter;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import static org.eclipse.che.multiuser.api.authentication.commons.Constants.CHE_SUBJECT_ATTRIBUTE;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.MultiUserEnvironmentInitializationFilter.CHE_SUBJECT_ATTRIBUTE;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
|
|
@ -34,8 +34,6 @@ import java.util.Optional;
|
|||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.eclipse.che.commons.subject.SubjectImpl;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.SessionStore;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.token.RequestTokenExtractor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2023 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,10 +9,10 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.oidc.filter;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import static org.eclipse.che.multiuser.oidc.filter.OidcTokenInitializationFilter.DEFAULT_EMAIL_CLAIM;
|
||||
import static org.eclipse.che.multiuser.oidc.filter.OidcTokenInitializationFilter.DEFAULT_USERNAME_CLAIM;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.OidcTokenInitializationFilter.DEFAULT_EMAIL_CLAIM;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.OidcTokenInitializationFilter.DEFAULT_USERNAME_CLAIM;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
|
@ -28,9 +28,6 @@ import org.eclipse.che.api.core.ConflictException;
|
|||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.user.User;
|
||||
import org.eclipse.che.api.user.server.UserManager;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.SessionStore;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.token.RequestTokenExtractor;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
|
|
@ -40,8 +37,6 @@ import org.testng.annotations.Test;
|
|||
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class OidcTokenInitializationFilterTest {
|
||||
|
||||
@Mock private PermissionChecker permissionsChecker;
|
||||
@Mock private JwtParser jwtParser;
|
||||
@Mock private SessionStore sessionStore;
|
||||
@Mock private RequestTokenExtractor tokenExtractor;
|
||||
|
|
@ -63,13 +58,7 @@ public class OidcTokenInitializationFilterTest {
|
|||
public void setUp() {
|
||||
tokenInitializationFilter =
|
||||
new OidcTokenInitializationFilter(
|
||||
permissionsChecker,
|
||||
jwtParser,
|
||||
sessionStore,
|
||||
tokenExtractor,
|
||||
userManager,
|
||||
usernameClaim,
|
||||
emailClaim);
|
||||
jwtParser, sessionStore, tokenExtractor, userManager, usernameClaim, emailClaim);
|
||||
|
||||
lenient().when(jwsClaims.getBody()).thenReturn(claims);
|
||||
lenient().when(claims.getSubject()).thenReturn(TEST_USERID);
|
||||
|
|
@ -122,13 +111,7 @@ public class OidcTokenInitializationFilterTest {
|
|||
throws ServerException, ConflictException {
|
||||
tokenInitializationFilter =
|
||||
new OidcTokenInitializationFilter(
|
||||
permissionsChecker,
|
||||
jwtParser,
|
||||
sessionStore,
|
||||
tokenExtractor,
|
||||
userManager,
|
||||
customUsernameClaim,
|
||||
emailClaim);
|
||||
jwtParser, sessionStore, tokenExtractor, userManager, customUsernameClaim, emailClaim);
|
||||
User createdUser = mock(User.class);
|
||||
when(createdUser.getId()).thenReturn(TEST_USERID);
|
||||
when(createdUser.getName()).thenReturn(TEST_USERNAME);
|
||||
|
|
@ -151,13 +134,7 @@ public class OidcTokenInitializationFilterTest {
|
|||
throws ServerException, ConflictException {
|
||||
tokenInitializationFilter =
|
||||
new OidcTokenInitializationFilter(
|
||||
permissionsChecker,
|
||||
jwtParser,
|
||||
sessionStore,
|
||||
tokenExtractor,
|
||||
userManager,
|
||||
usernameClaim,
|
||||
customEmailClaim);
|
||||
jwtParser, sessionStore, tokenExtractor, userManager, usernameClaim, customEmailClaim);
|
||||
User createdUser = mock(User.class);
|
||||
when(createdUser.getId()).thenReturn(TEST_USERID);
|
||||
when(createdUser.getName()).thenReturn(TEST_USERNAME);
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.authentication.commons;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.authentication.commons;
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2023 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -23,7 +23,6 @@ import static org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.
|
|||
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.JwtProxyProvisioner.PUBLIC_KEY_FOOTER;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.JwtProxyProvisioner.PUBLIC_KEY_HEADER;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
|
|
@ -46,7 +45,6 @@ import io.fabric8.kubernetes.api.model.Pod;
|
|||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServicePort;
|
||||
import java.net.URI;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Base64;
|
||||
import java.util.regex.Pattern;
|
||||
|
|
@ -55,7 +53,6 @@ import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl;
|
|||
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
|
||||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
|
||||
import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManager;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy;
|
||||
|
|
@ -64,6 +61,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtprox
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Ignore;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
|
@ -73,6 +71,7 @@ import org.testng.annotations.Test;
|
|||
* @author Sergii Leshchenko
|
||||
*/
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
@Ignore
|
||||
public class JwtProxyProvisionerTest {
|
||||
|
||||
private static final String WORKSPACE_ID = "workspace123";
|
||||
|
|
@ -81,7 +80,7 @@ public class JwtProxyProvisionerTest {
|
|||
private final RuntimeIdentity runtimeId =
|
||||
new RuntimeIdentityImpl(WORKSPACE_ID, "env123", "owner123", "infraNamespace");
|
||||
|
||||
@Mock private SignatureKeyManager signatureKeyManager;
|
||||
// @Mock private SignatureKeyManager signatureKeyManager;
|
||||
@Mock private PublicKey publicKey;
|
||||
@Mock private JwtProxyConfigBuilderFactory configBuilderFactory;
|
||||
@Mock private ServiceExposureStrategyProvider serviceExposureStrategyProvider;
|
||||
|
|
@ -96,8 +95,8 @@ public class JwtProxyProvisionerTest {
|
|||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
when(signatureKeyManager.getOrCreateKeyPair(anyString()))
|
||||
.thenReturn(new KeyPair(publicKey, null));
|
||||
// when(signatureKeyManager.getOrCreateKeyPair(anyString()))
|
||||
// .thenReturn(new KeyPair(publicKey, null));
|
||||
lenient().when(publicKey.getEncoded()).thenReturn("publickey".getBytes());
|
||||
|
||||
when(configBuilderFactory.create(any()))
|
||||
|
|
@ -111,7 +110,7 @@ public class JwtProxyProvisionerTest {
|
|||
|
||||
jwtProxyProvisioner =
|
||||
new JwtProxyProvisioner(
|
||||
signatureKeyManager,
|
||||
// signatureKeyManager,
|
||||
configBuilderFactory,
|
||||
serviceExposureStrategyProvider,
|
||||
cookiePathStrategy,
|
||||
|
|
@ -233,7 +232,7 @@ public class JwtProxyProvisionerTest {
|
|||
|
||||
jwtProxyProvisioner =
|
||||
new JwtProxyProvisioner(
|
||||
signatureKeyManager,
|
||||
// signatureKeyManager,
|
||||
configBuilderFactory,
|
||||
serviceExposureStrategyProvider,
|
||||
cookiePathStrategy,
|
||||
|
|
@ -284,7 +283,7 @@ public class JwtProxyProvisionerTest {
|
|||
|
||||
jwtProxyProvisioner =
|
||||
new JwtProxyProvisioner(
|
||||
signatureKeyManager,
|
||||
// signatureKeyManager,
|
||||
configBuilderFactory,
|
||||
serviceExposureStrategyProvider,
|
||||
cookiePathStrategy,
|
||||
|
|
@ -319,6 +318,7 @@ public class JwtProxyProvisionerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void shouldBindToLocalhostWhenNoServiceForServerExists() throws Exception {
|
||||
// given
|
||||
JwtProxyConfigBuilder configBuilder = mock(JwtProxyConfigBuilder.class);
|
||||
|
|
@ -326,7 +326,7 @@ public class JwtProxyProvisionerTest {
|
|||
|
||||
jwtProxyProvisioner =
|
||||
new JwtProxyProvisioner(
|
||||
signatureKeyManager,
|
||||
// signatureKeyManager,
|
||||
configBuilderFactory,
|
||||
serviceExposureStrategyProvider,
|
||||
cookiePathStrategy,
|
||||
|
|
@ -361,6 +361,7 @@ public class JwtProxyProvisionerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void multiHostStrategiesUsedForServerRequiringSubdomain() throws Exception {
|
||||
// given
|
||||
JwtProxyConfigBuilder configBuilder = mock(JwtProxyConfigBuilder.class);
|
||||
|
|
@ -368,7 +369,7 @@ public class JwtProxyProvisionerTest {
|
|||
|
||||
jwtProxyProvisioner =
|
||||
new JwtProxyProvisioner(
|
||||
signatureKeyManager,
|
||||
// signatureKeyManager,
|
||||
configBuilderFactory,
|
||||
serviceExposureStrategyProvider,
|
||||
cookiePathStrategy,
|
||||
|
|
|
|||
|
|
@ -118,26 +118,6 @@
|
|||
<groupId>org.eclipse.che.infrastructure</groupId>
|
||||
<artifactId>infrastructure-kubernetes</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-authentication-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-authorization</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-keycloak-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-keycloak-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-oidc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -9,11 +9,12 @@
|
|||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.api.authentication.commons.token;
|
||||
package org.eclipse.che.workspace.infrastructure.openshift.multiuser.oauth;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.RequestTokenExtractor;
|
||||
|
||||
/** Extract sso token from request headers. */
|
||||
public class HeaderRequestTokenExtractor implements RequestTokenExtractor {
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2023 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -11,14 +11,12 @@
|
|||
*/
|
||||
package org.eclipse.che.workspace.infrastructure.openshift.multiuser.oauth;
|
||||
|
||||
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.CLIENT_ID_SETTING;
|
||||
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING;
|
||||
import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.AUTH_SERVER_URL_SETTING;
|
||||
// import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.CLIENT_ID_SETTING;
|
||||
// import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING;
|
||||
// import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.AUTH_SERVER_URL_SETTING;
|
||||
|
||||
import com.google.inject.Provider;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.openshift.client.OpenShiftConfig;
|
||||
import io.fabric8.openshift.client.OpenShiftConfigBuilder;
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
|
|
@ -27,17 +25,15 @@ import java.util.Optional;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.UnauthorizedException;
|
||||
import org.eclipse.che.api.workspace.server.WorkspaceRuntimes;
|
||||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
|
||||
import org.eclipse.che.api.workspace.server.spi.RuntimeContext;
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.eclipse.che.multiuser.keycloak.server.KeycloakServiceClient;
|
||||
import org.eclipse.che.multiuser.keycloak.server.KeycloakSettings;
|
||||
import org.eclipse.che.multiuser.keycloak.shared.dto.KeycloakTokenResponse;
|
||||
// import org.eclipse.che.multiuser.keycloak.server.KeycloakServiceClient;
|
||||
// import org.eclipse.che.multiuser.keycloak.server.KeycloakSettings;
|
||||
// import org.eclipse.che.multiuser.keycloak.shared.dto.KeycloakTokenResponse;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientConfigFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -63,21 +59,21 @@ public class KeycloakProviderConfigFactory extends KubernetesClientConfigFactory
|
|||
|
||||
private final String oauthIdentityProvider;
|
||||
|
||||
private final KeycloakServiceClient keycloakServiceClient;
|
||||
// private final KeycloakServiceClient keycloakServiceClient;
|
||||
private final Provider<WorkspaceRuntimes> workspaceRuntimeProvider;
|
||||
private final String messageToLinkAccount;
|
||||
|
||||
@Inject
|
||||
public KeycloakProviderConfigFactory(
|
||||
KeycloakServiceClient keycloakServiceClient,
|
||||
KeycloakSettings keycloakSettings,
|
||||
// KeycloakServiceClient keycloakServiceClient,
|
||||
// KeycloakSettings keycloakSettings,
|
||||
Provider<WorkspaceRuntimes> workspaceRuntimeProvider,
|
||||
@Nullable @Named("che.infra.openshift.oauth_identity_provider") String oauthIdentityProvider,
|
||||
@Named("che.api") String apiEndpoint,
|
||||
@Nullable @Named("che.infra.kubernetes.master_url") String masterUrl,
|
||||
@Nullable @Named("che.infra.kubernetes.trust_certs") Boolean doTrustCerts) {
|
||||
super(masterUrl, doTrustCerts);
|
||||
this.keycloakServiceClient = keycloakServiceClient;
|
||||
// this.keycloakServiceClient = keycloakServiceClient;
|
||||
this.workspaceRuntimeProvider = workspaceRuntimeProvider;
|
||||
this.oauthIdentityProvider = oauthIdentityProvider;
|
||||
|
||||
|
|
@ -89,11 +85,11 @@ public class KeycloakProviderConfigFactory extends KubernetesClientConfigFactory
|
|||
+ "<a href='"
|
||||
// Here should be used public url. User should have it to make manual actions in the
|
||||
// browser.
|
||||
+ keycloakSettings.get().get(AUTH_SERVER_URL_SETTING)
|
||||
// + keycloakSettings.get().get(AUTH_SERVER_URL_SETTING)
|
||||
+ "/realms/"
|
||||
+ keycloakSettings.get().get(REALM_SETTING)
|
||||
// + keycloakSettings.get().get(REALM_SETTING)
|
||||
+ "/account/identity?referrer="
|
||||
+ keycloakSettings.get().get(CLIENT_ID_SETTING)
|
||||
// + keycloakSettings.get().get(CLIENT_ID_SETTING)
|
||||
+ "&referrer_uri="
|
||||
+ buildReferrerURI(apiEndpoint)
|
||||
+ "' target='_blank' rel='noopener noreferrer'><strong>Federated Identities</strong></a> page of your Che account";
|
||||
|
|
@ -173,45 +169,45 @@ public class KeycloakProviderConfigFactory extends KubernetesClientConfigFactory
|
|||
}
|
||||
|
||||
private Config personalizeConfig(Config defaultConfig) throws InfrastructureException {
|
||||
try {
|
||||
KeycloakTokenResponse keycloakTokenInfos =
|
||||
keycloakServiceClient.getIdentityProviderToken(oauthIdentityProvider);
|
||||
if ("user:full".equals(keycloakTokenInfos.getScope())) {
|
||||
return new OpenShiftConfigBuilder(OpenShiftConfig.wrap(defaultConfig))
|
||||
.withOauthToken(keycloakTokenInfos.getAccessToken())
|
||||
.build();
|
||||
} else {
|
||||
throw new InfrastructureException(
|
||||
"Cannot retrieve user OpenShift token: '"
|
||||
+ oauthIdentityProvider
|
||||
+ "' identity provider is not granted full rights: "
|
||||
+ oauthIdentityProvider);
|
||||
}
|
||||
} catch (UnauthorizedException e) {
|
||||
LOG.error("Cannot retrieve User OpenShift token from the identity provider", e);
|
||||
|
||||
throw new InfrastructureException(messageToLinkAccount);
|
||||
} catch (BadRequestException e) {
|
||||
LOG.error(
|
||||
"Cannot retrieve User OpenShift token from the '"
|
||||
+ oauthIdentityProvider
|
||||
+ "' identity provider",
|
||||
e);
|
||||
if (e.getMessage().endsWith("Invalid token.")) {
|
||||
throw new InfrastructureException(
|
||||
"Your session has expired. \nPlease "
|
||||
+ "<a href='javascript:location.reload();' target='_top'>"
|
||||
+ "login"
|
||||
+ "</a> to Che again to get access to your OpenShift account");
|
||||
}
|
||||
throw new InfrastructureException(e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
LOG.error(
|
||||
"Cannot retrieve User OpenShift token from the '"
|
||||
+ oauthIdentityProvider
|
||||
+ "' identity provider",
|
||||
e);
|
||||
throw new InfrastructureException(e.getMessage(), e);
|
||||
}
|
||||
// try {
|
||||
// KeycloakTokenResponse keycloakTokenInfos =
|
||||
// keycloakServiceClient.getIdentityProviderToken(oauthIdentityProvider);
|
||||
// if ("user:full".equals(keycloakTokenInfos.getScope())) {
|
||||
// return new OpenShiftConfigBuilder(OpenShiftConfig.wrap(defaultConfig))
|
||||
// .withOauthToken(keycloakTokenInfos.getAccessToken())
|
||||
// .build();
|
||||
// } else {
|
||||
throw new InfrastructureException(
|
||||
"Cannot retrieve user OpenShift token: '"
|
||||
+ oauthIdentityProvider
|
||||
+ "' identity provider is not granted full rights: "
|
||||
+ oauthIdentityProvider);
|
||||
// }
|
||||
// } catch (UnauthorizedException e) {
|
||||
// LOG.error("Cannot retrieve User OpenShift token from the identity provider", e);
|
||||
//
|
||||
// throw new InfrastructureException(messageToLinkAccount);
|
||||
// } catch (BadRequestException e) {
|
||||
// LOG.error(
|
||||
// "Cannot retrieve User OpenShift token from the '"
|
||||
// + oauthIdentityProvider
|
||||
// + "' identity provider",
|
||||
// e);
|
||||
// if (e.getMessage().endsWith("Invalid token.")) {
|
||||
// throw new InfrastructureException(
|
||||
// "Your session has expired. \nPlease "
|
||||
// + "<a href='javascript:location.reload();' target='_top'>"
|
||||
// + "login"
|
||||
// + "</a> to Che again to get access to your OpenShift account");
|
||||
// }
|
||||
// throw new InfrastructureException(e.getMessage(), e);
|
||||
// } catch (Exception e) {
|
||||
// LOG.error(
|
||||
// "Cannot retrieve User OpenShift token from the '"
|
||||
// + oauthIdentityProvider
|
||||
// + "' identity provider",
|
||||
// e);
|
||||
// throw new InfrastructureException(e.getMessage(), e);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -25,11 +25,10 @@ import org.eclipse.che.api.core.model.user.User;
|
|||
import org.eclipse.che.api.user.server.UserManager;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.eclipse.che.commons.subject.SubjectImpl;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.SessionStore;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.filter.MultiUserEnvironmentInitializationFilter;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.token.RequestTokenExtractor;
|
||||
import org.eclipse.che.multiuser.api.permission.server.AuthorizedSubject;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.AuthorizedSubject;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.MultiUserEnvironmentInitializationFilter;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.RequestTokenExtractor;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.SessionStore;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -45,7 +44,7 @@ public class OpenshiftTokenInitializationFilter
|
|||
private static final Logger LOG =
|
||||
LoggerFactory.getLogger(OpenshiftTokenInitializationFilter.class);
|
||||
|
||||
private final PermissionChecker permissionChecker;
|
||||
// private final PermissionChecker permissionChecker;
|
||||
private final OpenShiftClientFactory clientFactory;
|
||||
|
||||
private final UserManager userManager;
|
||||
|
|
@ -55,12 +54,11 @@ public class OpenshiftTokenInitializationFilter
|
|||
SessionStore sessionStore,
|
||||
RequestTokenExtractor tokenExtractor,
|
||||
OpenShiftClientFactory clientFactory,
|
||||
UserManager userManager,
|
||||
PermissionChecker permissionChecker) {
|
||||
UserManager userManager) {
|
||||
super(sessionStore, tokenExtractor);
|
||||
this.clientFactory = clientFactory;
|
||||
this.userManager = userManager;
|
||||
this.permissionChecker = permissionChecker;
|
||||
// this.permissionChecker = permissionChecker;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -92,8 +90,7 @@ public class OpenshiftTokenInitializationFilter
|
|||
try {
|
||||
ObjectMeta userMeta = osu.getMetadata();
|
||||
User user = userManager.getOrCreateUser(getUserId(osu), userMeta.getName());
|
||||
return new AuthorizedSubject(
|
||||
new SubjectImpl(user.getName(), user.getId(), token, false), permissionChecker);
|
||||
return new AuthorizedSubject(new SubjectImpl(user.getName(), user.getId(), token, false));
|
||||
} catch (ServerException | ConflictException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,253 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2023 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.workspace.infrastructure.openshift.multiuser.oauth;
|
||||
|
||||
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.CLIENT_ID_SETTING;
|
||||
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING;
|
||||
import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.AUTH_SERVER_URL_SETTING;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertSame;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
import com.google.inject.Provider;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.UnauthorizedException;
|
||||
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
|
||||
import org.eclipse.che.api.workspace.server.WorkspaceRuntimes;
|
||||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
|
||||
import org.eclipse.che.api.workspace.server.spi.RuntimeContext;
|
||||
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.keycloak.server.KeycloakServiceClient;
|
||||
import org.eclipse.che.multiuser.keycloak.server.KeycloakSettings;
|
||||
import org.eclipse.che.multiuser.keycloak.shared.dto.KeycloakTokenResponse;
|
||||
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;
|
||||
|
||||
/** @author David Festal */
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class KeycloakProviderConfigFactoryTest {
|
||||
private static final String PROVIDER = "openshift-v3";
|
||||
private static final String THE_USER_ID = "a_user_id";
|
||||
private static final String ANOTHER_USER_ID = "another_user_id";
|
||||
private static final String A_WORKSPACE_ID = "workspace_id";
|
||||
private static final String FULL_SCOPE = "user:full";
|
||||
private static final String ACCESS_TOKEN = "accessToken";
|
||||
private static final String AUTH_SERVER_URL = "http://keycloak.url/auth";
|
||||
private static final String REALM = "realm";
|
||||
private static final String CLIENT_ID = "clientId";
|
||||
private static final String API_ENDPOINT = "http://che-host/api";
|
||||
|
||||
private static final String SHOULD_LINK_ERROR_MESSAGE =
|
||||
"You should link your account with the <strong>"
|
||||
+ PROVIDER
|
||||
+ "</strong> \n"
|
||||
+ "identity provider by visiting the "
|
||||
+ "<a href='"
|
||||
+ AUTH_SERVER_URL
|
||||
+ "/realms/"
|
||||
+ REALM
|
||||
+ "/account/identity?referrer="
|
||||
+ CLIENT_ID
|
||||
+ "&referrer_uri="
|
||||
+ "http%3A%2F%2Fche-host%2Fdashboard%2F%3Fredirect_fragment%3D%2Fworkspaces'"
|
||||
+ " target='_blank' rel='noopener noreferrer'><strong>Federated Identities</strong></a> page of your Che account";
|
||||
|
||||
private static final String SESSION_EXPIRED_MESSAGE =
|
||||
"Your session has expired. \nPlease "
|
||||
+ "<a href='javascript:location.reload();' target='_top'>"
|
||||
+ "login"
|
||||
+ "</a> to Che again to get access to your OpenShift account";
|
||||
|
||||
private static final Map<String, String> keycloakSettingsMap = new HashMap<String, String>();
|
||||
|
||||
@Mock private KeycloakServiceClient keycloakServiceClient;
|
||||
@Mock private KeycloakSettings keycloakSettings;
|
||||
@Mock private Provider<WorkspaceRuntimes> workspaceRuntimeProvider;
|
||||
@Mock private WorkspaceRuntimes workspaceRuntimes;
|
||||
@Mock private Subject subject;
|
||||
@Mock private RuntimeIdentity runtimeIdentity;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Mock
|
||||
private RuntimeContext runtimeContext;
|
||||
|
||||
@Mock private KeycloakTokenResponse tokenResponse;
|
||||
|
||||
private EnvironmentContext context;
|
||||
private KeycloakProviderConfigFactory configBuilder;
|
||||
private Config defaultConfig;
|
||||
|
||||
static {
|
||||
keycloakSettingsMap.put(AUTH_SERVER_URL_SETTING, AUTH_SERVER_URL);
|
||||
keycloakSettingsMap.put(REALM_SETTING, REALM);
|
||||
keycloakSettingsMap.put(CLIENT_ID_SETTING, CLIENT_ID);
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
when(keycloakSettings.get()).thenReturn(keycloakSettingsMap);
|
||||
context = spy(EnvironmentContext.getCurrent());
|
||||
EnvironmentContext.setCurrent(context);
|
||||
lenient().doReturn(subject).when(context).getSubject();
|
||||
lenient().when(workspaceRuntimeProvider.get()).thenReturn(workspaceRuntimes);
|
||||
lenient()
|
||||
.when(workspaceRuntimes.getRuntimeContext(anyString()))
|
||||
.thenReturn(Optional.<RuntimeContext>ofNullable(runtimeContext));
|
||||
lenient().when(runtimeContext.getIdentity()).thenReturn(runtimeIdentity);
|
||||
lenient().when(runtimeIdentity.getOwnerId()).thenReturn(THE_USER_ID);
|
||||
lenient().when(subject.getUserId()).thenReturn(THE_USER_ID);
|
||||
lenient().when(tokenResponse.getScope()).thenReturn(FULL_SCOPE);
|
||||
lenient().when(tokenResponse.getAccessToken()).thenReturn(ACCESS_TOKEN);
|
||||
|
||||
configBuilder =
|
||||
new KeycloakProviderConfigFactory(
|
||||
keycloakServiceClient,
|
||||
keycloakSettings,
|
||||
workspaceRuntimeProvider,
|
||||
PROVIDER,
|
||||
API_ENDPOINT,
|
||||
null,
|
||||
null);
|
||||
defaultConfig = new io.fabric8.kubernetes.client.ConfigBuilder().build();
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
public void cleanup() {
|
||||
EnvironmentContext.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFallbackToDefaultConfigWhenProvideIsNull() throws Exception {
|
||||
configBuilder =
|
||||
new KeycloakProviderConfigFactory(
|
||||
keycloakServiceClient,
|
||||
keycloakSettings,
|
||||
workspaceRuntimeProvider,
|
||||
null,
|
||||
API_ENDPOINT,
|
||||
null,
|
||||
null);
|
||||
assertSame(defaultConfig, configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFallbackToDefaultConfigWhenSubjectIsAnonymous() throws Exception {
|
||||
doReturn(Subject.ANONYMOUS).when(context).getSubject();
|
||||
assertSame(defaultConfig, configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFallbackToDefaultConfigWhenCurrentUserIsDifferentFromWorkspaceOwner()
|
||||
throws Exception {
|
||||
when(runtimeIdentity.getOwnerId()).thenReturn(ANOTHER_USER_ID);
|
||||
assertSame(defaultConfig, configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID));
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testCreateUserConfigWhenNoRuntimeContext() throws Exception {
|
||||
when(keycloakServiceClient.getIdentityProviderToken(anyString())).thenReturn(tokenResponse);
|
||||
when(workspaceRuntimes.getRuntimeContext(anyString())).thenReturn(Optional.empty());
|
||||
|
||||
Config resultConfig = configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID);
|
||||
assertEquals(resultConfig.getOauthToken(), ACCESS_TOKEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUserConfigWhenWorkspaceIdIsNull() throws Exception {
|
||||
when(keycloakServiceClient.getIdentityProviderToken(anyString())).thenReturn(tokenResponse);
|
||||
Config resultConfig = configBuilder.buildConfig(defaultConfig, null);
|
||||
assertEquals(resultConfig.getOauthToken(), ACCESS_TOKEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUserConfig() throws Exception {
|
||||
when(keycloakServiceClient.getIdentityProviderToken(anyString())).thenReturn(tokenResponse);
|
||||
Config resultConfig = configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID);
|
||||
assertEquals(resultConfig.getOauthToken(), ACCESS_TOKEN);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = {InfrastructureException.class})
|
||||
public void testThrowOnBadScope() throws Exception {
|
||||
when(keycloakServiceClient.getIdentityProviderToken(anyString())).thenReturn(tokenResponse);
|
||||
when(tokenResponse.getScope()).thenReturn("bad:scope");
|
||||
Config resultConfig = configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID);
|
||||
assertEquals(resultConfig.getOauthToken(), ACCESS_TOKEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRethrowOnUnauthorizedException() throws Exception {
|
||||
doThrow(
|
||||
new UnauthorizedException(
|
||||
DtoFactory.newDto(ServiceError.class).withMessage("Any other message")))
|
||||
.when(keycloakServiceClient)
|
||||
.getIdentityProviderToken(anyString());
|
||||
try {
|
||||
configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID);
|
||||
} catch (InfrastructureException e) {
|
||||
assertEquals(e.getMessage(), SHOULD_LINK_ERROR_MESSAGE, "The exception message is wrong");
|
||||
return;
|
||||
}
|
||||
fail(
|
||||
"Should have thrown an exception with the following message: " + SHOULD_LINK_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = {InfrastructureException.class})
|
||||
public void testRethrowOnBadRequestException() throws Exception {
|
||||
doThrow(
|
||||
new BadRequestException(
|
||||
DtoFactory.newDto(ServiceError.class).withMessage("Any other message")))
|
||||
.when(keycloakServiceClient)
|
||||
.getIdentityProviderToken(anyString());
|
||||
configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRethrowOnInvalidTokenBadRequestException() throws Exception {
|
||||
doThrow(
|
||||
new BadRequestException(
|
||||
DtoFactory.newDto(ServiceError.class).withMessage("Invalid token.")))
|
||||
.when(keycloakServiceClient)
|
||||
.getIdentityProviderToken(anyString());
|
||||
try {
|
||||
configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID);
|
||||
} catch (InfrastructureException e) {
|
||||
assertEquals(e.getMessage(), SESSION_EXPIRED_MESSAGE, "The exception message is wrong");
|
||||
return;
|
||||
}
|
||||
fail("Should have thrown an exception with the following message: " + SESSION_EXPIRED_MESSAGE);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = {InfrastructureException.class})
|
||||
public void testRethrowOnAnyException() throws Exception {
|
||||
when(keycloakServiceClient.getIdentityProviderToken(anyString()))
|
||||
.thenThrow(org.eclipse.che.api.core.NotFoundException.class);
|
||||
configBuilder.buildConfig(defaultConfig, A_WORKSPACE_ID);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* Copyright (c) 2012-2024 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/
|
||||
|
|
@ -26,9 +26,8 @@ import org.eclipse.che.api.user.server.UserManager;
|
|||
import org.eclipse.che.api.user.server.model.impl.UserImpl;
|
||||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.SessionStore;
|
||||
import org.eclipse.che.multiuser.api.authentication.commons.token.RequestTokenExtractor;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.RequestTokenExtractor;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.SessionStore;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
|
|
@ -41,7 +40,7 @@ public class OpenshiftTokenInitializationFilterTest {
|
|||
@Mock private SessionStore sessionStore;
|
||||
@Mock private RequestTokenExtractor tokenExtractor;
|
||||
@Mock private UserManager userManager;
|
||||
@Mock private PermissionChecker permissionChecker;
|
||||
// @Mock private PermissionChecker permissionChecker;
|
||||
|
||||
@Mock private OpenShiftClientFactory openShiftClientFactory;
|
||||
@Mock private OpenShiftClient openShiftClient;
|
||||
|
|
@ -58,7 +57,7 @@ public class OpenshiftTokenInitializationFilterTest {
|
|||
public void setUp() throws InfrastructureException {
|
||||
openshiftTokenInitializationFilter =
|
||||
new OpenshiftTokenInitializationFilter(
|
||||
sessionStore, tokenExtractor, openShiftClientFactory, userManager, permissionChecker);
|
||||
sessionStore, tokenExtractor, openShiftClientFactory, userManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2024 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
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>che-multiuser-api</artifactId>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<version>7.86.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>che-multiuser-api-authentication-commons</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Che Multiuser :: API :: Authentication Commons</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.inject</groupId>
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.api.authentication.commons;
|
||||
|
||||
/** Auth-related constants. */
|
||||
public class Constants {
|
||||
|
||||
/** Name of the subject attribute in the Http session */
|
||||
public static final String CHE_SUBJECT_ATTRIBUTE = "che_subject";
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.api.authentication.commons;
|
||||
|
||||
import static org.eclipse.che.multiuser.api.authentication.commons.Constants.CHE_SUBJECT_ATTRIBUTE;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.http.HttpSessionEvent;
|
||||
import jakarta.servlet.http.HttpSessionListener;
|
||||
import java.util.Optional;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/** Purges deleted sessions from sessions cache store. */
|
||||
public class DestroySessionListener implements HttpSessionListener {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DestroySessionListener.class);
|
||||
|
||||
@Override
|
||||
public final void sessionCreated(HttpSessionEvent sessionEvent) {}
|
||||
|
||||
@Override
|
||||
public void sessionDestroyed(HttpSessionEvent sessionEvent) {
|
||||
|
||||
ServletContext servletContext = sessionEvent.getSession().getServletContext();
|
||||
|
||||
Optional<SessionStore> sessionStoreOptional = getSessionStoreInstance(servletContext);
|
||||
if (!sessionStoreOptional.isPresent()) {
|
||||
LOG.error(
|
||||
"Unable to remove session from store. Session store is not configured in servlet context.");
|
||||
return;
|
||||
}
|
||||
SessionStore sessionStore = sessionStoreOptional.get();
|
||||
Subject subject = (Subject) sessionEvent.getSession().getAttribute(CHE_SUBJECT_ATTRIBUTE);
|
||||
if (subject != null) {
|
||||
sessionStore.remove(subject.getUserId());
|
||||
}
|
||||
}
|
||||
|
||||
/** Searches session store component in servlet context when with help of guice injector. */
|
||||
private Optional<SessionStore> getSessionStoreInstance(ServletContext servletContext) {
|
||||
String attributeName = SessionStore.class.getName();
|
||||
SessionStore result = (SessionStore) servletContext.getAttribute(attributeName);
|
||||
if (result == null) {
|
||||
Injector injector = (Injector) servletContext.getAttribute(Injector.class.getName());
|
||||
if (injector != null) {
|
||||
result = injector.getInstance(SessionStore.class);
|
||||
if (result != null) {
|
||||
servletContext.setAttribute(attributeName, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.ofNullable(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.api.authentication.commons.token;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Try to extract token from request in 3 steps. 1. From query parameter. 2. From header. 3. From
|
||||
* cookie.
|
||||
*
|
||||
* @author Sergii Kabashniuk
|
||||
*/
|
||||
public class ChainedTokenExtractor implements RequestTokenExtractor {
|
||||
|
||||
private final HeaderRequestTokenExtractor headerRequestTokenExtractor;
|
||||
|
||||
private final QueryRequestTokenExtractor queryRequestTokenExtractor;
|
||||
|
||||
public ChainedTokenExtractor() {
|
||||
headerRequestTokenExtractor = new HeaderRequestTokenExtractor();
|
||||
queryRequestTokenExtractor = new QueryRequestTokenExtractor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToken(HttpServletRequest req) {
|
||||
String token;
|
||||
if ((token = queryRequestTokenExtractor.getToken(req)) == null) {
|
||||
token = headerRequestTokenExtractor.getToken(req);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.api.authentication.commons.token;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/** @author Max Shaposhnik (mshaposh@redhat.com) */
|
||||
public class QueryRequestTokenExtractor implements RequestTokenExtractor {
|
||||
@Override
|
||||
public String getToken(HttpServletRequest req) {
|
||||
String query = req.getQueryString();
|
||||
if (query != null) {
|
||||
int start = query.indexOf("&token=");
|
||||
if (start != -1 || query.startsWith("token=")) {
|
||||
int end = query.indexOf('&', start + 7);
|
||||
if (end == -1) {
|
||||
end = query.length();
|
||||
}
|
||||
if (end != start + 7) {
|
||||
return query.substring(start + 7, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.api.authentication.commons.token;
|
||||
|
||||
import static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class HeaderRequestTokenExtractorTest {
|
||||
|
||||
private HeaderRequestTokenExtractor tokenExtractor = new HeaderRequestTokenExtractor();
|
||||
|
||||
@Mock HttpServletRequest servletRequest;
|
||||
|
||||
@Test(dataProvider = "validHeadersProvider")
|
||||
public void shouldExtractTokensFromValidHeaders(String headerValue, String expectedToken) {
|
||||
|
||||
when(servletRequest.getHeader(eq(AUTHORIZATION))).thenReturn(headerValue);
|
||||
|
||||
// when
|
||||
String token = tokenExtractor.getToken(servletRequest);
|
||||
|
||||
// then
|
||||
assertEquals(token, expectedToken);
|
||||
}
|
||||
|
||||
@Test(
|
||||
dataProvider = "invalidHeadersProvider",
|
||||
expectedExceptions = BadRequestException.class,
|
||||
expectedExceptionsMessageRegExp = "Invalid authorization header format.")
|
||||
public void shouldThrowExceptionOnInvalidToken(String headerValue) {
|
||||
|
||||
when(servletRequest.getHeader(eq(AUTHORIZATION))).thenReturn(headerValue);
|
||||
|
||||
// when
|
||||
tokenExtractor.getToken(servletRequest);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
private Object[][] validHeadersProvider() {
|
||||
return new Object[][] {
|
||||
{"token123", "token123"},
|
||||
{"bearer token123", "token123"},
|
||||
{"Bearer token123", "token123"},
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
private Object[][] invalidHeadersProvider() {
|
||||
return new Object[][] {{"bearertoken123"}, {"bearer token123"}, {"bearer token 123"}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2024 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
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>che-multiuser-api</artifactId>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<version>7.86.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>che-multiuser-api-authorization-impl</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Che Multiuser :: API :: Authorization Impl</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.inject</groupId>
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-authorization</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission-shared</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* 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.api.permission.server;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
|
||||
/**
|
||||
* Implementation of {@link PermissionChecker} that use {@link PermissionsManager} for checking.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public class PermissionCheckerImpl implements PermissionChecker {
|
||||
private final PermissionsManager permissionsManager;
|
||||
|
||||
@Inject
|
||||
public PermissionCheckerImpl(PermissionsManager permissionsManager) {
|
||||
this.permissionsManager = permissionsManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String user, String domain, String instance, String action)
|
||||
throws ServerException, NotFoundException, ConflictException {
|
||||
return permissionsManager.exists(user, domain, instance, action)
|
||||
|| permissionsManager.exists("*", domain, instance, action);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.api.permission.server;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.ArgumentMatchers.anyObject;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.RETURNS_DEFAULTS;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import org.eclipse.che.api.core.rest.HttpJsonRequest;
|
||||
import org.eclipse.che.api.core.rest.HttpJsonRequestFactory;
|
||||
import org.eclipse.che.api.core.rest.HttpJsonResponse;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.multiuser.api.permission.shared.dto.PermissionsDto;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpPermissionCheckerImpl}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class HttpPermissionCheckerImplTest {
|
||||
private static final String API_ENDPOINT = "http://localhost:8000/api";
|
||||
|
||||
@Mock private HttpJsonRequestFactory requestFactory;
|
||||
@Mock private HttpJsonResponse response;
|
||||
private HttpJsonRequest request;
|
||||
|
||||
private HttpPermissionCheckerImpl httpPermissionChecker;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
request =
|
||||
mock(
|
||||
HttpJsonRequest.class,
|
||||
(Answer)
|
||||
invocation -> {
|
||||
if (invocation.getMethod().getReturnType().isInstance(invocation.getMock())) {
|
||||
return invocation.getMock();
|
||||
}
|
||||
return RETURNS_DEFAULTS.answer(invocation);
|
||||
});
|
||||
when(request.request()).thenReturn(response);
|
||||
when(requestFactory.fromUrl(anyString())).thenReturn(request);
|
||||
|
||||
httpPermissionChecker = new HttpPermissionCheckerImpl(API_ENDPOINT, requestFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckPermissionsByHttpRequestToPermissionsService() throws Exception {
|
||||
when(response.asDto(anyObject()))
|
||||
.thenReturn(
|
||||
DtoFactory.newDto(PermissionsDto.class)
|
||||
.withUserId("user123")
|
||||
.withDomainId("domain123")
|
||||
.withInstanceId("instance123")
|
||||
.withActions(asList("read", "test")));
|
||||
|
||||
final boolean hasPermission =
|
||||
httpPermissionChecker.hasPermission("user123", "domain123", "instance123", "test");
|
||||
|
||||
assertEquals(hasPermission, true);
|
||||
verify(requestFactory)
|
||||
.fromUrl(
|
||||
eq(
|
||||
UriBuilder.fromUri(API_ENDPOINT)
|
||||
.path(PermissionsService.class)
|
||||
.path(PermissionsService.class, "getCurrentUsersPermissions")
|
||||
.queryParam("instance", "instance123")
|
||||
.build("domain123")
|
||||
.toString()));
|
||||
verify(request).useGetMethod();
|
||||
verify(request).request();
|
||||
verifyNoMoreInteractions(request);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* 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.api.permission.server;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class PermissionCheckerImplTest {
|
||||
@Mock private PermissionsManager permissionsManager;
|
||||
|
||||
@InjectMocks private PermissionCheckerImpl permissionChecker;
|
||||
|
||||
@Test
|
||||
public void shouldCheckExistingDirectUsersPermissions() throws Exception {
|
||||
when(permissionsManager.exists(anyString(), anyString(), anyString(), anyString()))
|
||||
.thenReturn(true);
|
||||
|
||||
boolean hasPermission =
|
||||
permissionChecker.hasPermission("user123", "domain123", "instance123", "test");
|
||||
|
||||
assertEquals(hasPermission, true);
|
||||
verify(permissionsManager).exists("user123", "domain123", "instance123", "test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckExistingPublicPermissionsIfThereIsNoDirectUsersPermissions()
|
||||
throws Exception {
|
||||
doReturn(false)
|
||||
.when(permissionsManager)
|
||||
.exists(eq("user123"), anyString(), anyString(), anyString());
|
||||
doReturn(true).when(permissionsManager).exists(eq("*"), anyString(), anyString(), anyString());
|
||||
|
||||
boolean hasPermission =
|
||||
permissionChecker.hasPermission("user123", "domain123", "instance123", "test");
|
||||
|
||||
assertEquals(hasPermission, true);
|
||||
verify(permissionsManager).exists("user123", "domain123", "instance123", "test");
|
||||
verify(permissionsManager).exists("*", "domain123", "instance123", "test");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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
|
||||
|
||||
-->
|
||||
<configuration>
|
||||
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="file" class="ch.qos.logback.core.FileAppender">
|
||||
<File>target/log/authorization-impl.log</File>
|
||||
<encoder>
|
||||
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="stdout"/>
|
||||
<appender-ref ref="file"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2024 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
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>che-multiuser-api</artifactId>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<version>7.86.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>che-multiuser-api-authorization</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Che Multiuser :: API :: Authorization</name>
|
||||
<properties>
|
||||
<dto-generator-out-directory>${project.build.directory}/generated-sources/dto/</dto-generator-out-directory>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.inject</groupId>
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>${dto-generator-out-directory}</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission-shared</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<dtoPackages>
|
||||
<package>org.eclipse.che.api.permission.shared.dto</package>
|
||||
</dtoPackages>
|
||||
<outputDirectory>${dto-generator-out-directory}</outputDirectory>
|
||||
<genClassName>org.eclipse.che.multiuser.api.permission.server.dto.DtoServerImpls</genClassName>
|
||||
<impl>server</impl>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>pre-compile</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-domain</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>add-resource</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${dto-generator-out-directory}/META-INF</directory>
|
||||
<targetPath>META-INF</targetPath>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${dto-generator-out-directory}</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.api.permission.server;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.rest.HttpJsonRequestFactory;
|
||||
import org.eclipse.che.multiuser.api.permission.shared.dto.PermissionsDto;
|
||||
|
||||
/**
|
||||
* Implementation of {@link PermissionChecker} that load permissions by http requests to {@link
|
||||
* PermissionsService}
|
||||
*
|
||||
* <p>It also caches permissions to avoid frequently requests to workspace master.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class HttpPermissionCheckerImpl implements PermissionChecker {
|
||||
private final LoadingCache<Key, Set<String>> permissionsCache;
|
||||
|
||||
@Inject
|
||||
public HttpPermissionCheckerImpl(
|
||||
@Named("che.api") String apiEndpoint, HttpJsonRequestFactory requestFactory) {
|
||||
// TODO mb make configurable size of cache and expiration time
|
||||
this.permissionsCache =
|
||||
CacheBuilder.newBuilder()
|
||||
.maximumSize(1000)
|
||||
.expireAfterWrite(1, TimeUnit.MINUTES)
|
||||
.build(
|
||||
new CacheLoader<Key, Set<String>>() {
|
||||
@Override
|
||||
public Set<String> load(Key key) throws Exception {
|
||||
UriBuilder currentUsersPermissions =
|
||||
UriBuilder.fromUri(apiEndpoint).path("permissions/" + key.domain);
|
||||
if (key.instance != null) {
|
||||
currentUsersPermissions.queryParam("instance", key.instance);
|
||||
}
|
||||
String userPermissionsUrl = currentUsersPermissions.build().toString();
|
||||
try {
|
||||
PermissionsDto usersPermissions =
|
||||
requestFactory
|
||||
.fromUrl(userPermissionsUrl)
|
||||
.useGetMethod()
|
||||
.request()
|
||||
.asDto(PermissionsDto.class);
|
||||
return new HashSet<>(usersPermissions.getActions());
|
||||
} catch (NotFoundException e) {
|
||||
// user doesn't have permissions
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String user, String domain, String instance, String action)
|
||||
throws ServerException {
|
||||
try {
|
||||
return permissionsCache.get(new Key(user, domain, instance)).contains(action);
|
||||
} catch (Exception e) {
|
||||
throw new ServerException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Key {
|
||||
private final String user;
|
||||
private final String domain;
|
||||
private final String instance;
|
||||
|
||||
private Key(String user, String domain, String instance) {
|
||||
this.user = user;
|
||||
this.domain = domain;
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Key)) {
|
||||
return false;
|
||||
}
|
||||
final Key other = (Key) obj;
|
||||
return Objects.equals(user, other.user)
|
||||
&& Objects.equals(domain, other.domain)
|
||||
&& Objects.equals(instance, other.instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = hash * 31 + Objects.hashCode(user);
|
||||
hash = hash * 31 + Objects.hashCode(domain);
|
||||
hash = hash * 31 + Objects.hashCode(instance);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* 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.api.permission.server;
|
||||
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
|
||||
/**
|
||||
* Checks user's permission to perform some action with particular instance of given domain.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public interface PermissionChecker {
|
||||
/**
|
||||
* Checks user's permission to perform some action with particular instance.
|
||||
*
|
||||
* @param user user id
|
||||
* @param domain domain id
|
||||
* @param instance instance id
|
||||
* @param action action name
|
||||
* @return true if the user has given permission
|
||||
* @throws NotFoundException when given domain is unsupported
|
||||
* @throws ConflictException when given domain requires non nullable value for instance but it is
|
||||
* null
|
||||
* @throws ServerException when any other error occurs during permission existence checking
|
||||
*/
|
||||
boolean hasPermission(String user, String domain, String instance, String action)
|
||||
throws ServerException, NotFoundException, ConflictException;
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.api.permission.server;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.ArgumentMatchers.anyObject;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.RETURNS_DEFAULTS;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import org.eclipse.che.api.core.rest.HttpJsonRequest;
|
||||
import org.eclipse.che.api.core.rest.HttpJsonRequestFactory;
|
||||
import org.eclipse.che.api.core.rest.HttpJsonResponse;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.multiuser.api.permission.shared.dto.PermissionsDto;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpPermissionCheckerImpl}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class HttpPermissionCheckerImplTest {
|
||||
private static final String API_ENDPOINT = "http://localhost:8000/api";
|
||||
|
||||
@Mock private HttpJsonRequestFactory requestFactory;
|
||||
@Mock private HttpJsonResponse response;
|
||||
private HttpJsonRequest request;
|
||||
|
||||
private HttpPermissionCheckerImpl httpPermissionChecker;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
request =
|
||||
mock(
|
||||
HttpJsonRequest.class,
|
||||
(Answer)
|
||||
invocation -> {
|
||||
if (invocation.getMethod().getReturnType().isInstance(invocation.getMock())) {
|
||||
return invocation.getMock();
|
||||
}
|
||||
return RETURNS_DEFAULTS.answer(invocation);
|
||||
});
|
||||
when(request.request()).thenReturn(response);
|
||||
when(requestFactory.fromUrl(anyString())).thenReturn(request);
|
||||
|
||||
httpPermissionChecker = new HttpPermissionCheckerImpl(API_ENDPOINT, requestFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckPermissionsByHttpRequestToPermissionsService() throws Exception {
|
||||
when(response.asDto(anyObject()))
|
||||
.thenReturn(
|
||||
DtoFactory.newDto(PermissionsDto.class)
|
||||
.withUserId("user123")
|
||||
.withDomainId("domain123")
|
||||
.withInstanceId("instance123")
|
||||
.withActions(asList("read", "test")));
|
||||
|
||||
final boolean hasPermission =
|
||||
httpPermissionChecker.hasPermission("user123", "domain123", "instance123", "test");
|
||||
|
||||
assertEquals(hasPermission, true);
|
||||
verify(requestFactory)
|
||||
.fromUrl(
|
||||
eq(
|
||||
UriBuilder.fromUri(API_ENDPOINT)
|
||||
.path(PermissionsService.class)
|
||||
.path(PermissionsService.class, "getCurrentUsersPermissions")
|
||||
.queryParam("instance", "instance123")
|
||||
.build("domain123")
|
||||
.toString()));
|
||||
verify(request).useGetMethod();
|
||||
verify(request).request();
|
||||
verifyNoMoreInteractions(request);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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
|
||||
|
||||
-->
|
||||
<configuration>
|
||||
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="file" class="ch.qos.logback.core.FileAppender">
|
||||
<File>target/log/api-authorization.log</File>
|
||||
<encoder>
|
||||
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="stdout"/>
|
||||
<appender-ref ref="file"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2024 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
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>che-multiuser-api</artifactId>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<version>7.86.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>che-multiuser-api-organization-shared</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Che Multiuser :: Organization :: Shared</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-user-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-resource-shared</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared;
|
||||
|
||||
/**
|
||||
* Constants for Organization API
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public final class Constants {
|
||||
public static final String LINK_REL_SELF = "self";
|
||||
public static final String LINK_REL_SUBORGANIZATIONS = "organization.suborganizations";
|
||||
|
||||
private Constants() {}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.dto;
|
||||
|
||||
import org.eclipse.che.api.core.notification.EventOrigin;
|
||||
import org.eclipse.che.api.user.shared.dto.UserDto;
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
|
||||
/**
|
||||
* DTO for member added event.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@DTO
|
||||
@EventOrigin("organization")
|
||||
public interface MemberAddedEventDto extends OrganizationEventDto {
|
||||
|
||||
@Override
|
||||
MemberAddedEventDto withOrganization(OrganizationDto organization);
|
||||
|
||||
@Override
|
||||
MemberAddedEventDto withType(EventType eventType);
|
||||
|
||||
UserDto getMember();
|
||||
|
||||
void setMember(UserDto member);
|
||||
|
||||
MemberAddedEventDto withMember(UserDto member);
|
||||
|
||||
/** Returns name of user who initiated member invitation */
|
||||
String getInitiator();
|
||||
|
||||
void setInitiator(String initiator);
|
||||
|
||||
MemberAddedEventDto withInitiator(String initiator);
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.dto;
|
||||
|
||||
import org.eclipse.che.api.core.notification.EventOrigin;
|
||||
import org.eclipse.che.api.user.shared.dto.UserDto;
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
|
||||
/**
|
||||
* DTO for organization member removed event.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@DTO
|
||||
@EventOrigin("organization")
|
||||
public interface MemberRemovedEventDto extends OrganizationEventDto {
|
||||
|
||||
@Override
|
||||
MemberRemovedEventDto withOrganization(OrganizationDto organization);
|
||||
|
||||
@Override
|
||||
MemberRemovedEventDto withType(EventType eventType);
|
||||
|
||||
UserDto getMember();
|
||||
|
||||
void setMember(UserDto member);
|
||||
|
||||
MemberRemovedEventDto withMember(UserDto member);
|
||||
|
||||
/** Returns name of user who initiated member removal */
|
||||
String getInitiator();
|
||||
|
||||
void setInitiator(String initiator);
|
||||
|
||||
MemberRemovedEventDto withInitiator(String initiator);
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.dto;
|
||||
|
||||
import java.util.List;
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.OrganizationDistributedResources;
|
||||
import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto;
|
||||
|
||||
/** @author Sergii Leschenko */
|
||||
@DTO
|
||||
public interface OrganizationDistributedResourcesDto extends OrganizationDistributedResources {
|
||||
@Override
|
||||
String getOrganizationId();
|
||||
|
||||
void setOrganizationId(String organizationId);
|
||||
|
||||
OrganizationDistributedResourcesDto withOrganizationId(String organizationId);
|
||||
|
||||
@Override
|
||||
List<ResourceDto> getResourcesCap();
|
||||
|
||||
void setResourcesCap(List<ResourceDto> resourcesCap);
|
||||
|
||||
OrganizationDistributedResourcesDto withResourcesCap(List<ResourceDto> resourcesCap);
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.dto;
|
||||
|
||||
import java.util.List;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.Hyperlinks;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.Link;
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/** @author Sergii Leschenko */
|
||||
@DTO
|
||||
public interface OrganizationDto extends Organization, Hyperlinks {
|
||||
@Override
|
||||
String getId();
|
||||
|
||||
void setId(String id);
|
||||
|
||||
OrganizationDto withId(String id);
|
||||
|
||||
@Override
|
||||
String getName();
|
||||
|
||||
void setName(String name);
|
||||
|
||||
OrganizationDto withName(String name);
|
||||
|
||||
@Override
|
||||
String getQualifiedName();
|
||||
|
||||
void setQualifiedName(String qualifiedName);
|
||||
|
||||
OrganizationDto withQualifiedName(String qualifiedName);
|
||||
|
||||
@Override
|
||||
String getParent();
|
||||
|
||||
void setParent(String parent);
|
||||
|
||||
OrganizationDto withParent(String parent);
|
||||
|
||||
@Override
|
||||
OrganizationDto withLinks(List<Link> links);
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.dto;
|
||||
|
||||
import org.eclipse.che.api.core.notification.EventOrigin;
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.OrganizationEvent;
|
||||
|
||||
/**
|
||||
* DTO for {@link OrganizationEvent}.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@DTO
|
||||
@EventOrigin("organization")
|
||||
public interface OrganizationEventDto extends OrganizationEvent {
|
||||
|
||||
@Override
|
||||
OrganizationDto getOrganization();
|
||||
|
||||
void setOrganization(OrganizationDto organization);
|
||||
|
||||
OrganizationEventDto withOrganization(OrganizationDto organization);
|
||||
|
||||
void setType(EventType eventType);
|
||||
|
||||
OrganizationEventDto withType(EventType eventType);
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.dto;
|
||||
|
||||
import java.util.List;
|
||||
import org.eclipse.che.api.core.notification.EventOrigin;
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
|
||||
/**
|
||||
* DTO for organization removed event.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@DTO
|
||||
@EventOrigin("organization")
|
||||
public interface OrganizationRemovedEventDto extends OrganizationEventDto {
|
||||
|
||||
@Override
|
||||
OrganizationRemovedEventDto withOrganization(OrganizationDto organization);
|
||||
|
||||
@Override
|
||||
OrganizationRemovedEventDto withType(EventType eventType);
|
||||
|
||||
/** Returns name of user who initiated organization removal */
|
||||
String getInitiator();
|
||||
|
||||
void setInitiator(String initiator);
|
||||
|
||||
OrganizationRemovedEventDto withInitiator(String initiator);
|
||||
|
||||
List<String> getMembers();
|
||||
|
||||
void setMembers(List<String> members);
|
||||
|
||||
OrganizationRemovedEventDto withMembers(List<String> members);
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.dto;
|
||||
|
||||
import org.eclipse.che.api.core.notification.EventOrigin;
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
|
||||
/**
|
||||
* DTO for organization renamed event.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@DTO
|
||||
@EventOrigin("organization")
|
||||
public interface OrganizationRenamedEventDto extends OrganizationEventDto {
|
||||
|
||||
@Override
|
||||
OrganizationRenamedEventDto withOrganization(OrganizationDto organization);
|
||||
|
||||
@Override
|
||||
OrganizationRenamedEventDto withType(EventType eventType);
|
||||
|
||||
/** Returns organization name before renaming */
|
||||
String getOldName();
|
||||
|
||||
void setOldName(String oldName);
|
||||
|
||||
OrganizationRenamedEventDto withOldName(String oldName);
|
||||
|
||||
/** Returns organization name after renaming */
|
||||
String getNewName();
|
||||
|
||||
void setNewName(String newName);
|
||||
|
||||
OrganizationRenamedEventDto withNewName(String newName);
|
||||
|
||||
/** Returns name of user who initiated organization rename */
|
||||
String getInitiator();
|
||||
|
||||
void setInitiator(String initiator);
|
||||
|
||||
OrganizationRenamedEventDto withInitiator(String initiator);
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.event;
|
||||
|
||||
/**
|
||||
* Defines organizations event types.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
public enum EventType {
|
||||
|
||||
/** Published when organization name changed. */
|
||||
ORGANIZATION_RENAMED,
|
||||
|
||||
/** Published when organization removed. */
|
||||
ORGANIZATION_REMOVED,
|
||||
|
||||
/** Published when new member added to organization. */
|
||||
MEMBER_ADDED,
|
||||
|
||||
/** Published when member removed from organization. */
|
||||
MEMBER_REMOVED
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.event;
|
||||
|
||||
import org.eclipse.che.api.core.model.user.User;
|
||||
|
||||
/**
|
||||
* Defines organization member event.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
public interface MemberEvent extends OrganizationEvent {
|
||||
|
||||
/** Returns the member associated with this event. */
|
||||
User getMember();
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.event;
|
||||
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* The base interface for organization event.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
public interface OrganizationEvent {
|
||||
|
||||
/** Returns organization related to this event. */
|
||||
Organization getOrganization();
|
||||
|
||||
/** Returns type of this event. */
|
||||
EventType getType();
|
||||
|
||||
/** Returns name of user who acted with organization or null if user is undefined. */
|
||||
@Nullable
|
||||
String getInitiator();
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Describes relations of user and organization
|
||||
*
|
||||
* @author gazarenkov
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public interface Member {
|
||||
/** Returns id of user */
|
||||
String getUserId();
|
||||
|
||||
/** Returns id of organization */
|
||||
String getOrganizationId();
|
||||
|
||||
/** Returns list of actions that user can perform in organization */
|
||||
List<String> getActions();
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.model;
|
||||
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Describes group of users that can use common resources
|
||||
*
|
||||
* @author gazarenkov
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public interface Organization {
|
||||
|
||||
/**
|
||||
* Returns the identifier of the organization (e.g. "organization0x1234567890"). The identifier
|
||||
* value is unique and mandatory.
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Returns name of organization. The name is mandatory and updatable. The name is unique per
|
||||
* parent organization.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the qualified name that includes all parent's names and the name of current
|
||||
* organization separated by '/' symbol e.g. "parentOrgName/subOrgName/subSubOrgName". The
|
||||
* qualified name is unique.
|
||||
*/
|
||||
String getQualifiedName();
|
||||
|
||||
/**
|
||||
* Returns id of parent organization. The returned value can be nullable in case when organization
|
||||
* is root
|
||||
*/
|
||||
@Nullable
|
||||
String getParent();
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* 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.organization.shared.model;
|
||||
|
||||
import java.util.List;
|
||||
import org.eclipse.che.multiuser.resource.model.Resource;
|
||||
|
||||
/**
|
||||
* Defines resources which are distributed for suborganization by parent organization
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public interface OrganizationDistributedResources {
|
||||
/** Id of organization that owns these distributed resources */
|
||||
String getOrganizationId();
|
||||
|
||||
/**
|
||||
* Returns resources cap that limit usage of parent organization's resources.
|
||||
*
|
||||
* <p>Note that suborganization is not limited to use parent organization's resources if resource
|
||||
* is not capped.
|
||||
*/
|
||||
List<? extends Resource> getResourcesCap();
|
||||
}
|
||||
|
|
@ -1,313 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2024 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
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>che-multiuser-api</artifactId>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<version>7.86.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>che-multiuser-api-organization</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Che Multiuser :: Organization</name>
|
||||
<properties>
|
||||
<dto-generator-out-directory>${project.build.directory}/generated-sources/dto/</dto-generator-out-directory>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-persist</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations-jakarta</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.inject</groupId>
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-account</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-user</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-user-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-lang</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-organization-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-permission-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-resource</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-resource-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>jakarta.persistence</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.everrest</groupId>
|
||||
<artifactId>everrest-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.websocket</groupId>
|
||||
<artifactId>jakarta.websocket-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-sql-schema</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-sql-schema</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>org.eclipse.persistence.core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.everrest</groupId>
|
||||
<artifactId>everrest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.multiuser</groupId>
|
||||
<artifactId>che-multiuser-api-organization-shared</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<dtoPackages>
|
||||
<package>org.eclipse.che.multiuser.organization.shared.dto</package>
|
||||
</dtoPackages>
|
||||
<outputDirectory>${dto-generator-out-directory}</outputDirectory>
|
||||
<genClassName>org.eclipse.che.multiuser.organization.api.dto.DtoServerImpls</genClassName>
|
||||
<impl>server</impl>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>pre-compile</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-domain</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>add-resource</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${dto-generator-out-directory}/META-INF</directory>
|
||||
<targetPath>META-INF</targetPath>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${dto-generator-out-directory}</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Create the test jar -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/spi/tck/*.*</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>resource-dependencies</id>
|
||||
<phase>process-test-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeArtifactIds>che-core-sql-schema,
|
||||
che-multiuser-sql-schema</includeArtifactIds>
|
||||
<includes>che-schema/</includes>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api;
|
||||
|
||||
import static org.eclipse.che.dto.server.DtoFactory.newDto;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import org.eclipse.che.multiuser.organization.api.event.MemberAddedEvent;
|
||||
import org.eclipse.che.multiuser.organization.api.event.MemberRemovedEvent;
|
||||
import org.eclipse.che.multiuser.organization.api.event.OrganizationRemovedEvent;
|
||||
import org.eclipse.che.multiuser.organization.api.event.OrganizationRenamedEvent;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.MemberAddedEventDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.MemberRemovedEventDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDistributedResourcesDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationEventDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationRemovedEventDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationRenamedEventDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.OrganizationEvent;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.OrganizationDistributedResources;
|
||||
|
||||
/**
|
||||
* Helps to convert objects related to organization to DTOs.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public final class DtoConverter {
|
||||
private DtoConverter() {}
|
||||
|
||||
public static OrganizationDto asDto(Organization organization) {
|
||||
return newDto(OrganizationDto.class)
|
||||
.withId(organization.getId())
|
||||
.withName(organization.getName())
|
||||
.withQualifiedName(organization.getQualifiedName())
|
||||
.withParent(organization.getParent());
|
||||
}
|
||||
|
||||
public static OrganizationDistributedResourcesDto asDto(
|
||||
OrganizationDistributedResources distributedResources) {
|
||||
return newDto(OrganizationDistributedResourcesDto.class)
|
||||
.withOrganizationId(distributedResources.getOrganizationId())
|
||||
.withResourcesCap(
|
||||
distributedResources.getResourcesCap().stream()
|
||||
.map(org.eclipse.che.multiuser.resource.api.DtoConverter::asDto)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static OrganizationRemovedEventDto asDto(OrganizationRemovedEvent event) {
|
||||
return newDto(OrganizationRemovedEventDto.class)
|
||||
.withType(event.getType())
|
||||
.withOrganization(asDto(event.getOrganization()))
|
||||
.withMembers(event.getMembers())
|
||||
.withInitiator(event.getInitiator());
|
||||
}
|
||||
|
||||
public static OrganizationRenamedEventDto asDto(OrganizationRenamedEvent event) {
|
||||
return newDto(OrganizationRenamedEventDto.class)
|
||||
.withType(event.getType())
|
||||
.withOrganization(asDto(event.getOrganization()))
|
||||
.withOldName(event.getOldName())
|
||||
.withNewName(event.getNewName())
|
||||
.withInitiator(event.getInitiator());
|
||||
}
|
||||
|
||||
public static MemberAddedEventDto asDto(MemberAddedEvent event) {
|
||||
return newDto(MemberAddedEventDto.class)
|
||||
.withType(event.getType())
|
||||
.withOrganization(asDto(event.getOrganization()))
|
||||
.withInitiator(event.getInitiator())
|
||||
.withMember(org.eclipse.che.api.user.server.DtoConverter.asDto(event.getMember()));
|
||||
}
|
||||
|
||||
public static MemberRemovedEventDto asDto(MemberRemovedEvent event) {
|
||||
return newDto(MemberRemovedEventDto.class)
|
||||
.withType(event.getType())
|
||||
.withOrganization(asDto(event.getOrganization()))
|
||||
.withInitiator((event.getInitiator()))
|
||||
.withMember(org.eclipse.che.api.user.server.DtoConverter.asDto(event.getMember()));
|
||||
}
|
||||
|
||||
public static OrganizationEventDto asDto(OrganizationEvent event) {
|
||||
switch (event.getType()) {
|
||||
case ORGANIZATION_RENAMED:
|
||||
return asDto((OrganizationRenamedEvent) event);
|
||||
case ORGANIZATION_REMOVED:
|
||||
return asDto((OrganizationRemovedEvent) event);
|
||||
case MEMBER_ADDED:
|
||||
return asDto((MemberAddedEvent) event);
|
||||
case MEMBER_REMOVED:
|
||||
return asDto((MemberRemovedEvent) event);
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Can't convert event to dto, event type '" + event.getType() + "' is unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2024 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.organization.api;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.multibindings.MapBinder;
|
||||
import com.google.inject.multibindings.Multibinder;
|
||||
import com.google.inject.name.Names;
|
||||
import org.eclipse.che.multiuser.api.permission.server.SuperPrivilegesChecker;
|
||||
import org.eclipse.che.multiuser.api.permission.server.account.AccountPermissionsChecker;
|
||||
import org.eclipse.che.multiuser.api.permission.shared.model.PermissionsDomain;
|
||||
import org.eclipse.che.multiuser.organization.api.listener.MemberEventsPublisher;
|
||||
import org.eclipse.che.multiuser.organization.api.listener.OrganizationEventsWebsocketBroadcaster;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationPermissionsFilter;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationRemoteSubscriptionPermissionsChecks;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationResourceDistributionServicePermissionsFilter;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationalAccountPermissionsChecker;
|
||||
import org.eclipse.che.multiuser.organization.api.resource.DefaultOrganizationResourcesProvider;
|
||||
import org.eclipse.che.multiuser.organization.api.resource.OrganizationResourceLockKeyProvider;
|
||||
import org.eclipse.che.multiuser.organization.api.resource.OrganizationalAccountAvailableResourcesProvider;
|
||||
import org.eclipse.che.multiuser.organization.api.resource.SuborganizationResourcesProvider;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
import org.eclipse.che.multiuser.resource.api.AvailableResourcesProvider;
|
||||
import org.eclipse.che.multiuser.resource.api.ResourceLockKeyProvider;
|
||||
import org.eclipse.che.multiuser.resource.api.ResourcesProvider;
|
||||
import org.eclipse.che.multiuser.resource.api.free.DefaultResourcesProvider;
|
||||
|
||||
/** @author Sergii Leschenko */
|
||||
public class OrganizationApiModule extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
bind(OrganizationPermissionsFilter.class);
|
||||
bind(OrganizationRemoteSubscriptionPermissionsChecks.class);
|
||||
|
||||
Multibinder.newSetBinder(binder(), DefaultResourcesProvider.class)
|
||||
.addBinding()
|
||||
.to(DefaultOrganizationResourcesProvider.class);
|
||||
|
||||
Multibinder.newSetBinder(binder(), ResourcesProvider.class)
|
||||
.addBinding()
|
||||
.to(SuborganizationResourcesProvider.class);
|
||||
|
||||
MapBinder.newMapBinder(binder(), String.class, AvailableResourcesProvider.class)
|
||||
.addBinding(OrganizationImpl.ORGANIZATIONAL_ACCOUNT)
|
||||
.to(OrganizationalAccountAvailableResourcesProvider.class);
|
||||
|
||||
Multibinder.newSetBinder(binder(), ResourceLockKeyProvider.class)
|
||||
.addBinding()
|
||||
.to(OrganizationResourceLockKeyProvider.class);
|
||||
|
||||
Multibinder.newSetBinder(binder(), AccountPermissionsChecker.class)
|
||||
.addBinding()
|
||||
.to(OrganizationalAccountPermissionsChecker.class);
|
||||
|
||||
bind(OrganizationResourceDistributionServicePermissionsFilter.class);
|
||||
|
||||
bind(OrganizationEventsWebsocketBroadcaster.class).asEagerSingleton();
|
||||
bind(MemberEventsPublisher.class).asEagerSingleton();
|
||||
|
||||
Multibinder.newSetBinder(
|
||||
binder(),
|
||||
PermissionsDomain.class,
|
||||
Names.named(SuperPrivilegesChecker.SUPER_PRIVILEGED_DOMAINS))
|
||||
.addBinding()
|
||||
.to(OrganizationDomain.class);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2024 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.organization.api;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
|
||||
|
||||
/** @author Sergii Leschenko */
|
||||
public class OrganizationJpaModule extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
bind(new TypeLiteral<AbstractPermissionsDomain<MemberImpl>>() {}).to(OrganizationDomain.class);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api;
|
||||
|
||||
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
|
||||
import jakarta.ws.rs.HttpMethod;
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.rest.ServiceContext;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.Link;
|
||||
import org.eclipse.che.api.core.util.LinksHelper;
|
||||
import org.eclipse.che.multiuser.organization.shared.Constants;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
|
||||
|
||||
/**
|
||||
* Helps to inject {@link OrganizationService} related links.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class OrganizationLinksInjector {
|
||||
public OrganizationDto injectLinks(
|
||||
OrganizationDto organizationDto, ServiceContext serviceContext) {
|
||||
final UriBuilder uriBuilder = serviceContext.getBaseUriBuilder();
|
||||
final List<Link> links = new ArrayList<>(2);
|
||||
links.add(
|
||||
LinksHelper.createLink(
|
||||
HttpMethod.GET,
|
||||
uriBuilder
|
||||
.clone()
|
||||
.path(OrganizationService.class)
|
||||
.path(OrganizationService.class, "getById")
|
||||
.build(organizationDto.getId())
|
||||
.toString(),
|
||||
null,
|
||||
APPLICATION_JSON,
|
||||
Constants.LINK_REL_SELF));
|
||||
links.add(
|
||||
LinksHelper.createLink(
|
||||
HttpMethod.GET,
|
||||
uriBuilder
|
||||
.clone()
|
||||
.path(OrganizationService.class)
|
||||
.path(OrganizationService.class, "getByParent")
|
||||
.build(organizationDto.getId())
|
||||
.toString(),
|
||||
null,
|
||||
APPLICATION_JSON,
|
||||
Constants.LINK_REL_SUBORGANIZATIONS));
|
||||
return organizationDto.withLinks(links);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,336 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2024 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.organization.api;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.eclipse.che.multiuser.organization.api.DtoConverter.asDto;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.ApiException;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.Pages;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.commons.lang.NameGenerator;
|
||||
import org.eclipse.che.multiuser.organization.api.event.OrganizationRemovedEvent;
|
||||
import org.eclipse.che.multiuser.organization.api.event.OrganizationRenamedEvent;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Member;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.eclipse.che.multiuser.organization.spi.MemberDao;
|
||||
import org.eclipse.che.multiuser.organization.spi.OrganizationDao;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
|
||||
/**
|
||||
* Facade for Organization related operations.
|
||||
*
|
||||
* @author gazarenkov
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class OrganizationManager {
|
||||
|
||||
private final EventService eventService;
|
||||
private final OrganizationDao organizationDao;
|
||||
private final MemberDao memberDao;
|
||||
private final Set<String> reservedNames;
|
||||
|
||||
@Inject
|
||||
public OrganizationManager(
|
||||
EventService eventService,
|
||||
OrganizationDao organizationDao,
|
||||
MemberDao memberDao,
|
||||
@Named("che.auth.reserved_user_names") String[] reservedNames) {
|
||||
this.eventService = eventService;
|
||||
this.organizationDao = organizationDao;
|
||||
this.memberDao = memberDao;
|
||||
this.reservedNames = Sets.newHashSet(reservedNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new organization.
|
||||
*
|
||||
* @param newOrganization organization to create
|
||||
* @return created organization
|
||||
* @throws NullPointerException when {@code organization} is null
|
||||
* @throws NotFoundException when parent organization was not found
|
||||
* @throws ConflictException when organization with such id/name already exists
|
||||
* @throws ConflictException when specified organization name is reserved
|
||||
* @throws ServerException when any other error occurs during organization creation
|
||||
*/
|
||||
@Transactional(rollbackOn = {RuntimeException.class, ApiException.class})
|
||||
public Organization create(Organization newOrganization)
|
||||
throws NotFoundException, ConflictException, ServerException {
|
||||
requireNonNull(newOrganization, "Required non-null organization");
|
||||
requireNonNull(newOrganization.getName(), "Required non-null organization name");
|
||||
|
||||
String qualifiedName;
|
||||
if (newOrganization.getParent() != null) {
|
||||
final Organization parent = getById(newOrganization.getParent());
|
||||
qualifiedName = parent.getQualifiedName() + "/" + newOrganization.getName();
|
||||
} else {
|
||||
qualifiedName = newOrganization.getName();
|
||||
}
|
||||
checkNameReservation(qualifiedName);
|
||||
|
||||
final OrganizationImpl organization =
|
||||
new OrganizationImpl(
|
||||
NameGenerator.generate("organization", 16), qualifiedName, newOrganization.getParent());
|
||||
organizationDao.create(organization);
|
||||
addFirstMember(organization);
|
||||
return organization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates organization with new entity.
|
||||
*
|
||||
* @param organizationId id of organization to update
|
||||
* @param update organization update
|
||||
* @throws NullPointerException when {@code organizationId} or {@code update} is null
|
||||
* @throws NotFoundException when organization with given id doesn't exist
|
||||
* @throws ConflictException when name updated with a value which is reserved or is not unique
|
||||
* @throws ServerException when any other error occurs organization updating
|
||||
*/
|
||||
@Transactional(rollbackOn = {RuntimeException.class, ApiException.class})
|
||||
public Organization update(String organizationId, Organization update)
|
||||
throws NotFoundException, ConflictException, ServerException {
|
||||
requireNonNull(organizationId, "Required non-null organization id");
|
||||
requireNonNull(update, "Required non-null organization");
|
||||
requireNonNull(update.getName(), "Required non-null organization name");
|
||||
|
||||
final OrganizationImpl organization = organizationDao.getById(organizationId);
|
||||
final String oldQualifiedName = organization.getQualifiedName();
|
||||
final String oldName = organization.getName();
|
||||
|
||||
final String newName = update.getName();
|
||||
final String newQualifiedName = buildQualifiedName(oldQualifiedName, update.getName());
|
||||
|
||||
checkNameReservation(newQualifiedName);
|
||||
organization.setQualifiedName(newQualifiedName);
|
||||
|
||||
organizationDao.update(organization);
|
||||
if (!newName.equals(oldName)) {
|
||||
updateSuborganizationsQualifiedNames(oldQualifiedName, organization.getQualifiedName());
|
||||
|
||||
final String performerName = EnvironmentContext.getCurrent().getSubject().getUserName();
|
||||
// should be DTO as it sent via json rpc
|
||||
eventService.publish(
|
||||
asDto(new OrganizationRenamedEvent(performerName, oldName, newName, organization)));
|
||||
}
|
||||
return organization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes organization with given id
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @throws NullPointerException when {@code organizationId} is null
|
||||
* @throws ServerException when any other error occurs during organization removing
|
||||
*/
|
||||
@Transactional(rollbackOn = {RuntimeException.class, ApiException.class})
|
||||
public void remove(String organizationId) throws ServerException {
|
||||
requireNonNull(organizationId, "Required non-null organization id");
|
||||
try {
|
||||
OrganizationImpl organization = organizationDao.getById(organizationId);
|
||||
removeSuborganizations(organizationId);
|
||||
final List<String> members = removeMembers(organizationId);
|
||||
organizationDao.remove(organizationId);
|
||||
final String initiator = EnvironmentContext.getCurrent().getSubject().getUserName();
|
||||
eventService.publish(asDto(new OrganizationRemovedEvent(initiator, organization, members)));
|
||||
} catch (NotFoundException e) {
|
||||
// organization is already removed
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets organization by identifier.
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @return organization instance
|
||||
* @throws NullPointerException when {@code organizationId} is null
|
||||
* @throws NotFoundException when organization with given id was not found
|
||||
* @throws ServerException when any other error occurs during organization fetching
|
||||
*/
|
||||
public Organization getById(String organizationId) throws NotFoundException, ServerException {
|
||||
requireNonNull(organizationId, "Required non-null organization id");
|
||||
return organizationDao.getById(organizationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets organization by name.
|
||||
*
|
||||
* @param organizationName organization name
|
||||
* @return organization instance
|
||||
* @throws NullPointerException when {@code organizationName} is null
|
||||
* @throws NotFoundException when organization with given name was not found
|
||||
* @throws ServerException when any other error occurs during organization fetching
|
||||
*/
|
||||
public Organization getByName(String organizationName) throws NotFoundException, ServerException {
|
||||
requireNonNull(organizationName, "Required non-null organization name");
|
||||
return organizationDao.getByName(organizationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets child organizations by given parent.
|
||||
*
|
||||
* @param parent id of parent organizations
|
||||
* @param maxItems the maximum number of organizations to return
|
||||
* @param skipCount the number of organizations to skip
|
||||
* @return list of children organizations
|
||||
* @throws NullPointerException when {@code parent} is null
|
||||
* @throws ServerException when any other error occurs during organizations fetching
|
||||
*/
|
||||
public Page<? extends Organization> getByParent(String parent, int maxItems, long skipCount)
|
||||
throws ServerException {
|
||||
requireNonNull(parent, "Required non-null parent");
|
||||
return organizationDao.getByParent(parent, maxItems, skipCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all child organizations by specified parent qualified name.
|
||||
*
|
||||
* <p>Note that the result will includes all direct and nested suborganizations.
|
||||
*
|
||||
* @param parentQualifiedName qualified name of parent organization
|
||||
* @param maxItems the maximum number of organizations to return
|
||||
* @param skipCount the number of organizations to skip
|
||||
* @return list of children organizations
|
||||
* @throws NullPointerException when {@code parentQualifiedName} is null
|
||||
* @throws ServerException when any other error occurs during organizations fetching
|
||||
*/
|
||||
public Page<OrganizationImpl> getSuborganizations(
|
||||
String parentQualifiedName, int maxItems, long skipCount) throws ServerException {
|
||||
requireNonNull(parentQualifiedName, "Required non-null parent qualified name");
|
||||
return organizationDao.getSuborganizations(parentQualifiedName, maxItems, skipCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list organizations where user is member.
|
||||
*
|
||||
* @param userId user id
|
||||
* @param maxItems the maximum number of organizations to return
|
||||
* @param skipCount the number of organizations to skip
|
||||
* @return list of organizations where user is member
|
||||
* @throws NullPointerException when {@code userId} is null
|
||||
* @throws ServerException when any other error occurs during organizations fetching
|
||||
*/
|
||||
public Page<? extends Organization> getByMember(String userId, int maxItems, int skipCount)
|
||||
throws ServerException {
|
||||
requireNonNull(userId, "Required non-null user id");
|
||||
return memberDao.getOrganizations(userId, maxItems, skipCount);
|
||||
}
|
||||
|
||||
private String buildQualifiedName(String oldQualifiedName, String newName) {
|
||||
int lastSlashIndex = oldQualifiedName.lastIndexOf("/");
|
||||
if (lastSlashIndex != -1) { // check that it is not root organization
|
||||
return oldQualifiedName.substring(0, lastSlashIndex + 1) + newName;
|
||||
} else {
|
||||
return newName;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSuborganizationsQualifiedNames(
|
||||
String oldQualifiedName, String newQualifiedName)
|
||||
throws NotFoundException, ConflictException, ServerException {
|
||||
for (OrganizationImpl suborganization :
|
||||
Pages.iterate(
|
||||
(maxItems, skipCount) ->
|
||||
organizationDao.getSuborganizations(oldQualifiedName, maxItems, skipCount))) {
|
||||
suborganization.setQualifiedName(
|
||||
suborganization.getQualifiedName().replaceFirst(oldQualifiedName, newQualifiedName));
|
||||
organizationDao.update(suborganization);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of members by specified organization id.
|
||||
*
|
||||
* @param organizationId organization identifier
|
||||
* @param maxItems the maximum number of members to return
|
||||
* @param skipCount the number of members to skip
|
||||
* @return list of members
|
||||
* @throws NullPointerException when {@code organizationId} is null
|
||||
* @throws ServerException when any other error occurs during organizations fetching
|
||||
*/
|
||||
public Page<? extends Member> getMembers(String organizationId, int maxItems, long skipCount)
|
||||
throws ServerException {
|
||||
requireNonNull(organizationId, "Required non-null organization id");
|
||||
return memberDao.getMembers(organizationId, maxItems, skipCount);
|
||||
}
|
||||
|
||||
protected void addFirstMember(Organization organization) throws ServerException {
|
||||
memberDao.store(
|
||||
new MemberImpl(
|
||||
EnvironmentContext.getCurrent().getSubject().getUserId(),
|
||||
organization.getId(),
|
||||
OrganizationDomain.getActions()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes suborganizations of given parent organization page by page
|
||||
*
|
||||
* @param organizationId parent organization id
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void removeSuborganizations(String organizationId) throws ServerException {
|
||||
Page<? extends Organization> suborganizationsPage;
|
||||
do {
|
||||
// skip count always equals to 0 because elements will be shifted after removing previous
|
||||
// items
|
||||
suborganizationsPage = organizationDao.getByParent(organizationId, 100, 0);
|
||||
for (Organization suborganization : suborganizationsPage.getItems()) {
|
||||
remove(suborganization.getId());
|
||||
}
|
||||
} while (suborganizationsPage.hasNextPage());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<String> removeMembers(String organizationId) throws ServerException {
|
||||
List<String> removed = new ArrayList<>();
|
||||
Page<MemberImpl> membersPage;
|
||||
do {
|
||||
// skip count always equals to 0 because elements will be shifted after removing previous
|
||||
// items
|
||||
membersPage = memberDao.getMembers(organizationId, 100, 0);
|
||||
for (MemberImpl member : membersPage.getItems()) {
|
||||
removed.add(member.getUserId());
|
||||
memberDao.remove(member.getUserId(), member.getOrganizationId());
|
||||
}
|
||||
} while (membersPage.hasNextPage());
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks reservation of organization name
|
||||
*
|
||||
* @param organizationName organization name to check
|
||||
* @throws ConflictException when organization name is reserved and can be used by user
|
||||
*/
|
||||
private void checkNameReservation(String organizationName) throws ConflictException {
|
||||
if (reservedNames.contains(organizationName.toLowerCase())) {
|
||||
throw new ConflictException(
|
||||
String.format("Organization name '%s' is reserved", organizationName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api;
|
||||
|
||||
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
import static org.eclipse.che.multiuser.organization.api.DtoConverter.asDto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import javax.inject.Inject;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.rest.Service;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* Defines Organization REST API.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Tag(name = "organization", description = "Organization REST API")
|
||||
@Path("/organization")
|
||||
public class OrganizationService extends Service {
|
||||
private final OrganizationManager organizationManager;
|
||||
private final OrganizationLinksInjector linksInjector;
|
||||
private final OrganizationValidator organizationValidator;
|
||||
|
||||
@Inject
|
||||
public OrganizationService(
|
||||
OrganizationManager organizationManager,
|
||||
OrganizationLinksInjector linksInjector,
|
||||
OrganizationValidator organizationValidator) {
|
||||
this.organizationManager = organizationManager;
|
||||
this.linksInjector = linksInjector;
|
||||
this.organizationValidator = organizationValidator;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes(APPLICATION_JSON)
|
||||
@Produces(APPLICATION_JSON)
|
||||
@Operation(
|
||||
summary = "Create new organization",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "The organization successfully created",
|
||||
content = @Content(schema = @Schema(implementation = OrganizationDto.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Missed required parameters, parameters are not valid"),
|
||||
@ApiResponse(
|
||||
responseCode = "409",
|
||||
description =
|
||||
"Conflict error occurred during the organization creation"
|
||||
+ "(e.g. The organization with such name already exists)"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public Response create(
|
||||
@Parameter(description = "Organization to create", required = true)
|
||||
OrganizationDto organization)
|
||||
throws BadRequestException, NotFoundException, ConflictException, ServerException {
|
||||
organizationValidator.checkOrganization(organization);
|
||||
return Response.status(201)
|
||||
.entity(
|
||||
linksInjector.injectLinks(
|
||||
asDto(organizationManager.create(organization)), getServiceContext()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/{id}")
|
||||
@Consumes(APPLICATION_JSON)
|
||||
@Produces(APPLICATION_JSON)
|
||||
@Operation(
|
||||
summary = "Update organization",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "The organization successfully updated",
|
||||
content = @Content(schema = @Schema(implementation = OrganizationDto.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Missed required parameters, parameters are not valid"),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "The organization with given id was not found"),
|
||||
@ApiResponse(
|
||||
responseCode = "409",
|
||||
description =
|
||||
"Conflict error occurred during the organization creation"
|
||||
+ "(e.g. The organization with such name already exists)"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public OrganizationDto update(
|
||||
@Parameter(description = "Organization id") @PathParam("id") String organizationId,
|
||||
@Parameter(description = "Organization to update", required = true)
|
||||
OrganizationDto organization)
|
||||
throws BadRequestException, ConflictException, NotFoundException, ServerException {
|
||||
organizationValidator.checkOrganization(organization);
|
||||
return linksInjector.injectLinks(
|
||||
asDto(organizationManager.update(organizationId, organization)), getServiceContext());
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
@Operation(
|
||||
summary = "Remove organization with given id",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "204", description = "The organization successfully removed"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public void remove(
|
||||
@Parameter(description = "Organization id") @PathParam("id") String organization)
|
||||
throws ServerException {
|
||||
organizationManager.remove(organization);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(APPLICATION_JSON)
|
||||
@Path("/{organizationId}")
|
||||
@Operation(
|
||||
summary = "Get organization by id",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "The organization successfully fetched",
|
||||
content = @Content(schema = @Schema(implementation = OrganizationDto.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "The organization with given id was not found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public OrganizationDto getById(
|
||||
@Parameter(description = "Organization id") @PathParam("organizationId")
|
||||
String organizationId)
|
||||
throws NotFoundException, ServerException {
|
||||
return linksInjector.injectLinks(
|
||||
asDto(organizationManager.getById(organizationId)), getServiceContext());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(APPLICATION_JSON)
|
||||
@Path("/find")
|
||||
@Operation(
|
||||
summary = "Find organization by name",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "The organization successfully fetched",
|
||||
content = @Content(schema = @Schema(implementation = OrganizationDto.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Missed required parameters, parameters are not valid"),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "The organization with given name was not found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public OrganizationDto find(
|
||||
@Parameter(description = "Organization name", required = true) @QueryParam("name")
|
||||
String organizationName)
|
||||
throws NotFoundException, ServerException, BadRequestException {
|
||||
checkArgument(organizationName != null, "Missed organization's name");
|
||||
return linksInjector.injectLinks(
|
||||
asDto(organizationManager.getByName(organizationName)), getServiceContext());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(APPLICATION_JSON)
|
||||
@Path("/{parent}/organizations")
|
||||
@Operation(
|
||||
summary = "Get child organizations",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "The child organizations successfully fetched",
|
||||
content =
|
||||
@Content(
|
||||
array =
|
||||
@ArraySchema(schema = @Schema(implementation = OrganizationDto.class)))),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public Response getByParent(
|
||||
@Parameter(description = "Parent organization id") @PathParam("parent") String parent,
|
||||
@Parameter(description = "Max items") @QueryParam("maxItems") @DefaultValue("30")
|
||||
int maxItems,
|
||||
@Parameter(description = "Skip count") @QueryParam("skipCount") @DefaultValue("0")
|
||||
int skipCount)
|
||||
throws ServerException, BadRequestException {
|
||||
|
||||
checkArgument(maxItems >= 0, "The number of items to return can't be negative.");
|
||||
checkArgument(skipCount >= 0, "The number of items to skip can't be negative.");
|
||||
final Page<? extends Organization> organizationsPage =
|
||||
organizationManager.getByParent(parent, maxItems, skipCount);
|
||||
return Response.ok()
|
||||
.entity(
|
||||
organizationsPage.getItems(
|
||||
organization ->
|
||||
linksInjector.injectLinks(asDto(organization), getServiceContext())))
|
||||
.header("Link", createLinkHeader(organizationsPage))
|
||||
.build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(APPLICATION_JSON)
|
||||
@Operation(
|
||||
summary =
|
||||
"Get user's organizations. When user parameter is missed then will be fetched current user's organizations",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "The organizations successfully fetched",
|
||||
content =
|
||||
@Content(
|
||||
array =
|
||||
@ArraySchema(schema = @Schema(implementation = OrganizationDto.class)))),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Missed required parameters, parameters are not valid"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public Response getOrganizations(
|
||||
@Parameter(description = "User id") @QueryParam("user") String userId,
|
||||
@Parameter(description = "Max items") @QueryParam("maxItems") @DefaultValue("30")
|
||||
int maxItems,
|
||||
@Parameter(description = "Skip count") @QueryParam("skipCount") @DefaultValue("0")
|
||||
int skipCount)
|
||||
throws ServerException, BadRequestException {
|
||||
|
||||
checkArgument(maxItems >= 0, "The number of items to return can't be negative.");
|
||||
checkArgument(skipCount >= 0, "The number of items to skip can't be negative.");
|
||||
if (userId == null) {
|
||||
userId = EnvironmentContext.getCurrent().getSubject().getUserId();
|
||||
}
|
||||
final Page<? extends Organization> organizationsPage =
|
||||
organizationManager.getByMember(userId, maxItems, skipCount);
|
||||
return Response.ok()
|
||||
.entity(
|
||||
organizationsPage.getItems(
|
||||
organization ->
|
||||
linksInjector.injectLinks(asDto(organization), getServiceContext())))
|
||||
.header("Link", createLinkHeader(organizationsPage))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving one or more parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @param errorMessage the exception message to use if the check fails
|
||||
* @throws BadRequestException if {@code expression} is false
|
||||
*/
|
||||
private void checkArgument(boolean expression, String errorMessage) throws BadRequestException {
|
||||
if (!expression) {
|
||||
throw new BadRequestException(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import org.eclipse.che.account.spi.AccountValidator;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* Utils for organization validation.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public class OrganizationValidator {
|
||||
@Inject private AccountValidator accountValidator;
|
||||
|
||||
/**
|
||||
* Checks whether given organization is valid.
|
||||
*
|
||||
* @param organization organization to check
|
||||
* @throws BadRequestException when organization is not valid
|
||||
*/
|
||||
public void checkOrganization(Organization organization) throws BadRequestException {
|
||||
if (organization == null) {
|
||||
throw new BadRequestException("Organization required");
|
||||
}
|
||||
if (isNullOrEmpty(organization.getName())) {
|
||||
throw new BadRequestException("Organization name required");
|
||||
}
|
||||
if (!accountValidator.isValidName(organization.getName())) {
|
||||
throw new BadRequestException(
|
||||
"Organization name may only contain alphanumeric characters or single hyphens inside");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.event;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.shared.event.EventType.MEMBER_ADDED;
|
||||
|
||||
import org.eclipse.che.api.core.model.user.User;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.MemberEvent;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* Defines the event of adding the organization member.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
public class MemberAddedEvent implements MemberEvent {
|
||||
|
||||
private final String initiator;
|
||||
private final User member;
|
||||
private final Organization organization;
|
||||
|
||||
public MemberAddedEvent(String initiator, User member, Organization organization) {
|
||||
this.initiator = initiator;
|
||||
this.member = member;
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Organization getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventType getType() {
|
||||
return MEMBER_ADDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getMember() {
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.event;
|
||||
|
||||
import org.eclipse.che.api.core.model.user.User;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.MemberEvent;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* Defines the event for organization member removal.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
public class MemberRemovedEvent implements MemberEvent {
|
||||
|
||||
private final String initiator;
|
||||
private final User member;
|
||||
private final Organization organization;
|
||||
|
||||
public MemberRemovedEvent(String initiator, User member, Organization organization) {
|
||||
this.initiator = initiator;
|
||||
this.member = member;
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventType getType() {
|
||||
return EventType.MEMBER_REMOVED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Organization getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getMember() {
|
||||
return member;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.event;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.shared.event.EventType.ORGANIZATION_REMOVED;
|
||||
|
||||
import java.util.List;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.OrganizationEvent;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* Defines organization removed event.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
public class OrganizationRemovedEvent implements OrganizationEvent {
|
||||
|
||||
private final String initiator;
|
||||
private final Organization organization;
|
||||
private final List<String> members;
|
||||
|
||||
public OrganizationRemovedEvent(
|
||||
String initiator, Organization organization, List<String> members) {
|
||||
this.initiator = initiator;
|
||||
this.organization = organization;
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventType getType() {
|
||||
return ORGANIZATION_REMOVED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Organization getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
public List<String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/** Returns name of user who initiated organization removal */
|
||||
@Override
|
||||
public String getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.event;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.shared.event.EventType.ORGANIZATION_RENAMED;
|
||||
|
||||
import org.eclipse.che.multiuser.organization.shared.event.EventType;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.OrganizationEvent;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* Defines organization renamed event.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
public class OrganizationRenamedEvent implements OrganizationEvent {
|
||||
|
||||
private final String initiator;
|
||||
private final String oldName;
|
||||
private final String newName;
|
||||
private final Organization organization;
|
||||
|
||||
public OrganizationRenamedEvent(
|
||||
String initiator, String oldName, String newName, Organization organization) {
|
||||
this.initiator = initiator;
|
||||
this.oldName = oldName;
|
||||
this.newName = newName;
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Organization getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventType getType() {
|
||||
return ORGANIZATION_RENAMED;
|
||||
}
|
||||
|
||||
public String getOldName() {
|
||||
return oldName;
|
||||
}
|
||||
|
||||
public String getNewName() {
|
||||
return newName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api.listener;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.api.DtoConverter.asDto;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.user.User;
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.api.core.notification.EventSubscriber;
|
||||
import org.eclipse.che.api.user.server.UserManager;
|
||||
import org.eclipse.che.multiuser.api.permission.shared.event.PermissionsEvent;
|
||||
import org.eclipse.che.multiuser.api.permission.shared.model.Permissions;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.api.event.MemberAddedEvent;
|
||||
import org.eclipse.che.multiuser.organization.api.event.MemberRemovedEvent;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* Maps permissions to organization related events.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@Singleton
|
||||
public class MemberEventsPublisher implements EventSubscriber<PermissionsEvent> {
|
||||
|
||||
private final EventService eventService;
|
||||
private final UserManager userManager;
|
||||
private final OrganizationManager organizationManager;
|
||||
|
||||
@Inject
|
||||
public MemberEventsPublisher(
|
||||
EventService eventService, UserManager userManager, OrganizationManager organizationManager) {
|
||||
this.eventService = eventService;
|
||||
this.userManager = userManager;
|
||||
this.organizationManager = organizationManager;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void subscribe() {
|
||||
eventService.subscribe(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(PermissionsEvent event) {
|
||||
final Permissions permissions = event.getPermissions();
|
||||
if (OrganizationDomain.DOMAIN_ID.equals(permissions.getDomainId())) {
|
||||
try {
|
||||
switch (event.getType()) {
|
||||
case PERMISSIONS_ADDED:
|
||||
{
|
||||
final String initiator = event.getInitiator();
|
||||
final User addedMember = userManager.getById(permissions.getUserId());
|
||||
final Organization org = organizationManager.getById(permissions.getInstanceId());
|
||||
eventService.publish(asDto(new MemberAddedEvent(initiator, addedMember, org)));
|
||||
break;
|
||||
}
|
||||
case PERMISSIONS_REMOVED:
|
||||
{
|
||||
final String initiator = event.getInitiator();
|
||||
final User removedMember = userManager.getById(permissions.getUserId());
|
||||
final Organization org = organizationManager.getById(permissions.getInstanceId());
|
||||
eventService.publish(asDto(new MemberRemovedEvent(initiator, removedMember, org)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
} catch (NotFoundException | ServerException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api.listener;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.shared.event.EventType.MEMBER_ADDED;
|
||||
import static org.eclipse.che.multiuser.organization.shared.event.EventType.MEMBER_REMOVED;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.notification.RemoteSubscriptionManager;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.MemberAddedEventDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.MemberRemovedEventDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.event.OrganizationEvent;
|
||||
|
||||
/**
|
||||
* Broadcasts organization events through websocket connection.
|
||||
*
|
||||
* @author Anton Korneta
|
||||
*/
|
||||
@Singleton
|
||||
public class OrganizationEventsWebsocketBroadcaster {
|
||||
|
||||
private final RemoteSubscriptionManager remoteSubscriptionManager;
|
||||
|
||||
public static final String ORGANIZATION_MEMBERSHIP_METHOD_NAME = "organization/membershipChanged";
|
||||
public static final String ORGANIZATION_CHANGED_METHOD_NAME = "organization/statusChanged";
|
||||
|
||||
@Inject
|
||||
public OrganizationEventsWebsocketBroadcaster(
|
||||
RemoteSubscriptionManager remoteSubscriptionManager) {
|
||||
this.remoteSubscriptionManager = remoteSubscriptionManager;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void subscribe() {
|
||||
remoteSubscriptionManager.register(
|
||||
ORGANIZATION_MEMBERSHIP_METHOD_NAME, OrganizationEvent.class, this::predicate);
|
||||
remoteSubscriptionManager.register(
|
||||
ORGANIZATION_CHANGED_METHOD_NAME, OrganizationEvent.class, this::predicate);
|
||||
}
|
||||
|
||||
private boolean predicate(OrganizationEvent event, Map<String, String> scope) {
|
||||
if (MEMBER_ADDED == event.getType()) {
|
||||
return ((MemberAddedEventDto) event).getMember().getId().equals(scope.get("userId"));
|
||||
} else if (MEMBER_REMOVED == event.getType()) {
|
||||
return ((MemberRemovedEventDto) event).getMember().getId().equals(scope.get("userId"));
|
||||
} else {
|
||||
return event.getOrganization().getId().equals(scope.get("organizationId"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.permissions;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
|
||||
|
||||
/**
|
||||
* Domain for storing organizations' permissions
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public class OrganizationDomain extends AbstractPermissionsDomain<MemberImpl> {
|
||||
public static final String DOMAIN_ID = "organization";
|
||||
|
||||
public static final String UPDATE = "update";
|
||||
public static final String DELETE = "delete";
|
||||
public static final String MANAGE_SUBORGANIZATIONS = "manageSuborganizations";
|
||||
public static final String MANAGE_RESOURCES = "manageResources";
|
||||
public static final String CREATE_WORKSPACES = "createWorkspaces";
|
||||
public static final String MANAGE_WORKSPACES = "manageWorkspaces";
|
||||
|
||||
private static final List<String> ACTIONS =
|
||||
ImmutableList.of(
|
||||
SET_PERMISSIONS,
|
||||
UPDATE,
|
||||
DELETE,
|
||||
MANAGE_SUBORGANIZATIONS,
|
||||
MANAGE_RESOURCES,
|
||||
CREATE_WORKSPACES,
|
||||
MANAGE_WORKSPACES);
|
||||
|
||||
/** Returns all the available actions for {@link OrganizationDomain}. */
|
||||
public static List<String> getActions() {
|
||||
return ACTIONS;
|
||||
}
|
||||
|
||||
public OrganizationDomain() {
|
||||
super(DOMAIN_ID, ACTIONS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemberImpl doCreateInstance(
|
||||
String userId, String instanceId, List<String> allowedActions) {
|
||||
return new MemberImpl(userId, instanceId, allowedActions);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api.permissions;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.DOMAIN_ID;
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.MANAGE_SUBORGANIZATIONS;
|
||||
|
||||
import jakarta.ws.rs.Path;
|
||||
import javax.inject.Inject;
|
||||
import org.eclipse.che.api.core.ApiException;
|
||||
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.everrest.CheMethodInvokerFilter;
|
||||
import org.eclipse.che.multiuser.api.permission.server.SuperPrivilegesChecker;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationService;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.everrest.core.Filter;
|
||||
import org.everrest.core.resource.GenericResourceMethod;
|
||||
|
||||
/**
|
||||
* Restricts access to methods of {@link OrganizationService} by users' permissions
|
||||
*
|
||||
* <p>Filter contains rules for protecting of all methods of {@link OrganizationService}.<br>
|
||||
* In case when requested method is unknown filter throws {@link ForbiddenException}
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Filter
|
||||
@Path("/organization{path:(?!/resource)(/.*)?}")
|
||||
public class OrganizationPermissionsFilter extends CheMethodInvokerFilter {
|
||||
static final String CREATE_METHOD = "create";
|
||||
static final String UPDATE_METHOD = "update";
|
||||
static final String REMOVE_METHOD = "remove";
|
||||
static final String GET_BY_PARENT_METHOD = "getByParent";
|
||||
static final String GET_ORGANIZATIONS_METHOD = "getOrganizations";
|
||||
static final String GET_BY_ID_METHOD = "getById";
|
||||
static final String FIND_METHOD = "find";
|
||||
|
||||
@Inject private OrganizationManager manager;
|
||||
@Inject private SuperPrivilegesChecker superPrivilegesChecker;
|
||||
|
||||
@Override
|
||||
protected void filter(GenericResourceMethod genericMethodResource, Object[] arguments)
|
||||
throws ApiException {
|
||||
final String methodName = genericMethodResource.getMethod().getName();
|
||||
|
||||
final Subject currentSubject = EnvironmentContext.getCurrent().getSubject();
|
||||
String action;
|
||||
String organizationId;
|
||||
|
||||
switch (methodName) {
|
||||
case CREATE_METHOD:
|
||||
final OrganizationDto organization = (OrganizationDto) arguments[0];
|
||||
if (organization.getParent() != null) {
|
||||
organizationId = organization.getParent();
|
||||
action = OrganizationDomain.MANAGE_SUBORGANIZATIONS;
|
||||
break;
|
||||
}
|
||||
// anybody can create root organization
|
||||
return;
|
||||
|
||||
case UPDATE_METHOD:
|
||||
organizationId = ((String) arguments[0]);
|
||||
action = OrganizationDomain.UPDATE;
|
||||
break;
|
||||
|
||||
case REMOVE_METHOD:
|
||||
organizationId = ((String) arguments[0]);
|
||||
action = OrganizationDomain.DELETE;
|
||||
break;
|
||||
|
||||
case GET_BY_PARENT_METHOD:
|
||||
organizationId = ((String) arguments[0]);
|
||||
action = OrganizationDomain.MANAGE_SUBORGANIZATIONS;
|
||||
if (superPrivilegesChecker.hasSuperPrivileges()) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_ORGANIZATIONS_METHOD:
|
||||
final String userId = (String) arguments[0];
|
||||
if (userId != null
|
||||
&& !userId.equals(currentSubject.getUserId())
|
||||
&& !superPrivilegesChecker.hasSuperPrivileges()) {
|
||||
throw new ForbiddenException("The user is able to specify only his own id");
|
||||
}
|
||||
// user specified his user id or has super privileges
|
||||
return;
|
||||
|
||||
// methods accessible to every user
|
||||
case GET_BY_ID_METHOD:
|
||||
case FIND_METHOD:
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new ForbiddenException("The user does not have permission to perform this operation");
|
||||
}
|
||||
|
||||
// user is not admin and it is need to check permissions on organization instance level
|
||||
final Organization organization = manager.getById(organizationId);
|
||||
final String parentOrganizationId = organization.getParent();
|
||||
// check permissions on parent organization level when updating or removing child organization
|
||||
if (parentOrganizationId != null
|
||||
&& (OrganizationDomain.UPDATE.equals(action) || OrganizationDomain.DELETE.equals(action))) {
|
||||
if (currentSubject.hasPermission(
|
||||
OrganizationDomain.DOMAIN_ID, parentOrganizationId, MANAGE_SUBORGANIZATIONS)) {
|
||||
// user has permissions to manage organization on parent organization level
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentSubject.hasPermission(DOMAIN_ID, organizationId, action)) {
|
||||
throw new ForbiddenException(
|
||||
"The user does not have permission to "
|
||||
+ action
|
||||
+ " organization with id '"
|
||||
+ organizationId
|
||||
+ "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.permissions;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.api.listener.OrganizationEventsWebsocketBroadcaster.ORGANIZATION_CHANGED_METHOD_NAME;
|
||||
import static org.eclipse.che.multiuser.organization.api.listener.OrganizationEventsWebsocketBroadcaster.ORGANIZATION_MEMBERSHIP_METHOD_NAME;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.ForbiddenException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionsManager;
|
||||
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.api.permission.server.model.impl.AbstractPermissions;
|
||||
import org.eclipse.che.multiuser.organization.api.listener.OrganizationEventsWebsocketBroadcaster;
|
||||
|
||||
/**
|
||||
* Holds and registers permissions checks for organization related events.
|
||||
*
|
||||
* <p>Covers events published via {@link OrganizationEventsWebsocketBroadcaster}.
|
||||
*
|
||||
* @author Sergii Leshchenko
|
||||
*/
|
||||
@Singleton
|
||||
public class OrganizationRemoteSubscriptionPermissionsChecks {
|
||||
|
||||
private final PermissionsManager permissionsManager;
|
||||
|
||||
@Inject
|
||||
public OrganizationRemoteSubscriptionPermissionsChecks(PermissionsManager permissionsManager) {
|
||||
this.permissionsManager = permissionsManager;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void register(RemoteSubscriptionPermissionManager permissionFilter) {
|
||||
MembershipsChangedSubscriptionCheck membershipsEventsCheck =
|
||||
new MembershipsChangedSubscriptionCheck();
|
||||
|
||||
permissionFilter.registerCheck(membershipsEventsCheck, ORGANIZATION_MEMBERSHIP_METHOD_NAME);
|
||||
|
||||
OrganizationChangedSubscriptionCheck organizationChangedCheck =
|
||||
new OrganizationChangedSubscriptionCheck(permissionsManager);
|
||||
permissionFilter.registerCheck(organizationChangedCheck, ORGANIZATION_CHANGED_METHOD_NAME);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class MembershipsChangedSubscriptionCheck implements RemoteSubscriptionPermissionCheck {
|
||||
|
||||
@Override
|
||||
public void check(String methodName, Map<String, String> scope) throws ForbiddenException {
|
||||
String userId = scope.get("userId");
|
||||
if (userId == null) {
|
||||
throw new ForbiddenException("User id must be specified in scope");
|
||||
}
|
||||
|
||||
String currentUserId = EnvironmentContext.getCurrent().getSubject().getUserId();
|
||||
|
||||
if (!currentUserId.equals(userId)) {
|
||||
throw new ForbiddenException("It is only allowed to listen to own memberships changes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class OrganizationChangedSubscriptionCheck implements RemoteSubscriptionPermissionCheck {
|
||||
|
||||
private final PermissionsManager permissionsManager;
|
||||
|
||||
public OrganizationChangedSubscriptionCheck(PermissionsManager permissionsManager) {
|
||||
this.permissionsManager = permissionsManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(String methodName, Map<String, String> scope) throws ForbiddenException {
|
||||
String organizationId = scope.get("organizationId");
|
||||
if (organizationId == null) {
|
||||
throw new ForbiddenException("Organization id must be specified in scope");
|
||||
}
|
||||
|
||||
String currentUserId = EnvironmentContext.getCurrent().getSubject().getUserId();
|
||||
|
||||
try {
|
||||
// check if user has any permissions in organisation
|
||||
// to listen to related events
|
||||
AbstractPermissions permissions =
|
||||
permissionsManager.get(currentUserId, OrganizationDomain.DOMAIN_ID, organizationId);
|
||||
} catch (ConflictException | ServerException e) {
|
||||
throw new ForbiddenException("Error occurred while permission fetching: " + e.getMessage());
|
||||
} catch (NotFoundException e) {
|
||||
throw new ForbiddenException(
|
||||
"User doesn't have any permissions for the specified organization");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api.permissions;
|
||||
|
||||
import jakarta.ws.rs.Path;
|
||||
import javax.inject.Inject;
|
||||
import org.eclipse.che.api.core.ApiException;
|
||||
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.everrest.CheMethodInvokerFilter;
|
||||
import org.eclipse.che.multiuser.api.permission.server.SuperPrivilegesChecker;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.api.resource.OrganizationResourcesDistributionService;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.everrest.core.Filter;
|
||||
import org.everrest.core.resource.GenericResourceMethod;
|
||||
|
||||
/**
|
||||
* Restricts access to methods of {@link OrganizationResourcesDistributionService} by users'
|
||||
* permissions.
|
||||
*
|
||||
* <p>Filter contains rules for protecting of all methods of {@link
|
||||
* OrganizationResourcesDistributionService}.<br>
|
||||
* In case when requested method is unknown filter throws {@link ForbiddenException}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Filter
|
||||
@Path("/organization/resource{path:(/.*)?}")
|
||||
public class OrganizationResourceDistributionServicePermissionsFilter
|
||||
extends CheMethodInvokerFilter {
|
||||
static final String CAP_RESOURCES_METHOD = "capResources";
|
||||
static final String GET_RESOURCES_CAP_METHOD = "getResourcesCap";
|
||||
static final String GET_DISTRIBUTED_RESOURCES = "getDistributedResources";
|
||||
|
||||
@Inject private OrganizationManager organizationManager;
|
||||
@Inject private SuperPrivilegesChecker superPrivilegesChecker;
|
||||
|
||||
@Override
|
||||
protected void filter(GenericResourceMethod genericMethodResource, Object[] arguments)
|
||||
throws ApiException {
|
||||
final String methodName = genericMethodResource.getMethod().getName();
|
||||
|
||||
final Subject currentSubject = EnvironmentContext.getCurrent().getSubject();
|
||||
String organizationId;
|
||||
switch (methodName) {
|
||||
case GET_RESOURCES_CAP_METHOD:
|
||||
if (superPrivilegesChecker.hasSuperPrivileges()) {
|
||||
// user is able to see information about all organizations
|
||||
return;
|
||||
}
|
||||
// fall through
|
||||
case CAP_RESOURCES_METHOD:
|
||||
// we should check permissions on parent organization level
|
||||
Organization organization = organizationManager.getById((String) arguments[0]);
|
||||
organizationId = organization.getParent();
|
||||
if (organizationId == null) {
|
||||
// requested organization is root so manager should throw exception
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_DISTRIBUTED_RESOURCES:
|
||||
organizationId = (String) arguments[0];
|
||||
// get organization to ensure that organization exists
|
||||
organizationManager.getById(organizationId);
|
||||
if (superPrivilegesChecker.hasSuperPrivileges()) {
|
||||
// user is able to see information about all organizations
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ForbiddenException("The user does not have permission to perform this operation");
|
||||
}
|
||||
|
||||
if (!currentSubject.hasPermission(
|
||||
OrganizationDomain.DOMAIN_ID, organizationId, OrganizationDomain.MANAGE_RESOURCES)) {
|
||||
throw new ForbiddenException(
|
||||
"The user does not have permission to manage resources of organization with id '"
|
||||
+ organizationId
|
||||
+ "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.permissions;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.CREATE_WORKSPACES;
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.DOMAIN_ID;
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.MANAGE_RESOURCES;
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.MANAGE_WORKSPACES;
|
||||
|
||||
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.account.AccountOperation;
|
||||
import org.eclipse.che.multiuser.api.permission.server.account.AccountPermissionsChecker;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
|
||||
/**
|
||||
* Defines permissions checking for organizational accounts.
|
||||
*
|
||||
* @author Sergii Leshchenko
|
||||
*/
|
||||
@Singleton
|
||||
public class OrganizationalAccountPermissionsChecker implements AccountPermissionsChecker {
|
||||
@Override
|
||||
public void checkPermissions(String accountId, AccountOperation operation)
|
||||
throws ForbiddenException {
|
||||
Subject subject = EnvironmentContext.getCurrent().getSubject();
|
||||
switch (operation) {
|
||||
case CREATE_WORKSPACE:
|
||||
if (!subject.hasPermission(
|
||||
OrganizationDomain.DOMAIN_ID, accountId, OrganizationDomain.CREATE_WORKSPACES)) {
|
||||
throw new ForbiddenException(
|
||||
"User is not authorized to create workspaces in specified namespace.");
|
||||
}
|
||||
break;
|
||||
case MANAGE_WORKSPACES:
|
||||
if (!subject.hasPermission(
|
||||
OrganizationDomain.DOMAIN_ID, accountId, OrganizationDomain.MANAGE_WORKSPACES)) {
|
||||
throw new ForbiddenException("User is not authorized to use specified namespace.");
|
||||
}
|
||||
break;
|
||||
case SEE_RESOURCE_INFORMATION:
|
||||
if (subject.hasPermission(DOMAIN_ID, accountId, CREATE_WORKSPACES)
|
||||
|| subject.hasPermission(DOMAIN_ID, accountId, MANAGE_WORKSPACES)
|
||||
|| subject.hasPermission(DOMAIN_ID, accountId, MANAGE_RESOURCES)) {
|
||||
|
||||
// user is able to see resources usage information
|
||||
return;
|
||||
}
|
||||
throw new ForbiddenException(
|
||||
"User is not authorized to see resources information of requested organization.");
|
||||
default:
|
||||
throw new ForbiddenException("User is not authorized to use specified namespace.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccountType() {
|
||||
return OrganizationImpl.ORGANIZATIONAL_ACCOUNT;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.resource;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.commons.lang.Size;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
import org.eclipse.che.multiuser.resource.api.free.DefaultResourcesProvider;
|
||||
import org.eclipse.che.multiuser.resource.api.type.RamResourceType;
|
||||
import org.eclipse.che.multiuser.resource.api.type.RuntimeResourceType;
|
||||
import org.eclipse.che.multiuser.resource.api.type.TimeoutResourceType;
|
||||
import org.eclipse.che.multiuser.resource.api.type.WorkspaceResourceType;
|
||||
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
|
||||
|
||||
/**
|
||||
* Provided free resources that are available for usage by organizational accounts by default.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class DefaultOrganizationResourcesProvider implements DefaultResourcesProvider {
|
||||
private final OrganizationManager organizationManager;
|
||||
private final long ramPerOrganization;
|
||||
private final int workspacesPerOrganization;
|
||||
private final int runtimesPerOrganization;
|
||||
private final long timeout;
|
||||
|
||||
@Inject
|
||||
public DefaultOrganizationResourcesProvider(
|
||||
OrganizationManager organizationManager,
|
||||
@Named("che.limits.organization.workspaces.ram") String ramPerOrganization,
|
||||
@Named("che.limits.organization.workspaces.count") int workspacesPerOrganization,
|
||||
@Named("che.limits.organization.workspaces.run.count") int runtimesPerOrganization,
|
||||
@Named("che.limits.workspace.idle.timeout") long timeout) {
|
||||
this.timeout = TimeUnit.MILLISECONDS.toMinutes(timeout);
|
||||
this.organizationManager = organizationManager;
|
||||
this.ramPerOrganization =
|
||||
"-1".equals(ramPerOrganization) ? -1 : Size.parseSizeToMegabytes(ramPerOrganization);
|
||||
this.workspacesPerOrganization = workspacesPerOrganization;
|
||||
this.runtimesPerOrganization = runtimesPerOrganization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccountType() {
|
||||
return OrganizationImpl.ORGANIZATIONAL_ACCOUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResourceImpl> getResources(String accountId)
|
||||
throws ServerException, NotFoundException {
|
||||
final Organization organization = organizationManager.getById(accountId);
|
||||
// only root organizations should have own resources
|
||||
if (organization.getParent() == null) {
|
||||
return asList(
|
||||
new ResourceImpl(TimeoutResourceType.ID, timeout, TimeoutResourceType.UNIT),
|
||||
new ResourceImpl(RamResourceType.ID, ramPerOrganization, RamResourceType.UNIT),
|
||||
new ResourceImpl(
|
||||
WorkspaceResourceType.ID, workspacesPerOrganization, WorkspaceResourceType.UNIT),
|
||||
new ResourceImpl(
|
||||
RuntimeResourceType.ID, runtimesPerOrganization, RuntimeResourceType.UNIT));
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.resource;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
import org.eclipse.che.multiuser.resource.api.ResourceLockKeyProvider;
|
||||
|
||||
/**
|
||||
* Provides resources lock key for accounts with organizational type.
|
||||
*
|
||||
* <p>A lock key for any organization is an identifier of the root organization.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class OrganizationResourceLockKeyProvider implements ResourceLockKeyProvider {
|
||||
private final OrganizationManager organizationManager;
|
||||
|
||||
@Inject
|
||||
public OrganizationResourceLockKeyProvider(OrganizationManager organizationManager) {
|
||||
this.organizationManager = organizationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLockKey(String accountId) throws ServerException {
|
||||
String currentOrganizationId = accountId;
|
||||
try {
|
||||
Organization organization = organizationManager.getById(currentOrganizationId);
|
||||
while (organization.getParent() != null) {
|
||||
currentOrganizationId = organization.getParent();
|
||||
organization = organizationManager.getById(currentOrganizationId);
|
||||
}
|
||||
return organization.getId();
|
||||
} catch (NotFoundException e) {
|
||||
// should not happen
|
||||
throw new ServerException(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccountType() {
|
||||
return OrganizationImpl.ORGANIZATIONAL_ACCOUNT;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api.resource;
|
||||
|
||||
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.rest.Service;
|
||||
import org.eclipse.che.multiuser.organization.api.DtoConverter;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDistributedResourcesDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.OrganizationDistributedResources;
|
||||
import org.eclipse.che.multiuser.resource.api.free.ResourceValidator;
|
||||
import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto;
|
||||
|
||||
/**
|
||||
* REST API for resources distribution between suborganizations.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Tag(
|
||||
name = "organization-resource",
|
||||
description = "REST API for resources distribution between suborganizations")
|
||||
@Path("/organization/resource")
|
||||
public class OrganizationResourcesDistributionService extends Service {
|
||||
private final OrganizationResourcesDistributor resourcesDistributor;
|
||||
private final ResourceValidator resourceValidator;
|
||||
|
||||
@Inject
|
||||
public OrganizationResourcesDistributionService(
|
||||
OrganizationResourcesDistributor resourcesDistributor, ResourceValidator resourceValidator) {
|
||||
this.resourcesDistributor = resourcesDistributor;
|
||||
this.resourceValidator = resourceValidator;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/{suborganizationId}/cap")
|
||||
@Consumes(APPLICATION_JSON)
|
||||
@Operation(
|
||||
summary =
|
||||
"Cap usage of shared resources.. By default suborganization is able to use all parent organization resources."
|
||||
+ "Cap allow to limit usage of shared resources by suborganization.",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "204", description = "Resources successfully capped"),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Missed required parameters, parameters are not valid"),
|
||||
@ApiResponse(responseCode = "404", description = "Specified organization was not found"),
|
||||
@ApiResponse(
|
||||
responseCode = "409",
|
||||
description = "Specified organization is root organization"),
|
||||
@ApiResponse(
|
||||
responseCode = "409",
|
||||
description = "Suborganization is using shared resources"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public void capResources(
|
||||
@Parameter(description = "Suborganization id") @PathParam("suborganizationId")
|
||||
String suborganizationId,
|
||||
@Parameter(description = "Resources to cap") List<ResourceDto> resourcesCap)
|
||||
throws BadRequestException, NotFoundException, ConflictException, ServerException {
|
||||
checkArgument(resourcesCap != null, "Missed resources caps.");
|
||||
Set<String> resourcesToSet = new HashSet<>();
|
||||
for (ResourceDto resource : resourcesCap) {
|
||||
if (!resourcesToSet.add(resource.getType())) {
|
||||
throw new BadRequestException(
|
||||
format(
|
||||
"Resources to cap must contain only one resource with type '%s'.",
|
||||
resource.getType()));
|
||||
}
|
||||
resourceValidator.validate(resource);
|
||||
}
|
||||
|
||||
resourcesDistributor.capResources(suborganizationId, resourcesCap);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{suborganizationId}/cap")
|
||||
@Produces(APPLICATION_JSON)
|
||||
@Operation(
|
||||
summary = "Get resources cap of specified suborganization.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Resources caps successfully fetched",
|
||||
content =
|
||||
@Content(
|
||||
array =
|
||||
@ArraySchema(
|
||||
schema =
|
||||
@Schema(
|
||||
implementation = OrganizationDistributedResourcesDto.class)))),
|
||||
@ApiResponse(responseCode = "404", description = "Specified organization was not found"),
|
||||
@ApiResponse(
|
||||
responseCode = "409",
|
||||
description = "Specified organization is root organization"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public List<ResourceDto> getResourcesCap(
|
||||
@Parameter(description = "Suborganization id") @PathParam("suborganizationId")
|
||||
String suborganization)
|
||||
throws NotFoundException, ConflictException, ServerException {
|
||||
return resourcesDistributor.getResourcesCaps(suborganization).stream()
|
||||
.map(org.eclipse.che.multiuser.resource.api.DtoConverter::asDto)
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{organizationId}")
|
||||
@Produces(APPLICATION_JSON)
|
||||
@Operation(
|
||||
summary = "Get resources which are distributed by specified parent.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Resources caps successfully fetched",
|
||||
content =
|
||||
@Content(
|
||||
array =
|
||||
@ArraySchema(
|
||||
schema =
|
||||
@Schema(
|
||||
implementation = OrganizationDistributedResourcesDto.class)))),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error occurred")
|
||||
})
|
||||
public Response getDistributedResources(
|
||||
@Parameter(description = "Organization id") @PathParam("organizationId")
|
||||
String organizationId,
|
||||
@Parameter(description = "Max items") @QueryParam("maxItems") @DefaultValue("30")
|
||||
int maxItems,
|
||||
@Parameter(description = "Skip count") @QueryParam("skipCount") @DefaultValue("0")
|
||||
long skipCount)
|
||||
throws BadRequestException, ServerException {
|
||||
checkArgument(maxItems >= 0, "The number of items to return can't be negative.");
|
||||
checkArgument(skipCount >= 0, "The number of items to skip can't be negative.");
|
||||
|
||||
final Page<? extends OrganizationDistributedResources> distributedResourcesPage =
|
||||
resourcesDistributor.getByParent(organizationId, maxItems, skipCount);
|
||||
return Response.ok()
|
||||
.entity(distributedResourcesPage.getItems(DtoConverter::asDto))
|
||||
.header("Link", createLinkHeader(distributedResourcesPage))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving one or more parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @param errorMessage the exception message to use if the check fails
|
||||
* @throws BadRequestException if {@code expression} is false
|
||||
*/
|
||||
private void checkArgument(boolean expression, String errorMessage) throws BadRequestException {
|
||||
if (!expression) {
|
||||
throw new BadRequestException(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2024 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.organization.api.resource;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.commons.lang.concurrent.Unlocker;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.OrganizationDistributedResources;
|
||||
import org.eclipse.che.multiuser.organization.spi.OrganizationDistributedResourcesDao;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationDistributedResourcesImpl;
|
||||
import org.eclipse.che.multiuser.resource.api.ResourceAggregator;
|
||||
import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException;
|
||||
import org.eclipse.che.multiuser.resource.api.type.RamResourceType;
|
||||
import org.eclipse.che.multiuser.resource.api.type.RuntimeResourceType;
|
||||
import org.eclipse.che.multiuser.resource.api.type.WorkspaceResourceType;
|
||||
import org.eclipse.che.multiuser.resource.api.usage.ResourceManager;
|
||||
import org.eclipse.che.multiuser.resource.api.usage.ResourcesLocks;
|
||||
import org.eclipse.che.multiuser.resource.model.Resource;
|
||||
|
||||
/**
|
||||
* Facade for organization resources operations.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class OrganizationResourcesDistributor {
|
||||
private final OrganizationDistributedResourcesDao organizationDistributedResourcesDao;
|
||||
private final OrganizationManager organizationManager;
|
||||
private final ResourcesLocks resourcesLocks;
|
||||
private final ResourceManager resourceManager;
|
||||
private final ResourceAggregator resourceAggregator;
|
||||
|
||||
@Inject
|
||||
public OrganizationResourcesDistributor(
|
||||
OrganizationDistributedResourcesDao organizationDistributedResourcesDao,
|
||||
OrganizationManager organizationManager,
|
||||
ResourcesLocks resourcesLocks,
|
||||
ResourceManager resourceManager,
|
||||
ResourceAggregator resourceAggregator) {
|
||||
this.organizationDistributedResourcesDao = organizationDistributedResourcesDao;
|
||||
this.organizationManager = organizationManager;
|
||||
this.resourcesLocks = resourcesLocks;
|
||||
this.resourceManager = resourceManager;
|
||||
this.resourceAggregator = resourceAggregator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cap usage of shared resources.
|
||||
*
|
||||
* <p>By default suborganization is able to use all parent organization resources Cap allow to
|
||||
* limit usage of shared resources by suborganization.
|
||||
*
|
||||
* @param suborganizationId suborganization id
|
||||
* @param resourcesCaps resources to capped
|
||||
* @throws NotFoundException when specified suborganization was not found
|
||||
* @throws ConflictException when organization with specified id is root organization
|
||||
* @throws ConflictException when suborganization is currently using more shared resources than
|
||||
* should be capped
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
public void capResources(String suborganizationId, List<? extends Resource> resourcesCaps)
|
||||
throws NotFoundException, ConflictException, ServerException {
|
||||
requireNonNull(suborganizationId, "Required non-null suborganization id");
|
||||
requireNonNull(resourcesCaps, "Required non-null resources to capResources");
|
||||
checkIsSuborganization(suborganizationId);
|
||||
|
||||
// remove caps with amount -1
|
||||
resourcesCaps = resourcesCaps.stream().filter(res -> res.getAmount() != -1).collect(toList());
|
||||
|
||||
// locking resources by suborganization should lock resources whole organization tree
|
||||
// so we can check resource availability for suborganization organization
|
||||
try (@SuppressWarnings("unused")
|
||||
Unlocker u = resourcesLocks.lock(suborganizationId)) {
|
||||
if (resourcesCaps.isEmpty()) {
|
||||
organizationDistributedResourcesDao.remove(suborganizationId);
|
||||
} else {
|
||||
checkResourcesAvailability(suborganizationId, resourcesCaps);
|
||||
|
||||
organizationDistributedResourcesDao.store(
|
||||
new OrganizationDistributedResourcesImpl(suborganizationId, resourcesCaps));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns resources cap or empty list.
|
||||
*
|
||||
* @param suborganizationId suborganization id to fetch resources cap
|
||||
* @return resources cap or empty list
|
||||
* @throws NotFoundException when specified suborganization was not found
|
||||
* @throws ConflictException when organization with specified id is root organization
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
public List<? extends Resource> getResourcesCaps(String suborganizationId)
|
||||
throws NotFoundException, ConflictException, ServerException {
|
||||
requireNonNull(suborganizationId, "Required non-null suborganization id");
|
||||
checkIsSuborganization(suborganizationId);
|
||||
try {
|
||||
return organizationDistributedResourcesDao.get(suborganizationId).getResourcesCap();
|
||||
} catch (NotFoundException e) {
|
||||
return emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns distributed resources for specified suborganization.
|
||||
*
|
||||
* @param suborganizationId organization id
|
||||
* @return distributed resources for suborganization with specified id
|
||||
* @throws NullPointerException when either {@code suborganizationId} is null
|
||||
* @throws NotFoundException when there is not distributed resources for specified suborganization
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
public OrganizationDistributedResources get(String suborganizationId)
|
||||
throws NotFoundException, ServerException {
|
||||
requireNonNull(suborganizationId, "Required non-null organization id");
|
||||
|
||||
return organizationDistributedResourcesDao.get(suborganizationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns distributed resources for suborganizations by specified parent organization.
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @return distributed resources for suborganizations by specified parent organization
|
||||
* @throws NullPointerException when either {@code organizationId} is null
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
public Page<? extends OrganizationDistributedResources> getByParent(
|
||||
String organizationId, int maxItems, long skipCount) throws ServerException {
|
||||
requireNonNull(organizationId, "Required non-null organization id");
|
||||
|
||||
return organizationDistributedResourcesDao.getByParent(organizationId, maxItems, skipCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that suborganization is using less resources that new resources cap defines.
|
||||
*
|
||||
* @param suborganizationId identifier of suborganization
|
||||
* @param newResourcesCap resources to capResources
|
||||
* @throws ConflictException when parent organization doesn't have enough resources to increase
|
||||
* distributed resource amount
|
||||
* @throws ConflictException when resources can't be distributed because suborganization is using
|
||||
* existing resources or when they are distributed to next organizations level
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void checkResourcesAvailability(
|
||||
String suborganizationId, List<? extends Resource> newResourcesCap)
|
||||
throws NotFoundException, ConflictException, ServerException {
|
||||
Map<String, Resource> usedResources =
|
||||
resourceManager.getUsedResources(suborganizationId).stream()
|
||||
.collect(Collectors.toMap(Resource::getType, Function.identity()));
|
||||
for (Resource resourceToCheck : newResourcesCap) {
|
||||
Resource usedResource = usedResources.get(resourceToCheck.getType());
|
||||
if (usedResource != null) {
|
||||
try {
|
||||
resourceAggregator.deduct(resourceToCheck, usedResource);
|
||||
} catch (NoEnoughResourcesException e) {
|
||||
throw new ConflictException(
|
||||
"Resources are currently in use. "
|
||||
+ getMessage(e.getMissingResources().get(0).getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String getMessage(String requiredResourceType) {
|
||||
switch (requiredResourceType) {
|
||||
case RamResourceType.ID:
|
||||
return "You can't decrease RAM CAP, while the resources are in use. "
|
||||
+ "Free resources, by stopping workspaces, before changing the RAM CAP.";
|
||||
case WorkspaceResourceType.ID:
|
||||
return "You can't reduce the workspaces CAP to a value lower than the number of workspaces currently created. "
|
||||
+ "Free resources, by removing workspaces, before changing the workspaces CAP.";
|
||||
case RuntimeResourceType.ID:
|
||||
return "You can't reduce the running workspaces CAP to a value lower than the number of workspaces currently running. "
|
||||
+ "Free resources, by stopping workspaces, before changing the running workspaces CAP.";
|
||||
default:
|
||||
return "You can't reduce them while they are used. "
|
||||
+ "Free resources before changing the resources CAP.";
|
||||
}
|
||||
}
|
||||
|
||||
private String checkIsSuborganization(String organizationId)
|
||||
throws NotFoundException, ConflictException, ServerException {
|
||||
String parentOrganization = organizationManager.getById(organizationId).getParent();
|
||||
if (parentOrganization == null) {
|
||||
throw new ConflictException("It is not allowed to cap resources for root organization.");
|
||||
}
|
||||
return parentOrganization;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api.resource;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Pages;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.eclipse.che.multiuser.resource.api.AvailableResourcesProvider;
|
||||
import org.eclipse.che.multiuser.resource.api.ResourceAggregator;
|
||||
import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException;
|
||||
import org.eclipse.che.multiuser.resource.api.usage.ResourceManager;
|
||||
import org.eclipse.che.multiuser.resource.model.Resource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Provides available resources for organizational and suborganizational accounts.
|
||||
*
|
||||
* <p>Root organizational account can use resources by itself or share them for its
|
||||
* suborganizations. So available resources equal to total resources minus resources which are
|
||||
* already used by organization or by any of its suborganizations.
|
||||
*
|
||||
* <p>Suborganizational account can use all of parent resources or limited amount. So available
|
||||
* resource equal to minimum of parent available resources and parent shared resources minus
|
||||
* resources which are used by suborganization and its suborganizations.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class OrganizationalAccountAvailableResourcesProvider implements AvailableResourcesProvider {
|
||||
private static final Logger LOG =
|
||||
LoggerFactory.getLogger(OrganizationalAccountAvailableResourcesProvider.class);
|
||||
|
||||
private final Provider<ResourceManager> resourceManagerProvider;
|
||||
private final ResourceAggregator resourceAggregator;
|
||||
private final OrganizationManager organizationManager;
|
||||
|
||||
@Inject
|
||||
public OrganizationalAccountAvailableResourcesProvider(
|
||||
Provider<ResourceManager> resourceManagerProvider,
|
||||
ResourceAggregator resourceAggregator,
|
||||
OrganizationManager organizationManager) {
|
||||
this.resourceManagerProvider = resourceManagerProvider;
|
||||
this.resourceAggregator = resourceAggregator;
|
||||
this.organizationManager = organizationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Resource> getAvailableResources(String accountId)
|
||||
throws NotFoundException, ServerException {
|
||||
Organization organization = organizationManager.getById(accountId);
|
||||
|
||||
if (organization.getParent() == null) {
|
||||
return getAvailableOrganizationResources(organization);
|
||||
} else {
|
||||
Organization parentOrganization = organizationManager.getById(organization.getParent());
|
||||
return resourceAggregator.min(
|
||||
resourceAggregator.intersection(
|
||||
getAvailableOrganizationResources(parentOrganization),
|
||||
getAvailableOrganizationResources(organization)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns total resources minus resources which are already used by organization or by any of its
|
||||
* suborganizations.
|
||||
*
|
||||
* @param organization organization id to calculate its available resources
|
||||
* @return resources which are available for usage by specified organization
|
||||
* @throws NotFoundException when organization with specified id doesn't exist
|
||||
* @throws ServerException when any other exception occurs on calculation of available resources
|
||||
*/
|
||||
@VisibleForTesting
|
||||
List<? extends Resource> getAvailableOrganizationResources(Organization organization)
|
||||
throws NotFoundException, ServerException {
|
||||
final ResourceManager resourceManager = resourceManagerProvider.get();
|
||||
final List<? extends Resource> total = resourceManager.getTotalResources(organization.getId());
|
||||
final List<Resource> unavailable =
|
||||
new ArrayList<>(resourceManager.getUsedResources(organization.getId()));
|
||||
unavailable.addAll(getUsedResourcesBySuborganizations(organization.getQualifiedName()));
|
||||
try {
|
||||
return resourceAggregator.deduct(total, unavailable);
|
||||
} catch (NoEnoughResourcesException e) {
|
||||
LOG.warn(
|
||||
"Organization with id {} uses more resources {} than it has {}.",
|
||||
organization.getId(),
|
||||
format(unavailable),
|
||||
format(total));
|
||||
return resourceAggregator.excess(total, unavailable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns resources which are used by suborganizations of specified organization.
|
||||
*
|
||||
* <p>Note that the result will includes used resources of all direct and nested suborganizations.
|
||||
*
|
||||
* @param parentQualifiedName parent qualified name, e.g. 'parentName/suborgName
|
||||
* @return resources which are used by suborganizations of specified organization.
|
||||
* @throws ServerException when any other exception occurs on calculation of used resources
|
||||
*/
|
||||
@VisibleForTesting
|
||||
List<Resource> getUsedResourcesBySuborganizations(String parentQualifiedName)
|
||||
throws NotFoundException, ServerException {
|
||||
ResourceManager resourceManager = resourceManagerProvider.get();
|
||||
List<Resource> usedResources = new ArrayList<>();
|
||||
for (Organization suborganization :
|
||||
Pages.iterate(
|
||||
(maxItems, skipCount) ->
|
||||
organizationManager.getSuborganizations(
|
||||
parentQualifiedName, maxItems, skipCount))) {
|
||||
usedResources.addAll(resourceManager.getUsedResources(suborganization.getId()));
|
||||
}
|
||||
return usedResources;
|
||||
}
|
||||
|
||||
/** Returns formatted string for list of resources. */
|
||||
private static String format(Collection<? extends Resource> resources) {
|
||||
return '['
|
||||
+ resources.stream()
|
||||
.map(
|
||||
resource -> resource.getAmount() + resource.getUnit() + " of " + resource.getType())
|
||||
.collect(Collectors.joining(", "))
|
||||
+ ']';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api.resource;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.account.api.AccountManager;
|
||||
import org.eclipse.che.account.shared.model.Account;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
import org.eclipse.che.multiuser.resource.api.ResourcesProvider;
|
||||
import org.eclipse.che.multiuser.resource.api.usage.ResourceManager;
|
||||
import org.eclipse.che.multiuser.resource.model.ProvidedResources;
|
||||
import org.eclipse.che.multiuser.resource.model.Resource;
|
||||
import org.eclipse.che.multiuser.resource.spi.impl.ProvidedResourcesImpl;
|
||||
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
|
||||
|
||||
/**
|
||||
* Provides resources that are shared for suborganization by its parent organization.
|
||||
*
|
||||
* <p>By default suborganizations are able to use parent's resources. Parent organization can limit
|
||||
* usage of resources by suborganization by setting resources caps.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Singleton
|
||||
public class SuborganizationResourcesProvider implements ResourcesProvider {
|
||||
public static final String PARENT_RESOURCES_PROVIDER = "parentOrganization";
|
||||
|
||||
private final AccountManager accountManager;
|
||||
private final OrganizationManager organizationManager;
|
||||
private final Provider<OrganizationResourcesDistributor> distributorProvider;
|
||||
private final Provider<ResourceManager> resourceManagerProvider;
|
||||
|
||||
@Inject
|
||||
public SuborganizationResourcesProvider(
|
||||
AccountManager accountManager,
|
||||
OrganizationManager organizationManager,
|
||||
Provider<OrganizationResourcesDistributor> distributorProvider,
|
||||
Provider<ResourceManager> resourceManagerProvider) {
|
||||
this.accountManager = accountManager;
|
||||
this.organizationManager = organizationManager;
|
||||
this.distributorProvider = distributorProvider;
|
||||
this.resourceManagerProvider = resourceManagerProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProvidedResources> getResources(String accountId)
|
||||
throws NotFoundException, ServerException {
|
||||
final Account account = accountManager.getById(accountId);
|
||||
String parent;
|
||||
|
||||
if (!OrganizationImpl.ORGANIZATIONAL_ACCOUNT.equals(account.getType())
|
||||
|| (parent = organizationManager.getById(accountId).getParent()) == null) {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
// given account is suborganization's account and can have resources provided by parent
|
||||
List<? extends Resource> parentTotalResources =
|
||||
resourceManagerProvider.get().getTotalResources(parent);
|
||||
|
||||
if (!parentTotalResources.isEmpty()) {
|
||||
try {
|
||||
List<? extends Resource> resourcesCaps =
|
||||
distributorProvider.get().getResourcesCaps(accountId);
|
||||
|
||||
return singletonList(
|
||||
new ProvidedResourcesImpl(
|
||||
PARENT_RESOURCES_PROVIDER,
|
||||
null,
|
||||
accountId,
|
||||
-1L,
|
||||
-1L,
|
||||
cap(parentTotalResources, resourcesCaps)));
|
||||
} catch (ConflictException e) {
|
||||
throw new ServerException(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
private List<ResourceImpl> cap(
|
||||
Collection<? extends Resource> source, List<? extends Resource> caps) {
|
||||
final Map<String, Resource> resourcesCaps =
|
||||
caps.stream().collect(toMap(Resource::getType, Function.identity()));
|
||||
return source.stream()
|
||||
.map(
|
||||
resource -> {
|
||||
Resource resourceCap = resourcesCaps.get(resource.getType());
|
||||
if (resourceCap != null) {
|
||||
if (resource.getAmount() == -1) {
|
||||
return resourceCap;
|
||||
} else if (resourceCap.getAmount() < resource.getAmount()) {
|
||||
return resourceCap;
|
||||
}
|
||||
}
|
||||
return resource;
|
||||
})
|
||||
.map(ResourceImpl::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* 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.organization.spi;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
|
||||
/**
|
||||
* Defines data access object for {@link MemberImpl}
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public interface MemberDao {
|
||||
/**
|
||||
* Stores (adds or updates) member.
|
||||
*
|
||||
* @param member member to store
|
||||
* @return optional with updated member, other way empty optional must be returned
|
||||
* @throws NullPointerException when {@code member} is null
|
||||
* @throws ServerException when organization or user doesn't exist
|
||||
* @throws ServerException when any other error occurs during member storing
|
||||
*/
|
||||
Optional<MemberImpl> store(MemberImpl member) throws ServerException;
|
||||
|
||||
/**
|
||||
* Removes member with given organization and user
|
||||
*
|
||||
* @param userId id of user
|
||||
* @param organizationId id of organization
|
||||
* @throws NullPointerException when {@code organizationId} or {@code userId} is null
|
||||
* @throws ServerException when any other error occurs during member removing
|
||||
*/
|
||||
void remove(String userId, String organizationId) throws ServerException;
|
||||
|
||||
/**
|
||||
* Returns member for specified organization and user
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @param userId user id
|
||||
* @return member for specified organization and user
|
||||
* @throws NullPointerException when {@code organizationId} or {@code userId} is null
|
||||
* @throws NotFoundException when member for given user and organization was not found
|
||||
* @throws ServerException when any other error occurs during member fetching
|
||||
*/
|
||||
MemberImpl getMember(String organizationId, String userId)
|
||||
throws NotFoundException, ServerException;
|
||||
|
||||
/**
|
||||
* Returns all members of given organization
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @param maxItems the maximum number of members to return
|
||||
* @param skipCount the number of members to skip
|
||||
* @throws NullPointerException when {@code organizationId} is null
|
||||
* @throws ServerException when any other error occurs during members fetching
|
||||
*/
|
||||
Page<MemberImpl> getMembers(String organizationId, int maxItems, long skipCount)
|
||||
throws ServerException;
|
||||
|
||||
/**
|
||||
* Returns all memberships of given user
|
||||
*
|
||||
* @param userId user id
|
||||
* @throws NullPointerException when {@code userId} is null
|
||||
* @throws ServerException when any other error occurs during members fetching
|
||||
*/
|
||||
List<MemberImpl> getMemberships(String userId) throws ServerException;
|
||||
|
||||
/**
|
||||
* Gets list organizations where user is member.
|
||||
*
|
||||
* @param userId user id
|
||||
* @param maxItems the maximum number of organizations to return
|
||||
* @param skipCount the number of organizations to skip
|
||||
* @return list of organizations where user is member
|
||||
* @throws NullPointerException when {@code userId} is null
|
||||
* @throws ServerException when any other error occurs during organizations fetching
|
||||
*/
|
||||
Page<OrganizationImpl> getOrganizations(String userId, int maxItems, long skipCount)
|
||||
throws ServerException;
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* 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.organization.spi;
|
||||
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
|
||||
/**
|
||||
* Defines data access object for {@link OrganizationImpl}
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public interface OrganizationDao {
|
||||
/**
|
||||
* Creates organization.
|
||||
*
|
||||
* @param organization organization to create
|
||||
* @throws NullPointerException when {@code organization} is null
|
||||
* @throws ConflictException when organization with such id/name already exists
|
||||
* @throws ServerException when any other error occurs during organization creation
|
||||
*/
|
||||
void create(OrganizationImpl organization) throws ServerException, ConflictException;
|
||||
|
||||
/**
|
||||
* Updates organization with new entity.
|
||||
*
|
||||
* @param update organization update
|
||||
* @throws NullPointerException when {@code update} is null
|
||||
* @throws NotFoundException when organization with id {@code organization.getId()} doesn't exist
|
||||
* @throws ConflictException when name updated with a value which is not unique
|
||||
* @throws ServerException when any other error occurs organization updating
|
||||
*/
|
||||
void update(OrganizationImpl update) throws NotFoundException, ConflictException, ServerException;
|
||||
|
||||
/**
|
||||
* Removes organization with given id
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @throws NullPointerException when {@code organizationId} is null
|
||||
* @throws ServerException when any other error occurs during organization removing
|
||||
*/
|
||||
void remove(String organizationId) throws ServerException;
|
||||
|
||||
/**
|
||||
* Gets organization by identifier.
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @return organization instance
|
||||
* @throws NullPointerException when {@code organizationId} is null
|
||||
* @throws NotFoundException when organization with given id was not found
|
||||
* @throws ServerException when any other error occurs during organization fetching
|
||||
*/
|
||||
OrganizationImpl getById(String organizationId) throws NotFoundException, ServerException;
|
||||
|
||||
/**
|
||||
* Gets organization by name.
|
||||
*
|
||||
* @param organizationName organization name
|
||||
* @return organization instance
|
||||
* @throws NullPointerException when {@code organizationName} is null
|
||||
* @throws NotFoundException when organization with given name was not found
|
||||
* @throws ServerException when any other error occurs during organization fetching
|
||||
*/
|
||||
OrganizationImpl getByName(String organizationName) throws NotFoundException, ServerException;
|
||||
|
||||
/**
|
||||
* Gets child organizations by given parent.
|
||||
*
|
||||
* @param parent id of parent organization
|
||||
* @param maxItems the maximum number of organizations to return
|
||||
* @param skipCount the number of organizations to skip
|
||||
* @return list of children organizations
|
||||
* @throws NullPointerException when {@code parent} is null
|
||||
* @throws ServerException when any other error occurs during organizations fetching
|
||||
*/
|
||||
Page<OrganizationImpl> getByParent(String parent, int maxItems, long skipCount)
|
||||
throws ServerException;
|
||||
|
||||
/**
|
||||
* Gets all child organizations by specified parent qualified name.
|
||||
*
|
||||
* <p>Note that the result will includes all direct and nested suborganizations.
|
||||
*
|
||||
* @param parentQualifiedName qualified name of parent organization
|
||||
* @param maxItems the maximum number of organizations to return
|
||||
* @param skipCount the number of organizations to skip
|
||||
* @return list of children organizations
|
||||
* @throws NullPointerException when {@code parentQualifiedName} is null
|
||||
* @throws ServerException when any other error occurs during organizations fetching
|
||||
*/
|
||||
Page<OrganizationImpl> getSuborganizations(
|
||||
String parentQualifiedName, int maxItems, long skipCount) throws ServerException;
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* 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.organization.spi;
|
||||
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationDistributedResourcesImpl;
|
||||
|
||||
/**
|
||||
* Defines data access object contract for {@link OrganizationDistributedResourcesImpl}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
public interface OrganizationDistributedResourcesDao {
|
||||
/**
|
||||
* Stores (creates or updated) distributed resources for suborganization.
|
||||
*
|
||||
* @param distributedResources distributed resources to store
|
||||
* @throws NullPointerException when either {@code distributedResources} is null
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
void store(OrganizationDistributedResourcesImpl distributedResources) throws ServerException;
|
||||
|
||||
/**
|
||||
* Returns distributed resources for specified suborganization.
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @return distributed resources for specified suborganization
|
||||
* @throws NullPointerException when either {@code organizationId} is null
|
||||
* @throws NotFoundException when organization with specified id doesn't have distributed
|
||||
* resources
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
OrganizationDistributedResourcesImpl get(String organizationId)
|
||||
throws NotFoundException, ServerException;
|
||||
|
||||
/**
|
||||
* Returns distributed resources for suborganizations of given parent organization.
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @return distributed resources for suborganizations of given parent organization
|
||||
* @throws NullPointerException when either {@code organizationId} is null
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
Page<OrganizationDistributedResourcesImpl> getByParent(
|
||||
String organizationId, int maxItems, long skipCount) throws ServerException;
|
||||
|
||||
/**
|
||||
* Remove distributed organization resources.
|
||||
*
|
||||
* @param organizationId organization id
|
||||
* @throws NullPointerException when either {@code organizationId} is null
|
||||
* @throws ServerException when any other error occurs
|
||||
*/
|
||||
void remove(String organizationId) throws ServerException;
|
||||
}
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* 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.organization.spi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Member;
|
||||
|
||||
/**
|
||||
* Data object for {@link Member}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Entity(name = "Member")
|
||||
@NamedQueries({
|
||||
@NamedQuery(
|
||||
name = "Member.getMember",
|
||||
query =
|
||||
"SELECT m "
|
||||
+ "FROM Member m "
|
||||
+ "WHERE m.userId = :userId AND m.organizationId = :organizationId"),
|
||||
@NamedQuery(
|
||||
name = "Member.getByOrganization",
|
||||
query = "SELECT m " + "FROM Member m " + "WHERE m.organizationId = :organizationId"),
|
||||
@NamedQuery(
|
||||
name = "Member.getCountByOrganizationId",
|
||||
query = "SELECT COUNT(m) " + "FROM Member m " + "WHERE m.organizationId = :organizationId"),
|
||||
@NamedQuery(
|
||||
name = "Member.getByUser",
|
||||
query = "SELECT m " + "FROM Member m " + "WHERE m.userId = :userId"),
|
||||
@NamedQuery(
|
||||
name = "Member.getOrganizations",
|
||||
query = "SELECT org " + "FROM Member m, m.organization org " + "WHERE m.userId = :userId"),
|
||||
@NamedQuery(
|
||||
name = "Member.getOrganizationsCount",
|
||||
query = "SELECT COUNT(m) " + "FROM Member m " + "WHERE m.userId = :userId ")
|
||||
})
|
||||
@Table(name = "che_member")
|
||||
public class MemberImpl extends AbstractPermissions implements Member {
|
||||
@Column(name = "organization_id")
|
||||
private String organizationId;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@Column(name = "actions")
|
||||
@CollectionTable(name = "che_member_actions", joinColumns = @JoinColumn(name = "member_id"))
|
||||
protected List<String> actions;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(
|
||||
name = "organization_id",
|
||||
referencedColumnName = "id",
|
||||
insertable = false,
|
||||
updatable = false)
|
||||
private OrganizationImpl organization;
|
||||
|
||||
public MemberImpl() {}
|
||||
|
||||
public MemberImpl(String userId, String organizationId, List<String> actions) {
|
||||
super(userId);
|
||||
this.organizationId = organizationId;
|
||||
if (actions != null) {
|
||||
this.actions = actions;
|
||||
}
|
||||
}
|
||||
|
||||
public MemberImpl(Member member) {
|
||||
this(member.getUserId(), member.getOrganizationId(), member.getActions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInstanceId() {
|
||||
return organizationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDomainId() {
|
||||
return OrganizationDomain.DOMAIN_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrganizationId() {
|
||||
return organizationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MemberImpl{"
|
||||
+ "userId='"
|
||||
+ userId
|
||||
+ '\''
|
||||
+ ", organizationId='"
|
||||
+ organizationId
|
||||
+ '\''
|
||||
+ ", actions="
|
||||
+ actions
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
* 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.organization.spi.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.PrimaryKeyJoinColumn;
|
||||
import javax.persistence.Table;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.OrganizationDistributedResources;
|
||||
import org.eclipse.che.multiuser.resource.model.Resource;
|
||||
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
|
||||
|
||||
/**
|
||||
* Data object for {@link OrganizationDistributedResources}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Entity(name = "OrganizationDistributedResources")
|
||||
@NamedQueries({
|
||||
@NamedQuery(
|
||||
name = "OrganizationDistributedResources.get",
|
||||
query =
|
||||
"SELECT r "
|
||||
+ "FROM OrganizationDistributedResources r "
|
||||
+ "WHERE r.organizationId = :organizationId"),
|
||||
@NamedQuery(
|
||||
name = "OrganizationDistributedResources.getByParent",
|
||||
query =
|
||||
"SELECT r "
|
||||
+ "FROM OrganizationDistributedResources r "
|
||||
+ "WHERE r.organization.parent = :parent"),
|
||||
@NamedQuery(
|
||||
name = "OrganizationDistributedResources.getCountByParent",
|
||||
query =
|
||||
"SELECT COUNT(r) "
|
||||
+ "FROM OrganizationDistributedResources r "
|
||||
+ "WHERE r.organization.parent = :parent")
|
||||
})
|
||||
@Table(name = "che_organization_distributed_resources")
|
||||
public class OrganizationDistributedResourcesImpl implements OrganizationDistributedResources {
|
||||
@Id
|
||||
@Column(name = "organization_id")
|
||||
private String organizationId;
|
||||
|
||||
@PrimaryKeyJoinColumn private OrganizationImpl organization;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinTable(
|
||||
name = "che_organization_distributed_resources_resource",
|
||||
joinColumns = @JoinColumn(name = "organization_distributed_resources_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "resource_id"))
|
||||
private List<ResourceImpl> resourcesCap;
|
||||
|
||||
public OrganizationDistributedResourcesImpl() {}
|
||||
|
||||
public OrganizationDistributedResourcesImpl(
|
||||
OrganizationDistributedResources organizationDistributedResource) {
|
||||
this(
|
||||
organizationDistributedResource.getOrganizationId(),
|
||||
organizationDistributedResource.getResourcesCap());
|
||||
}
|
||||
|
||||
public OrganizationDistributedResourcesImpl(
|
||||
String organizationId, List<? extends Resource> resourcesCap) {
|
||||
this.organizationId = organizationId;
|
||||
if (resourcesCap != null) {
|
||||
this.resourcesCap = resourcesCap.stream().map(ResourceImpl::new).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrganizationId() {
|
||||
return organizationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResourceImpl> getResourcesCap() {
|
||||
if (resourcesCap == null) {
|
||||
resourcesCap = new ArrayList<>();
|
||||
}
|
||||
return resourcesCap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof OrganizationDistributedResourcesImpl)) {
|
||||
return false;
|
||||
}
|
||||
final OrganizationDistributedResourcesImpl that = (OrganizationDistributedResourcesImpl) obj;
|
||||
return Objects.equals(organizationId, that.organizationId)
|
||||
&& Objects.equals(organization, that.organization)
|
||||
&& getResourcesCap().equals(that.getResourcesCap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 31 * hash + Objects.hashCode(organizationId);
|
||||
hash = 31 * hash + Objects.hashCode(organization);
|
||||
hash = 31 * hash + getResourcesCap().hashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OrganizationDistributedResourcesImpl{"
|
||||
+ "organizationId='"
|
||||
+ organizationId
|
||||
+ '\''
|
||||
+ ", organization="
|
||||
+ organization
|
||||
+ ", resourcesCaps="
|
||||
+ getResourcesCap()
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* 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.organization.spi.impl;
|
||||
|
||||
import java.util.Objects;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.eclipse.che.account.spi.AccountImpl;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
|
||||
/**
|
||||
* Data object for {@link Organization}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Entity(name = "Organization")
|
||||
@NamedQueries({
|
||||
@NamedQuery(
|
||||
name = "Organization.getByName",
|
||||
query = "SELECT o " + "FROM Organization o " + "WHERE o.account.name = :name"),
|
||||
@NamedQuery(
|
||||
name = "Organization.getByParent",
|
||||
query = "SELECT o " + "FROM Organization o " + "WHERE o.parent = :parent "),
|
||||
@NamedQuery(
|
||||
name = "Organization.getByParentCount",
|
||||
query = "SELECT COUNT(o) " + "FROM Organization o " + "WHERE o.parent = :parent "),
|
||||
@NamedQuery(
|
||||
name = "Organization.getSuborganizations",
|
||||
query = "SELECT o " + "FROM Organization o " + "WHERE o.account.name LIKE :qualifiedName "),
|
||||
@NamedQuery(
|
||||
name = "Organization.getSuborganizationsCount",
|
||||
query =
|
||||
"SELECT COUNT(o) " + "FROM Organization o " + "WHERE o.account.name LIKE :qualifiedName ")
|
||||
})
|
||||
@Table(name = "che_organization")
|
||||
public class OrganizationImpl implements Organization {
|
||||
public static final String ORGANIZATIONAL_ACCOUNT = "organizational";
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private String id;
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "account_id", nullable = false)
|
||||
private AccountImpl account;
|
||||
|
||||
@Column(name = "parent")
|
||||
private String parent;
|
||||
|
||||
// Mapping exists for explicit constraints which allows
|
||||
// jpa backend to perform operations in correct order
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "parent", insertable = false, updatable = false)
|
||||
private OrganizationImpl parentObj;
|
||||
|
||||
public OrganizationImpl() {}
|
||||
|
||||
public OrganizationImpl(Organization organization) {
|
||||
this(organization.getId(), organization.getQualifiedName(), organization.getParent());
|
||||
}
|
||||
|
||||
public OrganizationImpl(String id, String qualifiedName, String parent) {
|
||||
this.id = id;
|
||||
this.account = new AccountImpl(id, qualifiedName, ORGANIZATIONAL_ACCOUNT);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
String qualifiedName = getQualifiedName();
|
||||
if (qualifiedName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int lastSlashIndex = qualifiedName.lastIndexOf("/");
|
||||
|
||||
if (lastSlashIndex == -1) {
|
||||
return qualifiedName;
|
||||
}
|
||||
|
||||
return qualifiedName.substring(lastSlashIndex + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQualifiedName() {
|
||||
if (account != null) {
|
||||
return account.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setQualifiedName(String qualifiedName) {
|
||||
if (account != null) {
|
||||
account.setName(qualifiedName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(String parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public AccountImpl getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof OrganizationImpl)) {
|
||||
return false;
|
||||
}
|
||||
OrganizationImpl that = (OrganizationImpl) o;
|
||||
return Objects.equals(id, that.id)
|
||||
&& Objects.equals(getName(), that.getName())
|
||||
&& Objects.equals(parent, that.parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 31 * hash + Objects.hashCode(id);
|
||||
hash = 31 * hash + Objects.hashCode(getName());
|
||||
hash = 31 * hash + Objects.hashCode(getQualifiedName());
|
||||
hash = 31 * hash + Objects.hashCode(parent);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OrganizationImpl{"
|
||||
+ "id='"
|
||||
+ id
|
||||
+ '\''
|
||||
+ ", name='"
|
||||
+ getName()
|
||||
+ '\''
|
||||
+ ", qualifiedName='"
|
||||
+ getQualifiedName()
|
||||
+ '\''
|
||||
+ ", parent='"
|
||||
+ parent
|
||||
+ '\''
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
\<html>
|
||||
\<head>
|
||||
\<style>@import url(https://fonts.googleapis.com/css?family=Roboto);\</style>
|
||||
\</head>
|
||||
\<body style="width: 700px; margin: 0 auto; font-size: 16px; font-family: Roboto;">
|
||||
\<div style="background-color: #292c2f; color: white; padding: 25px 10px;">
|
||||
\<span style="font-size: 26px; color: #cccccc;">Eclipse Che\</span>
|
||||
\<div style="height: 50px">\</div>
|
||||
\<span style="font-size: 24px; color: white;">Organization has been deleted\</span>
|
||||
\</div>
|
||||
|
||||
\<div style="padding: 10px;">
|
||||
\<p>Hi,\</p>
|
||||
\<p>\<b><organizationName>\</b> organization has been deleted.\</p>
|
||||
\</div>
|
||||
|
||||
\<div style="background-color: #292c2f; color: white; padding: 15px 10px 47px 10px;">
|
||||
\<a href="http://www.eclipse.org/che/">
|
||||
\<img src="https://www.eclipse.org/che/images/logo-eclipseche.svg" height="32" align="left" alt=" " />
|
||||
\</a>
|
||||
\</div>
|
||||
\</body>
|
||||
\</html>
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
\<html>
|
||||
\<head>
|
||||
\<style>@import url(https://fonts.googleapis.com/css?family=Roboto);\</style>
|
||||
\</head>
|
||||
\<body style="width: 700px; margin: 0 auto; font-size: 16px; font-family: Roboto;">
|
||||
\<div style="background-color: #292c2f; color: white; padding: 25px 10px;">
|
||||
\<span style="font-size: 26px; color: #cccccc;">Eclipse Che\</span>
|
||||
\<div style="height: 50px">\</div>
|
||||
\<span style="font-size: 24px; color: white;">Organization has been renamed\</span>
|
||||
\</div>
|
||||
|
||||
\<div style="padding: 10px;">
|
||||
\<p>Hi,\</p>
|
||||
\<p>\<b><orgOldName>\</b> organization has been renamed to \<b><orgNewName>\</b>\</p>
|
||||
\</div>
|
||||
|
||||
\<div style="background-color: #292c2f; color: white; padding: 15px 10px 47px 10px;">
|
||||
\<a href="http://www.eclipse.org/che/">
|
||||
\<img src="https://www.eclipse.org/che/images/logo-eclipseche.svg" height="32" align="left" alt=" " />
|
||||
\</a>
|
||||
\</div>
|
||||
\</body>
|
||||
\</html>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
\<html>
|
||||
\<head>
|
||||
\<style>@import url(https://fonts.googleapis.com/css?family=Roboto);\</style>
|
||||
\</head>
|
||||
\<body style="width: 700px; margin: 0 auto; font-size: 16px; font-family: Roboto;">
|
||||
\<div style="background-color: #292c2f; color: white; padding: 25px 10px;">
|
||||
\<span style="font-size: 26px; color: #cccccc;">Eclipse Che\</span>
|
||||
\<div style="height: 50px">\</div>
|
||||
\<span style="font-size: 24px; color: white;">User added to organization\</span>
|
||||
\</div>
|
||||
|
||||
\<div style="padding: 10px;">
|
||||
\<p>Hi,\</p>
|
||||
\<p>\<b><initiator>\</b> added you to a Che organization called \<b><organizationName>\</b>.\</p>
|
||||
\<p>Access the organization here \<a href="<dashboardEndpoint>/#/organization/<orgQualifiedName>">link\</a>.\</p>
|
||||
\</div>
|
||||
|
||||
\<div style="background-color: #292c2f; color: white; padding: 15px 10px 47px 10px;">
|
||||
\<a href="http://www.eclipse.org/che/">
|
||||
\<img src="https://www.eclipse.org/che/images/logo-eclipseche.svg" height="32" align="left" alt=" " />
|
||||
\</a>
|
||||
\</div>
|
||||
\</body>
|
||||
\</html>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
\<html>
|
||||
\<head>
|
||||
\<style>@import url(https://fonts.googleapis.com/css?family=Roboto);\</style>
|
||||
\</head>
|
||||
\<body style="width: 700px; margin: 0 auto; font-size: 16px; font-family: Roboto;">
|
||||
\<div style="background-color: #292c2f; color: white; padding: 25px 10px;">
|
||||
\<span style="font-size: 26px; color: #cccccc;">Eclipse Che\</span>
|
||||
\<div style="height: 50px">\</div>
|
||||
\<span style="font-size: 24px; color: white;">User removed from organization\</span>
|
||||
\</div>
|
||||
|
||||
\<div style="padding: 10px;">
|
||||
\<p>Hi,\</p>
|
||||
\<p>\<b><initiator>\</b> removed you from a Che organization called \<b><organizationName>\</b>.\</p>
|
||||
\</div>
|
||||
|
||||
\<div style="background-color: #292c2f; color: white; padding: 15px 10px 47px 10px;">
|
||||
\<a href="http://www.eclipse.org/che/">
|
||||
\<img src="https://www.eclipse.org/che/images/logo-eclipseche.svg" height="32" align="left" alt=" " />
|
||||
\</a>
|
||||
\</div>
|
||||
\</body>
|
||||
\</html>
|
||||
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import org.eclipse.che.api.core.rest.ServiceContext;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.multiuser.organization.shared.Constants;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
|
||||
import org.everrest.core.impl.uri.UriBuilderImpl;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link org.eclipse.che.multiuser.organization.api.OrganizationLinksInjector}
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class OrganizationLinksInjectorTest {
|
||||
private static final String URI_BASE = "http://localhost:8080";
|
||||
|
||||
@Mock ServiceContext context;
|
||||
|
||||
OrganizationLinksInjector organizationLinksInjector = new OrganizationLinksInjector();
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() {
|
||||
final UriBuilder uriBuilder = new UriBuilderImpl();
|
||||
uriBuilder.uri(URI_BASE);
|
||||
|
||||
when(context.getBaseUriBuilder()).thenReturn(uriBuilder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInjectLinks() {
|
||||
final OrganizationDto organization = DtoFactory.newDto(OrganizationDto.class).withId("org123");
|
||||
|
||||
final OrganizationDto withLinks = organizationLinksInjector.injectLinks(organization, context);
|
||||
|
||||
assertEquals(withLinks.getLinks().size(), 2);
|
||||
assertNotNull(withLinks.getLink(Constants.LINK_REL_SELF));
|
||||
assertNotNull(withLinks.getLink(Constants.LINK_REL_SUBORGANIZATIONS));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,359 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2024 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.organization.api;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.commons.subject.SubjectImpl;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Member;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.eclipse.che.multiuser.organization.spi.MemberDao;
|
||||
import org.eclipse.che.multiuser.organization.spi.OrganizationDao;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
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 for {@link org.eclipse.che.multiuser.organization.api.OrganizationManager}
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class OrganizationManagerTest {
|
||||
@Captor private ArgumentCaptor<OrganizationImpl> organizationCaptor;
|
||||
|
||||
private static final String USER_NAME = "user-name";
|
||||
private static final String USER_ID = "user-id";
|
||||
|
||||
@Mock private OrganizationDao organizationDao;
|
||||
|
||||
@Mock private MemberDao memberDao;
|
||||
|
||||
@Mock private EventService eventService;
|
||||
|
||||
private OrganizationManager manager;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
manager =
|
||||
spy(
|
||||
new OrganizationManager(
|
||||
eventService, organizationDao, memberDao, new String[] {"reserved"}));
|
||||
|
||||
lenient()
|
||||
.when(eventService.publish(any()))
|
||||
.thenAnswer(invocation -> invocation.getArguments()[0]);
|
||||
EnvironmentContext.getCurrent()
|
||||
.setSubject(new SubjectImpl(USER_NAME, USER_ID, "userToken", false));
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
public void tearDown() throws Exception {
|
||||
EnvironmentContext.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateOrganization() throws Exception {
|
||||
final Organization toCreate = DtoFactory.newDto(OrganizationDto.class).withName("newOrg");
|
||||
|
||||
manager.create(toCreate);
|
||||
|
||||
verify(organizationDao).create(organizationCaptor.capture());
|
||||
final OrganizationImpl createdOrganization = organizationCaptor.getValue();
|
||||
assertEquals(createdOrganization.getName(), toCreate.getName());
|
||||
assertEquals(createdOrganization.getQualifiedName(), toCreate.getName());
|
||||
assertEquals(createdOrganization.getParent(), toCreate.getParent());
|
||||
verify(memberDao)
|
||||
.store(
|
||||
new MemberImpl(USER_ID, createdOrganization.getId(), OrganizationDomain.getActions()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateSuborganization() throws Exception {
|
||||
final OrganizationImpl parentOrganization = new OrganizationImpl("org123", "parentOrg", null);
|
||||
when(organizationDao.getById(anyString())).thenReturn(parentOrganization);
|
||||
final Organization toCreate = new OrganizationImpl(null, "orgName", parentOrganization.getId());
|
||||
|
||||
manager.create(toCreate);
|
||||
|
||||
verify(organizationDao).create(organizationCaptor.capture());
|
||||
final OrganizationImpl createdOrganization = organizationCaptor.getValue();
|
||||
assertEquals(createdOrganization.getName(), toCreate.getName());
|
||||
assertEquals(
|
||||
createdOrganization.getQualifiedName(),
|
||||
parentOrganization.getQualifiedName() + "/" + toCreate.getName());
|
||||
assertEquals(createdOrganization.getParent(), toCreate.getParent());
|
||||
verify(memberDao)
|
||||
.store(
|
||||
new MemberImpl(USER_ID, createdOrganization.getId(), OrganizationDomain.getActions()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGenerateIdentifierWhenCreatingOrganization() throws Exception {
|
||||
final Organization organization =
|
||||
DtoFactory.newDto(OrganizationDto.class).withName("newOrg").withId("identifier");
|
||||
|
||||
manager.create(organization);
|
||||
|
||||
verify(organizationDao).create(organizationCaptor.capture());
|
||||
final String id = organizationCaptor.getValue().getId();
|
||||
assertNotNull(id);
|
||||
assertNotEquals(id, "identifier");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ConflictException.class)
|
||||
public void shouldThrowConflictExceptionOnCreationIfOrganizationNameIsReserved()
|
||||
throws Exception {
|
||||
final Organization organization =
|
||||
DtoFactory.newDto(OrganizationDto.class).withName("reserved").withParent(null);
|
||||
|
||||
manager.create(organization);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeWhenCreatingNullableOrganization() throws Exception {
|
||||
manager.create(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeWhenUpdatingOrganizationWithNullEntity() throws Exception {
|
||||
manager.update("organizationId", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateOrganizationAndIgnoreNewIdAndParentFields() throws Exception {
|
||||
final OrganizationImpl existing = new OrganizationImpl("org123", "oldName", "parent123");
|
||||
final OrganizationImpl expectedExistingToUpdate = new OrganizationImpl(existing);
|
||||
expectedExistingToUpdate.setQualifiedName("newName");
|
||||
|
||||
final OrganizationImpl suborganization =
|
||||
new OrganizationImpl("org321", "oldName/suborgName", "org123");
|
||||
final OrganizationImpl expectedSuborganizationToUpdate = new OrganizationImpl(suborganization);
|
||||
expectedSuborganizationToUpdate.setQualifiedName(
|
||||
expectedExistingToUpdate.getQualifiedName() + "/" + suborganization.getName());
|
||||
|
||||
when(organizationDao.getById(any())).thenReturn(existing);
|
||||
doReturn(new Page<>(singletonList(suborganization), 0, 1, 1))
|
||||
.when(organizationDao)
|
||||
.getSuborganizations(anyString(), anyInt(), anyLong());
|
||||
final OrganizationImpl update = new OrganizationImpl("newId", "newName", "newParentId");
|
||||
|
||||
final Organization updated = manager.update("organizationId", update);
|
||||
|
||||
verify(organizationDao).getById("organizationId");
|
||||
verify(organizationDao, times(2)).update(organizationCaptor.capture());
|
||||
List<OrganizationImpl> updatedOrganizations = organizationCaptor.getAllValues();
|
||||
assertEquals(updatedOrganizations.get(0), expectedExistingToUpdate);
|
||||
assertEquals(updatedOrganizations.get(1), expectedSuborganizationToUpdate);
|
||||
verify(organizationDao).getSuborganizations(eq("oldName"), anyInt(), anyLong());
|
||||
assertEquals(updated, expectedExistingToUpdate);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ConflictException.class)
|
||||
public void shouldThrowConflictExceptionOnUpdatingIfOrganizationNameIsReserved()
|
||||
throws Exception {
|
||||
when(organizationDao.getById("id")).thenReturn(new OrganizationImpl("id", "oldName", null));
|
||||
|
||||
manager.update("id", new OrganizationImpl("id", "reserved", null));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeWhenUpdatingOrganizationByNullId() throws Exception {
|
||||
manager.update(null, new OrganizationImpl());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeWhenRemovingOrganizationByNullId() throws Exception {
|
||||
manager.remove(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRemoveOrganization() throws Exception {
|
||||
doNothing().when(manager).removeSuborganizations(anyString());
|
||||
final List<Member> members = Collections.singletonList(mock(Member.class));
|
||||
doReturn(members).when(manager).removeMembers(anyString());
|
||||
OrganizationImpl toRemove = new OrganizationImpl("org123", "toRemove", null);
|
||||
when(organizationDao.getById(anyString())).thenReturn(toRemove);
|
||||
|
||||
manager.remove(toRemove.getId());
|
||||
|
||||
verify(organizationDao).remove(toRemove.getId());
|
||||
verify(manager).removeMembers(eq(toRemove.getId()));
|
||||
verify(manager).removeSuborganizations(eq(toRemove.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRemoveMembersByOrganizationId() throws Exception {
|
||||
MemberImpl member1 = new MemberImpl("user1", "org1", singletonList("read"));
|
||||
MemberImpl member2 = new MemberImpl("user2", "org1", singletonList("read"));
|
||||
doReturn(new Page<>(singletonList(member1), 0, 1, 2))
|
||||
.doReturn(new Page<>(singletonList(member2), 1, 1, 2))
|
||||
.when(memberDao)
|
||||
.getMembers(anyString(), anyInt(), anyLong());
|
||||
|
||||
manager.removeMembers("org1");
|
||||
|
||||
verify(memberDao, times(2)).getMembers("org1", 100, 0);
|
||||
verify(memberDao).remove("user1", "org1");
|
||||
verify(memberDao).remove("user2", "org1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRemoveSuborganizationsByParentOrganizationId() throws Exception {
|
||||
doNothing().when(manager).remove(any());
|
||||
OrganizationImpl subOrg1 = new OrganizationImpl("subOrg1", "subOrg1", "org1");
|
||||
OrganizationImpl subOrg2 = new OrganizationImpl("subOrg2", "subOrg2", "org1");
|
||||
doReturn(new Page<>(singletonList(subOrg1), 0, 1, 2))
|
||||
.doReturn(new Page<>(singletonList(subOrg2), 1, 1, 2))
|
||||
.when(organizationDao)
|
||||
.getByParent(anyString(), anyInt(), anyLong());
|
||||
|
||||
manager.removeSuborganizations("org1");
|
||||
|
||||
verify(organizationDao, times(2)).getByParent("org1", 100, 0);
|
||||
verify(manager).remove("subOrg1");
|
||||
verify(manager).remove("subOrg2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotTryToRemoveOrganizationWhenItIsNotExistRemoveOrganization()
|
||||
throws Exception {
|
||||
when(organizationDao.getById(anyString())).thenThrow(new NotFoundException("not found"));
|
||||
|
||||
manager.remove("id");
|
||||
|
||||
verify(organizationDao, never()).remove(anyString());
|
||||
verify(eventService, never()).publish(any());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeWhenGettingOrganizationByNullName() throws Exception {
|
||||
manager.getById(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetOrganizationByName() throws Exception {
|
||||
final OrganizationImpl toFetch = new OrganizationImpl("org123", "toFetchOrg", "org321");
|
||||
when(organizationDao.getByName(eq("org123"))).thenReturn(toFetch);
|
||||
|
||||
final Organization fetched = manager.getByName("org123");
|
||||
|
||||
assertEquals(fetched, toFetch);
|
||||
verify(organizationDao).getByName("org123");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeWhenGettingOrganizationByNullId() throws Exception {
|
||||
manager.getById(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetOrganizationById() throws Exception {
|
||||
final OrganizationImpl toFetch = new OrganizationImpl("org123", "toFetchOrg", "org321");
|
||||
when(organizationDao.getById(eq("org123"))).thenReturn(toFetch);
|
||||
|
||||
final Organization fetched = manager.getById("org123");
|
||||
|
||||
assertEquals(fetched, toFetch);
|
||||
verify(organizationDao).getById("org123");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeWhenGettingSuborganizationsByNullParent() throws Exception {
|
||||
manager.getByParent(null, 30, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetOrganizationsByParent() throws Exception {
|
||||
final OrganizationImpl toFetch = new OrganizationImpl("org321", "toFetchOrg", "org123");
|
||||
when(organizationDao.getByParent(eq("org123"), anyInt(), anyLong()))
|
||||
.thenReturn(new Page<>(singletonList(toFetch), 0, 1, 1));
|
||||
|
||||
final Page<? extends Organization> organizations = manager.getByParent("org123", 30, 0);
|
||||
|
||||
assertEquals(organizations.getItemsCount(), 1);
|
||||
assertEquals(organizations.getItems().get(0), toFetch);
|
||||
verify(organizationDao).getByParent("org123", 30, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetSuborganizations() throws Exception {
|
||||
final OrganizationImpl toFetch = new OrganizationImpl("org321", "parent/toFetchOrg", "org123");
|
||||
when(organizationDao.getSuborganizations(eq("parent"), anyInt(), anyLong()))
|
||||
.thenReturn(new Page<>(singletonList(toFetch), 0, 1, 1));
|
||||
|
||||
final Page<? extends Organization> organizations = manager.getSuborganizations("parent", 30, 0);
|
||||
|
||||
assertEquals(organizations.getItemsCount(), 1);
|
||||
assertEquals(organizations.getItems().get(0), toFetch);
|
||||
verify(organizationDao).getSuborganizations("parent", 30, 0);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeOnGettingSuborganizationsByNullParentQualifiedName() throws Exception {
|
||||
manager.getSuborganizations(null, 30, 0);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void shouldThrowNpeWhenGettingOrganizationsByNullUserId() throws Exception {
|
||||
manager.getByMember(null, 30, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetOrganizationsByMember() throws Exception {
|
||||
final OrganizationImpl toFetch = new OrganizationImpl("org123", "toFetchOrg", "org321");
|
||||
when(memberDao.getOrganizations(eq("org123"), anyInt(), anyLong()))
|
||||
.thenReturn(new Page<>(singletonList(toFetch), 0, 1, 1));
|
||||
|
||||
final Page<? extends Organization> organizations = manager.getByMember("org123", 30, 0);
|
||||
|
||||
assertEquals(organizations.getItemsCount(), 1);
|
||||
assertEquals(organizations.getItems().get(0), toFetch);
|
||||
verify(memberDao).getOrganizations("org123", 30, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,345 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
|
||||
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
|
||||
import static org.everrest.assured.JettyHttpServer.SECURE_PATH;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import io.restassured.response.Response;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.rest.ApiExceptionMapper;
|
||||
import org.eclipse.che.api.core.rest.CheJsonProvider;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.commons.subject.SubjectImpl;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
|
||||
import org.eclipse.che.multiuser.organization.shared.model.Organization;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
import org.everrest.assured.EverrestJetty;
|
||||
import org.everrest.core.Filter;
|
||||
import org.everrest.core.GenericContainerRequest;
|
||||
import org.everrest.core.RequestFilter;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link org.eclipse.che.multiuser.organization.api.OrganizationService}.
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Listeners({EverrestJetty.class, MockitoTestNGListener.class})
|
||||
public class OrganizationServiceTest {
|
||||
|
||||
private static final String CURRENT_USER_ID = "user123";
|
||||
|
||||
@SuppressWarnings("unused") // is declared for deploying by everrest-assured
|
||||
private ApiExceptionMapper mapper;
|
||||
|
||||
@SuppressWarnings("unused") // is declared for deploying by everrest-assured
|
||||
private EnvironmentFilter filter;
|
||||
|
||||
@SuppressWarnings("unused") // is declared for deploying by everrest-assured
|
||||
private CheJsonProvider jsonProvider = new CheJsonProvider(new HashSet<>());
|
||||
|
||||
@Mock private OrganizationManager orgManager;
|
||||
|
||||
@Mock private OrganizationLinksInjector linksInjector;
|
||||
|
||||
@Mock private OrganizationValidator validator;
|
||||
|
||||
@InjectMocks private OrganizationService service;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
lenient()
|
||||
.when(linksInjector.injectLinks(any(), any()))
|
||||
.thenAnswer(invocation -> invocation.getArguments()[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateOrganization() throws Exception {
|
||||
when(orgManager.create(any()))
|
||||
.thenAnswer(
|
||||
invocationOnMock ->
|
||||
new OrganizationImpl((Organization) invocationOnMock.getArguments()[0]));
|
||||
|
||||
final OrganizationDto toCreate = createOrganization();
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.body(toCreate)
|
||||
.when()
|
||||
.post(SECURE_PATH + "/organization");
|
||||
assertEquals(response.statusCode(), 201);
|
||||
final OrganizationDto createdOrganization = unwrapDto(response, OrganizationDto.class);
|
||||
assertEquals(createdOrganization, toCreate);
|
||||
verify(linksInjector).injectLinks(any(), any());
|
||||
verify(orgManager).create(eq(toCreate));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowBadRequestWhenCreatingNonValidOrganization() throws Exception {
|
||||
doThrow(new BadRequestException("non valid organization"))
|
||||
.when(validator)
|
||||
.checkOrganization(any());
|
||||
|
||||
final OrganizationDto toCreate = createOrganization();
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.body(toCreate)
|
||||
.when()
|
||||
.post(SECURE_PATH + "/organization");
|
||||
assertEquals(response.statusCode(), 400);
|
||||
final ServiceError error = unwrapDto(response, ServiceError.class);
|
||||
assertEquals(error.getMessage(), "non valid organization");
|
||||
verify(validator).checkOrganization(toCreate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateOrganization() throws Exception {
|
||||
when(orgManager.update(anyString(), any()))
|
||||
.thenAnswer(
|
||||
invocationOnMock ->
|
||||
new OrganizationImpl((Organization) invocationOnMock.getArguments()[1]));
|
||||
|
||||
final OrganizationDto toUpdate = createOrganization();
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.body(toUpdate)
|
||||
.when()
|
||||
.post(SECURE_PATH + "/organization/organization123");
|
||||
assertEquals(response.statusCode(), 200);
|
||||
final OrganizationDto createdOrganization = unwrapDto(response, OrganizationDto.class);
|
||||
assertEquals(createdOrganization, toUpdate);
|
||||
verify(linksInjector).injectLinks(any(), any());
|
||||
verify(orgManager).update(eq("organization123"), eq(toUpdate));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowBadRequestWhenUpdatingNonValidOrganization() throws Exception {
|
||||
doThrow(new BadRequestException("non valid organization"))
|
||||
.when(validator)
|
||||
.checkOrganization(any());
|
||||
|
||||
final OrganizationDto toUpdate = createOrganization();
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.body(toUpdate)
|
||||
.when()
|
||||
.post(SECURE_PATH + "/organization/organization123");
|
||||
assertEquals(response.statusCode(), 400);
|
||||
final ServiceError error = unwrapDto(response, ServiceError.class);
|
||||
assertEquals(error.getMessage(), "non valid organization");
|
||||
verify(validator).checkOrganization(toUpdate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRemoveOrganization() throws Exception {
|
||||
Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.delete(SECURE_PATH + "/organization/organization123");
|
||||
assertEquals(response.statusCode(), 204);
|
||||
verify(orgManager).remove(eq("organization123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetOrganizationById() throws Exception {
|
||||
final OrganizationDto toFetch = createOrganization();
|
||||
|
||||
when(orgManager.getById(eq("organization123"))).thenReturn(toFetch);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization/organization123");
|
||||
|
||||
assertEquals(response.statusCode(), 200);
|
||||
final OrganizationDto fetchedOrganization = unwrapDto(response, OrganizationDto.class);
|
||||
assertEquals(fetchedOrganization, toFetch);
|
||||
verify(orgManager).getById(eq("organization123"));
|
||||
verify(linksInjector).injectLinks(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindOrganizationByName() throws Exception {
|
||||
final OrganizationDto toFetch = createOrganization();
|
||||
|
||||
when(orgManager.getByName(eq("subOrg"))).thenReturn(toFetch);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.get(SECURE_PATH + "/organization/find?name=subOrg");
|
||||
assertEquals(response.statusCode(), 200);
|
||||
final OrganizationDto fetchedOrganization = unwrapDto(response, OrganizationDto.class);
|
||||
assertEquals(fetchedOrganization, toFetch);
|
||||
verify(orgManager).getByName(eq("subOrg"));
|
||||
verify(linksInjector).injectLinks(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowBadRequestExceptionWhenFindingOrganizationWithoutName() throws Exception {
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization/find")
|
||||
.then()
|
||||
.assertThat()
|
||||
.statusCode(400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetChildOrganizations() throws Exception {
|
||||
final OrganizationDto toFetch = createOrganization();
|
||||
|
||||
doReturn(new Page<>(singletonList(toFetch), 0, 1, 1))
|
||||
.when(orgManager)
|
||||
.getByParent(anyString(), anyInt(), anyLong());
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization/parentOrg123/organizations?skipCount=0&maxItems=1");
|
||||
assertEquals(response.statusCode(), 200);
|
||||
final List<OrganizationDto> organizationDtos = unwrapDtoList(response, OrganizationDto.class);
|
||||
assertEquals(organizationDtos.size(), 1);
|
||||
assertEquals(organizationDtos.get(0), toFetch);
|
||||
verify(orgManager).getByParent("parentOrg123", 1, 0);
|
||||
verify(linksInjector).injectLinks(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetOrganizationsByCurrentUserIfParameterIsNotSpecified() throws Exception {
|
||||
final OrganizationDto toFetch = createOrganization();
|
||||
|
||||
doReturn(new Page<>(singletonList(toFetch), 0, 1, 1))
|
||||
.when(orgManager)
|
||||
.getByMember(anyString(), anyInt(), anyInt());
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization?skipCount=0&maxItems=1");
|
||||
assertEquals(response.statusCode(), 200);
|
||||
final List<OrganizationDto> organizationDtos = unwrapDtoList(response, OrganizationDto.class);
|
||||
assertEquals(organizationDtos.size(), 1);
|
||||
assertEquals(organizationDtos.get(0), toFetch);
|
||||
verify(orgManager).getByMember(CURRENT_USER_ID, 1, 0);
|
||||
verify(linksInjector).injectLinks(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetOrganizationsBySpecifiedUser() throws Exception {
|
||||
final OrganizationDto toFetch = createOrganization();
|
||||
|
||||
doReturn(new Page<>(singletonList(toFetch), 0, 1, 1))
|
||||
.when(orgManager)
|
||||
.getByMember(anyString(), anyInt(), anyInt());
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization?user=user789&skipCount=0&maxItems=1");
|
||||
assertEquals(response.statusCode(), 200);
|
||||
final List<OrganizationDto> organizationDtos = unwrapDtoList(response, OrganizationDto.class);
|
||||
assertEquals(organizationDtos.size(), 1);
|
||||
assertEquals(organizationDtos.get(0), toFetch);
|
||||
verify(orgManager).getByMember("user789", 1, 0);
|
||||
verify(linksInjector).injectLinks(any(), any());
|
||||
}
|
||||
|
||||
private static <T> T unwrapDto(Response response, Class<T> dtoClass) {
|
||||
return DtoFactory.getInstance().createDtoFromJson(response.body().print(), dtoClass);
|
||||
}
|
||||
|
||||
private static <T> List<T> unwrapDtoList(Response response, Class<T> dtoClass) {
|
||||
return DtoFactory.getInstance()
|
||||
.createListDtoFromJson(response.body().print(), dtoClass)
|
||||
.stream()
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
private OrganizationDto createOrganization() {
|
||||
return DtoFactory.newDto(OrganizationDto.class)
|
||||
.withId("organization123")
|
||||
.withName("subOrg")
|
||||
.withQualifiedName("parentOrg/subOrg")
|
||||
.withParent("parentOrg123");
|
||||
}
|
||||
|
||||
@Filter
|
||||
public static class EnvironmentFilter implements RequestFilter {
|
||||
@Override
|
||||
public void doFilter(GenericContainerRequest request) {
|
||||
EnvironmentContext.getCurrent()
|
||||
.setSubject(new SubjectImpl("userName", CURRENT_USER_ID, "token", false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,499 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 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.organization.api.permissions;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.DELETE;
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.DOMAIN_ID;
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.MANAGE_SUBORGANIZATIONS;
|
||||
import static org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain.UPDATE;
|
||||
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
|
||||
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
|
||||
import static org.everrest.assured.JettyHttpServer.SECURE_PATH;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import io.restassured.response.Response;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.eclipse.che.api.core.ForbiddenException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.rest.ApiExceptionMapper;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
|
||||
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.api.permission.server.SuperPrivilegesChecker;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
|
||||
import org.eclipse.che.multiuser.organization.api.OrganizationService;
|
||||
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
|
||||
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
|
||||
import org.everrest.assured.EverrestJetty;
|
||||
import org.everrest.core.Filter;
|
||||
import org.everrest.core.GenericContainerRequest;
|
||||
import org.everrest.core.RequestFilter;
|
||||
import org.everrest.core.resource.GenericResourceMethod;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link
|
||||
* org.eclipse.che.multiuser.organization.api.permissions.OrganizationPermissionsFilter}
|
||||
*
|
||||
* @author Sergii Leschenko
|
||||
*/
|
||||
@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class})
|
||||
public class OrganizationPermissionsFilterTest {
|
||||
@SuppressWarnings("unused")
|
||||
private static final ApiExceptionMapper MAPPER = new ApiExceptionMapper();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final EnvironmentFilter FILTER = new EnvironmentFilter();
|
||||
|
||||
private static final String USER_ID = "user123";
|
||||
|
||||
@Mock private static Subject subject;
|
||||
|
||||
@Mock private OrganizationService service;
|
||||
|
||||
@Mock private OrganizationManager manager;
|
||||
|
||||
@Mock private SuperPrivilegesChecker superPrivilegesChecker;
|
||||
|
||||
@InjectMocks private OrganizationPermissionsFilter permissionsFilter;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
lenient().when(subject.getUserId()).thenReturn(USER_ID);
|
||||
|
||||
lenient()
|
||||
.when(manager.getById(anyString()))
|
||||
.thenReturn(new OrganizationImpl("organization123", "test", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTestThatAllPublicMethodsAreCoveredByPermissionsFilter() throws Exception {
|
||||
// given
|
||||
final List<String> collect =
|
||||
Stream.of(OrganizationService.class.getDeclaredMethods())
|
||||
.filter(method -> Modifier.isPublic(method.getModifiers()))
|
||||
.map(Method::getName)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// then
|
||||
assertEquals(collect.size(), 7);
|
||||
assertTrue(collect.contains(OrganizationPermissionsFilter.CREATE_METHOD));
|
||||
assertTrue(collect.contains(OrganizationPermissionsFilter.UPDATE_METHOD));
|
||||
assertTrue(collect.contains(OrganizationPermissionsFilter.REMOVE_METHOD));
|
||||
assertTrue(collect.contains(OrganizationPermissionsFilter.GET_BY_PARENT_METHOD));
|
||||
assertTrue(collect.contains(OrganizationPermissionsFilter.GET_ORGANIZATIONS_METHOD));
|
||||
assertTrue(collect.contains(OrganizationPermissionsFilter.GET_BY_ID_METHOD));
|
||||
assertTrue(collect.contains(OrganizationPermissionsFilter.FIND_METHOD));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCheckPermissionsOnGettingOrganizationById() throws Exception {
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization/organization123");
|
||||
|
||||
verify(service).getById("organization123");
|
||||
verifyNoMoreInteractions(subject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCheckPermissionsOnGettingOrganizationByName() throws Exception {
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization/find?name=test");
|
||||
|
||||
verify(service).find("test");
|
||||
verifyNoMoreInteractions(subject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCheckPermissionsOnOrganizationsFetchingIfUserIdIsNotSpecified()
|
||||
throws Exception {
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.expect()
|
||||
.statusCode(204)
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization");
|
||||
|
||||
verify(service).getOrganizations(eq(null), anyInt(), anyInt());
|
||||
verify(subject, never()).hasPermission(anyString(), anyString(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCheckPermissionsOnOrganizationsFetchingIfUserSpecifiesHisOwnId()
|
||||
throws Exception {
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.expect()
|
||||
.statusCode(204)
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization?user=" + USER_ID);
|
||||
|
||||
verify(service).getOrganizations(eq(USER_ID), anyInt(), anyInt());
|
||||
verify(subject, never()).hasPermission(anyString(), anyString(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckSuperPrivilegesOnOrganizationsFetchingIfUserSpecifiesForeignId()
|
||||
throws Exception {
|
||||
when(superPrivilegesChecker.hasSuperPrivileges()).thenReturn(true);
|
||||
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.expect()
|
||||
.statusCode(204)
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization?user=user321");
|
||||
|
||||
verify(service).getOrganizations(eq("user321"), anyInt(), anyInt());
|
||||
verify(superPrivilegesChecker).hasSuperPrivileges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
shouldThrowForbiddenExceptionOnOrganizationsFetchingIfUserSpecifiesForeignIdAndDoesNotHaveSuperPrivileges()
|
||||
throws Exception {
|
||||
when(superPrivilegesChecker.hasSuperPrivileges()).thenReturn(false);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.expect()
|
||||
.statusCode(403)
|
||||
.when()
|
||||
.get(SECURE_PATH + "/organization?user=user321");
|
||||
|
||||
assertEquals(unwrapError(response), "The user is able to specify only his own id");
|
||||
verify(superPrivilegesChecker).hasSuperPrivileges();
|
||||
verifyNoMoreInteractions(service);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckPermissionsOnOrganizationUpdating() throws Exception {
|
||||
when(subject.hasPermission(DOMAIN_ID, "organization123", UPDATE)).thenReturn(true);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.post(SECURE_PATH + "/organization/organization123");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(service).update(eq("organization123"), any());
|
||||
verify(subject).hasPermission(DOMAIN_ID, "organization123", UPDATE);
|
||||
verify(superPrivilegesChecker, never()).hasSuperPrivileges();
|
||||
verifyNoMoreInteractions(subject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckPermissionsOnParentOrgLevelOnChildOrganizationUpdating() throws Exception {
|
||||
when(manager.getById(anyString()))
|
||||
.thenReturn(new OrganizationImpl("organization123", "test", "parent123"));
|
||||
when(subject.hasPermission(DOMAIN_ID, "parent123", MANAGE_SUBORGANIZATIONS)).thenReturn(true);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.post(SECURE_PATH + "/organization/organization123");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(service).update(eq("organization123"), any());
|
||||
verify(subject).hasPermission(DOMAIN_ID, "parent123", MANAGE_SUBORGANIZATIONS);
|
||||
verify(superPrivilegesChecker, never()).hasSuperPrivileges();
|
||||
verifyNoMoreInteractions(subject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
shouldCheckPermissionsOnChildOrganizationUpdatingWhenUserDoesNotHavePermissionsOnParentOrgLevel()
|
||||
throws Exception {
|
||||
when(manager.getById(anyString()))
|
||||
.thenReturn(new OrganizationImpl("organization123", "test", "parent123"));
|
||||
doReturn(false).when(subject).hasPermission(DOMAIN_ID, "parent123", MANAGE_SUBORGANIZATIONS);
|
||||
doReturn(true).when(subject).hasPermission(DOMAIN_ID, "organization123", UPDATE);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.post(SECURE_PATH + "/organization/organization123");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(service).update(eq("organization123"), any());
|
||||
verify(subject).hasPermission(DOMAIN_ID, "parent123", MANAGE_SUBORGANIZATIONS);
|
||||
verify(subject).hasPermission(DOMAIN_ID, "organization123", UPDATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckPermissionsOnOrganizationRemoving() throws Exception {
|
||||
when(subject.hasPermission(DOMAIN_ID, "organization123", DELETE)).thenReturn(true);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.delete(SECURE_PATH + "/organization/organization123");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(service).remove(eq("organization123"));
|
||||
verify(subject).hasPermission(DOMAIN_ID, "organization123", DELETE);
|
||||
verify(superPrivilegesChecker, never()).hasSuperPrivileges();
|
||||
verifyNoMoreInteractions(subject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckPermissionsOnParentOrgLevelOnChildOrganizationRemoving() throws Exception {
|
||||
when(manager.getById(anyString()))
|
||||
.thenReturn(new OrganizationImpl("organization123", "test", "parent123"));
|
||||
when(subject.hasPermission(DOMAIN_ID, "parent123", MANAGE_SUBORGANIZATIONS)).thenReturn(true);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.delete(SECURE_PATH + "/organization/organization123");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(service).remove(eq("organization123"));
|
||||
verify(subject).hasPermission(DOMAIN_ID, "parent123", MANAGE_SUBORGANIZATIONS);
|
||||
verify(superPrivilegesChecker, never()).hasSuperPrivileges();
|
||||
verifyNoMoreInteractions(subject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
shouldCheckPermissionsOnChildOrganizationRemovingWhenUserDoesNotHavePermissionsOnParentOrgLevel()
|
||||
throws Exception {
|
||||
when(manager.getById(anyString()))
|
||||
.thenReturn(new OrganizationImpl("organization123", "test", "parent123"));
|
||||
doReturn(false).when(subject).hasPermission(DOMAIN_ID, "parent123", MANAGE_SUBORGANIZATIONS);
|
||||
doReturn(true).when(subject).hasPermission(DOMAIN_ID, "organization123", DELETE);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.delete(SECURE_PATH + "/organization/organization123");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(service).remove(eq("organization123"));
|
||||
verify(subject).hasPermission(DOMAIN_ID, "parent123", MANAGE_SUBORGANIZATIONS);
|
||||
verify(subject).hasPermission(DOMAIN_ID, "organization123", DELETE);
|
||||
verify(superPrivilegesChecker, never()).hasSuperPrivileges();
|
||||
verifyNoMoreInteractions(subject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCheckPermissionsOnRootOrganizationCreation() throws Exception {
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.body(DtoFactory.newDto(OrganizationDto.class).withParent(null))
|
||||
.post(SECURE_PATH + "/organization");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(service).create(any());
|
||||
verifyNoMoreInteractions(subject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckPermissionsOnChildOrganizationCreation() throws Exception {
|
||||
when(subject.hasPermission(DOMAIN_ID, "parent-org", MANAGE_SUBORGANIZATIONS)).thenReturn(true);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.body(DtoFactory.newDto(OrganizationDto.class).withParent("parent-org"))
|
||||
.post(SECURE_PATH + "/organization");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(service).create(any());
|
||||
verify(subject).hasPermission(DOMAIN_ID, "parent-org", MANAGE_SUBORGANIZATIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
shouldThrowForbiddenExceptionOnChildOrganizationCreationIfUserDoesNotHaveCorrespondingPermission()
|
||||
throws Exception {
|
||||
when(subject.hasPermission(DOMAIN_ID, "parent-org", MANAGE_SUBORGANIZATIONS)).thenReturn(false);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.body(DtoFactory.newDto(OrganizationDto.class).withParent("parent-org"))
|
||||
.post(SECURE_PATH + "/organization");
|
||||
|
||||
assertEquals(response.getStatusCode(), 403);
|
||||
verifyNoMoreInteractions(service);
|
||||
verify(subject).hasPermission(DOMAIN_ID, "parent-org", MANAGE_SUBORGANIZATIONS);
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = ForbiddenException.class,
|
||||
expectedExceptionsMessageRegExp =
|
||||
"The user does not have permission to perform this operation")
|
||||
public void shouldThrowForbiddenExceptionWhenRequestedUnknownMethod() throws Exception {
|
||||
final GenericResourceMethod mock = mock(GenericResourceMethod.class);
|
||||
Method injectLinks = OrganizationService.class.getMethod("getServiceDescriptor");
|
||||
when(mock.getMethod()).thenReturn(injectLinks);
|
||||
|
||||
permissionsFilter.filter(mock, new Object[] {});
|
||||
}
|
||||
|
||||
@Test(dataProvider = "coveredPaths")
|
||||
public void shouldThrowForbiddenExceptionWhenUserDoesNotHavePermissionsForPerformOperation(
|
||||
String path, String method, String action) throws Exception {
|
||||
when(subject.hasPermission(anyString(), anyString(), anyString())).thenReturn(false);
|
||||
|
||||
Response response =
|
||||
request(
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when(),
|
||||
SECURE_PATH + path,
|
||||
method);
|
||||
|
||||
assertEquals(response.getStatusCode(), 403);
|
||||
assertEquals(
|
||||
unwrapError(response),
|
||||
"The user does not have permission to "
|
||||
+ action
|
||||
+ " organization with id 'organization123'");
|
||||
|
||||
verifyNoMoreInteractions(service);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "coveredPaths")
|
||||
public void shouldThrowNotFoundWhenUserRequestsNonExistedOrganization(
|
||||
String path, String method, String ignored) throws Exception {
|
||||
when(manager.getById(anyString()))
|
||||
.thenThrow(new NotFoundException("Organization was not found"));
|
||||
|
||||
Response response =
|
||||
request(
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("application/json")
|
||||
.when(),
|
||||
SECURE_PATH + path,
|
||||
method);
|
||||
|
||||
assertEquals(response.getStatusCode(), 404);
|
||||
assertEquals(unwrapError(response), "Organization was not found");
|
||||
|
||||
verifyNoMoreInteractions(service);
|
||||
}
|
||||
|
||||
@DataProvider(name = "coveredPaths")
|
||||
public Object[][] pathsProvider() {
|
||||
return new Object[][] {
|
||||
{"/organization/organization123", "post", UPDATE},
|
||||
{"/organization/organization123", "delete", DELETE},
|
||||
{"/organization/organization123/organizations", "get", MANAGE_SUBORGANIZATIONS}
|
||||
};
|
||||
}
|
||||
|
||||
private Response request(RequestSpecification request, String path, String method) {
|
||||
switch (method) {
|
||||
case "post":
|
||||
return request.post(path);
|
||||
case "get":
|
||||
return request.get(path);
|
||||
case "delete":
|
||||
return request.delete(path);
|
||||
case "put":
|
||||
return request.put(path);
|
||||
}
|
||||
throw new RuntimeException("Unsupported method");
|
||||
}
|
||||
|
||||
private static String unwrapError(Response response) {
|
||||
return unwrapDto(response, ServiceError.class).getMessage();
|
||||
}
|
||||
|
||||
private static <T> T unwrapDto(Response response, Class<T> dtoClass) {
|
||||
return DtoFactory.getInstance().createDtoFromJson(response.body().print(), dtoClass);
|
||||
}
|
||||
|
||||
@Filter
|
||||
public static class EnvironmentFilter implements RequestFilter {
|
||||
@Override
|
||||
public void doFilter(GenericContainerRequest request) {
|
||||
EnvironmentContext.getCurrent().setSubject(subject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
/*
|
||||
* 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.organization.api.permissions;
|
||||
|
||||
import static org.eclipse.che.multiuser.organization.api.listener.OrganizationEventsWebsocketBroadcaster.ORGANIZATION_CHANGED_METHOD_NAME;
|
||||
import static org.eclipse.che.multiuser.organization.api.listener.OrganizationEventsWebsocketBroadcaster.ORGANIZATION_MEMBERSHIP_METHOD_NAME;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
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.api.core.NotFoundException;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionsManager;
|
||||
import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionManager;
|
||||
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationRemoteSubscriptionPermissionsChecks.MembershipsChangedSubscriptionCheck;
|
||||
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationRemoteSubscriptionPermissionsChecks.OrganizationChangedSubscriptionCheck;
|
||||
import org.mockito.InjectMocks;
|
||||
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 OrganizationRemoteSubscriptionPermissionsChecks}.
|
||||
*
|
||||
* @author Sergii Leshchenko
|
||||
*/
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class OrganizationRemoteSubscriptionPermissionsChecksTest {
|
||||
@Mock private Subject subject;
|
||||
|
||||
@Mock private PermissionsManager permissionsManager;
|
||||
@Mock private RemoteSubscriptionPermissionManager permissionManager;
|
||||
|
||||
@InjectMocks private OrganizationRemoteSubscriptionPermissionsChecks permissionsChecks;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() {
|
||||
EnvironmentContext.getCurrent().setSubject(subject);
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
public void tearDown() {
|
||||
EnvironmentContext.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRegisterChecks() {
|
||||
// when
|
||||
permissionsChecks.register(permissionManager);
|
||||
|
||||
// then
|
||||
verify(permissionManager)
|
||||
.registerCheck(
|
||||
any(OrganizationChangedSubscriptionCheck.class), eq(ORGANIZATION_CHANGED_METHOD_NAME));
|
||||
verify(permissionManager)
|
||||
.registerCheck(
|
||||
any(MembershipsChangedSubscriptionCheck.class),
|
||||
eq(ORGANIZATION_MEMBERSHIP_METHOD_NAME));
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = ForbiddenException.class,
|
||||
expectedExceptionsMessageRegExp = "User id must be specified in scope")
|
||||
public void shouldThrowExceptionIfUserIdIsMissing() throws Exception {
|
||||
// given
|
||||
MembershipsChangedSubscriptionCheck check = new MembershipsChangedSubscriptionCheck();
|
||||
when(subject.getUserId()).thenReturn("user2");
|
||||
|
||||
// when
|
||||
check.check(ORGANIZATION_MEMBERSHIP_METHOD_NAME, Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = ForbiddenException.class,
|
||||
expectedExceptionsMessageRegExp = "It is only allowed to listen to own memberships changes")
|
||||
public void shouldThrowExceptionIfUserTryToListenToForeignMemberships() throws Exception {
|
||||
// given
|
||||
MembershipsChangedSubscriptionCheck check = new MembershipsChangedSubscriptionCheck();
|
||||
when(subject.getUserId()).thenReturn("user2");
|
||||
|
||||
// when
|
||||
check.check(ORGANIZATION_MEMBERSHIP_METHOD_NAME, ImmutableMap.of("userId", "user1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDoNothingIfUserTryToListenToOwnMemberships() throws Exception {
|
||||
// given
|
||||
MembershipsChangedSubscriptionCheck check = new MembershipsChangedSubscriptionCheck();
|
||||
when(subject.getUserId()).thenReturn("user1");
|
||||
|
||||
// when
|
||||
check.check(ORGANIZATION_MEMBERSHIP_METHOD_NAME, ImmutableMap.of("userId", "user1"));
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = ForbiddenException.class,
|
||||
expectedExceptionsMessageRegExp = "Organization id must be specified in scope")
|
||||
public void shouldThrowExceptionIfOrganizationIdIsMissing() throws Exception {
|
||||
// given
|
||||
OrganizationChangedSubscriptionCheck check =
|
||||
new OrganizationChangedSubscriptionCheck(permissionsManager);
|
||||
|
||||
// when
|
||||
check.check(ORGANIZATION_MEMBERSHIP_METHOD_NAME, Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = ForbiddenException.class,
|
||||
expectedExceptionsMessageRegExp =
|
||||
"User doesn't have any permissions for the specified organization")
|
||||
public void shouldThrowExceptionIfUserDoesNotHaveAnyPermissionsToRequestedOrganization()
|
||||
throws Exception {
|
||||
// given
|
||||
OrganizationChangedSubscriptionCheck check =
|
||||
new OrganizationChangedSubscriptionCheck(permissionsManager);
|
||||
when(subject.getUserId()).thenReturn("user1");
|
||||
when(permissionsManager.get("user1", OrganizationDomain.DOMAIN_ID, "org123"))
|
||||
.thenThrow(new NotFoundException(""));
|
||||
|
||||
// when
|
||||
check.check(ORGANIZATION_MEMBERSHIP_METHOD_NAME, ImmutableMap.of("organizationId", "org123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDoNothingIfUserTryToListenEventsOfOrganizationWhereHeHasPermissions()
|
||||
throws Exception {
|
||||
// given
|
||||
OrganizationChangedSubscriptionCheck check =
|
||||
new OrganizationChangedSubscriptionCheck(permissionsManager);
|
||||
when(subject.getUserId()).thenReturn("user1");
|
||||
when(permissionsManager.get("user1", OrganizationDomain.DOMAIN_ID, "org123"))
|
||||
.thenReturn(mock(AbstractPermissions.class));
|
||||
|
||||
// when
|
||||
check.check(ORGANIZATION_MEMBERSHIP_METHOD_NAME, ImmutableMap.of("organizationId", "org123"));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue