[docker] upgrade to docker 1.7 and refactor TLS support

This commit is contained in:
Csaba Palfi 2015-07-13 22:26:26 +02:00 committed by Ignasi Barrera
parent 4edaf18226
commit 55a7d8ce3c
15 changed files with 402 additions and 236 deletions

View File

@ -8,15 +8,11 @@ Please follow these steps to configure your workstation for jclouds-docker:
- install the latest Docker release (please visit https://docs.docker.com/installation/)
If you are using `boot2docker`, notice that from version v1.3.0 the Docker daemon is set to use an encrypted TCP
socket (--tls, or --tlsverify),
then you need to import CA certificate into Trusted Certs:
`keytool -import -trustcacerts -file /Users/andrea/.boot2docker/certs/boot2docker-vm/ca.pem -alias BOOT2DOCKER -keystore $JAVA_HOME/jre/lib/security/cacerts`
If you are using `boot2docker` then it can also manage certificates and help you setup `DOCKER_CERT_PATH` and `DOCKER_HOST` environment variables. (See `boot2docker shellinit`)
by default the passoword is `changeit`
Assuming these environment variables are setup correctly there are no further setups steps are required.
N.B.: From `Docker 1.3.2+` the server doesn't accept sslv3 protocol (https://github.com/docker/docker/pull/8588/files)
Live tests then can now be run: `mvn -Plive integration-test`
#How it works

View File

@ -34,10 +34,11 @@
<packaging>bundle</packaging>
<properties>
<test.docker.endpoint>https://localhost:4243</test.docker.endpoint>
<test.docker.api-version>1.15</test.docker.api-version>
<test.docker.identity>FIXME</test.docker.identity>
<test.docker.credential>FIXME</test.docker.credential>
<test.docker.api-version>1.19</test.docker.api-version>
<test.docker.identity>${env.DOCKER_CERT_PATH}/cert.pem</test.docker.identity>
<test.docker.credential>${env.DOCKER_CERT_PATH}/key.pem</test.docker.credential>
<test.docker.cacert.path>${env.DOCKER_CERT_PATH}/ca.pem</test.docker.cacert.path>
<test.jclouds.trust-all-certs>false</test.jclouds.trust-all-certs>
<jclouds.osgi.export>org.jclouds.docker*;version="${project.version}"</jclouds.osgi.export>
<jclouds.osgi.import>
org.jclouds.compute.internal;version="${project.version}",
@ -134,6 +135,26 @@
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>regex-property</id>
<goals>
<goal>regex-property</goal>
</goals>
<configuration>
<name>test.docker.endpoint</name>
<value>${env.DOCKER_HOST}</value>
<regex>tcp</regex>
<replacement>https</replacement>
<failIfNoMatch>false</failIfNoMatch>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
@ -149,8 +170,10 @@
<systemPropertyVariables>
<test.docker.endpoint>${test.docker.endpoint}</test.docker.endpoint>
<test.docker.api-version>${test.docker.api-version}</test.docker.api-version>
<test.docker.credential>${test.docker.identity}</test.docker.credential>
<test.docker.identity>${test.docker.identity}</test.docker.identity>
<test.docker.credential>${test.docker.credential}</test.docker.credential>
<test.docker.cacert.path>${test.docker.cacert.path}</test.docker.cacert.path>
<test.jclouds.trust-all-certs>${test.jclouds.trust-all-certs}</test.jclouds.trust-all-certs>
</systemPropertyVariables>
</configuration>
</execution>

View File

@ -37,6 +37,8 @@ import static org.jclouds.reflect.Reflection2.typeToken;
@AutoService(ApiMetadata.class)
public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
public static final String DOCKER_CA_CERT_PATH = "docker.cacert.path";
@Override
public Builder toBuilder() {
return new Builder().fromApiMetadata(this);
@ -55,6 +57,7 @@ public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
properties.setProperty(Constants.PROPERTY_CONNECTION_TIMEOUT, "1200000"); // 15 minutes
properties.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password");
properties.setProperty(TEMPLATE, "osFamily=UBUNTU,os64Bit=true");
properties.setProperty(DOCKER_CA_CERT_PATH, "");
return properties;
}

View File

@ -16,8 +16,14 @@
*/
package org.jclouds.docker.config;
import com.google.common.base.Supplier;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
import com.google.inject.util.Modules;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.handlers.DockerErrorHandler;
import org.jclouds.docker.suppliers.DockerUntrustedSSLContextSupplier;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
@ -28,6 +34,8 @@ import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.config.HttpApiModule;
import javax.net.ssl.SSLContext;
/**
* Configures the Docker connection.
*/
@ -48,8 +56,13 @@ public class DockerHttpApiModule extends HttpApiModule<DockerApi> {
@Override
protected void configure() {
super.configure();
install(new OkHttpCommandExecutorServiceModule());
install(Modules.override(new OkHttpCommandExecutorServiceModule()).with(new AbstractModule() {
@Override
protected void configure() {
bind(new TypeLiteral<Supplier<SSLContext>>() {}).annotatedWith(Names.named("untrusted")).to(DockerUntrustedSSLContextSupplier.class);
}
}));
bind(OkHttpClientSupplier.class).to(DockerOkHttpClientSupplier.class);
}
}
}

