Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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/
Expand All @@ -22,6 +22,7 @@
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Collections;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.SubjectImpl;
import org.mockito.InjectMocks;
Expand Down Expand Up @@ -50,7 +51,8 @@ public void shouldRedirectIfGetRequestIsNotNamespaceWorkspaceName(String uri) th
when(request.getMethod()).thenReturn("GET");
when(request.getRequestURI()).thenReturn(uri);
EnvironmentContext context = new EnvironmentContext();
context.setSubject(new SubjectImpl("id123", "name", "token123", false));
context.setSubject(
new SubjectImpl("id123", Collections.emptyList(), "name", "token123", false));
EnvironmentContext.setCurrent(context);

// when
Expand All @@ -66,7 +68,8 @@ public void shouldRedirectIfHEADRequestIsNotNamespaceWorkspaceName(String uri) t
when(request.getMethod()).thenReturn("HEAD");
when(request.getRequestURI()).thenReturn(uri);
EnvironmentContext context = new EnvironmentContext();
context.setSubject(new SubjectImpl("id123", "name", "token123", false));
context.setSubject(
new SubjectImpl("id123", Collections.emptyList(), "name", "token123", false));
EnvironmentContext.setCurrent(context);

// when
Expand Down
6 changes: 1 addition & 5 deletions assembly/assembly-wsmaster-war/pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

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/
Expand Down Expand Up @@ -259,10 +259,6 @@
<groupId>org.eclipse.che.multiuser</groupId>
<artifactId>che-multiuser-api-workspace-activity</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.multiuser</groupId>
<artifactId>che-multiuser-keycloak-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.multiuser</groupId>
<artifactId>che-multiuser-keycloak-token-provider</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -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/
Expand All @@ -11,6 +11,7 @@
*/
package org.eclipse.che.api.deploy;

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;
Expand All @@ -26,7 +27,6 @@
import io.jsonwebtoken.SigningKeyResolver;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.che.api.core.notification.RemoteSubscriptionStorage;
import org.eclipse.che.api.core.rest.CheJsonProvider;
import org.eclipse.che.api.core.rest.MessageBodyAdapter;
import org.eclipse.che.api.core.rest.MessageBodyAdapterInterceptor;
Expand Down Expand Up @@ -63,8 +63,6 @@
import org.eclipse.che.api.user.server.spi.ProfileDao;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.workspace.server.WorkspaceEntityProvider;
import org.eclipse.che.api.workspace.server.WorkspaceLockService;
import org.eclipse.che.api.workspace.server.WorkspaceStatusCache;
import org.eclipse.che.api.workspace.server.devfile.DevfileModule;
import org.eclipse.che.api.workspace.server.hc.ServersCheckerFactory;
import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner;
Expand Down Expand Up @@ -105,6 +103,8 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientConfigFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfraModule;
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructure;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationChecker;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.KubernetesOIDCAuthorizationCheckerImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.multiuser.oauth.KubernetesOidcProviderConfigFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer;
Expand All @@ -118,8 +118,8 @@
import org.eclipse.che.workspace.infrastructure.metrics.InfrastructureMetricsModule;
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftInfraModule;
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftInfrastructure;
import org.eclipse.che.workspace.infrastructure.openshift.authorization.OpenShiftAuthorizationCheckerImpl;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.multiuser.oauth.KeycloakProviderConfigFactory;
import org.eclipse.persistence.config.PersistenceUnitProperties;

