feat: Advanced authorization (#619)

* feat: Advanced authorization

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Renames fields

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Address remarks

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Address remarks

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Address remarks

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

---------

Signed-off-by: Anatolii Bazko <abazko@redhat.com>
pull/624/head
Anatolii Bazko 2023-12-04 15:55:35 +01:00 committed by GitHub
parent 7acf4cc2d9
commit 7fe2a4dd3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 660 additions and 40 deletions

View File

@ -663,3 +663,16 @@ che.oauth2.gitlab.clientid_filepath=NULL
# Location of the file with GitLab client secret.
che.oauth2.gitlab.clientsecret_filepath=NULL
### Advanced authorization
# Comma separated list of users allowed to access Che.
che.infra.kubernetes.advanced_authorization.allow_users=NULL
# Comma separated list of groups of users allowed to access Che.
che.infra.kubernetes.advanced_authorization.allow_groups=NULL
# Comma separated list of users denied to access Che.
che.infra.kubernetes.advanced_authorization.deny_users=NULL
# Comma separated list of groups of users denied to access Che.
che.infra.kubernetes.advanced_authorization.deny_groups=NULL

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -11,6 +11,13 @@
*/
package org.eclipse.che.commons.lang;
import static com.google.common.base.Strings.isNullOrEmpty;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.Set;
/** Set of useful String methods */
public class StringUtils {
@ -91,4 +98,13 @@ public class StringUtils {
}
return -1;
}
/** Parse string to set of strings. String should be comma separated. Whitespaces are trimmed. */
public static Set<String> strToSet(String str) {
if (!isNullOrEmpty(str)) {
return Sets.newHashSet(Splitter.on(",").trimResults().omitEmptyStrings().split(str));
} else {
return Collections.emptySet();
}
}
}

View File

