Skip to content

Commit

Permalink
Fix Multiple CA in ca.crt file (#190)
Browse files Browse the repository at this point in the history
* Add HTTPS to WireMock tests
* Add support for multiple CA Certificates
* Rename `withCaCertificate` to `withCaCertificates`
  • Loading branch information
Rafał Leszko committed Jan 29, 2020
1 parent 4950faf commit e731619
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 20 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

<log4j.version>1.2.12</log4j.version>
<junit.version>4.12</junit.version>
<wiremock.version>2.18.0</wiremock.version>
<wiremock.version>2.25.1</wiremock.version>
<hamcrest.version>1.3</hamcrest.version>
<mockito.version>2.28.2</mockito.version>
<powermock.version>2.0.2</powermock.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ private JsonObject callGet(final String urlString) {
public JsonObject call() {
return Json
.parse(RestClient.create(urlString).withHeader("Authorization", String.format("Bearer %s", apiToken))
.withCaCertificate(caCertificate)
.withCaCertificates(caCertificate)
.get())
.asObject();
}
Expand Down
14 changes: 10 additions & 4 deletions src/main/java/com/hazelcast/kubernetes/RestClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Scanner;

Expand Down Expand Up @@ -69,7 +70,7 @@ RestClient withBody(String body) {
return this;
}

RestClient withCaCertificate(String caCertificate) {
RestClient withCaCertificates(String caCertificate) {
this.caCertificate = caCertificate;
return this;
}
Expand Down Expand Up @@ -175,7 +176,12 @@ private SSLSocketFactory buildSslSocketFactory() {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", generateCertificate());

int i = 0;
for (Certificate certificate : generateCertificates()) {
String alias = String.format("ca-%d", i++);
keyStore.setCertificateEntry(alias, certificate);
}

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
Expand All @@ -192,13 +198,13 @@ private SSLSocketFactory buildSslSocketFactory() {
/**
* Generates CA Certificate from the default CA Cert file or from the externally provided "ca-certificate" property.
*/
private Certificate generateCertificate()
private Collection<? extends Certificate> generateCertificates()
throws IOException, CertificateException {
InputStream caInput = null;
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
caInput = new ByteArrayInputStream(caCertificate.getBytes("UTF-8"));
return cf.generateCertificate(caInput);
return cf.generateCertificates(caInput);
} finally {
IOUtil.closeResource(caInput);
}
Expand Down
53 changes: 39 additions & 14 deletions src/test/java/com/hazelcast/kubernetes/RestClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@
import org.junit.Rule;
import org.junit.Test;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.io.File;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static com.hazelcast.kubernetes.KubernetesConfig.readFileContents;
import static org.junit.Assert.assertEquals;

public class RestClientTest {
Expand All @@ -52,13 +53,23 @@ public class RestClientTest {
private static final String BODY_RESPONSE = "some body response";

@Rule
public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort());
public WireMockRule wireMockRule = new WireMockRule(wireMockConfig()
.dynamicHttpsPort()
.keystorePath(pathTo("keystore.jks"))
);

private String address;

@Before
public void setUp() {
address = String.format("http://localhost:%s", wireMockRule.port());
// disable hostname HTTPS verification for testing
HttpsURLConnection.setDefaultHostnameVerifier(
new HostnameVerifier() {
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
});
address = String.format("https://localhost:%s", wireMockRule.httpsPort());
}

@Test
Expand All @@ -68,7 +79,9 @@ public void getSuccess() {
.willReturn(aResponse().withStatus(200).withBody(BODY_RESPONSE)));

// when
String result = RestClient.create(String.format("%s%s", address, API_ENDPOINT)).get();
String result = RestClient.create(String.format("%s%s", address, API_ENDPOINT))
.withCaCertificates(readFile("ca.crt"))
.get();

// then
assertEquals(BODY_RESPONSE, result);
Expand All @@ -85,8 +98,9 @@ public void getWithHeaderSuccess() {

// when
String result = RestClient.create(String.format("%s%s", address, API_ENDPOINT))
.withHeader(headerKey, headerValue)
.get();
.withHeader(headerKey, headerValue)
.withCaCertificates(readFile("ca.crt"))
.get();

// then
assertEquals(BODY_RESPONSE, result);
Expand All @@ -99,7 +113,9 @@ public void getFailure() {
.willReturn(aResponse().withStatus(500).withBody("Internal error")));

// when
RestClient.create(String.format("%s%s", address, API_ENDPOINT)).get();
RestClient.create(String.format("%s%s", address, API_ENDPOINT))
.withCaCertificates(readFile("ca.crt"))
.get();

// then
// throw exception
Expand All @@ -114,10 +130,19 @@ public void postSuccess() {

// when
String result = RestClient.create(String.format("%s%s", address, API_ENDPOINT))
.withBody(BODY_REQUEST)
.post();
.withBody(BODY_REQUEST)
.withCaCertificates(readFile("ca.crt"))
.post();

// then
assertEquals(BODY_RESPONSE, result);
}

private String readFile(String filename) {
return readFileContents(pathTo(filename));
}

private String pathTo(String filename) {
return new File(getClass().getClassLoader().getResource(filename).getFile()).getAbsolutePath();
}
}
58 changes: 58 additions & 0 deletions src/test/resources/ca.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
-----BEGIN CERTIFICATE-----
MIIDMjCCAhqgAwIBAgIIbACAU0ZsknAwDQYJKoZIhvcNAQELBQAwNzESMBAGA1UE
CxMJb3BlbnNoaWZ0MSEwHwYDVQQDExhrdWJlLWFwaXNlcnZlci1sYi1zaWduZXIw
HhcNMjAwMTIyMjE0MzE4WhcNMzAwMTE5MjE0MzE4WjA3MRIwEAYDVQQLEwlvcGVu
c2hpZnQxITAfBgNVBAMTGGt1YmUtYXBpc2VydmVyLWxiLXNpZ25lcjCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBANX8oMkxb4skmWGLXQxTbjYO50EZJ0uD
AgCQs/LDCWmNSbUdjUsCSLqQCadSEiH7f4VqtYyCfQMfcf3vtaebLL/qZ4RSQy67
xw6bYyN7Qh/ryNSPoczr0GXkrho4CYehRfnLaehUj6bGRe0Rhz5gisRMQ3jftKRj
rY0FP18R4kbSyMVDZWtc82WGTUxXc2gyklTWzPUVLihHAJw/ip39TmmewvYqCYhh
GGAZDbKVfVzZ9145/9K0EbVBRDn6lAWfh/44yrWy9cZAUidXFxLTo2YWoNzb5QJn
YPt/EXhaANS3E5SPgQrlZsbxXKMfACTPWc2Y9Wb4ES89NNP1bl4DC4sCAwEAAaNC
MEAwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJWe
blS+7Fg7apqyu3sMraGZ34OoMA0GCSqGSIb3DQEBCwUAA4IBAQCu3BbKy3H85zEY
hJTmCsRd4ZUyFjQd2D4Z0bZjdprbrW83P7UoHSA3giebvABrIzdrSANTfRLYTXCT
LuxBwcY9IabxggL9Ki8p80NoKC4sWwLO3qFLGNFUTCOVU7gl7RHaHLVpHUoGFRh1
kFPWnGnH1RniuY0vte8dYbUgKCzHdOW70ZdfxADwVwj1G31/KO93yO3BbX7d8IYa
mDvHco/FQWxDK1MigAOCRBpPAEdj+wz1DfnCx9ZqVy5AV1XChoEkK1ZROzHIH+mc
u5HFZn0ce0++aTZfnYVja7hGaFVf5rGi5i2NnACYbtT7rCXq9y/CsMb78HRly/En
adDce2Y3
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
MIICeDCCAeGgAwIBAgIECFbWTjANBgkqhkiG9w0BAQsFADBuMRAwDgYDVQQGEwdV
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRIwEAYDVQQDEwlsb2NhbGhv
c3QwIBcNMjAwMTI4MTU1MDQ4WhgPMjEyMDAxMDQxNTUwNDhaMG4xEDAOBgNVBAYT
B1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vua25vd24xEDAO
BgNVBAoTB1Vua25vd24xEDAOBgNVBAsTB1Vua25vd24xEjAQBgNVBAMTCWxvY2Fs
aG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqUga3JPPycHEsHS7LCRi
zZ9nruarwTzKSGoLUtJEH5SgmFucK+cJs0SvXWVTJ4BRlsyOjHYxnJN1gBSbzLt9
MkaoxzYfqPoQYuePOjFiBsmbbLBEk4yZhUB/ik4yLzu/aGUwuyJQayMNo3Th1WQ4
3qxzSdWAASPgBenOugiWTFECAwEAAaMhMB8wHQYDVR0OBBYEFARNaKaAcaGEuezm
meCv76mqmPVdMA0GCSqGSIb3DQEBCwUAA4GBAGznOs7mw+Swnzy3jtmLms1ajRlb
qhCQtd3d/I5NJYpq7z8n/5fkNx1orLcQ1cLQpoHQ4TIKjlrOlJnDp0m3i3fFyLv3
/zguGfAg9Fh//uY2fqd1H0f6tCd4631rTqH1aN15OFfyRGIItxp2xO+NEl2yMyc8
CyJtWtjG31l3ayBB
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
MIIDQDCCAiigAwIBAgIIaDKbna6B3DMwDQYJKoZIhvcNAQELBQAwPjESMBAGA1UE
CxMJb3BlbnNoaWZ0MSgwJgYDVQQDEx9rdWJlLWFwaXNlcnZlci1sb2NhbGhvc3Qt
c2lnbmVyMB4XDTIwMDEyMjIxNDMxOFoXDTMwMDExOTIxNDMxOFowPjESMBAGA1UE
CxMJb3BlbnNoaWZ0MSgwJgYDVQQDEx9rdWJlLWFwaXNlcnZlci1sb2NhbGhvc3Qt
c2lnbmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApAxgtdFW7XX3
KPeWAIFK7+mT2YMRxZo/WEMVEU56duWQJQ5vSOr2nxvMvuvmTRbMDMouDk2xllsk
AkB8osibpH4onK44RNXROLylnsEvANv7UhN1vAIfB5G6eoR/Lh6HMaeL/7jMUyxY
bKjQgUqgtzaNunNfgrpgB6TN8Kl6PD0kN+/SXZF1+VBvoptei0utBa1PGbHmGSid
2dy96CUKnlJBISLwW4kPdI6j9bl8+wbf50YB4f5cyiaQY7AwhBwZX1QsZNy74mXw
wNdre8YZF7ZwVpJ1Is7khFduEL5ya6PaU7/wNo5oejwkQ+4hDSptVl5/n3gJDhgg
3JMxufArrwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAqQwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUmGd2zDD68DdK2qOvVaOdL7jRGacwDQYJKoZIhvcNAQELBQAD
ggEBAAejSalM9im0Q4BIXw1JBwVCXvkL9z1USE+wB2rf3oS/GScNnpP2eMTpSoF0
U1ZYoHn/ARKKQX8SLmBmgUjasi7ZTZPpESh+hyMvAVyp7F8a1y0DiL4UIAksds4h
8jiW98paKuhQR3wAX54Q9n48LvusrRQVdEWyXsH30S1FkMawuzZgh5G0DvpaNgpP
b0syMDonXJ2yOkAGCr3Cm7zfhbfX09hsgoWh8ynMahtE4vXEDE7k+S7Brukn7uac
G/mUQBQYIjzRKgzPN54H0tCfTj+vDRYw9JuKEYPjOfK1+udMVx3zO/TjlnjOpH73
phFZaYFEgK7MESMl9oqpHYe/GJQ=
-----END CERTIFICATE-----
Binary file added src/test/resources/keystore.jks
Binary file not shown.

0 comments on commit e731619

Please sign in to comment.