View File

@ -19,7 +19,7 @@ package org.jclouds.docker.config;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.docker.suppliers.SSLContextWithKeysSupplier;
import org.jclouds.docker.suppliers.DockerSSLContextSupplier;
import org.jclouds.http.okhttp.OkHttpClientSupplier;
import com.google.common.collect.ImmutableList;
@ -30,24 +30,24 @@ import com.squareup.okhttp.TlsVersion;
@Singleton
public class DockerOkHttpClientSupplier implements OkHttpClientSupplier {
private final SSLContextWithKeysSupplier sslContextWithKeysSupplier;
private final DockerSSLContextSupplier dockerSSLContextSupplier;
@Inject
DockerOkHttpClientSupplier(SSLContextWithKeysSupplier sslContextWithKeysSupplier) {
this.sslContextWithKeysSupplier = sslContextWithKeysSupplier;
}
@Inject
DockerOkHttpClientSupplier(DockerSSLContextSupplier dockerSSLContextSupplier) {
this.dockerSSLContextSupplier = dockerSSLContextSupplier;
}
@Override
public OkHttpClient get() {
OkHttpClient client = new OkHttpClient();
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_0, TlsVersion.TLS_1_1, TlsVersion.TLS_1_2)
.build();
ConnectionSpec cleartextSpec = new ConnectionSpec.Builder(ConnectionSpec.CLEARTEXT)
.build();
client.setConnectionSpecs(ImmutableList.of(tlsSpec, cleartextSpec));
client.setSslSocketFactory(sslContextWithKeysSupplier.get().getSocketFactory());
return client;
}
@Override
public OkHttpClient get() {
OkHttpClient client = new OkHttpClient();
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_0, TlsVersion.TLS_1_1, TlsVersion.TLS_1_2)
.build();
ConnectionSpec cleartextSpec = new ConnectionSpec.Builder(ConnectionSpec.CLEARTEXT)
.build();
client.setConnectionSpecs(ImmutableList.of(tlsSpec, cleartextSpec));
client.setSslSocketFactory(dockerSSLContextSupplier.get().getSocketFactory());
return client;
}
}

View File

