diff --git a/assembly/assembly-wsmaster-war/.deps/prod.md b/assembly/assembly-wsmaster-war/.deps/prod.md index 99089f049c9..9b0d23e47c5 100644 --- a/assembly/assembly-wsmaster-war/.deps/prod.md +++ b/assembly/assembly-wsmaster-war/.deps/prod.md @@ -179,29 +179,12 @@ | `org.eclipse.che.multiuser/che-multiuser-api-authentication-commons@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.che.multiuser/che-multiuser-api-authorization-impl@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.che.multiuser/che-multiuser-api-authorization@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-api-organization-shared@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-api-organization@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.che.multiuser/che-multiuser-api-permission-shared@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.che.multiuser/che-multiuser-api-permission@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-api-resource-shared@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-api-resource@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.che.multiuser/che-multiuser-api-workspace-activity@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-keycloak-server@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-keycloak-shared@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-keycloak-token-provider@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-keycloak-user-remover@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.che.multiuser/che-multiuser-machine-authentication-shared@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.che.multiuser/che-multiuser-machine-authentication@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.che.multiuser/che-multiuser-oidc@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-permission-devfile@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-permission-logger@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-permission-resource@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-permission-system@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-permission-user@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-permission-workspace-activity@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-permission-workspace@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-personal-account@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | -| `org.eclipse.che.multiuser/che-multiuser-sql-schema@7.41.0-SNAPSHOT` | EPL-2.0 | ecd.che | | `org.eclipse.persistence/jakarta.persistence@2.2.3` | - | eclipse | | `org.eclipse.persistence/org.eclipse.persistence.antlr@2.7.9` | - | eclipse | | `org.eclipse.persistence/org.eclipse.persistence.asm@9.1.0` | - | eclipse | diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml index f16542fd140..ec1c5062204 100644 --- a/assembly/assembly-wsmaster-war/pom.xml +++ b/assembly/assembly-wsmaster-war/pom.xml @@ -251,14 +251,6 @@ org.eclipse.che.multiuser che-multiuser-api-authorization-impl - - org.eclipse.che.multiuser - che-multiuser-api-permission - - - org.eclipse.che.multiuser - che-multiuser-keycloak-token-provider - org.eclipse.che.multiuser che-multiuser-machine-authentication @@ -267,34 +259,6 @@ org.eclipse.che.multiuser che-multiuser-oidc - - org.eclipse.che.multiuser - che-multiuser-permission-devfile - - - org.eclipse.che.multiuser - che-multiuser-permission-logger - - - org.eclipse.che.multiuser - che-multiuser-permission-system - - - org.eclipse.che.multiuser - che-multiuser-permission-workspace - - - org.eclipse.che.multiuser - che-multiuser-permission-workspace-activity - - - org.eclipse.che.multiuser - che-multiuser-personal-account - - - org.eclipse.che.multiuser - che-multiuser-sql-schema - org.eclipse.persistence org.eclipse.persistence.core @@ -426,7 +390,6 @@ io.jaegertracing:jaeger-client io.jaegertracing:jaeger-tracerresolver org.eclipse.che.multiuser:che-multiuser-personal-account - org.eclipse.che.multiuser:che-multiuser-keycloak-token-provider org.eclipse.persistence:org.eclipse.persistence.extension org.eclipse.persistence:org.eclipse.persistence.jpa org.jgroups.kubernetes:jgroups-kubernetes diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 52ec056fab5..c6e011f35df 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -14,7 +14,6 @@ import static com.google.common.base.Strings.isNullOrEmpty; 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 com.auth0.jwk.JwkProvider; import com.google.inject.AbstractModule; @@ -65,6 +64,7 @@ import org.eclipse.che.api.workspace.server.WorkspaceEntityProvider; 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.env.AgentAuthEnableEnvVarProvider; import org.eclipse.che.api.workspace.server.spi.provision.env.CheApiEnvVarProvider; import org.eclipse.che.api.workspace.server.spi.provision.env.CheApiExternalEnvVarProvider; @@ -270,6 +270,7 @@ protected void configure() { install(new org.eclipse.che.security.oauth.GitLabModule()); install(new org.eclipse.che.security.oauth.AzureDevOpsModule()); install(new org.eclipse.che.security.oauth.GithubModule()); + install(new WorkspaceJpaModule()); configureMultiUserMode(persistenceProperties, infrastructure); @@ -315,33 +316,6 @@ private void configureMultiUserMode( bind(KubernetesClientConfigFactory.class).to(KubernetesOidcProviderConfigFactory.class); - persistenceProperties.put( - 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 org.eclipse.che.multiuser.permission.devfile.server.jpa - .MultiuserUserDevfileJpaModule()); - install( - new org.eclipse.che.multiuser.permission.devfile.server.UserDevfileApiPermissionsModule()); - - // 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 binder = - Multibinder.newSetBinder(binder(), String.class, Names.named(SYSTEM_DOMAIN_ACTIONS)); - bind(org.eclipse.che.multiuser.permission.logger.LoggerServicePermissionsFilter.class); - - bind(org.eclipse.che.multiuser.permission.workspace.activity.ActivityPermissionsFilter.class); - bind(RequestTokenExtractor.class).to(HeaderRequestTokenExtractor.class); if (isOpenShiftOAuthEnabled()) { bind(AuthorizationChecker.class).to(OpenShiftAuthorizationCheckerImpl.class); diff --git a/infrastructures/infrastructure-permission/pom.xml b/infrastructures/infrastructure-permission/pom.xml index acf9c027b20..855397108af 100644 --- a/infrastructures/infrastructure-permission/pom.xml +++ b/infrastructures/infrastructure-permission/pom.xml @@ -42,10 +42,6 @@ org.eclipse.che.multiuser che-multiuser-api-permission - - org.eclipse.che.multiuser - che-multiuser-permission-workspace - ch.qos.logback logback-classic diff --git a/infrastructures/infrastructure-permission/src/main/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilter.java b/infrastructures/infrastructure-permission/src/main/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilter.java index 0251ae2277c..66f6679f672 100644 --- a/infrastructures/infrastructure-permission/src/main/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilter.java +++ b/infrastructures/infrastructure-permission/src/main/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2025 Red Hat, Inc. + * Copyright (c) 2012-2026 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 org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.subject.Subject; import org.eclipse.che.multiuser.api.permission.server.jsonrpc.JsonRpcPermissionsFilterAdapter; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService; /** @@ -56,8 +55,7 @@ public void doAccept(String method, Object... params) throws ForbiddenException } Subject currentSubject = EnvironmentContext.getCurrent().getSubject(); - if (!currentSubject.hasPermission( - WorkspaceDomain.DOMAIN_ID, workspaceId, WorkspaceDomain.RUN)) { + if (!currentSubject.hasPermission("workspace", workspaceId, "run")) { throw new ForbiddenException( "User doesn't have the required permissions to the specified workspace"); } diff --git a/infrastructures/infrastructure-permission/src/test/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilterTest.java b/infrastructures/infrastructure-permission/src/test/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilterTest.java index c2aede4190a..c7d54973f97 100644 --- a/infrastructures/infrastructure-permission/src/test/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilterTest.java +++ b/infrastructures/infrastructure-permission/src/test/java/org/eclipse/che/multiuser/permission/workspace/infra/kubernetes/BrokerServicePermissionFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2025 Red Hat, Inc. + * Copyright (c) 2012-2026 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 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; @@ -74,8 +73,7 @@ public void shouldRegisterItself() { "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(subject.hasPermission(eq("workspace"), eq("ws123"), eq("run"))).thenReturn(false); // when permissionFilter.doAccept( @@ -87,8 +85,7 @@ public void shouldThrowExceptionIfUserDoesNotHaveRunPermission(String method) th @Test(dataProvider = "coveredMethods") public void shouldDoNothingIfUserHasRunPermissions(String method) throws Exception { // given - when(subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN)) - .thenReturn(true); + when(subject.hasPermission("workspace", "ws123", "run")).thenReturn(true); // when permissionFilter.doAccept( diff --git a/infrastructures/infrastructure-permission/src/test/resources/logback-test.xml b/infrastructures/infrastructure-permission/src/test/resources/logback-test.xml index c7a7b0b5cf3..c7107c8a4f7 100644 --- a/infrastructures/infrastructure-permission/src/test/resources/logback-test.xml +++ b/infrastructures/infrastructure-permission/src/test/resources/logback-test.xml @@ -1,7 +1,7 @@ - - 4.0.0 - - che-multiuser-api - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-api-organization-shared - jar - Che Multiuser :: Organization :: Shared - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-api-dto - - - org.eclipse.che.core - che-core-api-model - - - org.eclipse.che.core - che-core-api-user-shared - - - org.eclipse.che.core - che-core-commons-annotations - - - org.eclipse.che.multiuser - che-multiuser-api-resource-shared - - - diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/Constants.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/Constants.java deleted file mode 100644 index d66ac852061..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/Constants.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2012-2025 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() {} -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/MemberAddedEventDto.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/MemberAddedEventDto.java deleted file mode 100644 index 0c1e8b8b9f6..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/MemberAddedEventDto.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2012-2025 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); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/MemberRemovedEventDto.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/MemberRemovedEventDto.java deleted file mode 100644 index 293b15dd8ba..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/MemberRemovedEventDto.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2012-2025 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); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationDistributedResourcesDto.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationDistributedResourcesDto.java deleted file mode 100644 index 9093f969b10..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationDistributedResourcesDto.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 getResourcesCap(); - - void setResourcesCap(List resourcesCap); - - OrganizationDistributedResourcesDto withResourcesCap(List resourcesCap); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationDto.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationDto.java deleted file mode 100644 index ae99d425361..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationDto.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 links); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationEventDto.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationEventDto.java deleted file mode 100644 index deea6789ee7..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationEventDto.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2012-2025 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); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationRemovedEventDto.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationRemovedEventDto.java deleted file mode 100644 index 5e996a6bf06..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationRemovedEventDto.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 getMembers(); - - void setMembers(List members); - - OrganizationRemovedEventDto withMembers(List members); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationRenamedEventDto.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationRenamedEventDto.java deleted file mode 100644 index bb9b27faf44..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/dto/OrganizationRenamedEventDto.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2012-2025 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); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/EventType.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/EventType.java deleted file mode 100644 index ce734a2e4e7..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/EventType.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/MemberEvent.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/MemberEvent.java deleted file mode 100644 index 27c36840ba0..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/MemberEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2012-2025 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(); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/OrganizationEvent.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/OrganizationEvent.java deleted file mode 100644 index 1956c705ffc..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/event/OrganizationEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2012-2025 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(); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/Member.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/Member.java deleted file mode 100644 index b4f0c66b592..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/Member.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 getActions(); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/Organization.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/Organization.java deleted file mode 100644 index 60946cf274b..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/Organization.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2012-2025 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(); -} diff --git a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/OrganizationDistributedResources.java b/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/OrganizationDistributedResources.java deleted file mode 100644 index 4605d94f868..00000000000 --- a/multiuser/api/che-multiuser-api-organization-shared/src/main/java/org/eclipse/che/multiuser/organization/shared/model/OrganizationDistributedResources.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2012-2025 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. - * - *

Note that suborganization is not limited to use parent organization's resources if resource - * is not capped. - */ - List getResourcesCap(); -} diff --git a/multiuser/api/che-multiuser-api-organization/pom.xml b/multiuser/api/che-multiuser-api-organization/pom.xml deleted file mode 100644 index 6f2eb8c0cf9..00000000000 --- a/multiuser/api/che-multiuser-api-organization/pom.xml +++ /dev/null @@ -1,308 +0,0 @@ - - - - 4.0.0 - - che-multiuser-api - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-api-organization - jar - Che Multiuser :: Organization - - ${project.build.directory}/generated-sources/dto/ - - - - com.google.code.gson - gson - - - com.google.guava - guava - - - com.google.inject - guice - - - com.google.inject.extensions - guice-persist - - - io.swagger.core.v3 - swagger-annotations-jakarta - - - jakarta.annotation - jakarta.annotation-api - - - jakarta.inject - jakarta.inject-api - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.eclipse.che.core - che-core-api-account - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-api-dto - - - org.eclipse.che.core - che-core-api-model - - - org.eclipse.che.core - che-core-api-user - - - org.eclipse.che.core - che-core-api-user-shared - - - org.eclipse.che.core - che-core-commons-annotations - - - org.eclipse.che.core - che-core-commons-lang - - - org.eclipse.che.core - che-core-commons-test - - - org.eclipse.che.multiuser - che-multiuser-api-organization-shared - - - org.eclipse.che.multiuser - che-multiuser-api-permission - - - org.eclipse.che.multiuser - che-multiuser-api-permission-shared - - - org.eclipse.che.multiuser - che-multiuser-api-resource - - - org.eclipse.che.multiuser - che-multiuser-api-resource-shared - - - org.eclipse.persistence - jakarta.persistence - - - org.everrest - everrest-core - - - org.slf4j - slf4j-api - - - jakarta.websocket - jakarta.websocket-api - provided - - - ch.qos.logback - logback-classic - test - - - commons-fileupload - commons-fileupload - test - - - io.rest-assured - rest-assured - test - - - org.eclipse.che.core - che-core-sql-schema - test - - - org.eclipse.che.multiuser - che-multiuser-sql-schema - test - - - org.eclipse.persistence - org.eclipse.persistence.core - test - - - org.eclipse.persistence - org.eclipse.persistence.jpa - test - - - org.everrest - everrest-assured - test - - - org.hamcrest - hamcrest - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - - - - org.eclipse.che.core - che-core-api-dto-maven-plugin - ${project.version} - - - process-sources - - generate - - - - - - org.eclipse.che.multiuser - che-multiuser-api-organization-shared - ${project.version} - - - - - org.eclipse.che.multiuser.organization.shared.dto - - ${dto-generator-out-directory} - org.eclipse.che.multiuser.organization.api.dto.DtoServerImpls - server - - - - maven-compiler-plugin - - - pre-compile - generate-sources - - compile - - - - - - org.codehaus.mojo - build-helper-maven-plugin - - - add-domain - process-sources - - add-resource - - - - - ${dto-generator-out-directory}/META-INF - META-INF - - - - - - add-source - process-sources - - add-source - - - - ${dto-generator-out-directory} - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - **/spi/tck/*.* - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - resource-dependencies - process-test-resources - - unpack-dependencies - - - che-core-sql-schema, - che-multiuser-sql-schema - che-schema/ - ${project.build.directory} - - - - - - - diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/DtoConverter.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/DtoConverter.java deleted file mode 100644 index 0bb08f445b4..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/DtoConverter.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2012-2025 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"); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationApiModule.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationApiModule.java deleted file mode 100644 index 5da9b999196..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationApiModule.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012-2025 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); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationJpaModule.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationJpaModule.java deleted file mode 100644 index 7390df2c064..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationJpaModule.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2012-2025 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>() {}).to(OrganizationDomain.class); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationLinksInjector.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationLinksInjector.java deleted file mode 100644 index aba39ac11ab..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationLinksInjector.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 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); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationManager.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationManager.java deleted file mode 100644 index 2bebedbf1fa..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationManager.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 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 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 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. - * - *

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 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 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 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 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 removeMembers(String organizationId) throws ServerException { - List removed = new ArrayList<>(); - Page 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)); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationService.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationService.java deleted file mode 100644 index 904ed21bab9..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationService.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 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 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); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationValidator.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationValidator.java deleted file mode 100644 index b4bdbfdc50c..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/OrganizationValidator.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012-2025 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"); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/MemberAddedEvent.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/MemberAddedEvent.java deleted file mode 100644 index fe9d52ca39f..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/MemberAddedEvent.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012-2025 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; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/MemberRemovedEvent.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/MemberRemovedEvent.java deleted file mode 100644 index fddbf23b166..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/MemberRemovedEvent.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2012-2025 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; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/OrganizationRemovedEvent.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/OrganizationRemovedEvent.java deleted file mode 100644 index dee94e20b28..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/OrganizationRemovedEvent.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 members; - - public OrganizationRemovedEvent( - String initiator, Organization organization, List 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 getMembers() { - return members; - } - - /** Returns name of user who initiated organization removal */ - @Override - public String getInitiator() { - return initiator; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/OrganizationRenamedEvent.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/OrganizationRenamedEvent.java deleted file mode 100644 index 0f60ff7afce..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/event/OrganizationRenamedEvent.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2012-2025 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; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/listener/MemberEventsPublisher.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/listener/MemberEventsPublisher.java deleted file mode 100644 index 53e6ba76e6a..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/listener/MemberEventsPublisher.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 { - - 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) { - } - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/listener/OrganizationEventsWebsocketBroadcaster.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/listener/OrganizationEventsWebsocketBroadcaster.java deleted file mode 100644 index 9385b579483..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/listener/OrganizationEventsWebsocketBroadcaster.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 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")); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationDomain.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationDomain.java deleted file mode 100644 index d4fd34fa34f..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationDomain.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 { - 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 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 getActions() { - return ACTIONS; - } - - public OrganizationDomain() { - super(DOMAIN_ID, ACTIONS); - } - - @Override - protected MemberImpl doCreateInstance( - String userId, String instanceId, List allowedActions) { - return new MemberImpl(userId, instanceId, allowedActions); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationPermissionsFilter.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationPermissionsFilter.java deleted file mode 100644 index 0257c6f24c8..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationPermissionsFilter.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 - * - *

Filter contains rules for protecting of all methods of {@link OrganizationService}.
- * 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 - + "'"); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationRemoteSubscriptionPermissionsChecks.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationRemoteSubscriptionPermissionsChecks.java deleted file mode 100644 index 1e41e2ae9d4..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationRemoteSubscriptionPermissionsChecks.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2012-2025 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. - * - *

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 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 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"); - } - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationResourceDistributionServicePermissionsFilter.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationResourceDistributionServicePermissionsFilter.java deleted file mode 100644 index ed711cceeb7..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationResourceDistributionServicePermissionsFilter.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2012-2025 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. - * - *

Filter contains rules for protecting of all methods of {@link - * OrganizationResourcesDistributionService}.
- * 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 - + "'"); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationalAccountPermissionsChecker.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationalAccountPermissionsChecker.java deleted file mode 100644 index a6a0a593d29..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationalAccountPermissionsChecker.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2012-2025 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; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/DefaultOrganizationResourcesProvider.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/DefaultOrganizationResourcesProvider.java deleted file mode 100644 index ffc287bc6b4..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/DefaultOrganizationResourcesProvider.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 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(); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourceLockKeyProvider.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourceLockKeyProvider.java deleted file mode 100644 index bbcd871f898..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourceLockKeyProvider.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2012-2025 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. - * - *

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; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributionService.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributionService.java deleted file mode 100644 index 8d0bae84b0b..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributionService.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 resourcesCap) - throws BadRequestException, NotFoundException, ConflictException, ServerException { - checkArgument(resourcesCap != null, "Missed resources caps."); - Set 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 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 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); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributor.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributor.java deleted file mode 100644 index 7a7c2a6cdf5..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributor.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2012-2025 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. - * - *

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 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 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 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 newResourcesCap) - throws NotFoundException, ConflictException, ServerException { - Map 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; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationalAccountAvailableResourcesProvider.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationalAccountAvailableResourcesProvider.java deleted file mode 100644 index 12cbc5e51fe..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationalAccountAvailableResourcesProvider.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2012-2025 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. - * - *

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. - * - *

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 resourceManagerProvider; - private final ResourceAggregator resourceAggregator; - private final OrganizationManager organizationManager; - - @Inject - public OrganizationalAccountAvailableResourcesProvider( - Provider resourceManagerProvider, - ResourceAggregator resourceAggregator, - OrganizationManager organizationManager) { - this.resourceManagerProvider = resourceManagerProvider; - this.resourceAggregator = resourceAggregator; - this.organizationManager = organizationManager; - } - - @Override - public List 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 getAvailableOrganizationResources(Organization organization) - throws NotFoundException, ServerException { - final ResourceManager resourceManager = resourceManagerProvider.get(); - final List total = resourceManager.getTotalResources(organization.getId()); - final List 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. - * - *

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 getUsedResourcesBySuborganizations(String parentQualifiedName) - throws NotFoundException, ServerException { - ResourceManager resourceManager = resourceManagerProvider.get(); - List 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 resources) { - return '[' - + resources.stream() - .map( - resource -> resource.getAmount() + resource.getUnit() + " of " + resource.getType()) - .collect(Collectors.joining(", ")) - + ']'; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/SuborganizationResourcesProvider.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/SuborganizationResourcesProvider.java deleted file mode 100644 index 6ce55870d2b..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/api/resource/SuborganizationResourcesProvider.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2012-2025 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. - * - *

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 distributorProvider; - private final Provider resourceManagerProvider; - - @Inject - public SuborganizationResourcesProvider( - AccountManager accountManager, - OrganizationManager organizationManager, - Provider distributorProvider, - Provider resourceManagerProvider) { - this.accountManager = accountManager; - this.organizationManager = organizationManager; - this.distributorProvider = distributorProvider; - this.resourceManagerProvider = resourceManagerProvider; - } - - @Override - public List 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 parentTotalResources = - resourceManagerProvider.get().getTotalResources(parent); - - if (!parentTotalResources.isEmpty()) { - try { - List 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 cap( - Collection source, List caps) { - final Map 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()); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/MemberDao.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/MemberDao.java deleted file mode 100644 index 279495d4c9a..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/MemberDao.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 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 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 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 getOrganizations(String userId, int maxItems, long skipCount) - throws ServerException; -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/OrganizationDao.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/OrganizationDao.java deleted file mode 100644 index 44352d29b5c..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/OrganizationDao.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 getByParent(String parent, int maxItems, long skipCount) - throws ServerException; - - /** - * Gets all child organizations by specified parent qualified name. - * - *

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 getSuborganizations( - String parentQualifiedName, int maxItems, long skipCount) throws ServerException; -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/OrganizationDistributedResourcesDao.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/OrganizationDistributedResourcesDao.java deleted file mode 100644 index be69fd60a06..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/OrganizationDistributedResourcesDao.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 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; -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/MemberImpl.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/MemberImpl.java deleted file mode 100644 index c794b14ad69..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/MemberImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 actions; - - @ManyToOne - @JoinColumn( - name = "organization_id", - referencedColumnName = "id", - insertable = false, - updatable = false) - private OrganizationImpl organization; - - public MemberImpl() {} - - public MemberImpl(String userId, String organizationId, List 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 getActions() { - return actions; - } - - @Override - public String getOrganizationId() { - return organizationId; - } - - @Override - public String toString() { - return "MemberImpl{" - + "userId='" - + userId - + '\'' - + ", organizationId='" - + organizationId - + '\'' - + ", actions=" - + actions - + '}'; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/OrganizationDistributedResourcesImpl.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/OrganizationDistributedResourcesImpl.java deleted file mode 100644 index 8142f144230..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/OrganizationDistributedResourcesImpl.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 resourcesCap; - - public OrganizationDistributedResourcesImpl() {} - - public OrganizationDistributedResourcesImpl( - OrganizationDistributedResources organizationDistributedResource) { - this( - organizationDistributedResource.getOrganizationId(), - organizationDistributedResource.getResourcesCap()); - } - - public OrganizationDistributedResourcesImpl( - String organizationId, List 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 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() - + '}'; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/OrganizationImpl.java b/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/OrganizationImpl.java deleted file mode 100644 index fa8a56dd02e..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/java/org/eclipse/che/multiuser/organization/spi/impl/OrganizationImpl.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 - + '\'' - + '}'; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/organization_deleted b/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/organization_deleted deleted file mode 100644 index d19467bc298..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/organization_deleted +++ /dev/null @@ -1,23 +0,0 @@ -\ -\ -\ -\ -\ -\

- \Eclipse Che\ - \
\
- \Organization has been deleted\ -\
- - \
- \

Hi,\

- \

\\ organization has been deleted.\

- \
- -\
- \ - \ - \ -\
-\ -\ diff --git a/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/organization_renamed b/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/organization_renamed deleted file mode 100644 index 67f49953f8d..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/organization_renamed +++ /dev/null @@ -1,23 +0,0 @@ -\ -\ -\ -\ -\ -\
- \Eclipse Che\ - \
\
- \Organization has been renamed\ -\
- - \
- \

Hi,\

- \

\\ organization has been renamed to \\\

- \
- -\
- \ - \ - \ -\
-\ -\ diff --git a/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/user_added_to_organization b/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/user_added_to_organization deleted file mode 100644 index aad5354366f..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/user_added_to_organization +++ /dev/null @@ -1,24 +0,0 @@ -\ -\ -\ -\ -\ -\
- \Eclipse Che\ - \
\
- \User added to organization\ -\
- - \
- \

Hi,\

- \

\\ added you to a Che organization called \\.\

- \

Access the organization here \link\.\

- \
- -\
- \ - \ - \ -\
-\ -\ diff --git a/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/user_removed_from_organization b/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/user_removed_from_organization deleted file mode 100644 index ce4eee08e0c..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/main/resources/st-html-templates/user_removed_from_organization +++ /dev/null @@ -1,24 +0,0 @@ -\ -\ -\ -\ -\ -\
- \Eclipse Che\ - \
\
- \User removed from organization\ -\
- - \
- \

Hi,\

- \

\\ removed you from a Che organization called \\.\

- \
- -\
- \ - \ - \ -\
-\ -\ - diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationLinksInjectorTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationLinksInjectorTest.java deleted file mode 100644 index 4a8f079c933..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationLinksInjectorTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2012-2025 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)); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationManagerTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationManagerTest.java deleted file mode 100644 index 44e4bd4c9fe..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationManagerTest.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (c) 2012-2026 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 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, Collections.emptyList(), 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 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 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 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 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 organizations = manager.getByMember("org123", 30, 0); - - assertEquals(organizations.getItemsCount(), 1); - assertEquals(organizations.getItems().get(0), toFetch); - verify(memberDao).getOrganizations("org123", 30, 0); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationServiceTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationServiceTest.java deleted file mode 100644 index 3c236f7b92c..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/OrganizationServiceTest.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2012-2026 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.Collections; -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 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 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 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 unwrapDto(Response response, Class dtoClass) { - return DtoFactory.getInstance().createDtoFromJson(response.body().print(), dtoClass); - } - - private static List unwrapDtoList(Response response, Class 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", Collections.emptyList(), CURRENT_USER_ID, "token", false)); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationPermissionsFilterTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationPermissionsFilterTest.java deleted file mode 100644 index 8288a748f2a..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationPermissionsFilterTest.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 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 unwrapDto(Response response, Class 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); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationRemoteSubscriptionPermissionsChecksTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationRemoteSubscriptionPermissionsChecksTest.java deleted file mode 100644 index b8b200c8953..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationRemoteSubscriptionPermissionsChecksTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2012-2025 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")); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationResourceDistributionServicePermissionsFilterTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationResourceDistributionServicePermissionsFilterTest.java deleted file mode 100644 index d774a58c731..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationResourceDistributionServicePermissionsFilterTest.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 java.util.Collections.emptyList; -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.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -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.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import jakarta.ws.rs.core.MediaType; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Stream; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.core.rest.ApiExceptionMapper; -import org.eclipse.che.api.core.rest.CheJsonProvider; -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.resource.OrganizationResourcesDistributionService; -import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl; -import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto; -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.Listeners; -import org.testng.annotations.Test; - -/** - * Tests for {@link - * org.eclipse.che.multiuser.organization.api.permissions.OrganizationResourceDistributionServicePermissionsFilter} - * - * @author Sergii Leschenko - */ -@Listeners({EverrestJetty.class, MockitoTestNGListener.class}) -public class OrganizationResourceDistributionServicePermissionsFilterTest { - @SuppressWarnings("unused") - private static final ApiExceptionMapper MAPPER = new ApiExceptionMapper(); - - @SuppressWarnings("unused") - private static final EnvironmentFilter FILTER = new EnvironmentFilter(); - - @SuppressWarnings("unused") - private static final CheJsonProvider JSON_PROVIDER = new CheJsonProvider(new HashSet<>()); - - private static final String SUBORGANIZATION = "org123"; - private static final String PARENT_ORGANIZATION = "parentOrg123"; - - @Mock private static Subject subject; - - @Mock private OrganizationResourcesDistributionService service; - - @Mock private OrganizationManager manager; - - @Mock private SuperPrivilegesChecker superPrivilegesChecker; - - @InjectMocks private OrganizationResourceDistributionServicePermissionsFilter permissionsFilter; - - @BeforeMethod - public void setUp() throws Exception { - lenient() - .when(manager.getById(SUBORGANIZATION)) - .thenReturn(new OrganizationImpl(SUBORGANIZATION, "testOrg", PARENT_ORGANIZATION)); - lenient() - .when(manager.getById(PARENT_ORGANIZATION)) - .thenReturn(new OrganizationImpl(PARENT_ORGANIZATION, "parentOrg", null)); - - lenient().when(subject.hasPermission(anyString(), anyString(), anyString())).thenReturn(true); - } - - @Test - public void shouldTestThatAllPublicMethodsAreCoveredByPermissionsFilter() throws Exception { - // given - final List collect = - Stream.of(OrganizationResourcesDistributionService.class.getDeclaredMethods()) - .filter(method -> Modifier.isPublic(method.getModifiers())) - .map(Method::getName) - .collect(toList()); - - // then - assertEquals(collect.size(), 3); - assertTrue( - collect.contains( - OrganizationResourceDistributionServicePermissionsFilter.CAP_RESOURCES_METHOD)); - assertTrue( - collect.contains( - OrganizationResourceDistributionServicePermissionsFilter.GET_RESOURCES_CAP_METHOD)); - assertTrue( - collect.contains( - OrganizationResourceDistributionServicePermissionsFilter.GET_DISTRIBUTED_RESOURCES)); - } - - @Test - public void shouldCheckManageResourcesPermissionsOnResourcesCappingForSuborganization() - throws Exception { - List resources = - Collections.singletonList( - DtoFactory.newDto(ResourceDto.class).withType("test").withAmount(123).withUnit("unit")); - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType(MediaType.APPLICATION_JSON) - .body(resources) - .expect() - .statusCode(204) - .when() - .post(SECURE_PATH + "/organization/resource/" + SUBORGANIZATION + "/cap"); - - verify(service).capResources(SUBORGANIZATION, resources); - verify(subject) - .hasPermission( - OrganizationDomain.DOMAIN_ID, PARENT_ORGANIZATION, OrganizationDomain.MANAGE_RESOURCES); - } - - @Test - public void shouldNotCheckPermissionsOnResourcesCappingForRootOrganization() throws Exception { - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType(MediaType.APPLICATION_JSON) - .body(emptyList()) - .expect() - .statusCode(204) - .when() - .post(SECURE_PATH + "/organization/resource/" + PARENT_ORGANIZATION + "/cap"); - - verify(service).capResources(PARENT_ORGANIZATION, emptyList()); - verify(subject, never()).hasPermission(anyString(), anyString(), anyString()); - } - - @Test - public void - shouldCheckManageResourcesPermissionsOnGettingDistributedResourcesWhenUserDoesNotHaveSuperPrivileges() - throws Exception { - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .expect() - .statusCode(204) - .when() - .get(SECURE_PATH + "/organization/resource/" + PARENT_ORGANIZATION); - - verify(service).getDistributedResources(eq(PARENT_ORGANIZATION), anyInt(), anyLong()); - verify(subject) - .hasPermission( - OrganizationDomain.DOMAIN_ID, PARENT_ORGANIZATION, OrganizationDomain.MANAGE_RESOURCES); - verify(superPrivilegesChecker).hasSuperPrivileges(); - } - - @Test - public void - shouldNotCheckManageResourcesPermissionsOnGettingDistributedResourcesWhenUserHasSuperPrivileges() - throws Exception { - when(superPrivilegesChecker.hasSuperPrivileges()).thenReturn(true); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .expect() - .statusCode(204) - .when() - .get(SECURE_PATH + "/organization/resource/" + PARENT_ORGANIZATION); - - verify(service).getDistributedResources(eq(PARENT_ORGANIZATION), anyInt(), anyLong()); - verify(subject, never()) - .hasPermission( - OrganizationDomain.DOMAIN_ID, PARENT_ORGANIZATION, OrganizationDomain.MANAGE_RESOURCES); - verify(superPrivilegesChecker).hasSuperPrivileges(); - } - - @Test - public void - shouldCheckManageResourcesPermissionsOnGettingResourcesCapWhenUserDoesNotHaveSuperPrivileges() - throws Exception { - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .expect() - .statusCode(200) - .when() - .get(SECURE_PATH + "/organization/resource/" + SUBORGANIZATION + "/cap"); - - verify(service).getResourcesCap(SUBORGANIZATION); - verify(subject) - .hasPermission( - OrganizationDomain.DOMAIN_ID, PARENT_ORGANIZATION, OrganizationDomain.MANAGE_RESOURCES); - verify(superPrivilegesChecker).hasSuperPrivileges(); - } - - @Test - public void - shouldNotCheckManageResourcesPermissionsOnGettingResourcesCapWhenUserHasSuperPrivileges() - throws Exception { - when(superPrivilegesChecker.hasSuperPrivileges()).thenReturn(true); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .expect() - .statusCode(200) - .when() - .get(SECURE_PATH + "/organization/resource/" + SUBORGANIZATION + "/cap"); - - verify(service).getResourcesCap(SUBORGANIZATION); - verify(subject, never()) - .hasPermission( - OrganizationDomain.DOMAIN_ID, PARENT_ORGANIZATION, OrganizationDomain.MANAGE_RESOURCES); - verify(superPrivilegesChecker).hasSuperPrivileges(); - } - - @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 unknownMethod = - OrganizationResourcesDistributionService.class.getMethod("getServiceDescriptor"); - when(mock.getMethod()).thenReturn(unknownMethod); - - permissionsFilter.filter(mock, new Object[] {}); - } - - @Filter - public static class EnvironmentFilter implements RequestFilter { - @Override - public void doFilter(GenericContainerRequest request) { - EnvironmentContext.getCurrent().setSubject(subject); - } - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationalAccountPermissionsCheckerTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationalAccountPermissionsCheckerTest.java deleted file mode 100644 index f6440097e76..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/permissions/OrganizationalAccountPermissionsCheckerTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.mockito.ArgumentMatchers.anyString; -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 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.organization.spi.impl.OrganizationImpl; -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 for {@link - * org.eclipse.che.multiuser.organization.api.permissions.OrganizationalAccountPermissionsChecker} - * - * @author Sergii Leshchenko - */ -@Listeners(MockitoTestNGListener.class) -public class OrganizationalAccountPermissionsCheckerTest { - private static final String ORG_ID = "org123"; - - @Mock private Subject subject; - - private OrganizationalAccountPermissionsChecker permissionsChecker; - - @BeforeMethod - public void setUp() throws Exception { - lenient().when(subject.hasPermission(anyString(), anyString(), anyString())).thenReturn(true); - - EnvironmentContext.getCurrent().setSubject(subject); - - permissionsChecker = new OrganizationalAccountPermissionsChecker(); - } - - @AfterMethod - public void tearDown() throws Exception { - EnvironmentContext.reset(); - } - - @Test - public void shouldReturnOrganizationalReturnType() throws Exception { - // then - assertEquals(permissionsChecker.getAccountType(), OrganizationImpl.ORGANIZATIONAL_ACCOUNT); - } - - @Test - public void shouldCheckCreateWorkspacesPermissionOnOrganizationDomainLevel() throws Exception { - permissionsChecker.checkPermissions(ORG_ID, AccountOperation.CREATE_WORKSPACE); - - verify(subject) - .hasPermission(OrganizationDomain.DOMAIN_ID, ORG_ID, OrganizationDomain.CREATE_WORKSPACES); - } - - @Test( - expectedExceptions = ForbiddenException.class, - expectedExceptionsMessageRegExp = - "User is not authorized to create workspaces in specified namespace.") - public void shouldThrowForbiddenWhenUserDoesNotHavePermissionToCreateWorkspaces() - throws Exception { - when(subject.hasPermission( - OrganizationDomain.DOMAIN_ID, ORG_ID, OrganizationDomain.CREATE_WORKSPACES)) - .thenReturn(false); - - permissionsChecker.checkPermissions(ORG_ID, AccountOperation.CREATE_WORKSPACE); - } - - @Test - public void shouldCheckManageWorkspacesPermissionOnOrganizationDomainLevel() throws Exception { - permissionsChecker.checkPermissions(ORG_ID, AccountOperation.MANAGE_WORKSPACES); - - verify(subject) - .hasPermission(OrganizationDomain.DOMAIN_ID, ORG_ID, OrganizationDomain.MANAGE_WORKSPACES); - } - - @Test( - expectedExceptions = ForbiddenException.class, - expectedExceptionsMessageRegExp = "User is not authorized to use specified namespace.") - public void shouldThrowForbiddenWhenUserDoesNotHavePermissionToManagerWorkspaces() - throws Exception { - when(subject.hasPermission( - OrganizationDomain.DOMAIN_ID, ORG_ID, OrganizationDomain.MANAGE_WORKSPACES)) - .thenReturn(false); - - permissionsChecker.checkPermissions(ORG_ID, AccountOperation.MANAGE_WORKSPACES); - } - - @Test(dataProvider = "requiredAction") - public void - shouldNotThrowExceptionWhenUserHasAtLeastOnRequiredPermissionOnGettingResourcesInformation( - String action) throws Exception { - when(subject.hasPermission(anyString(), anyString(), anyString())).thenReturn(false); - when(subject.hasPermission(OrganizationDomain.DOMAIN_ID, ORG_ID, action)).thenReturn(true); - - permissionsChecker.checkPermissions(ORG_ID, AccountOperation.SEE_RESOURCE_INFORMATION); - - verify(subject).hasPermission(OrganizationDomain.DOMAIN_ID, ORG_ID, action); - } - - @Test( - expectedExceptions = ForbiddenException.class, - expectedExceptionsMessageRegExp = - "User is not authorized to see resources information of requested organization.") - public void shouldThrowForbiddenWhenUserDoesNotHavePermissionToSeeResourcesInformation() - throws Exception { - when(subject.hasPermission(anyString(), anyString(), anyString())).thenReturn(false); - - permissionsChecker.checkPermissions(ORG_ID, AccountOperation.SEE_RESOURCE_INFORMATION); - } - - @DataProvider - private Object[][] requiredAction() { - return new Object[][] { - {OrganizationDomain.CREATE_WORKSPACES}, - {OrganizationDomain.MANAGE_WORKSPACES}, - {OrganizationDomain.MANAGE_RESOURCES} - }; - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/DefaultOrganizationResourcesProviderTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/DefaultOrganizationResourcesProviderTest.java deleted file mode 100644 index 2d0e49bd3d7..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/DefaultOrganizationResourcesProviderTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 org.mockito.Mockito.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import java.util.List; -import org.eclipse.che.multiuser.organization.api.OrganizationManager; -import org.eclipse.che.multiuser.organization.shared.model.Organization; -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; -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.resource.DefaultOrganizationResourcesProvider} - * - * @author Sergii Leschenko - */ -@Listeners(MockitoTestNGListener.class) -public class DefaultOrganizationResourcesProviderTest { - @Mock private OrganizationManager organizationManager; - @Mock private Organization organization; - - private DefaultOrganizationResourcesProvider organizationResourcesProvider; - - @BeforeMethod - public void setUp() throws Exception { - organizationResourcesProvider = - new DefaultOrganizationResourcesProvider(organizationManager, "2gb", 10, 5, 10 * 60 * 1000); - when(organizationManager.getById(anyString())).thenReturn(organization); - } - - @Test - public void shouldNotProvideDefaultResourcesForSuborganization() throws Exception { - // given - when(organization.getParent()).thenReturn("parentId"); - - // when - final List defaultResources = - organizationResourcesProvider.getResources("organization123"); - - // then - verify(organizationManager).getById("organization123"); - assertTrue(defaultResources.isEmpty()); - } - - @Test - public void shouldProvideDefaultResourcesForRootOrganization() throws Exception { - // given - when(organization.getParent()).thenReturn(null); - - // when - final List defaultResources = - organizationResourcesProvider.getResources("organization123"); - - // then - verify(organizationManager).getById("organization123"); - assertEquals(defaultResources.size(), 4); - assertTrue( - defaultResources.contains( - new ResourceImpl(TimeoutResourceType.ID, 10, TimeoutResourceType.UNIT))); - assertTrue( - defaultResources.contains( - new ResourceImpl(RamResourceType.ID, 2048, RamResourceType.UNIT))); - assertTrue( - defaultResources.contains( - new ResourceImpl(WorkspaceResourceType.ID, 10, WorkspaceResourceType.UNIT))); - assertTrue( - defaultResources.contains( - new ResourceImpl(RuntimeResourceType.ID, 5, RuntimeResourceType.UNIT))); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourceLockKeyProviderTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourceLockKeyProviderTest.java deleted file mode 100644 index 0323e632bb8..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourceLockKeyProviderTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 org.mockito.Mockito.lenient; -import static org.testng.Assert.assertEquals; - -import org.eclipse.che.multiuser.organization.api.OrganizationManager; -import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** - * Tests for {@link - * org.eclipse.che.multiuser.organization.api.resource.OrganizationResourceLockKeyProvider} - * - * @author Sergii Leschenko - */ -@Listeners(MockitoTestNGListener.class) -public class OrganizationResourceLockKeyProviderTest { - @Mock private OrganizationManager organizationManager; - - @InjectMocks private OrganizationResourceLockKeyProvider lockProvider; - - @Test - public void shouldReturnRootOrganizationId() throws Exception { - // given - createOrganization("root", null); - createOrganization("suborg", "root"); - createOrganization("subsuborg", "suborg"); - - // when - final String lockId = lockProvider.getLockKey("subsuborg"); - - // then - assertEquals(lockId, "root"); - } - - @Test - public void shouldReturnOrganizationalReturnType() throws Exception { - // then - assertEquals(lockProvider.getAccountType(), OrganizationImpl.ORGANIZATIONAL_ACCOUNT); - } - - private void createOrganization(String id, String parentId) throws Exception { - lenient() - .when(organizationManager.getById(id)) - .thenReturn(new OrganizationImpl(id, id + "Name", parentId)); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributionServiceTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributionServiceTest.java deleted file mode 100644 index 1815b4df3f3..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributionServiceTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 io.restassured.RestAssured.given; -import static java.util.Collections.singletonList; -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.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import io.restassured.response.Response; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Collectors; -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.dto.server.DtoFactory; -import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDistributedResourcesDto; -import org.eclipse.che.multiuser.resource.api.free.ResourceValidator; -import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto; -import org.everrest.assured.EverrestJetty; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** - * Tests for {@link - * org.eclipse.che.multiuser.organization.api.resource.OrganizationResourcesDistributionService} - * - * @author Sergii Leschenko - */ -@Listeners({EverrestJetty.class, MockitoTestNGListener.class}) -public class OrganizationResourcesDistributionServiceTest { - @SuppressWarnings("unused") // is declared for deploying by everrest-assured - private ApiExceptionMapper mapper; - - @SuppressWarnings("unused") // is declared for deploying by everrest-assured - private CheJsonProvider jsonProvider = new CheJsonProvider(new HashSet<>()); - - @Mock private OrganizationResourcesDistributor organizationResourcesManager; - @Mock private ResourceValidator resourceValidator; - - @InjectMocks private OrganizationResourcesDistributionService service; - - @Test - public void shouldCapOrganizationResources() throws Exception { - ResourceDto resource = - DtoFactory.newDto(ResourceDto.class).withType("test").withAmount(1020).withUnit("unit"); - List resources = singletonList(resource); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType("application/json") - .body(resources) - .when() - .post(SECURE_PATH + "/organization/resource/organization123/cap") - .then() - .assertThat() - .statusCode(204); - - verify(organizationResourcesManager).capResources("organization123", resources); - verify(resourceValidator).validate(resource); - } - - @Test - public void - shouldReturn400WhenBodyContainTwoResourcesWithTheSameTypeOnDistributingOrganizationResources() - throws Exception { - List resources = - Arrays.asList( - DtoFactory.newDto(ResourceDto.class).withType("test"), - DtoFactory.newDto(ResourceDto.class).withType("test")); - - Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType("application/json") - .body(resources) - .when() - .post(SECURE_PATH + "/organization/resource/organization123/cap"); - assertEquals(response.statusCode(), 400); - String errorMessage = - DtoFactory.getInstance() - .createDtoFromJson(response.print(), ServiceError.class) - .getMessage(); - assertEquals(errorMessage, "Resources to cap must contain only one resource with type 'test'."); - } - - @Test - public void shouldReturnResourcesCapForSuborganization() throws Exception { - final ResourceDto resourcesCap = - DtoFactory.newDto(ResourceDto.class).withType("test").withAmount(1020).withUnit("unit"); - final List toFetch = singletonList(resourcesCap); - doReturn(toFetch).when(organizationResourcesManager).getResourcesCaps(any()); - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType("application/json") - .when() - .get(SECURE_PATH + "/organization/resource/organization123/cap"); - - assertEquals(response.statusCode(), 200); - final List fetched = unwrapDtoList(response, ResourceDto.class); - assertEquals(fetched.size(), 1); - assertTrue(fetched.contains(resourcesCap)); - verify(organizationResourcesManager).getResourcesCaps("organization123"); - } - - @Test - public void shouldReturnOrganizationDistributedResources() throws Exception { - final OrganizationDistributedResourcesDto distributedResources = - createOrganizationDistributedResources(); - final List toFetch = singletonList(distributedResources); - doReturn(new Page<>(toFetch, 1, 1, 3)) - .when(organizationResourcesManager) - .getByParent(any(), anyInt(), anyLong()); - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType("application/json") - .when() - .get(SECURE_PATH + "/organization/resource/organization123?maxItems=1&skipCount=1"); - assertEquals(response.statusCode(), 200); - final List fetched = - unwrapDtoList(response, OrganizationDistributedResourcesDto.class); - assertEquals(fetched.size(), 1); - assertTrue(fetched.contains(distributedResources)); - verify(organizationResourcesManager).getByParent("organization123", 1, 1L); - } - - private static List unwrapDtoList(Response response, Class dtoClass) { - return DtoFactory.getInstance() - .createListDtoFromJson(response.body().print(), dtoClass) - .stream() - .collect(Collectors.toList()); - } - - private OrganizationDistributedResourcesDto createOrganizationDistributedResources() { - return DtoFactory.newDto(OrganizationDistributedResourcesDto.class) - .withOrganizationId("organization123") - .withResourcesCap( - singletonList( - DtoFactory.newDto(ResourceDto.class) - .withType("test") - .withAmount(1020) - .withUnit("unit"))); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributorTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributorTest.java deleted file mode 100644 index 21f7b8ebfbb..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationResourcesDistributorTest.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 static java.util.Collections.emptyList; -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.Mockito.doCallRealMethod; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; - -import java.util.Collections; -import java.util.List; -import org.eclipse.che.api.core.ConflictException; -import org.eclipse.che.api.core.Page; -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.organization.spi.impl.OrganizationImpl; -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.api.usage.ResourcesLocks; -import org.eclipse.che.multiuser.resource.model.Resource; -import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** - * Tests for {@link OrganizationResourcesDistributor} - * - * @author Sergii Leschenko - */ -@Listeners(MockitoTestNGListener.class) -public class OrganizationResourcesDistributorTest { - private static final String PARENT_ORG_ID = "parentOrg123"; - private static final String ORG_ID = "organization123"; - - @Mock private Unlocker lock; - @Mock private OrganizationDistributedResourcesDao distributedResourcesDao; - @Mock private ResourcesLocks resourcesLocks; - @Mock private ResourceManager resourceManager; - @Mock private ResourceAggregator resourceAggregator; - @Mock private OrganizationManager organizationManager; - - @Spy @InjectMocks private OrganizationResourcesDistributor manager; - - @BeforeMethod - public void setUp() throws Exception { - lenient().doNothing().when(manager).checkResourcesAvailability(anyString(), any()); - lenient().when(resourcesLocks.lock(anyString())).thenReturn(lock); - - lenient() - .when(organizationManager.getById(ORG_ID)) - .thenReturn(new OrganizationImpl(ORG_ID, ORG_ID + "name", PARENT_ORG_ID)); - lenient() - .when(organizationManager.getById(PARENT_ORG_ID)) - .thenReturn(new OrganizationImpl(PARENT_ORG_ID, PARENT_ORG_ID + "name", null)); - } - - @Test - public void shouldCapResources() throws Exception { - List toCap = singletonList(createTestResource(1000)); - - // when - manager.capResources(ORG_ID, toCap); - - // then - verify(manager).checkResourcesAvailability(ORG_ID, toCap); - verify(distributedResourcesDao).store(new OrganizationDistributedResourcesImpl(ORG_ID, toCap)); - verify(resourcesLocks).lock(ORG_ID); - verify(lock).close(); - } - - @Test - public void shouldRemoveResourceFromListWhenItsAmountEqualsToMinusOne() throws Exception { - ResourceImpl toCap = new ResourceImpl("test1", 1000, "init"); - ResourceImpl toReset = new ResourceImpl("test2", -1, "init"); - List resourcesToCap = asList(toCap, toReset); - - // when - manager.capResources(ORG_ID, resourcesToCap); - - // then - verify(manager).checkResourcesAvailability(ORG_ID, singletonList(toCap)); - verify(distributedResourcesDao) - .store(new OrganizationDistributedResourcesImpl(ORG_ID, singletonList(toCap))); - verify(resourcesLocks).lock(ORG_ID); - verify(lock).close(); - } - - @Test - public void shouldRemoveResourcesCapWhenInvokeCapWithEmptyList() throws Exception { - // when - manager.capResources(ORG_ID, Collections.emptyList()); - - // then - verify(manager, never()).checkResourcesAvailability(anyString(), any()); - verify(distributedResourcesDao).remove(ORG_ID); - verify(resourcesLocks).lock(ORG_ID); - verify(lock).close(); - } - - @Test( - expectedExceptions = ConflictException.class, - expectedExceptionsMessageRegExp = "It is not allowed to cap resources for root organization.") - public void shouldThrowConflictExceptionOnCappingResourcesForRootOrganization() throws Exception { - // when - manager.capResources(PARENT_ORG_ID, Collections.emptyList()); - } - - @Test(expectedExceptions = NullPointerException.class) - public void shouldThrowNpeOnDistributionResourcesWithNullOrganizationId() throws Exception { - // when - manager.capResources(null, emptyList()); - } - - @Test(expectedExceptions = NullPointerException.class) - public void shouldThrowNpeOnDistributionNullResourcesList() throws Exception { - // when - manager.capResources(ORG_ID, null); - } - - @Test - public void shouldGetDistributedResources() throws Exception { - // given - final OrganizationDistributedResourcesImpl distributedResources = - createDistributedResources(1000); - doReturn(new Page<>(singletonList(distributedResources), 0, 10, 1)) - .when(distributedResourcesDao) - .getByParent(anyString(), anyInt(), anyLong()); - - // when - final Page fetchedDistributedResources = - manager.getByParent(ORG_ID, 10, 0); - - // then - assertEquals(fetchedDistributedResources.getTotalItemsCount(), 1); - assertEquals(fetchedDistributedResources.getItems().get(0), distributedResources); - verify(distributedResourcesDao).getByParent(ORG_ID, 10, 0); - } - - @Test(expectedExceptions = NullPointerException.class) - public void shouldThrowNpeOnGettingDistributedResourcesByNullOrganizationId() throws Exception { - // when - manager.getByParent(null, 10, 10); - } - - @Test - public void shouldGetResourcesCap() throws Exception { - // given - final OrganizationDistributedResourcesImpl distributedResources = - createDistributedResources(1000); - when(distributedResourcesDao.get(anyString())).thenReturn(distributedResources); - - // when - final List fetchedDistributedResources = manager.getResourcesCaps(ORG_ID); - - // then - assertEquals(fetchedDistributedResources, distributedResources.getResourcesCap()); - verify(distributedResourcesDao).get(ORG_ID); - } - - @Test(expectedExceptions = NullPointerException.class) - public void shouldThrowNpeOnGettingResourcesCapByNullOrganizationId() throws Exception { - // when - manager.getResourcesCaps(null); - } - - @Test - public void shouldResourceAvailabilityCappingResourcesWhenResourceCapIsLessThanUsedOne() - throws Exception { - // given - doCallRealMethod().when(manager).checkResourcesAvailability(anyString(), any()); - - ResourceImpl used = createTestResource(500); - doReturn(singletonList(used)).when(resourceManager).getUsedResources(any()); - - ResourceImpl toCap = createTestResource(700); - doReturn(createTestResource(200)).when(resourceAggregator).deduct((Resource) any(), any()); - - // when - manager.checkResourcesAvailability(ORG_ID, singletonList(toCap)); - - // then - verify(resourceManager).getUsedResources(ORG_ID); - verify(resourceAggregator).deduct(toCap, used); - } - - @Test( - expectedExceptions = ConflictException.class, - expectedExceptionsMessageRegExp = "Resources are currently in use. Denied.") - public void shouldResourceAvailabilityCappingResourcesWhenResourceCapIsGreaterThanUsedOne() - throws Exception { - // given - doCallRealMethod().when(manager).checkResourcesAvailability(anyString(), any()); - doReturn("Denied.").when(manager).getMessage(anyString()); - - ResourceImpl used = createTestResource(1000); - doReturn(singletonList(used)).when(resourceManager).getUsedResources(any()); - - ResourceImpl toCap = createTestResource(700); - doThrow(new NoEnoughResourcesException(emptyList(), emptyList(), singletonList(toCap))) - .when(resourceAggregator) - .deduct((Resource) any(), any()); - - // when - manager.checkResourcesAvailability(ORG_ID, singletonList(toCap)); - - // then - verify(resourceManager).getUsedResources(ORG_ID); - verify(resourceAggregator).deduct(toCap, used); - } - - private ResourceImpl createTestResource(long amount) { - return new ResourceImpl("test", amount, "init"); - } - - private OrganizationDistributedResourcesImpl createDistributedResources(long resourceAmount) { - return new OrganizationDistributedResourcesImpl( - ORG_ID, singletonList(createTestResource(resourceAmount))); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationalAccountAvailableResourcesProviderTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationalAccountAvailableResourcesProviderTest.java deleted file mode 100644 index 79e2d2e0c7a..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/OrganizationalAccountAvailableResourcesProviderTest.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -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.times; -import static org.mockito.Mockito.verify; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import java.util.List; -import javax.inject.Provider; -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.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.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.eclipse.che.multiuser.resource.spi.impl.ResourceImpl; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** Test for {@link OrganizationalAccountAvailableResourcesProvider} */ -@Listeners(MockitoTestNGListener.class) -public class OrganizationalAccountAvailableResourcesProviderTest { - private static final String ROOT_ORG_NAME = "root"; - private static final String ROOT_ORG_ID = "organization123"; - private static final String SUBORG_ID = "organization321"; - private static final String SUBSUBORG_ID = "organization231"; - - @Mock private Provider resourceManagerProvider; - @Mock private ResourceManager resourceManager; - @Mock private ResourceAggregator resourceAggregator; - @Mock private OrganizationManager organizationManager; - - @InjectMocks @Spy - private OrganizationalAccountAvailableResourcesProvider availableResourcesProvider; - - private Organization rootOrganization; - private Organization suborganization; - private Organization subsuborganization; - - @BeforeMethod - public void setUp() throws Exception { - lenient().when(resourceManagerProvider.get()).thenReturn(resourceManager); - - rootOrganization = new OrganizationImpl(ROOT_ORG_ID, ROOT_ORG_NAME, null); - suborganization = new OrganizationImpl(SUBORG_ID, "root/suborg", ROOT_ORG_ID); - subsuborganization = new OrganizationImpl(SUBSUBORG_ID, "root/suborg/subsuborg", SUBORG_ID); - - lenient().when(organizationManager.getById(ROOT_ORG_ID)).thenReturn(rootOrganization); - lenient().when(organizationManager.getById(SUBORG_ID)).thenReturn(suborganization); - lenient().when(organizationManager.getById(SUBSUBORG_ID)).thenReturn(subsuborganization); - } - - @Test - public void shouldReturnAvailableResourcesForRootOrganization() throws Exception { - // given - ResourceImpl availableResource = new ResourceImpl("test", 5000, "unit"); - doReturn(singletonList(availableResource)) - .when(availableResourcesProvider) - .getAvailableOrganizationResources(any()); - - // when - List availableResources = - availableResourcesProvider.getAvailableResources(ROOT_ORG_ID); - - // then - assertEquals(availableResources.size(), 1); - assertEquals(availableResources.get(0), availableResource); - verify(availableResourcesProvider).getAvailableResources(ROOT_ORG_ID); - } - - @Test - public void shouldReturnAvailableResourcesForSuborganization() throws Exception { - // given - ResourceImpl parentAvailableResource = new ResourceImpl("test", 3000, "unit"); - prepareAvailableResource(ROOT_ORG_ID, parentAvailableResource); - ResourceImpl suborgAvailableResource = new ResourceImpl("test", 5000, "unit"); - prepareAvailableResource(SUBORG_ID, suborgAvailableResource); - doReturn(asList(parentAvailableResource, suborgAvailableResource)) - .when(resourceAggregator) - .intersection(anyList(), anyList()); - doReturn(singletonList(parentAvailableResource)).when(resourceAggregator).min(anyList()); - - // when - List availableResources = - availableResourcesProvider.getAvailableResources(SUBORG_ID); - - // then - assertEquals(availableResources.size(), 1); - assertEquals(availableResources.get(0), parentAvailableResource); - verify(availableResourcesProvider).getAvailableOrganizationResources(rootOrganization); - verify(availableResourcesProvider).getAvailableOrganizationResources(suborganization); - verify(resourceAggregator) - .intersection( - singletonList(parentAvailableResource), singletonList(suborgAvailableResource)); - verify(resourceAggregator).min(asList(parentAvailableResource, suborgAvailableResource)); - } - - @Test - public void shouldReturnAvailableResourcesAsTotalMinusUsedByItselfAndItsSuborganizations() - throws Exception { - // given - ResourceImpl totalResource = new ResourceImpl("test", 9000, "unit"); - doReturn(singletonList(totalResource)).when(resourceManager).getTotalResources(anyString()); - - ResourceImpl usedResource = new ResourceImpl("test", 3000, "unit"); - doReturn(singletonList(usedResource)).when(resourceManager).getUsedResources(anyString()); - - ResourceImpl usedBySuborgResource = new ResourceImpl("test", 1500, "unit"); - ResourceImpl usedBySubsuborgResource = new ResourceImpl("test", 2000, "unit"); - doReturn(asList(usedBySuborgResource, usedBySubsuborgResource)) - .when(availableResourcesProvider) - .getUsedResourcesBySuborganizations(anyString()); - - ResourceImpl availableResource = new ResourceImpl("test", 2500, "unit"); - doReturn(singletonList(availableResource)) - .when(resourceAggregator) - .deduct(anyList(), anyList()); - - // when - List availableResources = - availableResourcesProvider.getAvailableOrganizationResources(rootOrganization); - - // then - assertEquals(availableResources.size(), 1); - assertEquals(availableResources.get(0), availableResource); - verify(resourceManager).getTotalResources(ROOT_ORG_ID); - verify(resourceManager).getUsedResources(ROOT_ORG_ID); - verify(availableResourcesProvider).getUsedResourcesBySuborganizations(ROOT_ORG_NAME); - verify(resourceAggregator) - .deduct( - singletonList(totalResource), - asList(usedResource, usedBySuborgResource, usedBySubsuborgResource)); - } - - @Test - public void shouldReturnExcessiveResourcesWhenUsedResourceAreGreaterThanTotal() throws Exception { - // given - ResourceImpl totalResource = new ResourceImpl("test", 9000, "unit"); - ResourceImpl excessiveTotalResource = new ResourceImpl("test1", 1000, "unit"); - doReturn(asList(totalResource, excessiveTotalResource)) - .when(resourceManager) - .getTotalResources(anyString()); - - ResourceImpl usedResource = new ResourceImpl("test", 10000, "unit"); - doReturn(singletonList(usedResource)).when(resourceManager).getUsedResources(anyString()); - - doReturn(emptyList()) - .when(availableResourcesProvider) - .getUsedResourcesBySuborganizations(anyString()); - - doThrow(new NoEnoughResourcesException(emptyList(), emptyList(), emptyList())) - .when(resourceAggregator) - .deduct(anyList(), anyList()); - doReturn(singletonList(excessiveTotalResource)) - .when(resourceAggregator) - .excess(anyList(), anyList()); - - // when - List availableResources = - availableResourcesProvider.getAvailableOrganizationResources(rootOrganization); - - // then - assertEquals(availableResources.size(), 1); - assertEquals(availableResources.get(0), excessiveTotalResource); - verify(resourceManager).getTotalResources(ROOT_ORG_ID); - verify(resourceManager).getUsedResources(ROOT_ORG_ID); - verify(availableResourcesProvider).getUsedResourcesBySuborganizations(ROOT_ORG_NAME); - verify(resourceAggregator) - .deduct(asList(totalResource, excessiveTotalResource), singletonList(usedResource)); - verify(resourceAggregator) - .excess(asList(totalResource, excessiveTotalResource), singletonList(usedResource)); - } - - @Test - public void shouldCalculateUsedResourceBySuborganizations() throws Exception { - // given - doReturn(new Page<>(singletonList(suborganization), 0, 1, 2)) - .doReturn(new Page<>(singletonList(subsuborganization), 1, 1, 2)) - .when(organizationManager) - .getSuborganizations(anyString(), anyInt(), anyLong()); - ResourceImpl usedBySuborgResource = new ResourceImpl("test", 1500, "unit"); - doReturn(singletonList(usedBySuborgResource)).when(resourceManager).getUsedResources(SUBORG_ID); - ResourceImpl usedBySubsuborgResource = new ResourceImpl("test", 2000, "unit"); - doReturn(singletonList(usedBySubsuborgResource)) - .when(resourceManager) - .getUsedResources(SUBSUBORG_ID); - - // when - List usedResources = - availableResourcesProvider.getUsedResourcesBySuborganizations(ROOT_ORG_NAME); - - // then - assertEquals(usedResources.size(), 2); - assertTrue(usedResources.contains(usedBySuborgResource)); - assertTrue(usedResources.contains(usedBySubsuborgResource)); - verify(organizationManager, times(2)) - .getSuborganizations(eq(ROOT_ORG_NAME), anyInt(), anyLong()); - verify(resourceManager).getUsedResources(SUBORG_ID); - verify(resourceManager).getUsedResources(SUBSUBORG_ID); - } - - private void prepareAvailableResource(String organizationId, ResourceImpl availableResource) - throws NotFoundException, ServerException { - doReturn(singletonList(availableResource)) - .when(availableResourcesProvider) - .getAvailableOrganizationResources( - argThat(argument -> organizationId.equals(((Organization) argument).getId()))); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/SuborganizationResourcesProviderTest.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/SuborganizationResourcesProviderTest.java deleted file mode 100644 index 7e3281f1695..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/api/resource/SuborganizationResourcesProviderTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2012-2025 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 static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import java.util.List; -import javax.inject.Provider; -import org.eclipse.che.account.api.AccountManager; -import org.eclipse.che.account.shared.model.Account; -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.usage.ResourceManager; -import org.eclipse.che.multiuser.resource.model.ProvidedResources; -import org.eclipse.che.multiuser.resource.spi.impl.ProvidedResourcesImpl; -import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl; -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.resource.SuborganizationResourcesProvider} - * - * @author Sergii Leschenko - */ -@Listeners(MockitoTestNGListener.class) -public class SuborganizationResourcesProviderTest { - @Mock private Account account; - @Mock private Organization organization; - - @Mock private AccountManager accountManager; - @Mock private OrganizationManager organizationManager; - @Mock private OrganizationResourcesDistributor resourcesDistributor; - @Mock private Provider distributorProvider; - @Mock private Provider resourceManagerProvider; - @Mock private ResourceManager resourceManager; - - private SuborganizationResourcesProvider suborganizationResourcesProvider; - - @BeforeMethod - public void setUp() throws Exception { - when(accountManager.getById(any())).thenReturn(account); - lenient().when(organizationManager.getById(any())).thenReturn(organization); - - lenient().when(distributorProvider.get()).thenReturn(resourcesDistributor); - - lenient().when(resourceManagerProvider.get()).thenReturn(resourceManager); - - suborganizationResourcesProvider = - new SuborganizationResourcesProvider( - accountManager, organizationManager, distributorProvider, resourceManagerProvider); - } - - @Test - public void shouldNotProvideResourcesForNonOrganizationalAccounts() throws Exception { - // given - when(account.getType()).thenReturn("test"); - - // when - final List providedResources = - suborganizationResourcesProvider.getResources("account123"); - - // then - assertTrue(providedResources.isEmpty()); - verify(accountManager).getById("account123"); - } - - @Test - public void shouldNotProvideResourcesForRootOrganizationalAccount() throws Exception { - // given - when(account.getType()).thenReturn(OrganizationImpl.ORGANIZATIONAL_ACCOUNT); - when(organization.getParent()).thenReturn(null); - - // when - final List providedResources = - suborganizationResourcesProvider.getResources("organization123"); - - // then - assertTrue(providedResources.isEmpty()); - verify(accountManager).getById("organization123"); - verify(organizationManager).getById("organization123"); - } - - @Test - public void shouldProvideResourcesForSuborganizationalAccount() throws Exception { - // given - when(account.getType()).thenReturn(OrganizationImpl.ORGANIZATIONAL_ACCOUNT); - when(organization.getParent()).thenReturn("parentOrg"); - final ResourceImpl parentNotCapedResource = new ResourceImpl("test", 1234, "unit"); - final ResourceImpl parentCapedResource = new ResourceImpl("caped", 20, "unit"); - final ResourceImpl parentUnlimitedCapedResource = new ResourceImpl("unlimited", -1, "unit"); - doReturn(asList(parentNotCapedResource, parentCapedResource, parentUnlimitedCapedResource)) - .when(resourceManager) - .getTotalResources(anyString()); - - final ResourceImpl capedResourceCap = new ResourceImpl("caped", 10, "unit"); - final ResourceImpl unlimitedCapedResourceCap = new ResourceImpl("unlimited", 40, "unit"); - doReturn(asList(capedResourceCap, unlimitedCapedResourceCap)) - .when(resourcesDistributor) - .getResourcesCaps(any()); - - // when - final List providedResources = - suborganizationResourcesProvider.getResources("organization123"); - - // then - assertEquals(providedResources.size(), 1); - assertEquals( - providedResources.get(0), - new ProvidedResourcesImpl( - SuborganizationResourcesProvider.PARENT_RESOURCES_PROVIDER, - null, - "organization123", - -1L, - -1L, - asList(parentNotCapedResource, capedResourceCap, unlimitedCapedResourceCap))); - verify(accountManager).getById("organization123"); - verify(organizationManager).getById("organization123"); - verify(resourcesDistributor).getResourcesCaps("organization123"); - verify(resourceManager).getTotalResources("parentOrg"); - } - - @Test - public void shouldNotProvideResourcesForOrganizationalAccountIfItDoesNotHaveDistributedResources() - throws Exception { - // given - when(account.getType()).thenReturn(OrganizationImpl.ORGANIZATIONAL_ACCOUNT); - when(organization.getParent()).thenReturn("parentOrg"); - - // when - final List providedResources = - suborganizationResourcesProvider.getResources("organization123"); - - // then - assertTrue(providedResources.isEmpty()); - verify(accountManager).getById("organization123"); - verify(organizationManager).getById("organization123"); - verify(resourcesDistributor, never()).getResourcesCaps("organization123"); - verify(resourceManager).getTotalResources("parentOrg"); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/spi/jpa/JpaOrganizationImplTckRepository.java b/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/spi/jpa/JpaOrganizationImplTckRepository.java deleted file mode 100644 index e6c73a061b5..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/java/org/eclipse/che/multiuser/organization/spi/jpa/JpaOrganizationImplTckRepository.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.jpa; - -import com.google.inject.Inject; -import com.google.inject.persist.UnitOfWork; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import javax.inject.Provider; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; -import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; -import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl; - -/** - * Organizations require to have own repository because it is important to delete organization in - * reverse order that they were stored. It allows to resolve problems with removing suborganization - * before parent organization removing. - * - * @author Sergii Leschenko - */ -public class JpaOrganizationImplTckRepository extends JpaTckRepository { - @Inject protected Provider managerProvider; - - @Inject protected UnitOfWork uow; - - private final List createdOrganizations = new ArrayList<>(); - - public JpaOrganizationImplTckRepository() { - super(OrganizationImpl.class); - } - - @Override - public void createAll(Collection entities) - throws TckRepositoryException { - super.createAll(entities); - // It's important to save organization to remove them in the reverse order - createdOrganizations.addAll(entities); - } - - @Override - public void removeAll() throws TckRepositoryException { - uow.begin(); - final EntityManager manager = managerProvider.get(); - try { - manager.getTransaction().begin(); - - for (int i = createdOrganizations.size() - 1; i > -1; i--) { - // The query 'DELETE FROM ....' won't be correct as it will ignore orphanRemoval - // and may also ignore some configuration options, while EntityManager#remove won't - try { - final OrganizationImpl organizationToRemove = - manager - .createQuery( - "SELECT o FROM Organization o " + "WHERE o.id = :id", OrganizationImpl.class) - .setParameter("id", createdOrganizations.get(i).getId()) - .getSingleResult(); - manager.remove(organizationToRemove); - } catch (NoResultException ignored) { - // it is already removed - } - } - createdOrganizations.clear(); - - manager.getTransaction().commit(); - } catch (RuntimeException x) { - if (manager.getTransaction().isActive()) { - manager.getTransaction().rollback(); - } - throw new TckRepositoryException(x.getLocalizedMessage(), x); - } finally { - uow.end(); - } - - // remove all objects that was created in tests - super.removeAll(); - } -} diff --git a/multiuser/api/che-multiuser-api-organization/src/test/resources/META-INF/persistence.xml b/multiuser/api/che-multiuser-api-organization/src/test/resources/META-INF/persistence.xml deleted file mode 100644 index c9409c32cad..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/resources/META-INF/persistence.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - org.eclipse.persistence.jpa.PersistenceProvider - org.eclipse.che.account.spi.AccountImpl - org.eclipse.che.api.user.server.model.impl.UserImpl - org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl - org.eclipse.che.multiuser.organization.spi.impl.MemberImpl - org.eclipse.che.multiuser.organization.spi.impl.OrganizationDistributedResourcesImpl - org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl - true - - - - - - - - - - - - - diff --git a/multiuser/api/che-multiuser-api-organization/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule b/multiuser/api/che-multiuser-api-organization/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule deleted file mode 100644 index ad7b8c2b406..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule +++ /dev/null @@ -1 +0,0 @@ -org.eclipse.che.multiuser.organization.spi.tck.jpa.OrganizationJpaTckModule diff --git a/multiuser/api/che-multiuser-api-organization/src/test/resources/logback-test.xml b/multiuser/api/che-multiuser-api-organization/src/test/resources/logback-test.xml deleted file mode 100644 index 3d4d10adab1..00000000000 --- a/multiuser/api/che-multiuser-api-organization/src/test/resources/logback-test.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n - - - - - - - diff --git a/multiuser/api/che-multiuser-api-permission/pom.xml b/multiuser/api/che-multiuser-api-permission/pom.xml index 7934b3ae473..676caa680ea 100644 --- a/multiuser/api/che-multiuser-api-permission/pom.xml +++ b/multiuser/api/che-multiuser-api-permission/pom.xml @@ -108,16 +108,6 @@ che-core-api-account test
- - org.eclipse.che.core - che-core-sql-schema - test - - - org.eclipse.che.multiuser - che-multiuser-sql-schema - test - org.eclipse.persistence org.eclipse.persistence.core @@ -261,11 +251,6 @@ unpack-dependencies - - che-core-sql-schema, che-multiuser-sql-schema - che-schema/ - ${project.build.directory} - diff --git a/multiuser/api/che-multiuser-api-resource-shared/pom.xml b/multiuser/api/che-multiuser-api-resource-shared/pom.xml deleted file mode 100644 index 1cf4b7cfcbc..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - 4.0.0 - - che-multiuser-api - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-api-resource-shared - jar - Che Multiuser :: Resource :: Shared - - - org.eclipse.che.core - che-core-api-dto - - - org.eclipse.che.core - che-core-commons-annotations - - - diff --git a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/FreeResourcesLimit.java b/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/FreeResourcesLimit.java deleted file mode 100644 index a33d2b911a4..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/FreeResourcesLimit.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.model; - -import java.util.List; - -/** - * Represents limit of resources which are available for free usage by some account. - * - * @author Sergii Leschenko - */ -public interface FreeResourcesLimit { - /** Returns id of account that can use free resources. */ - String getAccountId(); - - /** Returns resources which are available for free usage. */ - List getResources(); -} diff --git a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/ProvidedResources.java b/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/ProvidedResources.java deleted file mode 100644 index 3833ab5b5ff..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/ProvidedResources.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.model; - -import java.util.List; -import org.eclipse.che.commons.annotation.Nullable; - -/** - * Resources that are provided for using by account by some resource providing mechanism. - * - * @author Sergii Leschenko - */ -public interface ProvidedResources { - - /** Returns id of resource provider. */ - String getProviderId(); - - /** - * Returns id of granted resource entity. Can be null when provider provides static single entry. - */ - @Nullable - String getId(); - - /** Returns owner of resources. */ - String getOwner(); - - /** Returns time when resources became active. */ - Long getStartTime(); - - /** Returns time when resources will be/became inactive. */ - Long getEndTime(); - - /** Returns list of resources which can be used by owner. */ - List getResources(); -} diff --git a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/Resource.java b/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/Resource.java deleted file mode 100644 index 552337b871d..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/Resource.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.model; - -/** - * Represents some number of resources that can be used by account. - * - * @author gazarenkov - * @author Sergii Leschenko - */ -public interface Resource { - /** Returns type of resources, e.g. RAM. */ - String getType(); - - /** - * Returns amount of resources. - * - *

Applicable values here are from -1 to {@link Long#MAX_VALUE} inclusively. -1 value represent - * infinity. - */ - long getAmount(); - - /** Returns unit of resources. */ - String getUnit(); -} diff --git a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/ResourcesDetails.java b/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/ResourcesDetails.java deleted file mode 100644 index d51ea27b063..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/model/ResourcesDetails.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.model; - -import java.util.List; - -/** - * Permits account to use some resources. - * - * @author gazarenkov - * @author Sergii Leschenko - */ -public interface ResourcesDetails { - /** Returns id of account that is owner of these resources. */ - String getAccountId(); - - /** Returns detailed list of resources which can be used by owner. */ - List getProvidedResources(); - - /** Returns list of resources which can be used by owner. */ - List getTotalResources(); -} diff --git a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/FreeResourcesLimitDto.java b/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/FreeResourcesLimitDto.java deleted file mode 100644 index 743e541396f..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/FreeResourcesLimitDto.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.shared.dto; - -import java.util.List; -import org.eclipse.che.dto.shared.DTO; -import org.eclipse.che.multiuser.resource.model.FreeResourcesLimit; - -/** - * @author Sergii Leschenko - */ -@DTO -public interface FreeResourcesLimitDto extends FreeResourcesLimit { - @Override - String getAccountId(); - - void setAccountId(String accountId); - - FreeResourcesLimitDto withAccountId(String accountId); - - @Override - List getResources(); - - void setResources(List resources); - - FreeResourcesLimitDto withResources(List resources); -} diff --git a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ProvidedResourcesDto.java b/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ProvidedResourcesDto.java deleted file mode 100644 index a7e240edc61..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ProvidedResourcesDto.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.shared.dto; - -import java.util.List; -import org.eclipse.che.dto.shared.DTO; -import org.eclipse.che.multiuser.resource.model.ProvidedResources; - -/** - * @author Sergii Leschenko - */ -@DTO -public interface ProvidedResourcesDto extends ProvidedResources { - @Override - String getProviderId(); - - void setProviderId(String providerId); - - ProvidedResourcesDto withProviderId(String providerId); - - @Override - String getId(); - - void setId(String id); - - ProvidedResourcesDto withId(String id); - - @Override - String getOwner(); - - void setOwner(String owner); - - ProvidedResourcesDto withOwner(String owner); - - @Override - Long getStartTime(); - - void setStartTime(Long startTime); - - ProvidedResourcesDto withStartTime(Long startTime); - - @Override - Long getEndTime(); - - void setEndTime(Long endTime); - - ProvidedResourcesDto withEndTime(Long endTime); - - @Override - List getResources(); - - void setResources(List resources); - - ProvidedResourcesDto withResources(List resources); -} diff --git a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ResourceDto.java b/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ResourceDto.java deleted file mode 100644 index 71d9276b339..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ResourceDto.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.shared.dto; - -import org.eclipse.che.dto.shared.DTO; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * @author Sergii Leschenko - */ -@DTO -public interface ResourceDto extends Resource { - @Override - String getType(); - - void setType(String type); - - ResourceDto withType(String type); - - @Override - long getAmount(); - - void setAmount(long amount); - - ResourceDto withAmount(long amount); - - @Override - String getUnit(); - - void setUnit(String unit); - - ResourceDto withUnit(String unit); -} diff --git a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ResourcesDetailsDto.java b/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ResourcesDetailsDto.java deleted file mode 100644 index daa0df2cd2d..00000000000 --- a/multiuser/api/che-multiuser-api-resource-shared/src/main/java/org/eclipse/che/multiuser/resource/shared/dto/ResourcesDetailsDto.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.shared.dto; - -import java.util.List; -import org.eclipse.che.dto.shared.DTO; -import org.eclipse.che.multiuser.resource.model.ResourcesDetails; - -/** - * @author Sergii Leschenko - */ -@DTO -public interface ResourcesDetailsDto extends ResourcesDetails { - @Override - String getAccountId(); - - void setAccountId(String accountId); - - ResourcesDetailsDto withAccountId(String accountId); - - @Override - List getProvidedResources(); - - void setProvidedResources(List providedResources); - - ResourcesDetailsDto withProvidedResources(List providedResources); - - @Override - List getTotalResources(); - - void setTotalResources(List totalResources); - - ResourcesDetailsDto withTotalResources(List totalResources); -} diff --git a/multiuser/api/che-multiuser-api-resource/pom.xml b/multiuser/api/che-multiuser-api-resource/pom.xml deleted file mode 100644 index 9d309e4f423..00000000000 --- a/multiuser/api/che-multiuser-api-resource/pom.xml +++ /dev/null @@ -1,197 +0,0 @@ - - - - 4.0.0 - - che-multiuser-api - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-api-resource - jar - Che Multiuser :: Resource - - ${project.build.directory}/generated-sources/dto/ - - - - com.google.code.gson - gson - - - com.google.guava - guava - - - com.google.inject - guice - - - jakarta.inject - jakarta.inject-api - - - org.eclipse.che.core - che-core-api-account - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-api-dto - - - org.eclipse.che.core - che-core-api-model - - - org.eclipse.che.core - che-core-api-workspace - - - org.eclipse.che.core - che-core-commons-annotations - - - org.eclipse.che.core - che-core-commons-lang - - - org.eclipse.che.multiuser - che-multiuser-api-permission - - - org.eclipse.che.multiuser - che-multiuser-api-resource-shared - - - org.eclipse.persistence - jakarta.persistence - - - org.slf4j - slf4j-api - - - org.eclipse.persistence - org.eclipse.persistence.core - provided - - - org.eclipse.persistence - org.eclipse.persistence.jpa - provided - - - - - - - org.eclipse.che.core - che-core-api-dto-maven-plugin - ${project.version} - - - process-sources - - generate - - - - - - org.eclipse.che.multiuser - che-multiuser-api-resource-shared - ${project.version} - - - - - org.eclipse.che.multiuser.resource.shared.dto - - ${dto-generator-out-directory} - org.eclipse.che.multiuser.resource.api.dto.DtoServerImpls - server - - - - maven-compiler-plugin - - - pre-compile - generate-sources - - compile - - - - - - org.codehaus.mojo - build-helper-maven-plugin - - - add-domain - process-sources - - add-resource - - - - - ${dto-generator-out-directory}/META-INF - META-INF - - - - - - add-source - process-sources - - add-source - - - - ${dto-generator-out-directory} - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - resource-dependencies - process-test-resources - - unpack-dependencies - - - che-core-sql-schema, - che-multiuser-sql-schema - che-schema/ - ${project.build.directory} - - - - - - - diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/AvailableResourcesProvider.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/AvailableResourcesProvider.java deleted file mode 100644 index dc075ce30a6..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/AvailableResourcesProvider.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api; - -import java.util.List; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * Provides resources which are available for usage by account. - * - *

It can be used for example for implementing resources sharing between accounts or resources - * usage limitation when limit should be less than resources provided to account. - * - * @author Sergii Leschenko - */ -public interface AvailableResourcesProvider { - /** - * Returns resources that are available for usage by account with specified id. - * - * @param accountId account identifier - * @return resources that are available for usage by account with specified id. - * @throws NotFoundException when account with specified id was not found - * @throws ServerException when some exception occurs - */ - List getAvailableResources(String accountId) - throws NotFoundException, ServerException; -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/DtoConverter.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/DtoConverter.java deleted file mode 100644 index 0f345f559e0..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/DtoConverter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api; - -import java.util.stream.Collectors; -import org.eclipse.che.dto.server.DtoFactory; -import org.eclipse.che.multiuser.resource.model.FreeResourcesLimit; -import org.eclipse.che.multiuser.resource.model.ProvidedResources; -import org.eclipse.che.multiuser.resource.model.Resource; -import org.eclipse.che.multiuser.resource.model.ResourcesDetails; -import org.eclipse.che.multiuser.resource.shared.dto.FreeResourcesLimitDto; -import org.eclipse.che.multiuser.resource.shared.dto.ProvidedResourcesDto; -import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto; -import org.eclipse.che.multiuser.resource.shared.dto.ResourcesDetailsDto; - -/** - * Helps to convert objects related to resource to DTOs. - * - * @author Sergii Leschenko - */ -public final class DtoConverter { - private DtoConverter() {} - - public static ResourceDto asDto(Resource resource) { - return DtoFactory.newDto(ResourceDto.class) - .withAmount(resource.getAmount()) - .withType(resource.getType()) - .withUnit(resource.getUnit()); - } - - public static FreeResourcesLimitDto asDto(FreeResourcesLimit limit) { - return DtoFactory.newDto(FreeResourcesLimitDto.class) - .withResources( - limit.getResources().stream().map(DtoConverter::asDto).collect(Collectors.toList())) - .withAccountId(limit.getAccountId()); - } - - public static ResourcesDetailsDto asDto(ResourcesDetails resourcesDetails) { - return DtoFactory.newDto(ResourcesDetailsDto.class) - .withAccountId(resourcesDetails.getAccountId()) - .withTotalResources( - resourcesDetails.getTotalResources().stream() - .map(DtoConverter::asDto) - .collect(Collectors.toList())) - .withProvidedResources( - resourcesDetails.getProvidedResources().stream() - .map(DtoConverter::asDto) - .collect(Collectors.toList())); - } - - private static ProvidedResourcesDto asDto(ProvidedResources providedResources) { - return DtoFactory.newDto(ProvidedResourcesDto.class) - .withId(providedResources.getId()) - .withOwner(providedResources.getOwner()) - .withStartTime(providedResources.getStartTime()) - .withEndTime(providedResources.getEndTime()) - .withProviderId(providedResources.getProviderId()) - .withResources( - providedResources.getResources().stream() - .map(DtoConverter::asDto) - .collect(Collectors.toList())); - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceAggregator.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceAggregator.java deleted file mode 100644 index 9f8eb215ea2..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceAggregator.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api; - -import static java.util.stream.Collectors.toSet; - -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException; -import org.eclipse.che.multiuser.resource.api.type.ResourceType; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * Helps aggregate resources by theirs type. - * - * @author Sergii Leschenko - */ -@Singleton -public class ResourceAggregator { - private final Map resourcesTypes; - - @Inject - public ResourceAggregator(Set resourcesTypes) { - this.resourcesTypes = - resourcesTypes.stream().collect(Collectors.toMap(ResourceType::getId, Function.identity())); - } - - /** - * Aggregates resources of the same type. - * - * @param resources resources list which can contain more that one instance for some type - * @return map where key is resources type and value is aggregated resource - * @throws IllegalArgumentException when resources list contains resource with not supported type - */ - public Map aggregateByType(List resources) { - checkSupporting(resources); - - Map type2Resource = new HashMap<>(); - for (Resource resource : resources) { - final Resource resource1 = type2Resource.get(resource.getType()); - if (resource1 != null) { - type2Resource.put(resource.getType(), aggregate(resource1, resource)); - } else { - type2Resource.put(resource.getType(), resource); - } - } - return type2Resource; - } - - /** - * Returns list which is result of deduction {@code resourceToDeduct} from {@code - * sourceResources}. - * - * @param sourceResources the source resources - * @param resourcesToDeduct the resources which should be deducted from {@code sourceResources} - * @throws NoEnoughResourcesException when {@code sourceResources} list doesn't contain enough - * resources - * @throws IllegalArgumentException when {@code sourceResources} or {@code resourcesToDeduct} - * contain resource with not supported type - */ - public List deduct( - List sourceResources, List resourcesToDeduct) - throws NoEnoughResourcesException { - checkSupporting(sourceResources); - checkSupporting(resourcesToDeduct); - - final Map result = - sourceResources.stream().collect(Collectors.toMap(Resource::getType, Function.identity())); - final List missingResources = new ArrayList<>(); - - for (Resource toDeduct : resourcesToDeduct) { - final Resource sourceResource = result.get(toDeduct.getType()); - if (sourceResource != null) { - try { - result.put(toDeduct.getType(), deduct(sourceResource, toDeduct)); - } catch (NoEnoughResourcesException e) { - result.remove(toDeduct.getType()); - missingResources.addAll(e.getMissingResources()); - } - } else { - missingResources.add(toDeduct); - } - } - - if (!missingResources.isEmpty()) { - throw new NoEnoughResourcesException(sourceResources, resourcesToDeduct, missingResources); - } - - return new ArrayList<>(result.values()); - } - - /** - * Returns list which contains resources from specified {@code sourceResources} which have - * excessive amount in compare to specified {@code resourcesToCompare}. - * - *

Example : - * - *

-   * |      \      | Source    | To compare| Result   |
-   * |:------------|:----------|:----------|:---------|
-   * | Resource1   | 5         | 3         | 2        |
-   * | ----------- | --------- | --------- | -------- |
-   * | Resource2   | -         | 9         | -        |
-   * | ----------- | --------- | --------- | -------- |
-   * | Resource3   | 1         | -         | 1        |
-   * | ----------- | --------- | --------- | -------- |
-   * 
- * - * @param sourceResources the source resources - * @param resourcesToCompare the resources which should be compared to {@code sourceResources} - * @throws IllegalArgumentException when {@code sourceResources} or {@code resourcesToCompare} - * contain resource with not supported type - */ - public List excess( - List sourceResources, List resourcesToCompare) { - checkSupporting(sourceResources); - checkSupporting(resourcesToCompare); - - final Map result = - sourceResources.stream().collect(Collectors.toMap(Resource::getType, Function.identity())); - for (Resource toCompare : resourcesToCompare) { - String resourceType = toCompare.getType(); - final Resource sourceResource = result.get(resourceType); - if (sourceResource != null) { - if (sourceResource.getAmount() == toCompare.getAmount()) { - // source resource doesn't have excessive amount - result.remove(resourceType); - continue; - } - try { - Resource excess = deduct(sourceResource, toCompare); - if (excess.getAmount() == 0) { - // source resource doesn't have excessive amount - result.remove(resourceType); - } else { - result.put(resourceType, excess); - } - } catch (NoEnoughResourcesException e) { - // source resource doesn't have excessive amount - result.remove(resourceType); - } - } - } - - return new ArrayList<>(result.values()); - } - - /** - * Aggregates two resources which have the same type. - * - * @param resourceA resources A - * @param resourceB resource B - * @return one resources with type {@code T} that is result of aggregating {@code resourceA} and - * {@code resourceB} - * @throws IllegalArgumentException when {@code T} is not supported type - */ - public Resource aggregate(Resource resourceA, Resource resourceB) { - final String typeId = resourceA.getType(); - final ResourceType resourceType = getResourceType(typeId); - return resourceType.aggregate(resourceA, resourceB); - } - - /** - * Deducts two resources which have the same type. - * - * @param totalResource total resource - * @param deduction resources which should be deducted from {@code totalResource} - * @return one resources with type {@code T} that is result of subtraction {@code totalResource} - * and {@code deduction} - * @throws NoEnoughResourcesException when {@code totalResource}'s amount is less than {@code - * deduction}'s amount - * @throws IllegalArgumentException when {@code T} is not supported type - */ - public Resource deduct(Resource totalResource, Resource deduction) - throws NoEnoughResourcesException { - final String typeId = totalResource.getType(); - final ResourceType resourceType = getResourceType(typeId); - return resourceType.deduct(totalResource, deduction); - } - - /** - * Returns resources list that contains resources with types that are contained by both input - * lists. - * - * @throws IllegalArgumentException when {@code resources} list contains resource with not - * supported type - */ - public List intersection( - List resourcesA, List resourcesB) { - checkSupporting(resourcesA); - checkSupporting(resourcesB); - - final Set keysA = resourcesA.stream().map(Resource::getType).collect(toSet()); - final Set keysB = resourcesB.stream().map(Resource::getType).collect(toSet()); - final Set commonKeys = ImmutableSet.copyOf(Sets.intersection(keysA, keysB)); - return Stream.concat(resourcesA.stream(), resourcesB.stream()) - .filter(res -> commonKeys.contains(res.getType())) - .collect(Collectors.toList()); - } - - /** - * Returns list that contains one resource with minimum amount for each resource type. - * - * @throws IllegalArgumentException when {@code resources} list contains resource with not - * supported type - */ - public List min(Collection resources) { - checkSupporting(resources); - Map result = new HashMap<>(); - for (Resource resource : resources) { - String type = resource.getType(); - Resource min = result.get(type); - if (min == null) { - result.put(type, resource); - } else if (resource.getAmount() != -1) { - if (min.getAmount() == -1 || min.getAmount() > resource.getAmount()) { - result.put(type, resource); - } - } - } - return new ArrayList<>(result.values()); - } - - /** - * Check supporting of all given resources. - * - * @param resources resources to check types - * @throws IllegalArgumentException when {@code resources} list contains resource with not - * supported type - */ - private void checkSupporting(Collection resources) { - final Set resourcesTypes = - resources.stream().map(Resource::getType).collect(Collectors.toSet()); - for (String resourcesType : resourcesTypes) { - if (!this.resourcesTypes.containsKey(resourcesType)) { - throw new IllegalArgumentException( - String.format("'%s' resource type is not supported", resourcesType)); - } - } - } - - /** - * Returns resources type by given id. - * - * @param typeId id of resources type - * @return resources type by given id - * @throws IllegalArgumentException when type by given id is not supported type - */ - private ResourceType getResourceType(String typeId) { - final ResourceType resourceType = resourcesTypes.get(typeId); - if (resourceType == null) { - throw new IllegalArgumentException( - String.format("'%s' resource type is not supported", typeId)); - } - return resourceType; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceLockKeyProvider.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceLockKeyProvider.java deleted file mode 100644 index 09de29423d0..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceLockKeyProvider.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api; - -import org.eclipse.che.api.core.ServerException; - -/** - * Returns key for fetching lock which will be used for locking resources during resources - * operations for account with some type. - * - * @author Sergii Leschenko - */ -public interface ResourceLockKeyProvider { - /** - * Returns lock key by which resources should be lock during resources operations - * - * @param accountId account id - * @return lock key by which resources should be lock during resources operations - * @throws ServerException when any other exception occurs - */ - String getLockKey(String accountId) throws ServerException; - - /** Returns account type for which this class provides locks' ids */ - String getAccountType(); -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceModule.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceModule.java deleted file mode 100644 index 810322ea6fd..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceModule.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2012-2026 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.resource.api; - -import com.google.inject.AbstractModule; -import com.google.inject.multibindings.MapBinder; -import com.google.inject.multibindings.Multibinder; -import org.eclipse.che.multiuser.api.permission.server.account.AccountPermissionsChecker; -import org.eclipse.che.multiuser.resource.api.free.DefaultResourcesProvider; -import org.eclipse.che.multiuser.resource.api.free.FreeResourcesProvider; -import org.eclipse.che.multiuser.resource.api.type.RamResourceType; -import org.eclipse.che.multiuser.resource.api.type.ResourceType; -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; - -/** - * @author Sergii Leschenko - */ -public class ResourceModule extends AbstractModule { - @Override - protected void configure() { - MapBinder.newMapBinder(binder(), String.class, AvailableResourcesProvider.class); - Multibinder.newSetBinder(binder(), DefaultResourcesProvider.class); - Multibinder.newSetBinder(binder(), ResourceLockKeyProvider.class); - Multibinder.newSetBinder(binder(), AccountPermissionsChecker.class); - - Multibinder.newSetBinder(binder(), ResourcesProvider.class) - .addBinding() - .to(FreeResourcesProvider.class); - - MapBinder.newMapBinder(binder(), String.class, AvailableResourcesProvider.class); - - Multibinder resourcesTypesBinder = - Multibinder.newSetBinder(binder(), ResourceType.class); - resourcesTypesBinder.addBinding().to(RamResourceType.class); - resourcesTypesBinder.addBinding().to(WorkspaceResourceType.class); - resourcesTypesBinder.addBinding().to(RuntimeResourceType.class); - resourcesTypesBinder.addBinding().to(TimeoutResourceType.class); - - Multibinder usageTrackersBinder = - Multibinder.newSetBinder(binder(), ResourceUsageTracker.class); - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceUsageTracker.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceUsageTracker.java deleted file mode 100644 index 9c883d5f5a7..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourceUsageTracker.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api; - -import java.util.Optional; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * Tracks usage of resources of specified type. - * - * @author Sergii Leschenko - */ -public interface ResourceUsageTracker { - /** - * Returns used resource by given account. - * - * @param accountId account id to fetch used resource - * @return used resource by given account - * @throws NotFoundException when account with specified id was not found - * @throws ServerException when some exception occurs on used resources fetching - */ - Optional getUsedResource(String accountId) throws NotFoundException, ServerException; -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourcesProvider.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourcesProvider.java deleted file mode 100644 index 232e0e55798..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/ResourcesProvider.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api; - -import java.util.List; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.multiuser.resource.model.ProvidedResources; - -/** - * Bridge class that link resources details and resources granting mechanisms. - * - * @author Sergii Leschenko - */ -public interface ResourcesProvider { - /** - * Returns list of provided resources for given account. - * - * @param accountId account id - * @return list of provided resources for given account or empty list if there are not any - * resources for given account - * @throws NotFoundException when account with specified id was not found - * @throws ServerException when some exception occurs - */ - List getResources(String accountId) throws ServerException, NotFoundException; -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/exception/NoEnoughResourcesException.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/exception/NoEnoughResourcesException.java deleted file mode 100644 index 0e8664a9d49..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/exception/NoEnoughResourcesException.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.exception; - -import static java.util.Collections.singletonList; - -import java.util.List; -import java.util.stream.Collectors; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * Thrown in case when account doesn't have enough resources to perform some operation. - * - *

It contains detailed information about resources so required, available, missing amounts to - * provide ability to construct user friendly message. - * - * @author Sergii Leschenko - */ -public class NoEnoughResourcesException extends Exception { - private static final String MESSAGE = - "Account has %s resources to use, but operation requires %s. It requires more %s."; - - private String message; - private List availableResources; - private List requiredResources; - private List missedResources; - - public NoEnoughResourcesException( - Resource availableResource, Resource requiredResource, Resource missedResource) { - this( - singletonList(availableResource), - singletonList(requiredResource), - singletonList(missedResource)); - } - - public NoEnoughResourcesException( - List availableResources, - List requiredResources, - List missedResources) { - this.availableResources = availableResources; - this.requiredResources = requiredResources; - this.missedResources = missedResources; - } - - @Override - public String getMessage() { - if (message == null) { - message = - String.format( - MESSAGE, - resourcesToString(availableResources), - resourcesToString(requiredResources), - resourcesToString(missedResources)); - } - return message; - } - - public List getRequiredResources() { - return requiredResources; - } - - public List getAvailableResources() { - return availableResources; - } - - public List getMissingResources() { - return missedResources; - } - - private String resourcesToString(List resources) { - return '[' - + resources.stream() - .map(resource -> resource.getAmount() + resource.getUnit() + " " + resource.getType()) - .collect(Collectors.joining(", ")) - + ']'; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/DefaultResourcesProvider.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/DefaultResourcesProvider.java deleted file mode 100644 index eca6a86bf51..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/DefaultResourcesProvider.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.free; - -import java.util.List; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl; - -/** - * Provides default resources which should be are available for usage by account when admin doesn't - * override limit by {@link FreeResourcesLimitService}. - * - * @author Sergii Leschenko - */ -public interface DefaultResourcesProvider { - /** Provides default resources are available for usage by account */ - List getResources(String accountId) throws ServerException, NotFoundException; - - /** Returns account type for which this class provides default resources. */ - String getAccountType(); -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesLimitManager.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesLimitManager.java deleted file mode 100644 index bb669c42cc9..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesLimitManager.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.free; - -import static java.util.Objects.requireNonNull; - -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.multiuser.resource.model.FreeResourcesLimit; -import org.eclipse.che.multiuser.resource.spi.FreeResourcesLimitDao; -import org.eclipse.che.multiuser.resource.spi.impl.FreeResourcesLimitImpl; - -/** - * Facade for free resources limit related operations. - * - * @author Sergii Leschenko - */ -// TODO Add checking resources availability before limit changing and removing -@Singleton -public class FreeResourcesLimitManager { - private final FreeResourcesLimitDao freeResourcesLimitDao; - - @Inject - public FreeResourcesLimitManager(FreeResourcesLimitDao freeResourcesLimitDao) { - this.freeResourcesLimitDao = freeResourcesLimitDao; - } - - /** - * Stores (creates new one or updates existed) free resource limit. - * - * @param freeResourcesLimit resources limit to store - * @return stored resources limit - * @throws NullPointerException when {@code freeResourcesLimit} is null - * @throws NotFoundException when resources limit contains resource with non supported type - * @throws ConflictException when the specified account doesn't exist - * @throws ServerException when any other error occurs - */ - public FreeResourcesLimit store(FreeResourcesLimit freeResourcesLimit) - throws NotFoundException, ConflictException, ServerException { - requireNonNull(freeResourcesLimit, "Required non-null free resources limit"); - final FreeResourcesLimitImpl toStore = new FreeResourcesLimitImpl(freeResourcesLimit); - freeResourcesLimitDao.store(toStore); - return toStore; - } - - /** - * Returns free resources limit for account with specified id. - * - * @param accountId account id to fetch resources limit - * @return free resources limit for account with specified id - * @throws NullPointerException when {@code accountId} is null - * @throws NotFoundException when free resources limit for specifies id was not found - * @throws ServerException when any other error occurs - */ - public FreeResourcesLimit get(String accountId) throws NotFoundException, ServerException { - requireNonNull(accountId, "Required non-null account id"); - return freeResourcesLimitDao.get(accountId); - } - - /** - * Removes free resources limit for account with specified id. - * - *

After removing resources limit account will be able to use default resources - * - *

Doesn't throw an exception when resources limit for specified {@code accountId} does not - * exist - * - * @param accountId account id to remove resources limit - * @throws NullPointerException when {@code accountId} is null - * @throws ServerException when any other error occurs - */ - public void remove(String accountId) throws ServerException { - requireNonNull(accountId, "Required non-null account id"); - freeResourcesLimitDao.remove(accountId); - } - - /** - * Gets all free resources limits. - * - * @param maxItems the maximum number of limits to return - * @param skipCount the number of limits to skip - * @return list of limits POJO or empty list if no limits were found - * @throws ServerException when any other error occurs - */ - public Page getAll(int maxItems, int skipCount) - throws ServerException { - return freeResourcesLimitDao.getAll(maxItems, skipCount); - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesLimitValidator.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesLimitValidator.java deleted file mode 100644 index 31bf222ff99..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesLimitValidator.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.free; - -import static java.lang.String.format; - -import java.util.HashSet; -import java.util.Set; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.BadRequestException; -import org.eclipse.che.multiuser.resource.model.FreeResourcesLimit; -import org.eclipse.che.multiuser.resource.shared.dto.FreeResourcesLimitDto; -import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto; - -/** - * Utils for validation of {@link FreeResourcesLimit} - * - * @author Sergii Leschenko - */ -@Singleton -public class FreeResourcesLimitValidator { - private final ResourceValidator resourceValidator; - - @Inject - public FreeResourcesLimitValidator(ResourceValidator resourceValidator) { - this.resourceValidator = resourceValidator; - } - - /** - * Validates given {@code freeResourcesLimit} - * - * @param freeResourcesLimit resources limit to validate - * @throws BadRequestException when {@code freeResourcesLimit} is null - * @throws BadRequestException when any of {@code freeResourcesLimit.getResources} is not valid - * @see ResourceValidator#validate(ResourceDto) - */ - public void check(FreeResourcesLimitDto freeResourcesLimit) throws BadRequestException { - if (freeResourcesLimit == null) { - throw new BadRequestException("Missed free resources limit description."); - } - if (freeResourcesLimit.getAccountId() == null) { - throw new BadRequestException("Missed account id."); - } - - Set resourcesToSet = new HashSet<>(); - for (ResourceDto resource : freeResourcesLimit.getResources()) { - if (!resourcesToSet.add(resource.getType())) { - throw new BadRequestException( - format( - "Free resources limit should contain only one resources with type '%s'.", - resource.getType())); - } - resourceValidator.validate(resource); - } - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesProvider.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesProvider.java deleted file mode 100644 index 74326447e08..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/FreeResourcesProvider.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.free; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toMap; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import javax.inject.Inject; -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.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.multiuser.resource.api.ResourcesProvider; -import org.eclipse.che.multiuser.resource.model.FreeResourcesLimit; -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 free resources for account usage. - * - *

Returns free resources limits if it is specified for given account or default free resources - * limit in other case - * - *

Default resources should be provided by {@link DefaultResourcesProvider} for different account - * types - * - * @author Sergii Leschenko - */ -@Singleton -public class FreeResourcesProvider implements ResourcesProvider { - public static final String FREE_RESOURCES_PROVIDER = "free"; - - private final FreeResourcesLimitManager freeResourcesLimitManager; - private final AccountManager accountManager; - private final Map defaultResourcesProviders; - - @Inject - public FreeResourcesProvider( - FreeResourcesLimitManager freeResourcesLimitManager, - AccountManager accountManager, - Set defaultResourcesProviders) { - this.freeResourcesLimitManager = freeResourcesLimitManager; - this.accountManager = accountManager; - this.defaultResourcesProviders = - defaultResourcesProviders.stream() - .collect(toMap(DefaultResourcesProvider::getAccountType, Function.identity())); - } - - @Override - public List getResources(String accountId) - throws ServerException, NotFoundException { - Map freeResources = new HashMap<>(); - String limitId = null; - try { - FreeResourcesLimit resourcesLimit = freeResourcesLimitManager.get(accountId); - for (Resource resource : resourcesLimit.getResources()) { - freeResources.put(resource.getType(), new ResourceImpl(resource)); - } - limitId = resourcesLimit.getAccountId(); - } catch (NotFoundException ignored) { - // there is no resources limit for given account - } - - // add default resources which are not specified by limit - for (ResourceImpl resource : getDefaultResources(accountId)) { - freeResources.putIfAbsent(resource.getType(), resource); - } - - if (!freeResources.isEmpty()) { - return singletonList( - new ProvidedResourcesImpl( - FREE_RESOURCES_PROVIDER, limitId, accountId, -1L, -1L, freeResources.values())); - } else { - return emptyList(); - } - } - - private List getDefaultResources(String accountId) - throws NotFoundException, ServerException { - List defaultResources = new ArrayList<>(); - final Account account = accountManager.getById(accountId); - - final DefaultResourcesProvider defaultResourcesProvider = - defaultResourcesProviders.get(account.getType()); - if (defaultResourcesProvider != null) { - defaultResources.addAll(defaultResourcesProvider.getResources(accountId)); - } - - return defaultResources; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/ResourceValidator.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/ResourceValidator.java deleted file mode 100644 index 05dd3b0d491..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/free/ResourceValidator.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.free; - -import static java.util.stream.Collectors.toMap; - -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.BadRequestException; -import org.eclipse.che.multiuser.resource.api.type.ResourceType; -import org.eclipse.che.multiuser.resource.model.Resource; -import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto; - -/** - * Utils for validation of {@link Resource}. - * - * @author Sergii Leschenko - */ -@Singleton -public class ResourceValidator { - private final Map> resourcesTypesToUnits; - private final Map resourcesTypesToDefaultUnit; - - @Inject - public ResourceValidator(Set supportedResources) { - this.resourcesTypesToUnits = - supportedResources.stream() - .collect(toMap(ResourceType::getId, ResourceType::getSupportedUnits)); - this.resourcesTypesToDefaultUnit = - supportedResources.stream() - .collect(toMap(ResourceType::getId, ResourceType::getDefaultUnit)); - } - - /** - * Validates given {@code resource} - * - *

{@link ResourceDto#getUnit()} can be null then {@link ResourceType#getDefaultUnit() default - * unit} of {@link ResourceDto#getType() specified type} will be set. - * - * @param resource resource to validate - * @throws BadRequestException when {@code resource} is null - * @throws BadRequestException when {@code resource} has non supported type - * @throws BadRequestException when {@code resource} has non supported unit - */ - public void validate(ResourceDto resource) throws BadRequestException { - if (resource == null) { - throw new BadRequestException("Missed resource"); - } - - final Set units = resourcesTypesToUnits.get(resource.getType()); - - if (units == null) { - throw new BadRequestException( - "Specified resources type '" + resource.getType() + "' is not supported"); - } - - if (resource.getUnit() == null) { - resource.setUnit(resourcesTypesToDefaultUnit.get(resource.getType())); - } else { - if (!units.contains(resource.getUnit())) { - throw new BadRequestException( - "Specified resources type '" - + resource.getType() - + "' support only following units: " - + units.stream().collect(Collectors.joining(", "))); - } - } - - if (resource.getAmount() < -1) { - throw new BadRequestException( - "Resources with type '" + resource.getType() + "' has negative amount"); - } - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/AbstractExhaustibleResource.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/AbstractExhaustibleResource.java deleted file mode 100644 index 31372025e09..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/AbstractExhaustibleResource.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.type; - -import static com.google.common.base.Preconditions.checkArgument; - -import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException; -import org.eclipse.che.multiuser.resource.model.Resource; -import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl; - -/** - * Abstract resource that contains logic for aggregating and deduction for exhaustible resources. - * - * @author Sergii Leschenko - */ -public abstract class AbstractExhaustibleResource implements ResourceType { - @Override - public Resource aggregate(Resource resourceA, Resource resourceB) { - checkResource(resourceA); - checkResource(resourceB); - - if (resourceA.getAmount() == -1 || resourceB.getAmount() == -1) { - return new ResourceImpl(getId(), -1, getDefaultUnit()); - } - - return new ResourceImpl( - getId(), resourceA.getAmount() + resourceB.getAmount(), getDefaultUnit()); - } - - @Override - public Resource deduct(Resource total, Resource deduction) throws NoEnoughResourcesException { - checkResource(total); - checkResource(deduction); - - if (total.getAmount() == -1) { - return total; - } - - if (deduction.getAmount() == -1) { - throw new NoEnoughResourcesException(total, deduction, deduction); - } - - final long resultAmount = total.getAmount() - deduction.getAmount(); - if (resultAmount < 0) { - throw new NoEnoughResourcesException( - total, deduction, new ResourceImpl(getId(), -resultAmount, getDefaultUnit())); - } - return new ResourceImpl(getId(), resultAmount, getDefaultUnit()); - } - - /** - * Checks that given resources can be processed by this resource type - * - * @param resource resource to check - * @throws IllegalArgumentException if given resources has unsupported type or unit - */ - private void checkResource(Resource resource) { - checkArgument( - getId().equals(resource.getType()), "Resource should have '" + getId() + "' type"); - checkArgument( - getSupportedUnits().contains(resource.getUnit()), - "Resource has unsupported unit '" + resource.getUnit() + "'"); - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/RamResourceType.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/RamResourceType.java deleted file mode 100644 index 0648b129360..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/RamResourceType.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.type; - -import com.google.common.collect.ImmutableSet; -import java.util.Set; - -/** - * Describes resource type that control number of RAM which can be used by running workspaces at the - * same time. - * - * @author Sergii Leschenko - */ -public class RamResourceType extends AbstractExhaustibleResource { - public static final String ID = "RAM"; - public static final String UNIT = "mb"; - - private static final Set SUPPORTED_UNITS = ImmutableSet.of(UNIT); - - @Override - public String getId() { - return ID; - } - - @Override - public String getDescription() { - return "Number of RAM which can be used by running workspaces at the same time"; - } - - @Override - public Set getSupportedUnits() { - return SUPPORTED_UNITS; - } - - @Override - public String getDefaultUnit() { - return UNIT; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/ResourceType.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/ResourceType.java deleted file mode 100644 index 049a514fb81..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/ResourceType.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.type; - -import java.util.Set; -import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * Represents some kind of resources which can be used by account. - * - * @author Sergii Leschenko - */ -public interface ResourceType { - /** Returns id of resource type. */ - String getId(); - - /** Returns description of resource type. */ - String getDescription(); - - /** Returns supported units. */ - Set getSupportedUnits(); - - /** Returns default unit. */ - String getDefaultUnit(); - - /** - * Defines function for aggregating two resources of this type. - * - * @param resourceA resources A - * @param resourceB resource B - * @throws IllegalArgumentException if one of resources has unsupported type or unit - */ - Resource aggregate(Resource resourceA, Resource resourceB); - - /** - * Defines function for subtraction two resources of this type. - * - * @param total total resource - * @param deduction resource that should be deducted from {@code total} - * @throws IllegalArgumentException if one of resources has unsupported type or unit - * @throws NoEnoughResourcesException when {@code total}'s amount is less than {@code deduction}'s - * amount - */ - Resource deduct(Resource total, Resource deduction) throws NoEnoughResourcesException; -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/RuntimeResourceType.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/RuntimeResourceType.java deleted file mode 100644 index 1f96501f887..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/RuntimeResourceType.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.type; - -import com.google.common.collect.ImmutableSet; -import java.util.Set; - -/** - * Describes resource type that control number of workspaces which user can run at the same time. - * - * @author Sergii Leshchenko - */ -public class RuntimeResourceType extends AbstractExhaustibleResource { - public static final String ID = "runtime"; - public static final String UNIT = "item"; - - private static final Set SUPPORTED_UNITS = ImmutableSet.of(UNIT); - - @Override - public String getId() { - return ID; - } - - @Override - public String getDescription() { - return "Number of workspaces which user can run at the same time"; - } - - @Override - public Set getSupportedUnits() { - return SUPPORTED_UNITS; - } - - @Override - public String getDefaultUnit() { - return UNIT; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/TimeoutResourceType.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/TimeoutResourceType.java deleted file mode 100644 index 140148c4298..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/TimeoutResourceType.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.type; - -import com.google.common.collect.ImmutableSet; -import java.util.Set; -import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * Describes resource type that control the length of time that a user is idle with their workspace - * when the system will suspend the workspace by snapshotting it and then stopping it. - * - * @author Sergii Leschenko - */ -public class TimeoutResourceType implements ResourceType { - public static final String ID = "timeout"; - public static final String UNIT = "minute"; - - private static final Set SUPPORTED_UNITS = ImmutableSet.of(UNIT); - - @Override - public String getId() { - return ID; - } - - @Override - public String getDescription() { - return "Timeout"; - } - - @Override - public Set getSupportedUnits() { - return SUPPORTED_UNITS; - } - - @Override - public String getDefaultUnit() { - return UNIT; - } - - @Override - public Resource aggregate(Resource resourceA, Resource resourceB) { - return resourceA.getAmount() > resourceB.getAmount() ? resourceA : resourceB; - } - - @Override - public Resource deduct(Resource total, Resource deduction) throws NoEnoughResourcesException { - return total; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/WorkspaceResourceType.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/WorkspaceResourceType.java deleted file mode 100644 index 818919a01d9..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/type/WorkspaceResourceType.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.type; - -import com.google.common.collect.ImmutableSet; -import java.util.Set; - -/** - * Describes resource type that control number of workspaces which user can have at the same time. - * - * @author Sergii Leshchenko - */ -public class WorkspaceResourceType extends AbstractExhaustibleResource { - public static final String ID = "workspace"; - public static final String UNIT = "item"; - - private static final Set SUPPORTED_UNITS = ImmutableSet.of(UNIT); - - @Override - public String getId() { - return ID; - } - - @Override - public String getDescription() { - return "Number of workspaces which user can have at the same time"; - } - - @Override - public Set getSupportedUnits() { - return SUPPORTED_UNITS; - } - - @Override - public String getDefaultUnit() { - return UNIT; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/DefaultAvailableResourcesProvider.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/DefaultAvailableResourcesProvider.java deleted file mode 100644 index 809b319e9be..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/DefaultAvailableResourcesProvider.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.usage; - -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.ServerException; -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.model.Resource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Default implementation of providing available resources for accounts. - * - *

By default account can use resources only by itself, so available resources equals to total - * resources minus resources which are already used by account. - * - * @author Sergii Leschenko - */ -@Singleton -public class DefaultAvailableResourcesProvider implements AvailableResourcesProvider { - private static final Logger LOG = - LoggerFactory.getLogger(DefaultAvailableResourcesProvider.class); - - private final Provider resourceManagerProvider; - private final ResourceAggregator resourceAggregator; - - @Inject - public DefaultAvailableResourcesProvider( - Provider resourceManagerProvider, ResourceAggregator resourceAggregator) { - this.resourceManagerProvider = resourceManagerProvider; - this.resourceAggregator = resourceAggregator; - } - - @Override - public List getAvailableResources(String accountId) - throws NotFoundException, ServerException { - ResourceManager resourceManager = resourceManagerProvider.get(); - List totalResources = null; - List usedResources = null; - try { - totalResources = resourceManager.getTotalResources(accountId); - usedResources = new ArrayList<>(resourceManager.getUsedResources(accountId)); - return resourceAggregator.deduct(totalResources, usedResources); - } catch (NoEnoughResourcesException e) { - LOG.warn( - "Account with id {} uses more resources {} than he has {}.", - accountId, - format(usedResources), - format(totalResources)); - return resourceAggregator.excess(totalResources, usedResources); - } - } - - /** Returns formatted string for list of resources. */ - private static String format(Collection resources) { - return '[' - + resources.stream() - .map( - resource -> resource.getAmount() + resource.getUnit() + " of " + resource.getType()) - .collect(Collectors.joining(", ")) - + ']'; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/ResourceManager.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/ResourceManager.java deleted file mode 100644 index efc75cd7f0f..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/ResourceManager.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.usage; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import javax.inject.Inject; -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.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.multiuser.resource.api.AvailableResourcesProvider; -import org.eclipse.che.multiuser.resource.api.ResourceAggregator; -import org.eclipse.che.multiuser.resource.api.ResourceUsageTracker; -import org.eclipse.che.multiuser.resource.api.ResourcesProvider; -import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException; -import org.eclipse.che.multiuser.resource.model.ProvidedResources; -import org.eclipse.che.multiuser.resource.model.Resource; -import org.eclipse.che.multiuser.resource.model.ResourcesDetails; -import org.eclipse.che.multiuser.resource.spi.impl.ResourcesDetailsImpl; - -/** - * Facade for resources related operations. - * - * @author Sergii Leschenko - */ -@Singleton -public class ResourceManager { - private final ResourceAggregator resourceAggregator; - private final Set resourcesProviders; - private final Set usageTrackers; - private final AccountManager accountManager; - private final Map accountTypeToAvailableResourcesProvider; - private final DefaultAvailableResourcesProvider defaultAvailableResourcesProvider; - - @Inject - public ResourceManager( - ResourceAggregator resourceAggregator, - Set resourcesProviders, - Set usageTrackers, - AccountManager accountManager, - Map accountTypeToAvailableResourcesProvider, - DefaultAvailableResourcesProvider defaultAvailableResourcesProvider) { - this.resourceAggregator = resourceAggregator; - this.resourcesProviders = resourcesProviders; - this.usageTrackers = usageTrackers; - this.accountManager = accountManager; - this.accountTypeToAvailableResourcesProvider = accountTypeToAvailableResourcesProvider; - this.defaultAvailableResourcesProvider = defaultAvailableResourcesProvider; - } - - /** - * Returns list of resources which are available for usage by given account. - * - * @param accountId id of account - * @return list of resources which are available for usage by given account - * @throws NotFoundException when account with specified id was not found - * @throws ServerException when some exception occurred while resources fetching - */ - public List getTotalResources(String accountId) - throws NotFoundException, ServerException { - return getResourceDetails(accountId).getTotalResources(); - } - - /** - * Returns list of resources which are available for usage by given account. - * - * @param accountId id of account - * @return list of resources which are available for usage by given account - * @throws NotFoundException when account with specified id was not found - * @throws ServerException when some exception occurred while resources fetching - */ - public List getAvailableResources(String accountId) - throws NotFoundException, ServerException { - final Account account = accountManager.getById(accountId); - final AvailableResourcesProvider availableResourcesProvider = - accountTypeToAvailableResourcesProvider.get(account.getType()); - - if (availableResourcesProvider == null) { - return defaultAvailableResourcesProvider.getAvailableResources(accountId); - } - - return availableResourcesProvider.getAvailableResources(accountId); - } - - /** - * Returns list of resources which are used by given account. - * - * @param accountId id of account - * @return list of resources which are used by given account - * @throws NotFoundException when account with specified id was not found - * @throws ServerException when some exception occurred while resources fetching - */ - public List getUsedResources(String accountId) - throws NotFoundException, ServerException { - List usedResources = new ArrayList<>(); - for (ResourceUsageTracker usageTracker : usageTrackers) { - Optional usedResource = usageTracker.getUsedResource(accountId); - usedResource.ifPresent(usedResources::add); - } - return usedResources; - } - - /** - * Checks that specified account has available resources to use - * - * @param accountId account id - * @param resources resources to check availability - * @throws NotFoundException when account with specified id was not found - * @throws NoEnoughResourcesException when account doesn't have specified available resources - * @throws ServerException when any other error occurs - */ - public void checkResourcesAvailability(String accountId, List resources) - throws NotFoundException, NoEnoughResourcesException, ServerException { - List availableResources = getAvailableResources(accountId); - // check resources availability - resourceAggregator.deduct(availableResources, resources); - } - - /** - * Returns detailed information about resources which given account can use. - * - * @param accountId account id - * @return detailed information about resources which can be used by given account - * @throws NotFoundException when account with specified id was not found - * @throws ServerException when some exception occurs - */ - public ResourcesDetails getResourceDetails(String accountId) - throws NotFoundException, ServerException { - final List resources = new ArrayList<>(); - for (ResourcesProvider resourcesProvider : resourcesProviders) { - resources.addAll(resourcesProvider.getResources(accountId)); - } - - final List allResources = - resources.stream() - .flatMap(providedResources -> providedResources.getResources().stream()) - .collect(Collectors.toList()); - - return new ResourcesDetailsImpl( - accountId, - resources, - new ArrayList<>(resourceAggregator.aggregateByType(allResources).values())); - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/ResourcesLocks.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/ResourcesLocks.java deleted file mode 100644 index be224279eee..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/ResourcesLocks.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.usage; - -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import javax.inject.Inject; -import org.eclipse.che.account.api.AccountManager; -import org.eclipse.che.account.shared.model.Account; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.commons.lang.concurrent.StripedLocks; -import org.eclipse.che.commons.lang.concurrent.Unlocker; -import org.eclipse.che.multiuser.resource.api.ResourceLockKeyProvider; - -/** - * Helps to lock resources while performing operations related to them. - * - *

Resources will be locked not by account id but by key which will be provided by {@link - * ResourceLockKeyProvider} for specified account's type - * - *

It based on {@link StripedLocks} so it can be used in try-with-resources construction. - * - *

- * try (Unlocker u = resourceLocks.lock("account123")) {
- *    // check resources availability and perform operation here
- * }
- * 
- * - * @author Sergii Leschenko - */ -public class ResourcesLocks { - - private final AccountManager accountManager; - private final Map accountTypeToLockProvider; - private final StripedLocks stripedLocks; - - @Inject - public ResourcesLocks( - Set resourceLockKeyProviders, AccountManager accountManager) { - this.accountManager = accountManager; - this.stripedLocks = new StripedLocks(16); - this.accountTypeToLockProvider = - resourceLockKeyProviders.stream() - .collect( - Collectors.toMap(ResourceLockKeyProvider::getAccountType, Function.identity())); - } - - /** - * Acquire resources lock for specified account. - * - * @param accountId account id to lock resources - * @return lock for unlocking resources when resources operation finishes - * @throws NotFoundException when account with specified {@code account id} was not found - * @throws ServerException when any other error occurs - */ - public Unlocker lock(String accountId) throws NotFoundException, ServerException { - final Account account = accountManager.getById(accountId); - final ResourceLockKeyProvider resourceLockKeyProvider = - accountTypeToLockProvider.get(account.getType()); - String lockKey; - if (resourceLockKeyProvider == null) { - // this account type doesn't have custom lock provider. - // Lock resources by current account - lockKey = accountId; - } else { - lockKey = resourceLockKeyProvider.getLockKey(accountId); - } - - return stripedLocks.writeLock(lockKey); - } - - public Unlocker lock(String... accountIds) throws NotFoundException, ServerException { - // TODO It should be implemented for making possible lock resources by two or more accounts in - // case of resources redistribution - throw new UnsupportedOperationException("Not implemented."); - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/EnvironmentRamCalculator.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/EnvironmentRamCalculator.java deleted file mode 100644 index c4244bb5c1b..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/EnvironmentRamCalculator.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.api.usage.tracker; - -import static java.lang.String.format; -import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; - -import java.util.Map; -import javax.inject.Inject; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.ValidationException; -import org.eclipse.che.api.core.model.workspace.Runtime; -import org.eclipse.che.api.core.model.workspace.config.Environment; -import org.eclipse.che.api.core.model.workspace.config.MachineConfig; -import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; -import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironmentFactory; -import org.eclipse.che.commons.annotation.Nullable; - -/** - * Helps to calculate amount of RAM defined in {@link Environment environment} - * - * @author Sergii Leschenko - * @author Anton Korneta - */ -public class EnvironmentRamCalculator { - private static final long BYTES_TO_MEGABYTES_DIVIDER = 1024L * 1024L; - - private final Map environmentFactories; - - @Inject - public EnvironmentRamCalculator(Map environmentFactories) { - this.environmentFactories = environmentFactories; - } - - /** - * Parses (and fetches if needed) recipe of environment and sums RAM size of all machines in - * environment in megabytes. - */ - public long calculate(@Nullable Environment environment) throws ServerException { - if (environment == null) { - return 0; - } - try { - return getInternalEnvironment(environment).getMachines().values().stream() - .mapToLong( - m -> parseMemoryAttributeValue(m.getAttributes().get(MEMORY_LIMIT_ATTRIBUTE))) - .sum() - / BYTES_TO_MEGABYTES_DIVIDER; - } catch (InfrastructureException | ValidationException | NotFoundException ex) { - throw new ServerException(ex.getMessage(), ex); - } - } - - /** - * Calculates summary RAM of given {@link Runtime}. - * - * @return summary RAM of all machines in runtime in megabytes - */ - public long calculate(Runtime runtime) { - return runtime.getMachines().values().stream() - .mapToLong( - m -> parseMemoryAttributeValue(m.getAttributes().get(MEMORY_LIMIT_ATTRIBUTE))) - .sum() - / BYTES_TO_MEGABYTES_DIVIDER; - } - - /** - * Parse {@link MachineConfig#MEMORY_LIMIT_ATTRIBUTE} value to {@code Long}. - * - * @param attributeValue value of {@link MachineConfig#MEMORY_LIMIT_ATTRIBUTE} attribute from - * machine config or runtime - * @return long value parsed from provided string attribute value or {@code 0} if {@code null} is - * provided - * @throws NumberFormatException if provided value is neither {@code null} nor valid stringified - * long - * @see Long#parseLong(String) - */ - private long parseMemoryAttributeValue(String attributeValue) { - if (attributeValue == null) { - return 0; - } else { - return Long.parseLong(attributeValue); - } - } - - private InternalEnvironment getInternalEnvironment(Environment environment) - throws InfrastructureException, ValidationException, NotFoundException { - final String recipeType = environment.getRecipe().getType(); - final InternalEnvironmentFactory factory = environmentFactories.get(recipeType); - if (factory == null) { - throw new NotFoundException( - format("InternalEnvironmentFactory is not configured for recipe type: '%s'", recipeType)); - } - return factory.create(environment); - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/FreeResourcesLimitDao.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/FreeResourcesLimitDao.java deleted file mode 100644 index 4acd7107fb9..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/FreeResourcesLimitDao.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.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.resource.spi.impl.FreeResourcesLimitImpl; - -/** - * Defines data access object contract for {@link FreeResourcesLimitImpl}. - * - * @author Sergii Leschenko - */ -public interface FreeResourcesLimitDao { - /** - * Stores (creates new one or updates existed) free resource limit. - * - * @param resourcesLimit resources limit to store - * @throws NullPointerException when {@code resourcesLimit} is null - * @throws ConflictException when the specified account doesn't exist - * @throws ServerException when any other error occurs - */ - void store(FreeResourcesLimitImpl resourcesLimit) throws ConflictException, ServerException; - - /** - * Returns free resources limit for account with specified id. - * - * @param accountId account id to fetch resources limit - * @return free resources limit for account with specified id - * @throws NullPointerException when {@code accountId} is null - * @throws NotFoundException when free resources limit for specifies id was not found - * @throws ServerException when any other error occurs - */ - FreeResourcesLimitImpl get(String accountId) throws NotFoundException, ServerException; - - /** - * Gets all free resources limits. - * - * @param maxItems the maximum number of limits to return - * @param skipCount the number of limits to skip - * @return list of limits POJO or empty list if no limits were found - * @throws ServerException when any other error occurs - */ - Page getAll(int maxItems, int skipCount) throws ServerException; - - /** - * Removes free resources limit for account with specified id. - * - *

Doesn't throw an exception when resources limit for specified {@code accountId} does not - * exist - * - * @param accountId account id to remove resources limit - * @throws NullPointerException when {@code accountId} is null - * @throws ServerException when any other error occurs - */ - void remove(String accountId) throws ServerException; -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/FreeResourcesLimitImpl.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/FreeResourcesLimitImpl.java deleted file mode 100644 index 7e70efffdc3..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/FreeResourcesLimitImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.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.account.spi.AccountImpl; -import org.eclipse.che.multiuser.resource.model.FreeResourcesLimit; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * Data object for {@link FreeResourcesLimit}. - * - * @author Sergii Leschenko - */ -@Entity(name = "FreeResourcesLimit") -@NamedQueries({ - @NamedQuery( - name = "FreeResourcesLimit.get", - query = "SELECT limit FROM FreeResourcesLimit limit WHERE limit.accountId= :accountId"), - @NamedQuery( - name = "FreeResourcesLimit.getAll", - query = "SELECT limit FROM FreeResourcesLimit limit"), - @NamedQuery( - name = "FreeResourcesLimit.getTotalCount", - query = "SELECT COUNT(limit) FROM FreeResourcesLimit limit") -}) -@Table(name = "che_free_resources_limit") -public class FreeResourcesLimitImpl implements FreeResourcesLimit { - @Id - @Column(name = "account_id") - private String accountId; - - @PrimaryKeyJoinColumn private AccountImpl account; - - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinTable( - name = "che_free_resources_limit_resource", - joinColumns = @JoinColumn(name = "free_resources_limit_account_id"), - inverseJoinColumns = @JoinColumn(name = "resources_id")) - private List resources; - - public FreeResourcesLimitImpl() {} - - public FreeResourcesLimitImpl(FreeResourcesLimit freeResourcesLimit) { - this(freeResourcesLimit.getAccountId(), freeResourcesLimit.getResources()); - } - - public FreeResourcesLimitImpl(String accountId, List resources) { - this.accountId = accountId; - if (resources != null) { - this.resources = resources.stream().map(ResourceImpl::new).collect(Collectors.toList()); - } - } - - @Override - public String getAccountId() { - return accountId; - } - - @Override - public List getResources() { - if (resources == null) { - resources = new ArrayList<>(); - } - return resources; - } - - public void setResources(List resources) { - this.resources = resources; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof FreeResourcesLimitImpl)) return false; - FreeResourcesLimitImpl that = (FreeResourcesLimitImpl) o; - return Objects.equals(accountId, that.accountId) - && Objects.equals(getResources(), that.getResources()); - } - - @Override - public int hashCode() { - return Objects.hash(accountId, getResources()); - } - - @Override - public String toString() { - return "FreeResourcesLimitImpl{" - + "accountId='" - + accountId - + '\'' - + ", resources=" - + getResources() - + '}'; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ProvidedResourcesImpl.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ProvidedResourcesImpl.java deleted file mode 100644 index 41328ad6c38..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ProvidedResourcesImpl.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.spi.impl; - -import com.google.common.base.Objects; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; -import org.eclipse.che.multiuser.resource.model.ProvidedResources; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * @author Sergii Leschenko - */ -public class ProvidedResourcesImpl implements ProvidedResources { - private String provider; - private String id; - private String owner; - private Long startTime; - private Long endTime; - private List resources; - - public ProvidedResourcesImpl(ProvidedResources providedResources) { - this( - providedResources.getProviderId(), - providedResources.getId(), - providedResources.getOwner(), - providedResources.getStartTime(), - providedResources.getEndTime(), - providedResources.getResources()); - } - - public ProvidedResourcesImpl( - String provider, - String id, - String owner, - Long startTime, - Long endTime, - Collection resources) { - this.provider = provider; - this.id = id; - this.owner = owner; - this.startTime = startTime; - this.endTime = endTime; - if (resources != null) { - this.resources = resources.stream().map(ResourceImpl::new).collect(Collectors.toList()); - } - } - - @Override - public String getProviderId() { - return provider; - } - - @Override - public String getId() { - return id; - } - - @Override - public String getOwner() { - return owner; - } - - @Override - public Long getStartTime() { - return startTime; - } - - @Override - public Long getEndTime() { - return endTime; - } - - @Override - public List getResources() { - if (resources == null) { - resources = new ArrayList<>(); - } - return resources; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ProvidedResourcesImpl)) return false; - ProvidedResourcesImpl that = (ProvidedResourcesImpl) o; - return Objects.equal(provider, that.provider) - && Objects.equal(id, that.id) - && Objects.equal(owner, that.owner) - && Objects.equal(startTime, that.startTime) - && Objects.equal(endTime, that.endTime) - && Objects.equal(getResources(), that.getResources()); - } - - @Override - public int hashCode() { - return Objects.hashCode(provider, id, owner, startTime, endTime, getResources()); - } - - @Override - public String toString() { - return "GrantedResourceImpl{" - + "provider='" - + provider - + '\'' - + ", id='" - + id - + '\'' - + ", owner='" - + owner - + '\'' - + ", startTime=" - + startTime - + ", endTime=" - + endTime - + ", resources=" - + getResources() - + '}'; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ResourceImpl.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ResourceImpl.java deleted file mode 100644 index 597655040f3..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ResourceImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.spi.impl; - -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Table; -import org.eclipse.che.multiuser.resource.model.Resource; - -/** - * @author Sergii Leschenko - */ -@Entity(name = "Resource") -@Table(name = "che_resource") -public class ResourceImpl implements Resource { - @Id - @GeneratedValue - @Column(name = "id") - private Long id; - - @Column(name = "type", nullable = false) - private String type; - - @Column(name = "amount", nullable = false) - private long amount; - - @Column(name = "unit", nullable = false) - private String unit; - - public ResourceImpl() {} - - public ResourceImpl(String type, long amount, String unit) { - this.amount = amount; - this.type = type; - this.unit = unit; - } - - public ResourceImpl(Resource resource) { - this(resource.getType(), resource.getAmount(), resource.getUnit()); - } - - @Override - public String getType() { - return type; - } - - @Override - public long getAmount() { - return amount; - } - - @Override - public String getUnit() { - return unit; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof ResourceImpl)) { - return false; - } - final ResourceImpl that = (ResourceImpl) obj; - return amount == that.amount - && Objects.equals(id, that.id) - && Objects.equals(type, that.type) - && Objects.equals(unit, that.unit); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 31 * hash + Objects.hashCode(id); - hash = 31 * hash + Objects.hashCode(type); - hash = 31 * hash + Long.hashCode(amount); - hash = 31 * hash + Objects.hashCode(unit); - return hash; - } - - @Override - public String toString() { - return "ResourceImpl{" - + "id=" - + id - + ", type='" - + type - + '\'' - + ", amount=" - + amount - + ", unit='" - + unit - + '\'' - + '}'; - } -} diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ResourcesDetailsImpl.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ResourcesDetailsImpl.java deleted file mode 100644 index 25c94b57b9d..00000000000 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/spi/impl/ResourcesDetailsImpl.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.resource.spi.impl; - -import com.google.common.base.Objects; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import org.eclipse.che.multiuser.resource.model.ProvidedResources; -import org.eclipse.che.multiuser.resource.model.Resource; -import org.eclipse.che.multiuser.resource.model.ResourcesDetails; - -/** - * @author Sergii Leschenko - */ -public class ResourcesDetailsImpl implements ResourcesDetails { - private String accountId; - private List providedResources; - private List totalResources; - - public ResourcesDetailsImpl(ResourcesDetails resourcesDetails) { - this( - resourcesDetails.getAccountId(), - resourcesDetails.getProvidedResources(), - resourcesDetails.getTotalResources()); - } - - public ResourcesDetailsImpl( - String owner, - List providedResources, - List totalResources) { - this.accountId = owner; - if (providedResources != null) { - this.providedResources = - providedResources.stream().map(ProvidedResourcesImpl::new).collect(Collectors.toList()); - } - if (totalResources != null) { - this.totalResources = - totalResources.stream().map(ResourceImpl::new).collect(Collectors.toList()); - } - } - - @Override - public String getAccountId() { - return accountId; - } - - @Override - public List getProvidedResources() { - if (providedResources == null) { - providedResources = new ArrayList<>(); - } - return providedResources; - } - - @Override - public List getTotalResources() { - if (totalResources == null) { - totalResources = new ArrayList<>(); - } - return totalResources; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ResourcesDetailsImpl)) return false; - ResourcesDetailsImpl resourceDetails = (ResourcesDetailsImpl) o; - return Objects.equal(accountId, resourceDetails.accountId) - && Objects.equal(providedResources, resourceDetails.providedResources) - && Objects.equal(totalResources, resourceDetails.totalResources); - } - - @Override - public int hashCode() { - return Objects.hashCode(accountId, providedResources, totalResources); - } - - @Override - public String toString() { - return "ResourcesDetailsImpl{" - + "accountId='" - + accountId - + '\'' - + ", providedResources=" - + providedResources - + ", totalResources=" - + totalResources - + '}'; - } -} diff --git a/multiuser/api/pom.xml b/multiuser/api/pom.xml index 94f22ad63e1..87554dbabf7 100644 --- a/multiuser/api/pom.xml +++ b/multiuser/api/pom.xml @@ -29,9 +29,5 @@ che-multiuser-api-permission che-multiuser-api-authorization che-multiuser-api-authorization-impl - che-multiuser-api-resource-shared - che-multiuser-api-resource - che-multiuser-api-organization-shared - che-multiuser-api-organization diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/authenticating-to-the-che-server-using-openid.adoc b/multiuser/keycloak/che-multiuser-keycloak-server/authenticating-to-the-che-server-using-openid.adoc deleted file mode 100644 index 5cfd947c873..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/authenticating-to-the-che-server-using-openid.adoc +++ /dev/null @@ -1,109 +0,0 @@ -// authenticating-to-the-che-server - -[id="authenticating-to-the-che-server-using-openid_che"] -= Authenticating to the Che server using OpenID - -OpenID authentication on the Che server implies the presence of an external OpenID Connect provider and has the following main steps: - -* Authenticate the user through a JWT token that is retrieved from an HTTP request or, in case of a missing or invalid token, redirect the user to the Keycloak login page. - -* Send authentication tokens in an *Authorization* header. In limited cases, when it is impossible to use the *Authorization* header, the token can be sent in the token query parameter. Example: OAuth authentication initialization. - -* Compose an internal `subject` object that represents the current user inside the Che server code. - -NOTE: The only supported and tested OpenID provider is Keycloak. - -.Procedure - -To authenticate to the Che server using OpenID authentication: - -. Request the OpenID settings service where clients can find all the necessary URLs and properties of the OpenId provider, such as `jwks.endpoint`, `token.endpoint`, `logout.endpoint`, `realm.name`, or `client_id` returned in the JSON format. - -. The service URL is `pass:c,a,q[https://che-host:che-port/api/keycloak/settings]`, and it is only available in the Che multiuser mode. The presence of the service in the URL confirms that the authentication is enabled in the current deployment. -+ -Example output: -+ -[source,json] ----- -{ - "che.keycloak.token.endpoint": "http://172.19.20.9:5050/auth/realms/che/protocol/openid-connect/token", - "che.keycloak.profile.endpoint": "http://172.19.20.9:5050/auth/realms/che/account", - "che.keycloak.client_id": "che-public", - "che.keycloak.auth_server_url": "http://172.19.20.9:5050/auth", - "che.keycloak.password.endpoint": "http://172.19.20.9:5050/auth/realms/che/account/password", - "che.keycloak.logout.endpoint": "http://172.19.20.9:5050/auth/realms/che/protocol/openid-connect/logout", - "che.keycloak.realm": "che" -} ----- -+ -The service allows downloading the JavaScript client library to interact with the provider using the `pass:c,a,q[https://che-host:che-port/api/keycloak/OIDCKeycloak.js]` URL. - -. Redirect the user to the appropriate provider's login page with all the necessary parameters, including `client_id` and the return redirection path. This can be done with any client library (JS or Java). - -. When the user is logged in to the provider, the client side-code is obtained, and the JWT token has validated the token, the creation of the `subject` begins. - -The verification of the token signature occurs in two main steps: - -. Authentication: The token is extracted from the *Authorization* header or from the `token` query parameter and is parsed using the public key retrieved from the provider. In case of expired, invalid, or malformed tokens, a `403` error is sent to the user. The minimal use of the query parameter is recommended, due to its support limitations or complete removal in upcoming versions. -+ -If the validation is successful, the parsed form of the token is passed to the environment initialization step: - -. Environment initialization: The filter extracts data from the JWT token claims, creates the user in the local database if it is not yet available, and constructs the `subject` object and sets it into the per-request *EnvironmentContext* object, which is statically accessible everywhere. -+ -If the request was made using only a JWT token, the following single authentication filter is used: -+ -*org.eclipse.che.multiuser.machine.authentication.server.MachineLoginFilter*: The filter finds the user that the `userId` token belongs to, retrieves the user instance, and sets the principal to the session. The Che server-to-server requests are performed using a dedicated request factory that signs every request with the current subject token obtained from the `EnvironmentContext` object. - -[NOTE] -==== -.Providing user-specific data - -Since Keycloak may store user-specific information (first and last name, phone number, job title), there is a special implementation of the *ProfileDao* that can provide this data to consumers. The implementation is read-only, so users cannot perform create and update operations. -==== - - -[id="obtaining-the-token-from-keycloak_che"] -== Obtaining the token from credentials through Keycloak - -Clients that cannot run JavaScript or other clients (such as command-line clients or Selenium tests) must request the authorization token directly from Keycloak. - -To obtain the token, send a request to the token endpoint with the username and password credentials. This request can be schematically described as the following cURL request: - -[subs="+quotes,+attributes"] ----- -$ curl --insecure --data "grant_type=password&client_id=che-public&username=____&password=____" \ <1> <2> -https:///auth/realms/che/protocol/openid-connect/token <3> ----- -<1> Eclipse Che username -<2> Eclipse Che user's password -<3> Keycloak host - -The Che dashboard uses a customized Keycloak login page and an authentication mechanism based on `grant_type=authorization_code`. It is a two-step authentication process: - -. Logging in and obtaining the authorization code. -. Obtaining the token using this authorization code. - -[id="obtaining-the-token-from-openshift-token-through-keycloak_che"] -== Obtaining the token from the OpenShift token through Keycloak - -When Che was installed on OpenShift using the Operator, and the OpenShift OAuth integration is enabled, as it is by default, -the user's Che authentication token can be retrieved from the user's OpenShift token. - -To retrieve the authentication token from the OpenShift token, send a schematically described cURL request to the OpenShift token endpoint: - -[subs="+quotes,+attributes"] ----- -$ curl --insecure -X POST \ --d "client_id=che-public" \ --d "subject_token=____" \ <1> --d "subject_issuer=____" \ <2> ---data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ ---data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \ -https://____/auth/realms/che/protocol/openid-connect/token <3> ----- -<1> The token retrieved by the end-user with the command `oc whoami --show-token` -<2> `openshift-v4` for OpenShift 4.x and `openshift-v3` for OpenShift 3.11 -<3> Keycloak host - - -WARNING: Before using this token exchange feature, it is required for an end user to be interactively logged in at least once to the Che Dashboard using the OpenShift login page. This step is needed to link the OpenShift and Keycloak user accounts properly and set the required user profile information. diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/pom.xml b/multiuser/keycloak/che-multiuser-keycloak-server/pom.xml deleted file mode 100644 index 2aed4bcab13..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/pom.xml +++ /dev/null @@ -1,281 +0,0 @@ - - - - 4.0.0 - - che-multiuser-keycloak - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-keycloak-server - jar - Che Multiuser :: Keycloak Server - - ${project.build.directory}/generated-sources/dto/ - - - - com.auth0 - jwks-rsa - - - com.google.code.gson - gson - - - com.google.guava - guava - - - com.google.inject - guice - - - com.google.inject.extensions - guice-persist - - - io.jsonwebtoken - jjwt-api - - - jakarta.inject - jakarta.inject-api - - - jakarta.validation - jakarta.validation-api - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.eclipse.che.core - che-core-api-account - - - org.eclipse.che.core - che-core-api-auth - - - org.eclipse.che.core - che-core-api-auth-shared - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-api-dto - - - org.eclipse.che.core - che-core-api-model - - - org.eclipse.che.core - che-core-api-user - - - org.eclipse.che.core - che-core-commons-annotations - - - org.eclipse.che.core - che-core-commons-lang - - - org.eclipse.che.core - che-core-logback - - - org.eclipse.che.multiuser - che-multiuser-api-authentication-commons - - - org.eclipse.che.multiuser - che-multiuser-api-authorization - - - org.eclipse.che.multiuser - che-multiuser-keycloak-shared - - - org.eclipse.che.multiuser - che-multiuser-machine-authentication-shared - - - org.eclipse.che.multiuser - che-multiuser-oidc - - - org.eclipse.che.multiuser - che-multiuser-personal-account - - - org.everrest - everrest-guice-servlet - - - org.slf4j - slf4j-api - - - jakarta.servlet - jakarta.servlet-api - provided - - - com.github.tomakehurst - wiremock-jre8-standalone - test - - - commons-fileupload - commons-fileupload - test - - - io.jsonwebtoken - jjwt-impl - test - - - io.jsonwebtoken - jjwt-jackson - test - - - io.rest-assured - rest-assured - test - - - org.eclipse.che.multiuser - che-multiuser-machine-authentication - test - - - org.everrest - everrest-assured - test - - - org.hamcrest - hamcrest - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - org.wiremock - wiremock-standalone - test - - - - - - org.codehaus.mojo - build-helper-maven-plugin - - - add-resource - process-sources - - add-resource - - - - - ${dto-generator-out-directory}/META-INF - META-INF - - - - - - add-source - process-sources - - add-source - - - - ${dto-generator-out-directory} - - - - - - - maven-compiler-plugin - - - pre-compile - generate-sources - - compile - - - - - - org.eclipse.che.core - che-core-api-dto-maven-plugin - ${project.version} - - - server - process-sources - - generate - - - - org.eclipse.che.multiuser.keycloak.shared.dto - - ${dto-generator-out-directory} - org.eclipse.che.multiuser.keycloak.server.DtoServerImpls - server - - - - - - org.eclipse.che.multiuser - che-multiuser-keycloak-shared - ${project.version} - - - - - - diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakConfigurationService.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakConfigurationService.java deleted file mode 100644 index b2973f67388..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakConfigurationService.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.rest.Service; - -/** - * Endpoint which provides keycloak public client authentication information (such as URL, realm, - * client_id). - * - * @author Max Shaposhnik (mshaposh@redhat.com) - */ -@Singleton -@Path("/keycloak") -public class KeycloakConfigurationService extends Service { - - private final KeycloakSettings keycloakSettings; - - @Inject - public KeycloakConfigurationService(KeycloakSettings keycloakSettings) { - this.keycloakSettings = keycloakSettings; - } - - @GET - @Path("/settings") - @Produces(APPLICATION_JSON) - public Map settings() { - return keycloakSettings.get(); - } - - private String getKeycloakResource(String fileName) throws IOException { - URL resource = - Thread.currentThread().getContextClassLoader().getResource("keycloak/" + fileName); - if (resource != null) { - URLConnection conn = resource.openConnection(); - try (InputStream is = conn.getInputStream(); - ByteArrayOutputStream os = new ByteArrayOutputStream()) { - byte[] buffer = new byte[1024]; - int length; - while ((length = is.read(buffer)) != -1) { - os.write(buffer, 0, length); - } - return os.toString("UTF-8"); - } - } - return ""; - } - - @GET - @Path("/OIDCKeycloak.js") - @Produces("text/javascript") - public String javascriptAdapter() throws IOException { - return getKeycloakResource("OIDCKeycloak.js"); - } - - @GET - @Path("/oidcCallback.js") - @Produces("text/javascript") - public String callbackScript() throws IOException { - return getKeycloakResource("oidcCallback.js"); - } - - @GET - @Path("/oidcCallbackIde.html") - @Produces("text/html") - public String ideCallback() throws IOException { - return getKeycloakResource("oidcCallbackIde.html"); - } - - @GET - @Path("/oidcCallbackDashboard.html") - @Produces("text/html") - public String dashboardCallback() throws IOException { - return getKeycloakResource("oidcCallbackDashboard.html"); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakEnvironmentInitializationFilter.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakEnvironmentInitializationFilter.java deleted file mode 100644 index bbc548abf8e..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakEnvironmentInitializationFilter.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2012-2026 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.keycloak.server; - -import static com.google.common.base.Strings.isNullOrEmpty; -import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_USERNAME_CLAIM_SETTING; - -import com.google.common.base.Splitter; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jws; -import io.jsonwebtoken.JwtException; -import io.jsonwebtoken.JwtParser; -import jakarta.servlet.FilterChain; -import jakarta.servlet.FilterConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; -import java.util.Optional; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -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.api.core.model.user.User; -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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Sets subject attribute into session based on keycloak authentication data. - * - * @author Max Shaposhnik (mshaposhnik@redhat.com) - */ -@Singleton -public class KeycloakEnvironmentInitializationFilter - extends MultiUserEnvironmentInitializationFilter> { - - private static final Logger LOG = - LoggerFactory.getLogger(KeycloakEnvironmentInitializationFilter.class); - - private final KeycloakUserManager userManager; - private final KeycloakProfileRetriever keycloakProfileRetriever; - private final PermissionChecker permissionChecker; - private final KeycloakSettings keycloakSettings; - private final JwtParser jwtParser; - private final Map userNameReplacementPatterns; - - @Inject - public KeycloakEnvironmentInitializationFilter( - SessionStore sessionStore, - JwtParser jwtParser, - KeycloakUserManager userManager, - KeycloakProfileRetriever keycloakProfileRetriever, - RequestTokenExtractor tokenExtractor, - PermissionChecker permissionChecker, - KeycloakSettings settings, - @Nullable @Named("che.keycloak.username.replacement_patterns") - String userNameReplacementPatterns) { - super(sessionStore, tokenExtractor); - this.jwtParser = jwtParser; - this.userManager = userManager; - this.keycloakProfileRetriever = keycloakProfileRetriever; - this.permissionChecker = permissionChecker; - this.keycloakSettings = settings; - this.userNameReplacementPatterns = - isNullOrEmpty(userNameReplacementPatterns) - ? Collections.emptyMap() - : Splitter.on(",").withKeyValueSeparator("=").split(userNameReplacementPatterns); - } - - @Override - public void init(FilterConfig filterConfig) {} - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) - throws IOException, ServletException { - try { - super.doFilter(request, response, filterChain); - } catch (MachineTokenJwtException mte) { - filterChain.doFilter(request, response); - } catch (JwtException e) { - sendError(response, SC_UNAUTHORIZED, e.getMessage()); - return; - } - } - - @Override - protected Optional> processToken(String token) { - return Optional.ofNullable(jwtParser.parseClaimsJws(token)); - } - - @Override - protected String getUserId(Jws processedToken) { - return processedToken.getBody().getSubject(); - } - - @Override - public Subject extractSubject(String token, Jws processedToken) throws ServletException { - Claims claims = processedToken.getBody(); - LOG.debug("JWT = {}", processedToken); - // OK, we can trust this JWT - - try { - String username = - claims.get(keycloakSettings.get().get(OIDC_USERNAME_CLAIM_SETTING), String.class); - if (username == null) { // fallback to unique id promised by spec - // https://openid.net/specs/openid-connect-basic-1_0.html#ClaimStability - username = claims.getIssuer() + ":" + claims.getSubject(); - } - if (!userNameReplacementPatterns.isEmpty()) { - for (Map.Entry entry : userNameReplacementPatterns.entrySet()) { - username = username.replaceAll(entry.getKey(), entry.getValue()); - } - } - String id = claims.getSubject(); - - String email = - retrieveEmail(token, claims, id) - .orElseThrow( - () -> - new JwtException( - "Unable to authenticate user because email address is not set in keycloak profile")); - User user = userManager.getOrCreateUser(id, email, username); - // #KeycloakEnvironmentInitializationFilter is not used anymore, so we can ignore obtaining - // the list of groups user belongs to - return new AuthorizedSubject( - new SubjectImpl(user.getName(), Collections.emptyList(), user.getId(), token, false), - permissionChecker); - } catch (ServerException | ConflictException e) { - throw new ServletException( - "Unable to identify user " + claims.getSubject() + " in Che database", e); - } - } - - @Override - protected void handleMissingToken( - ServletRequest request, ServletResponse response, FilterChain chain) throws IOException { - sendError(response, 401, "Authorization token is missing"); - } - - private Optional retrieveEmail(String token, Claims claims, String id) - throws ServerException { - String email = claims.get("email", String.class); - - if (isNullOrEmpty(email)) { - try { - userManager.getById(id); - } catch (NotFoundException e) { - Map profileAttributes = - keycloakProfileRetriever.retrieveKeycloakAttributes("Bearer " + token); - email = profileAttributes.get("email"); - } - } - return Optional.ofNullable(email); - } - - @Override - public void destroy() {} -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakHttpJsonRequestFactory.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakHttpJsonRequestFactory.java deleted file mode 100644 index 8dee719df99..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakHttpJsonRequestFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import jakarta.validation.constraints.NotNull; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.rest.DefaultHttpJsonRequestFactory; -import org.eclipse.che.api.core.rest.HttpJsonRequest; -import org.eclipse.che.api.core.rest.shared.dto.Link; -import org.eclipse.che.commons.env.EnvironmentContext; - -@Singleton -public class KeycloakHttpJsonRequestFactory extends DefaultHttpJsonRequestFactory { - - @Inject - public KeycloakHttpJsonRequestFactory() {} - - @Override - public HttpJsonRequest fromUrl(@NotNull String url) { - return super.fromUrl(url) - .setAuthorizationHeader( - "Bearer " + EnvironmentContext.getCurrent().getSubject().getToken()); - } - - @Override - public HttpJsonRequest fromLink(@NotNull Link link) { - return super.fromLink(link) - .setAuthorizationHeader( - "Bearer " + EnvironmentContext.getCurrent().getSubject().getToken()); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakOIDCInfoProvider.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakOIDCInfoProvider.java deleted file mode 100644 index 207353d9e58..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakOIDCInfoProvider.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; - -import javax.inject.Inject; -import javax.inject.Named; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.multiuser.oidc.OIDCInfoProvider; - -/** - * KeycloakOIDCInfoProvider retrieves OpenID Connect (OIDC) configuration for well-known endpoint. - * These information is useful to provide access to the Keycloak api. - */ -public class KeycloakOIDCInfoProvider extends OIDCInfoProvider { - public final String realm; - - @Inject - public KeycloakOIDCInfoProvider( - @Nullable @Named(AUTH_SERVER_URL_SETTING) String serverURL, - @Nullable @Named(AUTH_SERVER_URL_INTERNAL_SETTING) String serverInternalURL, - @Nullable @Named(OIDC_PROVIDER_SETTING) String oidcProviderUrl, - @Nullable @Named(REALM_SETTING) String realm) { - super(serverURL, serverInternalURL, oidcProviderUrl); - this.realm = realm; - } - - @Override - protected String constructServerAuthUrl(String serverAuthUrl) { - return serverAuthUrl + "/realms/" + realm; - } - - protected void validate() { - if (oidcProviderUrl == null && realm == null) { - throw new RuntimeException("The '" + REALM_SETTING + "' property must be set"); - } - super.validate(); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakProfileRetriever.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakProfileRetriever.java deleted file mode 100644 index f7c3b47c8c4..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakProfileRetriever.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static com.google.common.base.Strings.isNullOrEmpty; - -import jakarta.validation.constraints.NotNull; -import java.io.IOException; -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.ApiException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.rest.HttpJsonRequestFactory; -import org.eclipse.che.multiuser.oidc.OIDCInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Fetches user profile from Keycloack server. - * - * @author David Festal - */ -@Singleton -public class KeycloakProfileRetriever { - private static final Logger LOG = LoggerFactory.getLogger(KeycloakProfileRetriever.class); - - private final String keyclockCurrentUserInfoUrl; - private final HttpJsonRequestFactory requestFactory; - - @Inject - public KeycloakProfileRetriever(OIDCInfo oidcInfo, HttpJsonRequestFactory requestFactory) { - this.requestFactory = requestFactory; - this.keyclockCurrentUserInfoUrl = - isNullOrEmpty(oidcInfo.getUserInfoInternalEndpoint()) - ? oidcInfo.getUserInfoPublicEndpoint() - : oidcInfo.getUserInfoInternalEndpoint(); - } - - /** - * Retrieves attributes from keycloak using default request factory assuming that there is an - * {@code Subject} with authorization token present in {@code EnvironmentContext} - * - * @return map of user attributes from keycloak - * @throws ServerException in an error happened - */ - public Map retrieveKeycloakAttributes() throws ServerException { - try { - return requestFactory.fromUrl(keyclockCurrentUserInfoUrl).request().asProperties(); - } catch (IOException | ApiException e) { - LOG.warn("Exception during retrieval of the Keycloak user profile", e); - throw new ServerException("Exception during retrieval of the Keycloak user profile", e); - } - } - - /** - * Retrieves attributes from keycloak using default request factory and provided authorization - * header for cases when no {@code Subject} set in {@code EnvironmentContext} - * - * @return map of user attributes from keycloak - * @throws ServerException in an error happened - */ - public Map retrieveKeycloakAttributes(@NotNull String authorizationHeader) - throws ServerException { - try { - return requestFactory - .fromUrl(keyclockCurrentUserInfoUrl) - .setAuthorizationHeader(authorizationHeader) - .request() - .asProperties(); - } catch (IOException | ApiException e) { - LOG.warn("Exception during retrieval of the Keycloak user profile", e); - throw new ServerException("Exception during retrieval of the Keycloak user profile", e); - } - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClient.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClient.java deleted file mode 100644 index 1542b5c409b..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClient.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; - -import com.google.common.io.CharStreams; -import com.google.gson.Gson; -import com.google.gson.JsonSyntaxException; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.JwtParser; -import jakarta.ws.rs.HttpMethod; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.UriBuilder; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.BadRequestException; -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.api.core.UnauthorizedException; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.lang.Pair; -import org.eclipse.che.dto.server.DtoFactory; -import org.eclipse.che.multiuser.keycloak.shared.dto.KeycloakErrorResponse; -import org.eclipse.che.multiuser.keycloak.shared.dto.KeycloakTokenResponse; -import org.eclipse.che.multiuser.oidc.OIDCInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Helps to perform keycloak operations and provide correct errors handling. - * - * @author Max Shaposhnik (mshaposh@redhat.com) - */ -@Singleton -public class KeycloakServiceClient { - - private final KeycloakSettings keycloakSettings; - private final OIDCInfo oidcInfo; - - private static final Logger LOG = LoggerFactory.getLogger(KeycloakServiceClient.class); - - private static final Pattern assotiateUserPattern = - Pattern.compile("User (.+) is not associated with identity provider (.+)"); - - private static final Pattern errorPageMessagePattern = - Pattern.compile("

(\\s*)

(.+?)

"); - - private static final Gson gson = new Gson(); - private final JwtParser jwtParser; - - @Inject - public KeycloakServiceClient( - KeycloakSettings keycloakSettings, OIDCInfo oidcInfo, JwtParser jwtParser) { - this.keycloakSettings = keycloakSettings; - this.oidcInfo = oidcInfo; - this.jwtParser = jwtParser; - } - - /** - * Generates URL for account linking redirect - * - * @param token client jwt token - * @param oauthProvider provider name - * @param redirectAfterLogin URL to return after login - * @return URL to redirect client to perform account linking - */ - public String getAccountLinkingURL( - String token, String oauthProvider, String redirectAfterLogin) { - - Claims claims = jwtParser.parseClaimsJws(token).getBody(); - final String clientId = claims.get("azp", String.class); - final String sessionState = claims.get("session_state", String.class); - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - - final String nonce = UUID.randomUUID().toString(); - final String input = nonce + sessionState + clientId + oauthProvider; - byte[] check = md.digest(input.getBytes(StandardCharsets.UTF_8)); - final String hash = Base64.getUrlEncoder().encodeToString(check); - - return UriBuilder.fromUri(oidcInfo.getAuthServerPublicURL()) - .path("/realms/{realm}/broker/{provider}/link") - .queryParam("nonce", nonce) - .queryParam("hash", hash) - .queryParam("client_id", clientId) - .queryParam("redirect_uri", redirectAfterLogin) - .build(keycloakSettings.get().get(REALM_SETTING), oauthProvider) - .toString(); - } - - /** - * Gets auth token from given identity provider. - * - * @param oauthProvider provider name - * @return KeycloakTokenResponse token response - * @throws ForbiddenException when HTTP request was forbidden - * @throws BadRequestException when HTTP request considered as bad - * @throws IOException when unable to parse error response - * @throws NotFoundException when requested URL not found - * @throws ServerException when other error occurs - * @throws UnauthorizedException when no token present for user or user not linked to provider - */ - public KeycloakTokenResponse getIdentityProviderToken(String oauthProvider) - throws ForbiddenException, - BadRequestException, - IOException, - NotFoundException, - ServerException, - UnauthorizedException { - String url = - UriBuilder.fromUri(oidcInfo.getAuthServerURL()) - .path("/realms/{realm}/broker/{provider}/token") - .build(keycloakSettings.get().get(REALM_SETTING), oauthProvider) - .toString(); - try { - String response = doRequest(url, HttpMethod.GET, null); - // Successful answer is not a json, but key=value&foo=bar format pairs - return DtoFactory.getInstance() - .createDtoFromJson(toJson(response), KeycloakTokenResponse.class); - } catch (BadRequestException e) { - if (assotiateUserPattern.matcher(e.getMessage()).matches()) { - // If user has no link with identity provider yet, - // we should threat this as unauthorized and send to OAuth login page. - throw new UnauthorizedException(e.getMessage()); - } - throw e; - } - } - - private String doRequest(String url, String method, List> parameters) - throws IOException, - ServerException, - ForbiddenException, - NotFoundException, - UnauthorizedException, - BadRequestException { - final String authToken = EnvironmentContext.getCurrent().getSubject().getToken(); - final boolean hasQueryParams = parameters != null && !parameters.isEmpty(); - if (hasQueryParams) { - final UriBuilder ub = UriBuilder.fromUri(url); - for (Pair parameter : parameters) { - ub.queryParam(parameter.first, parameter.second); - } - url = ub.build().toString(); - } - final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); - conn.setConnectTimeout(60000); - conn.setReadTimeout(60000); - - try { - conn.setRequestMethod(method); - // drop a hint for server side that we want to receive application/json - conn.addRequestProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON); - if (authToken != null) { - conn.setRequestProperty(HttpHeaders.AUTHORIZATION, "bearer " + authToken); - } - final int responseCode = conn.getResponseCode(); - if ((responseCode / 100) != 2) { - InputStream in = conn.getErrorStream(); - if (in == null) { - in = conn.getInputStream(); - } - final String output; - try (Reader reader = new InputStreamReader(in)) { - String read = CharStreams.toString(reader); - // Unspecific errors always returned from Keycloak as 502 + HTML error page. - // So try to handle that case separately - if (responseCode == 502) { - Matcher matcher = errorPageMessagePattern.matcher(read); - output = matcher.find() ? matcher.group(2) : read; - } else { - output = read; - } - } - final String contentType = conn.getContentType(); - if (contentType != null - && (contentType.startsWith(MediaType.APPLICATION_JSON) - || contentType.startsWith("application/vnd.api+json"))) { - final KeycloakErrorResponse serviceError = - DtoFactory.getInstance().createDtoFromJson(output, KeycloakErrorResponse.class); - if (responseCode == Response.Status.FORBIDDEN.getStatusCode()) { - throw new ForbiddenException(serviceError.getErrorMessage()); - } else if (responseCode == Response.Status.NOT_FOUND.getStatusCode()) { - throw new NotFoundException(serviceError.getErrorMessage()); - } else if (responseCode == Response.Status.UNAUTHORIZED.getStatusCode()) { - throw new UnauthorizedException(serviceError.getErrorMessage()); - } else if (responseCode == Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) { - throw new ServerException(serviceError.getErrorMessage()); - } else if (responseCode == Response.Status.BAD_REQUEST.getStatusCode()) { - throw new BadRequestException(serviceError.getErrorMessage()); - } - throw new ServerException(serviceError.getErrorMessage()); - } - // Can't parse content as json or content has format other we expect for error. - LOG.warn( - String.format( - "Failed access: %s, method: %s, response code: %d, message: %s", - UriBuilder.fromUri(url).replaceQuery("token").build(), - method, - responseCode, - output)); - throw new IOException(output); - } - try (Reader reader = new InputStreamReader(conn.getInputStream())) { - return CharStreams.toString(reader); - } - } finally { - conn.disconnect(); - } - } - - /** Converts key=value&foo=bar string into json if necessary */ - private static String toJson(String source) { - if (source == null) { - return null; - } - try { - // Check that the source is valid Json Object (can be returned as a Map) - Map unused = gson.>fromJson(source, Map.class); - return source; - } catch (JsonSyntaxException notJsonException) { - // The source is not valid Json: let's see if - // it is in 'key=value&foo=bar' format - Map queryPairs = new HashMap<>(); - Arrays.stream(source.split("&")) - .forEach( - p -> { - int delimiterIndex = p.indexOf("="); - queryPairs.put(p.substring(0, delimiterIndex), p.substring(delimiterIndex + 1)); - }); - return gson.toJson(queryPairs); - } - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSettings.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSettings.java deleted file mode 100644 index abe3d6383db..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSettings.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.CLIENT_ID_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.FIXED_REDIRECT_URL_FOR_DASHBOARD; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.FIXED_REDIRECT_URL_FOR_IDE; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.GITHUB_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.JS_ADAPTER_URL_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.JWKS_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.LOGOUT_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.OSO_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.PASSWORD_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.PROFILE_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.TOKEN_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.USERINFO_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.USE_FIXED_REDIRECT_URLS_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.USE_NONCE_SETTING; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.AUTH_SERVER_URL_SETTING; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_PROVIDER_SETTING; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_USERNAME_CLAIM_SETTING; - -import com.google.common.collect.Maps; -import java.util.Collections; -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.multiuser.oidc.OIDCInfo; - -/** - * @author Max Shaposhnik (mshaposh@redhat.com) - */ -@Singleton -public class KeycloakSettings { - protected static final String DEFAULT_USERNAME_CLAIM = "preferred_username"; - - private final Map settings; - private final String oidcProviderUrl; - - @Inject - public KeycloakSettings( - @Named("che.api") String cheServerEndpoint, - @Nullable @Named(JS_ADAPTER_URL_SETTING) String jsAdapterUrl, - @Nullable @Named(AUTH_SERVER_URL_SETTING) String serverURL, - @Nullable @Named(REALM_SETTING) String realm, - @Named(CLIENT_ID_SETTING) String clientId, - @Nullable @Named(OIDC_PROVIDER_SETTING) String oidcProviderUrl, - @Nullable @Named(OIDC_USERNAME_CLAIM_SETTING) String usernameClaim, - @Named(USE_NONCE_SETTING) boolean useNonce, - @Nullable @Named(OSO_ENDPOINT_SETTING) String osoEndpoint, - @Nullable @Named(GITHUB_ENDPOINT_SETTING) String gitHubEndpoint, - @Named(USE_FIXED_REDIRECT_URLS_SETTING) boolean useFixedRedirectUrls, - OIDCInfo oidcInfo) { - this.oidcProviderUrl = oidcProviderUrl; - - Map settings = Maps.newHashMap(); - settings.put( - OIDC_USERNAME_CLAIM_SETTING, - usernameClaim == null ? DEFAULT_USERNAME_CLAIM : usernameClaim); - settings.put(CLIENT_ID_SETTING, clientId); - settings.put(REALM_SETTING, realm); - - if (serverURL != null) { - settings.put(AUTH_SERVER_URL_SETTING, serverURL); - settings.put(PROFILE_ENDPOINT_SETTING, serverURL + "/realms/" + realm + "/account"); - settings.put(PASSWORD_ENDPOINT_SETTING, serverURL + "/realms/" + realm + "/account/password"); - settings.put( - LOGOUT_ENDPOINT_SETTING, - serverURL + "/realms/" + realm + "/protocol/openid-connect/logout"); - settings.put( - TOKEN_ENDPOINT_SETTING, - serverURL + "/realms/" + realm + "/protocol/openid-connect/token"); - } - - oidcInfo.getEndSessionPublicEndpoint().ifPresent(e -> settings.put(LOGOUT_ENDPOINT_SETTING, e)); - - if (oidcInfo.getTokenPublicEndpoint() != null) { - settings.put(TOKEN_ENDPOINT_SETTING, oidcInfo.getTokenPublicEndpoint()); - } - if (oidcInfo.getUserInfoPublicEndpoint() != null) { - settings.put(USERINFO_ENDPOINT_SETTING, oidcInfo.getUserInfoPublicEndpoint()); - } - if (oidcInfo.getJwksPublicUri() != null) { - settings.put(JWKS_ENDPOINT_SETTING, oidcInfo.getJwksPublicUri()); - } - - settings.put(OSO_ENDPOINT_SETTING, osoEndpoint); - settings.put(GITHUB_ENDPOINT_SETTING, gitHubEndpoint); - - this.setUpKeycloakJSAdaptersURLS( - settings, useNonce, useFixedRedirectUrls, jsAdapterUrl, cheServerEndpoint, serverURL); - - this.settings = Collections.unmodifiableMap(settings); - } - - private void setUpKeycloakJSAdaptersURLS( - Map settings, - boolean useNonce, - boolean useFixedRedirectUrls, - String jsAdapterUrl, - String cheServerEndpoint, - String serverURL) { - if (oidcProviderUrl != null) { - settings.put(OIDC_PROVIDER_SETTING, oidcProviderUrl); - if (useFixedRedirectUrls) { - String rootUrl = - cheServerEndpoint.endsWith("/") ? cheServerEndpoint : cheServerEndpoint + "/"; - settings.put( - FIXED_REDIRECT_URL_FOR_DASHBOARD, rootUrl + "keycloak/oidcCallbackDashboard.html"); - settings.put(FIXED_REDIRECT_URL_FOR_IDE, rootUrl + "keycloak/oidcCallbackIde.html"); - } - } - - settings.put(USE_NONCE_SETTING, Boolean.toString(useNonce)); - - if (jsAdapterUrl == null) { - jsAdapterUrl = - (oidcProviderUrl != null) - ? "/api/keycloak/OIDCKeycloak.js" - : serverURL + "/js/keycloak.js"; - } - settings.put(JS_ADAPTER_URL_SETTING, jsAdapterUrl); - } - - /** - * Public Keycloak connection settings. It contains information about keycloak api urls and - * information required to make Keycloak connection using public domain hostname. This info will - * be shared with frontend. - */ - public Map get() { - return settings; - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSigningKeyResolver.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSigningKeyResolver.java deleted file mode 100644 index 2cd32df86e4..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSigningKeyResolver.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012-2026 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.keycloak.server; - -import static org.eclipse.che.multiuser.machine.authentication.shared.Constants.MACHINE_TOKEN_KIND; - -import com.auth0.jwk.JwkProvider; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.JwsHeader; -import java.security.Key; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.multiuser.oidc.OIDCSigningKeyResolver; - -/** Resolves signing key based on id from JWT header */ -@Singleton -public class KeycloakSigningKeyResolver extends OIDCSigningKeyResolver { - @Inject - KeycloakSigningKeyResolver(JwkProvider jwkProvider) { - super(jwkProvider); - } - - @Override - public Key resolveSigningKey(JwsHeader header, byte[] content) { - if (MACHINE_TOKEN_KIND.equals(header.get("kind"))) { - throw new MachineTokenJwtException(); // machine token, doesn't need to verify - } - return getJwtPublicKey(header); - } - - @Override - public Key resolveSigningKey(JwsHeader header, Claims claims) { - if (MACHINE_TOKEN_KIND.equals(header.get("kind"))) { - throw new MachineTokenJwtException(); // machine token, doesn't need to verify - } - return getJwtPublicKey(header); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakTokenValidator.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakTokenValidator.java deleted file mode 100644 index c6155d0ff72..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakTokenValidator.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import org.eclipse.che.api.core.ConflictException; -import org.eclipse.che.api.core.model.user.User; -import org.eclipse.che.api.user.server.TokenValidator; -import org.eclipse.che.api.user.server.model.impl.UserImpl; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; - -/** - * Dummy stub for {@link org.eclipse.che.api.user.server.UserService}. - * - * @author Max Shaposhnik (mshaposhnik@redhat.com) - */ -public class KeycloakTokenValidator implements TokenValidator { - @Override - public User validateToken(String token) throws ConflictException { - final Subject subject = EnvironmentContext.getCurrent().getSubject(); - return new UserImpl(subject.getUserId(), "", subject.getUserName()); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserManager.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserManager.java deleted file mode 100644 index 2bf7baf9628..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserManager.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static java.lang.System.currentTimeMillis; - -import com.google.common.collect.ImmutableMap; -import com.google.inject.Inject; -import com.google.inject.persist.Transactional; -import javax.inject.Named; -import javax.inject.Singleton; -import org.eclipse.che.account.api.AccountManager; -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.ServerException; -import org.eclipse.che.api.core.notification.EventService; -import org.eclipse.che.api.user.server.model.impl.UserImpl; -import org.eclipse.che.api.user.server.spi.PreferenceDao; -import org.eclipse.che.api.user.server.spi.ProfileDao; -import org.eclipse.che.api.user.server.spi.UserDao; -import org.eclipse.che.multiuser.api.account.personal.PersonalAccountUserManager; - -/** - * Extension of User Manager, providing utility operations related to Keycloak User management, and - * overriding create/remove operations to be compatible with {@link - * org.eclipse.che.multiuser.keycloak.server.dao.KeycloakProfileDao} - * - * @author Mykhailo Kuznietsov - */ -@Singleton -public class KeycloakUserManager extends PersonalAccountUserManager { - - @Inject - public KeycloakUserManager( - UserDao userDao, - ProfileDao profileDao, - PreferenceDao preferencesDao, - AccountManager accountManager, - EventService eventService, - @Named("che.auth.reserved_user_names") String[] reservedNames) { - super(userDao, profileDao, preferencesDao, reservedNames, accountManager, eventService); - } - - @Transactional(rollbackOn = {RuntimeException.class, ApiException.class}) - protected void doCreate(UserImpl user, boolean isTemporary) - throws ConflictException, ServerException { - userDao.create(user); - preferencesDao.setPreferences( - user.getId(), - ImmutableMap.of( - "temporary", Boolean.toString(isTemporary), - "codenvy:created", Long.toString(currentTimeMillis()))); - } - - @Transactional(rollbackOn = {RuntimeException.class, ApiException.class}) - protected void doRemove(String id) throws ServerException { - UserImpl user; - try { - user = userDao.getById(id); - } catch (NotFoundException ignored) { - return; - } - preferencesDao.remove(id); - userDao.remove(id); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/MachineTokenJwtException.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/MachineTokenJwtException.java deleted file mode 100644 index a5621cd6efe..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/MachineTokenJwtException.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import io.jsonwebtoken.JwtException; - -public class MachineTokenJwtException extends JwtException { - - public MachineTokenJwtException() { - super("This is a machine token"); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/UnavailableResourceInMultiUserFilter.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/UnavailableResourceInMultiUserFilter.java deleted file mode 100644 index 9a02b9046f3..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/UnavailableResourceInMultiUserFilter.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.FilterConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import javax.inject.Singleton; - -/** - * Filter that will return HTTP status 403. Used for resources, that are not meant to be available - * in multi-user Che. Filter omits GET requests. - */ -@Singleton -public class UnavailableResourceInMultiUserFilter implements Filter { - protected static final String ERROR_RESPONSE_JSON_MESSAGE = - "{\"error\" : \"This operation is not allowed since third-party user management service is configured\" }"; - - @Override - public void init(FilterConfig filterConfig) throws ServletException {} - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - String requestMethod = ((HttpServletRequest) request).getMethod(); - if (requestMethod.equals("GET")) { - // allow request to go through - chain.doFilter(request, response); - return; - } - - HttpServletResponse httpResponse = (HttpServletResponse) response; - httpResponse.setStatus(403); - httpResponse.setContentType("application/json"); - httpResponse.getWriter().println(ERROR_RESPONSE_JSON_MESSAGE); - } - - @Override - public void destroy() {} -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/dao/KeycloakProfileDao.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/dao/KeycloakProfileDao.java deleted file mode 100644 index 8a5a83db311..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/dao/KeycloakProfileDao.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server.dao; - -import static java.util.Objects.requireNonNull; - -import java.util.HashMap; -import java.util.Map; -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; -import org.eclipse.che.api.user.server.model.impl.ProfileImpl; -import org.eclipse.che.api.user.server.spi.ProfileDao; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.multiuser.keycloak.server.KeycloakProfileRetriever; - -/** - * Fetches user profile from Keycloak server. - * - * @author Max Shaposhnik (mshaposh@redhat.com) - * @author Sergii Leshchenko - */ -public class KeycloakProfileDao implements ProfileDao { - - private final KeycloakProfileRetriever keycloakProfileRetriever; - - @Inject - public KeycloakProfileDao(KeycloakProfileRetriever keycloakProfileRetriever) { - this.keycloakProfileRetriever = keycloakProfileRetriever; - } - - @Override - public void create(ProfileImpl profile) throws ServerException, ConflictException { - throw new ServerException("Given operation doesn't supported on current configured storage."); - } - - @Override - public void update(ProfileImpl profile) throws NotFoundException, ServerException { - throw new ServerException("Given operation doesn't supported on current configured storage."); - } - - @Override - public void remove(String userId) throws ServerException { - throw new ServerException("Given operation doesn't supported on current configured storage."); - } - - @Override - public ProfileImpl getById(String userId) throws NotFoundException, ServerException { - requireNonNull(userId, "Required non-null id"); - String currentUserId = EnvironmentContext.getCurrent().getSubject().getUserId(); - if (!userId.equals(currentUserId)) { - throw new ServerException( - "It's not allowed to get foreign profile on current configured storage."); - } - - // Retrieving own profile - Map keycloakUserAttributes = - keycloakProfileRetriever.retrieveKeycloakAttributes(); - - return new ProfileImpl(userId, mapAttributes(keycloakUserAttributes)); - } - - private Map mapAttributes(Map keycloakUserAttributes) { - Map profileAttributes = new HashMap<>(); - String givenName = keycloakUserAttributes.remove("given_name"); - if (givenName != null) { - profileAttributes.put("firstName", givenName); - } - - String familyName = keycloakUserAttributes.remove("family_name"); - if (familyName != null) { - profileAttributes.put("lastName", familyName); - } - - // profile should be accessible from user object - keycloakUserAttributes.remove("email"); - - profileAttributes.putAll(keycloakUserAttributes); - return profileAttributes; - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakModule.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakModule.java deleted file mode 100644 index fef7ac15806..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakModule.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server.deploy; - -import com.auth0.jwk.JwkProvider; -import com.google.inject.AbstractModule; -import io.jsonwebtoken.JwtParser; -import io.jsonwebtoken.SigningKeyResolver; -import org.eclipse.che.api.core.rest.HttpJsonRequestFactory; -import org.eclipse.che.api.user.server.TokenValidator; -import org.eclipse.che.api.user.server.spi.ProfileDao; -import org.eclipse.che.multiuser.api.account.personal.PersonalAccountUserManager; -import org.eclipse.che.multiuser.keycloak.server.KeycloakOIDCInfoProvider; -import org.eclipse.che.multiuser.keycloak.server.KeycloakSigningKeyResolver; -import org.eclipse.che.multiuser.keycloak.server.KeycloakTokenValidator; -import org.eclipse.che.multiuser.keycloak.server.KeycloakUserManager; -import org.eclipse.che.multiuser.keycloak.server.dao.KeycloakProfileDao; -import org.eclipse.che.multiuser.oidc.OIDCInfo; -import org.eclipse.che.multiuser.oidc.OIDCJwkProvider; -import org.eclipse.che.multiuser.oidc.OIDCJwtParserProvider; -import org.eclipse.che.security.oauth.OAuthAPI; - -public class KeycloakModule extends AbstractModule { - @Override - protected void configure() { - - bind(HttpJsonRequestFactory.class) - .to(org.eclipse.che.multiuser.keycloak.server.KeycloakHttpJsonRequestFactory.class); - bind(TokenValidator.class).to(KeycloakTokenValidator.class); - - bind(ProfileDao.class).to(KeycloakProfileDao.class); - bind(JwkProvider.class).toProvider(OIDCJwkProvider.class); - bind(SigningKeyResolver.class).to(KeycloakSigningKeyResolver.class); - bind(JwtParser.class).toProvider(OIDCJwtParserProvider.class); - bind(OIDCInfo.class).toProvider(KeycloakOIDCInfoProvider.class).asEagerSingleton(); - bind(PersonalAccountUserManager.class).to(KeycloakUserManager.class); - - bind(OAuthAPI.class).toProvider(OAuthAPIProvider.class); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakServletModule.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakServletModule.java deleted file mode 100644 index e58cb1a0f1c..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakServletModule.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server.deploy; - -import com.google.inject.servlet.ServletModule; -import org.eclipse.che.commons.logback.filter.IdentityIdLoggerFilter; -import org.eclipse.che.multiuser.keycloak.server.KeycloakEnvironmentInitializationFilter; -import org.eclipse.che.multiuser.keycloak.server.UnavailableResourceInMultiUserFilter; - -public class KeycloakServletModule extends ServletModule { - - static final String KEYCLOAK_FILTER_PATHS = - "^" - // not equals to /keycloak/OIDCKeycloak.js - + "(?!/keycloak/(OIDC|oidc)[^\\/]+$)" - // not equals to openapi.json (for swagger) - + "(?!.*(/openapi\\.json))" - // not ends with '/oauth/callback/' or '/oauth/1.0/callback/' or '/keycloak/settings/' or - // '/system/state' - + "(?!.*(/keycloak/settings/?|/oauth/callback/?|/oauth/1.0/callback/?|/system/state/?)$)" - // all other - + ".*"; - - @Override - protected void configureServlets() { - filterRegex(KEYCLOAK_FILTER_PATHS).through(KeycloakEnvironmentInitializationFilter.class); - filterRegex(KEYCLOAK_FILTER_PATHS).through(IdentityIdLoggerFilter.class); - - // Ban change password (POST /user/password) and create a user (POST /user/) methods - // but not remove user (DELETE /user/{USER_ID} - filterRegex("^/user(/password/?|/)?$").through(UnavailableResourceInMultiUserFilter.class); - - filterRegex("^/profile/(.*/)?attributes$").through(UnavailableResourceInMultiUserFilter.class); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/OAuthAPIProvider.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/OAuthAPIProvider.java deleted file mode 100644 index d173bc5d7d6..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/deploy/OAuthAPIProvider.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server.deploy; - -import com.google.inject.Injector; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Provider; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.multiuser.keycloak.server.oauth2.DelegatedOAuthAPI; -import org.eclipse.che.security.oauth.EmbeddedOAuthAPI; -import org.eclipse.che.security.oauth.OAuthAPI; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Provides appropriate OAuth Authentication API depending on configuration. - * - * @author Mykhailo Kuznietsov. - */ -public class OAuthAPIProvider implements Provider { - private static final Logger LOG = LoggerFactory.getLogger(OAuthAPIProvider.class); - private String oauthType; - private Injector injector; - - @Inject - public OAuthAPIProvider( - @Nullable @Named("che.oauth.service_mode") String oauthType, Injector injector) { - this.oauthType = oauthType; - this.injector = injector; - } - - @Override - public OAuthAPI get() { - switch (oauthType) { - case "embedded": - return injector.getInstance(EmbeddedOAuthAPI.class); - case "delegated": - return injector.getInstance(DelegatedOAuthAPI.class); - default: - throw new RuntimeException( - "Unknown value configured for \"che.oauth.service_mode\", must be either \"embedded\", or \"delegated\""); - } - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/oauth2/DelegatedOAuthAPI.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/oauth2/DelegatedOAuthAPI.java deleted file mode 100644 index 62c9901ca52..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/oauth2/DelegatedOAuthAPI.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server.oauth2; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.UriInfo; -import java.io.IOException; -import java.net.URI; -import java.util.List; -import java.util.Set; -import javax.inject.Inject; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; -import org.eclipse.che.api.core.BadRequestException; -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.api.core.UnauthorizedException; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.dto.server.DtoFactory; -import org.eclipse.che.multiuser.keycloak.server.KeycloakServiceClient; -import org.eclipse.che.multiuser.keycloak.shared.dto.KeycloakTokenResponse; -import org.eclipse.che.security.oauth.OAuthAPI; -import org.eclipse.che.security.oauth.OAuthAuthenticationService; -import org.eclipse.che.security.oauth.shared.dto.OAuthAuthenticatorDescriptor; - -/** - * Implementation of functional API component for {@link OAuthAuthenticationService}, that uses - * {@link KeycloakServiceClient} for authenticating users through Keycloak Identity providers. - * - * @author Mykhailo Kuznietsov - */ -public class DelegatedOAuthAPI implements OAuthAPI { - - private final KeycloakServiceClient keycloakServiceClient; - - @Inject - public DelegatedOAuthAPI(KeycloakServiceClient keycloakServiceClient) { - this.keycloakServiceClient = keycloakServiceClient; - } - - @Override - public Response authenticate( - UriInfo uriInfo, - String oauthProvider, - List scopes, - String redirectAfterLogin, - HttpServletRequest request) - throws BadRequestException { - - String jwtToken = EnvironmentContext.getCurrent().getSubject().getToken(); - if (jwtToken == null) { - throw new BadRequestException("No token provided."); - } - String accountLinkUrl = - keycloakServiceClient.getAccountLinkingURL(jwtToken, oauthProvider, redirectAfterLogin); - return Response.temporaryRedirect(URI.create(accountLinkUrl)).build(); - } - - @Override - public OAuthToken getOrRefreshToken(String oauthProvider) - throws ForbiddenException, - BadRequestException, - NotFoundException, - ServerException, - UnauthorizedException { - try { - KeycloakTokenResponse response = - keycloakServiceClient.getIdentityProviderToken(oauthProvider); - return DtoFactory.newDto(OAuthToken.class) - .withToken(response.getAccessToken()) - .withScope(response.getScope()); - } catch (IOException e) { - throw new ServerException(e.getMessage()); - } - } - - @Override - public OAuthToken refreshToken(String oauthProvider) throws ForbiddenException { - throw new ForbiddenException("Method is not supported in this implementation of OAuth API"); - } - - @Override - public void invalidateToken(String oauthProvider) throws ForbiddenException { - throw new ForbiddenException("Method is not supported in this implementation of OAuth API"); - } - - @Override - public Response callback(UriInfo uriInfo, List errorValues) throws ForbiddenException { - throw new ForbiddenException("Method is not supported in this implementation of OAuth API"); - } - - @Override - public Set getRegisteredAuthenticators(UriInfo uriInfo) - throws ForbiddenException { - throw new ForbiddenException("Method is not supported in this implementation of OAuth API"); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClientTest.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClientTest.java deleted file mode 100644 index 8bb7da5fdcf..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClientTest.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; -import static jakarta.ws.rs.core.Response.Status.*; -import static org.eclipse.che.dto.server.DtoFactory.newDto; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jws; -import io.jsonwebtoken.JwtParser; -import io.restassured.RestAssured; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import org.eclipse.che.api.core.ApiException; -import org.eclipse.che.api.core.AuthenticationException; -import org.eclipse.che.api.core.BadRequestException; -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.api.core.UnauthorizedException; -import org.eclipse.che.api.core.rest.Service; -import org.eclipse.che.dto.server.DtoFactory; -import org.eclipse.che.multiuser.keycloak.shared.dto.KeycloakErrorResponse; -import org.eclipse.che.multiuser.keycloak.shared.dto.KeycloakTokenResponse; -import org.eclipse.che.multiuser.oidc.OIDCInfo; -import org.everrest.assured.EverrestJetty; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** - * @author Max Shaposhnik (mshaposh@redhat.com) - */ -@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class}) -public class KeycloakServiceClientTest { - - @Mock private KeycloakSettings keycloakSettings; - @Mock private JwtParser jwtParser; - @Mock private OIDCInfo oidcInfo; - @Mock private Jws jws; - @Mock private Claims claims; - - private KeycloakServiceClient keycloakServiceClient; - - @SuppressWarnings("unused") - private KeycloakService keycloakService; - - private static final String token = "token123"; - private static final String clientId = "some-client-id"; - private static final String someSessionState = "some-state"; - private static final String scope = "test_scope"; - - @SuppressWarnings("unused") - private final LocalApiExceptionMapper exceptionMapper = new LocalApiExceptionMapper(); - - @BeforeMethod - public void setUp() throws Exception { - when(oidcInfo.getAuthServerURL()) - .thenReturn(RestAssured.baseURI + ":" + RestAssured.port + RestAssured.basePath); - lenient().when(oidcInfo.getAuthServerPublicURL()).thenReturn("https://keycloak-che"); - lenient().when(jwtParser.parseClaimsJws(token)).thenReturn(jws); - lenient().when(jws.getBody()).thenReturn(claims); - lenient() - .when(claims.get(anyString(), eq(String.class))) - .thenAnswer( - invocationOnMock -> { - String arg = (String) invocationOnMock.getArguments()[0]; - if (arg.equals("azp")) { - return clientId; - } - if (arg.equals("session_state")) { - return someSessionState; - } - return null; - }); - - keycloakServiceClient = new KeycloakServiceClient(keycloakSettings, oidcInfo, jwtParser); - Map confInternal = new HashMap<>(); - confInternal.put(REALM_SETTING, "che"); - when(keycloakSettings.get()).thenReturn(confInternal); - } - - @Test - public void shouldReturnPublicAccountLinkingURL() throws Exception { - keycloakService = new KeycloakService(token, scope, token, null); - keycloakServiceClient.getIdentityProviderToken("github"); - - String accountLinkURL = - keycloakServiceClient.getAccountLinkingURL( - token, "github", "https://some-redirect-link/auth/realms/che/broker/github/endpoint"); - assertTrue( - accountLinkURL.matches( - "https://keycloak-che/realms/che/broker/github/link\\?nonce=([0-9a-z-]*)&hash=([0-9A-Za-z-_%]*)&client_id=some-client-id&redirect_uri=https://some-redirect-link/auth/realms/che/broker/github/endpoint")); - } - - @Test - public void shouldReturnToken() throws Exception { - String tokenType = "test_type"; - keycloakService = new KeycloakService(token, scope, tokenType, null); - KeycloakTokenResponse response = keycloakServiceClient.getIdentityProviderToken("github"); - assertNotNull(response); - assertEquals(response.getAccessToken(), token); - assertEquals(response.getScope(), scope); - assertEquals(response.getTokenType(), tokenType); - } - - @Test( - expectedExceptions = BadRequestException.class, - expectedExceptionsMessageRegExp = "Invalid token.") - public void shouldThrowBadRequestException() throws Exception { - keycloakService = - new KeycloakService(null, null, null, new BadRequestException("Invalid token.")); - keycloakServiceClient.getIdentityProviderToken("github"); - } - - @Test( - expectedExceptions = ForbiddenException.class, - expectedExceptionsMessageRegExp = "Forbidden.") - public void shouldThrowForbiddenException() throws Exception { - keycloakService = new KeycloakService(null, null, null, new ForbiddenException("Forbidden.")); - keycloakServiceClient.getIdentityProviderToken("github"); - } - - @Test( - expectedExceptions = UnauthorizedException.class, - expectedExceptionsMessageRegExp = "Unauthorized.") - public void shouldThrowUnauthorizedException() throws Exception { - keycloakService = - new KeycloakService(null, null, null, new UnauthorizedException("Unauthorized.")); - keycloakServiceClient.getIdentityProviderToken("github"); - } - - @Test( - expectedExceptions = IOException.class, - expectedExceptionsMessageRegExp = "Could not obtain token from identity provider.") - public void shouldThrowParse502ExceptionText() throws Exception { - keycloakService = new KeycloakService(null, null, null, new AuthenticationException("foo")); - keycloakServiceClient.getIdentityProviderToken("github"); - } - - @Test( - expectedExceptions = NotFoundException.class, - expectedExceptionsMessageRegExp = "Not found.") - public void shouldThrowNotFoundException() throws Exception { - keycloakService = new KeycloakService(null, null, null, new NotFoundException("Not found.")); - keycloakServiceClient.getIdentityProviderToken("github"); - } - - // Special case - @Test( - expectedExceptions = UnauthorizedException.class, - expectedExceptionsMessageRegExp = "User (.+) is not associated with identity provider (.+).") - public void shouldThrowUnauthorizedExceptionWhenNoProviderLink() throws Exception { - keycloakService = - new KeycloakService( - null, - null, - null, - new BadRequestException( - "User 1234-5678-90 is not associated with identity provider gitlab.")); - keycloakServiceClient.getIdentityProviderToken("github"); - } - - @Path("/realms/che") - public class KeycloakService extends Service { - - private String token; - private String scope; - private String tokenType; - private ApiException exception; - - public KeycloakService(String token, String scope, String tokenType, ApiException exception) { - this.token = token; - this.scope = scope; - this.tokenType = tokenType; - this.exception = exception; - } - - @GET - @Path("/broker/{provider}/token") - @Produces(APPLICATION_JSON) - public String getToken(@PathParam("provider") String provider) throws Exception { - if (exception == null) { - return "access_token=" + token + "&scope=" + scope + "&tokenType=" + tokenType; - } else { - throw exception; - } - } - } - - @Provider - public static class LocalApiExceptionMapper implements ExceptionMapper { - @Override - public Response toResponse(ApiException exception) { - - if (exception instanceof ForbiddenException) - return Response.status(FORBIDDEN) - .entity( - DtoFactory.getInstance() - .toJson( - newDto(KeycloakErrorResponse.class) - .withErrorMessage(exception.getServiceError().getMessage()))) - .type(MediaType.APPLICATION_JSON) - .build(); - else if (exception instanceof NotFoundException) - return Response.status(NOT_FOUND) - .entity( - DtoFactory.getInstance() - .toJson( - newDto(KeycloakErrorResponse.class) - .withErrorMessage(exception.getServiceError().getMessage()))) - .type(MediaType.APPLICATION_JSON) - .build(); - else if (exception instanceof UnauthorizedException) - return Response.status(UNAUTHORIZED) - .entity( - DtoFactory.getInstance() - .toJson( - newDto(KeycloakErrorResponse.class) - .withErrorMessage(exception.getServiceError().getMessage()))) - .type(MediaType.APPLICATION_JSON) - .build(); - else if (exception instanceof BadRequestException) - return Response.status(BAD_REQUEST) - .entity( - DtoFactory.getInstance() - .toJson( - newDto(KeycloakErrorResponse.class) - .withErrorMessage(exception.getServiceError().getMessage()))) - .type(MediaType.APPLICATION_JSON) - .build(); - else if (exception instanceof ServerException) - return Response.serverError() - .entity( - DtoFactory.getInstance() - .toJson( - newDto(KeycloakErrorResponse.class) - .withErrorMessage(exception.getServiceError().getMessage()))) - .type(MediaType.APPLICATION_JSON) - .build(); - else - return Response.status(BAD_GATEWAY) - .entity( - "\n" - + "\n" - + "
\n" - + "

Could not obtain token from identity provider.

\n" - + "
\n" - + "\n" - + "\n") - .type(MediaType.TEXT_HTML_TYPE) - .build(); - } - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSettingsTest.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSettingsTest.java deleted file mode 100644 index 428dbcca26d..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSettingsTest.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static org.eclipse.che.multiuser.keycloak.server.KeycloakSettings.DEFAULT_USERNAME_CLAIM; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.CLIENT_ID_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.FIXED_REDIRECT_URL_FOR_DASHBOARD; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.FIXED_REDIRECT_URL_FOR_IDE; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.GITHUB_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.JS_ADAPTER_URL_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.JWKS_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.LOGOUT_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.OSO_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.PASSWORD_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.PROFILE_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.TOKEN_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.USERINFO_ENDPOINT_SETTING; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.USE_NONCE_SETTING; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.AUTH_SERVER_URL_SETTING; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_PROVIDER_SETTING; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_USERNAME_CLAIM_SETTING; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; - -import java.util.Map; -import java.util.Optional; -import org.eclipse.che.multiuser.oidc.OIDCInfo; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** - * @author Ilya Buziuk - */ -@Listeners(value = {MockitoTestNGListener.class}) -public class KeycloakSettingsTest { - - @Mock private OIDCInfo oidcInfo; - - private static final String CHE_REALM = "che"; - private static final String CLIENT_ID = "che-public"; - private static final String PROFILE_URL_PATH = "/realms/" + CHE_REALM + "/account"; - private static final String LOGOUT_URL_PATH = - "/realms/" + CHE_REALM + "/protocol/openid-connect/logout"; - private static final String TOKEN_URL_PATH = - "/realms/" + CHE_REALM + "/protocol/openid-connect/token"; - private static final String USER_INFO_PATH = - "/realms/" + CHE_REALM + "/protocol/openid-connect/userinfo"; - private static final String PASSWORD_URL_PATH = "/realms/" + CHE_REALM + "/account/password"; - private static final String JWKS_ENDPOINT_PATH = - "/realms/" + CHE_REALM + "/protocol/openid-connect/certs"; - private static final String cheServerEndpoint = "https://test-crc-cluster.com.testing"; - - @Test - public void shouldBeSetGithubEndpointSettings() { - final String SERVER_AUTH_URL = "keycloak-che.apps-crc.testing/auth"; - final String GITHUB_ENDPOINT = "github.com/some/endpoint"; - - KeycloakSettings settings = - new KeycloakSettings( - null, - SERVER_AUTH_URL, - null, - CHE_REALM, - CLIENT_ID, - null, - null, - false, - null, - GITHUB_ENDPOINT, - false, - oidcInfo); - - assertEquals(settings.get().get(GITHUB_ENDPOINT_SETTING), GITHUB_ENDPOINT); - } - - @Test - public void shouldBeSetOSOEndpointSettings() { - final String SERVER_AUTH_URL = "https://keycloak-che.apps-crc.testing/auth"; - final String OSO_ENDPOINT = "oso/some/endpoint"; - - KeycloakSettings settings = - new KeycloakSettings( - null, - SERVER_AUTH_URL, - null, - CHE_REALM, - CLIENT_ID, - null, - null, - false, - OSO_ENDPOINT, - null, - false, - oidcInfo); - - assertEquals(settings.get().get(OSO_ENDPOINT_SETTING), OSO_ENDPOINT); - } - - @Test - public void shouldBeEnabledNonce() { - final String SERVER_AUTH_URL = "https://keycloak-che.apps-crc.testing/auth"; - final boolean USE_NONCE = true; - - KeycloakSettings settings = - new KeycloakSettings( - null, - SERVER_AUTH_URL, - null, - CHE_REALM, - CLIENT_ID, - null, - null, - USE_NONCE, - null, - null, - false, - oidcInfo); - - assertEquals(settings.get().get(USE_NONCE_SETTING), "true"); - } - - @Test - public void shouldConfigureKeycloakAdaptersUrl() { - final String SERVER_AUTH_URL = "https://external-keycloak-che.apps-crc.testing/auth"; - final String JS_ADAPTER_URL = "https://js/adapters/endpoint"; - - KeycloakSettings settings = - new KeycloakSettings( - cheServerEndpoint, - JS_ADAPTER_URL, - null, - CHE_REALM, - CLIENT_ID, - SERVER_AUTH_URL, - null, - false, - null, - null, - false, - oidcInfo); - - assertEquals(settings.get().get(JS_ADAPTER_URL_SETTING), JS_ADAPTER_URL); - } - - @Test - public void shouldBeUsedConfigurationFromExternalOIDCProviderWithFixedRedirectLinks() { - final String SERVER_AUTH_URL = "https://external-keycloak-che.apps-crc.testing/auth"; - - KeycloakSettings settings = - new KeycloakSettings( - cheServerEndpoint, - null, - null, - CHE_REALM, - CLIENT_ID, - SERVER_AUTH_URL, - null, - false, - null, - null, - true, - oidcInfo); - - Map publicSettings = settings.get(); - assertEquals(publicSettings.get(OIDC_PROVIDER_SETTING), SERVER_AUTH_URL); - assertEquals( - publicSettings.get(FIXED_REDIRECT_URL_FOR_DASHBOARD), - cheServerEndpoint + "/keycloak/oidcCallbackDashboard.html"); - assertEquals( - publicSettings.get(FIXED_REDIRECT_URL_FOR_IDE), - cheServerEndpoint + "/keycloak/oidcCallbackIde.html"); - assertEquals(publicSettings.get(JS_ADAPTER_URL_SETTING), "/api/keycloak/OIDCKeycloak.js"); - } - - @Test - public void shouldBeUsedConfigurationFromExternalOIDCProviderWithoutFixedRedirectLinks() { - final String SERVER_AUTH_URL = "https://external-keycloak-che.apps-crc.testing/auth"; - - when(oidcInfo.getEndSessionPublicEndpoint()) - .thenReturn(Optional.of(SERVER_AUTH_URL + LOGOUT_URL_PATH)); - when(oidcInfo.getJwksPublicUri()).thenReturn(SERVER_AUTH_URL + JWKS_ENDPOINT_PATH); - when(oidcInfo.getUserInfoPublicEndpoint()).thenReturn(SERVER_AUTH_URL + USER_INFO_PATH); - when(oidcInfo.getTokenPublicEndpoint()).thenReturn(SERVER_AUTH_URL + TOKEN_URL_PATH); - - KeycloakSettings settings = - new KeycloakSettings( - cheServerEndpoint, - null, - null, - CHE_REALM, - CLIENT_ID, - SERVER_AUTH_URL, - null, - false, - null, - null, - false, - oidcInfo); - - Map publicSettings = settings.get(); - assertEquals(publicSettings.get(OIDC_USERNAME_CLAIM_SETTING), DEFAULT_USERNAME_CLAIM); - assertEquals(publicSettings.get(CLIENT_ID_SETTING), CLIENT_ID); - assertEquals(publicSettings.get(REALM_SETTING), CHE_REALM); - assertNull(publicSettings.get(AUTH_SERVER_URL_SETTING)); - assertNull(publicSettings.get(PROFILE_ENDPOINT_SETTING)); - assertNull(publicSettings.get(PASSWORD_ENDPOINT_SETTING)); - assertEquals(publicSettings.get(LOGOUT_ENDPOINT_SETTING), SERVER_AUTH_URL + LOGOUT_URL_PATH); - assertEquals(publicSettings.get(TOKEN_ENDPOINT_SETTING), SERVER_AUTH_URL + TOKEN_URL_PATH); - assertEquals(publicSettings.get(USERINFO_ENDPOINT_SETTING), SERVER_AUTH_URL + USER_INFO_PATH); - assertEquals(publicSettings.get(JWKS_ENDPOINT_SETTING), SERVER_AUTH_URL + JWKS_ENDPOINT_PATH); - assertNull(publicSettings.get(OSO_ENDPOINT_SETTING)); - assertNull(publicSettings.get(GITHUB_ENDPOINT_SETTING)); - assertEquals(publicSettings.get(OIDC_PROVIDER_SETTING), SERVER_AUTH_URL); - assertNull(publicSettings.get(FIXED_REDIRECT_URL_FOR_DASHBOARD)); - assertNull(publicSettings.get(FIXED_REDIRECT_URL_FOR_IDE)); - assertEquals(publicSettings.get(USE_NONCE_SETTING), "false"); - assertEquals(publicSettings.get(JS_ADAPTER_URL_SETTING), "/api/keycloak/OIDCKeycloak.js"); - } - - @Test - public void shouldBeUsedConfigurationFromExternalAuthServer() { - final String SERVER_AUTH_URL = "https://keycloak-che.apps-crc.testing/auth"; - - when(oidcInfo.getEndSessionPublicEndpoint()) - .thenReturn(Optional.of(SERVER_AUTH_URL + LOGOUT_URL_PATH)); - when(oidcInfo.getJwksPublicUri()).thenReturn(SERVER_AUTH_URL + JWKS_ENDPOINT_PATH); - when(oidcInfo.getUserInfoPublicEndpoint()).thenReturn(SERVER_AUTH_URL + USER_INFO_PATH); - when(oidcInfo.getTokenPublicEndpoint()).thenReturn(SERVER_AUTH_URL + TOKEN_URL_PATH); - - KeycloakSettings settings = - new KeycloakSettings( - null, - null, - SERVER_AUTH_URL, - CHE_REALM, - CLIENT_ID, - null, - null, - false, - null, - null, - false, - oidcInfo); - - Map publicSettings = settings.get(); - assertEquals(publicSettings.get(OIDC_USERNAME_CLAIM_SETTING), DEFAULT_USERNAME_CLAIM); - assertEquals(publicSettings.get(CLIENT_ID_SETTING), CLIENT_ID); - assertEquals(publicSettings.get(REALM_SETTING), CHE_REALM); - assertEquals(publicSettings.get(AUTH_SERVER_URL_SETTING), SERVER_AUTH_URL); - assertEquals(publicSettings.get(PROFILE_ENDPOINT_SETTING), SERVER_AUTH_URL + PROFILE_URL_PATH); - assertEquals( - publicSettings.get(PASSWORD_ENDPOINT_SETTING), SERVER_AUTH_URL + PASSWORD_URL_PATH); - assertEquals(publicSettings.get(LOGOUT_ENDPOINT_SETTING), SERVER_AUTH_URL + LOGOUT_URL_PATH); - assertEquals(publicSettings.get(TOKEN_ENDPOINT_SETTING), SERVER_AUTH_URL + TOKEN_URL_PATH); - assertEquals(publicSettings.get(USERINFO_ENDPOINT_SETTING), SERVER_AUTH_URL + USER_INFO_PATH); - assertEquals(publicSettings.get(JWKS_ENDPOINT_SETTING), SERVER_AUTH_URL + JWKS_ENDPOINT_PATH); - assertNull(publicSettings.get(OSO_ENDPOINT_SETTING)); - assertNull(publicSettings.get(GITHUB_ENDPOINT_SETTING)); - assertNull(publicSettings.get(OIDC_PROVIDER_SETTING)); - assertNull(publicSettings.get(FIXED_REDIRECT_URL_FOR_DASHBOARD)); - assertNull(publicSettings.get(FIXED_REDIRECT_URL_FOR_IDE)); - assertEquals(publicSettings.get(USE_NONCE_SETTING), "false"); - assertEquals(publicSettings.get(JS_ADAPTER_URL_SETTING), SERVER_AUTH_URL + "/js/keycloak.js"); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSigningKeyResolverTest.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSigningKeyResolverTest.java deleted file mode 100644 index 97eda1d75f3..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakSigningKeyResolverTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2012-2026 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.keycloak.server; - -import static java.util.Collections.emptyMap; -import static org.eclipse.che.multiuser.machine.authentication.shared.Constants.MACHINE_TOKEN_KIND; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; - -import com.auth0.jwk.Jwk; -import com.auth0.jwk.JwkProvider; -import io.jsonwebtoken.JwtException; -import io.jsonwebtoken.impl.DefaultClaims; -import io.jsonwebtoken.impl.DefaultJwsHeader; -import java.security.Key; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.util.HashMap; -import java.util.Map; -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 KeycloakSigningKeyResolverTest { - - @Mock private JwkProvider jwkProvider; - - @InjectMocks private KeycloakSigningKeyResolver signingKeyResolver; - - @Test(expectedExceptions = MachineTokenJwtException.class) - public void shouldThrowMachineTokenExceptionOnMachineTokensWithPlainText() { - final Map param = new HashMap<>(); - param.put("kind", MACHINE_TOKEN_KIND); - DefaultJwsHeader header = new DefaultJwsHeader(param); - - signingKeyResolver.resolveSigningKey(header, "plaintext".getBytes()); - verifyNoMoreInteractions(jwkProvider); - } - - @Test(expectedExceptions = MachineTokenJwtException.class) - public void shouldThrowMachineTokenExceptionOnMachineTokensWithClaims() { - final Map param = new HashMap<>(); - param.put("kind", MACHINE_TOKEN_KIND); - DefaultJwsHeader header = new DefaultJwsHeader(param); - - signingKeyResolver.resolveSigningKey(header, new DefaultClaims(emptyMap())); - verifyNoMoreInteractions(jwkProvider); - } - - @Test(expectedExceptions = JwtException.class) - public void shouldThrowJwtExceptionifNoKeyIdHeader() { - - signingKeyResolver.resolveSigningKey(new DefaultJwsHeader(emptyMap()), "plaintext".getBytes()); - verifyNoMoreInteractions(jwkProvider); - } - - @Test - public void shouldReturnPublicKey() throws Exception { - final String kid = "123"; - final Jwk jwk = mock(Jwk.class); - final Map param = new HashMap<>(); - param.put("kid", kid); - final KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(1024); - final KeyPair keyPair = kpg.generateKeyPair(); - - when(jwk.getPublicKey()).thenReturn(keyPair.getPublic()); - when(jwkProvider.get(eq(kid))).thenReturn(jwk); - - Key actual = - signingKeyResolver.resolveSigningKey(new DefaultJwsHeader(param), "plaintext".getBytes()); - assertEquals(actual, keyPair.getPublic()); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfoProviderTest.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfoProviderTest.java deleted file mode 100644 index 8308e4a4d74..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfoProviderTest.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import org.eclipse.che.multiuser.oidc.OIDCInfo; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -public class OIDCInfoProviderTest { - private WireMockServer wireMockServer; - - private static final String CHE_REALM = "che"; - private static final String TEST_URL = "some-test-url-to-skip"; - - private String serverUrl; - private String openIdConfig; - - private static final String OPEN_ID_CONF_TEMPLATE = - "" - + "{" - + " \"token_endpoint\": \"" - + "" - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/token\"," - + " \"end_session_endpoint\": \"" - + "" - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/logout\"," - + " \"userinfo_endpoint\": \"" - + "" - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/userinfo\"," - + " \"jwks_uri\": \"" - + "" - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/certs\"" - + "}"; - - @BeforeClass - void start() { - wireMockServer = new WireMockServer(wireMockConfig().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - serverUrl = "http://localhost:" + wireMockServer.port() + "/auth"; - openIdConfig = OPEN_ID_CONF_TEMPLATE.replaceAll("", serverUrl); - } - - @AfterClass - void stop() { - if (wireMockServer != null) { - wireMockServer.stop(); - } - } - - @Test( - expectedExceptions = RuntimeException.class, - expectedExceptionsMessageRegExp = - "Exception while retrieving OpenId configuration from endpoint: .*") - public void shouldFailToParseOIDCConfiguration() { - stubFor( - get(urlEqualTo("/auth/realms/che/.well-known/openid-configuration")) - .willReturn( - aResponse().withHeader("Content-Type", "text/html").withBody("broken json"))); - - KeycloakOIDCInfoProvider oidcInfoProvider = - new KeycloakOIDCInfoProvider(null, null, serverUrl, CHE_REALM); - - oidcInfoProvider.get(); - } - - @Test - public void shouldParseOIDCConfigurationForServerUrl() { - stubFor( - get(urlEqualTo("/auth/realms/che/.well-known/openid-configuration")) - .willReturn( - aResponse().withHeader("Content-Type", "text/html").withBody(openIdConfig))); - - KeycloakOIDCInfoProvider oidcInfoProvider = - new KeycloakOIDCInfoProvider(serverUrl, null, null, CHE_REALM); - OIDCInfo oidcInfo = oidcInfoProvider.get(); - - assertEquals( - serverUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/token", - oidcInfo.getTokenPublicEndpoint()); - assertEquals( - serverUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/logout", - oidcInfo.getEndSessionPublicEndpoint().get()); - assertNull(oidcInfo.getUserInfoInternalEndpoint()); - assertNull(oidcInfo.getJwksInternalUri()); - } - - @Test - public void shouldParseOIDCConfigurationForInternalServerUrl() { - String serverPublicUrl = "che-eclipse-che.apps-crc.testing"; - String OPEN_ID_CONF_TEMPLATE = - "" - + "{" - + " \"token_endpoint\": \"" - + serverPublicUrl - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/token\"," - + " \"end_session_endpoint\": \"" - + serverPublicUrl - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/logout\"," - + " \"userinfo_endpoint\": \"" - + serverPublicUrl - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/userinfo\"," - + " \"jwks_uri\": \"" - + serverPublicUrl - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/certs\"" - + "}"; - - stubFor( - get(urlEqualTo("/auth/realms/che/.well-known/openid-configuration")) - .willReturn( - aResponse() - .withHeader("Content-Type", "text/html") - .withBody(OPEN_ID_CONF_TEMPLATE))); - - KeycloakOIDCInfoProvider oidcInfoProvider = - new KeycloakOIDCInfoProvider(serverPublicUrl, serverUrl, null, CHE_REALM); - OIDCInfo oidcInfo = oidcInfoProvider.get(); - - assertEquals( - serverPublicUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/token", - oidcInfo.getTokenPublicEndpoint()); - assertEquals( - serverPublicUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/logout", - oidcInfo.getEndSessionPublicEndpoint().get()); - assertEquals( - serverPublicUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/userinfo", - oidcInfo.getUserInfoPublicEndpoint()); - assertEquals( - serverPublicUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/certs", - oidcInfo.getJwksPublicUri()); - - assertEquals( - serverUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/certs", - oidcInfo.getJwksInternalUri()); - assertEquals( - serverUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/userinfo", - oidcInfo.getUserInfoInternalEndpoint()); - assertEquals(serverUrl, oidcInfo.getAuthServerURL()); - } - - @Test - public void shouldParseOIDCConfigurationWithPublicUrlsForInternalServerUrl() { - String serverPublicUrl = "https://keycloak-che.domain/auth"; - String serverInternalUrl = serverUrl; - - String OPEN_ID_CONF_TEMPLATE = - "" - + "{" - + " \"token_endpoint\": \"" - + serverInternalUrl - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/token\"," - + " \"end_session_endpoint\": \"" - + serverInternalUrl - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/logout\"," - + " \"userinfo_endpoint\": \"" - + serverInternalUrl - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/userinfo\"," - + " \"jwks_uri\": \"" - + serverInternalUrl - + "/realms/" - + CHE_REALM - + "/protocol/openid-connect/certs\"" - + "}"; - - stubFor( - get(urlEqualTo("/auth/realms/che/.well-known/openid-configuration")) - .willReturn( - aResponse() - .withHeader("Content-Type", "text/html") - .withBody(OPEN_ID_CONF_TEMPLATE))); - - KeycloakOIDCInfoProvider oidcInfoProvider = - new KeycloakOIDCInfoProvider(serverPublicUrl, serverInternalUrl, null, CHE_REALM); - OIDCInfo oidcInfo = oidcInfoProvider.get(); - - assertEquals( - serverPublicUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/token", - oidcInfo.getTokenPublicEndpoint()); - assertEquals( - serverPublicUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/logout", - oidcInfo.getEndSessionPublicEndpoint().get()); - assertEquals( - serverPublicUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/userinfo", - oidcInfo.getUserInfoPublicEndpoint()); - assertEquals( - serverPublicUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/certs", - oidcInfo.getJwksPublicUri()); - - assertEquals( - serverInternalUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/certs", - oidcInfo.getJwksInternalUri()); - assertEquals( - serverInternalUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/userinfo", - oidcInfo.getUserInfoInternalEndpoint()); - - assertEquals(serverInternalUrl, oidcInfo.getAuthServerURL()); - assertEquals(serverPublicUrl, oidcInfo.getAuthServerPublicURL()); - } - - @Test - public void shouldParseOIDCConfigurationForOIDCProviderUrl() { - String OIDCProviderUrl = "http://localhost:" + wireMockServer.port() + "/realms/"; - stubFor( - get(urlEqualTo("/realms/.well-known/openid-configuration")) - .willReturn( - aResponse().withHeader("Content-Type", "text/html").withBody(openIdConfig))); - - KeycloakOIDCInfoProvider oidcInfoProvider = - new KeycloakOIDCInfoProvider(TEST_URL, TEST_URL, OIDCProviderUrl, CHE_REALM); - OIDCInfo oidcInfo = oidcInfoProvider.get(); - - assertEquals( - serverUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/token", - oidcInfo.getTokenPublicEndpoint()); - assertEquals( - serverUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/logout", - oidcInfo.getEndSessionPublicEndpoint().get()); - assertEquals( - serverUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/userinfo", - oidcInfo.getUserInfoInternalEndpoint()); - assertEquals( - serverUrl + "/realms/" + CHE_REALM + "/protocol/openid-connect/certs", - oidcInfo.getJwksInternalUri()); - } - - @Test( - expectedExceptions = RuntimeException.class, - expectedExceptionsMessageRegExp = "Either the '.*' or '.*' or '.*' property should be set") - public void shouldThrowErrorWhenAuthServerWasNotSet() { - KeycloakOIDCInfoProvider oidcInfoProvider = - new KeycloakOIDCInfoProvider(null, null, null, CHE_REALM); - oidcInfoProvider.get(); - } - - @Test( - expectedExceptions = RuntimeException.class, - expectedExceptionsMessageRegExp = "The '.*' property must be set") - public void shouldThrowErrorWhenRealmPropertyWasNotSet() { - KeycloakOIDCInfoProvider oidcInfoProvider = - new KeycloakOIDCInfoProvider(null, null, null, null); - oidcInfoProvider.get(); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/UnavailableResourceInMultiUserFilterTest.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/UnavailableResourceInMultiUserFilterTest.java deleted file mode 100644 index 7cba8798d87..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/UnavailableResourceInMultiUserFilterTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static io.restassured.RestAssured.given; -import static org.eclipse.che.multiuser.keycloak.server.UnavailableResourceInMultiUserFilter.ERROR_RESPONSE_JSON_MESSAGE; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotEquals; - -import io.restassured.response.Response; -import org.everrest.assured.EverrestJetty; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class}) -public class UnavailableResourceInMultiUserFilterTest { - @SuppressWarnings("unused") - private static final UnavailableResourceInMultiUserFilter FILTER = - new UnavailableResourceInMultiUserFilter(); - - @Test(dataProvider = "allowedRequests") - public void shouldAllowGetRequests(String url) { - final Response response = given().when().get(url); - - assertNotEquals(response.getStatusCode(), 403); - assertNotEquals(response.getBody().print().trim(), ERROR_RESPONSE_JSON_MESSAGE); - } - - @Test - public void shouldReturnForbiddenResponseForUserDeletion() { - - final Response response = given().when().delete("/user/123"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(response.getBody().print().trim(), ERROR_RESPONSE_JSON_MESSAGE); - } - - @Test - public void shouldReturnForbiddenResponseForUserPasswordUpdate() { - - final Response response = given().when().post("/user/password"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(response.getBody().print().trim(), ERROR_RESPONSE_JSON_MESSAGE); - } - - @Test - public void shouldReturnForbiddenResponseForCurrentUserProfileUpdate() { - - final Response response = given().when().post("/profile/attributes"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(response.getBody().print().trim(), ERROR_RESPONSE_JSON_MESSAGE); - } - - @Test - public void shouldReturnForbiddenResponseFortUserProfileUpdate() { - - final Response response = given().when().post("/profile/profile123/attributes"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(response.getBody().print().trim(), ERROR_RESPONSE_JSON_MESSAGE); - } - - @Test - public void shouldReturnForbiddenResponseForCurrentUserProfileDelete() { - - final Response response = given().when().delete("/profile/attributes"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(response.getBody().print().trim(), ERROR_RESPONSE_JSON_MESSAGE); - } - - @DataProvider(name = "allowedRequests") - public Object[][] allowedRequests() { - return new Object[][] { - {"/user"}, - {"/user/"}, - {"/user/user123"}, - {"/user/find"}, - {"/user/settings"}, - {"/profile"}, - {"/profile/profile123"} - }; - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakServletModuleTest.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakServletModuleTest.java deleted file mode 100644 index cc5c1fe8e6c..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/deploy/KeycloakServletModuleTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server.deploy; - -import java.util.regex.Pattern; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -public class KeycloakServletModuleTest { - private static final Pattern KEYCLOAK_FILTER_PATHS_PATTERN = - Pattern.compile(KeycloakServletModule.KEYCLOAK_FILTER_PATHS); - - @Test(dataProvider = "allowedRequests") - public void shouldSkipOpenApi(String url) { - Assert.assertFalse(KEYCLOAK_FILTER_PATHS_PATTERN.matcher(url).matches()); - } - - @DataProvider(name = "allowedRequests") - public Object[][] allowedRequests() { - return new Object[][] { - {"/keycloak/OIDCKeycloak.js"}, - {"/openapi.json"}, - {"/oauth/callback/"}, - {"/oauth/callback/"}, - {"/system/state"} - }; - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/resources/logback-test.xml b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/resources/logback-test.xml deleted file mode 100644 index 5396bf41370..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/resources/logback-test.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n - - - - - target/log/log.log - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n - - - - - - - - - - diff --git a/multiuser/keycloak/che-multiuser-keycloak-shared/pom.xml b/multiuser/keycloak/che-multiuser-keycloak-shared/pom.xml deleted file mode 100644 index 16e78e0d202..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-shared/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - 4.0.0 - - che-multiuser-keycloak - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-keycloak-shared - jar - Che Multiuser :: Keycloak Shared module - - - org.eclipse.che.core - che-core-api-dto - - - jakarta.servlet - jakarta.servlet-api - provided - - - diff --git a/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/KeycloakConstants.java b/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/KeycloakConstants.java deleted file mode 100644 index c71a1f661fb..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/KeycloakConstants.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.shared; - -/** - * @author Max Shaposhnik (mshaposh@redhat.com) - */ -public class KeycloakConstants { - - private static final String KEYCLOAK_SETTING_PREFIX = "che.keycloak."; - - public static final String REALM_SETTING = KEYCLOAK_SETTING_PREFIX + "realm"; - public static final String CLIENT_ID_SETTING = KEYCLOAK_SETTING_PREFIX + "client_id"; - public static final String USE_NONCE_SETTING = KEYCLOAK_SETTING_PREFIX + "use_nonce"; - public static final String USE_FIXED_REDIRECT_URLS_SETTING = - KEYCLOAK_SETTING_PREFIX + "use_fixed_redirect_urls"; - public static final String JS_ADAPTER_URL_SETTING = KEYCLOAK_SETTING_PREFIX + "js_adapter_url"; - - public static final String OSO_ENDPOINT_SETTING = KEYCLOAK_SETTING_PREFIX + "oso.endpoint"; - public static final String PROFILE_ENDPOINT_SETTING = - KEYCLOAK_SETTING_PREFIX + "profile.endpoint"; - public static final String PASSWORD_ENDPOINT_SETTING = - KEYCLOAK_SETTING_PREFIX + "password.endpoint"; - public static final String LOGOUT_ENDPOINT_SETTING = KEYCLOAK_SETTING_PREFIX + "logout.endpoint"; - public static final String TOKEN_ENDPOINT_SETTING = KEYCLOAK_SETTING_PREFIX + "token.endpoint"; - public static final String JWKS_ENDPOINT_SETTING = KEYCLOAK_SETTING_PREFIX + "jwks.endpoint"; - public static final String USERINFO_ENDPOINT_SETTING = - KEYCLOAK_SETTING_PREFIX + "userinfo.endpoint"; - public static final String GITHUB_ENDPOINT_SETTING = KEYCLOAK_SETTING_PREFIX + "github.endpoint"; - - public static final String FIXED_REDIRECT_URL_FOR_DASHBOARD = - KEYCLOAK_SETTING_PREFIX + "redirect_url.dashboard"; - public static final String FIXED_REDIRECT_URL_FOR_IDE = - KEYCLOAK_SETTING_PREFIX + "redirect_url.ide"; -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/dto/KeycloakErrorResponse.java b/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/dto/KeycloakErrorResponse.java deleted file mode 100644 index 4b180b4fecf..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/dto/KeycloakErrorResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.shared.dto; - -import org.eclipse.che.dto.shared.DTO; - -/** - * @author Max Shaposhnik (mshaposh@redhat.com) - */ -@DTO -public interface KeycloakErrorResponse { - - String getErrorMessage(); - - void setErrorMessage(String errorMessage); - - KeycloakErrorResponse withErrorMessage(String errorMessage); -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/dto/KeycloakTokenResponse.java b/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/dto/KeycloakTokenResponse.java deleted file mode 100644 index 05305a791c2..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-shared/src/main/java/org/eclipse/che/multiuser/keycloak/shared/dto/KeycloakTokenResponse.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.shared.dto; - -import org.eclipse.che.dto.shared.DTO; -import org.eclipse.che.dto.shared.JsonFieldName; - -/** - * @author Max Shaposhnik (mshaposh@redhat.com) - */ -@DTO -public interface KeycloakTokenResponse { - - @JsonFieldName("access_token") - String getAccessToken(); - - void setAccessToken(String accessToken); - - KeycloakTokenResponse withAccessToken(String accessToken); - - String getTokenType(); - - void setTokenType(String tokenType); - - KeycloakTokenResponse withTokenType(String tokenType); - - String getScope(); - - void setScope(String scope); - - KeycloakTokenResponse withScope(String scope); -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/pom.xml b/multiuser/keycloak/che-multiuser-keycloak-token-provider/pom.xml deleted file mode 100644 index 96c64ba3610..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - 4.0.0 - - che-multiuser-keycloak - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-keycloak-token-provider - Che Multiuser :: Keycloak Token Provider - - - com.fasterxml.jackson.core - jackson-databind - - - com.google.guava - guava - - - com.google.http-client - google-http-client - - - com.google.inject - guice - - - com.google.oauth-client - google-oauth-client - - - jakarta.inject - jakarta.inject-api - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.apache.commons - commons-lang3 - - - org.eclipse.che.core - che-core-api-auth - - - org.eclipse.che.core - che-core-api-auth-github-common - - - org.eclipse.che.core - che-core-api-auth-shared - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-commons-annotations - - - org.eclipse.che.core - che-core-commons-inject - - - junit - junit - test - - - diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/contoller/TokenController.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/contoller/TokenController.java deleted file mode 100644 index c1be01f8a25..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/contoller/TokenController.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.contoller; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.HeaderParam; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import java.io.IOException; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; -import org.eclipse.che.api.core.BadRequestException; -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.api.core.UnauthorizedException; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.multiuser.keycloak.token.provider.exception.KeycloakException; -import org.eclipse.che.multiuser.keycloak.token.provider.oauth.OpenShiftGitHubOAuthAuthenticator; -import org.eclipse.che.multiuser.keycloak.token.provider.service.KeycloakTokenProvider; -import org.eclipse.che.multiuser.keycloak.token.provider.validator.KeycloakTokenValidator; -import org.eclipse.che.security.oauth.OAuthAuthenticator; -import org.eclipse.che.security.oauth.OAuthAuthenticatorProvider; - -@Path("/token") -@Singleton -public class TokenController { - private static final String GIT_HUB_OAUTH_PROVIDER = "github"; - - @Inject private KeycloakTokenProvider tokenProvider; - - @Inject private KeycloakTokenValidator validator; - - @Inject protected OAuthAuthenticatorProvider providers; - - @POST - @Path("/github") - @Consumes(MediaType.APPLICATION_JSON) - public void setGitHubToken(OAuthToken token) throws ServerException { - - if (token == null) { - throw new ServerException("No token provided"); - } - - OAuthAuthenticator provider = providers.getAuthenticator(GIT_HUB_OAUTH_PROVIDER); - - if (provider == null) { - throw new ServerException("\"" + GIT_HUB_OAUTH_PROVIDER + "\" oauth provider not registered"); - } else if (!(provider instanceof OpenShiftGitHubOAuthAuthenticator)) { - throw new ServerException( - "'setToken' API is not supported by the original 'GitHubOAuthAuthenticator', 'OpenShiftGitHubOAuthAuthenticator' should be configured instead"); - } - - String userId = EnvironmentContext.getCurrent().getSubject().getUserId(); - - try { - ((OpenShiftGitHubOAuthAuthenticator) provider).setToken(userId, token); - } catch (IOException e) { - throw new ServerException(e.getMessage()); - } - } - - @GET - @Path("/github") - public Response getGitHubToken(@HeaderParam(HttpHeaders.AUTHORIZATION) String keycloakToken) - throws ForbiddenException, - NotFoundException, - ConflictException, - BadRequestException, - ServerException, - UnauthorizedException, - IOException { - String token = null; - try { - validator.validate(keycloakToken); - token = tokenProvider.obtainGitHubToken(keycloakToken); - } catch (KeycloakException e) { - return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build(); - } - return Response.ok(token).build(); - } - - @GET - @Path("/oso") - public Response getOpenShiftToken(@HeaderParam(HttpHeaders.AUTHORIZATION) String keycloakToken) - throws ForbiddenException, - NotFoundException, - ConflictException, - BadRequestException, - ServerException, - UnauthorizedException, - IOException { - String token = null; - try { - validator.validate(keycloakToken); - token = tokenProvider.obtainOsoToken(keycloakToken); - } catch (KeycloakException e) { - return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build(); - } - return Response.ok(token).build(); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/deploy/KeycloakModule.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/deploy/KeycloakModule.java deleted file mode 100644 index 6ff78b7b492..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/deploy/KeycloakModule.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.deploy; - -import com.google.inject.AbstractModule; -import org.eclipse.che.inject.DynaModule; - -@DynaModule -public class KeycloakModule extends AbstractModule { - @Override - protected void configure() { - bind(org.eclipse.che.multiuser.keycloak.token.provider.contoller.TokenController.class); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/exception/KeycloakException.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/exception/KeycloakException.java deleted file mode 100644 index a91bbb20f01..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/exception/KeycloakException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.exception; - -public class KeycloakException extends Exception { - - private static final long serialVersionUID = 1L; - - public KeycloakException() {} - - public KeycloakException(String message) { - super(message); - } - - public KeycloakException(Throwable cause) { - super(cause); - } - - public KeycloakException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/oauth/OpenShiftGitHubOAuthAuthenticator.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/oauth/OpenShiftGitHubOAuthAuthenticator.java deleted file mode 100644 index 673227927bd..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/oauth/OpenShiftGitHubOAuthAuthenticator.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.oauth; - -import static com.google.common.base.Strings.isNullOrEmpty; - -import com.google.api.client.auth.oauth2.TokenResponse; -import com.google.api.client.util.store.MemoryDataStoreFactory; -import java.io.IOException; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -import org.eclipse.che.api.auth.shared.dto.OAuthToken; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.security.oauth.GitHubOAuthAuthenticator; - -@Singleton -public class OpenShiftGitHubOAuthAuthenticator extends GitHubOAuthAuthenticator { - - @Inject - public OpenShiftGitHubOAuthAuthenticator( - @Nullable @Named("che.oauth.github.redirecturis") String[] redirectUris, - @Nullable @Named("che.oauth.github.authuri") String authUri, - @Nullable @Named("che.oauth.github.tokenuri") String tokenUri) - throws IOException { - - super("NULL", "NULL", redirectUris, null, authUri, tokenUri, "github"); - - if (!isNullOrEmpty(authUri) - && !isNullOrEmpty(tokenUri) - && redirectUris != null - && redirectUris.length != 0) { - - configure("NULL", "NULL", redirectUris, authUri, tokenUri, new MemoryDataStoreFactory()); - } - } - - public void setToken(String userId, OAuthToken token) throws IOException { - flow.createAndStoreCredential( - new TokenResponse().setAccessToken(token.getToken()).setScope(token.getScope()), userId); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/service/KeycloakTokenProvider.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/service/KeycloakTokenProvider.java deleted file mode 100644 index 9af27f4d30c..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/service/KeycloakTokenProvider.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.service; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.util.Map; -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.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.api.core.UnauthorizedException; -import org.eclipse.che.api.core.rest.HttpJsonRequestFactory; -import org.eclipse.che.api.core.rest.HttpJsonResponse; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.multiuser.keycloak.token.provider.util.UrlHelper; - -@Singleton -public class KeycloakTokenProvider { - private static final String ACCESS_TOKEN = "access_token"; - private final String gitHubEndpoint; - private final String openShiftEndpoint; - - private final HttpJsonRequestFactory httpJsonRequestFactory; - - @Inject - public KeycloakTokenProvider( - @Nullable @Named("che.keycloak.github.endpoint") String gitHubEndpoint, - @Nullable @Named("che.keycloak.oso.endpoint") String openShiftEndpoint, - HttpJsonRequestFactory httpJsonRequestFactory) { - this.gitHubEndpoint = gitHubEndpoint; - this.openShiftEndpoint = openShiftEndpoint; - this.httpJsonRequestFactory = httpJsonRequestFactory; - } - - /** - * Return GitHub access token based on Keycloak token - * - *

Note: valid response from keycloak endpoint: - * access_token=token&scope=scope&token_type=bearer - * - * @param keycloakToken - * @return GitHub access token - * @throws IOException - * @throws BadRequestException - * @throws ConflictException - * @throws NotFoundException - * @throws ForbiddenException - * @throws UnauthorizedException - * @throws ServerException - */ - public String obtainGitHubToken(String keycloakToken) - throws ServerException, - UnauthorizedException, - ForbiddenException, - NotFoundException, - ConflictException, - BadRequestException, - IOException { - String responseBody = getResponseBody(gitHubEndpoint, keycloakToken); - Map parameter = UrlHelper.splitQuery(responseBody); - String token = parameter.get(ACCESS_TOKEN); - return token; - } - - /** - * Return OpenShift online token based on Keycloak token - * - *

Note: valid response from keycloak endpoint: - * {"access_token":"token","expires_in":86400,"scope":"user:full","token_type":"Bearer"} - * - * @param keycloakToken - * @return OpenShift online token - * @throws BadRequestException - * @throws ConflictException - * @throws NotFoundException - * @throws ForbiddenException - * @throws UnauthorizedException - * @throws ServerException - */ - public String obtainOsoToken(String keycloakToken) - throws IOException, - ServerException, - UnauthorizedException, - ForbiddenException, - NotFoundException, - ConflictException, - BadRequestException { - String responseBody = getResponseBody(openShiftEndpoint, keycloakToken); - ObjectMapper mapper = new ObjectMapper(); - JsonNode json = mapper.readTree(responseBody); - JsonNode token = json.get(ACCESS_TOKEN); - return token.asText(); - } - - private String getResponseBody(final String endpoint, final String keycloakToken) - throws ServerException, - UnauthorizedException, - ForbiddenException, - NotFoundException, - ConflictException, - BadRequestException, - IOException { - HttpJsonResponse request = - httpJsonRequestFactory - .fromUrl(endpoint) - .setMethod("GET") - .setAuthorizationHeader(keycloakToken) - .request(); - return request.asString(); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/util/UrlHelper.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/util/UrlHelper.java deleted file mode 100644 index 9fbf28b9b9e..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/util/UrlHelper.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.util; - -import java.util.HashMap; -import java.util.Map; - -public final class UrlHelper { - - private UrlHelper() {} - - public static Map splitQuery(String query) { - Map queryPairs = new HashMap(); - String[] pairs = query.split("&"); - for (String pair : pairs) { - int delimiterIndex = pair.indexOf("="); - queryPairs.put(pair.substring(0, delimiterIndex), pair.substring(delimiterIndex + 1)); - } - return queryPairs; - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/validator/KeycloakTokenValidator.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/validator/KeycloakTokenValidator.java deleted file mode 100644 index 10633fd41d1..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/main/java/org/eclipse/che/multiuser/keycloak/token/provider/validator/KeycloakTokenValidator.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.validator; - -import javax.inject.Singleton; -import org.apache.commons.lang3.StringUtils; -import org.eclipse.che.multiuser.keycloak.token.provider.exception.KeycloakException; - -@Singleton -public class KeycloakTokenValidator { - private static final String BEARER_PREFIX = "Bearer "; - - public void validate(final String keycloakToken) throws KeycloakException { - if (!isValid(keycloakToken)) { - throw new KeycloakException("Keycloak token must have '" + BEARER_PREFIX + "' prefix"); - } - } - - private boolean isValid(final String keycloakToken) { - return (StringUtils.isNotBlank(keycloakToken) && keycloakToken.startsWith(BEARER_PREFIX)); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/test/java/org/eclipse/che/multiuser/keycloak/token/provider/util/UrlHelperTest.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/test/java/org/eclipse/che/multiuser/keycloak/token/provider/util/UrlHelperTest.java deleted file mode 100644 index 3da837c4cbf..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/test/java/org/eclipse/che/multiuser/keycloak/token/provider/util/UrlHelperTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.util; - -import static org.junit.Assert.assertEquals; - -import java.util.Map; -import org.junit.Test; - -public class UrlHelperTest { - private static final String TOKEN = "kjhKJhLKJHSLKJDHDSKJAHLKAHSdshjs"; - private static final String SCOPE = "scope"; - private static final String RESPONSE_BODY = "access_token=" + TOKEN + "&scope=" + SCOPE; - private static final String ACCESS_TOKEN = "access_token"; - - @Test - public void processQuery() { - Map parameters = UrlHelper.splitQuery(RESPONSE_BODY); - String token = parameters.get(ACCESS_TOKEN); - String scope = parameters.get(SCOPE); - assertEquals(token, TOKEN); - assertEquals(scope, SCOPE); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/test/java/org/eclipse/che/multiuser/keycloak/token/provider/validator/KeycloakTokenValidatorTest.java b/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/test/java/org/eclipse/che/multiuser/keycloak/token/provider/validator/KeycloakTokenValidatorTest.java deleted file mode 100644 index f53fe2fa73a..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-token-provider/src/test/java/org/eclipse/che/multiuser/keycloak/token/provider/validator/KeycloakTokenValidatorTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.token.provider.validator; - -import org.eclipse.che.multiuser.keycloak.token.provider.exception.KeycloakException; -import org.junit.BeforeClass; -import org.junit.Test; - -public class KeycloakTokenValidatorTest { - private static final String VALID_TOKEN = "Bearer token"; - private static final String INVALID_TOKEN = "token"; - private static KeycloakTokenValidator keycloakTokenValidator; - - @BeforeClass - public static void init() { - keycloakTokenValidator = new KeycloakTokenValidator(); - } - - @Test - public void processValidToken() throws KeycloakException { - keycloakTokenValidator.validate(VALID_TOKEN); - } - - @Test(expected = KeycloakException.class) - public void processInvalidToken() throws KeycloakException { - keycloakTokenValidator.validate(INVALID_TOKEN); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-user-remover/pom.xml b/multiuser/keycloak/che-multiuser-keycloak-user-remover/pom.xml deleted file mode 100644 index 24ca069464c..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-user-remover/pom.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - - 4.0.0 - - che-multiuser-keycloak - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-keycloak-user-remover - jar - Che Multiuser :: Remove User from Keycloak Server - - - com.google.code.gson - gson - - - com.google.guava - guava - - - jakarta.inject - jakarta.inject-api - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-commons-annotations - - - org.eclipse.che.core - che-core-commons-inject - - - org.eclipse.che.core - che-core-commons-lang - - - org.eclipse.che.multiuser - che-multiuser-keycloak-server - - - org.eclipse.che.multiuser - che-multiuser-keycloak-shared - - - org.eclipse.che.multiuser - che-multiuser-oidc - - - org.slf4j - slf4j-api - - - jakarta.servlet - jakarta.servlet-api - provided - - - com.github.tomakehurst - wiremock-jre8-standalone - test - - - io.rest-assured - rest-assured - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - org.wiremock - wiremock-standalone - test - - - diff --git a/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakPasswordGrantTokenRequester.java b/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakPasswordGrantTokenRequester.java deleted file mode 100644 index 9a0029b284d..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakPasswordGrantTokenRequester.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static jakarta.ws.rs.HttpMethod.POST; -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MediaType; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import javax.inject.Singleton; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.commons.lang.IoUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Requests the Keycloak access token with grant_type=password, using a Keycloak username, password, - * and token endpoint. - */ -@Singleton -public class KeycloakPasswordGrantTokenRequester { - - private static final Logger LOG = - LoggerFactory.getLogger(KeycloakPasswordGrantTokenRequester.class); - - private static final String GRANT_TYPE = "grant_type"; - private static final String GRANT_TYPE_VALUE = "password"; - private static final String USERNAME = "username"; - private static final String PASSWORD = "password"; - private static final String CLIENT_ID = "client_id"; - private static final String CLIENT_ID_VALUE = "admin-cli"; - private static final String ACCESS_TOKEN = "access_token"; - - /** - * Requests the Keycloak access token with grant_type=password for the provided Keycloak user, - * password, and token endpoint. - * - * @param keycloakUser the Keycloak user - * @param keycloakPassword the Keycloak password - * @param keycloakTokenEndpoint the Keycloak token endpoint - * @return Keycloak access token - * @throws ServerException when any server error occurs while performing the request - * @throws IOException when an IO error occurs while connecting to the server - * @throws JsonSyntaxException when an error occurs while parsing JSON response - */ - public String requestToken( - String keycloakUser, String keycloakPassword, String keycloakTokenEndpoint) - throws ServerException, IOException, JsonSyntaxException { - - String accessToken = ""; - HttpURLConnection http = null; - try { - http = createURLConnection(keycloakUser, keycloakPassword, keycloakTokenEndpoint); - checkResponseCode(http, keycloakTokenEndpoint); - - final BufferedReader response = - new BufferedReader(new InputStreamReader(http.getInputStream(), UTF_8)); - accessToken = getAccessToken(response); - - } catch (IOException | JsonSyntaxException ex) { - throw ex; - } finally { - if (http != null) { - http.disconnect(); - } - } - return accessToken; - } - - private HttpURLConnection createURLConnection( - String keycloakUser, String keycloakPassword, String keycloakTokenEndpoint) - throws IOException { - HttpURLConnection http = (HttpURLConnection) new URL(keycloakTokenEndpoint).openConnection(); - http.setConnectTimeout(60000); - http.setReadTimeout(60000); - http.setRequestMethod(POST); - http.setAllowUserInteraction(false); - http.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); - http.setInstanceFollowRedirects(true); - http.setDoOutput(true); - StringBuilder sb = new StringBuilder(); - sb.append(GRANT_TYPE + "=" + GRANT_TYPE_VALUE) - .append("&" + USERNAME + "=") - .append(keycloakUser) - .append("&" + PASSWORD + "=") - .append(keycloakPassword) - .append("&" + CLIENT_ID + "=" + CLIENT_ID_VALUE); - - try (OutputStream output = http.getOutputStream()) { - output.write(sb.toString().getBytes(UTF_8)); - } - return http; - } - - private void checkResponseCode(HttpURLConnection http, String keycloakTokenEndpoint) - throws IOException, ServerException { - if (http.getResponseCode() != 200) { - throw new ServerException( - "Cannot get Keycloak access token. Server response: " - + keycloakTokenEndpoint - + " " - + http.getResponseCode() - + IoUtil.readStream(http.getErrorStream())); - } - } - - private String getAccessToken(BufferedReader response) - throws ServerException, JsonSyntaxException { - JsonParser jsonParser = new JsonParser(); - JsonElement jsonElement = jsonParser.parse(response); - JsonObject asJsonObject = jsonElement.getAsJsonObject(); - if (!asJsonObject.has(ACCESS_TOKEN)) { - throw new ServerException("Keycloak access token does not exist."); - } - return asJsonObject.get(ACCESS_TOKEN).getAsString(); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserRemover.java b/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserRemover.java deleted file mode 100644 index dd20cc33571..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserRemover.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.AUTH_SERVER_URL_INTERNAL_SETTING; -import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.AUTH_SERVER_URL_SETTING; - -import com.google.common.base.Strings; -import com.google.gson.JsonSyntaxException; -import java.io.IOException; -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.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.rest.HttpJsonRequestFactory; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.inject.ConfigurationException; -import org.eclipse.che.multiuser.oidc.OIDCInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Remove user from Keycloak server on {@link - * org.eclipse.che.api.user.server.event.BeforeUserRemovedEvent}. Turn on with {@code - * che.keycloak.cascade_user_removal_enabled} property. - * - *

For correct work need to set keycloak admin credentials via {@code - * che.keycloak.admin_username} and {@code che.keycloak.admin_password} properties. - */ -@Singleton -public class KeycloakUserRemover { - private static final Logger LOG = LoggerFactory.getLogger(KeycloakUserRemover.class); - - private final String keycloakUser; - private final String keycloakPassword; - private final KeycloakPasswordGrantTokenRequester keycloakTokenRequester; - private final HttpJsonRequestFactory requestFactory; - - private String keycloakRemoveUserUrl; - private String keycloakTokenEndpoint; - - @Inject - public KeycloakUserRemover( - @Nullable @Named("che.keycloak.cascade_user_removal_enabled") boolean userRemovalEnabled, - @Nullable @Named("che.keycloak.admin_username") String keycloakUser, - @Nullable @Named("che.keycloak.admin_password") String keycloakPassword, - KeycloakSettings keycloakSettings, - KeycloakPasswordGrantTokenRequester keycloakTokenRequester, - OIDCInfo oidcInfo, - HttpJsonRequestFactory requestFactory) { - this.keycloakUser = keycloakUser; - this.keycloakPassword = keycloakPassword; - this.keycloakTokenRequester = keycloakTokenRequester; - this.requestFactory = requestFactory; - - if (userRemovalEnabled) { - String serverUrl = oidcInfo.getAuthServerURL(); - if (serverUrl == null) { - throw new ConfigurationException( - AUTH_SERVER_URL_SETTING - + " or " - + AUTH_SERVER_URL_INTERNAL_SETTING - + " is not configured"); - } - String realm = keycloakSettings.get().get(REALM_SETTING); - if (realm == null) { - throw new ConfigurationException(REALM_SETTING + " is not configured"); - } - if (Strings.isNullOrEmpty(keycloakUser) || Strings.isNullOrEmpty(keycloakPassword)) { - throw new ConfigurationException("Keycloak administrator username or password not set."); - } - this.keycloakTokenEndpoint = serverUrl + "/realms/master/protocol/openid-connect/token"; - this.keycloakRemoveUserUrl = serverUrl + "/admin/realms/" + realm + "/users/"; - } - } - - /** - * Remove user from Keycloak server by given user id. - * - * @param userId the user id to remove - * @throws ServerException when user exists, but could not be removed from Keycloak - */ - public void removeUserFromKeycloak(String userId) - throws ServerException, IOException, JsonSyntaxException { - - String token = - keycloakTokenRequester.requestToken(keycloakUser, keycloakPassword, keycloakTokenEndpoint); - - try { - int responseCode = - requestFactory - .fromUrl(keycloakRemoveUserUrl + userId) - .setAuthorizationHeader("Bearer " + token) - .useDeleteMethod() - .request() - .getResponseCode(); - if (responseCode != 204) { - throw new ServerException("Can't remove user from Keycloak. UserId:" + userId); - } - } catch (IOException | NotFoundException e) { - LOG.warn( - "User with userId: " + userId + " does not exist in Keycloak. Continuing user deletion.", - e); - } catch (ApiException e) { - LOG.warn("Exception during removing user from Keycloak", e); - throw new ServerException("Exception during removing user from Keycloak", e); - } - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakPasswordGrantTokenRequesterTest.java b/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakPasswordGrantTokenRequesterTest.java deleted file mode 100644 index 711e3d2d3f5..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakPasswordGrantTokenRequesterTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static org.testng.Assert.assertEquals; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.google.gson.JsonSyntaxException; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -public class KeycloakPasswordGrantTokenRequesterTest { - private WireMockServer wireMockServer; - private String path; - private String OIDCProviderUrl; - - @BeforeClass - void start() { - wireMockServer = new WireMockServer(wireMockConfig().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - path = "/auth/realms/master/protocol/openid-connect/token"; - OIDCProviderUrl = "http://localhost:" + wireMockServer.port() + path; - } - - @AfterClass - void stop() { - if (wireMockServer != null) { - wireMockServer.stop(); - } - } - - @Test - public void shouldRetrieveAccessToken() throws Exception { - String expectedToken = - "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ4NkRsYjhFS3VuVDQ3Ui1YRG1JdWJkcEo0"; - stubFor( - post(urlEqualTo(path)) - .withRequestBody( - matching( - "grant_type=password&username=admin&password=password&client_id=admin-cli")) - .willReturn( - aResponse() - .withHeader("Content-Type", "application/json") - .withBody("{\"access_token\": \"" + expectedToken + "\"}"))); - - KeycloakPasswordGrantTokenRequester r = new KeycloakPasswordGrantTokenRequester(); - String actualToken = r.requestToken("admin", "password", OIDCProviderUrl); - assertEquals(actualToken, expectedToken); - } - - @Test(expectedExceptions = JsonSyntaxException.class) - public void shouldThrowJsonSyntaxException() throws Exception { - stubFor( - post(urlEqualTo(path)) - .willReturn( - aResponse() - .withHeader("Content-Type", "application/json") - .withBody("MALFORMED JSON"))); - - KeycloakPasswordGrantTokenRequester r = new KeycloakPasswordGrantTokenRequester(); - r.requestToken("admin", "password", OIDCProviderUrl); - } -} diff --git a/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserRemoverTest.java b/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserRemoverTest.java deleted file mode 100644 index 8ca3cc72a43..00000000000 --- a/multiuser/keycloak/che-multiuser-keycloak-user-remover/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakUserRemoverTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.keycloak.server; - -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import java.io.FileNotFoundException; -import java.util.HashMap; -import java.util.Map; -import org.eclipse.che.api.core.ApiException; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.rest.DefaultHttpJsonRequest; -import org.eclipse.che.api.core.rest.HttpJsonRequestFactory; -import org.eclipse.che.multiuser.oidc.OIDCInfo; -import org.mockito.Mock; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -public class KeycloakUserRemoverTest { - - @Mock private KeycloakSettings keycloakSettings; - @Mock private OIDCInfo oidcInfo; - @Mock private HttpJsonRequestFactory requestFactory; - @Mock private KeycloakPasswordGrantTokenRequester tokenRequester; - @Mock private DefaultHttpJsonRequest jsonRequest; - - private KeycloakUserRemover keycloakUserRemover; - - @BeforeMethod - public void setUp() throws Exception { - initMocks(this); - - Map settingsMap = new HashMap<>(); - settingsMap.put(REALM_SETTING, "realm"); - when(keycloakSettings.get()).thenReturn(settingsMap); - when(oidcInfo.getAuthServerURL()).thenReturn("auth.server.url"); - when(requestFactory.fromUrl(anyString())).thenReturn(jsonRequest); - when(tokenRequester.requestToken(anyString(), anyString(), anyString())).thenReturn("token"); - when(jsonRequest.setAuthorizationHeader(anyString())).thenCallRealMethod(); - when(jsonRequest.useDeleteMethod()).thenCallRealMethod(); - when(jsonRequest.setMethod(anyString())).thenCallRealMethod(); - keycloakUserRemover = - new KeycloakUserRemover( - true, "admin", "admin", keycloakSettings, tokenRequester, oidcInfo, requestFactory); - } - - @Test - public void shouldCatchFileNotFoundException() throws Exception { - when(jsonRequest.request()).thenThrow(FileNotFoundException.class); - keycloakUserRemover.removeUserFromKeycloak("123"); - verify(jsonRequest).request(); - } - - @Test - public void shouldCatchNotFoundException() throws Exception { - when(jsonRequest.request()).thenThrow(NotFoundException.class); - keycloakUserRemover.removeUserFromKeycloak("123"); - verify(jsonRequest).request(); - } - - @Test( - expectedExceptions = ApiException.class, - expectedExceptionsMessageRegExp = "Exception during removing user from Keycloak") - public void shouldThrowAPIException() throws Exception { - when(jsonRequest.request()).thenThrow(ServerException.class); - keycloakUserRemover.removeUserFromKeycloak("123"); - verify(jsonRequest).request(); - } -} diff --git a/multiuser/keycloak/pom.xml b/multiuser/keycloak/pom.xml deleted file mode 100644 index 5cf3ddf78d4..00000000000 --- a/multiuser/keycloak/pom.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - 4.0.0 - - che-multiuser-parent - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - ../pom.xml - - che-multiuser-keycloak - pom - Che Multiuser :: Keycloak Integration Parent - - che-multiuser-keycloak-shared - che-multiuser-keycloak-server - che-multiuser-keycloak-token-provider - che-multiuser-keycloak-user-remover - - diff --git a/multiuser/machine-auth/che-multiuser-machine-authentication/pom.xml b/multiuser/machine-auth/che-multiuser-machine-authentication/pom.xml index b0c58fc7b11..8eacd7e3a78 100644 --- a/multiuser/machine-auth/che-multiuser-machine-authentication/pom.xml +++ b/multiuser/machine-auth/che-multiuser-machine-authentication/pom.xml @@ -102,10 +102,6 @@ org.eclipse.che.multiuser che-multiuser-machine-authentication-shared - - org.eclipse.che.multiuser - che-multiuser-permission-workspace - org.eclipse.persistence jakarta.persistence diff --git a/multiuser/machine-auth/che-multiuser-machine-authentication/src/main/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenAuthorizedSubject.java b/multiuser/machine-auth/che-multiuser-machine-authentication/src/main/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenAuthorizedSubject.java index b9469adc9f3..345a1d41cad 100644 --- a/multiuser/machine-auth/che-multiuser-machine-authentication/src/main/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenAuthorizedSubject.java +++ b/multiuser/machine-auth/che-multiuser-machine-authentication/src/main/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenAuthorizedSubject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2025 Red Hat, Inc. + * Copyright (c) 2012-2026 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,7 +14,6 @@ import org.eclipse.che.commons.subject.Subject; import org.eclipse.che.multiuser.api.permission.server.AuthorizedSubject; import org.eclipse.che.multiuser.api.permission.server.PermissionChecker; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; /** * An implementation of {@link Subject} which should be used when request was signed by machine @@ -35,7 +34,7 @@ public MachineTokenAuthorizedSubject( @Override public boolean hasPermission(String domain, String instance, String action) { - if (domain.equals(WorkspaceDomain.DOMAIN_ID) && !instance.equals(claimsWorkspaceId)) { + if (domain.equals("workspace") && !instance.equals(claimsWorkspaceId)) { return false; } return super.hasPermission(domain, instance, action); diff --git a/multiuser/machine-auth/che-multiuser-machine-authentication/src/main/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenProviderImpl.java b/multiuser/machine-auth/che-multiuser-machine-authentication/src/main/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenProviderImpl.java index bfa3fd2a8e5..e54e265fb0b 100644 --- a/multiuser/machine-auth/che-multiuser-machine-authentication/src/main/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenProviderImpl.java +++ b/multiuser/machine-auth/che-multiuser-machine-authentication/src/main/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2025 Red Hat, Inc. + * Copyright (c) 2012-2026 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,15 +12,9 @@ package org.eclipse.che.multiuser.machine.authentication.server; import static java.lang.String.format; -import static org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain.DOMAIN_ID; -import static org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain.USE; 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.ServerException; -import org.eclipse.che.api.workspace.server.token.MachineAccessForbidden; import org.eclipse.che.api.workspace.server.token.MachineTokenException; import org.eclipse.che.api.workspace.server.token.MachineTokenProvider; import org.eclipse.che.commons.env.EnvironmentContext; @@ -63,16 +57,16 @@ public String getToken(String workspaceId) throws MachineTokenException { @Override public String getToken(String userId, String workspaceId) throws MachineTokenException { - try { - if (!permissionChecker.hasPermission(userId, DOMAIN_ID, workspaceId, USE)) { - throw new MachineAccessForbidden( - format( - "The user `%s` doesn't have the required `use` permission for workspace `%s`", - userId, workspaceId)); - } - } catch (ServerException | NotFoundException | ConflictException e) { - throw new MachineTokenException(e.getMessage(), e); - } + // try { + // if (!permissionChecker.hasPermission(userId, DOMAIN_ID, workspaceId, USE)) { + // throw new MachineAccessForbidden( + // format( + // "The user `%s` doesn't have the required `use` permission for workspace `%s`", + // userId, workspaceId)); + // } + // } catch (ServerException | NotFoundException | ConflictException e) { + // throw new MachineTokenException(e.getMessage(), e); + // } return tokenRegistry.getOrCreateToken(userId, workspaceId); } diff --git a/multiuser/machine-auth/che-multiuser-machine-authentication/src/test/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenAuthorizedSubjectTest.java b/multiuser/machine-auth/che-multiuser-machine-authentication/src/test/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenAuthorizedSubjectTest.java deleted file mode 100644 index c13e5522eb2..00000000000 --- a/multiuser/machine-auth/che-multiuser-machine-authentication/src/test/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenAuthorizedSubjectTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.machine.authentication.server; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.verify; -import static org.testng.Assert.assertFalse; - -import org.eclipse.che.commons.subject.Subject; -import org.eclipse.che.multiuser.api.permission.server.PermissionChecker; -import org.eclipse.che.multiuser.api.permission.server.SystemDomain; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -@Listeners(MockitoTestNGListener.class) -public class MachineTokenAuthorizedSubjectTest { - - private static final String WS_ID = "ws123"; - private static final String USER_ID = "user123"; - @Mock private PermissionChecker permissionChecker; - - @Mock Subject baseSubject; - - private MachineTokenAuthorizedSubject subject; - - @BeforeMethod - private void setUp() { - lenient().when(baseSubject.getUserId()).thenReturn(USER_ID); - subject = new MachineTokenAuthorizedSubject(baseSubject, permissionChecker, WS_ID); - } - - @Test - public void shouldRejectPermissionsFromAnotherWorkspace() { - assertFalse( - subject.hasPermission(WorkspaceDomain.DOMAIN_ID, "another_ws", WorkspaceDomain.READ)); - } - - @Test - public void shouldRequestPermissionsFromBaseSubjectForNonWorkspaceDomains() throws Exception { - subject.hasPermission(SystemDomain.DOMAIN_ID, "", SystemDomain.MANAGE_SYSTEM_ACTION); - verify(permissionChecker, atLeastOnce()) - .hasPermission( - eq(USER_ID), eq(SystemDomain.DOMAIN_ID), eq(""), eq(SystemDomain.MANAGE_SYSTEM_ACTION)); - } -} diff --git a/multiuser/machine-auth/che-multiuser-machine-authentication/src/test/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenProviderImplTest.java b/multiuser/machine-auth/che-multiuser-machine-authentication/src/test/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenProviderImplTest.java deleted file mode 100644 index 3bc8837386c..00000000000 --- a/multiuser/machine-auth/che-multiuser-machine-authentication/src/test/java/org/eclipse/che/multiuser/machine/authentication/server/MachineTokenProviderImplTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.machine.authentication.server; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.testng.Assert.assertEquals; - -import org.eclipse.che.api.workspace.server.token.MachineAccessForbidden; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; -import org.eclipse.che.multiuser.api.permission.server.PermissionChecker; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; -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 MachineTokenProviderImpl}. - * - * @author Sergii Leshchenko - */ -@Listeners(MockitoTestNGListener.class) -public class MachineTokenProviderImplTest { - @Mock private PermissionChecker permissionChecker; - - @Mock private MachineTokenRegistry tokenRegistry; - - @InjectMocks private MachineTokenProviderImpl tokenProvider; - - @Mock private Subject currentSubject; - - @BeforeMethod - public void setUp() { - EnvironmentContext environmentContext = new EnvironmentContext(); - environmentContext.setSubject(currentSubject); - EnvironmentContext.setCurrent(environmentContext); - } - - @AfterMethod - public void tearDown() { - EnvironmentContext.reset(); - } - - @Test - public void shouldReturnMachineTokenForCurrentSubject() throws Exception { - // given - doReturn("user123").when(currentSubject).getUserId(); - doReturn("secret").when(tokenRegistry).getOrCreateToken(any(), any()); - doReturn(true) - .when(permissionChecker) - .hasPermission("user123", WorkspaceDomain.DOMAIN_ID, "workspace123", WorkspaceDomain.USE); - - // when - String token = tokenProvider.getToken("workspace123"); - - // then - assertEquals(token, "secret"); - verify(tokenRegistry).getOrCreateToken("user123", "workspace123"); - verify(permissionChecker) - .hasPermission("user123", WorkspaceDomain.DOMAIN_ID, "workspace123", WorkspaceDomain.USE); - } - - @Test( - expectedExceptions = IllegalStateException.class, - expectedExceptionsMessageRegExp = - "Unable to get machine token of the workspace " - + "'workspace123' because it does not exist for an anonymous user\\.") - public void shouldThrowExceptionIfCurrentSubjectIsAnonymous() throws Exception { - // given - doReturn(true).when(currentSubject).isAnonymous(); - - // when - tokenProvider.getToken("workspace123"); - } - - @Test( - expectedExceptions = MachineAccessForbidden.class, - expectedExceptionsMessageRegExp = - "The user `user123` doesn't have the required `use` permission for workspace `workspace123`") - public void shouldThrowExceptionIfCurrentSubjectDoesNotHavePermissionToRetrieveToken() - throws Exception { - // given - doReturn(false) - .when(permissionChecker) - .hasPermission("user123", WorkspaceDomain.DOMAIN_ID, "workspace123", WorkspaceDomain.USE); - doReturn("user123").when(currentSubject).getUserId(); - doReturn("secret").when(tokenRegistry).getOrCreateToken(any(), any()); - - // when - tokenProvider.getToken("workspace123"); - } - - @Test - public void shouldReturnMachineTokenForTheSpecifiedUser() throws Exception { - // given - doReturn("secret").when(tokenRegistry).getOrCreateToken(any(), any()); - doReturn(true) - .when(permissionChecker) - .hasPermission("user123", WorkspaceDomain.DOMAIN_ID, "workspace123", WorkspaceDomain.USE); - - // when - String token = tokenProvider.getToken("user123", "workspace123"); - - // then - assertEquals(token, "secret"); - verify(tokenRegistry).getOrCreateToken("user123", "workspace123"); - verify(permissionChecker) - .hasPermission("user123", WorkspaceDomain.DOMAIN_ID, "workspace123", WorkspaceDomain.USE); - } - - @Test( - expectedExceptions = MachineAccessForbidden.class, - expectedExceptionsMessageRegExp = - "The user `user123` doesn't have the required `use` permission for workspace `workspace123`") - public void shouldThrowExceptionIfTheSpecifiedUserDoesNotHavePermissionToRetrieveToken() - throws Exception { - // given - doReturn(false) - .when(permissionChecker) - .hasPermission("user123", WorkspaceDomain.DOMAIN_ID, "workspace123", WorkspaceDomain.USE); - doReturn("secret").when(tokenRegistry).getOrCreateToken(any(), any()); - - // when - tokenProvider.getToken("user123", "workspace123"); - } -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/pom.xml b/multiuser/permission/che-multiuser-permission-devfile/pom.xml deleted file mode 100644 index b182945325e..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/pom.xml +++ /dev/null @@ -1,205 +0,0 @@ - - - - 4.0.0 - - che-multiuser-permission - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-permission-devfile - Che Multiuser :: Devfile Permissions - - - com.google.guava - guava - - - com.google.inject - guice - - - org.eclipse.che.core - che-core-commons-test - - - com.google.inject.extensions - guice-persist - provided - - - org.eclipse.che.core - che-core-api-devfile - provided - - - org.eclipse.che.core - che-core-api-model - provided - - - org.eclipse.che.multiuser - che-multiuser-api-permission - provided - - - org.eclipse.che.multiuser - che-multiuser-api-permission-shared - provided - - - org.eclipse.persistence - jakarta.persistence - provided - - - aopalliance - aopalliance - test - - - ch.qos.logback - logback-classic - test - - - commons-fileupload - commons-fileupload - test - - - io.rest-assured - rest-assured - test - - - org.eclipse.che.core - che-core-api-account - test - - - org.eclipse.che.core - che-core-api-core - test - - - org.eclipse.che.core - che-core-api-devfile-shared - test - - - org.eclipse.che.core - che-core-api-dto - test - - - org.eclipse.che.core - che-core-api-user - test - - - org.eclipse.che.core - che-core-api-workspace - test - - - org.eclipse.che.core - che-core-commons-inject - test - - - org.eclipse.che.core - che-core-commons-json - test - - - org.eclipse.che.core - che-core-commons-lang - test - - - org.eclipse.che.core - che-core-sql-schema - test - - - org.eclipse.che.multiuser - che-multiuser-sql-schema - test - - - org.eclipse.persistence - org.eclipse.persistence.core - test - - - org.eclipse.persistence - org.eclipse.persistence.jpa - test - - - org.everrest - everrest-assured - test - - - org.flywaydb - flyway-core - test - - - org.hamcrest - hamcrest - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - **/spi/tck/*.* - **/TestObjectGenerator.* - - - - - - - - diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/UserDevfileApiPermissionsModule.java b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/UserDevfileApiPermissionsModule.java deleted file mode 100644 index 38291154236..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/UserDevfileApiPermissionsModule.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.devfile.server; - -import com.google.inject.AbstractModule; -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.shared.model.PermissionsDomain; - -public class UserDevfileApiPermissionsModule extends AbstractModule { - - @Override - protected void configure() { - - Multibinder.newSetBinder( - binder(), - PermissionsDomain.class, - Names.named(SuperPrivilegesChecker.SUPER_PRIVILEGED_DOMAINS)) - .addBinding() - .to(UserDevfileDomain.class); - } -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/UserDevfileDomain.java b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/UserDevfileDomain.java deleted file mode 100644 index 9613f300698..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/UserDevfileDomain.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.devfile.server; - -import com.google.common.collect.ImmutableList; -import java.util.List; -import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain; -import org.eclipse.che.multiuser.permission.devfile.server.model.impl.UserDevfilePermissionImpl; - -/** Domain for storing devfile's permissions */ -public class UserDevfileDomain extends AbstractPermissionsDomain { - public static final String READ = "read"; - public static final String DELETE = "delete"; - public static final String UPDATE = "update"; - public static final String DOMAIN_ID = "devfile"; - - public UserDevfileDomain() { - super(DOMAIN_ID, ImmutableList.of(READ, DELETE, UPDATE)); - } - - @Override - public UserDevfilePermissionImpl doCreateInstance( - String userId, String instanceId, List allowedActions) { - return new UserDevfilePermissionImpl(instanceId, userId, allowedActions); - } -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/jpa/MultiuserUserDevfileJpaModule.java b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/jpa/MultiuserUserDevfileJpaModule.java deleted file mode 100644 index 57cf910cfdf..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/jpa/MultiuserUserDevfileJpaModule.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.devfile.server.jpa; - -import com.google.inject.AbstractModule; -import com.google.inject.TypeLiteral; -import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain; -import org.eclipse.che.multiuser.permission.devfile.server.UserDevfileDomain; -import org.eclipse.che.multiuser.permission.devfile.server.model.impl.UserDevfilePermissionImpl; - -public class MultiuserUserDevfileJpaModule extends AbstractModule { - - @Override - protected void configure() { - - bind(new TypeLiteral>() {}) - .to(UserDevfileDomain.class); - } -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/model/UserDevfilePermission.java b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/model/UserDevfilePermission.java deleted file mode 100644 index 2935b6d1cbc..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/model/UserDevfilePermission.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.devfile.server.model; - -import java.util.List; - -public interface UserDevfilePermission { - /** Returns user id */ - String getUserId(); - - /** Returns user devfile id */ - String getUserDevfileId(); - - /** Returns list of user devfile actions which can be performed by current user */ - List getActions(); -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/model/impl/UserDevfilePermissionImpl.java b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/model/impl/UserDevfilePermissionImpl.java deleted file mode 100644 index 97709268d2c..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/server/model/impl/UserDevfilePermissionImpl.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.devfile.server.model.impl; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -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.QueryHint; -import javax.persistence.Table; -import org.eclipse.che.api.devfile.server.model.impl.UserDevfileImpl; -import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions; -import org.eclipse.che.multiuser.permission.devfile.server.UserDevfileDomain; -import org.eclipse.che.multiuser.permission.devfile.server.model.UserDevfilePermission; - -/** Data object for {@link UserDevfilePermission} */ -@Entity(name = "UserDevfilePermission") -@NamedQueries({ - @NamedQuery( - name = "UserDevfilePermission.getByUserDevfileId", - query = - "SELECT permission " - + "FROM UserDevfilePermission permission " - + "WHERE permission.userDevfileId = :userDevfileId "), - @NamedQuery( - name = "UserDevfilePermission.getCountByUserDevfileId", - query = - "SELECT COUNT(permission) " - + "FROM UserDevfilePermission permission " - + "WHERE permission.userDevfileId = :userDevfileId "), - @NamedQuery( - name = "UserDevfilePermission.getByUserId", - query = - "SELECT permission " - + "FROM UserDevfilePermission permission " - + "WHERE permission.userId = :userId "), - @NamedQuery( - name = "UserDevfilePermission.getByUserAndUserDevfileId", - query = - "SELECT permission " - + "FROM UserDevfilePermission permission " - + "WHERE permission.userId = :userId " - + "AND permission.userDevfileId = :userDevfileId ", - hints = {@QueryHint(name = "eclipselink.query-results-cache", value = "true")}) -}) -@Table(name = "che_userdevfile_permissions") -public class UserDevfilePermissionImpl extends AbstractPermissions - implements UserDevfilePermission { - - @Column(name = "userdevfile_id") - private String userDevfileId; - - @ManyToOne - @JoinColumn(name = "userdevfile_id", insertable = false, updatable = false) - private UserDevfileImpl userDevfile; - - @ElementCollection(fetch = FetchType.EAGER) - @Column(name = "actions") - @CollectionTable( - name = "che_userdevfile_permissions_actions", - joinColumns = @JoinColumn(name = "userdevfile_permissions_id")) - protected List actions; - - public UserDevfilePermissionImpl() {} - - public UserDevfilePermissionImpl(String userDevfileId, String userId, List actions) { - super(userId); - this.userDevfileId = userDevfileId; - if (actions != null) { - this.actions = new ArrayList<>(actions); - } - } - - public UserDevfilePermissionImpl(UserDevfilePermission userDevfilePermission) { - this( - userDevfilePermission.getUserDevfileId(), - userDevfilePermission.getUserId(), - userDevfilePermission.getActions()); - } - - @Override - public String getInstanceId() { - return userDevfileId; - } - - @Override - public String getDomainId() { - return UserDevfileDomain.DOMAIN_ID; - } - - @Override - public List getActions() { - return actions; - } - - @Override - public String getUserDevfileId() { - return userDevfileId; - } - - @Override - public String toString() { - return "UserDevfilePermissionImpl{" - + "userDevfileId='" - + userDevfileId - + '\'' - + ", userDevfile=" - + userDevfile - + ", actions=" - + actions - + "} " - + super.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - UserDevfilePermissionImpl that = (UserDevfilePermissionImpl) o; - return Objects.equals(userDevfileId, that.userDevfileId) - && Objects.equals(actions, that.actions); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), userDevfileId, actions); - } -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/TestObjectGenerator.java b/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/TestObjectGenerator.java deleted file mode 100644 index 82a96d2ff0d..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/TestObjectGenerator.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2012-2026 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.devfile.server; - -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; - -import com.google.common.collect.ImmutableMap; -import java.util.Collections; -import org.eclipse.che.account.shared.model.Account; -import org.eclipse.che.account.spi.AccountImpl; -import org.eclipse.che.api.devfile.server.DtoConverter; -import org.eclipse.che.api.devfile.server.model.impl.UserDevfileImpl; -import org.eclipse.che.api.devfile.shared.dto.UserDevfileDto; -import org.eclipse.che.api.workspace.server.model.impl.devfile.ActionImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.CommandImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.ComponentImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.DevfileImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.EndpointImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.EntrypointImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.EnvImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.MetadataImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.ProjectImpl; -import org.eclipse.che.api.workspace.server.model.impl.devfile.SourceImpl; -import org.eclipse.che.commons.lang.NameGenerator; -import org.eclipse.che.commons.subject.Subject; -import org.eclipse.che.commons.subject.SubjectImpl; - -public class TestObjectGenerator { - - public static final String TEST_CHE_NAMESPACE = "user"; - public static final String CURRENT_USER_ID = NameGenerator.generate("usrid", 6); - public static final Subject TEST_SUBJECT = - new SubjectImpl(TEST_CHE_NAMESPACE, Collections.emptyList(), CURRENT_USER_ID, "token", false); - public static final String USER_DEVFILE_ID = NameGenerator.generate("usrd", 16); - public static final AccountImpl TEST_ACCOUNT = - new AccountImpl("acc-id042u3ui3oi", TEST_CHE_NAMESPACE, "test"); - - public static UserDevfileDto createUserDevfileDto() { - return DtoConverter.asDto(createUserDevfile(NameGenerator.generate("name", 6))); - } - - public static UserDevfileImpl createUserDevfile() { - return createUserDevfile(NameGenerator.generate("name", 6)); - } - - public static UserDevfileImpl createUserDevfile(String name) { - return createUserDevfile(NameGenerator.generate("id", 6), name); - } - - public static UserDevfileImpl createUserDevfile(String id, String name) { - return new UserDevfileImpl(id, TEST_ACCOUNT, name, "devfile description", createDevfile(name)); - } - - public static UserDevfileImpl createUserDevfile(String id, Account account, String name) { - return new UserDevfileImpl(id, account, name, "devfile description", createDevfile(name)); - } - - public static DevfileImpl createDevfile(String name) { - return createDevfile(name, "rosetta-"); - } - - public static DevfileImpl createDevfile(String name, String generatedName) { - - SourceImpl source1 = - new SourceImpl( - "type1", - "http://location", - "branch1", - "point1", - "tag1", - "commit1", - "sparseCheckoutDir1"); - ProjectImpl project1 = new ProjectImpl("project1", source1, "path1"); - - SourceImpl source2 = - new SourceImpl( - "type2", - "http://location", - "branch2", - "point2", - "tag2", - "commit2", - "sparseCheckoutDir2"); - ProjectImpl project2 = new ProjectImpl("project2", source2, "path2"); - - ActionImpl action1 = - new ActionImpl("exec1", "component1", "run.sh", "/home/user/1", null, null); - ActionImpl action2 = - new ActionImpl("exec2", "component2", "run.sh", "/home/user/2", null, null); - - CommandImpl command1 = - new CommandImpl(name + "-1", singletonList(action1), singletonMap("attr1", "value1"), null); - CommandImpl command2 = - new CommandImpl(name + "-2", singletonList(action2), singletonMap("attr2", "value2"), null); - - EntrypointImpl entrypoint1 = - new EntrypointImpl( - "parentName1", - singletonMap("parent1", "selector1"), - "containerName1", - asList("command1", "command2"), - asList("arg1", "arg2")); - - EntrypointImpl entrypoint2 = - new EntrypointImpl( - "parentName2", - singletonMap("parent2", "selector2"), - "containerName2", - asList("command3", "command4"), - asList("arg3", "arg4")); - - org.eclipse.che.api.workspace.server.model.impl.devfile.VolumeImpl volume1 = - new org.eclipse.che.api.workspace.server.model.impl.devfile.VolumeImpl("name1", "path1"); - - org.eclipse.che.api.workspace.server.model.impl.devfile.VolumeImpl volume2 = - new org.eclipse.che.api.workspace.server.model.impl.devfile.VolumeImpl("name2", "path2"); - - EnvImpl env1 = new EnvImpl("name1", "value1"); - EnvImpl env2 = new EnvImpl("name2", "value2"); - - EndpointImpl endpoint1 = new EndpointImpl("name1", 1111, singletonMap("key1", "value1")); - EndpointImpl endpoint2 = new EndpointImpl("name2", 2222, singletonMap("key2", "value2")); - - ComponentImpl component1 = - new ComponentImpl( - "kubernetes", - "component1", - "eclipse/che-theia/0.0.1", - ImmutableMap.of("java.home", "/home/user/jdk11"), - "https://mysite.com/registry/somepath1", - "/dev.yaml", - "refcontent1", - ImmutableMap.of("app.kubernetes.io/component", "db"), - asList(entrypoint1, entrypoint2), - "image", - "256G", - "128M", - "2", - "130m", - false, - false, - singletonList("command"), - singletonList("arg"), - asList(volume1, volume2), - asList(env1, env2), - asList(endpoint1, endpoint2)); - component1.setSelector(singletonMap("key1", "value1")); - - ComponentImpl component2 = - new ComponentImpl( - "kubernetes", - "component2", - "eclipse/che-theia/0.0.1", - ImmutableMap.of( - "java.home", - "/home/user/jdk11aertwertert", - "java.boolean", - true, - "java.long", - 123444L), - "https://mysite.com/registry/somepath2", - "/dev.yaml", - "refcontent2", - ImmutableMap.of("app.kubernetes.io/component", "webapp"), - asList(entrypoint1, entrypoint2), - "image", - "256G", - "256M", - "3", - "180m", - false, - false, - singletonList("command"), - singletonList("arg"), - asList(volume1, volume2), - asList(env1, env2), - asList(endpoint1, endpoint2)); - component2.setSelector(singletonMap("key2", "value2")); - MetadataImpl metadata = new MetadataImpl(name); - metadata.setGenerateName(generatedName); - DevfileImpl devfile = - new DevfileImpl( - "0.0.1", - asList(project1, project2), - asList(component1, component2), - asList(command1, command2), - singletonMap("attribute1", "value1"), - metadata); - - return devfile; - } -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/spi/jpa/EntityManagerExceptionInterceptor.java b/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/spi/jpa/EntityManagerExceptionInterceptor.java deleted file mode 100644 index 24998f8b964..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/spi/jpa/EntityManagerExceptionInterceptor.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.devfile.server.spi.jpa; - -import com.google.inject.Inject; -import com.google.inject.Provider; -import javax.persistence.EntityManager; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -public class EntityManagerExceptionInterceptor implements MethodInterceptor { - @Inject Provider emf; - - @Override - public Object invoke(MethodInvocation methodInvocation) throws Throwable { - emf.get().getTransaction().setRollbackOnly(); - throw new RuntimeException("Database exception"); - } -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/spi/jpa/JpaTckModule.java b/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/spi/jpa/JpaTckModule.java deleted file mode 100644 index 98359146144..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permission/devfile/server/spi/jpa/JpaTckModule.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.devfile.server.spi.jpa; - -import com.google.inject.TypeLiteral; -import org.eclipse.che.account.spi.AccountImpl; -import org.eclipse.che.api.devfile.server.model.impl.UserDevfileImpl; -import org.eclipse.che.api.user.server.model.impl.UserImpl; -import org.eclipse.che.commons.test.tck.TckModule; -import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; -import org.eclipse.che.commons.test.tck.repository.TckRepository; -import org.eclipse.che.multiuser.permission.devfile.server.model.UserDevfilePermission; - -public class JpaTckModule extends TckModule { - - @Override - protected void configure() { - bind(new TypeLiteral>() {}) - .toInstance(new JpaTckRepository<>(UserDevfilePermission.class)); - bind(new TypeLiteral>() {}) - .toInstance(new JpaTckRepository<>(UserImpl.class)); - bind(new TypeLiteral>() {}) - .toInstance(new JpaTckRepository<>(UserDevfileImpl.class)); - bind(new TypeLiteral>() {}) - .toInstance(new JpaTckRepository<>(AccountImpl.class)); - } -} diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule b/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule deleted file mode 100644 index edd289622d5..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule +++ /dev/null @@ -1 +0,0 @@ -org.eclipse.che.multiuser.permission.devfile.server.spi.jpa.JpaTckModule diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/logback-test.xml b/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/logback-test.xml deleted file mode 100644 index 3d4d10adab1..00000000000 --- a/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/logback-test.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n - - - - - - - diff --git a/multiuser/permission/che-multiuser-permission-factory/pom.xml b/multiuser/permission/che-multiuser-permission-factory/pom.xml deleted file mode 100644 index 48189feeb9c..00000000000 --- a/multiuser/permission/che-multiuser-permission-factory/pom.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - - 4.0.0 - - che-multiuser-permission - org.eclipse.che.multiuser - 7.20.0-SNAPSHOT - - che-multiuser-permission-factory - Che Multiuser :: Factory Permissions - - false - - - - jakarta.inject - jakarta.inject-api - - - commons-fileupload - commons-fileupload - test - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-api-factory - - - org.eclipse.che.core - che-core-api-model - - - org.eclipse.che.core - che-core-commons-test - - - org.eclipse.che.multiuser - che-multiuser-api-permission - - - org.eclipse.che.multiuser - che-multiuser-permission-workspace - - - org.everrest - everrest-core - - - ch.qos.logback - logback-classic - test - - - io.rest-assured - rest-assured - test - - - org.eclipse.che.core - che-core-api-dto - test - - - org.eclipse.che.core - che-core-api-factory-shared - test - - - org.everrest - everrest-assured - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - - analyze - - - org.eclipse.che.multiuser:che-multiuser-api-permission - - - - - - - - diff --git a/multiuser/permission/che-multiuser-permission-factory/src/main/java/org/eclipse/che/multiuser/permission/factory/FactoryPermissionsFilter.java b/multiuser/permission/che-multiuser-permission-factory/src/main/java/org/eclipse/che/multiuser/permission/factory/FactoryPermissionsFilter.java deleted file mode 100644 index bc3aff69c75..00000000000 --- a/multiuser/permission/che-multiuser-permission-factory/src/main/java/org/eclipse/che/multiuser/permission/factory/FactoryPermissionsFilter.java +++ /dev/null @@ -1,90 +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.permission.factory; - -import javax.inject.Inject; -import jakarta.ws.rs.Path; -import org.eclipse.che.api.core.ApiException; -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.api.core.model.factory.Factory; -import org.eclipse.che.api.factory.server.FactoryManager; -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.permission.workspace.server.WorkspaceDomain; -import org.everrest.core.Filter; -import org.everrest.core.resource.GenericResourceMethod; - -/** - * Restricts access to methods of FactoryService by user's permissions. - * - * @author Anton Korneta - * @author Sergii Leshchenko - */ -@Filter -@Path("/factory/{path:.*}") -public class FactoryPermissionsFilter extends CheMethodInvokerFilter { - - private final FactoryManager factoryManager; - - @Inject - public FactoryPermissionsFilter(FactoryManager factoryManager) { - this.factoryManager = factoryManager; - } - - @Override - protected void filter(GenericResourceMethod genericResourceMethod, Object[] arguments) - throws ApiException { - final String methodName = genericResourceMethod.getMethod().getName(); - - final Subject currentSubject = EnvironmentContext.getCurrent().getSubject(); - - switch (methodName) { - case "getFactoryJson": - { - String workspaceId = ((String) arguments[0]); - - currentSubject.checkPermission( - WorkspaceDomain.DOMAIN_ID, workspaceId, WorkspaceDomain.READ); - return; - } - case "removeFactory": - checkSubjectIsCreator((String) arguments[0], currentSubject, "remove"); - return; - case "updateFactory": - checkSubjectIsCreator((String) arguments[0], currentSubject, "update"); - return; - - case "getFactory": - case "saveFactory": - case "getFactoryByAttribute": - case "resolveFactory": - // public methods - // do nothing - return; - - default: - throw new ForbiddenException("The user does not have permission to perform this operation"); - } - } - - private void checkSubjectIsCreator(String factoryId, Subject currentSubject, String action) - throws NotFoundException, ServerException, ForbiddenException { - Factory factory = factoryManager.getById(factoryId); - String creatorId = factory.getCreator().getUserId(); - if (!creatorId.equals(currentSubject.getUserId())) { - throw new ForbiddenException("It is not allowed to " + action + " foreign factory"); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-factory/src/test/java/org/eclipse/che/multiuser/permission/factory/FactoryPermissionsFilterTest.java b/multiuser/permission/che-multiuser-permission-factory/src/test/java/org/eclipse/che/multiuser/permission/factory/FactoryPermissionsFilterTest.java deleted file mode 100644 index 3c04ff38cad..00000000000 --- a/multiuser/permission/che-multiuser-permission-factory/src/test/java/org/eclipse/che/multiuser/permission/factory/FactoryPermissionsFilterTest.java +++ /dev/null @@ -1,90 +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.permission.factory; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.Map; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.factory.server.FactoryManager; -import org.eclipse.che.api.factory.server.FactoryService; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; -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.DataProvider; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** - * Tests for {@link FactoryPermissionsFilter}. - * - * @author Sergii Leschenko - */ -@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class}) -public class FactoryPermissionsFilterTest { - - @SuppressWarnings("unused") - private static final EnvironmentFilter FILTER = new EnvironmentFilter(); - - @Mock private static Subject subject; - - @Mock private FactoryService service; - - @Mock private FactoryManager factoryManager; - - @InjectMocks private FactoryPermissionsFilter permissionsFilter; - - @Test(dataProvider = "publicMethods") - public void shouldDoNothingWhenPublicMethodMethodIsCalled(String name, Class[] parameterTypes) - throws Exception { - GenericResourceMethod genericResourceMethod = mock(GenericResourceMethod.class); - when(genericResourceMethod.getMethod()) - .thenReturn(FactoryService.class.getMethod(name, parameterTypes)); - - permissionsFilter.filter(genericResourceMethod, new Object[0]); - } - - @DataProvider(name = "publicMethods") - public Object[][] publicMethods() { - return new Object[][] { - {"resolveFactory", new Class[] {Map.class, Boolean.class}}, - }; - } - - @Test( - expectedExceptions = ForbiddenException.class, - expectedExceptionsMessageRegExp = - "The user does not have permission to perform this operation") - public void shouldThrowForbiddenExceptionWhenUnlistedMethodIsCalled() throws Exception { - GenericResourceMethod genericResourceMethod = mock(GenericResourceMethod.class); - when(genericResourceMethod.getMethod()) - .thenReturn(FactoryService.class.getMethod("getServiceDescriptor")); - - permissionsFilter.filter(genericResourceMethod, new Object[0]); - } - - @Filter - public static class EnvironmentFilter implements RequestFilter { - - public void doFilter(GenericContainerRequest request) { - EnvironmentContext.getCurrent().setSubject(subject); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-factory/src/test/resources/logback-test.xml b/multiuser/permission/che-multiuser-permission-factory/src/test/resources/logback-test.xml deleted file mode 100644 index e7bf50602e3..00000000000 --- a/multiuser/permission/che-multiuser-permission-factory/src/test/resources/logback-test.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n - - - - - - - diff --git a/multiuser/permission/che-multiuser-permission-logger/pom.xml b/multiuser/permission/che-multiuser-permission-logger/pom.xml deleted file mode 100644 index 016360e7271..00000000000 --- a/multiuser/permission/che-multiuser-permission-logger/pom.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - - 4.0.0 - - che-multiuser-permission - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-permission-logger - Che Multiuser :: Logger Permissions - - false - - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-commons-test - - - org.eclipse.che.multiuser - che-multiuser-api-permission - - - org.everrest - everrest-core - - - ch.qos.logback - logback-classic - test - - - commons-fileupload - commons-fileupload - test - - - io.rest-assured - rest-assured - test - - - org.eclipse.che.core - che-core-api-dto - test - - - org.eclipse.che.core - che-core-api-logger - test - - - org.eclipse.che.core - che-core-commons-inject - test - - - org.eclipse.che.core - che-core-commons-json - test - - - org.everrest - everrest-assured - test - - - org.hamcrest - hamcrest - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - diff --git a/multiuser/permission/che-multiuser-permission-logger/src/main/java/org/eclipse/che/multiuser/permission/logger/LoggerServicePermissionsFilter.java b/multiuser/permission/che-multiuser-permission-logger/src/main/java/org/eclipse/che/multiuser/permission/logger/LoggerServicePermissionsFilter.java deleted file mode 100644 index d3b5451ce70..00000000000 --- a/multiuser/permission/che-multiuser-permission-logger/src/main/java/org/eclipse/che/multiuser/permission/logger/LoggerServicePermissionsFilter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.logger; - -import jakarta.ws.rs.Path; -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.everrest.CheMethodInvokerFilter; -import org.eclipse.che.multiuser.api.permission.server.SystemDomain; -import org.everrest.core.Filter; -import org.everrest.core.resource.GenericResourceMethod; - -/** - * Filter that covers calls to {@link org.eclipse.che.api.logger.LoggerService} with authorization - * - * @author Florent Benoit - */ -@Filter -@Path("/logger{path:.*}") -public class LoggerServicePermissionsFilter extends CheMethodInvokerFilter { - - @Override - protected void filter(GenericResourceMethod resource, Object[] args) throws ApiException { - switch (resource.getMethod().getName()) { - case "getLoggerByName": - case "getLoggers": - case "updateLogger": - case "createLogger": - EnvironmentContext.getCurrent() - .getSubject() - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - break; - default: - throw new ForbiddenException("The user does not have permission to perform this operation"); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-logger/src/test/java/org/eclipse/che/multiuser/permission/user/LoggerServicePermissionsFilterTest.java b/multiuser/permission/che-multiuser-permission-logger/src/test/java/org/eclipse/che/multiuser/permission/user/LoggerServicePermissionsFilterTest.java deleted file mode 100644 index 0256acc3b89..00000000000 --- a/multiuser/permission/che-multiuser-permission-logger/src/test/java/org/eclipse/che/multiuser/permission/user/LoggerServicePermissionsFilterTest.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.user; - -import static io.restassured.RestAssured.given; -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.Mockito.doThrow; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.testng.Assert.assertEquals; - -import io.restassured.response.Response; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.core.rest.ApiExceptionMapper; -import org.eclipse.che.api.core.rest.shared.dto.ServiceError; -import org.eclipse.che.api.logger.LoggerService; -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.SystemDomain; -import org.eclipse.che.multiuser.permission.logger.LoggerServicePermissionsFilter; -import org.everrest.assured.EverrestJetty; -import org.everrest.core.Filter; -import org.everrest.core.GenericContainerRequest; -import org.everrest.core.RequestFilter; -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.permission.logger.LoggerServicePermissionsFilter} - * - * @author Florent Benoit - */ -@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class}) -public class LoggerServicePermissionsFilterTest { - @SuppressWarnings("unused") - private static final ApiExceptionMapper MAPPER = new ApiExceptionMapper(); - - @SuppressWarnings("unused") - private static final EnvironmentFilter FILTER = new EnvironmentFilter(); - - LoggerServicePermissionsFilter permissionsFilter; - - @Mock private static Subject subject; - - @Mock LoggerService service; - - @BeforeMethod - public void setUp() { - permissionsFilter = new LoggerServicePermissionsFilter(); - } - - @Test - public void shouldCheckPermissionsOnGetLoggers() throws Exception { - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/logger"); - - assertEquals(response.getStatusCode(), 200); - verify(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - } - - @Test - public void shouldThrowExceptionWhenUserDoesNotHavePermissionsToGetLoggers() throws Exception { - doThrow(new ForbiddenException("User is not authorized")) - .when(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/logger"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(unwrapError(response), "User is not authorized"); - verify(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - verifyNoMoreInteractions(service); - } - - @Test - public void shouldCheckPermissionsOnGetLogger() throws Exception { - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/logger/FOO"); - - assertEquals(response.getStatusCode(), 204); - verify(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - } - - @Test - public void shouldThrowExceptionWhenUserDoesNotHavePermissionsToGetLogger() throws Exception { - doThrow(new ForbiddenException("User is not authorized")) - .when(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/logger/FOO"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(unwrapError(response), "User is not authorized"); - verify(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - verifyNoMoreInteractions(service); - } - - @Test - public void shouldCheckPermissionsOnUpdateLogger() throws Exception { - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType("application/json") - .when() - .put(SECURE_PATH + "/logger/FOO"); - - assertEquals(response.getStatusCode(), 204); - verify(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - } - - @Test - public void shouldThrowExceptionWhenUserDoesNotHavePermissionsToUpdateLogger() throws Exception { - doThrow(new ForbiddenException("User is not authorized")) - .when(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType("application/json") - .when() - .put(SECURE_PATH + "/logger/FOO"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(unwrapError(response), "User is not authorized"); - verify(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - verifyNoMoreInteractions(service); - } - - @Test - public void shouldCheckPermissionsOnCreateLogger() throws Exception { - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType("application/json") - .when() - .post(SECURE_PATH + "/logger/FOO"); - - assertEquals(response.getStatusCode(), 204); - verify(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - } - - @Test - public void shouldThrowExceptionWhenUserDoesNotHavePermissionsToCreateLogger() throws Exception { - doThrow(new ForbiddenException("User is not authorized")) - .when(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - - final Response response = - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .contentType("application/json") - .when() - .post(SECURE_PATH + "/logger/FOO"); - - assertEquals(response.getStatusCode(), 403); - assertEquals(unwrapError(response), "User is not authorized"); - verify(subject) - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - verifyNoMoreInteractions(service); - } - - private static String unwrapError(Response response) { - return unwrapDto(response, ServiceError.class).getMessage(); - } - - private static T unwrapDto(Response response, Class dtoClass) { - return DtoFactory.getInstance().createDtoFromJson(response.body().print(), dtoClass); - } - - @Filter - public static class EnvironmentFilter implements RequestFilter { - public void doFilter(GenericContainerRequest request) { - EnvironmentContext.getCurrent().setSubject(subject); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-system/pom.xml b/multiuser/permission/che-multiuser-permission-system/pom.xml deleted file mode 100644 index 9711b82b27f..00000000000 --- a/multiuser/permission/che-multiuser-permission-system/pom.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - 4.0.0 - - che-multiuser-permission - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-permission-system - Che Multiuser :: System Permissions - - false - - - - jakarta.inject - jakarta.inject-api - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-api-system - - - org.eclipse.che.core - che-core-commons-test - - - org.eclipse.che.multiuser - che-multiuser-api-permission - - - org.everrest - everrest-core - - - ch.qos.logback - logback-classic - test - - - com.google.guava - guava - test - - - commons-fileupload - commons-fileupload - test - - - io.rest-assured - rest-assured - test - - - org.eclipse.che.core - che-core-api-system-shared - test - - - org.everrest - everrest-assured - test - - - org.hamcrest - hamcrest - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - - analyze - - - org.eclipse.che.core:che-core-api-system - - - - - - - - diff --git a/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/JvmServicePermissionsFilter.java b/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/JvmServicePermissionsFilter.java deleted file mode 100644 index f6e89421742..00000000000 --- a/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/JvmServicePermissionsFilter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.system; - -import jakarta.ws.rs.Path; -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.everrest.CheMethodInvokerFilter; -import org.eclipse.che.multiuser.api.permission.server.SystemDomain; -import org.everrest.core.Filter; -import org.everrest.core.resource.GenericResourceMethod; - -/** - * Rejects/allows access to the methods of {@link org.eclipse.che.api.system.server.JvmService} - * - * @author Sergii Kabashniuk - */ -@Filter -@Path("/jvm{path:.*}") -public class JvmServicePermissionsFilter extends CheMethodInvokerFilter { - @Override - protected void filter(GenericResourceMethod resource, Object[] args) throws ApiException { - switch (resource.getMethod().getName()) { - case "threadDump": - case "heapDump": - EnvironmentContext.getCurrent() - .getSubject() - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - break; - default: - throw new ForbiddenException("The user does not have permission to perform this operation"); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/SystemEventsSubscriptionPermissionsCheck.java b/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/SystemEventsSubscriptionPermissionsCheck.java deleted file mode 100644 index e28694c0dad..00000000000 --- a/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/SystemEventsSubscriptionPermissionsCheck.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.system; - -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.system.server.SystemEventsWebsocketBroadcaster; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.multiuser.api.permission.server.SystemDomain; -import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionCheck; -import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionManager; - -/** - * @author Sergii Leshchenko - */ -@Singleton -public class SystemEventsSubscriptionPermissionsCheck implements RemoteSubscriptionPermissionCheck { - @Inject - public void register(RemoteSubscriptionPermissionManager permissionFilter) { - permissionFilter.registerCheck(this, SystemEventsWebsocketBroadcaster.SYSTEM_STATE_METHOD_NAME); - } - - @Override - public void check(String methodName, Map scope) throws ForbiddenException { - EnvironmentContext.getCurrent() - .getSubject() - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - } -} diff --git a/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/SystemServicePermissionsFilter.java b/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/SystemServicePermissionsFilter.java deleted file mode 100644 index 09feca56220..00000000000 --- a/multiuser/permission/che-multiuser-permission-system/src/main/java/org/eclipse/che/multiuser/permission/system/SystemServicePermissionsFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.system; - -import jakarta.ws.rs.Path; -import org.eclipse.che.api.core.ApiException; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.system.server.SystemService; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.everrest.CheMethodInvokerFilter; -import org.eclipse.che.multiuser.api.permission.server.SystemDomain; -import org.everrest.core.Filter; -import org.everrest.core.resource.GenericResourceMethod; - -/** - * Rejects/allows access to the methods of {@link SystemService} - * - * @author Yevhenii Voevodin - */ -@Filter -@Path("/system{path:.*}") -public class SystemServicePermissionsFilter extends CheMethodInvokerFilter { - @Override - protected void filter(GenericResourceMethod resource, Object[] args) throws ApiException { - switch (resource.getMethod().getName()) { - case "stop": - EnvironmentContext.getCurrent() - .getSubject() - .checkPermission(SystemDomain.DOMAIN_ID, null, SystemDomain.MANAGE_SYSTEM_ACTION); - break; - case "getState": - break; - default: - throw new ForbiddenException("The user does not have permission to perform this operation"); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-system/src/test/java/org/eclipse/che/multiuser/permission/system/JvmServicePermissionsFilterTest.java b/multiuser/permission/che-multiuser-permission-system/src/test/java/org/eclipse/che/multiuser/permission/system/JvmServicePermissionsFilterTest.java deleted file mode 100644 index 8a787b81602..00000000000 --- a/multiuser/permission/che-multiuser-permission-system/src/test/java/org/eclipse/che/multiuser/permission/system/JvmServicePermissionsFilterTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2012-2026 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.system; - -import static io.restassured.RestAssured.given; -import static java.lang.String.format; -import static java.util.Arrays.asList; -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.Mockito.doAnswer; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.testng.Assert.fail; - -import com.google.common.collect.Sets; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.system.server.JvmService; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; -import org.eclipse.che.multiuser.api.permission.server.SystemDomain; -import org.everrest.assured.EverrestJetty; -import org.everrest.core.Filter; -import org.everrest.core.GenericContainerRequest; -import org.everrest.core.RequestFilter; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** Tests {@link SystemServicePermissionsFilter}. */ -@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class}) -public class JvmServicePermissionsFilterTest { - - private static final Set TEST_HANDLED_METHODS = - new HashSet<>(asList("heapDump", "threadDump")); - - @SuppressWarnings("unused") - private static final JvmServicePermissionsFilter serviceFilter = - new JvmServicePermissionsFilter(); - - @SuppressWarnings("unused") - private static final EnvironmentFilter envFilter = new EnvironmentFilter(); - - @Mock private static Subject subject; - - @Mock private JvmService jvmService; - - @Test - public void allPublicMethodsAreFiltered() { - Set existingMethods = getDeclaredPublicMethods(JvmService.class); - - if (!existingMethods.equals(TEST_HANDLED_METHODS)) { - Set existingMinusExpected = Sets.difference(existingMethods, TEST_HANDLED_METHODS); - Set expectedMinusExisting = Sets.difference(TEST_HANDLED_METHODS, existingMethods); - fail( - format( - "The set of public methods tested by by the filter was changed.\n" - + "Methods present in service but not declared in test: '%s'\n" - + "Methods present in test but missing from service: '%s'", - existingMinusExpected, expectedMinusExisting)); - } - } - - @Test - public void allowsGenerateThreadDumpWithManageSystemPermission() throws Exception { - permitSubject(SystemDomain.MANAGE_SYSTEM_ACTION); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/jvm/dump/thread") - .then() - .statusCode(204); - - verify(jvmService).threadDump(); - } - - @Test - public void rejectsGenerateThreadDumpWithoutManageSystemPermission() throws Exception { - permitSubject("nothing"); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/jvm/dump/thread") - .then() - .statusCode(403); - - verify(jvmService, never()).threadDump(); - } - - @Test - public void allowsGenerateHeapDumpWithManageSystemPermission() throws Exception { - permitSubject(SystemDomain.MANAGE_SYSTEM_ACTION); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/jvm/dump/heap"); - - verify(jvmService).heapDump(); - } - - @Test - public void rejectsGenerateHeapDumpWithoutManageSystemPermission() throws Exception { - permitSubject("nothing"); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/jvm/dump/heap") - .then() - .statusCode(403); - - verify(jvmService, never()).heapDump(); - } - - private static void permitSubject(String... allowedActions) throws ForbiddenException { - doAnswer( - inv -> { - if (!new HashSet<>(Arrays.asList(allowedActions)) - .contains(inv.getArguments()[2].toString())) { - throw new ForbiddenException("Not allowed!"); - } - return null; - }) - .when(subject) - .checkPermission(any(), any(), any()); - } - - private static Set getDeclaredPublicMethods(Class c) { - return Arrays.stream(c.getDeclaredMethods()) - .filter(m -> Modifier.isPublic(m.getModifiers())) - .map(Method::getName) - .collect(Collectors.toSet()); - } - - @Filter - public static class EnvironmentFilter implements RequestFilter { - @Override - public void doFilter(GenericContainerRequest request) { - EnvironmentContext.getCurrent().setSubject(subject); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-system/src/test/java/org/eclipse/che/multiuser/permission/system/SystemServicePermissionsFilterTest.java b/multiuser/permission/che-multiuser-permission-system/src/test/java/org/eclipse/che/multiuser/permission/system/SystemServicePermissionsFilterTest.java deleted file mode 100644 index e5fcbc94a8b..00000000000 --- a/multiuser/permission/che-multiuser-permission-system/src/test/java/org/eclipse/che/multiuser/permission/system/SystemServicePermissionsFilterTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.system; - -import static io.restassured.RestAssured.given; -import static java.lang.String.format; -import static java.util.Arrays.asList; -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.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.testng.Assert.fail; - -import com.google.common.collect.Sets; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.system.server.SystemService; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; -import org.eclipse.che.multiuser.api.permission.server.SystemDomain; -import org.everrest.assured.EverrestJetty; -import org.everrest.core.Filter; -import org.everrest.core.GenericContainerRequest; -import org.everrest.core.RequestFilter; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** - * Tests {@link SystemServicePermissionsFilter}. - * - * @author Yevhenii Voevodin - */ -@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class}) -public class SystemServicePermissionsFilterTest { - - private static final Set TEST_HANDLED_METHODS = new HashSet<>(asList("stop", "getState")); - - @SuppressWarnings("unused") - private static final SystemServicePermissionsFilter serviceFilter = - new SystemServicePermissionsFilter(); - - @SuppressWarnings("unused") - private static final EnvironmentFilter envFilter = new EnvironmentFilter(); - - @Mock private static Subject subject; - - @Mock private SystemService systemService; - - @Test - public void allPublicMethodsAreFiltered() { - Set existingMethods = getDeclaredPublicMethods(SystemService.class); - - if (!existingMethods.equals(TEST_HANDLED_METHODS)) { - Set existingMinusExpected = Sets.difference(existingMethods, TEST_HANDLED_METHODS); - Set expectedMinusExisting = Sets.difference(TEST_HANDLED_METHODS, existingMethods); - fail( - format( - "The set of public methods tested by by the filter was changed.\n" - + "Methods present in service but not declared in test: '%s'\n" - + "Methods present in test but missing from service: '%s'", - existingMinusExpected, expectedMinusExisting)); - } - } - - @Test - public void allowsStopForUserWithManageSystemPermission() throws Exception { - permitSubject(SystemDomain.MANAGE_SYSTEM_ACTION); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .post(SECURE_PATH + "/system/stop") - .then() - .statusCode(204); - - verify(systemService).stop(anyBoolean()); - } - - @Test - public void rejectsStopForUserWithoutManageSystemPermission() throws Exception { - permitSubject("nothing"); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .post(SECURE_PATH + "/system/stop") - .then() - .statusCode(403); - - verify(systemService, never()).stop(anyBoolean()); - } - - @Test - public void allowsGetStateForUserWithManageSystemPermission() throws Exception { - permitSubject(SystemDomain.MANAGE_SYSTEM_ACTION); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/system/state"); - - verify(systemService).getState(); - } - - @Test - public void shouldNotRejectsGetStateForUserWithoutManageSystemPermission() throws Exception { - permitSubject("nothing"); - - given() - .auth() - .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) - .when() - .get(SECURE_PATH + "/system/state"); - - verify(systemService).getState(); - } - - private static void permitSubject(String... allowedActions) throws ForbiddenException { - lenient() - .doAnswer( - inv -> { - if (!new HashSet<>(Arrays.asList(allowedActions)) - .contains(inv.getArguments()[2].toString())) { - throw new ForbiddenException("Not allowed!"); - } - return null; - }) - .when(subject) - .checkPermission(anyString(), isNull(), anyString()); - } - - private static Set getDeclaredPublicMethods(Class c) { - return Arrays.stream(c.getDeclaredMethods()) - .filter(method -> Modifier.isPublic(method.getModifiers())) - .map(Method::getName) - .collect(Collectors.toSet()); - } - - @Filter - public static class EnvironmentFilter implements RequestFilter { - @Override - public void doFilter(GenericContainerRequest request) { - EnvironmentContext.getCurrent().setSubject(subject); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-system/src/test/resources/logback-test.xml b/multiuser/permission/che-multiuser-permission-system/src/test/resources/logback-test.xml deleted file mode 100644 index 3d4d10adab1..00000000000 --- a/multiuser/permission/che-multiuser-permission-system/src/test/resources/logback-test.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n - - - - - - - diff --git a/multiuser/permission/che-multiuser-permission-workspace-activity/pom.xml b/multiuser/permission/che-multiuser-permission-workspace-activity/pom.xml deleted file mode 100644 index 2e064ea9aca..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace-activity/pom.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - 4.0.0 - - che-multiuser-permission - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-permission-workspace-activity - Che Multiuser :: Workspace Activity Permissions - - - jakarta.ws.rs - jakarta.ws.rs-api - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-commons-test - - - org.eclipse.che.multiuser - che-multiuser-api-permission - - - org.eclipse.che.multiuser - che-multiuser-permission-workspace - - - org.everrest - everrest-core - - - ch.qos.logback - logback-classic - test - - - commons-fileupload - commons-fileupload - test - - - io.rest-assured - rest-assured - test - - - org.eclipse.che.core - che-core-commons-inject - test - - - org.eclipse.che.core - che-core-commons-json - test - - - org.eclipse.che.core - che-core-sql-schema - test - - - org.eclipse.che.multiuser - che-multiuser-sql-schema - test - - - org.eclipse.persistence - org.eclipse.persistence.core - test - - - org.eclipse.persistence - org.eclipse.persistence.jpa - test - - - org.everrest - everrest-assured - test - - - org.flywaydb - flyway-core - test - - - org.hamcrest - hamcrest - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - diff --git a/multiuser/permission/che-multiuser-permission-workspace-activity/src/main/java/org/eclipse/che/multiuser/permission/workspace/activity/ActivityPermissionsFilter.java b/multiuser/permission/che-multiuser-permission-workspace-activity/src/main/java/org/eclipse/che/multiuser/permission/workspace/activity/ActivityPermissionsFilter.java deleted file mode 100644 index 8201d5177d3..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace-activity/src/main/java/org/eclipse/che/multiuser/permission/workspace/activity/ActivityPermissionsFilter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.activity; - -import jakarta.ws.rs.Path; -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.SystemDomain; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; -import org.everrest.core.Filter; -import org.everrest.core.resource.GenericResourceMethod; - -/** - * Restricts access to methods of {@link WorkspaceActivityService} by user's permissions - * - * @author Max Shaposhnik (mshaposhnik@codenvy.com) - */ -@Filter -@Path("/activity{path:(/.*)?}") -public class ActivityPermissionsFilter extends CheMethodInvokerFilter { - - @Override - protected void filter(GenericResourceMethod genericResourceMethod, Object[] arguments) - throws ApiException { - final String methodName = genericResourceMethod.getMethod().getName(); - - final Subject currentSubject = EnvironmentContext.getCurrent().getSubject(); - String domain; - String action; - String instance; - - switch (methodName) { - case "active": - domain = WorkspaceDomain.DOMAIN_ID; - instance = (String) arguments[0]; - action = WorkspaceDomain.USE; - break; - case "getWorkspacesByActivity": - domain = SystemDomain.DOMAIN_ID; - instance = null; - action = SystemDomain.MONITOR_SYSTEM_ACTION; - break; - default: - throw new ForbiddenException("The user does not have permission to perform this operation"); - } - currentSubject.checkPermission(domain, instance, action); - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/pom.xml b/multiuser/permission/che-multiuser-permission-workspace/pom.xml deleted file mode 100644 index be5c8ab907c..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/pom.xml +++ /dev/null @@ -1,188 +0,0 @@ - - - - 4.0.0 - - che-multiuser-permission - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-permission-workspace - Che Multiuser :: Workspace Permissions - - false - - - - com.google.guava - guava - - - com.google.inject - guice - - - jakarta.inject - jakarta.inject-api - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-api-workspace - - - org.eclipse.che.core - che-core-api-workspace-shared - - - org.eclipse.che.core - che-core-commons-test - - - com.google.inject.extensions - guice-persist - provided - - - org.eclipse.che.core - che-core-api-model - provided - - - org.eclipse.che.multiuser - che-multiuser-api-permission - provided - - - org.eclipse.che.multiuser - che-multiuser-api-permission-shared - provided - - - org.eclipse.persistence - jakarta.persistence - provided - - - aopalliance - aopalliance - test - - - ch.qos.logback - logback-classic - test - - - commons-fileupload - commons-fileupload - test - - - io.rest-assured - rest-assured - test - - - org.eclipse.che.core - che-core-api-dto - test - - - org.eclipse.che.core - che-core-commons-inject - test - - - org.eclipse.che.core - che-core-commons-json - test - - - org.eclipse.che.core - che-core-sql-schema - test - - - org.eclipse.che.multiuser - che-multiuser-sql-schema - test - - - org.eclipse.persistence - org.eclipse.persistence.core - test - - - org.eclipse.persistence - org.eclipse.persistence.jpa - test - - - org.everrest - everrest-assured - test - - - org.flywaydb - flyway-core - test - - - org.hamcrest - hamcrest - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - **/spi/tck/*.* - - - - - - - - diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceApiPermissionsModule.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceApiPermissionsModule.java deleted file mode 100644 index 468fd2d7bfb..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceApiPermissionsModule.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server; - -import com.google.inject.AbstractModule; -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.shared.model.PermissionsDomain; -import org.eclipse.che.multiuser.permission.workspace.server.filters.WorkspaceRemoteSubscriptionPermissionFilter; - -/** - * @author Sergii Leschenko - */ -public class WorkspaceApiPermissionsModule extends AbstractModule { - - @Override - protected void configure() { - bind(WorkspaceRemoteSubscriptionPermissionFilter.class).asEagerSingleton(); - - Multibinder.newSetBinder( - binder(), - PermissionsDomain.class, - Names.named(SuperPrivilegesChecker.SUPER_PRIVILEGED_DOMAINS)) - .addBinding() - .to(WorkspaceDomain.class); - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceDomain.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceDomain.java deleted file mode 100644 index bac29ad1eb3..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/WorkspaceDomain.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server; - -import com.google.common.collect.ImmutableList; -import java.util.List; -import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain; -import org.eclipse.che.multiuser.permission.workspace.server.model.impl.WorkerImpl; - -/** - * Domain for storing workspaces' permissions - * - * @author Sergii Leschenko - */ -public class WorkspaceDomain extends AbstractPermissionsDomain { - public static final String READ = "read"; - public static final String RUN = "run"; - public static final String USE = "use"; - public static final String CONFIGURE = "configure"; - public static final String DELETE = "delete"; - - public static final String DOMAIN_ID = "workspace"; - - public WorkspaceDomain() { - super(DOMAIN_ID, ImmutableList.of(READ, RUN, USE, CONFIGURE, DELETE)); - } - - @Override - public WorkerImpl doCreateInstance( - String userId, String instanceId, List allowedActions) { - return new WorkerImpl(instanceId, userId, allowedActions); - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilter.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilter.java deleted file mode 100644 index cb023547a8a..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server.filters; - -import static org.eclipse.che.api.workspace.shared.Constants.BOOTSTRAPPER_STATUS_CHANGED_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.INSTALLER_LOG_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.INSTALLER_STATUS_CHANGED_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.MACHINE_LOG_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.MACHINE_STATUS_CHANGED_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.RUNTIME_LOG_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.SERVER_STATUS_CHANGED_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_STATUS_CHANGED_METHOD; - -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; -import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionCheck; -import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionManager; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; - -/** - * Holds and registers permissions checks for workspaces related events. - * - * @author Sergii Leshchenko - */ -@Singleton -public class WorkspaceRemoteSubscriptionPermissionFilter - implements RemoteSubscriptionPermissionCheck { - - @Inject - public void register(RemoteSubscriptionPermissionManager permissionFilter) { - permissionFilter.registerCheck( - this, - WORKSPACE_STATUS_CHANGED_METHOD, - MACHINE_STATUS_CHANGED_METHOD, - SERVER_STATUS_CHANGED_METHOD, - RUNTIME_LOG_METHOD, - MACHINE_LOG_METHOD, - INSTALLER_LOG_METHOD, - INSTALLER_STATUS_CHANGED_METHOD, - BOOTSTRAPPER_STATUS_CHANGED_METHOD); - } - - @Override - public void check(String methodName, Map scope) throws ForbiddenException { - String workspaceId = scope.get("workspaceId"); - - if (workspaceId == null) { - throw new ForbiddenException("Workspace id must be specified in scope"); - } - - Subject currentSubject = EnvironmentContext.getCurrent().getSubject(); - if (!currentSubject.hasPermission(WorkspaceDomain.DOMAIN_ID, workspaceId, WorkspaceDomain.RUN) - && !currentSubject.hasPermission( - WorkspaceDomain.DOMAIN_ID, workspaceId, WorkspaceDomain.USE)) { - throw new ForbiddenException( - "The current user doesn't have permissions to listen to the specified workspace events"); - } - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserWorkspaceJpaModule.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserWorkspaceJpaModule.java deleted file mode 100644 index 311289022d6..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserWorkspaceJpaModule.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server.jpa; - -import com.google.inject.AbstractModule; -import com.google.inject.TypeLiteral; -import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; -import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; -import org.eclipse.che.multiuser.permission.workspace.server.model.impl.WorkerImpl; -import org.eclipse.che.multiuser.permission.workspace.server.spi.jpa.MultiuserJpaWorkspaceDao; - -/** - * @author Yevhenii Voevodin - */ -public class MultiuserWorkspaceJpaModule extends AbstractModule { - - @Override - protected void configure() { - bind(WorkspaceDao.class).to(MultiuserJpaWorkspaceDao.class); - - bind(new TypeLiteral>() {}).to(WorkspaceDomain.class); - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/model/Worker.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/model/Worker.java deleted file mode 100644 index 85c474d4407..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/model/Worker.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server.model; - -import java.util.List; - -/** - * Describes relations between user and workspace - * - * @author Sergii Leschenko - */ -public interface Worker { - /** Returns user id */ - String getUserId(); - - /** Returns workspace id */ - String getWorkspaceId(); - - /** Returns list of workspace actions which can be performed by current user */ - List getActions(); -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/model/impl/WorkerImpl.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/model/impl/WorkerImpl.java deleted file mode 100644 index b595608d3f4..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/model/impl/WorkerImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server.model.impl; - -import java.util.ArrayList; -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.QueryHint; -import javax.persistence.Table; -import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; -import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; -import org.eclipse.che.multiuser.permission.workspace.server.model.Worker; - -/** - * Data object for {@link Worker} - * - * @author Sergii Leschenko - */ -@Entity(name = "Worker") -@NamedQueries({ - @NamedQuery( - name = "Worker.getByWorkspaceId", - query = - "SELECT worker " + "FROM Worker worker " + "WHERE worker.workspaceId = :workspaceId "), - @NamedQuery( - name = "Worker.getCountByWorkspaceId", - query = - "SELECT COUNT(worker) " - + "FROM Worker worker " - + "WHERE worker.workspaceId = :workspaceId "), - @NamedQuery( - name = "Worker.getByUserId", - query = "SELECT worker " + "FROM Worker worker " + "WHERE worker.userId = :userId "), - @NamedQuery( - name = "Worker.getByUserAndWorkspaceId", - query = - "SELECT worker " - + "FROM Worker worker " - + "WHERE worker.userId = :userId " - + "AND worker.workspaceId = :workspaceId ", - hints = {@QueryHint(name = "eclipselink.query-results-cache", value = "true")}) -}) -@Table(name = "che_worker") -public class WorkerImpl extends AbstractPermissions implements Worker { - - @Column(name = "workspace_id") - private String workspaceId; - - @ManyToOne - @JoinColumn(name = "workspace_id", insertable = false, updatable = false) - private WorkspaceImpl workspace; - - @ElementCollection(fetch = FetchType.EAGER) - @Column(name = "actions") - @CollectionTable(name = "che_worker_actions", joinColumns = @JoinColumn(name = "worker_id")) - protected List actions; - - public WorkerImpl() {} - - public WorkerImpl(String workspaceId, String userId, List actions) { - super(userId); - this.workspaceId = workspaceId; - if (actions != null) { - this.actions = new ArrayList<>(actions); - } - } - - public WorkerImpl(Worker worker) { - this(worker.getWorkspaceId(), worker.getUserId(), worker.getActions()); - } - - @Override - public String getInstanceId() { - return workspaceId; - } - - @Override - public String getDomainId() { - return WorkspaceDomain.DOMAIN_ID; - } - - @Override - public List getActions() { - return actions; - } - - @Override - public String getWorkspaceId() { - return workspaceId; - } - - @Override - public String toString() { - return "WorkerImpl{" - + "userId='" - + getUserId() - + '\'' - + ", workspaceId='" - + workspaceId - + '\'' - + ", actions=" - + actions - + '}'; - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java deleted file mode 100644 index f8ad74a20c3..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server.spi.jpa; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.lang.String.format; -import static java.util.Objects.requireNonNull; -import static java.util.stream.Collectors.toList; - -import com.google.inject.persist.Transactional; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import javax.inject.Inject; -import javax.inject.Provider; -import javax.inject.Singleton; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -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.notification.EventService; -import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; -import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; -import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; -import org.eclipse.che.api.workspace.shared.event.WorkspaceRemovedEvent; - -/** - * JPA based implementation of {@link WorkspaceDao}. - * - * @author Yevhenii Voevodin - */ -@Singleton -public class MultiuserJpaWorkspaceDao implements WorkspaceDao { - - @Inject private EventService eventService; - @Inject private Provider managerProvider; - - private static final String findByWorkerQuery = - "SELECT ws FROM Worker worker " - + " LEFT JOIN worker.workspace ws " - + " WHERE worker.userId = :userId " - + " AND 'read' MEMBER OF worker.actions"; - private static final String findByWorkerCountQuery = - "SELECT COUNT(ws) FROM Worker worker " - + " LEFT JOIN worker.workspace ws " - + " WHERE worker.userId = :userId " - + " AND 'read' MEMBER OF worker.actions"; - - @Override - public WorkspaceImpl create(WorkspaceImpl workspace) throws ConflictException, ServerException { - requireNonNull(workspace, "Required non-null workspace"); - try { - doCreate(workspace); - } catch (RuntimeException x) { - throw new ServerException(x.getMessage(), x); - } - return new WorkspaceImpl(workspace); - } - - @Override - public WorkspaceImpl update(WorkspaceImpl update) - throws NotFoundException, ConflictException, ServerException { - requireNonNull(update, "Required non-null update"); - try { - return new WorkspaceImpl(doUpdate(update)); - } catch (RuntimeException x) { - throw new ServerException(x.getMessage(), x); - } - } - - @Override - public Optional remove(String id) throws ServerException { - requireNonNull(id, "Required non-null id"); - Optional workspaceOpt; - try { - workspaceOpt = doRemove(id); - workspaceOpt.ifPresent( - workspace -> eventService.publish(new WorkspaceRemovedEvent(workspace))); - } catch (RuntimeException x) { - throw new ServerException(x.getLocalizedMessage(), x); - } - return workspaceOpt; - } - - @Override - @Transactional - public WorkspaceImpl get(String id) throws NotFoundException, ServerException { - requireNonNull(id, "Required non-null id"); - try { - final WorkspaceImpl workspace = managerProvider.get().find(WorkspaceImpl.class, id); - if (workspace == null) { - throw new NotFoundException(format("Workspace with id '%s' doesn't exist", id)); - } - return new WorkspaceImpl(workspace); - } catch (RuntimeException x) { - throw new ServerException(x.getLocalizedMessage(), x); - } - } - - @Override - @Transactional - public WorkspaceImpl get(String name, String namespace) - throws NotFoundException, ServerException { - requireNonNull(name, "Required non-null name"); - requireNonNull(namespace, "Required non-null namespace"); - try { - return new WorkspaceImpl( - managerProvider - .get() - .createNamedQuery("Workspace.getByName", WorkspaceImpl.class) - .setParameter("namespace", namespace) - .setParameter("name", name) - .getSingleResult()); - } catch (NoResultException noResEx) { - throw new NotFoundException( - format("Workspace with name '%s' in namespace '%s' doesn't exist", name, namespace)); - } catch (RuntimeException x) { - throw new ServerException(x.getLocalizedMessage(), x); - } - } - - @Override - @Transactional - public Page getByNamespace(String namespace, int maxItems, long skipCount) - throws ServerException { - requireNonNull(namespace, "Required non-null namespace"); - try { - final EntityManager manager = managerProvider.get(); - final List list = - manager - .createNamedQuery("Workspace.getByNamespace", WorkspaceImpl.class) - .setParameter("namespace", namespace) - .setMaxResults(maxItems) - .setFirstResult((int) skipCount) - .getResultList() - .stream() - .map(WorkspaceImpl::new) - .collect(Collectors.toList()); - final long count = - manager - .createNamedQuery("Workspace.getByNamespaceCount", Long.class) - .setParameter("namespace", namespace) - .getSingleResult(); - return new Page<>(list, skipCount, maxItems, count); - } catch (RuntimeException x) { - throw new ServerException(x.getLocalizedMessage(), x); - } - } - - @Override - @Transactional - public Page getWorkspaces(String userId, int maxItems, long skipCount) - throws ServerException { - try { - final List list = - managerProvider - .get() - .createQuery(findByWorkerQuery, WorkspaceImpl.class) - .setParameter("userId", userId) - .setMaxResults(maxItems) - .setFirstResult((int) skipCount) - .getResultList(); - - final long count = - managerProvider - .get() - .createQuery(findByWorkerCountQuery, Long.class) - .setParameter("userId", userId) - .getSingleResult(); - - return new Page<>(list, skipCount, maxItems, count); - } catch (RuntimeException x) { - throw new ServerException(x.getLocalizedMessage(), x); - } - } - - @Override - @Transactional - public Page getWorkspaces(boolean isTemporary, int maxItems, long skipCount) - throws 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 or greater than " + Integer.MAX_VALUE); - try { - final List list = - managerProvider - .get() - .createNamedQuery("Workspace.getByTemporary", WorkspaceImpl.class) - .setParameter("temporary", isTemporary) - .setMaxResults(maxItems) - .setFirstResult((int) skipCount) - .getResultList() - .stream() - .map(WorkspaceImpl::new) - .collect(toList()); - final long count = - managerProvider - .get() - .createNamedQuery("Workspace.getByTemporaryCount", Long.class) - .setParameter("temporary", isTemporary) - .getSingleResult(); - return new Page<>(list, skipCount, maxItems, count); - } catch (RuntimeException x) { - throw new ServerException(x.getLocalizedMessage(), x); - } - } - - @Override - @Transactional - public long getWorkspacesTotalCount() throws ServerException { - try { - return managerProvider - .get() - .createNamedQuery("Workspace.getWorkspacesTotalCount", Long.class) - .getSingleResult(); - } catch (RuntimeException x) { - throw new ServerException(x.getLocalizedMessage(), x); - } - } - - @Transactional - protected void doCreate(WorkspaceImpl workspace) { - if (workspace.getConfig() != null) { - workspace.getConfig().getProjects().forEach(ProjectConfigImpl::prePersistAttributes); - } - EntityManager manager = managerProvider.get(); - manager.persist(workspace); - manager.flush(); - } - - @Transactional(rollbackOn = {RuntimeException.class, ServerException.class}) - protected Optional doRemove(String id) throws ServerException { - final WorkspaceImpl workspace = managerProvider.get().find(WorkspaceImpl.class, id); - if (workspace == null) { - return Optional.empty(); - } - final EntityManager manager = managerProvider.get(); - manager.remove(workspace); - manager.flush(); - return Optional.of(workspace); - } - - @Transactional - protected WorkspaceImpl doUpdate(WorkspaceImpl update) throws NotFoundException { - EntityManager manager = managerProvider.get(); - if (manager.find(WorkspaceImpl.class, update.getId()) == null) { - throw new NotFoundException(format("Workspace with id '%s' doesn't exist", update.getId())); - } - if (update.getConfig() != null) { - update.getConfig().getProjects().forEach(ProjectConfigImpl::prePersistAttributes); - } - WorkspaceImpl merged = manager.merge(update); - manager.flush(); - return merged; - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilterTest.java b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilterTest.java deleted file mode 100644 index 88b5ba86904..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspaceRemoteSubscriptionPermissionFilterTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server.filters; - -import static org.eclipse.che.api.workspace.shared.Constants.BOOTSTRAPPER_STATUS_CHANGED_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.INSTALLER_LOG_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.INSTALLER_STATUS_CHANGED_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.MACHINE_LOG_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.MACHINE_STATUS_CHANGED_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.RUNTIME_LOG_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.SERVER_STATUS_CHANGED_METHOD; -import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_STATUS_CHANGED_METHOD; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.ImmutableMap; -import java.util.Collections; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; -import org.eclipse.che.multiuser.api.permission.server.jsonrpc.RemoteSubscriptionPermissionManager; -import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** - * Tests {@link WorkspaceRemoteSubscriptionPermissionFilter} - * - * @author Sergii Leshchenko - */ -@Listeners(MockitoTestNGListener.class) -public class WorkspaceRemoteSubscriptionPermissionFilterTest { - - @Mock private RemoteSubscriptionPermissionManager permissionManager; - - @Mock private Subject subject; - - private WorkspaceRemoteSubscriptionPermissionFilter permissionFilter; - - @BeforeMethod - public void setUp() { - EnvironmentContext.getCurrent().setSubject(subject); - permissionFilter = new WorkspaceRemoteSubscriptionPermissionFilter(); - } - - @AfterMethod - public void tearDown() { - EnvironmentContext.reset(); - } - - @Test - public void shouldRegisterItself() { - // when - permissionFilter.register(permissionManager); - - // then - verify(permissionManager) - .registerCheck( - permissionFilter, - WORKSPACE_STATUS_CHANGED_METHOD, - MACHINE_STATUS_CHANGED_METHOD, - SERVER_STATUS_CHANGED_METHOD, - RUNTIME_LOG_METHOD, - MACHINE_LOG_METHOD, - INSTALLER_LOG_METHOD, - INSTALLER_STATUS_CHANGED_METHOD, - BOOTSTRAPPER_STATUS_CHANGED_METHOD); - } - - @Test( - expectedExceptions = ForbiddenException.class, - expectedExceptionsMessageRegExp = - "The current user doesn't have permissions to listen to the specified workspace events") - public void shouldThrowExceptionIfUserDoesNotHaveRunNorUsePermissions() throws Exception { - // given - doReturn(false) - .when(subject) - .hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN); - doReturn(false) - .when(subject) - .hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.USE); - - // when - permissionFilter.check("ignored", ImmutableMap.of("workspaceId", "ws123")); - } - - @Test( - expectedExceptions = ForbiddenException.class, - expectedExceptionsMessageRegExp = "Workspace id must be specified in scope") - public void shouldThrowExceptionIfWorkspaceIdIsMissing() throws Exception { - // given - doReturn(false) - .when(subject) - .hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN); - doReturn(false) - .when(subject) - .hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.USE); - - // when - permissionFilter.check("ignored", Collections.emptyMap()); - } - - @Test - public void shouldDoNothingIfUserHasAtLeastRunPermission() throws Exception { - // given - lenient() - .doReturn(false) - .when(subject) - .hasPermission(eq(WorkspaceDomain.DOMAIN_ID), any(), any()); - doReturn(true) - .when(subject) - .hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.RUN); - - // when - permissionFilter.check("ignored", ImmutableMap.of("workspaceId", "ws123")); - } - - @Test - public void shouldDoNothingIfUserHasAtLeastUsePermission() throws Exception { - // given - lenient() - .doReturn(false) - .when(subject) - .hasPermission(eq(WorkspaceDomain.DOMAIN_ID), any(), any()); - doReturn(true) - .when(subject) - .hasPermission(WorkspaceDomain.DOMAIN_ID, "ws123", WorkspaceDomain.USE); - - // when - permissionFilter.check("ignored", ImmutableMap.of("workspaceId", "ws123")); - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/EntityManagerExceptionInterceptor.java b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/EntityManagerExceptionInterceptor.java deleted file mode 100644 index 430c2d66be9..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/EntityManagerExceptionInterceptor.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2012-2025 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.multiuser.permission.workspace.server.spi.jpa; - -import com.google.inject.Inject; -import com.google.inject.Provider; -import javax.persistence.EntityManager; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -public class EntityManagerExceptionInterceptor implements MethodInterceptor { - @Inject Provider emf; - - @Override - public Object invoke(MethodInvocation methodInvocation) throws Throwable { - emf.get().getTransaction().setRollbackOnly(); - throw new RuntimeException("Database exception"); - } -} diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule b/multiuser/permission/che-multiuser-permission-workspace/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule deleted file mode 100644 index 21a216704b1..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/test/resources/META-INF/services/org.eclipse.che.commons.test.tck.TckModule +++ /dev/null @@ -1 +0,0 @@ -org.eclipse.che.multiuser.permission.workspace.server.spi.jpa.JpaTckModule diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/resources/logback-test.xml b/multiuser/permission/che-multiuser-permission-workspace/src/test/resources/logback-test.xml deleted file mode 100644 index c7a7b0b5cf3..00000000000 --- a/multiuser/permission/che-multiuser-permission-workspace/src/test/resources/logback-test.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n%nopex - - - - target/log/test.log - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n - - - - - - - - - - diff --git a/multiuser/permission/pom.xml b/multiuser/permission/pom.xml deleted file mode 100644 index e7beea9ed70..00000000000 --- a/multiuser/permission/pom.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - 4.0.0 - - che-multiuser-parent - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - ../pom.xml - - che-multiuser-permission - pom - Che Multiuser :: Permissions Parent - - che-multiuser-permission-devfile - che-multiuser-permission-workspace - che-multiuser-permission-workspace-activity - che-multiuser-permission-system - che-multiuser-permission-logger - - diff --git a/multiuser/personal-account/pom.xml b/multiuser/personal-account/pom.xml deleted file mode 100644 index 71c75118dc4..00000000000 --- a/multiuser/personal-account/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - 4.0.0 - - che-multiuser-parent - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - - che-multiuser-personal-account - jar - Che Multiuser :: Personal account - - - com.google.inject - guice - - - com.google.inject.extensions - guice-persist - - - jakarta.inject - jakarta.inject-api - - - org.eclipse.che.core - che-core-api-account - - - org.eclipse.che.core - che-core-api-core - - - org.eclipse.che.core - che-core-api-model - - - org.eclipse.che.core - che-core-api-user - - - org.eclipse.che.core - che-core-commons-inject - - - org.eclipse.che.core - che-core-commons-lang - - - org.eclipse.che.core - che-core-commons-test - - - org.eclipse.che.multiuser - che-multiuser-api-permission - - - org.eclipse.che.multiuser - che-multiuser-api-resource - - - ch.qos.logback - logback-classic - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.testng - testng - test - - - diff --git a/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/DefaultUserResourcesProvider.java b/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/DefaultUserResourcesProvider.java deleted file mode 100644 index 2c0a333cec3..00000000000 --- a/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/DefaultUserResourcesProvider.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.account.personal; - -import static java.util.Arrays.asList; - -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.api.user.server.UserManager; -import org.eclipse.che.commons.lang.Size; -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 personal accounts by default. - * - * @author Sergii Leschenko - */ -@Singleton -public class DefaultUserResourcesProvider implements DefaultResourcesProvider { - private final long timeout; - private final long ramPerUser; - private final int workspacesPerUser; - private final int runtimesPerUser; - - @Inject - public DefaultUserResourcesProvider( - @Named("che.limits.workspace.idle.timeout") long timeout, - @Named("che.limits.user.workspaces.ram") String ramPerUser, - @Named("che.limits.user.workspaces.count") int workspacesPerUser, - @Named("che.limits.user.workspaces.run.count") int runtimesPerUser) { - this.timeout = TimeUnit.MILLISECONDS.toMinutes(timeout); - this.ramPerUser = "-1".equals(ramPerUser) ? -1 : Size.parseSizeToMegabytes(ramPerUser); - this.workspacesPerUser = workspacesPerUser; - this.runtimesPerUser = runtimesPerUser; - } - - @Override - public String getAccountType() { - return UserManager.PERSONAL_ACCOUNT; - } - - @Override - public List getResources(String accountId) - throws ServerException, NotFoundException { - return asList( - new ResourceImpl(TimeoutResourceType.ID, timeout, TimeoutResourceType.UNIT), - new ResourceImpl(RamResourceType.ID, ramPerUser, RamResourceType.UNIT), - new ResourceImpl(WorkspaceResourceType.ID, workspacesPerUser, WorkspaceResourceType.UNIT), - new ResourceImpl(RuntimeResourceType.ID, runtimesPerUser, RuntimeResourceType.UNIT)); - } -} diff --git a/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/PersonalAccountModule.java b/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/PersonalAccountModule.java deleted file mode 100644 index 2b53e9acf53..00000000000 --- a/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/PersonalAccountModule.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.account.personal; - -import com.google.inject.AbstractModule; -import com.google.inject.multibindings.Multibinder; -import org.eclipse.che.api.user.server.UserManager; -import org.eclipse.che.inject.DynaModule; -import org.eclipse.che.multiuser.api.permission.server.account.AccountPermissionsChecker; -import org.eclipse.che.multiuser.permission.account.PersonalAccountPermissionsChecker; -import org.eclipse.che.multiuser.resource.api.free.DefaultResourcesProvider; - -/** - * @author Sergii Leschenko - */ -@DynaModule -public class PersonalAccountModule extends AbstractModule { - @Override - protected void configure() { - Multibinder.newSetBinder(binder(), DefaultResourcesProvider.class) - .addBinding() - .to(DefaultUserResourcesProvider.class); - - Multibinder.newSetBinder(binder(), AccountPermissionsChecker.class) - .addBinding() - .to(PersonalAccountPermissionsChecker.class); - - bind(UserManager.class).to(PersonalAccountUserManager.class); - } -} diff --git a/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/PersonalAccountUserManager.java b/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/PersonalAccountUserManager.java deleted file mode 100644 index 463dc765034..00000000000 --- a/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/api/account/personal/PersonalAccountUserManager.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.account.personal; - -import com.google.inject.persist.Transactional; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -import org.eclipse.che.account.api.AccountManager; -import org.eclipse.che.account.spi.AccountImpl; -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.ServerException; -import org.eclipse.che.api.core.model.user.User; -import org.eclipse.che.api.core.notification.EventService; -import org.eclipse.che.api.user.server.UserManager; -import org.eclipse.che.api.user.server.spi.PreferenceDao; -import org.eclipse.che.api.user.server.spi.ProfileDao; -import org.eclipse.che.api.user.server.spi.UserDao; - -/** - * Manager that ensures that every user has one and only one personal account. Doesn't contain any - * logic related to user changing. - * - * @author Sergii Leschenko - */ -@Singleton -public class PersonalAccountUserManager extends UserManager { - public static final String PERSONAL_ACCOUNT = "personal"; - - private final AccountManager accountManager; - - @Inject - public PersonalAccountUserManager( - UserDao userDao, - ProfileDao profileDao, - PreferenceDao preferencesDao, - @Named("che.auth.reserved_user_names") String[] reservedNames, - AccountManager accountManager, - EventService eventService) { - super(userDao, profileDao, preferencesDao, eventService, reservedNames); - this.accountManager = accountManager; - } - - @Transactional(rollbackOn = {RuntimeException.class, ApiException.class}) - @Override - public User create(User newUser, boolean isTemporary) throws ConflictException, ServerException { - User createdUser = super.create(newUser, isTemporary); - return createdUser; - } - - @Transactional(rollbackOn = {RuntimeException.class, ApiException.class}) - @Override - public void update(User user) throws NotFoundException, ServerException, ConflictException { - User originalUser = getById(user.getId()); - - if (!originalUser.getName().equals(user.getName())) { - accountManager.update(new AccountImpl(user.getId(), user.getName(), PERSONAL_ACCOUNT)); - } - - super.update(user); - } - - @Transactional(rollbackOn = {RuntimeException.class, ApiException.class}) - @Override - public void remove(String id) throws ServerException, ConflictException { - accountManager.remove(id); - super.remove(id); - } -} diff --git a/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/permission/account/PersonalAccountPermissionsChecker.java b/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/permission/account/PersonalAccountPermissionsChecker.java deleted file mode 100644 index 715c50a5fb5..00000000000 --- a/multiuser/personal-account/src/main/java/org/eclipse/che/multiuser/permission/account/PersonalAccountPermissionsChecker.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.account; - -import javax.inject.Singleton; -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.user.server.UserManager; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.multiuser.api.permission.server.account.AccountOperation; -import org.eclipse.che.multiuser.api.permission.server.account.AccountPermissionsChecker; - -/** - * Defines permissions checking for personal accounts. - * - *

Throws exception during permissions checking when user tries to perform any operation with - * foreign personal account. - * - * @author Sergii Leshchenko - */ -@Singleton -public class PersonalAccountPermissionsChecker implements AccountPermissionsChecker { - @Override - public void checkPermissions(String id, AccountOperation operation) throws ForbiddenException { - // ignore action because user should be able to do anything in his personal account - if (!EnvironmentContext.getCurrent().getSubject().getUserId().equals(id)) { - throw new ForbiddenException("User is not authorized to use specified account"); - } - } - - @Override - public String getAccountType() { - return UserManager.PERSONAL_ACCOUNT; - } -} diff --git a/multiuser/personal-account/src/test/java/org/eclipse/che/multiuser/api/account/personal/DefaultUserResourcesProviderTest.java b/multiuser/personal-account/src/test/java/org/eclipse/che/multiuser/api/account/personal/DefaultUserResourcesProviderTest.java deleted file mode 100644 index 491cbe685e3..00000000000 --- a/multiuser/personal-account/src/test/java/org/eclipse/che/multiuser/api/account/personal/DefaultUserResourcesProviderTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.account.personal; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import java.util.List; -import org.eclipse.che.api.user.server.UserManager; -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; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * Tests for {@link DefaultUserResourcesProvider} - * - * @author Sergii Leschenko - */ -public class DefaultUserResourcesProviderTest { - private DefaultUserResourcesProvider resourcesProvider; - - @BeforeMethod - public void setUp() throws Exception { - resourcesProvider = new DefaultUserResourcesProvider(20 * 60 * 1000, "2gb", 10, 5); - } - - @Test - public void shouldReturnPersonalAccountType() throws Exception { - // when - final String accountType = resourcesProvider.getAccountType(); - - // then - assertEquals(accountType, UserManager.PERSONAL_ACCOUNT); - } - - @Test - public void shouldProvideDefaultRamResourceForUser() throws Exception { - // when - final List defaultResources = resourcesProvider.getResources("user123"); - - // then - assertEquals(defaultResources.size(), 4); - assertTrue( - defaultResources.contains( - new ResourceImpl(RamResourceType.ID, 2048, RamResourceType.UNIT))); - assertTrue( - defaultResources.contains( - new ResourceImpl(WorkspaceResourceType.ID, 10, WorkspaceResourceType.UNIT))); - assertTrue( - defaultResources.contains( - new ResourceImpl(RuntimeResourceType.ID, 5, RuntimeResourceType.UNIT))); - assertTrue( - defaultResources.contains( - new ResourceImpl(TimeoutResourceType.ID, 20, TimeoutResourceType.UNIT))); - } -} diff --git a/multiuser/personal-account/src/test/java/org/eclipse/che/multiuser/permission/account/PersonalAccountPermissionsCheckerTest.java b/multiuser/personal-account/src/test/java/org/eclipse/che/multiuser/permission/account/PersonalAccountPermissionsCheckerTest.java deleted file mode 100644 index 7c533c8c5b5..00000000000 --- a/multiuser/personal-account/src/test/java/org/eclipse/che/multiuser/permission/account/PersonalAccountPermissionsCheckerTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2012-2025 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.account; - -import static org.mockito.Mockito.lenient; - -import org.eclipse.che.api.core.ForbiddenException; -import org.eclipse.che.api.user.server.UserManager; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.Assert; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -@Listeners(MockitoTestNGListener.class) -public class PersonalAccountPermissionsCheckerTest { - private static String userId = "userok"; - @Mock private Subject subject; - - private PersonalAccountPermissionsChecker permissionsChecker; - - @BeforeMethod - public void setUp() { - lenient().when(subject.getUserId()).thenReturn(userId); - EnvironmentContext.getCurrent().setSubject(subject); - - permissionsChecker = new PersonalAccountPermissionsChecker(); - } - - @AfterMethod - public void cleanUp() { - EnvironmentContext.getCurrent().setSubject(null); - } - - @Test - public void shouldNotThrowExceptionWhenUserIdFromSubjectEqualsToSpecifiedAccountId() - throws Exception { - permissionsChecker.checkPermissions(userId, null); - } - - @Test( - expectedExceptions = ForbiddenException.class, - expectedExceptionsMessageRegExp = "User is not authorized to use specified account") - public void shouldThrowForbiddenExceptionWhenUserIdFromSubjectDoesNotEqualToSpecifiedAccountId() - throws Exception { - permissionsChecker.checkPermissions("anotherUserId", null); - } - - @Test - public void shouldReturnPersonalAccountType() throws Exception { - // when - final String accountType = permissionsChecker.getAccountType(); - - // then - Assert.assertEquals(accountType, UserManager.PERSONAL_ACCOUNT); - } -} diff --git a/multiuser/personal-account/src/test/resources/logback-test.xml b/multiuser/personal-account/src/test/resources/logback-test.xml deleted file mode 100644 index 3d4d10adab1..00000000000 --- a/multiuser/personal-account/src/test/resources/logback-test.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n - - - - - - - diff --git a/multiuser/pom.xml b/multiuser/pom.xml index cd33ca8f2d1..598c86a3e76 100644 --- a/multiuser/pom.xml +++ b/multiuser/pom.xml @@ -25,12 +25,8 @@ pom Che Multiuser :: Parent - sql-schema api - permission - keycloak machine-auth - personal-account oidc diff --git a/multiuser/sql-schema/pom.xml b/multiuser/sql-schema/pom.xml deleted file mode 100644 index 27d4f050368..00000000000 --- a/multiuser/sql-schema/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - 4.0.0 - - che-multiuser-parent - org.eclipse.che.multiuser - 7.117.0-SNAPSHOT - ../pom.xml - - che-multiuser-sql-schema - Che Multiuser :: Sql Schema - - - - com.mycila - license-maven-plugin - - - **/*.sql - - - - - - diff --git a/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.1__add_permissions.sql b/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.1__add_permissions.sql deleted file mode 100644 index 50709dff4f9..00000000000 --- a/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.1__add_permissions.sql +++ /dev/null @@ -1,122 +0,0 @@ --- --- Copyright (c) 2012-2017 Red Hat, Inc. --- All rights reserved. This program and the accompanying materials --- are made available under the terms of the Eclipse Public License v1.0 --- which accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- Contributors: --- Red Hat, Inc. - initial API and implementation --- - --- System permissions ---------------------------------------------------------- -CREATE TABLE che_system_permissions ( - id VARCHAR(255) NOT NULL, - user_id VARCHAR(255), - - PRIMARY KEY (id) -); --- indexes -CREATE UNIQUE INDEX che_index_system_permissions_user_id ON che_system_permissions (user_id); --- constraints -ALTER TABLE che_system_permissions ADD CONSTRAINT che_fk_system_permissions_user_id FOREIGN KEY (user_id) REFERENCES usr (id); --------------------------------------------------------------------------------- - - --- System permissions actions -------------------------------------------------- -CREATE TABLE che_system_permissions_actions ( - system_permissions_id VARCHAR(255), - actions VARCHAR(255) -); --- indexes -CREATE INDEX che_index_system_permissions_actions_actions ON che_system_permissions_actions (actions); --- constraints -ALTER TABLE che_system_permissions_actions ADD CONSTRAINT che_fk_system_permissions_actions_system_permissions_id FOREIGN KEY (system_permissions_id) REFERENCES che_system_permissions (id); --------------------------------------------------------------------------------- - - --- Workspace workers ----------------------------------------------------------- -CREATE TABLE che_worker ( - id VARCHAR(255) NOT NULL, - user_id VARCHAR(255), - workspace_id VARCHAR(255), - - PRIMARY KEY (id) -); --- indexes -CREATE UNIQUE INDEX che_index_worker_user_id_workspace_id ON che_worker (user_id, workspace_id); -CREATE INDEX che_index_worker_workspace_id ON che_worker (workspace_id); --- constraints -ALTER TABLE che_worker ADD CONSTRAINT che_fk_worker_user_id FOREIGN KEY (user_id) REFERENCES usr (id); -ALTER TABLE che_worker ADD CONSTRAINT che_fk_worker_workspace_id FOREIGN KEY (workspace_id) REFERENCES workspace (id); --------------------------------------------------------------------------------- - - --- Worker actions -------------------------------------------------------------- -CREATE TABLE che_worker_actions ( - worker_id VARCHAR(255), - actions VARCHAR(255) -); --- indexes -CREATE INDEX che_index_worker_actions_actions ON che_worker_actions (actions); --- constraints -ALTER TABLE che_worker_actions ADD CONSTRAINT che_fk_worker_actions_worker_id FOREIGN KEY (worker_id) REFERENCES che_worker (id); --------------------------------------------------------------------------------- - - --- Stack permissions ----------------------------------------------------------- -CREATE TABLE che_stack_permissions ( - id VARCHAR(255) NOT NULL, - stack_id VARCHAR(255), - user_id VARCHAR(255), - - PRIMARY KEY (id) -); --- indexes -CREATE UNIQUE INDEX che_index_stack_permissions_user_id_stack_id ON che_stack_permissions (user_id, stack_id); -CREATE INDEX che_index_stack_permissions_stack_id ON che_stack_permissions (stack_id); --- constraints -ALTER TABLE che_stack_permissions ADD CONSTRAINT che_fk_stack_permissions_user_id FOREIGN KEY (user_id) REFERENCES usr (id); -ALTER TABLE che_stack_permissions ADD CONSTRAINT che_fk_stack_permissions_stack_id FOREIGN KEY (stack_id) REFERENCES stack (id); --------------------------------------------------------------------------------- - - --- Stack permissions actions --------------------------------------------------- -CREATE TABLE che_stack_permissions_actions ( - stack_permissions_id VARCHAR(255), - actions VARCHAR(255) -); --- indexes -CREATE INDEX che_index_stack_permissions_actions_actions ON che_stack_permissions_actions (actions); --- constraints -ALTER TABLE che_stack_permissions_actions ADD CONSTRAINT che_fk_stack_permissions_actions_stack_permissions_id FOREIGN KEY (stack_permissions_id) REFERENCES che_stack_permissions (id); --------------------------------------------------------------------------------- - - --- Recipe permissions ---------------------------------------------------------- -CREATE TABLE che_recipe_permissions ( - id VARCHAR(255) NOT NULL, - recipe_id VARCHAR(255), - user_id VARCHAR(255), - - PRIMARY KEY (id) -); --- indexes -CREATE UNIQUE INDEX che_index_recipe_permissions_user_id_recipe_id ON che_recipe_permissions (user_id, recipe_id); -CREATE INDEX che_index_recipe_permissions_recipe_id ON che_recipe_permissions (recipe_id); --- constraints -ALTER TABLE che_recipe_permissions ADD CONSTRAINT che_fk_recipe_permissions_user_id FOREIGN KEY (user_id) REFERENCES usr (id); -ALTER TABLE che_recipe_permissions ADD CONSTRAINT che_fk_recipe_permissions_recipe_id FOREIGN KEY (recipe_id) REFERENCES recipe (id); --------------------------------------------------------------------------------- - - --- Recipe permissions actions -------------------------------------------------- -CREATE TABLE che_recipe_permissions_actions ( - recipe_permissions_id varchar(255), - actions VARCHAR(255) -); --- indexes -CREATE index che_index_recipe_permissions_actions_actions ON che_recipe_permissions_actions (actions); --- constraints -ALTER TABLE che_recipe_permissions_actions ADD CONSTRAINT che_fk_recipe_permissions_actions_recipe_permissions_id FOREIGN KEY (recipe_permissions_id) REFERENCES che_recipe_permissions (id); --------------------------------------------------------------------------------- diff --git a/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.2__add_resources.sql b/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.2__add_resources.sql deleted file mode 100644 index 01a6ab974b2..00000000000 --- a/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.2__add_resources.sql +++ /dev/null @@ -1,44 +0,0 @@ --- --- Copyright (c) 2012-2017 Red Hat, Inc. --- All rights reserved. This program and the accompanying materials --- are made available under the terms of the Eclipse Public License v1.0 --- which accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- Contributors: --- Red Hat, Inc. - initial API and implementation --- - --- Resource -------------------------------------------------------------------- -CREATE TABLE che_resource ( - id BIGINT NOT NULL, - amount BIGINT, - type VARCHAR(255) NOT NULL, - unit VARCHAR(255) NOT NULL, - - PRIMARY KEY (id) -); --------------------------------------------------------------------------------- - --- Free resource limit --------------------------------------------------------- -CREATE TABLE che_free_resources_limit ( - account_id VARCHAR(255) NOT NULL, - - PRIMARY KEY (account_id) -); --- constraints -ALTER TABLE che_free_resources_limit ADD CONSTRAINT che_fk_free_resources_limit_account_id FOREIGN KEY (account_id) REFERENCES account (id); --------------------------------------------------------------------------------- - - --- Free resource limit resource ------------------------------------------------ -CREATE TABLE che_free_resources_limit_resource ( - free_resources_limit_account_id VARCHAR(255) NOT NULL, - resources_id BIGINT NOT NULL, - - PRIMARY KEY (free_resources_limit_account_id, resources_id) -); --- constraints -ALTER TABLE che_free_resources_limit_resource ADD CONSTRAINT che_fk_free_resources_limit_resource_resources_id FOREIGN KEY (resources_id) REFERENCES che_resource (id); -ALTER TABLE che_free_resources_limit_resource ADD CONSTRAINT che_fk_free_resources_limit_resource_account_id FOREIGN KEY (free_resources_limit_account_id) REFERENCES che_free_resources_limit (account_id); --------------------------------------------------------------------------------- diff --git a/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.3__add_organization.sql b/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.3__add_organization.sql deleted file mode 100644 index d81883bd8e3..00000000000 --- a/multiuser/sql-schema/src/main/resources/che-schema/5.19.0/0.3__add_organization.sql +++ /dev/null @@ -1,77 +0,0 @@ --- --- Copyright (c) 2012-2017 Red Hat, Inc. --- All rights reserved. This program and the accompanying materials --- are made available under the terms of the Eclipse Public License v1.0 --- which accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- Contributors: --- Red Hat, Inc. - initial API and implementation --- - --- Organization ---------------------------------------------------------------- -CREATE TABLE che_organization ( - id VARCHAR(255) NOT NULL, - parent VARCHAR(255), - account_id VARCHAR(255) NOT NULL, - - PRIMARY KEY (id) -); --- indexes -CREATE INDEX che_index_organization_parent ON che_organization (parent); --- constraints -ALTER TABLE che_organization ADD CONSTRAINT che_fk_organization_parent FOREIGN KEY (parent) REFERENCES che_organization (id); -ALTER TABLE che_organization ADD CONSTRAINT che_fk_organization_account_id FOREIGN KEY (account_id) REFERENCES account (id); --------------------------------------------------------------------------------- - - --- Organization member --------------------------------------------------------- -CREATE TABLE che_member ( - id VARCHAR(255) NOT NULL, - organization_id VARCHAR(255), - user_id VARCHAR(255), - - PRIMARY KEY (id) -); --- indexes -CREATE UNIQUE INDEX che_index_member_user_id_organization_id ON che_member (user_id, organization_id); -CREATE INDEX che_index_member_organization_id ON che_member (organization_id); --- constraints -ALTER TABLE che_member ADD CONSTRAINT che_fk_member_organization_id FOREIGN KEY (organization_id) REFERENCES che_organization (id); -ALTER TABLE che_member ADD CONSTRAINT che_fk_member_user_id FOREIGN KEY (user_id) REFERENCES usr (id); --------------------------------------------------------------------------------- - - ---Member actions --------------------------------------------------------------- -CREATE TABLE che_member_actions ( - member_id VARCHAR(255), - actions VARCHAR(255) -); --- indexes -CREATE INDEX che_index_member_actions_actions ON che_member_actions (actions); --- constraints -ALTER TABLE che_member_actions ADD CONSTRAINT che_fk_member_actions_member_id FOREIGN KEY (member_id) REFERENCES che_member (id); --------------------------------------------------------------------------------- - --- Organization distributed resources ----------------------------------------------------------- -CREATE TABLE che_organization_distributed_resources ( - organization_id VARCHAR(255) NOT NULL, - - PRIMARY KEY (organization_id) -); --- constraints -ALTER TABLE che_organization_distributed_resources ADD CONSTRAINT che_fk_org_distributed_res_organization_id FOREIGN KEY (organization_id) REFERENCES che_organization (id); --------------------------------------------------------------------------------- - - --- Organization distributed resources to resource ------------------------------------------------ -CREATE TABLE che_organization_distributed_resources_resource ( - organization_distributed_resources_id VARCHAR(255) NOT NULL, - resource_id BIGINT NOT NULL, - - PRIMARY KEY (organization_distributed_resources_id, resource_id) -); --- constraints -ALTER TABLE che_organization_distributed_resources_resource ADD CONSTRAINT che_fk_org_distributed_res_resource_resource_id FOREIGN KEY (resource_id) REFERENCES che_resource (id); -ALTER TABLE che_organization_distributed_resources_resource ADD CONSTRAINT che_fk_org_distributed_res_resource_org_distributed_res_id FOREIGN KEY (organization_distributed_resources_id) REFERENCES che_organization_distributed_resources (organization_id); --------------------------------------------------------------------------------- diff --git a/multiuser/sql-schema/src/main/resources/che-schema/6.0.0/3.1__remove_old_recipe_permissions.sql b/multiuser/sql-schema/src/main/resources/che-schema/6.0.0/3.1__remove_old_recipe_permissions.sql deleted file mode 100644 index 5224fe6dffa..00000000000 --- a/multiuser/sql-schema/src/main/resources/che-schema/6.0.0/3.1__remove_old_recipe_permissions.sql +++ /dev/null @@ -1,14 +0,0 @@ --- --- Copyright (c) 2012-2017 Red Hat, Inc. --- All rights reserved. This program and the accompanying materials --- are made available under the terms of the Eclipse Public License v1.0 --- which accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- Contributors: --- Red Hat, Inc. - initial API and implementation --- - -DROP TABLE che_recipe_permissions_actions; -DROP TABLE che_recipe_permissions; - diff --git a/multiuser/sql-schema/src/main/resources/che-schema/6.3.0/1.1__add_fk_indexes.sql b/multiuser/sql-schema/src/main/resources/che-schema/6.3.0/1.1__add_fk_indexes.sql deleted file mode 100644 index 591834f6d44..00000000000 --- a/multiuser/sql-schema/src/main/resources/che-schema/6.3.0/1.1__add_fk_indexes.sql +++ /dev/null @@ -1,19 +0,0 @@ --- --- Copyright (c) 2012-2017 Red Hat, Inc. --- All rights reserved. This program and the accompanying materials --- are made available under the terms of the Eclipse Public License v1.0 --- which accompanies this distribution, and is available at --- http://www.eclipse.org/legal/epl-v10.html --- --- Contributors: --- Red Hat, Inc. - initial API and implementation --- - --- Indexes for "reference-side" foreign keys -CREATE INDEX che_index_system_permissions_actions_system_permissions_id ON che_system_permissions_actions(system_permissions_id); -CREATE INDEX che_index_stack_permissions_actions_stack_permissions_id ON che_stack_permissions_actions(stack_permissions_id); -CREATE INDEX che_index_worker_actions_worker_id ON che_worker_actions(worker_id); -CREATE INDEX che_index_member_actions_member_id ON che_member_actions(member_id); -CREATE INDEX che_index_organization_account_id ON che_organization(account_id); -CREATE INDEX che_index_organization_distributed_resources_resource_id ON che_organization_distributed_resources_resource(resource_id); -CREATE INDEX che_index_free_resources_limit_resource_resourses_id ON che_free_resources_limit_resource(resources_id); diff --git a/multiuser/sql-schema/src/main/resources/che-schema/7.1.0/1.1__remove_stack_permissions.sql b/multiuser/sql-schema/src/main/resources/che-schema/7.1.0/1.1__remove_stack_permissions.sql deleted file mode 100644 index 79d0290402b..00000000000 --- a/multiuser/sql-schema/src/main/resources/che-schema/7.1.0/1.1__remove_stack_permissions.sql +++ /dev/null @@ -1,14 +0,0 @@ --- --- Copyright (c) 2012-2019 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 --- - -DROP TABLE che_stack_permissions_actions; -DROP TABLE che_stack_permissions; diff --git a/multiuser/sql-schema/src/main/resources/che-schema/7.20.0/1.1__add_userdevfile_permissions.sql b/multiuser/sql-schema/src/main/resources/che-schema/7.20.0/1.1__add_userdevfile_permissions.sql deleted file mode 100644 index 915b974305d..00000000000 --- a/multiuser/sql-schema/src/main/resources/che-schema/7.20.0/1.1__add_userdevfile_permissions.sql +++ /dev/null @@ -1,40 +0,0 @@ --- --- Copyright (c) 2012-2020 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 --- - --- User devfile permissions ----------------------------------------------------------- -CREATE TABLE che_userdevfile_permissions ( - id VARCHAR(255) NOT NULL, - user_id VARCHAR(255), - userdevfile_id VARCHAR(255), - - PRIMARY KEY (id) -); --- indexes -CREATE UNIQUE INDEX che_index_userdevfile_permissions_user_id_userdevfile_id ON che_userdevfile_permissions (user_id, userdevfile_id); -CREATE INDEX che_index_userdevfile_permissions_userdevfile_id ON che_userdevfile_permissions (userdevfile_id); --- constraints -ALTER TABLE che_userdevfile_permissions ADD CONSTRAINT che_fk_userdevfile_permissions_user_id FOREIGN KEY (user_id) REFERENCES usr (id); -ALTER TABLE che_userdevfile_permissions ADD CONSTRAINT che_fk_userdevfile_permissions_workspace_id FOREIGN KEY (userdevfile_id) REFERENCES userdevfile (id); --------------------------------------------------------------------------------- - - --- User devfile permission actions -------------------------------------------------------------- -CREATE TABLE che_userdevfile_permissions_actions ( - userdevfile_permissions_id VARCHAR(255), - actions VARCHAR(255) -); --- indexes -CREATE INDEX che_index_userdevfile_permissions_actions_actions ON che_userdevfile_permissions_actions (actions); -CREATE INDEX che_index_userdevfile_permissions_actions_userdevfile_id ON che_userdevfile_permissions_actions (userdevfile_permissions_id); --- constraints -ALTER TABLE che_userdevfile_permissions_actions ADD CONSTRAINT che_fk_userdevfile_permissions_actions_id FOREIGN KEY (userdevfile_permissions_id) REFERENCES che_userdevfile_permissions(id); --------------------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index e6dcfeaa305..23a538e4723 100644 --- a/pom.xml +++ b/pom.xml @@ -1161,11 +1161,6 @@ che-multiuser-keycloak-shared ${che.version} - - org.eclipse.che.multiuser - che-multiuser-keycloak-token-provider - ${che.version} - org.eclipse.che.multiuser che-multiuser-keycloak-user-remover @@ -1197,58 +1192,6 @@ che-multiuser-permission-devfile ${che.version} - - org.eclipse.che.multiuser - che-multiuser-permission-devfile - ${che.version} - tests - - - org.eclipse.che.multiuser - che-multiuser-permission-logger - ${che.version} - - - org.eclipse.che.multiuser - che-multiuser-permission-resource - ${che.version} - - - org.eclipse.che.multiuser - che-multiuser-permission-system - ${che.version} - - - org.eclipse.che.multiuser - che-multiuser-permission-user - ${che.version} - - - org.eclipse.che.multiuser - che-multiuser-permission-workspace - ${che.version} - - - org.eclipse.che.multiuser - che-multiuser-permission-workspace - ${che.version} - tests - - - org.eclipse.che.multiuser - che-multiuser-permission-workspace-activity - ${che.version} - - - org.eclipse.che.multiuser - che-multiuser-personal-account - ${che.version} - - - org.eclipse.che.multiuser - che-multiuser-sql-schema - ${che.version} - org.eclipse.che.multiuser multiuser-infrastructure-openshift