diff --git a/pom.xml b/pom.xml
index 13c71b63f..4b3d7cc0d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,6 +64,7 @@
1.3.9
0.3
18.0
+ 1.51
1.0.1
@@ -142,6 +143,12 @@
guava
${guava.version}
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ ${bouncycastle.version}
+
diff --git a/src/main/java/com/github/dockerjava/core/CertificateUtils.java b/src/main/java/com/github/dockerjava/core/CertificateUtils.java
new file mode 100644
index 000000000..89722a94d
--- /dev/null
+++ b/src/main/java/com/github/dockerjava/core/CertificateUtils.java
@@ -0,0 +1,142 @@
+package com.github.dockerjava.core;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.apache.commons.io.IOUtils;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+
+public class CertificateUtils {
+
+ public static boolean verifyCertificatesExist(String dockerCertPath) {
+ String[] files = {"ca.pem", "cert.pem", "key.pem"};
+ for (String file : files) {
+ Path path = Paths.get(dockerCertPath, file);
+ boolean exists = Files.exists(path);
+ if(!exists) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static KeyStore createKeyStore(final String dockerCertPath) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, CertificateException, KeyStoreException {
+ KeyPair keyPair = loadPrivateKey(dockerCertPath);
+ Certificate privateCertificate = loadCertificate(dockerCertPath);
+
+ KeyStore keyStore = KeyStore.getInstance("JKS");
+ keyStore.load(null);
+
+ keyStore.setKeyEntry("docker", keyPair.getPrivate(), "docker".toCharArray(), new Certificate[]{privateCertificate});
+ return keyStore;
+ }
+
+ public static KeyStore createTrustStore(final String dockerCertPath) throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
+ Path caPath = Paths.get(dockerCertPath, "ca.pem");
+ BufferedReader reader = Files.newBufferedReader(caPath, Charset.defaultCharset());
+ PEMParser pemParser = null;
+
+ try {
+ pemParser = new PEMParser(reader);
+ X509CertificateHolder certificateHolder = (X509CertificateHolder) pemParser.readObject();
+ Certificate caCertificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certificateHolder);
+
+ KeyStore trustStore = KeyStore.getInstance("JKS");
+ trustStore.load(null);
+ trustStore.setCertificateEntry("ca", caCertificate);
+ return trustStore;
+
+ }
+ finally {
+ if(pemParser != null) {
+ IOUtils.closeQuietly(pemParser);
+ }
+
+ if(reader != null) {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+
+ }
+
+ private static Certificate loadCertificate(final String dockerCertPath) throws IOException, CertificateException {
+ Path certificate = Paths.get(dockerCertPath, "cert.pem");
+ BufferedReader reader = Files.newBufferedReader(certificate, Charset.defaultCharset());
+ PEMParser pemParser = null;
+
+ try {
+ pemParser = new PEMParser(reader);
+ X509CertificateHolder certificateHolder = (X509CertificateHolder) pemParser.readObject();
+ return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certificateHolder);
+ }
+ finally {
+ if(pemParser != null) {
+ IOUtils.closeQuietly(pemParser);
+ }
+
+ if(reader != null) {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+
+ }
+
+ private static KeyPair loadPrivateKey(final String dockerCertPath) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+ Path certificate = Paths.get(dockerCertPath, "key.pem");
+ BufferedReader reader = Files.newBufferedReader(certificate, Charset.defaultCharset());
+
+ PEMParser pemParser = null;
+
+ try {
+ pemParser = new PEMParser(reader);
+
+ PEMKeyPair pemKeyPair = (PEMKeyPair) pemParser.readObject();
+
+ byte[] pemPrivateKeyEncoded = pemKeyPair.getPrivateKeyInfo().getEncoded();
+ byte[] pemPublicKeyEncoded = pemKeyPair.getPublicKeyInfo().getEncoded();
+
+ KeyFactory factory = KeyFactory.getInstance("RSA");
+
+ X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pemPublicKeyEncoded);
+ PublicKey publicKey = factory.generatePublic(publicKeySpec);
+
+ PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pemPrivateKeyEncoded);
+ PrivateKey privateKey = factory.generatePrivate(privateKeySpec);
+
+ return new KeyPair(publicKey, privateKey);
+
+ }
+ finally {
+ if(pemParser != null) {
+ IOUtils.closeQuietly(pemParser);
+ }
+
+ if(reader != null) {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+
+
+ }
+
+}
diff --git a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
index b2adea7fc..6e3795e97 100644
--- a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
+++ b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
@@ -10,7 +10,7 @@
public class DockerClientConfig {
private final URI uri;
- private final String version, username, password, email;
+ private final String version, username, password, email, dockerCertPath;
private final Integer readTimeout;
private final boolean loggingFilterEnabled;
@@ -22,6 +22,7 @@ private DockerClientConfig(DockerClientConfigBuilder builder) {
this.email = builder.email;
this.readTimeout = builder.readTimeout;
this.loggingFilterEnabled = builder.loggingFilterEnabled;
+ this.dockerCertPath = builder.dockerCertPath;
}
public URI getUri() {
@@ -51,6 +52,10 @@ public Integer getReadTimeout() {
public boolean isLoggingFilterEnabled() {
return loggingFilterEnabled;
}
+
+ public String getDockerCertPath() {
+ return dockerCertPath;
+ }
public static Properties loadIncludedDockerProperties() {
try {
@@ -97,7 +102,7 @@ public static Properties overrideDockerPropertiesWithSystemProperties(Properties
overriddenProperties.putAll(p);
// TODO Add all values from system properties that begin with docker.io.*
- for (String s : new String[]{ "url", "version", "username", "password", "email", "readTimeout", "enableLoggingFilter"}) {
+ for (String s : new String[]{ "url", "version", "username", "password", "email", "readTimeout", "enableLoggingFilter", "dockerCertPath"}) {
final String key = "docker.io." + s;
if (System.getProperties().containsKey(key)) {
overriddenProperties.setProperty(key, System.getProperty(key));
@@ -115,7 +120,7 @@ public static DockerClientConfigBuilder createDefaultConfigBuilder() {
public static class DockerClientConfigBuilder {
private URI uri;
- private String version, username, password, email;
+ private String version, username, password, email, dockerCertPath;
private Integer readTimeout;
private boolean loggingFilterEnabled;
@@ -124,7 +129,7 @@ public DockerClientConfigBuilder() {
/**
* This will set all fields in the builder to those contained in the Properties object. The Properties object
- * should contain the following docker.io.* keys: url, version, username, password, and email. If
+ * should contain the following docker.io.* keys: url, version, username, password, email, and dockerCertPath. If
* docker.io.readTimeout or docker.io.enableLoggingFilter are not contained, they will be set to 1000 and true,
* respectively.
*
@@ -138,7 +143,8 @@ public DockerClientConfigBuilder withProperties(Properties p) {
.withPassword(p.getProperty("docker.io.password"))
.withEmail(p.getProperty("docker.io.email"))
.withReadTimeout(Integer.valueOf(p.getProperty("docker.io.readTimeout", "0")))
- .withLoggingFilter(Boolean.valueOf(p.getProperty("docker.io.enableLoggingFilter", "true")));
+ .withLoggingFilter(Boolean.valueOf(p.getProperty("docker.io.enableLoggingFilter", "true")))
+ .withDockerCertPath(p.getProperty("docker.io.dockerCertPath"));
}
public final DockerClientConfigBuilder withUri(String uri) {
@@ -170,6 +176,10 @@ public final DockerClientConfigBuilder withLoggingFilter(boolean loggingFilterEn
this.loggingFilterEnabled = loggingFilterEnabled;
return this;
}
+ public final DockerClientConfigBuilder withDockerCertPath(String dockerCertPath) {
+ this.dockerCertPath = dockerCertPath;
+ return this;
+ }
public DockerClientConfig build() {
return new DockerClientConfig(this);
}
diff --git a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
index 74d3073f0..58450c8a6 100644
--- a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
+++ b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
@@ -1,18 +1,7 @@
package com.github.dockerjava.jaxrs;
-import java.io.IOException;
-import java.util.logging.Logger;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.client.WebTarget;
-
-import com.github.dockerjava.api.command.EventsCmd;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.CommonProperties;
-
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
+import com.github.dockerjava.api.DockerClientException;
import com.github.dockerjava.api.command.AttachContainerCmd;
import com.github.dockerjava.api.command.AuthCmd;
import com.github.dockerjava.api.command.BuildImageCmd;
@@ -22,6 +11,7 @@
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.CreateImageCmd;
import com.github.dockerjava.api.command.DockerCmdExecFactory;
+import com.github.dockerjava.api.command.EventsCmd;
import com.github.dockerjava.api.command.InfoCmd;
import com.github.dockerjava.api.command.InspectContainerCmd;
import com.github.dockerjava.api.command.InspectImageCmd;
@@ -44,12 +34,30 @@
import com.github.dockerjava.api.command.UnpauseContainerCmd;
import com.github.dockerjava.api.command.VersionCmd;
import com.github.dockerjava.api.command.WaitContainerCmd;
+import com.github.dockerjava.core.CertificateUtils;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.jaxrs.util.JsonClientFilter;
import com.github.dockerjava.jaxrs.util.ResponseStatusExceptionFilter;
import com.github.dockerjava.jaxrs.util.SelectiveLoggingFilter;
import com.google.common.base.Preconditions;
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.Security;
+import java.util.logging.Logger;
+
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.SslConfigurator;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+
public class DockerCmdExecFactoryImpl implements DockerCmdExecFactory {
private Client client;
@@ -78,7 +86,55 @@ public void init(DockerClientConfig dockerClientConfig) {
int readTimeout = dockerClientConfig.getReadTimeout();
clientConfig.property(ClientProperties.READ_TIMEOUT, readTimeout);
}
- client = ClientBuilder.newClient(clientConfig);
+
+ ClientBuilder clientBuilder = ClientBuilder.newBuilder().withConfig(clientConfig);
+
+ // Attempt to load Docker SSL certificates from location in following order:
+ // 1. User Defined
+ // 2. Environment Variable
+ // 3. User Home Directory
+ String dockerCertPath = dockerClientConfig.getDockerCertPath();
+
+ if(dockerCertPath == null) {
+ dockerCertPath = System.getenv("DOCKER_CERT_PATH");
+ }
+
+ if(dockerCertPath == null) {
+ dockerCertPath = System.getProperty("USER_HOME") + File.separator + ".docker";
+ }
+
+ if(dockerCertPath != null) {
+ boolean certificatesExist = CertificateUtils.verifyCertificatesExist(dockerCertPath);
+
+ if(certificatesExist) {
+
+ try {
+
+ Security.addProvider(new BouncyCastleProvider());
+
+ SslConfigurator sslConfig = SslConfigurator.newInstance();
+
+ KeyStore keyStore = CertificateUtils.createKeyStore(dockerCertPath);
+ KeyStore trustStore = CertificateUtils.createTrustStore(dockerCertPath);
+
+ sslConfig.keyStore(keyStore);
+ sslConfig.keyStorePassword("docker");
+
+ sslConfig.trustStore(trustStore);
+
+ SSLContext sslContext = sslConfig.createSSLContext();
+ clientBuilder.sslContext(sslContext);
+
+ }
+ catch(Exception e) {
+ throw new DockerClientException(e.getMessage(), e);
+ }
+
+ }
+
+ }
+
+ client = clientBuilder.build();
WebTarget webResource = client.target(dockerClientConfig.getUri());