Support supplying key and certificate to Docker as data

This commit is contained in:
Andrew Donald Kennedy 2016-05-18 11:28:58 +01:00 committed by Andrea Turli
parent 42d0576aa9
commit 61fb3ec145
4 changed files with 67 additions and 26 deletions

View File

@ -38,6 +38,7 @@ import com.google.inject.Module;
public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
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 class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
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 @@ public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
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.21")
.defaultEndpoint("https://127.0.0.1:2376")

View File

@ -18,6 +18,7 @@ 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;
@ -26,22 +27,25 @@ 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;
import static org.jclouds.docker.suppliers.SSLContextBuilder.isClientKeyAndCertificateData;
@Singleton
public class DockerSSLContextSupplier implements Supplier<SSLContext> {
private final Supplier<Credentials> creds;
private final String caCertPath;
private final String caCertData;
@Inject
DockerSSLContextSupplier(@Provider Supplier<Credentials> creds, @Named(DockerApiMetadata.DOCKER_CA_CERT_PATH) String caCertPath) {
DockerSSLContextSupplier(@Provider Supplier<Credentials> 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 class DockerSSLContextSupplier implements Supplier<SSLContext> {
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) {

View File

@ -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;
@ -30,6 +31,7 @@ import java.io.IOException;
import java.security.GeneralSecurityException;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.docker.suppliers.SSLContextBuilder.isClientKeyAndCertificateData;
@Singleton
public class DockerUntrustedSSLContextSupplier implements Supplier<SSLContext> {
@ -45,13 +47,13 @@ public class DockerUntrustedSSLContextSupplier implements Supplier<SSLContext> {
@Override
public SSLContext get() {
Credentials currentCreds = creds.get();
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
try {
SSLContextBuilder builder = new SSLContextBuilder();
// check if identity and credential are files, to set up sslContext
if (currentCreds != null && new File(currentCreds.identity).isFile()
&& new File(currentCreds.credential).isFile()) {
builder.clientKeyAndCertificate(currentCreds.credential, currentCreds.identity);
if (isClientKeyAndCertificateData(currentCreds.credential, currentCreds.identity)) {
builder.clientKeyAndCertificateData(currentCreds.credential, currentCreds.identity);
} else if (new File(currentCreds.identity).isFile() && new File(currentCreds.credential).isFile()) {
builder.clientKeyAndCertificatePaths(currentCreds.credential, currentCreds.identity);
}
builder.trustManager(insecureTrustManager);
return builder.build();

View File

@ -18,10 +18,13 @@ 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.crypto.Pems;
import org.jclouds.util.Closeables2;
import javax.net.ssl.KeyManager;
@ -29,6 +32,7 @@ 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;
@ -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 caCertificate(String caCertPath){
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 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 class SSLContextBuilder {
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 @@ public class SSLContextBuilder {
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 class SSLContextBuilder {
@Override
public String[] getServerAliases(final String keyType, final Principal[] issuers) {
return new String[]{DEFAULT_ALIAS};
return new String[] { DEFAULT_ALIAS };
}
}