diff --git a/Gemfile b/Gemfile index d40160a4..3899da04 100644 --- a/Gemfile +++ b/Gemfile @@ -21,3 +21,8 @@ end group :local_development do gem "pry-byebug" end + +group :test do + gem 'faraday', '~>2.0' + gem 'faraday-retry', '~>2.0' +end diff --git a/documentation/configuration.md b/documentation/configuration.md index a8964304..f6b0517e 100644 --- a/documentation/configuration.md +++ b/documentation/configuration.md @@ -7,6 +7,7 @@ * [log_dir](#log_dir) * [logger](#logger) * [logger.level](#loggerlevel) +* [SSL certificate](#SSL-Certificate) #### Consumer only configuration options * [pact_dir](#pact_dir) @@ -51,6 +52,14 @@ end Default value: `Logger::DEBUG` +### SSL Certificate + +To connect to a Pact Broker that uses custom SSL certificates, set the environment variable `$SSL_CERT_FILE` or `$SSL_CERT_DIR` to a path that contains the appropriate certificate. + +#### Using x509 Certificates + +To connect to a Pact Broker that uses x509 certificates for client authentication, set the environment variable `$X509_CLIENT_CERT_FILE` to the path of the client's x509 certificate and `$X509_CLIENT_KEY_FILE` to the path of the client's private key. + ### diff_formatter ```ruby @@ -184,7 +193,7 @@ To make modules available in the provider state set_up and tear_down blocks, inc Default value: `:recorded` Options: `:recorded`, `:random` -Replays interactions in a specific order. In combination with pactfile_write_order will allow you to have a consistent pact contract replayed in random order. +Replays interactions in a specific order. In combination with pactfile_write_order will allow you to have a consistent pact contract replayed in random order. ```ruby Pact.configure do | config | diff --git a/lib/pact/hal/http_client.rb b/lib/pact/hal/http_client.rb index 1e78b22d..fb0b1415 100644 --- a/lib/pact/hal/http_client.rb +++ b/lib/pact/hal/http_client.rb @@ -53,6 +53,12 @@ def perform_request request, uri http.use_ssl = (uri.scheme == 'https') http.ca_file = ENV['SSL_CERT_FILE'] if ENV['SSL_CERT_FILE'] && ENV['SSL_CERT_FILE'] != '' http.ca_path = ENV['SSL_CERT_DIR'] if ENV['SSL_CERT_DIR'] && ENV['SSL_CERT_DIR'] != '' + + if x509_certificate? + http.cert = OpenSSL::X509::Certificate.new(x509_client_cert_file) + http.key = OpenSSL::PKey::RSA.new(x509_client_key_file) + end + if disable_ssl_verification? if verbose? Pact.configuration.output_stream.puts("SSL verification is disabled") @@ -74,6 +80,19 @@ def verbose? verbose || ENV['VERBOSE'] == 'true' end + def x509_certificate? + ENV['X509_CLIENT_CERT_FILE'] && ENV['X509_CLIENT_CERT_FILE'] != '' && + ENV['X509_CLIENT_KEY_FILE'] && ENV['X509_CLIENT_KEY_FILE'] != '' + end + + def x509_client_cert_file + File.read(ENV['X509_CLIENT_CERT_FILE']) + end + + def x509_client_key_file + File.read(ENV['X509_CLIENT_KEY_FILE']) + end + def disable_ssl_verification? ENV['PACT_DISABLE_SSL_VERIFICATION'] == 'true' || ENV['PACT_BROKER_DISABLE_SSL_VERIFICATION'] == 'true' end diff --git a/spec/fixtures/certificates/ca_cert.pem b/spec/fixtures/certificates/ca_cert.pem new file mode 100644 index 00000000..ad49d99f --- /dev/null +++ b/spec/fixtures/certificates/ca_cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDATCCAemgAwIBAgIUWfQF2Mh+eFd3q+cSVgekpaMTh9MwDQYJKoZIhvcNAQEL +BQAwDzENMAsGA1UEAwwETXlDQTAgFw0yMzA5MTkxMTA2MjZaGA8yMTIzMDgyNjEx +MDYyNlowDzENMAsGA1UEAwwETXlDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAK9Qha2OdeFrSCUqiYRUBngNLn8PRGDaKPWmjd+3WOWJNM1RNgFfGpKY +nxYJp4J6eW7aeQ6o94Q+QOZp+Yxm6thrtvjRbcEafAore4EwC4tjXvoFoy+mKwzm +njlJw+ha3TsMAqD3GGDLF7uDnmliURRo8TOmJ++Mwss9Uhb5p9LArjWXa3sV8da+ +gsxP2aTgBZfznUhNKDGUfezYa5UEbHQ869rA1PAqL3tOC2M5LTX08C2PlzzLOF5S +gBzicV1PPDkmkbxKmFV+D8LmkwWNsRhrzZ6TIxYoXIRhziS7JuYOGU7G0+6ZKpIP +mo7WXSoSrd7GL5PQJzlHKCsTckd4so0CAwEAAaNTMFEwHQYDVR0OBBYEFCeovNXs +r1mcbprFaLyll+LrBJmQMB8GA1UdIwQYMBaAFCeovNXsr1mcbprFaLyll+LrBJmQ +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHOsbZ0iDiKiRU8Q +hIAav056dboPjTK19Q736DUD6oCbTbvecfxMv/wu9LmYGW5jt/DWP6s+jDYhcPpj +c3U03pPKCnvsG5z60ZgmNSqzyVAVPW17UVdw/ZnkKK/SFxYgYQaF/1g6opS2Zana +4aBGypqqGoD4KE+DAnRjuuCUpiz3zXwGd86auajY6soMlLNnVXteVa/whW6IZ84x +w4LISeMGUr+MXw9ye4WhcZYKZ4vwJdUYst2PA0pDuGwBDbGnrYloGm2BSpaHXUUo +XrwKFFkIxcK63IpAhoceTJpyfjI1BSmItfjEwToOUu6xDBsHLNiH6BKstSxk0DfX +01PHz2I= +-----END CERTIFICATE----- diff --git a/spec/fixtures/certificates/ca_cert.srl b/spec/fixtures/certificates/ca_cert.srl new file mode 100644 index 00000000..5a951072 --- /dev/null +++ b/spec/fixtures/certificates/ca_cert.srl @@ -0,0 +1 @@ +494F82D5FE5055D2C9C64941C421085B59521071 diff --git a/spec/fixtures/certificates/ca_key.pem b/spec/fixtures/certificates/ca_key.pem new file mode 100644 index 00000000..c29f42ee --- /dev/null +++ b/spec/fixtures/certificates/ca_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvUIWtjnXha0gl +KomEVAZ4DS5/D0Rg2ij1po3ft1jliTTNUTYBXxqSmJ8WCaeCenlu2nkOqPeEPkDm +afmMZurYa7b40W3BGnwKK3uBMAuLY176BaMvpisM5p45ScPoWt07DAKg9xhgyxe7 +g55pYlEUaPEzpifvjMLLPVIW+afSwK41l2t7FfHWvoLMT9mk4AWX851ITSgxlH3s +2GuVBGx0POvawNTwKi97TgtjOS019PAtj5c8yzheUoAc4nFdTzw5JpG8SphVfg/C +5pMFjbEYa82ekyMWKFyEYc4kuybmDhlOxtPumSqSD5qO1l0qEq3exi+T0Cc5Rygr +E3JHeLKNAgMBAAECggEAF2EHQqWB24V2rIYnVT9DUZUobdyiWMF0aYtEK4uuzjAQ +RjpzQkGQMJvWc0DnAW5wbTOzUHIrTTZkFJYYp6boiziUwPUPduCfnqznySBCxIbZ +mUFRNBSBHzT4mq6B8qV+D9bChFFkrdvHlsOu8gzLaouyxsQnWo8MlxU0B55UHrWc +nqIsPKVBeBtiF7c7eyZtpKmYgmWN8hnPzTZ2rtCL/BS3p2+/O+fFJKuul58Yo4t6 +bmMCPN5C6HxNhB6ADHm3lPVU3ap5g3a/4UHqVJ8c2SGKfAx6C1PgbajxiA74qMLS +YOhMXzc3jSLmakqvSmVhQFJhFt7drbbGtx4oD3+XPQKBgQDj1k7O2A0yJRQPtvQJ +A1m+H5fmynMnH6XuQuO8WzqCsDsE786EAG6AzY562SMEQrQ0zgpFx0A9ZmECNaOZ +28OnzcA5xGKQh5dD0ou9lvRHXEavu7fYCrAG+wlQTo1eRHUDOAN4pQPoZ9r3bz1M +tnGtG3rak4KemAsoX8aSy59ZswKBgQDE/C+eu012vzjyr2J1W0Gdms7fh5CWzMp8 +hCHk+kmLCY4DHIaUv0tT3IXGKebRH+PZObE3zZ5Hx2QXPjFQWsyTkd9D2tRIWHaZ +ZpKPBLxYJJuBc3YWZM1qC2ZcRyvv1NgtNUFpB5xOGIUL3/QsfcOE25kC7Z21aN+e +uXSi3CkivwKBgGFHSZLLcKbuaehjx0Jp6dFhj+v8mLolqyVV7gKoOQ0/zZNICLcX +sBbSrXkKaQcSq/q31m8Aqg8NPXJCEL5KtPlawi5oCWWIXy+YIA4s+9PUNGIoFlDq +D0qLuOhPAdE0DXn4WpMScd6zKSzolBXC+DpfN09IGEc6x9jPO+vFgR49AoGABPiw +YvsrK1IMJ+PRQlD5SPb9PZr4RTYJ7jaPfG3sqTumf+Gaa+qgBg/MuIGaN7DsWTEh +jdz8n6cimYuSRwrjmt3VmqrNLL4+0ARMsptV/Yt++TdmxY3puUFsZevN6hGfGxT6 +/6GXikkIIpKWYQETjCjWpcJFdqyc6C6aCPoxd5UCgYEA1B4AdDgxhZgXhz24sKM7 +aX2aY4glBsEZ7dxaqpqvwmsSshvdfudjuFxo5jjMKV2C9JmwrCGML9O6MvSP03n8 +B3R543JqKqWLTaSROHkcoil+LdIV9w7jrMBildOCHSDXwuM8Pl7YObIdKMq4pVwe +87n9/ZihlrKGaZ8utMrrGmc= +-----END PRIVATE KEY----- diff --git a/spec/fixtures/certificates/client_cert.pem b/spec/fixtures/certificates/client_cert.pem new file mode 100644 index 00000000..c97f425f --- /dev/null +++ b/spec/fixtures/certificates/client_cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICrDCCAZQCFElPgtX+UFXSycZJQcQhCFtZUhBxMA0GCSqGSIb3DQEBCwUAMA8x +DTALBgNVBAMMBE15Q0EwIBcNMjMwOTE5MTEwNzM1WhgPMjEyMzA4MjYxMTA3MzVa +MBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAJj6DF+bu0DhXmkBaC2+CkoqNlsO+LzW9bZnNCQk0Jw99fgCGTLifU3N +eyAhKgHs+V3G/9ULbMrxYMSQ/psrrXpS7FM9xtA0WZ0VAg7Oi4WEi+wueE0R1GmO +NMuCVT2JCYd5uDh8+mrWoVqb9L4xIsy0kaV0Nnl+NX1zDvHXUHzfo3T3roaxRbd6 +N92qNPzrj8TviwbapT0bo4GKwTCOO1ewPFGCjsWEeLZ4p2UfbOzW/zjIBEUD8Kqg +FOht48y9J6XG3Tb61/7neT0xj6E7cn6hGSzuiIM/oZbtuUt72VDgbLbOrS02oHTz +YmC9tVL35Qvfgzrqw0DEv7zpm/3iG0sCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA +nndLK/t6+dmoAwg4K7pdo8xqUEDnUx8K7sU2whZvLEUM+mO+jWOe3USHjR3aXYnU +OjNhN90/TAy5wlIK6U2C36nHyZJUeScxuiaVwErwayE+GgwYmw9R7HVofgcVfTve +IpjyrT7mDOCMYjkHgZv1dSHQTcc6uclaw7SgywEEjxjCNSJCN+WPjxCdcuno0td8 +i7F6FL7FeOiP1mtQrTo42Tq+knerUc55CbTW4anbQfL+6TFEVCPJKduLHFieGB0k +BFilUR3JD2t8/f4fIilQ6FrMZpUzKcLbgW9cjts8mxq0zNV+z6lISgKbdxZFQp+2 +fvyYdnoNLP0YeRI6j9x1pg== +-----END CERTIFICATE----- diff --git a/spec/fixtures/certificates/key.pem b/spec/fixtures/certificates/key.pem new file mode 100644 index 00000000..e0879e33 --- /dev/null +++ b/spec/fixtures/certificates/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCY+gxfm7tA4V5p +AWgtvgpKKjZbDvi81vW2ZzQkJNCcPfX4Ahky4n1NzXsgISoB7Pldxv/VC2zK8WDE +kP6bK616UuxTPcbQNFmdFQIOzouFhIvsLnhNEdRpjjTLglU9iQmHebg4fPpq1qFa +m/S+MSLMtJGldDZ5fjV9cw7x11B836N0966GsUW3ejfdqjT864/E74sG2qU9G6OB +isEwjjtXsDxRgo7FhHi2eKdlH2zs1v84yARFA/CqoBTobePMvSelxt02+tf+53k9 +MY+hO3J+oRks7oiDP6GW7blLe9lQ4Gy2zq0tNqB082JgvbVS9+UL34M66sNAxL+8 +6Zv94htLAgMBAAECggEAF2l9Z0yANgfH2S478XQ6Qut+8iSycMQ9SrM0yatQufjJ +ojFABgefwb6G733j3fOUnoOMN+DNv6l9c9f0/26J2ETEomC8ArVgWagTboyx0bdd +asIZ60GlTppS/ipuPUKx0KgSR6Lo+FzsyN9Bb7I5bzbba4UDqUhli1OGoACh8tpS +pyhD58C0nWBCYUjgkB2ilVoguQnnTvYC0VDbGOWK1P8bw0to810mkKTyv7ztifW2 +lHUwTe8vbQk7jY52+crvtgVZWNaXEdma3ivDSDHUjK3WLmPw9MFgVSMVYFLDZUQN +Btd7PyBSkjeHOzoS5b9l4qnjn2vhObpjrT5PZT6TMQKBgQDI+xrzk351kyqezHuZ +Bqo5CqEN3BHvwKALh3DA3uxHVaLqOo/yALv86yHgue/9ksaxxDwufAnVvcg5eEEh +XIsZrfKBIaNV5umqJAkbCbx4hVCX9mE45THv3Nc7XhiHuZZpUHb1i7qcab1lly5Y +7lFoCd5dCQJUoBf3/9Bw76OjRwKBgQDC2sba56V0dahFxTE3bOIRR2HIYWNfPv0a +7ejiNSHVHGTLrEfnya5ZcerT0j6QNA2IQcKw5ovPKn2xgjGlfPWgtBAz55r+lfU2 ++/6CRf8v6tu9FdPs7RDHxBuicOGQlQGSAH2+tfcY9ZCB8wcdGYB3v5ko0OFsFdZY ++fJOIt4h3QKBgByFJanzADsHC0FFmzR38afujjQ9Sn5PQ2bfbWyxNa5ZxKigbtTU +rdiSNViCij/dmDyZsECYcXzXVZZyLivhygt217bjYx5JilcOjgw8MXaY1Hr8B4ff +Xlq/Z/uQusJn36RKOtdVYMHZb3r/HSCZkQvGeruRD7eakEwtDRM5rmr5AoGAZFt9 +s90/ED5RDq5DbQJ9ZNzY9fWC0tmETsxd97PZ2wMmvufamPz8+UB86+ALLQZCOf10 +otv7AhYmarhdjZhQghZ7ieAtqhXeGBWtvbcDedCCoF6PqiVnURwmB4IQCwFTr7jl +CsZ5n7dKWEOtVEWALyzVW3pJv/t3TJhfPfMjaVkCgYAxmC4/jmBCLmQZ3eWbmZHx +X7N2qAI7Cu2JVi1Wut4WnBgFNynYH+kt67LZSQ9Jf9lHDnlBe5gOTvF5/8UeoTMv +MGI4R4WJ6ezWV12ugbmKAvzHB/SiJ9U0ph78ibejCxW3gomuDzY1T+xF56kCKXJ0 +uPaEN0rPMT6wMEegJHaE8A== +-----END PRIVATE KEY----- diff --git a/spec/fixtures/certificates/server.csr b/spec/fixtures/certificates/server.csr new file mode 100644 index 00000000..d8020bb5 --- /dev/null +++ b/spec/fixtures/certificates/server.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAmPoMX5u7QOFeaQFoLb4KSio2Ww74vNb1tmc0JCTQ +nD31+AIZMuJ9Tc17ICEqAez5Xcb/1QtsyvFgxJD+myutelLsUz3G0DRZnRUCDs6L +hYSL7C54TRHUaY40y4JVPYkJh3m4OHz6atahWpv0vjEizLSRpXQ2eX41fXMO8ddQ +fN+jdPeuhrFFt3o33ao0/OuPxO+LBtqlPRujgYrBMI47V7A8UYKOxYR4tninZR9s +7Nb/OMgERQPwqqAU6G3jzL0npcbdNvrX/ud5PTGPoTtyfqEZLO6Igz+hlu25S3vZ +UOBsts6tLTagdPNiYL21UvflC9+DOurDQMS/vOmb/eIbSwIDAQABoAAwDQYJKoZI +hvcNAQELBQADggEBAEz74PiDtYCL1XiZV4On0l5jRjBrKTVEAnjEtWgygy9V6U1d +BYE3AxwsdTUygl/cS2i3g8U2yZGQ1ZAh/qHq0sHB6TDePLmNSEiksP7KOJwXU9vO +/pCS9qbOYcWucLlQpnHxySpUlcxFWmrl33pMaNCzxxLN1q3eRbNmxoxACI/+vZsX +M6sm2fhhw6yZkU7D04BDgSwsddW8ApDqbtwbndyv/ZL13xjG9yow8noSF7uxGQnn +UnVFMGVGp3I6M/E3VFIwRvUYA1MJeqh9tLIEItlGmqkrQmxOnMvXKzJnQ9nK1KBq +2gaBXdvbabkXKAHnV0tYbDmZXvTO+7Ci7wgapNU= +-----END CERTIFICATE REQUEST----- diff --git a/spec/fixtures/certificates/unsigned_cert.pem b/spec/fixtures/certificates/unsigned_cert.pem new file mode 100644 index 00000000..ea787127 --- /dev/null +++ b/spec/fixtures/certificates/unsigned_cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCzCCAfOgAwIBAgIUN2/oKOttkdOretzyqc+Zv8IqpT8wDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIzMDkxOTExMjEzM1oYDzIxMjMw +ODI2MTEyMTMzWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQD30tqrKrHa0p1RsGlDc7lUUS/ZF2/7ZtNWe0gRuuum +6l/X5H8F+Ay1cO8DirGx3s/LPpj7DwvjjKo2eE+wcO2v/R5S+uPL4Bm0o+bPGwZP +vw+XMMgBZUsNSMER6DUliP5bHQ/8TCXWpfP3rLJ9QitOAX/rD9bVrOs3g3I0uf2A +RZ0O40//5q9fiXRC3PAfPbX7XdyI9Mr3duwmAW+nK2Gbd98ut27PkO0Fze27Xtk2 +EdIh3u5pajK/ub8rf5vyfk+c/6pcN9kMakPtlgIR/eqzTkfRWyIpMoFn/X8VumUQ +X4ylj1SfSs+K47GBjrqknEh1BYlblW8WKg5cUjx/r/b/AgMBAAGjUzBRMB0GA1Ud +DgQWBBQUEefafoC0qDhzThhEBMMwr/C5FTAfBgNVHSMEGDAWgBQUEefafoC0qDhz +ThhEBMMwr/C5FTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDn +dfkjZtgSdbsEPhUMfUlhZWXqxtLDQBoxM7xF+i5WC6w3yHpN/teA8SqA8CYiPb9d +5rNfnmJLP4PeyfTu6Pc0EJpQsmK19i9z0FPrA7bqPIzgF4U4R1eQ5mvTzlNoGkp3 +1gnjDdwtTq0RFfuvHKm5EqECKX+hBEJKMiviEH/mGqQuoycpKifZ5WRTQonnWjGe +BVkhdn4Psp83EWdnD/yQbo1XEbYRtsaPM4Dozr6uKbeq9Zbu+xDO9Uw4mTE/WSfb +t4AXqOLDRafOP9w3twlFH2ZQxqpSaqXo8z1RkS9jtCm69JcDnsePKqkhesToMZAz +2cylIQmuuNIRGLmCRsVK +-----END CERTIFICATE----- diff --git a/spec/fixtures/certificates/unsigned_key.pem b/spec/fixtures/certificates/unsigned_key.pem new file mode 100644 index 00000000..c7fab0c3 --- /dev/null +++ b/spec/fixtures/certificates/unsigned_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD30tqrKrHa0p1R +sGlDc7lUUS/ZF2/7ZtNWe0gRuuum6l/X5H8F+Ay1cO8DirGx3s/LPpj7DwvjjKo2 +eE+wcO2v/R5S+uPL4Bm0o+bPGwZPvw+XMMgBZUsNSMER6DUliP5bHQ/8TCXWpfP3 +rLJ9QitOAX/rD9bVrOs3g3I0uf2ARZ0O40//5q9fiXRC3PAfPbX7XdyI9Mr3duwm +AW+nK2Gbd98ut27PkO0Fze27Xtk2EdIh3u5pajK/ub8rf5vyfk+c/6pcN9kMakPt +lgIR/eqzTkfRWyIpMoFn/X8VumUQX4ylj1SfSs+K47GBjrqknEh1BYlblW8WKg5c +Ujx/r/b/AgMBAAECggEAR4aYzBwndvOgqioTR3+H9tjzyWFlVZbo2iX8t/lN+D/e +562wJ6Xe7SMqKMiH3sFjEdMATj2afdNkcRIqVc9SGqAgd2yoAHiukp9Xh2DSYoPP +WSCgKR72GWBtMODnLe0rFFr/+R51MU12a35xiYtmej4ekFZi+ArPXJdYh/VCQBnG +BGF+EnUJqCAOXLz9zG3FoYVBWu071vEnpBtfblbHYfY2/o5CSoORkxcput6XDHxO +7pOXN7IRt7DJZ0goda3OwZQ9suKyTLcOxa8cA+DteVP6cvh4u2l+ZMxUIYK5B1eh +VAmJkIbcbAaz/SxyO9E2gWraz+pu6ArOGY/0krcBmQKBgQD9BlVtx7QTVzu+nLzF +2++cB0LTsTD9T9rlMfIuQMBIOywmsivyvUDr9SjOPqICQUIRufHKqCgHs4TH7Ifs +4AxyUEwQMG4xuYh3nU5eZlpUEjzUWbbe7o0NjhaJ4ZlUBvzHBcgptUlKTwvwamMs +pnzQxWlFXFuh+pxPPdSXZVmWJQKBgQD6vN0pO/xc3bAqHSCavX95NBjUhFvkAsoo +T8tfv2qoAN8RhI2/N8prix6tJk3AdhzdLmmMktv3MBDXd3cgLgmXQTYHIijWXPlF +/WXWmZXK0E9fiDjfXI9eB7E237fYGOaSobOhLOLoHcuL0kndps67QP2BhtXhYB88 +1We7LoJVUwKBgQCnF1qtH5d0ukPTEdC73Q0z/buM7tPKRMTqXHxxPQN9782tVDYf +nAlWiVTENqpoUM4fxKq/SSL+SvfhyvrMW/z8NLi2bDUpEzviufg58N+v60dOeFyC +hgiSLgYGUfweeGrPx6qymGxo7SCWSLtrjhqZB/UIAADnTAeTcOKGhECQHQKBgAlM +A29J+BuBZMzK87CJIjbeRaVrmvSjXdeMzd+o+01ratn9bjwO14SRTfvhlbRzLLLO +y78YmutZbuZuWY5p5pUjJ9uv2o/INr3vnV0NqM4yVx8Vr/YoOnCkHGAKf4iVs8bw +E/b/8RHmOOvgSjjbvIKY8E1jMH8Az2e0CfqYyOBdAoGAOlhTefyBGgAWFHqH/l4p +ThbWupIMsw1ZXlArwBnTfsUFuz0Yq7B+0tqrV8lhS3P4/0jI2yWnzhluDk62clwz +Xg187V85Ylagshsjv60mP5qBEF4N7Nf5fP2w6+GjMU+YiHEBsgGGt+2jPgKeCGQW +IlV3ym59oL+wGyN9OK3z+aw= +-----END PRIVATE KEY----- diff --git a/spec/lib/pact/hal/http_client_spec.rb b/spec/lib/pact/hal/http_client_spec.rb index f79f03cb..bf39d7ba 100644 --- a/spec/lib/pact/hal/http_client_spec.rb +++ b/spec/lib/pact/hal/http_client_spec.rb @@ -1,4 +1,6 @@ require 'pact/hal/http_client' +require "faraday" +require "faraday/retry" module Pact module Hal @@ -129,6 +131,80 @@ module Hal end end end + + describe "x509 certificate" do + FAKE_SERVER_URL = 'https://localhost:4444' + X509_CERT_FILE_PATH = './spec/fixtures/certificates/client_cert.pem' + X509_KEY_FILE_PATH = './spec/fixtures/certificates/key.pem' + UNSIGNED_X509_CERT_FILE_PATH = './spec/fixtures/certificates/unsigned_cert.pem' + UNSIGNED_X509_KEY_FILE_PATH = './spec/fixtures/certificates/unsigned_key.pem' + + def wait_for_server_to_start + Faraday.new( + url: FAKE_SERVER_URL, + ssl: { + verify: false, + client_cert: OpenSSL::X509::Certificate.new(File.read(X509_CERT_FILE_PATH)), + client_key: OpenSSL::PKey::RSA.new(File.read(X509_KEY_FILE_PATH)) + } + ) do |builder| + builder.request :retry, max: 20, interval: 0.5, exceptions: [StandardError] + builder.adapter :net_http + end.get + end + + let(:do_get) { subject.get(FAKE_SERVER_URL) } + + before(:all) do + @pipe = IO.popen("bundle exec ruby ./spec/support/ssl_server.rb") + ENV['SSL_CERT_FILE'] = "./spec/fixtures/certificates/ca_cert.pem" + + wait_for_server_to_start() + end + + context "with valid x509 client certificates" do + before do + ENV['X509_CLIENT_CERT_FILE'] = X509_CERT_FILE_PATH + ENV['X509_CLIENT_KEY_FILE'] = X509_KEY_FILE_PATH + end + + it "succeeds" do + expect(do_get.status).to eq 200 + end + end + + context "when invalid x509 certificates are set" do + before do + ENV['X509_CLIENT_CERT_FILE'] = UNSIGNED_X509_CERT_FILE_PATH + ENV['X509_CLIENT_KEY_FILE'] = UNSIGNED_X509_KEY_FILE_PATH + end + + it "fails raising SSL error" do + expect { do_get } + .to raise_error { |error| + expect([OpenSSL::SSL::SSLError, Errno::ECONNRESET]).to include(error.class) + } + end + end + + context "when no x509 certificates are set" do + before do + ENV['X509_CLIENT_CERT_FILE'] = nil + ENV['X509_CLIENT_KEY_FILE'] = nil + end + + it "fails raising SSL error" do + expect { do_get } + .to raise_error { |error| + expect([OpenSSL::SSL::SSLError, Errno::ECONNRESET]).to include(error.class) + } + end + end + + after(:all) do + Process.kill "KILL", @pipe.pid + end + end end end end diff --git a/spec/support/ssl_server.rb b/spec/support/ssl_server.rb new file mode 100644 index 00000000..e5322985 --- /dev/null +++ b/spec/support/ssl_server.rb @@ -0,0 +1,42 @@ +if __FILE__ == $0 + + SSL_KEY = "spec/fixtures/certificates/key.pem" + SSL_CERT = "spec/fixtures/certificates/client_cert.pem" + SSL_CA_CERT = "spec/fixtures/certificates/ca_cert.pem" + + trap(:INT) do + @server.shutdown + exit + end + + def webrick_opts port + certificate = OpenSSL::X509::Certificate.new(File.read(SSL_CERT)) + cert_name = certificate.subject.to_a.collect{|a| a[0..1] } + logger_stream = ENV["DEBUG"] ? $stderr : StringIO.new + { + Port: port, + Host: "0.0.0.0", + AccessLog: [], + Logger: WEBrick::Log.new(logger_stream,WEBrick::Log::INFO), + SSLVerifyClient: OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT | OpenSSL::SSL::VERIFY_PEER, + SSLCACertificateFile: SSL_CA_CERT, + SSLCertificate: certificate, + SSLPrivateKey: OpenSSL::PKey::RSA.new(File.read(SSL_KEY)), + SSLEnable: true, + SSLCertName: cert_name, + } + end + + app = ->(_env) { puts "hello"; [200, {}, ["Hello world" + "\n"]] } + + require "webrick" + require "webrick/https" + require "rack" + require "rack/handler/webrick" + + opts = webrick_opts(4444) + + Rack::Handler::WEBrick.run(app, **opts) do |server| + @server = server + end +end