/**
Expand Down Expand Up @@ -319,27 +319,13 @@ protected void configure() {

private void configureMultiUserMode(
Map<String, String> persistenceProperties, String infrastructure) {
if (OpenShiftInfrastructure.NAME.equals(infrastructure)
|| KubernetesInfrastructure.NAME.equals(infrastructure)) {
install(new ReplicationModule(persistenceProperties));
bind(
org.eclipse.che.multiuser.permission.workspace.infra.kubernetes
.BrokerServicePermissionFilter.class);
configureJwtProxySecureProvisioner(infrastructure);
} else {
bind(RemoteSubscriptionStorage.class)
.to(org.eclipse.che.api.core.notification.InmemoryRemoteSubscriptionStorage.class);
bind(WorkspaceLockService.class)
.to(org.eclipse.che.api.workspace.server.DefaultWorkspaceLockService.class);
bind(WorkspaceStatusCache.class)
.to(org.eclipse.che.api.workspace.server.DefaultWorkspaceStatusCache.class);
}
install(new ReplicationModule(persistenceProperties));
bind(
org.eclipse.che.multiuser.permission.workspace.infra.kubernetes
.BrokerServicePermissionFilter.class);
configureJwtProxySecureProvisioner(infrastructure);

if (Boolean.parseBoolean(System.getenv("CHE_AUTH_NATIVEUSER"))) {
bind(KubernetesClientConfigFactory.class).to(KubernetesOidcProviderConfigFactory.class);
} else if (OpenShiftInfrastructure.NAME.equals(infrastructure)) {
bind(KubernetesClientConfigFactory.class).to(KeycloakProviderConfigFactory.class);
}
bind(KubernetesClientConfigFactory.class).to(KubernetesOidcProviderConfigFactory.class);

persistenceProperties.put(
PersistenceUnitProperties.EXCEPTION_HANDLER_CLASS,
Expand Down Expand Up @@ -369,18 +355,19 @@ private void configureMultiUserMode(

bind(org.eclipse.che.multiuser.permission.workspace.activity.ActivityPermissionsFilter.class);

if (Boolean.parseBoolean(System.getenv("CHE_AUTH_NATIVEUSER"))) {
bind(RequestTokenExtractor.class).to(HeaderRequestTokenExtractor.class);
if (KubernetesInfrastructure.NAME.equals(infrastructure)) {
bind(OIDCInfo.class).toProvider(OIDCInfoProvider.class).asEagerSingleton();
bind(SigningKeyResolver.class).to(OIDCSigningKeyResolver.class);
bind(JwtParser.class).toProvider(OIDCJwtParserProvider.class);
bind(JwkProvider.class).toProvider(OIDCJwkProvider.class);
}
bind(TokenValidator.class).to(NotImplementedTokenValidator.class);
bind(ProfileDao.class).to(JpaProfileDao.class);
bind(OAuthAPI.class).to(EmbeddedOAuthAPI.class).asEagerSingleton();
bind(RequestTokenExtractor.class).to(HeaderRequestTokenExtractor.class);
if (isOpenShiftOAuthEnabled()) {
bind(AuthorizationChecker.class).to(OpenShiftAuthorizationCheckerImpl.class);
} else {
bind(OIDCInfo.class).toProvider(OIDCInfoProvider.class).asEagerSingleton();
bind(SigningKeyResolver.class).to(OIDCSigningKeyResolver.class);
bind(JwtParser.class).toProvider(OIDCJwtParserProvider.class);
bind(JwkProvider.class).toProvider(OIDCJwkProvider.class);
bind(AuthorizationChecker.class).to(KubernetesOIDCAuthorizationCheckerImpl.class);
}
bind(TokenValidator.class).to(NotImplementedTokenValidator.class);
bind(ProfileDao.class).to(JpaProfileDao.class);
bind(OAuthAPI.class).to(EmbeddedOAuthAPI.class).asEagerSingleton();

install(new MachineAuthModule());

Expand Down Expand Up @@ -483,4 +470,15 @@ private void installDefaultSecureServerExposer(String infrastructure) {
PassThroughProxySecureServerExposerFactory<OpenShiftEnvironment>>() {});
}
}

private boolean isOpenShiftOAuthEnabled() {
String openShiftOAuthEnabled = System.getenv("CHE_INFRA_OPENSHIFT_OAUTH__ENABLED");

if (!isNullOrEmpty(openShiftOAuthEnabled)) {
return Boolean.valueOf(openShiftOAuthEnabled);
}

String infrastructure = System.getenv("CHE_INFRASTRUCTURE_ACTIVE");
return OpenShiftInfrastructure.NAME.equals(infrastructure);
}
}
Original file line number Diff line number Diff line change
@@ -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/
Expand All @@ -11,16 +11,14 @@
*/
package org.eclipse.che.api.deploy;

import static com.google.common.base.Strings.isNullOrEmpty;

