Merge pull request #4 from cprice404/feature/master/PE-3484-support-sslcontext-with-ca-cert-only

Support SSLContext configured with only CA cert
This commit is contained in:
Kevin Corcoran 2014-04-14 12:29:33 -07:00
commit b39f17e536
6 changed files with 105 additions and 4 deletions

View file

@ -8,7 +8,7 @@
:dependencies [[org.clojure/clojure "1.5.1"]
[http-kit "2.1.16"]
[puppetlabs/certificate-authority "0.1.3"]
[puppetlabs/certificate-authority "0.1.4"]
[org.clojure/tools.logging "0.2.6"]
[org.slf4j/slf4j-api "1.7.6"]]

View file

@ -28,6 +28,13 @@
(:ssl-ca-cert req)))
(dissoc :ssl-cert :ssl-key :ssl-ca-cert)))
(defn- initialize-ssl-context-from-ca-pem
[req]
(-> req
(assoc :ssl-context (ssl/ca-cert-pem->ssl-context
(:ssl-ca-cert req)))
(dissoc :ssl-ca-cert)))
(defn- configure-ssl-from-context
"Configures an SSLEngine in the request starting from an SSLContext"
[req]
@ -42,6 +49,13 @@
initialize-ssl-context-from-pems
configure-ssl-from-context))
(defn- configure-ssl-from-ca-pem
"Configures an SSLEngine in the request starting from a CA PEM file"
[req]
(-> req
initialize-ssl-context-from-ca-pem
configure-ssl-from-context))
(defn configure-ssl
"Configures a request map to have an SSLEngine. It will use an existing one
if already present, , then use an SSLContext (stored in :ssl-context) if
@ -53,6 +67,7 @@
(:sslengine req) req
(:ssl-context req) (configure-ssl-from-context req)
(every? (partial req) [:ssl-cert :ssl-key :ssl-ca-cert]) (configure-ssl-from-pems req)
(:ssl-ca-cert req) (configure-ssl-from-ca-pem req)
:else req))
(defn- check-url! [url]

View file

@ -0,0 +1,7 @@
package com.puppetlabs.http.client;
public class HttpClientException extends RuntimeException {
public HttpClientException(String msg, Throwable t) {
super(msg, t);
}
}

View file

@ -20,7 +20,7 @@ public class SyncHttpClient {
private static void logAndRethrow(String msg, Throwable t) {
LOGGER.error(msg, t);
throw new RuntimeException(msg, t);
throw new HttpClientException(msg, t);
}
private static RequestOptions configureSslFromContext(RequestOptions options) {
@ -68,6 +68,27 @@ public class SyncHttpClient {
return configureSslFromContext(options);
}
if (options.getSslCaCert() != null) {
try {
options.setSslContext(
CertificateAuthority.caCertPemToSSLContext(
new FileReader(options.getSslCaCert()))
);
} catch (KeyStoreException e) {
logAndRethrow("Error while configuring SSL", e);
} catch (CertificateException e) {
logAndRethrow("Error while configuring SSL", e);
} catch (IOException e) {
logAndRethrow("Error while configuring SSL", e);
} catch (NoSuchAlgorithmException e) {
logAndRethrow("Error while configuring SSL", e);
} catch (KeyManagementException e) {
logAndRethrow("Error while configuring SSL", e);
}
options.setSslCaCert(null);
return configureSslFromContext(options);
}
return options;
}

View file

@ -21,6 +21,16 @@
(is (not (:ssl-key configured-req)))
(is (not (:ssl-ca-cert configured-req))))))
(deftest ssl-config-with-ca-file
(let [req {:ssl-ca-cert (resource "ssl/ca.pem")}
configured-req (http/configure-ssl req)]
(testing "configure-ssl sets up an SSLEngine when given ca-cert"
(is (instance? SSLEngine (:sslengine configured-req))))
(testing "removes ssl-ca-cert"
(is (not (:ssl-ca-cert configured-req))))))
(deftest ssl-config-without-ssl-params
(let [req {:url "http://localhost"
:method :get}

View file

@ -1,5 +1,7 @@
(ns puppetlabs.http.client.sync-test
(:import (com.puppetlabs.http.client SyncHttpClient RequestOptions))
(:import (com.puppetlabs.http.client SyncHttpClient RequestOptions
HttpClientException)
(javax.net.ssl SSLHandshakeException))
(:require [clojure.test :refer :all]
[puppetlabs.trapperkeeper.core :as tk]
[puppetlabs.trapperkeeper.testutils.bootstrap :as testutils]
@ -18,7 +20,7 @@
(add-ring-handler app "/hello")
context))
(deftest sync-client-test
(deftest sync-client-test-from-pems
(testlogging/with-test-logging
(testutils/with-app-with-config app
[jetty9/jetty9-service test-web-service]
@ -42,3 +44,49 @@
:ssl-ca-cert "./dev-resources/ssl/ca.pem"})]
(is (= 200 (:status response)))
(is (= "Hello, World!" (slurp (:body response)))))))))
(deftest sync-client-test-from-ca-cert
(testlogging/with-test-logging
(testutils/with-app-with-config app
[jetty9/jetty9-service test-web-service]
{:webserver {:ssl-host "0.0.0.0"
:ssl-port 10080
:ssl-ca-cert "./dev-resources/ssl/ca.pem"
:ssl-cert "./dev-resources/ssl/cert.pem"
:ssl-key "./dev-resources/ssl/key.pem"
:client-auth "want"}}
(testing "java sync client"
(let [options (.. (RequestOptions. "https://localhost:10080/hello/")
(setSslCaCert "./dev-resources/ssl/ca.pem"))
response (SyncHttpClient/get options)]
(is (= 200 (.getStatus response)))
(is (= "Hello, World!" (slurp (.getBody response))))))
(testing "clojure sync client"
(let [response (sync/get "https://localhost:10080/hello/"
{:ssl-ca-cert "./dev-resources/ssl/ca.pem"})]
(is (= 200 (:status response)))
(is (= "Hello, World!" (slurp (:body response)))))))))
(deftest sync-client-test-with-invalid-ca-cert
(testlogging/with-test-logging
(testutils/with-app-with-config app
[jetty9/jetty9-service test-web-service]
{:webserver {:ssl-host "0.0.0.0"
:ssl-port 10081
:ssl-ca-cert "./dev-resources/ssl/ca.pem"
:ssl-cert "./dev-resources/ssl/cert.pem"
:ssl-key "./dev-resources/ssl/key.pem"
:client-auth "want"}}
(testing "java sync client"
(let [options (.. (RequestOptions. "https://localhost:10081/hello/")
(setSslCaCert "./dev-resources/ssl/alternate-ca.pem"))]
(try
(SyncHttpClient/get options)
; fail if we don't get an exception
(is (not true) "expected HttpClientException")
(catch HttpClientException e
(is (instance? SSLHandshakeException (.getCause e)))))))
(testing "clojure sync client"
(is (thrown? SSLHandshakeException
(sync/get "https://localhost:10081/hello/"
{:ssl-ca-cert "./dev-resources/ssl/alternate-ca.pem"})))))))