diff --git a/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java b/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java index 65855419f..59318f12f 100644 --- a/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java +++ b/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java @@ -38,6 +38,7 @@ public class DockerApiMetadata extends BaseHttpApiMetadata { public static final String DOCKER_CA_CERT_PATH = "docker.cacert.path"; + public static final String DOCKER_CA_CERT_DATA = "docker.cacert.data"; @Override public Builder toBuilder() { @@ -58,6 +59,7 @@ public static Properties defaultProperties() { properties.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password"); properties.setProperty(TEMPLATE, "osFamily=UBUNTU,os64Bit=true"); properties.setProperty(DOCKER_CA_CERT_PATH, ""); + properties.setProperty(DOCKER_CA_CERT_DATA, ""); return properties; } @@ -67,8 +69,8 @@ protected Builder() { super(DockerApi.class); id("docker") .name("Docker API") - .identityName("Path to certificate .pem file") - .credentialName("Path to key .pem file") + .identityName("Path or data for certificate .pem file") + .credentialName("Path or data for key .pem file") .documentation(URI.create("https://docs.docker.com/reference/api/docker_remote_api/")) .version("1.16") .defaultEndpoint("https://127.0.0.1:2376") diff --git a/docker/src/main/java/org/jclouds/docker/suppliers/DockerSSLContextSupplier.java b/docker/src/main/java/org/jclouds/docker/suppliers/DockerSSLContextSupplier.java index ed901f36d..326528a61 100644 --- a/docker/src/main/java/org/jclouds/docker/suppliers/DockerSSLContextSupplier.java +++ b/docker/src/main/java/org/jclouds/docker/suppliers/DockerSSLContextSupplier.java @@ -18,6 +18,7 @@ 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; @@ -26,22 +27,25 @@ 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; +import static org.jclouds.docker.suppliers.SSLContextBuilder.isClientKeyAndCertificateData; @Singleton public class DockerSSLContextSupplier implements Supplier { private final Supplier creds; private final String caCertPath; - + private final String caCertData; @Inject - DockerSSLContextSupplier(@Provider Supplier creds, @Named(DockerApiMetadata.DOCKER_CA_CERT_PATH) String caCertPath) { + DockerSSLContextSupplier(@Provider Supplier creds, @Named(DockerApiMetadata.DOCKER_CA_CERT_PATH) String caCertPath, @Named(DockerApiMetadata.DOCKER_CA_CERT_DATA) String caCertData) { this.creds = creds; this.caCertPath = caCertPath; + this.caCertData = caCertData; } @Override @@ -49,9 +53,15 @@ public SSLContext get() { Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null"); try { SSLContextBuilder builder = new SSLContextBuilder(); - builder.clientKeyAndCertificate(currentCreds.credential, currentCreds.identity); + if (isClientKeyAndCertificateData(currentCreds.credential, currentCreds.identity)) { + builder.clientKeyAndCertificateData(currentCreds.credential, currentCreds.identity); + } else { + builder.clientKeyAndCertificatePaths(currentCreds.credential, currentCreds.identity); + } if (!Strings.isNullOrEmpty(caCertPath)) { - builder.caCertificate(caCertPath); + builder.caCertificatePath(caCertPath); + } else if (!Strings.isNullOrEmpty(caCertData)) { + builder.caCertificateData(caCertData); } return builder.build(); } catch (GeneralSecurityException e) { diff --git a/docker/src/main/java/org/jclouds/docker/suppliers/DockerUntrustedSSLContextSupplier.java b/docker/src/main/java/org/jclouds/docker/suppliers/DockerUntrustedSSLContextSupplier.java index d0c9077f5..0480f13a8 100644 --- a/docker/src/main/java/org/jclouds/docker/suppliers/DockerUntrustedSSLContextSupplier.java +++ b/docker/src/main/java/org/jclouds/docker/suppliers/DockerUntrustedSSLContextSupplier.java @@ -17,6 +17,7 @@ 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; @@ -24,11 +25,13 @@ 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; +import static org.jclouds.docker.suppliers.SSLContextBuilder.isClientKeyAndCertificateData; @Singleton public class DockerUntrustedSSLContextSupplier implements Supplier { @@ -47,7 +50,11 @@ public SSLContext get() { Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null"); try { SSLContextBuilder builder = new SSLContextBuilder(); - builder.clientKeyAndCertificate(currentCreds.credential, currentCreds.identity); + if (isClientKeyAndCertificateData(currentCreds.credential, currentCreds.identity)) { + builder.clientKeyAndCertificateData(currentCreds.credential, currentCreds.identity); + } else { + builder.clientKeyAndCertificatePaths(currentCreds.credential, currentCreds.identity); + } builder.trustManager(insecureTrustManager); return builder.build(); } catch (GeneralSecurityException e) { diff --git a/docker/src/main/java/org/jclouds/docker/suppliers/SSLContextBuilder.java b/docker/src/main/java/org/jclouds/docker/suppliers/SSLContextBuilder.java index 6030def59..cc1025b74 100644 --- a/docker/src/main/java/org/jclouds/docker/suppliers/SSLContextBuilder.java +++ b/docker/src/main/java/org/jclouds/docker/suppliers/SSLContextBuilder.java @@ -18,10 +18,13 @@ 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.crypto.Pems; import org.jclouds.util.Closeables2; import javax.net.ssl.KeyManager; @@ -29,6 +32,7 @@ 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; @@ -54,22 +58,48 @@ public class SSLContextBuilder { private KeyManager[] keyManagers; private TrustManager[] trustManagers; + public static final boolean isClientKeyAndCertificateData(String key, String cert) { + return (key.startsWith(Pems.PUBLIC_X509_MARKER) || key.startsWith(Pems.PUBLIC_PKCS1_MARKER)) && + cert.startsWith(Pems.CERTIFICATE_X509_MARKER); + } + public SSLContextBuilder() { } - public SSLContextBuilder clientKeyAndCertificate(String keyPath, String certPath) throws IOException, CertificateException { + public SSLContextBuilder clientKeyAndCertificatePaths(String keyPath, String certPath) throws IOException, CertificateException { X509Certificate certificate = getCertificate(loadFile(certPath)); PrivateKey privateKey = getKey(loadFile(keyPath)); - keyManagers = new KeyManager[]{new InMemoryKeyManager(certificate, privateKey)}; + keyManager(new InMemoryKeyManager(certificate, privateKey)); + return this; + } + + public SSLContextBuilder clientKeyAndCertificateData(String keyData, String certData) throws CertificateException { + X509Certificate certificate = getCertificate(certData); + PrivateKey privateKey = getKey(keyData); + keyManager(new InMemoryKeyManager(certificate, privateKey)); + return this; + } + + public SSLContextBuilder caCertificatePath(String caCertPath) { + try { + trustManagers = getTrustManagerWithCaCert(loadFile(caCertPath)); + } catch (IOException e) { + throw propagate(e); + } return this; } - public SSLContextBuilder caCertificate(String caCertPath){ + public SSLContextBuilder caCertificateData(String caCertPath) { trustManagers = getTrustManagerWithCaCert(caCertPath); return this; } + public SSLContextBuilder keyManager(KeyManager keyManager) { + keyManagers = new KeyManager[] { keyManager }; + return this; + } + public SSLContextBuilder trustManager(TrustManager trustManager) { - trustManagers = new TrustManager[]{trustManager}; + trustManagers = new TrustManager[] { trustManager }; return this; } @@ -79,9 +109,9 @@ public SSLContext build() throws NoSuchAlgorithmException, KeyManagementExceptio return sslContext; } - private TrustManager[] getTrustManagerWithCaCert(String caCertPath) { + private TrustManager[] getTrustManagerWithCaCert(String caCertData) { try { - X509Certificate caCert = getCertificate(loadFile(caCertPath)); + X509Certificate caCert = getCertificate(caCertData); KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); trustStore.setCertificateEntry("ca", caCert); @@ -132,32 +162,29 @@ private static class InMemoryKeyManager extends X509ExtendedKeyManager { private final PrivateKey privateKey; - public InMemoryKeyManager(final X509Certificate certificate, final PrivateKey privateKey) - throws IOException, CertificateException { + public InMemoryKeyManager(final X509Certificate certificate, final PrivateKey privateKey) throws CertificateException { this.certificate = certificate; this.privateKey = privateKey; } @Override - public String chooseClientAlias(final String[] keyType, final Principal[] issuers, - final Socket socket) { + 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) { + 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}; + return new X509Certificate[] { certificate }; } @Override public String[] getClientAliases(final String keyType, final Principal[] issuers) { - return new String[]{DEFAULT_ALIAS}; + return new String[] { DEFAULT_ALIAS }; } @Override @@ -167,7 +194,7 @@ public PrivateKey getPrivateKey(final String alias) { @Override public String[] getServerAliases(final String keyType, final Principal[] issuers) { - return new String[]{DEFAULT_ALIAS}; + return new String[] { DEFAULT_ALIAS }; } }