From 3282254ecf608ffaed468177f46a48c7b5afd8b5 Mon Sep 17 00:00:00 2001 From: Matt Taylor Date: Fri, 15 Jun 2018 00:31:05 +0100 Subject: [PATCH 1/3] Support for specifying trust-store --- src/clj_http/lite/core.clj | 39 +++++++++++++++++++++++++++------- test-resources/README.org | 12 +++++++++++ test-resources/ca-cert.pem | 21 ++++++++++++++++++ test-resources/ca-cert.srl | 1 + test-resources/ca-key.pem | 30 ++++++++++++++++++++++++++ test-resources/keystore | Bin 1363 -> 0 bytes test-resources/keystore.jks | Bin 0 -> 3986 bytes test-resources/localhost.cer | 31 +++++++++++++++++++++++++++ test-resources/localhost.csr | 25 ++++++++++++++++++++++ test-resources/truststore.jks | Bin 0 -> 970 bytes test/clj_http/test/core.clj | 28 ++++++++++++++++++------ 11 files changed, 173 insertions(+), 14 deletions(-) create mode 100644 test-resources/README.org create mode 100644 test-resources/ca-cert.pem create mode 100644 test-resources/ca-cert.srl create mode 100644 test-resources/ca-key.pem delete mode 100644 test-resources/keystore create mode 100644 test-resources/keystore.jks create mode 100644 test-resources/localhost.cer create mode 100644 test-resources/localhost.csr create mode 100644 test-resources/truststore.jks diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 246d1d2f..0705140d 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -1,8 +1,10 @@ (ns clj-http.lite.core "Core HTTP request/response implementation." (:require [clojure.java.io :as io]) - (:import (java.io ByteArrayOutputStream InputStream IOException) - (java.net URI URL HttpURLConnection))) + (:import [java.io ByteArrayOutputStream InputStream IOException] + [java.net URI URL HttpURLConnection] + [javax.net.ssl HttpsURLConnection SSLContext TrustManagerFactory] + [java.security KeyStore])) (defn parse-headers "Takes a URLConnection and returns a map of names to values. @@ -39,6 +41,24 @@ (.flush baos) (.toByteArray baos))))) +(defn get-connection [url] + (.openConnection ^URL (URL. url))) + +(defn set-trust-store + [^HttpsURLConnection conn + {:keys [trust-store trust-store-pass trust-store-type security-protocol] + :or {trust-store-type "jks" security-protocol "TLS"}}] + (let [ssl-context (SSLContext/getInstance security-protocol) + key-store (KeyStore/getInstance trust-store-type) + trust-manager-factory (TrustManagerFactory/getInstance "SunX509")] + (.load key-store (io/input-stream + (or (io/resource trust-store) + (io/file trust-store))) + (char-array trust-store-pass)) + (.init trust-manager-factory key-store) + (.init ssl-context nil (.getTrustManagers trust-manager-factory) nil) + (.setSSLSocketFactory conn (.getSocketFactory ssl-context)))) + (defn request "Executes the HTTP request corresponding to the given Ring request map and returns the Ring response map corresponding to the resulting HTTP response. @@ -48,12 +68,15 @@ [{:keys [request-method scheme server-name server-port uri query-string headers content-type character-encoding body socket-timeout conn-timeout multipart debug insecure? save-request? follow-redirects - chunk-size] :as req}] + chunk-size trust-store trust-store-pass] :as req}] (let [http-url (str (name scheme) "://" server-name (when server-port (str ":" server-port)) uri (when query-string (str "?" query-string))) - conn (.openConnection ^URL (URL. http-url))] + ^HttpURLConnection conn + (cond-> (get-connection http-url) + (and (= scheme :https) trust-store trust-store-pass) + (set-trust-store req))] (when (and content-type character-encoding) (.setRequestProperty conn "Content-Type" (str content-type "; charset=" @@ -63,8 +86,8 @@ (doseq [[h v] headers] (.setRequestProperty conn h v)) (when (false? follow-redirects) - (.setInstanceFollowRedirects ^HttpURLConnection conn false)) - (.setRequestMethod ^HttpURLConnection conn (.toUpperCase (name request-method))) + (.setInstanceFollowRedirects conn false)) + (.setRequestMethod conn (.toUpperCase (name request-method))) (when body (.setDoOutput conn true)) (when socket-timeout @@ -78,9 +101,9 @@ (with-open [out (.getOutputStream conn)] (io/copy body out))) (merge {:headers (parse-headers conn) - :status (.getResponseCode ^HttpURLConnection conn) + :status (.getResponseCode conn) :body (when-not (= request-method :head) (coerce-body-entity req conn))} (when save-request? {:request (assoc (dissoc req :save-request?) - :http-url http-url)})))) + :http-url http-url)})))) diff --git a/test-resources/README.org b/test-resources/README.org new file mode 100644 index 00000000..5fc9d063 --- /dev/null +++ b/test-resources/README.org @@ -0,0 +1,12 @@ +* Generate CA and import into keystore and truststore +openssl req -new -x509 -keyout ca-key.pem -out ca-cert.pem -days 3650 +keytool -import -keystore truststore.jks -file ca-cert.pem +keytool -import -keystore keystore.jks -file ca-cert.pem + +* Generate key and CSR for server (Jetty running on localhost) +keytool -keystore keystore.jks -genkey -alias localhost +keytool -keystore keystore.jks -certreq -alias localhost -keyalg rsa -file localhost.csr + +* Sign CSR with CA cert and import into keystore +openssl x509 -req -CA ca-cert.pem -CAkey ca-key.pem -in localhost.csr -out localhost.cer -days 3650 -CAcreateserial +keytool -import -keystore keystore.jks -file localhost.cer -alias localhost diff --git a/test-resources/ca-cert.pem b/test-resources/ca-cert.pem new file mode 100644 index 00000000..30561159 --- /dev/null +++ b/test-resources/ca-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDiDCCAnCgAwIBAgIJANa5pPKrnuBoMA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA2MTQyMjM4 +MjRaFw0yODA2MTEyMjM4MjRaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l +LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV +BAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMtf +R79GuNTxPZcISS/iSSC0ejkUAhSysQb0a3zSvKCGZmxFtV0LtgIQFS/KlyTIKokr +BIV5ToOB6Zy7jc7bKoCaPvEPjT8i8rnjCUtFb+XFITdi0TI+macYb2/CCgrY7ePG +aewO+kK20eVeSjygPgi8svEsdVyIpH8PEuAxCdjsCo8F3EHQHhrokEqUh+rLA9AX +A0uhJAkiPUGdxozE5L68WrvUs8GD9I8QmCYBldhvjD5nI5NFVDF8yZduWX6NuX5g +1etxZ86ob1Tcy4BtVVYskCjHuT57mMFdspsC59cUiM1RUYOia/GkgDK38An2NJyN +OEr3MC77m1qP0XOvJ/0CAwEAAaNTMFEwHQYDVR0OBBYEFAvylOxjTNSDjCqBlncO +HBaDc5L5MB8GA1UdIwQYMBaAFAvylOxjTNSDjCqBlncOHBaDc5L5MA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFCVTNyT4RR64lEe03y487s8efyp +HX9kxbS2PyUx327PakqVhu/6EU1VWEI8FIwxFYQB+WpTjh5qB/8y1Y4TMWAD7VRH +MsVzf3k4Wf+jH0GaO9ZNI4NSXXlZHKjxCb+ahQOcnEFXRog6f1locJIcJlNZ6JEJ +Tncnehe5YH0YhBhRZuR46ACExMSjfF+6rymxJnQg1KkGQaA7ypu79PF9wcc/tzfR +RFMP8esEQARWDYQRuA9Ms2DDDYE5lZx0QYjh/ljnfNxmimmRtg7TFkpadkaAChHj +jEaoDHPe5y4ktrK6N5snKDX0XhLLTQptntYUOugT/NCylqaATRUQVTQNCSY= +-----END CERTIFICATE----- diff --git a/test-resources/ca-cert.srl b/test-resources/ca-cert.srl new file mode 100644 index 00000000..e629314c --- /dev/null +++ b/test-resources/ca-cert.srl @@ -0,0 +1 @@ +E9DE7EDC3590114D diff --git a/test-resources/ca-key.pem b/test-resources/ca-key.pem new file mode 100644 index 00000000..b84745d9 --- /dev/null +++ b/test-resources/ca-key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQILkQiXuciC7QCAggA +MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECBYw8AvZ5P56BIIEyB+Uh5zShr1o +fSL1oMlKOizKDkfNYNc2k/lV4I/X/vCARSAKa5/bU3dAh82p16Te3Z1N99X7LWTk +Bd2WrcIjZxm8fC20ew/zD4/fVKOI/t56WUV6tavNyEOfLhzgrtWv7eo5an65V1QW +eYS9syDCaHocQZzI96m+dyDKy7cJMUaVJIIlasGEuV0Lt2pkg6WfMHJbmd5wyqyM +/tsx8aIkZlDVvXdddI+OfQ7Pa0LlTqXfuYqmEuez4Uz6uP6EaRnOyXlbWhtJeMAG +NaRQ95Ew339k+4j2N/o45DLWXORiBZxCD0YmyioZiFEvA4BnzzJ/R2BtY7v3zj+X +S7puFG21Lwe2zb1PQoKljVeJVWwbCaOzL3E+oXHj7xz26OxYhGT6xn0YT6HJaOjE +1Np9Kv+UeZi+zw2C8s7ru1b0UaIoRpwNH4+d39N8lBEaBlW2byZ+hV51BwbnLVOs +t5G2P8ppKsg8hSlxAw6hgyiTqXvvo4BX1U9aBvznt8dUI35dzhBG4G0u3UrYLEw0 +eYMecbSR12xQ1kRf+gO+g1uxsMY5odnz9I0WhwVGzEyjKdAXdQf/xZOtb+A2bUZx +RO/Ir1qSr58A1kUOyTWhv4EWxhviStqc9P0jQlA0olkkkZ2OULlXKh49Qemukbms +Og6jHIAljsbh4hZfyKFSUJJGC3GftoaMYErLcGJw3BmEavZcFM1z4FWu6HoQ5nEP +aDtGf0/ZN653VE0YRlmjxL85o7V3ZkOGakdTZnNaFi8wEv0nMCq+DbN5LghWokyM +bSdus2hmZr2j7fScYvdh+TBAOO73+ziVVM34SHqmcUYuuH4vv94GJwYLo3LUbDLL +uIQFJmBXekVpZ3l3HqSge5JYMXQ5vM11cJpjFrnyCNDISnunGpfDc2TGn4/CRQ4v +1EjwZLoWiQBsiw3FnKCqSLtl6pHcyMgWS/wkeQqHOcOyK4bFKBhtfe/Yp/xsTLt5 +6n7Yo0VGe6qcRTA5H+fkMRzVlFmrmqB6eN9Md85YQ7bK6nfOg2jbUMejHJUTxPC3 +BhRq0rMQXDhHvdomzxijWSznwtZs31UiG3Zis52ua4/Ux3K1yTKXVbfWqBhMNuVW +r7pvsTuLh+cdZQe4dxQgZXTNdVqrKa3yE0h6zbhBPlV1PXGzbSw8RSK0wYhJr167 +MPN7S74YJTjV2ujhLD4cUEONACXbLI2FE3jx2lLKbFN/Ih421x1lJWtADWnT6CDB +19/kmNyI2bCkYGomoQ9qaVw7p7a0d9OV5VRXavEn7scAhOj4/cNrAukvedionpIx +autWzyZAyAOpmGCTtlRnImDBfs8tpWqf36qfAxIM3gZlKGB2cijNAKbYEld9XzFX +Kw0CWvZro3/QOkqabtcwvcoupxX2mZsju5uahlJwZ1xQFz4j6svtYwvpMRpySI+K +mzpRcDhNsY9vY3lKHHYw8ModxIZ1WlHz5xf9FsrQEsKpseZXy7ItxtIimu3saufj +6XHvQl4K88/W4d2Q+WoUIkhK1sU4mcad3WXjxhOEgboNqsV41U5QJTAYOTecdfTp +PcrHf/EFwwiePRruw90DiGB+fCqBGl5B3bpUORl0wjpSXHfxW3RBpA0KkXByeB4C +wm31ey9mnr8ylJ1p6chHog== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test-resources/keystore b/test-resources/keystore deleted file mode 100644 index 24b84f38c953e7c26637301bfa7819ab34610373..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1363 zcmezO_TO6u1_mY|W&~r_tkjZ{N+8eJ{e|~mpv*3VCZ=r$d~96WY>X_7T11b-`A(-*w&+%(NA3v(-0B%BPFVlI$ZQFHa&81LP5X33;&bG>e`_^erePi%9j z{HCqOw^&~D2-i>JytDsOlEbzsC5hJIyUc^dOu>8NLHP^z|^lNCdKG;^e0a`>1lLvZsMfk zjt#=R{bJ#2#XqK;j{SCX?w!M?d*`=a3yRg>JlFfmYLBG-wn|6qRxg%P=9Kg`TGCil z8?YwZ>c9Gd`93~<#oSw}z20wO&Dk*b#oN4sdlTN|ZJpZvqHRsX&c6(dypN7?#j;ts zoEO^h^XV}T=Nzp!O;6q(48Nrw_0041?T??I-@CBg|HR(i%*(a9K22xL`SIxT>kB^; z*(8)SZb;2uTKo95G5Z_S4NBK^&PP|jS!8QqTXXw~laVw_x?T&K^0>>?j$(`Exv%N{F8~v)KQ*Kgq&F zBUh;LW>=qWctWqvlK%|m*DY4IZn?@iLm}pzU;V#($1YlR?zztHe`SsQYv(_c_(T%} zTX>&8yIP(h-dv)2J+kVfN6x?7aN)JeUXv zh6p=`2p5J3H--o^T*N?5oY&CM(7?#Tz`)4J#4rlTH8LRad3UPqn$&+fkC$|G~Vb8){-WoSm#-%smEY%nBmB&oc@@V)Q>Qo|f2e%aRcS}y>*dUg@7*oi!ux*)|8?m& E00X%!egFUf diff --git a/test-resources/keystore.jks b/test-resources/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..053df1235172db6d5b802a68d4a279511b57836f GIT binary patch literal 3986 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 literal 0 HcmV?d00001 diff --git a/test-resources/localhost.cer b/test-resources/localhost.cer new file mode 100644 index 00000000..0f772f73 --- /dev/null +++ b/test-resources/localhost.cer @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYzCCBEsCCQDp3n7cNZARTTANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTgwNjE0MjI1NjIwWhcN +MjgwNjExMjI1NjIwWjBuMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtu +b3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQL +EwdVbmtub3duMRIwEAYDVQQDEwlsb2NhbGhvc3QwggNCMIICNQYHKoZIzjgEATCC +AigCggEBAI95Ndm5qum/q+2Ies9JUbbzLsWeO683GOjqxJYfPv02BudDUanEGDM5 +uAnnwq4cU5unR1uF0BGtuLR5h3VJhGlcrA6PFLM2CCiiL/onEQo9YqmTRTQJoP5p +bEZY+EvdIIGcNwmgEFexla3NACM9ulSEtikfnWSO+INEhneXnOwEtDSmrC516Zhd +4j2wKS/BEYyf+p2BgeczjbeStzDXueNJWS9oCZhyFTkV6j1ri0ZTxjNFj4A7MqTC +4PJykCVuTj+KOwg4ocRQ5OGMGimjfd9eoUPeS2b/BJA+1c8WI+FY1IfGCOl/IRzY +Hcojy244B2X4IuNCvkhMBXY5OWAc1mcCHQC69pamhXj3397n+mfJd8eF7zKyM7rl +gMC81WldAoIBABamXFggSFBwTnUCo5dXBA002jo0eMFU1OSlwC0kLuBPluYeS9CQ +Sr2sjzfuseCfMYLSPJBDy2QviABBYO35ygmzIHannDKmJ/JHPpGHm6LE50S9IIFU +TLVbgCw2jR+oPtSJ6U4PoGiOMkKKXHjEeMaNBSe3HJo6uwsL4SxEaJY559POdNsQ +GmWqK4f2TGgm2z7HL0tVmYNLtO2wL3yQ6aSW06VdU1vr/EXU9hn2Pz3tu4c5JcLy +JOB3MSltqIfsHkdI+H77X963VIQxayIy3uVT3a8CESsNHwLaMJcyJP4nrtqLnUsp +Itm6i+Oe2eEDpjxSgQvGiLfi7UMW4e8X294DggEFAAKCAQBj5iGy71+T7dyNUGYR +4tcboG43+q3i96dH+ft7opHNDBqPhAUo++YukC9Q9leMmyqjd8be5VGkPGxjePuS +wN6mQK2ilzAyTGUL2ICJdKE7U0b8AMy42rjoZVGwkRkpfahUkgfEB10TtS+AlbIZ +1azN98V+7yXwYPe1J5ioU9jDGMNC717ySBjORHIlOVmGOLK4Uylo2gW03he1nkAb +BxXoJATgV3VqwddJb5DMJoB0o5jwyMzL/cZHSABhukdrgK/KdAonVy0wzDQyScIj +3NIRCiDhFFGu0ZsruSG/vfNl1QLHToPzhgGIuGDO471hRP7Y1b/CE7eIzViyreTZ +LZW3MA0GCSqGSIb3DQEBCwUAA4IBAQB5cyUQA4maQogpheAwIsHD1R7TQFApu79N +1fKlvGGYutVo0EYv+FvIZsVmkoKKF725xXfjCfFOwIlGF6OrK/3xJNWBrSZr/jHs +1hOzdP0/Kmp63U2jfhBqn/7PiWYSvLUnwx7hj2qKhoGXhrXGTEs2kSyiRt92UFLM +9u+sajB2Wn0P3lxFHFI4Djv5uq4/Gb/Qjt2hJsB3W5yUdTgdpqyghDzrblXhrkhp +xQJhMb2pVLI7ZaJgBst0Ymllf4PHry1PF7WcgG0RlsTR8Xjh9YFcmnSAw2Hp/eDY +lsZBbkdZbjgqOifTGqBJ5RbTL3QFR3UFw3lMkTxDXYHzvwJ+iVhd +-----END CERTIFICATE----- diff --git a/test-resources/localhost.csr b/test-resources/localhost.csr new file mode 100644 index 00000000..e1f00dcf --- /dev/null +++ b/test-resources/localhost.csr @@ -0,0 +1,25 @@ +-----BEGIN NEW CERTIFICATE REQUEST----- +MIIEQDCCA+sCAQAwbjEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93 +bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMH +VW5rbm93bjESMBAGA1UEAxMJbG9jYWxob3N0MIIDQjCCAjUGByqGSM44BAEwggIo +AoIBAQCPeTXZuarpv6vtiHrPSVG28y7FnjuvNxjo6sSWHz79NgbnQ1GpxBgzObgJ +58KuHFObp0dbhdARrbi0eYd1SYRpXKwOjxSzNggooi/6JxEKPWKpk0U0CaD+aWxG +WPhL3SCBnDcJoBBXsZWtzQAjPbpUhLYpH51kjviDRIZ3l5zsBLQ0pqwudemYXeI9 +sCkvwRGMn/qdgYHnM423krcw17njSVkvaAmYchU5Feo9a4tGU8YzRY+AOzKkwuDy +cpAlbk4/ijsIOKHEUOThjBopo33fXqFD3ktm/wSQPtXPFiPhWNSHxgjpfyEc2B3K +I8tuOAdl+CLjQr5ITAV2OTlgHNZnAh0AuvaWpoV499/e5/pnyXfHhe8ysjO65YDA +vNVpXQKCAQAWplxYIEhQcE51AqOXVwQNNNo6NHjBVNTkpcAtJC7gT5bmHkvQkEq9 +rI837rHgnzGC0jyQQ8tkL4gAQWDt+coJsyB2p5wypifyRz6Rh5uixOdEvSCBVEy1 +W4AsNo0fqD7UielOD6BojjJCilx4xHjGjQUntxyaOrsLC+EsRGiWOefTznTbEBpl +qiuH9kxoJts+xy9LVZmDS7TtsC98kOmkltOlXVNb6/xF1PYZ9j897buHOSXC8iTg +dzEpbaiH7B5HSPh++1/et1SEMWsiMt7lU92vAhErDR8C2jCXMiT+J67ai51LKSLZ +uovjntnhA6Y8UoELxoi34u1DFuHvF9veA4IBBQACggEAY+Yhsu9fk+3cjVBmEeLX +G6BuN/qt4venR/n7e6KRzQwaj4QFKPvmLpAvUPZXjJsqo3fG3uVRpDxsY3j7ksDe +pkCtopcwMkxlC9iAiXShO1NG/ADMuNq46GVRsJEZKX2oVJIHxAddE7UvgJWyGdWs +zffFfu8l8GD3tSeYqFPYwxjDQu9e8kgYzkRyJTlZhjiyuFMpaNoFtN4XtZ5AGwcV +6CQE4Fd1asHXSW+QzCaAdKOY8MjMy/3GR0gAYbpHa4CvynQKJ1ctMMw0MknCI9zS +EQog4RRRrtGbK7khv73zZdUCx06D84YBiLhgzuO9YUT+2NW/whO3iM1Ysq3k2S2V +t6AwMC4GCSqGSIb3DQEJDjEhMB8wHQYDVR0OBBYEFP+8yPg7WQpeC6R7LxYkW/FW +C21UMA0GCWCGSAFlAwQDAgUAA0AAMD0CHBBBmwajAf0D5p7cRxAj4iq/DUTMOyBu +JZBDhcQCHQCcd1nksVdQIHO7f27vJ4u0nC/1gm6IBuwhnocn +-----END NEW CERTIFICATE REQUEST----- diff --git a/test-resources/truststore.jks b/test-resources/truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..34cdefc34c58d3954f77ee60e1277d16c456260a GIT binary patch literal 970 zcmezO_TO6u1_mY|W(3o$xs}l3J9PTA~o1nUbDaQmhbAQmNoml42-iAOKRr%)^Mn2$*#GyXF*$9j_cM~?rls0qWY(% ztDMm4)Mja|^lNT>IcIn8x!YO|v+O?d_u4Cc+WDB%+cp2`QAP8li$-=cmrLa5AL8P= z@%Hht%r|_$oVHzj8s}xRz>Z_jrjI(MF&#_l`Gp=Ba^85u)z5mz@q(PxiwRy++FzY! zz97!*y-Wro2h^xzgOD)i|x3Pe!b{ zc+yXB#LFtPNEnDUU{}Bo(l5-&_@9Nj zdACjFpOv!pDMz<#vsX2|pLagXYiis3UxL1&5l%KDJ%*w!j6bu2`{c6N{~KNH6E;j> zejDO$bhNm>(jxNzVtL0|*4KQMn}cF2BV|^6yd2>-dTY1*;|Ur~Wj6JAcWh6&}&zGrvu RoOrdjcd|v&Th|_GUI3c1V>$o; literal 0 HcmV?d00001 diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index 66bb778f..f6b0ab08 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -138,19 +138,35 @@ (deftest ^{:integration true} self-signed-ssl-get (let [t (doto (Thread. #(ring/run-jetty handler {:port 8081 :ssl-port 18082 :ssl? true - :keystore "test-resources/keystore" - :key-password "keykey"})) .start)] + :keystore "test-resources/keystore.jks" + :key-password "changeit"})) .start)] (Thread/sleep 1000) (try (is (thrown? javax.net.ssl.SSLException (request {:request-method :get :uri "/get" :server-port 18082 :scheme :https}))) #_(let [resp (request {:request-method :get :uri "/get" :server-port 18082 - :scheme :https :insecure? true})] - (is (= 200 (:status resp))) - (is (= "get" (slurp-body resp)))) + :scheme :https :insecure? true})] + (is (= 200 (:status resp))) + (is (= "get" (slurp-body resp)))) (finally - (.stop t))))) + (.stop t))))) + +(deftest ^{:integration true} self-signed-ssl-get-with-trust-store + (let [t (doto (Thread. #(ring/run-jetty handler + {:port 8082 :ssl-port 18083 :ssl? true + :keystore "test-resources/keystore.jks" + :key-password "changeit"})) .start)] + (Thread/sleep 1000) + (try + (let [resp (request {:request-method :get :uri "/get" :server-port 18083 + :scheme :https + :trust-store "truststore.jks" + :trust-store-pass "changeit"})] + (is (= 200 (:status resp))) + (is (= "get" (slurp-body resp)))) + (finally + (.stop t))))) ;; (deftest ^{:integration true} multipart-form-uploads ;; (run-server) From 4483b7bcd68b4fbc0995dacea96705b31f36bc83 Mon Sep 17 00:00:00 2001 From: Matt Taylor Date: Fri, 15 Jun 2018 10:52:17 +0100 Subject: [PATCH 2/3] Fix integration test --- src/clj_http/lite/core.clj | 3 ++- test/clj_http/test/core.clj | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 0705140d..183f7011 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -57,7 +57,8 @@ (char-array trust-store-pass)) (.init trust-manager-factory key-store) (.init ssl-context nil (.getTrustManagers trust-manager-factory) nil) - (.setSSLSocketFactory conn (.getSocketFactory ssl-context)))) + (.setSSLSocketFactory conn (.getSocketFactory ssl-context)) + conn)) (defn request "Executes the HTTP request corresponding to the given Ring request map and diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index f6b0ab08..8948fc67 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -161,7 +161,7 @@ (try (let [resp (request {:request-method :get :uri "/get" :server-port 18083 :scheme :https - :trust-store "truststore.jks" + :trust-store "test-resources/truststore.jks" :trust-store-pass "changeit"})] (is (= 200 (:status resp))) (is (= "get" (slurp-body resp)))) From 060fe406119b226ea74c5ecd1503764c9570a37e Mon Sep 17 00:00:00 2001 From: Matt Taylor Date: Fri, 15 Jun 2018 10:59:16 +0100 Subject: [PATCH 3/3] Documentation for trust store --- Readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Readme.md b/Readme.md index 10c9a78d..9043e949 100644 --- a/Readme.md +++ b/Readme.md @@ -65,6 +65,12 @@ More example requests: ;; Need to contact a server with an untrusted SSL cert? (client/get "https://alioth.debian.org" {:insecure? true}) +;; Need to specify a trust store? +(client/get "https://my.corp.com" {:trust-store "/path/to/trust-store.jks" + :trust-store-type "jks" ; default jks + :trust-store-pass "trustpass" + :security-protocol "TLS" ; default TLS}) + ;; If you don't want to follow-redirects automatically: (client/get "http://site.come/redirects-somewhere" {:follow-redirects false})