Skip to content

Commit

Permalink
Added test case for Docker EE client bundle using the EC algo and PR …
Browse files Browse the repository at this point in the history
…fixes for spotify#887
  • Loading branch information
Christoffer Soop committed May 30, 2018
1 parent 68e67ea commit 3b88da4
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 10 deletions.
21 changes: 17 additions & 4 deletions src/main/java/com/spotify/docker/client/DockerCertificates.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package com.spotify.docker.client;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.spotify.docker.client.exceptions.DockerCertificateException;

import java.io.BufferedReader;
Expand All @@ -44,6 +45,7 @@
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
Expand All @@ -62,11 +64,13 @@
*/
public class DockerCertificates implements DockerCertificatesStore {


public static final String DEFAULT_CA_CERT_NAME = "ca.pem";
public static final String DEFAULT_CLIENT_CERT_NAME = "cert.pem";
public static final String DEFAULT_CLIENT_KEY_NAME = "key.pem";

private static final char[] KEY_STORE_PASSWORD = "docker!!11!!one!".toCharArray();
private static final Set<String> PRIVATE_KEY_ALGS = ImmutableSet.of("RSA", "EC");
private static final Logger log = LoggerFactory.getLogger(DockerCertificates.class);

private final SSLContext sslContext;
Expand Down Expand Up @@ -143,12 +147,12 @@ private PrivateKey readPrivateKey(Path file) throws IOException, InvalidKeySpecE
}

private static PrivateKey generatePrivateKey(PrivateKeyInfo privateKeyInfo) throws IOException,
InvalidKeySpecException, NoSuchAlgorithmException {
InvalidKeySpecException {
final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded());
return tryGeneratePrivateKey(spec, "RSA", "EC");
return tryGeneratePrivateKey(spec, PRIVATE_KEY_ALGS);
}

private static PrivateKey tryGeneratePrivateKey(PKCS8EncodedKeySpec spec, String... algorithms)
private static PrivateKey tryGeneratePrivateKey(PKCS8EncodedKeySpec spec, Set<String> algorithms)
throws InvalidKeySpecException {

KeyFactory kf;
Expand All @@ -164,7 +168,16 @@ private static PrivateKey tryGeneratePrivateKey(PKCS8EncodedKeySpec spec, String
}
}

throw new InvalidKeySpecException("Could not generate private key from spec");
// Would love to use String.join or the streams API but given that legacy Java support is required here goes...
StringBuilder error = new StringBuilder("Could not generate private key from spec; tried using the [");
String delimeter = "";
for(String algorithm : algorithms) {
error.append(delimeter);
error.append(algorithm);
delimeter = ", ";
}
error.append("] algorithms");
throw new InvalidKeySpecException(error.toString());
}

private List<Certificate> readCertificates(Path file) throws CertificateException, IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@