@ -101,8 +101,6 @@ public abstract class Config {
@Nullable public abstract String networkMode();
public abstract Map<String, String> devices();
Config() {
}
@ -112,7 +110,7 @@ public abstract class Config {
"AttachStderr", "Tty", "OpenStdin", "StdinOnce", "Env", "Cmd", "Entrypoint", "Image", "Volumes",
"WorkingDir", "NetworkDisabled", "ExposedPorts", "SecurityOpts", "HostConfig", "Binds", "Links",
"LxcConf", "PortBindings", "PublishAllPorts", "Privileged", "Dns", "DnsSearch", "VolumesFrom",
"CapAdd", "CapDrop", "RestartPolicy", "NetworkMode", "Devices"
"CapAdd", "CapDrop", "RestartPolicy", "NetworkMode"
})
public static Config create(String hostname, String domainname, String user, int memory, int memorySwap,
int cpuShares, boolean attachStdin, boolean attachStdout, boolean attachStderr, boolean tty,
@ -121,13 +119,12 @@ public abstract class Config {
Map<String, ?> exposedPorts, List<String> securityOpts, HostConfig hostConfig, List<String> binds,
List<String> links, List<Map<String, String>> lxcConf, Map<String, List<Map<String, String>>> portBindings,
boolean publishAllPorts, boolean privileged, List<String> dns, String dnsSearch, String volumesFrom,
List<String> capAdd, List<String> capDrop, Map<String, String> restartPolicy, String networkMode, Map<String, String> devices) {
List<String> capAdd, List<String> capDrop, Map<String, String> restartPolicy, String networkMode) {
return new AutoValue_Config(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin,
attachStdout, attachStderr, tty, openStdin, stdinOnce, copyOf(env), copyOf(cmd), copyOf(entrypoint),
image, copyOf(volumes), workingDir, networkDisabled, copyOf(exposedPorts), copyOf(securityOpts), hostConfig,
copyOf(binds), copyOf(links), copyOf(lxcConf), copyOf(portBindings), publishAllPorts, privileged,
copyOf(dns), dnsSearch, volumesFrom, copyOf(capAdd), copyOf(capDrop), copyOf(restartPolicy), networkMode,
copyOf(devices));
copyOf(dns), dnsSearch, volumesFrom, copyOf(capAdd), copyOf(capDrop), copyOf(restartPolicy), networkMode);
}
public static Builder builder() {
@ -174,7 +171,6 @@ public abstract class Config {
private List<String> capDrop = Lists.newArrayList();
private Map<String, String> restartPolicy = Maps.newHashMap();
private String networkMode;
private Map<String, String> devices = Maps.newHashMap();
public Builder hostname(String hostname) {
this.hostname = hostname;
@ -191,18 +187,24 @@ public abstract class Config {
return this;
}
public Builder memory(int memory) {
this.memory = memory;
public Builder memory(Integer memory) {
if (memory != null) {
this.memory = memory;
}
return this;
}
public Builder memorySwap(int memorySwap) {
this.memorySwap = memorySwap;
public Builder memorySwap(Integer memorySwap) {
if (memorySwap != null) {
this.memorySwap = memorySwap;
}
return this;
}
public Builder cpuShares(int cpuShares) {
this.cpuShares = cpuShares;
public Builder cpuShares(Integer cpuShares) {
if (cpuShares != null) {
this.cpuShares = cpuShares;
}
return this;
}
@ -351,17 +353,12 @@ public abstract class Config {
return this;
}
public Builder devices(Map<String, String> devices) {
this.devices = devices;
return this;
}
public Config build() {
return Config.create(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin, attachStdout,
attachStderr, tty, openStdin, stdinOnce, env, cmd, entrypoint, image, volumes, workingDir,
networkDisabled, exposedPorts, securityOpts, hostConfig, binds, links, lxcConf, portBindings,
publishAllPorts, privileged, dns, dnsSearch, volumesFrom, capAdd, capDrop, restartPolicy,
networkMode, devices);
networkMode);
}
public Builder fromConfig(Config in) {
@ -373,7 +370,7 @@ public abstract class Config {
.hostConfig(in.hostConfig()).binds(in.binds()).links(in.links()).lxcConf(in.lxcConf())
.portBindings(in.portBindings()).publishAllPorts(in.publishAllPorts()).privileged(in.privileged())
.dns(in.dns()).dnsSearch(in.dnsSearch()).volumesFrom(in.volumesFrom()).capAdd(in.capAdd())
.capDrop(in.capDrop()).restartPolicy(in.restartPolicy()).networkMode(in.networkMode()).devices(in.devices());
.capDrop(in.capDrop()).restartPolicy(in.restartPolicy()).networkMode(in.networkMode());
}
}

View File

@ -28,7 +28,7 @@ public abstract class Info {
public abstract int containers();
public abstract int debug();
public abstract boolean debug();
public abstract String driver();
@ -36,7 +36,7 @@ public abstract class Info {
public abstract String executionDriver();
public abstract int iPv4Forwarding();
public abstract boolean iPv4Forwarding();
public abstract int images();
@ -48,7 +48,7 @@ public abstract class Info {
public abstract String kernelVersion();
public abstract int memoryLimit();
public abstract boolean memoryLimit();
public abstract int nEventsListener();
@ -58,7 +58,7 @@ public abstract class Info {
public abstract String operatingSystem();
public abstract int swapLimit();
public abstract boolean swapLimit();
public abstract String dockerRootDir();
@ -96,10 +96,10 @@ public abstract class Info {
"NFd", "NGoroutines", "OperatingSystem", "SwapLimit", "DockerRootDir", "Labels", "MemTotal", "NCPU",
"ID", "Name"
})
public static Info create(int containers, int debug, String driver, List<List<String>> driverStatus,
String executionDriver, int iPv4Forwarding, int images, String indexServerAddress,
String initPath, String initSha1, String kernelVersion, int memoryLimit,
int nEventsListener, int nFd, int nGoroutines, String operatingSystem, int swapLimit,
public static Info create(int containers, boolean debug, String driver, List<List<String>> driverStatus,
String executionDriver, boolean iPv4Forwarding, int images, String indexServerAddress,
String initPath, String initSha1, String kernelVersion, boolean memoryLimit,
int nEventsListener, int nFd, int nGoroutines, String operatingSystem, boolean swapLimit,
String dockerRootDir, List<String> labels, long memTotal, int ncpu, String id, String name) {
return new AutoValue_Info(containers, debug, driver, driverStatus, executionDriver, iPv4Forwarding, images,
indexServerAddress, initPath, initSha1, kernelVersion, memoryLimit, nEventsListener, nFd, nGoroutines,

View File

@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.suppliers;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import org.jclouds.docker.DockerApiMetadata;
import org.jclouds.domain.Credentials;
import org.jclouds.location.Provider;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.GeneralSecurityException;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
@Singleton
public class DockerSSLContextSupplier implements Supplier<SSLContext> {
private final Supplier<Credentials> creds;
private final String caCertPath;
@Inject
DockerSSLContextSupplier(@Provider Supplier<Credentials> creds, @Named(DockerApiMetadata.DOCKER_CA_CERT_PATH) String caCertPath) {
this.creds = creds;
this.caCertPath = caCertPath;
}
@Override
public SSLContext get() {
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
try {
SSLContextBuilder builder = new SSLContextBuilder();
builder.clientKeyAndCertificate(currentCreds.credential, currentCreds.identity);
if (!Strings.isNullOrEmpty(caCertPath)) {
builder.caCertificate(caCertPath);
}
return builder.build();
} catch (GeneralSecurityException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.suppliers;
import com.google.common.base.Supplier;
import org.jclouds.domain.Credentials;
import org.jclouds.http.config.SSLModule;
import org.jclouds.location.Provider;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.GeneralSecurityException;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
@Singleton
public class DockerUntrustedSSLContextSupplier implements Supplier<SSLContext> {
private final Supplier<Credentials> creds;
private final SSLModule.TrustAllCerts insecureTrustManager;
@Inject
DockerUntrustedSSLContextSupplier(@Provider Supplier<Credentials> creds, SSLModule.TrustAllCerts insecureTrustManager) {
this.creds = creds;
this.insecureTrustManager = insecureTrustManager;
}
@Override
public SSLContext get() {
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
try {
SSLContextBuilder builder = new SSLContextBuilder();
builder.clientKeyAndCertificate(currentCreds.credential, currentCreds.identity);
builder.trustManager(insecureTrustManager);
return builder.build();
} catch (GeneralSecurityException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
}
}
}

View File

@ -0,0 +1,174 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.suppliers;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.jclouds.util.Closeables2;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import static com.google.common.base.Throwables.propagate;
public class SSLContextBuilder {
private KeyManager[] keyManagers;
private TrustManager[] trustManagers;
public SSLContextBuilder() { }
public SSLContextBuilder clientKeyAndCertificate(String keyPath, String certPath) throws IOException, CertificateException {
X509Certificate certificate = getCertificate(loadFile(certPath));
PrivateKey privateKey = getKey(loadFile(keyPath));
keyManagers = new KeyManager[]{new InMemoryKeyManager(certificate, privateKey)};
return this;
}
public SSLContextBuilder caCertificate(String caCertPath){
trustManagers = getTrustManagerWithCaCert(caCertPath);
return this;
}
public SSLContextBuilder trustManager(TrustManager trustManager) {
trustManagers = new TrustManager[]{trustManager};
return this;
}
public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
return sslContext;
}
private TrustManager[] getTrustManagerWithCaCert(String caCertPath) {
try {
X509Certificate caCert = getCertificate(loadFile(caCertPath));
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
trustStore.setCertificateEntry("ca", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
return tmf.getTrustManagers();
} catch (GeneralSecurityException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
}
}
private static X509Certificate getCertificate(String certificate) {
try {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(
new ByteArrayInputStream(certificate.getBytes(Charsets.UTF_8)));
} catch (CertificateException ex) {
throw new RuntimeException("Invalid certificate", ex);
}
}
private static PrivateKey getKey(String privateKey) {
PEMParser pemParser = new PEMParser(new StringReader(privateKey));
try {
Object object = pemParser.readObject();
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
}
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair keyPair = converter.getKeyPair((PEMKeyPair) object);
return keyPair.getPrivate();
} catch (IOException ex) {
throw new RuntimeException("Invalid private key", ex);
} finally {
Closeables2.closeQuietly(pemParser);
}
}
private static String loadFile(final String filePath) throws IOException {
return Files.toString(new File(filePath), Charsets.UTF_8);
}
private static class InMemoryKeyManager extends X509ExtendedKeyManager {
private static final String DEFAULT_ALIAS = "docker";
private final X509Certificate certificate;
private final PrivateKey privateKey;
public InMemoryKeyManager(final X509Certificate certificate, final PrivateKey privateKey)
throws IOException, CertificateException {
this.certificate = certificate;
this.privateKey = privateKey;
}
@Override
public String chooseClientAlias(final String[] keyType, final Principal[] issuers,
final Socket socket) {
return DEFAULT_ALIAS;
}
@Override
public String chooseServerAlias(final String keyType, final Principal[] issuers,
final Socket socket) {
return DEFAULT_ALIAS;
}
@Override
public X509Certificate[] getCertificateChain(final String alias) {
return new X509Certificate[]{certificate};
}
@Override
public String[] getClientAliases(final String keyType, final Principal[] issuers) {
return new String[]{DEFAULT_ALIAS};
}
@Override
public PrivateKey getPrivateKey(final String alias) {
return privateKey;
}
@Override
public String[] getServerAliases(final String keyType, final Principal[] issuers) {
return new String[]{DEFAULT_ALIAS};
}
}
}

View File

@ -1,166 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.suppliers;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedKeyManager;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.config.SSLModule.TrustAllCerts;
import org.jclouds.location.Provider;
import org.jclouds.util.Closeables2;
import com.google.common.base.Charsets;
import com.google.common.base.Supplier;
import com.google.common.io.Files;
@Singleton
public class SSLContextWithKeysSupplier implements Supplier<SSLContext> {
private final TrustManager[] trustManager;
private final Supplier<Credentials> creds;
@Inject
SSLContextWithKeysSupplier(@Provider Supplier<Credentials> creds, HttpUtils utils, TrustAllCerts trustAllCerts) {
this.trustManager = utils.trustAllCerts() ? new TrustManager[]{trustAllCerts} : null;
this.creds = creds;
}
@Override
public SSLContext get() {
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
X509Certificate certificate = getCertificate(loadFile(currentCreds.identity));
PrivateKey privateKey = getKey(loadFile(currentCreds.credential));
sslContext.init(new KeyManager[]{new InMemoryKeyManager(certificate, privateKey)}, trustManager, new SecureRandom());
return sslContext;
} catch (NoSuchAlgorithmException e) {
throw propagate(e);
} catch (KeyManagementException e) {
throw propagate(e);
} catch (CertificateException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
}
}
private static X509Certificate getCertificate(String certificate) {
try {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(
new ByteArrayInputStream(certificate.getBytes(Charsets.UTF_8)));
} catch (CertificateException ex) {
throw new RuntimeException("Invalid certificate", ex);
}
}
private static PrivateKey getKey(String privateKey) {
PEMParser pemParser = new PEMParser(new StringReader(privateKey));
try {
Object object = pemParser.readObject();
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
}
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair keyPair = converter.getKeyPair((PEMKeyPair) object);
return keyPair.getPrivate();
} catch (IOException ex) {
throw new RuntimeException("Invalid private key", ex);
} finally {
Closeables2.closeQuietly(pemParser);
}
}
private static String loadFile(final String filePath) throws IOException {
return Files.toString(new File(filePath), Charsets.UTF_8);
}
private static class InMemoryKeyManager extends X509ExtendedKeyManager {
private static final String DEFAULT_ALIAS = "docker";
private final X509Certificate certificate;
private final PrivateKey privateKey;
public InMemoryKeyManager(final X509Certificate certificate, final PrivateKey privateKey)
throws IOException, CertificateException {
this.certificate = certificate;
this.privateKey = privateKey;
}
@Override
public String chooseClientAlias(final String[] keyType, final Principal[] issuers,
final Socket socket) {
return DEFAULT_ALIAS;
}
@Override
public String chooseServerAlias(final String keyType, final Principal[] issuers,
final Socket socket) {
return DEFAULT_ALIAS;
}
@Override
public X509Certificate[] getCertificateChain(final String alias) {
return new X509Certificate[]{certificate};
}
@Override
public String[] getClientAliases(final String keyType, final Principal[] issuers) {
return new String[]{DEFAULT_ALIAS};
}
@Override
public PrivateKey getPrivateKey(final String alias) {
return privateKey;
}
@Override
public String[] getServerAliases(final String keyType, final Principal[] issuers) {
return new String[]{DEFAULT_ALIAS};
}
}
}

View File

@ -29,6 +29,7 @@ import org.jboss.shrinkwrap.api.GenericArchive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset;
import org.jboss.shrinkwrap.api.exporter.TarExporter;
import org.jclouds.Constants;
import org.jclouds.apis.BaseApiLiveTest;
import org.jclouds.compute.config.ComputeServiceProperties;
import org.jclouds.docker.DockerApi;
@ -56,8 +57,9 @@ public class BaseDockerApiLiveTest extends BaseApiLiveTest<DockerApi> {
@Override
protected Properties setupProperties() {
Properties overrides = super.setupProperties();
overrides.setProperty("jclouds.trust-all-certs", "false");
overrides.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password");
setIfTestSystemPropertyPresent(overrides, provider + ".cacert.path");
setIfTestSystemPropertyPresent(overrides, Constants.PROPERTY_TRUST_ALL_CERTS);
return overrides;
}

View File

@ -128,7 +128,7 @@ public class ContainerApiLiveTest extends BaseDockerApiLiveTest {
@Test(dependsOnMethods = "testRestartContainer")
public void testWaitContainer() {
api().stopContainer(container.id(), 1);
assertEquals(api().wait(container.id()).statusCode(), -1);
assertEquals(api().wait(container.id()).statusCode(), 137);
}
@Test(dependsOnMethods = "testWaitContainer")

View File

@ -40,25 +40,25 @@ public class InfoParseTest extends BaseDockerParseTest<Info> {
public Info expected() {
return Info.create(
0, // containers
1, // debug
true, // debug
"aufs", // driver
ImmutableList.<List<String>>of(
ImmutableList.of("Root Dir", "/mnt/sda1/var/lib/docker/aufs"),
ImmutableList.of("Dirs", "46")
), // driverStatus
"native-0.2", // ExecutionDriver
1, // IPv4Forwarding
true, // IPv4Forwarding
46, // Images
"https://index.docker.io/v1/", // IndexServerAddress
"/usr/local/bin/docker", // InitPath
"", // InitSha1
"3.16.7-tinycore64", // KernelVersion
1, // MemoryLimit
true, // MemoryLimit
0, // NEventsListener
10, // NFd
11, // NGoroutines
"Boot2Docker 1.4.1 (TCL 5.4); master : 86f7ec8 - Tue Dec 16 23:11:29 UTC 2014", // OperatingSystem
1, // SwapLimit
true, // SwapLimit
"/mnt/sda1/var/lib/docker", // DockerRootDir
null, // Labels
2105585664, // MemTotal

View File

@ -1,6 +1,6 @@
{
"Containers": 0,
"Debug": 1,
"Debug": true,
"DockerRootDir": "/mnt/sda1/var/lib/docker",
"Driver": "aufs",
"DriverStatus": [
@ -15,7 +15,7 @@
],
"ExecutionDriver": "native-0.2",
"ID": "7V5Y:IQ2M:HWIL:AZJV:HKRD:Q7OZ:3EQA:ZHMO:4LAD:OSIY:YBAA:BSX6",
"IPv4Forwarding": 1,
"IPv4Forwarding": true,
"Images": 46,
"IndexServerAddress": "https://index.docker.io/v1/",
"InitPath": "/usr/local/bin/docker",
@ -23,12 +23,12 @@
"KernelVersion": "3.16.7-tinycore64",
"Labels": null,
"MemTotal": 2105585664,
"MemoryLimit": 1,
"MemoryLimit": true,
"NCPU": 8,
"NEventsListener": 0,
"NFd": 10,
"NGoroutines": 11,
"Name": "boot2docker",
"OperatingSystem": "Boot2Docker 1.4.1 (TCL 5.4); master : 86f7ec8 - Tue Dec 16 23:11:29 UTC 2014",
"SwapLimit": 1
"SwapLimit": true
}