From 23c5fb2b47dda8908d061c0396a37bcd0965aa2b Mon Sep 17 00:00:00 2001 From: Lukas Krejci Date: Mon, 5 Oct 2020 13:14:26 +0200 Subject: [PATCH] Fixes #17852 - jwtproxy is the new default for the secure servers (#17946) Signed-off-by: Lukas Krejci --- .../che/api/deploy/WsMasterModule.java | 84 ++++++++++++++++++- .../webapp/WEB-INF/classes/che/che.properties | 2 +- .../kubernetes/KubernetesInfraModule.java | 30 ------- .../KubernetesPluginsToolingApplier.java | 7 -- .../KubernetesPluginsToolingApplierTest.java | 19 ----- .../openshift/OpenShiftInfraModule.java | 28 ------- 6 files changed, 83 insertions(+), 87 deletions(-) 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 56d713ae67..15131e2f5d 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 @@ -93,9 +93,14 @@ import org.eclipse.che.security.oauth.OpenShiftOAuthModule; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfraModule; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructure; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.PassThroughProxySecureServerExposer; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.JwtProxyConfigBuilderFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.JwtProxyProvisionerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.JwtProxySecureServerExposerFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.PassThroughProxyProvisionerFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.PassThroughProxySecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.metrics.InfrastructureMetricsModule; import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientConfigFactory; import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftInfraModule; @@ -237,10 +242,15 @@ public class WsMasterModule extends AbstractModule { bindConstant().annotatedWith(Names.named("jndi.datasource.name")).to("java:/comp/env/jdbc/che"); String infrastructure = System.getenv("CHE_INFRASTRUCTURE_ACTIVE"); + + install(new FactoryModuleBuilder().build(JwtProxyConfigBuilderFactory.class)); + install(new FactoryModuleBuilder().build(PassThroughProxyProvisionerFactory.class)); + installDefaultSecureServerExposer(infrastructure); + if (Boolean.valueOf(System.getenv("CHE_MULTIUSER"))) { configureMultiUserMode(persistenceProperties, infrastructure); } else { - configureSingleUserMode(persistenceProperties); + configureSingleUserMode(persistenceProperties, infrastructure); } install( @@ -278,7 +288,8 @@ public class WsMasterModule extends AbstractModule { install(new OpenShiftOAuthModule()); } - private void configureSingleUserMode(Map persistenceProperties) { + private void configureSingleUserMode( + Map persistenceProperties, String infrastructure) { persistenceProperties.put( PersistenceUnitProperties.EXCEPTION_HANDLER_CLASS, "org.eclipse.che.core.db.h2.jpa.eclipselink.H2ExceptionHandler"); @@ -306,6 +317,11 @@ public class WsMasterModule extends AbstractModule { .to(org.eclipse.che.api.workspace.server.DefaultWorkspaceStatusCache.class); install(new org.eclipse.che.api.workspace.activity.inject.WorkspaceActivityModule()); + + // In single user mode jwtproxy provisioner isn't actually bound at all, but since + // it is the new default, we need to "fake it" by binding the passthrough provisioner + // as the jwtproxy impl. + configureImpostorJwtProxySecureProvisioner(infrastructure); } private void configureMultiUserMode( @@ -414,4 +430,68 @@ public class WsMasterModule extends AbstractModule { .to(new TypeLiteral>() {}); } } + + private void configureImpostorJwtProxySecureProvisioner(String infrastructure) { + if (KubernetesInfrastructure.NAME.equals(infrastructure)) { + MapBinder.newMapBinder( + binder(), + new TypeLiteral() {}, + new TypeLiteral>() {}) + .addBinding("jwtproxy") + .to( + new TypeLiteral< + PassThroughProxySecureServerExposerFactory>() {}); + } else { + MapBinder.newMapBinder( + binder(), + new TypeLiteral() {}, + new TypeLiteral>() {}) + .addBinding("jwtproxy") + .to( + new TypeLiteral< + PassThroughProxySecureServerExposerFactory>() {}); + } + } + + private void installDefaultSecureServerExposer(String infrastructure) { + if (KubernetesInfrastructure.NAME.equals(infrastructure)) { + MapBinder> + secureServerExposerFactories = + MapBinder.newMapBinder(binder(), new TypeLiteral<>() {}, new TypeLiteral<>() {}); + + install( + new FactoryModuleBuilder() + .implement( + new TypeLiteral>() {}, + new TypeLiteral>() {}) + .build( + new TypeLiteral< + PassThroughProxySecureServerExposerFactory>() {})); + + secureServerExposerFactories + .addBinding("default") + .to( + new TypeLiteral< + PassThroughProxySecureServerExposerFactory>() {}); + } else { + MapBinder> + secureServerExposerFactories = + MapBinder.newMapBinder(binder(), new TypeLiteral<>() {}, new TypeLiteral<>() {}); + + install( + new FactoryModuleBuilder() + .implement( + new TypeLiteral>() {}, + new TypeLiteral>() {}) + .build( + new TypeLiteral< + PassThroughProxySecureServerExposerFactory>() {})); + + secureServerExposerFactories + .addBinding("default") + .to( + new TypeLiteral< + PassThroughProxySecureServerExposerFactory>() {}); + } + } } diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index 183399a898..f07d56e482 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -606,7 +606,7 @@ che.workspace.storage.preferred_type=persistent # So, servers should authenticate requests themselves. # - 'jwtproxy': jwtproxy will authenticate requests. # So, servers will receive only authenticated ones. -che.server.secure_exposer=default +che.server.secure_exposer=jwtproxy # Jwtproxy issuer string, token lifetime and optional auth page path to route unsigned requests to. che.server.secure_exposer.jwtproxy.token.issuer=wsmaster diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java index 7a64d8ca79..f8eb125e3e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java @@ -78,13 +78,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.Multi import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultihostIngressServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ServiceExposureStrategyProvider; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.PassThroughProxySecureServerExposer; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.JwtProxyConfigBuilderFactory; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.PassThroughProxyProvisionerFactory; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.PassThroughProxySecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.util.NonTlsDistributedClusterModeNotifier; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.KubernetesPluginsToolingApplier; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.PluginBrokerManager; @@ -205,30 +199,6 @@ public class KubernetesInfraModule extends AbstractModule { .addBinding(KubernetesEnvironment.TYPE) .to(KubernetesPluginsToolingApplier.class); - MapBinder> - secureServerExposerFactories = - MapBinder.newMapBinder( - binder(), - new TypeLiteral() {}, - new TypeLiteral>() {}); - - install(new FactoryModuleBuilder().build(JwtProxyConfigBuilderFactory.class)); - install(new FactoryModuleBuilder().build(PassThroughProxyProvisionerFactory.class)); - install( - new FactoryModuleBuilder() - .implement( - new TypeLiteral>() {}, - new TypeLiteral>() {}) - .build( - new TypeLiteral< - PassThroughProxySecureServerExposerFactory>() {})); - - secureServerExposerFactories - .addBinding("default") - .to( - new TypeLiteral< - PassThroughProxySecureServerExposerFactory>() {}); - bind(BrokerService.class); bind(new TypeLiteral>() {}) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java index 91c2a9609d..784fb56b00 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java @@ -18,7 +18,6 @@ import static org.eclipse.che.api.core.model.workspace.config.Command.WORKING_DI import static org.eclipse.che.api.workspace.shared.Constants.CONTAINER_SOURCE_ATTRIBUTE; import static org.eclipse.che.api.workspace.shared.Constants.PLUGIN_MACHINE_ATTRIBUTE; import static org.eclipse.che.api.workspace.shared.Constants.TOOL_CONTAINER_SOURCE; -import static org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider.SECURE_EXPOSER_IMPL_PROPERTY; import com.google.common.annotations.Beta; import com.google.common.collect.ArrayListMultimap; @@ -174,12 +173,6 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { } chePlugins.forEach(chePlugin -> populateWorkspaceEnvVars(chePlugin, k8sEnv)); - - if (isAuthEnabled) { - // enable per-workspace security with JWT proxy for sidecar based workspaces - // because it is the only workspace security implementation supported for now - k8sEnv.getAttributes().putIfAbsent(SECURE_EXPOSER_IMPL_PROPERTY, "jwtproxy"); - } } private void addToolingPod(KubernetesEnvironment kubernetesEnvironment) { diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java index b0ef2d55e2..d15c137d08 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java @@ -789,25 +789,6 @@ public class KubernetesPluginsToolingApplierTest { applier.apply(runtimeIdentity, internalEnvironment, singletonList(chePlugin)); } - @Test - public void shouldSetJWTServerExposerAttributeIfAuthEnabled() throws Exception { - applier = - new KubernetesPluginsToolingApplier( - TEST_IMAGE_POLICY, - MEMORY_LIMIT_MB, - MEMORY_REQUEST_MB, - CPU_LIMIT, - CPU_REQUEST, - true, - projectsRootEnvVariableProvider, - chePluginsVolumeApplier, - envVars); - - applier.apply(runtimeIdentity, internalEnvironment, singletonList(createChePlugin())); - - assertEquals(internalEnvironment.getAttributes().get(SECURE_EXPOSER_IMPL_PROPERTY), "jwtproxy"); - } - @Test public void shouldNotSetJWTServerExposerAttributeIfAuthEnabledButAttributeIsPresent() throws Exception { diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java index 6c69f1e2a5..259f96bb4c 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java @@ -77,14 +77,8 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.Exter import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ServiceExposureStrategyProvider; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.CookiePathStrategy; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.PassThroughProxySecureServerExposer; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.JwtProxyConfigBuilderFactory; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.PassThroughProxyProvisionerFactory; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.PassThroughProxySecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.util.NonTlsDistributedClusterModeNotifier; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.KubernetesPluginsToolingApplier; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.PluginBrokerManager; @@ -183,28 +177,6 @@ public class OpenShiftInfraModule extends AbstractModule { bind(SecureServerExposerFactoryProvider.class) .to(new TypeLiteral>() {}); - MapBinder> - secureServerExposerFactories = - MapBinder.newMapBinder( - binder(), - new TypeLiteral() {}, - new TypeLiteral>() {}); - - install(new FactoryModuleBuilder().build(JwtProxyConfigBuilderFactory.class)); - install(new FactoryModuleBuilder().build(PassThroughProxyProvisionerFactory.class)); - install( - new FactoryModuleBuilder() - .implement( - new TypeLiteral>() {}, - new TypeLiteral>() {}) - .build( - new TypeLiteral< - PassThroughProxySecureServerExposerFactory>() {})); - - secureServerExposerFactories - .addBinding("default") - .to(new TypeLiteral>() {}); - bind(BrokerService.class); bind(new TypeLiteral>() {})