@ -36,6 +36,9 @@ import org.eclipse.che.api.workspace.server.spi.provision.env.CheApiInternalEnvV
import org.eclipse.che.api.workspace.server.wsplugins.ChePluginsApplier;
import org.eclipse.che.api.workspace.shared.Constants;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.KubernetesNamespaceService;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationChecker;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.KubernetesAuthorizationCheckerImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.PermissionsCleaner;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.jpa.JpaKubernetesRuntimeCacheModule;
import org.eclipse.che.workspace.infrastructure.kubernetes.devfile.DockerimageComponentToWorkspaceApplier;
import org.eclipse.che.workspace.infrastructure.kubernetes.devfile.KubernetesComponentToWorkspaceApplier;
@ -110,6 +113,9 @@ public class KubernetesInfraModule extends AbstractModule {
namespaceConfigurators.addBinding().to(SshKeysConfigurator.class);
namespaceConfigurators.addBinding().to(GitconfigUserDataConfigurator.class);
bind(AuthorizationChecker.class).to(KubernetesAuthorizationCheckerImpl.class);
bind(PermissionsCleaner.class).asEagerSingleton();
bind(KubernetesNamespaceService.class);
MapBinder<String, InternalEnvironmentFactory> factories =

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.authorization;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
/** This {@link AuthorizationChecker} checks if user is allowed to use Che. */
public interface AuthorizationChecker {
boolean isAuthorized(String username) throws InfrastructureException;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.authorization;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure;
/**
* An exception thrown by {@link RuntimeInfrastructure} and related components. Indicates that a
* user is not authorized to use Che.
*
* @author Anatolii Bazko
*/
public class AuthorizationException extends InfrastructureException {
public AuthorizationException(String message) {
super(message);
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.authorization;
import static org.eclipse.che.commons.lang.StringUtils.strToSet;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.commons.annotation.Nullable;
/** This {@link KubernetesAuthorizationCheckerImpl} checks if user is allowed to use Che. */
@Singleton
public class KubernetesAuthorizationCheckerImpl implements AuthorizationChecker {
private final Set<String> allowUsers;
private final Set<String> denyUsers;
@Inject
public KubernetesAuthorizationCheckerImpl(
@Nullable @Named("che.infra.kubernetes.advanced_authorization.allow_users") String allowUsers,
@Nullable @Named("che.infra.kubernetes.advanced_authorization.deny_users") String denyUsers) {
this.allowUsers = strToSet(allowUsers);
this.denyUsers = strToSet(denyUsers);
}
public boolean isAuthorized(String username) {
return isAllowedUser(username) && !isDeniedUser(username);
}
private boolean isAllowedUser(String username) {
return allowUsers.isEmpty() || allowUsers.contains(username);
}
private boolean isDeniedUser(String username) {
return !denyUsers.isEmpty() && denyUsers.contains(username);
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.authorization;
import static org.eclipse.che.commons.lang.StringUtils.strToSet;
import io.fabric8.kubernetes.client.KubernetesClient;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory;
/** This {@link PermissionsCleaner} cleans up all user's permissions. */
@Singleton
public class PermissionsCleaner {
private final Set<String> userClusterRoles;
private final CheServerKubernetesClientFactory cheServerKubernetesClientFactory;
@Inject
public PermissionsCleaner(
@Nullable @Named("che.infra.kubernetes.user_cluster_roles") String userClusterRoles,
CheServerKubernetesClientFactory cheServerKubernetesClientFactory) {
this.cheServerKubernetesClientFactory = cheServerKubernetesClientFactory;
this.userClusterRoles = strToSet(userClusterRoles);
}
public void cleanUp(String namespaceName) throws InfrastructureException {
KubernetesClient client = cheServerKubernetesClientFactory.create();
for (String userClusterRole : userClusterRoles) {
client.rbac().roleBindings().inNamespace(namespaceName).withName(userClusterRole).delete();
}
}
}

View File

@ -57,6 +57,9 @@ import org.eclipse.che.inject.ConfigurationException;
import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationChecker;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationException;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.PermissionsCleaner;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.util.KubernetesSharedPool;
import org.slf4j.Logger;
@ -98,6 +101,8 @@ public class KubernetesNamespaceFactory {
private final PreferenceManager preferenceManager;
protected final Set<NamespaceConfigurator> namespaceConfigurators;
protected final KubernetesSharedPool sharedPool;
protected final AuthorizationChecker authorizationChecker;
protected final PermissionsCleaner permissionsCleaner;
@Inject
public KubernetesNamespaceFactory(
@ -110,7 +115,9 @@ public class KubernetesNamespaceFactory {
Set<NamespaceConfigurator> namespaceConfigurators,
CheServerKubernetesClientFactory cheServerKubernetesClientFactory,
PreferenceManager preferenceManager,
KubernetesSharedPool sharedPool)
KubernetesSharedPool sharedPool,
AuthorizationChecker authorizationChecker,
PermissionsCleaner permissionsCleaner)
throws ConfigurationException {
this.namespaceCreationAllowed = namespaceCreationAllowed;
this.cheServerKubernetesClientFactory = cheServerKubernetesClientFactory;
@ -120,6 +127,8 @@ public class KubernetesNamespaceFactory {
this.labelNamespaces = labelNamespaces;
this.annotateNamespaces = annotateNamespaces;
this.namespaceConfigurators = ImmutableSet.copyOf(namespaceConfigurators);
this.authorizationChecker = authorizationChecker;
this.permissionsCleaner = permissionsCleaner;
//noinspection UnstableApiUsage
Splitter.MapSplitter csvMapSplitter = Splitter.on(",").withKeyValueSeparator("=");
@ -281,6 +290,9 @@ public class KubernetesNamespaceFactory {
var subject = EnvironmentContext.getCurrent().getSubject();
var userName = subject.getUserName();
validateAuthorization(namespace.getName(), userName);
NamespaceResolutionContext resolutionCtx =
new NamespaceResolutionContext(identity.getWorkspaceId(), subject.getUserId(), userName);
Map<String, String> namespaceAnnotationsEvaluated =
@ -573,6 +585,27 @@ public class KubernetesNamespaceFactory {
}
}
protected void validateAuthorization(String namespaceName, String username)
throws InfrastructureException {
if (!authorizationChecker.isAuthorized(username)) {
try {
permissionsCleaner.cleanUp(namespaceName);
} catch (InfrastructureException | KubernetesClientException e) {
LOG.error(
"Failed to clean up permissions for user '{}' in namespace '{}'. Cause: {}",
username,
namespaceName,
e.getMessage(),
e);
}
throw new AuthorizationException(
format(
"User '%s' is not authorized to create a project. Please contact your system administrator.",
username));
}
}
protected String evalPlaceholders(String namespace, NamespaceResolutionContext ctx) {
checkArgument(!isNullOrEmpty(namespace));
String evaluated = namespace;

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.authorization;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(MockitoTestNGListener.class)
public class KubernetesAuthorizationCheckerTest {
@Test(dataProvider = "advancedAuthorizationData")
public void advancedAuthorization(
String testUserName, String allowedUsers, String deniedUsers, boolean expectedIsAuthorized)
throws InfrastructureException {
// give
AuthorizationChecker authorizationChecker =
new KubernetesAuthorizationCheckerImpl(allowedUsers, deniedUsers);
// when
boolean isAuthorized = authorizationChecker.isAuthorized(testUserName);
// then
Assert.assertEquals(isAuthorized, expectedIsAuthorized);
}
@DataProvider
public static Object[][] advancedAuthorizationData() {
return new Object[][] {
{"user1", "", "", true},
{"user1", "user1", "", true},
{"user1", "user1", "user2", true},
{"user1", "user1", "user1", false},
{"user2", "user1", "", false},
{"user2", "user1", "user2", false},
};
}
}

View File

@ -87,6 +87,8 @@ import org.eclipse.che.inject.ConfigurationException;
import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationChecker;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.PermissionsCleaner;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.PreferencesConfigMapConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.WorkspaceServiceAccountConfigurator;
@ -126,6 +128,8 @@ public class KubernetesNamespaceFactoryTest {
private KubernetesClient k8sClient;
@Mock private PreferenceManager preferenceManager;
@Mock Appender mockedAppender;
@Mock AuthorizationChecker authorizationChecker;
@Mock PermissionsCleaner permissionsCleaner;
@Mock private NonNamespaceOperation namespaceOperation;
@ -151,6 +155,7 @@ public class KubernetesNamespaceFactoryTest {
lenient().when(namespaceOperation.withName(any())).thenReturn(namespaceResource);
lenient().when(namespaceResource.get()).thenReturn(mock(Namespace.class));
lenient().when(authorizationChecker.isAuthorized(anyString())).thenReturn(true);
lenient().doReturn(namespaceListResource).when(namespaceOperation).withLabels(anyMap());
lenient().when(namespaceListResource.list()).thenReturn(namespaceList);
@ -179,7 +184,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
namespaceFactory.checkIfNamespaceIsAllowed("jondoe-che");
}
@ -204,7 +211,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
namespaceFactory.checkIfNamespaceIsAllowed("any-namespace");
}
@ -222,7 +231,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
assertEquals("che-kube-admin", namespaceFactory.normalizeNamespaceName("kube:admin"));
}
@ -245,7 +256,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
namespaceFactory.checkIfNamespaceIsAllowed("any-namespace");
}
@ -265,7 +278,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
}
@Test
@ -313,7 +328,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));
// when
@ -354,7 +371,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));
// when
@ -382,7 +401,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
// when
namespaceFactory.list();
@ -413,7 +434,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
List<KubernetesNamespaceMeta> availableNamespaces = namespaceFactory.list();
assertEquals(availableNamespaces.size(), 1);
@ -439,7 +462,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
List<KubernetesNamespaceMeta> availableNamespaces = namespaceFactory.list();
assertEquals(availableNamespaces.size(), 1);
@ -467,7 +492,9 @@ public class KubernetesNamespaceFactoryTest {
Set.of(new PreferencesConfigMapConfigurator(cheServerKubernetesClientFactory)),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
when(toReturnNamespace.getName()).thenReturn("namespaceName");
doReturn(toReturnNamespace).when(namespaceFactory).doCreateNamespaceAccess(any(), any());
@ -508,7 +535,9 @@ public class KubernetesNamespaceFactoryTest {
namespaceConfigurators,
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
@ -543,7 +572,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
doReturn(toReturnNamespace).when(namespaceFactory).doCreateNamespaceAccess(any(), any());
@ -575,7 +606,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
doReturn(toReturnNamespace).when(namespaceFactory).doCreateNamespaceAccess(any(), any());
@ -608,7 +641,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
throwOnTryToGetNamespaceByName(
"jondoe-che", new KubernetesClientException("connection refused"));
@ -631,7 +666,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
throwOnTryToGetNamespacesList(new KubernetesClientException("connection refused"));
namespaceFactory.list();
@ -659,7 +696,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
doReturn(toReturnNamespace).when(namespaceFactory).doCreateNamespaceAccess(any(), any());
@ -688,7 +727,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
doReturn(toReturnNamespace).when(namespaceFactory).doCreateNamespaceAccess(any(), any());
@ -723,7 +764,9 @@ public class KubernetesNamespaceFactoryTest {
Set.of(serviceAccountCfg),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
when(toReturnNamespace.getName()).thenReturn("workspace123");
@ -761,7 +804,9 @@ public class KubernetesNamespaceFactoryTest {
Set.of(serviceAccountConfigurator),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
when(toReturnNamespace.getName()).thenReturn("workspace123");
@ -836,7 +881,9 @@ public class KubernetesNamespaceFactoryTest {
Set.of(serviceAccountConfigurator),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
when(toReturnNamespace.getName()).thenReturn("workspace123");
@ -881,7 +928,9 @@ public class KubernetesNamespaceFactoryTest {
"serviceAccount", "", cheServerKubernetesClientFactory)),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
when(toReturnNamespace.getName()).thenReturn("workspace123");
@ -945,7 +994,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
WorkspaceImpl workspace =
new WorkspaceImplBuilder().setId("workspace123").setAttributes(emptyMap()).build();
@ -968,7 +1019,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
Map<String, String> prefs = new HashMap<>();
prefs.put(WORKSPACE_INFRASTRUCTURE_NAMESPACE_ATTRIBUTE, "che-123");
@ -996,7 +1049,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
Map<String, String> prefs = new HashMap<>();
// returned but ignored
@ -1025,7 +1080,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
Map<String, String> prefs = new HashMap<>();
// returned but ignored
@ -1054,7 +1111,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
doReturn(empty()).when(namespaceFactory).fetchNamespace(anyString());
String namespace =
@ -1079,7 +1138,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
WorkspaceImpl workspace =
new WorkspaceImplBuilder()
@ -1106,7 +1167,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
WorkspaceImpl workspace =
new WorkspaceImplBuilder()
@ -1154,7 +1217,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
String namespace =
namespaceFactory.evaluateNamespaceName(
@ -1178,7 +1243,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
when(toReturnNamespace.getName()).thenReturn("jondoe-che");
@ -1215,7 +1282,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
when(toReturnNamespace.getName()).thenReturn("jondoe-cha-cha-cha");
@ -1251,7 +1320,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
when(toReturnNamespace.getName()).thenReturn("jondoe-cha-cha-cha");
@ -1299,7 +1370,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));
namespaceFactory.list();
@ -1322,7 +1395,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool));
pool,
authorizationChecker,
permissionsCleaner));
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));
KubernetesNamespace toReturnNamespace = mock(KubernetesNamespace.class);
prepareNamespace(toReturnNamespace);
@ -1351,7 +1426,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
assertEquals(expected, namespaceFactory.normalizeNamespaceName(raw));
}
@ -1368,7 +1445,9 @@ public class KubernetesNamespaceFactoryTest {
emptySet(),
cheServerKubernetesClientFactory,
preferenceManager,
pool);
pool,
authorizationChecker,
permissionsCleaner);
assertEquals(
63,

View File

@ -161,6 +161,17 @@
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-server-mock</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-jupiter-api</artifactId>
<groupId>org.junit.jupiter</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>openshift-server-mock</artifactId>

View File

@ -40,6 +40,8 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientTermi
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesEnvironmentProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizerFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.KubernetesNamespaceService;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationChecker;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.PermissionsCleaner;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.jpa.JpaKubernetesRuntimeCacheModule;
import org.eclipse.che.workspace.infrastructure.kubernetes.devfile.DockerimageComponentToWorkspaceApplier;
import org.eclipse.che.workspace.infrastructure.kubernetes.devfile.KubernetesComponentToWorkspaceApplier;
@ -80,6 +82,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.PluginBroke
import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.SidecarToolingProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.BrokerEnvironmentFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService;
import org.eclipse.che.workspace.infrastructure.openshift.authorization.OpenShiftAuthorizationCheckerImpl;
import org.eclipse.che.workspace.infrastructure.openshift.devfile.OpenshiftComponentToWorkspaceApplier;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironmentFactory;
@ -118,6 +121,9 @@ public class OpenShiftInfraModule extends AbstractModule {
namespaceConfigurators.addBinding().to(SshKeysConfigurator.class);
namespaceConfigurators.addBinding().to(GitconfigUserDataConfigurator.class);
bind(AuthorizationChecker.class).to(OpenShiftAuthorizationCheckerImpl.class);
bind(PermissionsCleaner.class).asEagerSingleton();
bind(KubernetesNamespaceService.class);
MapBinder<String, InternalEnvironmentFactory> factories =

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.openshift.authorization;
import static org.eclipse.che.commons.lang.StringUtils.strToSet;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.openshift.api.model.Group;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationChecker;
/** This {@link OpenShiftAuthorizationCheckerImpl} checks if user is allowed to use Che. */
@Singleton
public class OpenShiftAuthorizationCheckerImpl implements AuthorizationChecker {
private final CheServerKubernetesClientFactory cheServerKubernetesClientFactory;
private final Set<String> allowUsers;
private final Set<String> allowGroups;
private final Set<String> denyUsers;
private final Set<String> denyGroups;
@Inject
public OpenShiftAuthorizationCheckerImpl(
@Nullable @Named("che.infra.kubernetes.advanced_authorization.allow_users") String allowUsers,
@Nullable @Named("che.infra.kubernetes.advanced_authorization.allow_groups")
String allowGroups,
@Nullable @Named("che.infra.kubernetes.advanced_authorization.deny_users") String denyUsers,
@Nullable @Named("che.infra.kubernetes.advanced_authorization.deny_groups") String denyGroups,
CheServerKubernetesClientFactory cheServerKubernetesClientFactory) {
this.allowUsers = strToSet(allowUsers);
this.allowGroups = strToSet(allowGroups);
this.denyUsers = strToSet(denyUsers);
this.denyGroups = strToSet(denyGroups);
this.cheServerKubernetesClientFactory = cheServerKubernetesClientFactory;
}
public boolean isAuthorized(String username) throws InfrastructureException {
return isAllowedUser(cheServerKubernetesClientFactory.create(), username)
&& !isDeniedUser(cheServerKubernetesClientFactory.create(), username);
}
private boolean isAllowedUser(KubernetesClient client, String username) {
// All users from all groups are allowed by default
if (allowUsers.isEmpty() && allowGroups.isEmpty()) {
return true;
}
if (allowUsers.contains(username)) {
return true;
}
for (String groupName : allowGroups) {
Group group = client.resources(Group.class).withName(groupName).get();
if (group != null && group.getUsers().contains(username)) {
return true;
}
}
return false;
}
private boolean isDeniedUser(KubernetesClient client, String username) {
// All users from all groups are allowed by default
if (denyUsers.isEmpty() && denyGroups.isEmpty()) {
return false;
}
if (denyUsers.contains(username)) {
return true;
}
for (String groupName : denyGroups) {
Group group = client.resources(Group.class).withName(groupName).get();
if (group != null && group.getUsers().contains(username)) {
return true;
}
}
return false;
}
}

View File

@ -40,6 +40,8 @@ import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationChecker;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.PermissionsCleaner;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.util.KubernetesSharedPool;
@ -81,6 +83,8 @@ public class OpenShiftProjectFactory extends KubernetesNamespaceFactory {
CheServerOpenshiftClientFactory cheServerOpenshiftClientFactory,
PreferenceManager preferenceManager,
KubernetesSharedPool sharedPool,
AuthorizationChecker authorizationChecker,
PermissionsCleaner permissionsCleaner,
@Nullable @Named("che.infra.openshift.oauth_identity_provider")
String oAuthIdentityProvider) {
super(
@ -93,7 +97,9 @@ public class OpenShiftProjectFactory extends KubernetesNamespaceFactory {
namespaceConfigurators,
cheServerKubernetesClientFactory,
preferenceManager,
sharedPool);
sharedPool,
authorizationChecker,
permissionsCleaner);
this.initWithCheServerSa = initWithCheServerSa;
this.cheServerKubernetesClientFactory = cheServerKubernetesClientFactory;
this.cheServerOpenshiftClientFactory = cheServerOpenshiftClientFactory;
@ -105,6 +111,9 @@ public class OpenShiftProjectFactory extends KubernetesNamespaceFactory {
OpenShiftProject osProject = get(identity);
var subject = EnvironmentContext.getCurrent().getSubject();
var userName = subject.getUserName();
validateAuthorization(osProject.getName(), userName);
NamespaceResolutionContext resolutionCtx =
new NamespaceResolutionContext(identity.getWorkspaceId(), subject.getUserId(), userName);
Map<String, String> namespaceAnnotationsEvaluated =

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.openshift.authorization;
import static org.mockito.Mockito.*;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
import io.fabric8.openshift.api.model.Group;
import java.util.Collections;
import java.util.List;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(MockitoTestNGListener.class)
public class OpenShiftAuthorizationCheckerTest {
@Mock private CheServerKubernetesClientFactory clientFactory;
private KubernetesClient client;
private KubernetesServer serverMock;
@BeforeMethod
public void setUp() throws InfrastructureException {
serverMock = new KubernetesServer(true, true);
serverMock.before();
client = spy(serverMock.getClient());
lenient().when(clientFactory.create()).thenReturn(client);
}
@Test(dataProvider = "advancedAuthorizationData")
public void advancedAuthorization(
String testUserName,
List<Group> groups,
String allowedUsers,
String allowedGroups,
String deniedUsers,
String deniedGroups,
boolean expectedIsAuthorized)
throws InfrastructureException {
// give
OpenShiftAuthorizationCheckerImpl authorizationChecker =
new OpenShiftAuthorizationCheckerImpl(
allowedUsers, allowedGroups, deniedUsers, deniedGroups, clientFactory);
groups.forEach(group -> client.resources(Group.class).create(group));
// when
boolean isAuthorized = authorizationChecker.isAuthorized(testUserName);
// then
Assert.assertEquals(isAuthorized, expectedIsAuthorized);
}
@DataProvider
public static Object[][] advancedAuthorizationData() {
Group groupWithUser1 =
new Group(
"v1",
"Group",
new ObjectMetaBuilder().withName("groupWithUser1").build(),
List.of("user1"));
Group groupWithUser2 =
new Group(
"v1",
"Group",
new ObjectMetaBuilder().withName("groupWithUser2").build(),
List.of("user2"));
return new Object[][] {
{"user1", Collections.emptyList(), "", "", "", "", true},
{"user1", Collections.emptyList(), "user1", "", "", "", true},
{"user1", Collections.emptyList(), "user1", "", "user2", "", true},
{"user1", List.of(groupWithUser2), "user1", "", "", "groupWithUser2", true},
{"user1", List.of(groupWithUser1), "", "groupWithUser1", "", "", true},
{"user2", List.of(groupWithUser1), "user2", "groupWithUser1", "", "", true},
{
"user1",
List.of(groupWithUser1, groupWithUser2),
"",
"groupWithUser1",
"",
"groupWithUser2",
true
},
{"user1", Collections.emptyList(), "user1", "", "user1", "", false},
{"user2", Collections.emptyList(), "user1", "", "", "", false},
{"user2", Collections.emptyList(), "user1", "", "user2", "", false},
{"user2", List.of(groupWithUser1), "", "groupWithUser1", "", "", false},
{"user1", Collections.emptyList(), "", "", "user1", "", false},
{"user1", List.of(groupWithUser1), "", "", "", "groupWithUser1", false},
{"user1", List.of(groupWithUser1), "", "groupWithUser1", "", "groupWithUser1", false},
{
"user2",
List.of(groupWithUser1, groupWithUser2),
"",
"groupWithUser1",
"",
"groupWithUser2",
false
},
};
}
}

View File

@ -71,6 +71,8 @@ import org.eclipse.che.commons.subject.SubjectImpl;
import org.eclipse.che.inject.ConfigurationException;
import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.AuthorizationChecker;
import org.eclipse.che.workspace.infrastructure.kubernetes.authorization.PermissionsCleaner;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesConfigsMaps;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesSecrets;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator;
@ -113,6 +115,8 @@ public class OpenShiftProjectFactoryTest {
@Mock private WorkspaceManager workspaceManager;
@Mock private PreferenceManager preferenceManager;
@Mock private KubernetesSharedPool pool;
@Mock private AuthorizationChecker authorizationChecker;
@Mock private PermissionsCleaner permissionsCleaner;
@Mock private ProjectOperation projectOperation;
@ -134,6 +138,7 @@ public class OpenShiftProjectFactoryTest {
lenient().when(cheServerOpenshiftClientFactory.createOC()).thenReturn(osClient);
lenient().when(cheServerKubernetesClientFactory.create()).thenReturn(osClient);
lenient().when(osClient.projects()).thenReturn(projectOperation);
lenient().when(authorizationChecker.isAuthorized(anyString())).thenReturn(true);
lenient()
.when(workspaceManager.getWorkspace(any()))
@ -174,6 +179,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
projectFactory.checkIfNamespaceIsAllowed(USER_NAME + "-che");
@ -204,6 +211,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
try {
projectFactory.checkIfNamespaceIsAllowed("any-namespace");
@ -234,6 +243,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
}
@ -269,6 +280,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));
@ -305,6 +318,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "u123", null, false));
@ -337,6 +352,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
// when
@ -379,6 +396,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
List<KubernetesNamespaceMeta> availableNamespaces = projectFactory.list();
@ -415,6 +434,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
List<KubernetesNamespaceMeta> availableNamespaces = projectFactory.list();
@ -451,6 +472,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
projectFactory.list();
@ -477,6 +500,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
projectFactory.list();
@ -508,6 +533,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER));
OpenShiftProject toReturnProject = mock(OpenShiftProject.class);
prepareProject(toReturnProject);
@ -542,6 +569,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER));
OpenShiftProject toReturnProject = mock(OpenShiftProject.class);
doReturn(toReturnProject).when(projectFactory).doCreateProjectAccess(any(), any());
@ -584,6 +613,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER));
OpenShiftProject toReturnProject = mock(OpenShiftProject.class);
prepareProject(toReturnProject);
@ -628,6 +659,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
OAUTH_IDENTITY_PROVIDER));
OpenShiftProject toReturnProject = mock(OpenShiftProject.class);
when(toReturnProject.getName()).thenReturn("workspace123");
@ -677,6 +710,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
String namespace =
@ -709,6 +744,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER);
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));
projectFactory.list();
@ -735,6 +772,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER));
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));
OpenShiftProject toReturnProject = mock(OpenShiftProject.class);
@ -775,6 +814,8 @@ public class OpenShiftProjectFactoryTest {
cheServerOpenshiftClientFactory,
preferenceManager,
pool,
authorizationChecker,
permissionsCleaner,
NO_OAUTH_IDENTITY_PROVIDER));
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("jondoe", "123", null, false));