package com.spotify.docker.client;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import com.google.common.base.Optional;
import com.google.common.io.Resources;
import com.spotify.docker.client.DockerCertificates.SslContextFactory;
Expand All @@ -39,6 +33,12 @@
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class DockerCertificatesTest {

private SslContextFactory factory = mock(SslContextFactory.class);
Expand Down Expand Up @@ -137,10 +137,29 @@ public void testReadPrivateKeyPkcs8() throws Exception {
assertNotNull(pkEntry.getPrivateKey());
}

@Test
public void testReadDockerEEClientBundle() throws Exception {
Optional<DockerCertificatesStore> store = DockerCertificates.builder()
.dockerCertPath(getDockerEEClientBundlePath())
.sslFactory(factory)
.build();

verify(factory).newSslContext(keyStore.capture(), password.capture(), trustStore.capture());

final KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getValue()
.getEntry("key", new KeyStore.PasswordProtection(password.getValue()));

assertNotNull(pkEntry.getPrivateKey());
}

private Path getResourceFile(String path) throws URISyntaxException {
return Paths.get(Resources.getResource(path).toURI());
}

private Path getDockerEEClientBundlePath() throws URISyntaxException {
return getResourceFile("dockerSslDirectory");
}

private Path getCertPath() throws URISyntaxException {
return getResourceFile("dockerSslDirectory");
}
Expand Down
21 changes: 21 additions & 0 deletions src/test/resources/dockerEEClientBundle/ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIBgTCCASegAwIBAgIUSDpwT90Xy4XatwFHXuyazJQNEf4wCgYIKoZIzj0EAwIw
HTEbMBkGA1UEAxMSVUNQIENsaWVudCBSb290IENBMB4XDTE4MDIyMjEwMjIwMFoX
DTIzMDIyMTEwMjIwMFowHTEbMBkGA1UEAxMSVUNQIENsaWVudCBSb290IENBMFkw
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7/PN6GE2k0y3927Y2cZpV29o4vwvRqVp
hbjRBDqDrbEDNQ2iObGTI0h2N3AedH8ID9YtzrkIlIyQrRqBiYeDUqNFMEMwDgYD
VR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFLW4zQYH
RlnC2+K+yJUUmm8HK6oNMAoGCCqGSM49BAMCA0gAMEUCIQDv+a4ZccY7eAKZ6Uv9
8iYt/It0oi8/yKjwvcj+xq4cWAIgOoG5nUw+kJgdeKWh2ykeKkr8W35YKPVUgLLT
Dly4Dgg=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBajCCARCgAwIBAgIUM9oWZbj9B/Zn+nMRW/ZSby3kCY4wCgYIKoZIzj0EAwIw
EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTgwMjIyMTAyMjAwWhcNMzgwMjE3MTAy
MjAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABHB576n29gJNGxzciJBM8bpltIaCJGR91AlKVcQOJiXcqzS1l69Ypy2bkBpG
Q+OGFFxLMm4LwQ9gEXWn8pWD4LOjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBSrjMUwJK/LbbGGvtw9lSdU2ee1fTAKBggqhkjO
PQQDAgNIADBFAiEAuZITvKIFBc0qgxDmXglz+NSqBTqhLum6RMAjGbX7EZYCICXq
T4LPHVlg7FCJlK5jdGvHXKCK0iD9SJDFY6nac74S
-----END CERTIFICATE-----
13 changes: 13 additions & 0 deletions src/test/resources/dockerEEClientBundle/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIICBjCCAaugAwIBAgIUNKAK+kxeV1WQ2f14p2XZ9lDLToYwCgYIKoZIzj0EAwIw
EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTgwNDAxMTE1MjAwWhcNMjgwMzI5MTE1
MjAwWjBsMQkwBwYDVQQGEwAxCTAHBgNVBAgTADEJMAcGA1UEBxMAMSgwJgYDVQQK
Ex9PcmNhOiAzenhyMmVkNWdncm1qN2c0a3Vzd29pbm9iMQ8wDQYDVQQLEwZDbGll
bnQxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4E38
k2IT/7YDQ1xJz7AKqtFej9kiNZGktrYdXRKaDHnrwwKHrZPIn2B1QWsJkbEc2GPN
E4PQvjT6z9m0n3ibX6OBgzCBgDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI
KwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUYUZw4IfDSxvF7RMMUNNz
oZGNGg8wHwYDVR0jBBgwFoAUq4zFMCSvy22xhr7cPZUnVNnntX0wCwYDVR0RBAQw
AoEAMAoGCCqGSM49BAMCA0kAMEYCIQDx+3BtBxIFtz/l2JNbbp/UmSH3ki70lJbB
ot8exwXWXwIhAOiiZ2hlAPcPE1x3tNUpTmSemvGog5M8hyePWtviq+qy
-----END CERTIFICATE-----
4 changes: 4 additions & 0 deletions src/test/resources/dockerEEClientBundle/cert.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4E38k2IT/7YDQ1xJz7AKqtFej9ki
NZGktrYdXRKaDHnrwwKHrZPIn2B1QWsJkbEc2GPNE4PQvjT6z9m0n3ibXw==
-----END PUBLIC KEY-----
15 changes: 15 additions & 0 deletions src/test/resources/dockerEEClientBundle/env.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@echo off
set DOCKER_TLS_VERIFY=1
set DOCKER_CERT_PATH=%~dp0
set DOCKER_HOST=tcp://127.0.0.1:443
REM
REM Bundle for user admin
REM UCP Instance ID REDACTED-REDACTED-REDACTED
REM
REM This admin cert will also work directly against Swarm and the individual
REM engine proxies for troubleshooting. After sourcing this env file, use
REM "docker info" to discover the location of Swarm managers and engines.
REM and use the --host option to override $DOCKER_HOST
REM
REM Run this command from within this directory to configure your shell:
REM .\env.cmd
14 changes: 14 additions & 0 deletions src/test/resources/dockerEEClientBundle/env.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$Env:DOCKER_TLS_VERIFY = "1"
$Env:DOCKER_CERT_PATH = $(Split-Path $script:MyInvocation.MyCommand.Path)
$Env:DOCKER_HOST = "tcp://10.236.0.33:443"
#
# Bundle for user admin
# UCP Instance ID 3zxr2ed5ggrmj7g4kuswoinob
#
# This admin cert will also work directly against Swarm and the individual
# engine proxies for troubleshooting. After sourcing this env file, use
# "docker info" to discover the location of Swarm managers and engines.
# and use the --host option to override $DOCKER_HOST
#
# Run this command from within this directory to configure your shell:
# Import-Module .\env.ps1
14 changes: 14 additions & 0 deletions src/test/resources/dockerEEClientBundle/env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH="$(pwd)"
export DOCKER_HOST=tcp://127.0.0.1:443
#
# Bundle for user admin
# UCP Instance ID REDACTED-REDACTED-REDACTED
#
# This admin cert will also work directly against Swarm and the individual
# engine proxies for troubleshooting. After sourcing this env file, use
# "docker info" to discover the location of Swarm managers and engines.
# and use the --host option to override $DOCKER_HOST
#
# Run this command from within this directory to configure your shell:
# eval $(<env.sh)
5 changes: 5 additions & 0 deletions src/test/resources/dockerEEClientBundle/key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIPiEL1Rb11CWgyr+e5KF2Gu4jh7QR2FywdHMGXnE5bvRoAoGCCqGSM49
AwEHoUQDQgAE4E38k2IT/7YDQ1xJz7AKqtFej9kiNZGktrYdXRKaDHnrwwKHrZPI
n2B1QWsJkbEc2GPNE4PQvjT6z9m0n3ibXw==
-----END EC PRIVATE KEY-----

0 comments on commit 3b88da4

Please sign in to comment.