diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerRegistryAuthResolver.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerRegistryAuthResolver.java index 763f2ace20..90840c70b5 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerRegistryAuthResolver.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerRegistryAuthResolver.java @@ -42,11 +42,14 @@ public class DockerRegistryAuthResolver { public static final String DEFAULT_REGISTRY = "https://index.docker.io/v1/"; - private final InitialAuthConfig initialAuthConfig; + private final InitialAuthConfig initialAuthConfig; + private final DockerRegistryDynamicAuthResolver dynamicAuthResolver; @Inject - public DockerRegistryAuthResolver(InitialAuthConfig initialAuthConfig) { + public DockerRegistryAuthResolver(InitialAuthConfig initialAuthConfig, + DockerRegistryDynamicAuthResolver dynamicAuthResolver) { this.initialAuthConfig = initialAuthConfig; + this.dynamicAuthResolver = dynamicAuthResolver; } /** @@ -70,6 +73,9 @@ public class DockerRegistryAuthResolver { if (authConfig == null) { authConfig = normalizeDockerHubRegistryUrl(initialAuthConfig.getAuthConfigs().getConfigs()).get(normalizedRegistry); } + if (authConfig == null) { + authConfig = dynamicAuthResolver.getXRegistryAuth(registry); + } String authConfigJson; if (authConfig == null) { @@ -97,8 +103,9 @@ public class DockerRegistryAuthResolver { if (paramAuthConfigs != null && paramAuthConfigs.getConfigs() != null) { authConfigs.putAll(paramAuthConfigs.getConfigs()); } + authConfigs.putAll(dynamicAuthResolver.getXRegistryConfig()); - authConfigs = normalizeDockerHubRegistryUrl(authConfigs); + authConfigs = normalizeDockerHubRegistryUrl(authConfigs); return Base64.getEncoder().encodeToString(JsonHelper.toJson(authConfigs).getBytes()); } diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerRegistryDynamicAuthResolver.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerRegistryDynamicAuthResolver.java new file mode 100644 index 0000000000..9e1c75b4d2 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/DockerRegistryDynamicAuthResolver.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * 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: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.docker.client; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.plugin.docker.client.dto.AuthConfig; + +import java.util.Map; + +/** + * Resolves dynamic auth config for docker registries. + * + * @author Mykola Morhun + */ +public interface DockerRegistryDynamicAuthResolver { + /** + * Retrieves actual auth data for given registry. + * If no credential found for given registry null will be returned. + * + * @param registry + * registry to which + * @return dynamic auth data for specified registry or null if no credential found + */ + @Nullable + AuthConfig getXRegistryAuth(@Nullable String registry); + + /** + * Retrieves all actual auth configs for all configured registries with dynamic auth credentials. + * If no registries with dynamic auth credentials found, empty map will be returned. + * + * @return all dynamic auth configs or empty map if no credentials found + */ + Map getXRegistryConfig(); + +} diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/NoOpDockerRegistryDynamicAuthResolverImpl.java b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/NoOpDockerRegistryDynamicAuthResolverImpl.java new file mode 100644 index 0000000000..c836214873 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-docker-client/src/main/java/org/eclipse/che/plugin/docker/client/NoOpDockerRegistryDynamicAuthResolverImpl.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * 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: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.docker.client; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.plugin.docker.client.dto.AuthConfig; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Mykola Morhun + */ +public class NoOpDockerRegistryDynamicAuthResolverImpl implements DockerRegistryDynamicAuthResolver { + @Override + @Nullable + public AuthConfig getXRegistryAuth(@Nullable String registry) { + return null; + } + + @Override + public Map getXRegistryConfig() { + return Collections.emptyMap(); + } +} diff --git a/plugins/plugin-docker/che-plugin-docker-client/src/test/java/org/eclipse/che/plugin/docker/client/DockerRegistryAuthResolverTest.java b/plugins/plugin-docker/che-plugin-docker-client/src/test/java/org/eclipse/che/plugin/docker/client/DockerRegistryAuthResolverTest.java index d151c2d7a9..c52daee737 100644 --- a/plugins/plugin-docker/che-plugin-docker-client/src/test/java/org/eclipse/che/plugin/docker/client/DockerRegistryAuthResolverTest.java +++ b/plugins/plugin-docker/che-plugin-docker-client/src/test/java/org/eclipse/che/plugin/docker/client/DockerRegistryAuthResolverTest.java @@ -25,6 +25,7 @@ import java.util.Base64; import java.util.HashMap; import java.util.Map; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -46,7 +47,8 @@ public class DockerRegistryAuthResolverTest { private static final String INITIAL_REGISTRY1_X_REGISTRY_AUTH_HEADER_VALUE = "{\"username\":\"user1\",\"password\":\"1234\"}"; private static final String INITIAL_REGISTRY2_X_REGISTRY_AUTH_HEADER_VALUE = "{\"username\":\"login2\",\"password\":\"abcd\"}"; - private static final String INITIAL_REGISTRY3_X_REGISTRY_AUTH_HEADER_VALUE = "{\"username\":\"username1234\",\"password\":\"a1b2c3d4\"}"; + private static final String INITIAL_REGISTRY3_X_REGISTRY_AUTH_HEADER_VALUE = + "{\"username\":\"username1234\",\"password\":\"a1b2c3d4\"}"; private static final String REGISTRY1_URL = "user.registry.com:5000"; private static final String REGISTRY2_URL = "local.registry:1234"; @@ -62,27 +64,35 @@ public class DockerRegistryAuthResolverTest { private static final String REGISTRY2_X_REGISTRY_AUTH_HEADER_VALUE = "{\"username\":\"mylocallogin\",\"password\":\"localreg\"}"; private static final String REGISTRY3_X_REGISTRY_AUTH_HEADER_VALUE = "{\"username\":\"usrname\",\"password\":\"pass1234\"}"; - private static final String INITIAL_X_AUTH_CONFIG_VALUE = + private static final String REGISTRY_WITH_DYNAMIC_PASSWORD_URL = "some.registry.com:1234"; + private static final String REGISTRY_WITH_DYNAMIC_PASSWORD_USERNAME = "USR"; + private static final String REGISTRY_WITH_DYNAMIC_PASSWORD_PASSWORD = ""; + + private static final String REGISTRY_WITH_DYNAMIC_PASSWORD_AUTH_HEADER_VALUE = "{\"username\":\"USR\",\"password\":\"\"}"; + + private static final String INITIAL_X_AUTH_CONFIG_VALUE = "{\"test.registry.com:5050\":{\"password\":\"1234\",\"username\":\"user1\"}," + "\"somehost:4567\":{\"password\":\"a1b2c3d4\",\"username\":\"username1234\"}," + "\"some.reg:1234\":{\"password\":\"abcd\",\"username\":\"login2\"}}"; - private static final String CUSTOM_X_AUTH_CONFIG_VALUE = + private static final String CUSTOM_X_AUTH_CONFIG_VALUE = "{\"local.registry:1234\":{\"password\":\"localreg\",\"username\":\"mylocallogin\"}," + "\"test.registry.com:5050\":{\"password\":\"pass1234\",\"username\":\"usrname\"}," + "\"user.registry.com:5000\":{\"password\":\"pass\",\"username\":\"user\"}}"; - private static final String X_AUTH_CONFIG_VALUE = + private static final String REGISTRY_WITH_DYNAMIC_PASSWORD_X_AUTH_CONFIG_VALUE = + "{\"some.registry.com:1234\":{\"password\":\"\",\"username\":\"USR\"}}"; + private static final String X_AUTH_CONFIG_VALUE = "{\"local.registry:1234\":{\"password\":\"localreg\",\"username\":\"mylocallogin\"}," + "\"test.registry.com:5050\":{\"password\":\"pass1234\",\"username\":\"usrname\"}," + "\"somehost:4567\":{\"password\":\"a1b2c3d4\",\"username\":\"username1234\"}," + "\"some.reg:1234\":{\"password\":\"abcd\",\"username\":\"login2\"}," + "\"user.registry.com:5000\":{\"password\":\"pass\",\"username\":\"user\"}}"; - private static final String DEFAULT_REGISTRY_URL_ALIAS1 = null; - private static final String DEFAULT_REGISTRY_URL_ALIAS2 = ""; - private static final String DEFAULT_REGISTRY_URL_ALIAS3 = "docker.io"; - private static final String DEFAULT_REGISTRY_URL = "https://index.docker.io/v1/"; - private static final String DEFAULT_REGISTRY_USERNAME = "dockerHubUser"; - private static final String DEFAULT_REGISTRY_PASSWORD = "passwordFromDockerHubAccount"; + private static final String DEFAULT_REGISTRY_URL_ALIAS1 = null; + private static final String DEFAULT_REGISTRY_URL_ALIAS2 = ""; + private static final String DEFAULT_REGISTRY_URL_ALIAS3 = "docker.io"; + private static final String DEFAULT_REGISTRY_URL = "https://index.docker.io/v1/"; + private static final String DEFAULT_REGISTRY_USERNAME = "dockerHubUser"; + private static final String DEFAULT_REGISTRY_PASSWORD = "passwordFromDockerHubAccount"; private static final String DEFAULT_REGISTRY_X_REGISTRY_AUTH_VALUE = "{\"username\":\"dockerHubUser\",\"password\":\"passwordFromDockerHubAccount\"}"; @@ -93,10 +103,13 @@ public class DockerRegistryAuthResolverTest { private static final String EMPTY_JSON = "{}"; @Mock - private InitialAuthConfig initialAuthConfig; + private InitialAuthConfig initialAuthConfig; + @Mock + private DockerRegistryDynamicAuthResolver dynamicAuthResolver; private AuthConfigs initialAuthConfigs; private AuthConfigs customAuthConfigs; + private AuthConfigs dynamicAuthConfigs; private AuthConfigs emptyAuthConfigs; private AuthConfigs dockerHubAuthConfigs; @@ -122,7 +135,13 @@ public class DockerRegistryAuthResolverTest { .withPassword(REGISTRY2_PASSWORD)); customAuthConfigsMap.put(REGISTRY3_URL, DtoFactory.newDto(AuthConfig.class).withUsername(REGISTRY3_USERNAME) .withPassword(REGISTRY3_PASSWORD)); - customAuthConfigs = DtoFactory.newDto(AuthConfigs.class).withConfigs(customAuthConfigsMap); + customAuthConfigs = DtoFactory.newDto(AuthConfigs.class).withConfigs(customAuthConfigsMap); + + Map dynamicAuthConfigsMap = new HashMap<>(); + dynamicAuthConfigsMap.put(REGISTRY_WITH_DYNAMIC_PASSWORD_URL, DtoFactory.newDto(AuthConfig.class) + .withUsername(REGISTRY_WITH_DYNAMIC_PASSWORD_USERNAME) + .withPassword(REGISTRY_WITH_DYNAMIC_PASSWORD_PASSWORD)); + dynamicAuthConfigs = DtoFactory.newDto(AuthConfigs.class).withConfigs(dynamicAuthConfigsMap); emptyAuthConfigs = DtoFactory.newDto(AuthConfigs.class).withConfigs(new HashMap<>()); @@ -135,6 +154,7 @@ public class DockerRegistryAuthResolverTest { @BeforeMethod private void setup() { when(initialAuthConfig.getAuthConfigs()).thenReturn(initialAuthConfigs); + } @Test @@ -382,13 +402,46 @@ public class DockerRegistryAuthResolverTest { jsonToAuthConfigs(EMPTY_JSON)); } + @Test + public void shouldGetXRegistryAuthHeaderValueFromDynamicConfigOnly() { + when(initialAuthConfig.getAuthConfigs()).thenReturn(emptyAuthConfigs); + when(dynamicAuthResolver.getXRegistryAuth(REGISTRY_WITH_DYNAMIC_PASSWORD_URL)) + .thenReturn(dynamicAuthConfigs.getConfigs().get(REGISTRY_WITH_DYNAMIC_PASSWORD_URL)); + + String base64HeaderValue = authResolver.getXRegistryAuthHeaderValue(REGISTRY_WITH_DYNAMIC_PASSWORD_URL, emptyAuthConfigs); + + assertEqualsXRegistryAuthHeader(base64ToAuthConfig(base64HeaderValue), + jsonToAuthConfig(REGISTRY_WITH_DYNAMIC_PASSWORD_AUTH_HEADER_VALUE)); + } + + @Test + public void shouldGetXRegistryAuthHeaderValueFromDynamicConfig() { + when(dynamicAuthResolver.getXRegistryAuth(REGISTRY_WITH_DYNAMIC_PASSWORD_URL)) + .thenReturn(dynamicAuthConfigs.getConfigs().get(REGISTRY_WITH_DYNAMIC_PASSWORD_URL)); + + String base64HeaderValue = authResolver.getXRegistryAuthHeaderValue(REGISTRY_WITH_DYNAMIC_PASSWORD_URL, customAuthConfigs); + + assertEqualsXRegistryAuthHeader(base64ToAuthConfig(base64HeaderValue), + jsonToAuthConfig(REGISTRY_WITH_DYNAMIC_PASSWORD_AUTH_HEADER_VALUE)); + } + + @Test + public void shouldGetXRegistryConfigValueFromDynamicAuthConfigOnly() { + when(initialAuthConfig.getAuthConfigs()).thenReturn(emptyAuthConfigs); + when(dynamicAuthResolver.getXRegistryConfig()).thenReturn(dynamicAuthConfigs.getConfigs()); + + String base64HeaderValue = authResolver.getXRegistryConfigHeaderValue(emptyAuthConfigs); + + assertEqualsXRegistryConfigHeader(base64ToAuthConfigs(base64HeaderValue), + jsonToAuthConfigs(REGISTRY_WITH_DYNAMIC_PASSWORD_X_AUTH_CONFIG_VALUE)); + } private AuthConfig base64ToAuthConfig(String base64decodedJson) { return jsonToAuthConfig(new String(Base64.getDecoder().decode(base64decodedJson.getBytes()))); } private AuthConfig jsonToAuthConfig(String json) { - return DtoFactory.getInstance().createDtoFromJson(json, AuthConfig.class); + return DtoFactory.getInstance().createDtoFromJson(json, AuthConfig.class); } private void assertEqualsXRegistryAuthHeader(AuthConfig actual, AuthConfig expected) { diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java index d22a9a9542..b8d4d909a6 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java @@ -49,6 +49,8 @@ public class LocalDockerModule extends AbstractModule { bind(org.eclipse.che.plugin.docker.machine.node.WorkspaceFolderPathProvider.class) .to(org.eclipse.che.plugin.docker.machine.local.node.provider.LocalWorkspaceFolderPathProvider.class); + bind(org.eclipse.che.plugin.docker.client.DockerRegistryDynamicAuthResolver.class) + .to(org.eclipse.che.plugin.docker.client.NoOpDockerRegistryDynamicAuthResolverImpl.class); bind(org.eclipse.che.plugin.docker.client.DockerRegistryChecker.class).asEagerSingleton(); Multibinder devMachineEnvVars = Multibinder.newSetBinder(binder(), diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/integration/DockerProcessTest.java b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/integration/DockerProcessTest.java index da2bfaecb1..3faa73c5f8 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/integration/DockerProcessTest.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/integration/DockerProcessTest.java @@ -54,7 +54,7 @@ public class DockerProcessTest { new DefaultNetworkFinder()); docker = new DockerConnector(dockerConnectorConfiguration, new DockerConnectionFactory(dockerConnectorConfiguration), - new DockerRegistryAuthResolver(null), + new DockerRegistryAuthResolver(null, null), new DockerApiVersionPathPrefixProvider("1.18")); final ContainerCreated containerCreated = docker.createContainer( @@ -93,7 +93,7 @@ public class DockerProcessTest { new DefaultNetworkFinder()); docker = new DockerConnector(dockerConnectorConfiguration, new DockerConnectionFactory(dockerConnectorConfiguration), - new DockerRegistryAuthResolver(null), + new DockerRegistryAuthResolver(null, null), new DockerApiVersionPathPrefixProvider("")); } Command command = new CommandImpl("tailf", "tail -f /dev/null", "mvn");