import com.google.common.collect.ImmutableMap;
import com.google.inject.servlet.ServletModule;
import org.eclipse.che.api.core.cors.CheCorsFilter;
import org.eclipse.che.commons.logback.filter.RequestIdLoggerFilter;
import org.eclipse.che.inject.ConfigurationException;
import org.eclipse.che.inject.DynaModule;
import org.eclipse.che.multiuser.keycloak.server.deploy.KeycloakServletModule;
import org.eclipse.che.multiuser.machine.authentication.server.MachineLoginFilter;
import org.eclipse.che.multiuser.oidc.filter.OidcTokenInitializationFilter;
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructure;
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftInfrastructure;
import org.eclipse.che.workspace.infrastructure.openshift.multiuser.oauth.OpenshiftTokenInitializationFilter;
import org.everrest.guice.servlet.GuiceEverrestServlet;
Expand Down Expand Up @@ -50,13 +48,8 @@ protected void configureServlets() {
serveRegex("^(?!/websocket.?)(.*)")
.with(GuiceEverrestServlet.class, ImmutableMap.of("openapi.context.id", "org.eclipse.che"));

if (Boolean.parseBoolean(System.getenv("CHE_AUTH_NATIVEUSER"))) {
LOG.info("Running in native-user mode ...");
configureNativeUserMode();
} else {
LOG.info("Running in classic multi-user mode ...");
configureMultiUserMode();
}
LOG.info("Running in native-user mode ...");
configureNativeUserMode();

if (Boolean.valueOf(System.getenv("CHE_METRICS_ENABLED"))) {
install(new org.eclipse.che.core.metrics.MetricsServletModule());
Expand All @@ -73,19 +66,22 @@ private boolean isCheCorsEnabled() {
}
}

private void configureMultiUserMode() {
filterRegex(".*").through(MachineLoginFilter.class);
install(new KeycloakServletModule());
}

private void configureNativeUserMode() {
final String infrastructure = System.getenv("CHE_INFRASTRUCTURE_ACTIVE");
if (OpenShiftInfrastructure.NAME.equals(infrastructure)) {
if (isOpenShiftOAuthEnabled()) {
filter("/*").through(OpenshiftTokenInitializationFilter.class);
} else if (KubernetesInfrastructure.NAME.equals(infrastructure)) {
filter("/*").through(OidcTokenInitializationFilter.class);
} else {
throw new ConfigurationException("Native user mode is currently supported on on OpenShift.");
filter("/*").through(OidcTokenInitializationFilter.class);
}
}

private boolean isOpenShiftOAuthEnabled() {
String openShiftOAuthEnabled = System.getenv("CHE_INFRA_OPENSHIFT_OAUTH__ENABLED");

if (!isNullOrEmpty(openShiftOAuthEnabled)) {
return Boolean.valueOf(openShiftOAuthEnabled);
}

String infrastructure = System.getenv("CHE_INFRASTRUCTURE_ACTIVE");
return OpenShiftInfrastructure.NAME.equals(infrastructure);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2012-2023 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/
Expand Down Expand Up @@ -92,6 +92,18 @@ che.oidc.allowed_clock_skew_sec=3
# `name` in Dex installations.
che.oidc.username_claim=NULL

# Prefix to be prepended to username values extracted from the OIDC token.
# If not defined, no prefix will be added.
che.oidc.username_prefix=NULL

# Claim to be used for extracting user group membership from the JWT token.
# If not defined, group information will not be extracted from the token.
che.oidc.groups_claim=NULL

# Prefix to be prepended to group names extracted from the OIDC token.
# If not defined, no prefix will be added.
che.oidc.group_prefix=NULL

# Email claim to be used when parsing JWT token.
# If not defined, the fallback value is 'email'.
che.oidc.email_claim=NULL
Expand Down
Original file line number Diff line number Diff line change
@@ -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/
Expand All @@ -11,6 +11,7 @@
*/
package org.eclipse.che.commons.subject;

import java.util.List;
import org.eclipse.che.api.core.ForbiddenException;

/**
Expand All @@ -33,6 +34,11 @@ public String getUserName() {
return "Anonymous";
}

@Override
public List<String> getGroups() {
return java.util.Collections.emptyList();
}

@Override
public boolean hasPermission(String domain, String instance, String action) {
return false;
Expand Down Expand Up @@ -81,6 +87,11 @@ public boolean isTemporary() {
*/
String getUserName();

/**
* @return list of groups the user belongs to
*/
List<String> getGroups();

/**
* Checks does subject have specified permission.
*
Expand Down
Loading
Loading