CODENVY-453: Add ability to support docker registries with dynamic passwords

Signed-off-by: Mykola Morhun <mmorhun@codenvy.com>
6.19.x
Mykola Morhun 2016-08-08 11:32:17 +03:00
parent ad62c13a14
commit 3ebc3cdf34
6 changed files with 157 additions and 18 deletions

View File

@ -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());
}

View File

@ -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<String, AuthConfig> getXRegistryConfig();
}

View File

@ -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<String, AuthConfig> getXRegistryConfig() {
return Collections.emptyMap();
}
}

View File

@ -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 = "<current time>";
private static final String REGISTRY_WITH_DYNAMIC_PASSWORD_AUTH_HEADER_VALUE = "{\"username\":\"USR\",\"password\":\"<current time>\"}";
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\":\"<current time>\",\"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<String, AuthConfig> 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) {

View File

@ -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<String> devMachineEnvVars = Multibinder.newSetBinder(binder(),

View File

@ -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");