webserver: improve SSL certificate handling * Allows users to specify a separate location for PEM private-key file using --webserver_private_key_file (previously required private-key and cert. to be in same file).
* Allows users to specify a shell command to run to get the password for the webserver's private-key file using --webserver_private_key_password_cmd The separate configuration of cert and key is apparently more commonly used, so this simplifies deployment. The use of a script to provide the password for the private key makes it easier to integrate with external credential providers. This mirrors the change made in Impala by IMPALA-2051 (8bbe45393c7). Change-Id: I4b508cebbe6f31556e6d5a5fba5e5e9fb44cf1b9 Reviewed-on: http://gerrit.cloudera.org:8080/5015 Tested-by: Kudu Jenkins Reviewed-by: Dan Burkert <[email protected]> Reviewed-by: Alexey Serbin <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/2c052fcb Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/2c052fcb Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/2c052fcb Branch: refs/heads/master Commit: 2c052fcb4cd66cd901d40cf053be0c01d0ebc84e Parents: b235487 Author: Todd Lipcon <[email protected]> Authored: Tue Nov 8 16:32:11 2016 -0800 Committer: Todd Lipcon <[email protected]> Committed: Thu Jan 26 23:38:29 2017 +0000 ---------------------------------------------------------------------- src/kudu/security/security-test-util.h | 3 ++ src/kudu/security/test/test_certs.cc | 79 +++++++++++++++++++++++++++ src/kudu/security/test/test_certs.h | 16 ++++-- src/kudu/server/CMakeLists.txt | 2 +- src/kudu/server/webserver-test.cc | 84 +++++++++++++++++++++++++++-- src/kudu/server/webserver.cc | 51 +++++++++++++----- src/kudu/server/webserver_options.cc | 16 +++++- src/kudu/server/webserver_options.h | 2 + src/kudu/util/curl_util.cc | 3 ++ src/kudu/util/curl_util.h | 10 ++++ 10 files changed, 245 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/security/security-test-util.h ---------------------------------------------------------------------- diff --git a/src/kudu/security/security-test-util.h b/src/kudu/security/security-test-util.h index b9ea0b2..76853d4 100644 --- a/src/kudu/security/security-test-util.h +++ b/src/kudu/security/security-test-util.h @@ -25,6 +25,9 @@ namespace kudu { namespace security { +// TODO(todd): consolidate these certs with those in +// security/test/test_certs.h once we support configuring a password +// for the RPC cert. static Status CreateSSLServerCert(const std::string& file_path) { static const char* test_server_cert = R"( -----BEGIN CERTIFICATE----- http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/security/test/test_certs.cc ---------------------------------------------------------------------- diff --git a/src/kudu/security/test/test_certs.cc b/src/kudu/security/test/test_certs.cc index 15d4519..1f1e5e5 100644 --- a/src/kudu/security/test/test_certs.cc +++ b/src/kudu/security/test/test_certs.cc @@ -17,6 +17,14 @@ #include "kudu/security/test/test_certs.h" +#include <string> + +#include "kudu/util/env.h" +#include "kudu/util/path_util.h" +#include "kudu/util/status.h" + +using std::string; + namespace kudu { namespace security { namespace ca { @@ -208,5 +216,76 @@ H/sbP2R+P6RvQceLEEtk6ZZLiuScVmLtVOpUoUZb3Rx6a7GKbec7oQ== )***"; } // namespace ca + +Status CreateTestSSLCerts(const string& dir, + string* cert_file, + string* key_file, + string* key_password) { + const char* kCert = R"( +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAOOmFHYkBz4rMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTYxMTAyMjI0OTQ5WhcNMTcwMjEwMjI0OTQ5WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAppo9GwiDisQVYAF9NXl8ykqo0MIi5rfNwiE9kUWbZ2ejzxs+1Cf7WCn4 +mzbkJx5ZscRjhnNb6dJxtZJeid/qgiNVBcNzh35H8J+ao0tEbHjCs7rKOX0etsFU +p4GQwYkdfpvVBsU8ciXvkxhvt1XjSU3/YJJRAvCyGVxUQlKiVKGCD4OnFNBwMdNw +7qI8ryiRv++7I9udfSuM713yMeBtkkV7hWUfxrTgQOLsV/CS+TsSoOJ7JJqHozeZ ++VYom85UqSfpIFJVzM6S7BTb6SX/vwYIoS70gubT3HbHgDRcMvpCye1npHL9fL7B +87XZn7wnnUem0eeCqWyUjJ82Uj9mQQIDAQABo1AwTjAdBgNVHQ4EFgQUOY7rpWGo +ZMrmyRZ9RohPWVwyPBowHwYDVR0jBBgwFoAUOY7rpWGoZMrmyRZ9RohPWVwyPBow +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATKh3io8ruqbhmopY3xQW +A2pEhs4ZSu3H+AfULMruVsXKEZjWp27nTsFaxLZYUlzeZr0EcWwZ79qkcA8Dyj+m +VHhrCAPpcjsDACh1ZdUQAgASkVS4VQvkukct3DFa3y0lz5VwQIxjoQR5y6dCvxxX +T9NpRo/Z7pd4MRhEbz3NT6PScQ9f2MTrR0NOikLdB98JlpKQbEKxzbMhWDw4J3mr +mK6zdemjdCcRDsBVPswKnyAjkibXaZkpNRzjvDNAgO88MKlArCYoyRZqIfkcSXAw +wTdGQ+5GQLsY9zS49Rrhk9R7eOmDhaHybdRBDqW1JiCSmzURZAxlnrjox4GmC3JJ +aA== +-----END CERTIFICATE----- +)"; + const char* kKey = R"( +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIA3+5nR+Jr18CAggA +MBQGCCqGSIb3DQMHBAhCwHFGbZEcBgSCBMjT9vVbrYpd1reGwfLhk8703ihlspZi +cm4Z2MM+lkJs0Pi8O4n+zNSTfgrEr2XGlKIktBWEBxbhYrdYy1bYm4Fu5Z055JFo +89L/9zT1Zm/agk3CUW+ljirYZF60t/dDWmzLwt9f4dp8m4etL/UwvMJ1NglyxMkj +c03+aWWh4wHLRGkGDJFsKEQY87LL+nAOZS7P1qY38HnzQTOgLyNpntXX3SryzvQ6 +CpNIyQFhVGXfGn6DzGJB76heyLpCyAvIiP87vBS3zbnSqDM6v6PTW3SMo8R42RfL +d0CVmO8Z8NQeX29EkMHSRu7gCwXu1pf40QIog2vJZ7dmUgsU9GbBSg8l3nVWS6sm +AICNwPvHXRMMGX0wBJyK2ihuC7rVd5aZLgmu1sjlLYaB9KkoETcFFT8KbFpnd6aR +1whXQ4rPm1WyGtqbVGkZthisvGUeeGnbv2HXUVthSGleD+hQuwFXa8wE/8+Ruq9X +rNv/WMrf2NLIm+wbr19JzVSvLh+j7mIBMZmIwGQvBPo3/Tuq2zeyZdfSOroFcanq +Lyoc6yF5rAkU5BLVe36e48MarWICWDCxiz1n6tWdCpcXWfBvlWIkkjP1/rhqnOW3 +DKNjTyGJhaVYydkseoGrrpj4gkyyWtpgw+8c7jdtk+7cmIxpXu3UU6fh+Yt3vEhF +VqHvCd+YuUgpJ+TW574xiau4xbyib5Qv6JAR1Qp3MtzZ1IngyCU4QqqgxBGMBVqc +2LI7Romw7icfdzJxMeMp9WXh8D0Bxx5kjDcO0eUnkpVkFyozXZkoLCnoJ8u3yJo6 +yV4RQ4mOAWj7uZYg9KEUywNCHuIVPKG0CEfQkxKiPw4uvmdimKZ6Ij7aqrrc68Vi +oZnNHJEfJhnG78MKHgxXHNrMLFXBgPpLoBQxUBVhI2nq5D2l7gL5bKc9JZNg+mRJ +CouijXBHS1nZ/7GwVjLvNIGKWEsuiz1P0SYki1S02/3bBF9ySdeNGl1XTNqK4Xqy +arK4agJc89wg3N6SOIA+q8kA4LScafMtCkVDChw0CcLUrQERpH1tv1cqCt5zXF9n +5AnnWmEM2knlkHxXzg7k/1YXUz4JMmAhS4gVHuNU1uZR152lD+kgSy2K4sCyCfx2 +iWFpDGj556AUxDRGrqKU7OLC/64AuNz5IJs8doDa29cGGKFw3/foRoOaya84ISGW +GTl2qDOHZrJbgR6BUpSh2E2mVyO3GwIBst6yIb5VaTpNuIwS6fhjC4fQZEV6hHcx +qNvHxTTvz6eag4TeUPR48h/kGsI44DB0r4I79WbTwg5dvdlYbchPIwAs888bxpd6 +7ZxSg7EwuyHqJEL0FkWcDgw89+vLDETQiTwfscDxwm893gTymj5JPSDz35kudPlI +rsNfABLeXSg8Z8/7LsPP6Q48c1jisLVPPndV80cS791dvyXRxZWvX2z5UFuTDy3K +PV3L60mdejXudzFPfvovhgJDIWsKMmlxYplRWvG3WUXTck1Kb7KEcZmuo4nJMOID +6caoDNa5L9p5XH54sBCB7uqTNdqijaqq9iBFx/MqL3LHt6/wVF5J9g6PmuDxuYDX +tBKU0ns67U6wUxvLGBX/7RnWUibc5JwVGPBGw1E5u6MKWxW9Q6Dk1WakAtsqtDkR +WEc= +-----END ENCRYPTED PRIVATE KEY----- +)"; + const char* kKeyPassword = "test"; + + *cert_file = JoinPathSegments(dir, "test.cert"); + *key_file = JoinPathSegments(dir, "test.key"); + *key_password = kKeyPassword; + + RETURN_NOT_OK(WriteStringToFile(Env::Default(), kCert, *cert_file)); + RETURN_NOT_OK(WriteStringToFile(Env::Default(), kKey, *key_file)); + return Status::OK(); +} + } // namespace security } // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/security/test/test_certs.h ---------------------------------------------------------------------- diff --git a/src/kudu/security/test/test_certs.h b/src/kudu/security/test/test_certs.h index bafc11b..863c141 100644 --- a/src/kudu/security/test/test_certs.h +++ b/src/kudu/security/test/test_certs.h @@ -14,11 +14,13 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -// - #pragma once +#include <string> + namespace kudu { +class Status; + namespace security { namespace ca { @@ -40,6 +42,14 @@ extern const char kCaExpiredCert[]; extern const char kCaExpiredPrivateKey[]; } // namespace ca + +// Creates a matching SSL certificate and private key file in 'dir', returning +// their paths in '*cert_file' and '*key_file'. The password associated with +// the private key is stored in '*key_password'. +Status CreateTestSSLCerts(const std::string& dir, + std::string* cert_file, + std::string* key_file, + std::string* key_password); + } // namespace security } // namespace kudu - http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/server/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/src/kudu/server/CMakeLists.txt b/src/kudu/server/CMakeLists.txt index 1cdb0f8..25ce3df 100644 --- a/src/kudu/server/CMakeLists.txt +++ b/src/kudu/server/CMakeLists.txt @@ -102,5 +102,5 @@ endif() # server_process tests ######################################### -set(KUDU_TEST_LINK_LIBS server_process ${KUDU_MIN_TEST_LIBS}) +set(KUDU_TEST_LINK_LIBS server_process security-test ${KUDU_MIN_TEST_LIBS}) ADD_KUDU_TEST(webserver-test) http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/server/webserver-test.cc ---------------------------------------------------------------------- diff --git a/src/kudu/server/webserver-test.cc b/src/kudu/server/webserver-test.cc index 5ad7aa4..28c25ed 100644 --- a/src/kudu/server/webserver-test.cc +++ b/src/kudu/server/webserver-test.cc @@ -23,6 +23,7 @@ #include "kudu/gutil/strings/substitute.h" #include "kudu/gutil/strings/util.h" #include "kudu/gutil/stringprintf.h" +#include "kudu/security/test/test_certs.h" #include "kudu/server/default-path-handlers.h" #include "kudu/server/webserver.h" #include "kudu/util/curl_util.h" @@ -35,20 +36,32 @@ DECLARE_int32(webserver_max_post_length_bytes); namespace kudu { +namespace { +void SetSslOptions(WebserverOptions* opts) { + string password; + CHECK_OK(security::CreateTestSSLCerts(GetTestDataDirectory(), + &opts->certificate_file, + &opts->private_key_file, + &password)); + opts->private_key_password_cmd = strings::Substitute("echo $0", password); +} +} // anonymous namespace + class WebserverTest : public KuduTest { public: WebserverTest() { static_dir_ = GetTestPath("webserver-docroot"); CHECK_OK(env_->CreateDir(static_dir_)); + } + + virtual void SetUp() OVERRIDE { + KuduTest::SetUp(); WebserverOptions opts; opts.port = 0; opts.doc_root = static_dir_; + if (use_ssl()) SetSslOptions(&opts); server_.reset(new Webserver(opts)); - } - - virtual void SetUp() OVERRIDE { - KuduTest::SetUp(); AddDefaultPathHandlers(server_.get()); ASSERT_OK(server_->Start()); @@ -60,6 +73,9 @@ class WebserverTest : public KuduTest { } protected: + // Overridden by subclasses. + virtual bool use_ssl() const { return false; } + EasyCurl curl_; faststring buf_; gscoped_ptr<Webserver> server_; @@ -68,6 +84,11 @@ class WebserverTest : public KuduTest { string static_dir_; }; +class SslWebserverTest : public WebserverTest { + protected: + bool use_ssl() const override { return true; } +}; + TEST_F(WebserverTest, TestIndexPage) { ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/", addr_.ToString()), &buf_)); @@ -78,6 +99,16 @@ TEST_F(WebserverTest, TestIndexPage) { ASSERT_STR_CONTAINS(buf_.ToString(), "memz"); } +TEST_F(SslWebserverTest, TestSSL) { + // We use a self-signed cert, so we need to disable cert verification in curl. + curl_.set_verify_peer(false); + + ASSERT_OK(curl_.FetchURL(strings::Substitute("https://$0/", addr_.ToString()), + &buf_)); + // Should have expected title. + ASSERT_STR_CONTAINS(buf_.ToString(), "Kudu"); +} + TEST_F(WebserverTest, TestDefaultPaths) { // Test memz ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/memz?raw=1", addr_.ToString()), @@ -161,4 +192,49 @@ TEST_F(WebserverTest, TestStaticFiles) { ASSERT_EQ("Remote error: HTTP 403", s.ToString()); } +// Various tests for failed webserver startup cases. +class WebserverNegativeTests : public KuduTest { + protected: + + // Tries to start the webserver, expecting it to fail. + // 'func' is used to set webserver options before starting it. + template<class OptsFunc> + void ExpectFailedStartup(const OptsFunc& func) { + WebserverOptions opts; + opts.port = 0; + func(&opts); + Webserver server(opts); + Status s = server.Start(); + ASSERT_FALSE(s.ok()); + } +}; + +TEST_F(WebserverNegativeTests, BadCertFile) { + ExpectFailedStartup([this](WebserverOptions* opts) { + SetSslOptions(opts); + opts->certificate_file = "/dev/null"; + }); +} + +TEST_F(WebserverNegativeTests, BadKeyFile) { + ExpectFailedStartup([this](WebserverOptions* opts) { + SetSslOptions(opts); + opts->private_key_file = "/dev/null"; + }); +} + +TEST_F(WebserverNegativeTests, WrongPassword) { + ExpectFailedStartup([this](WebserverOptions* opts) { + SetSslOptions(opts); + opts->private_key_password_cmd = "echo wrong_pass"; + }); +} + +TEST_F(WebserverNegativeTests, BadPasswordCommand) { + ExpectFailedStartup([this](WebserverOptions* opts) { + SetSslOptions(opts); + opts->private_key_password_cmd = "/bin/false"; + }); +} + } // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/server/webserver.cc ---------------------------------------------------------------------- diff --git a/src/kudu/server/webserver.cc b/src/kudu/server/webserver.cc index ceca077..0b8cdfd 100644 --- a/src/kudu/server/webserver.cc +++ b/src/kudu/server/webserver.cc @@ -39,11 +39,13 @@ #include "kudu/gutil/strings/numbers.h" #include "kudu/gutil/strings/split.h" #include "kudu/gutil/strings/stringpiece.h" +#include "kudu/gutil/strings/strip.h" #include "kudu/util/env.h" #include "kudu/util/flag_tags.h" #include "kudu/util/locks.h" #include "kudu/util/logging.h" #include "kudu/util/net/net_util.h" +#include "kudu/util/subprocess.h" #include "kudu/util/url-coding.h" #include "kudu/util/version_info.h" @@ -125,12 +127,12 @@ Status Webserver::BuildListenSpec(string* spec) const { Status Webserver::Start() { LOG(INFO) << "Starting webserver on " << http_address_; - vector<const char*> options; + vector<string> options; if (static_pages_available()) { LOG(INFO) << "Document root: " << opts_.doc_root; options.push_back("document_root"); - options.push_back(opts_.doc_root.c_str()); + options.push_back(opts_.doc_root); options.push_back("enable_directory_listing"); options.push_back("no"); } else { @@ -140,12 +142,34 @@ Status Webserver::Start() { if (IsSecure()) { LOG(INFO) << "Webserver: Enabling HTTPS support"; options.push_back("ssl_certificate"); - options.push_back(opts_.certificate_file.c_str()); + options.push_back(opts_.certificate_file); + + if (!opts_.private_key_file.empty()) { + options.push_back("ssl_private_key"); + options.push_back(opts_.private_key_file); + + string key_password; + if (!opts_.private_key_password_cmd.empty()) { + vector<string> argv = strings::Split(opts_.private_key_password_cmd, " ", + strings::SkipEmpty()); + if (argv.empty()) { + return Status::RuntimeError("invalid empty private key password command"); + } + string stderr; + Status s = Subprocess::Call(argv, "" /* stdin */, &key_password, &stderr); + if (!s.ok()) { + return Status::RuntimeError("failed to run private key password command", stderr); + } + StripTrailingWhitespace(&key_password); + } + options.push_back("ssl_private_key_password"); + options.push_back(key_password); // maybe empty if not configured. + } } if (!opts_.authentication_domain.empty()) { options.push_back("authentication_domain"); - options.push_back(opts_.authentication_domain.c_str()); + options.push_back(opts_.authentication_domain); } if (!opts_.password_file.empty()) { @@ -158,21 +182,17 @@ Status Webserver::Start() { } LOG(INFO) << "Webserver: Password file is " << opts_.password_file; options.push_back("global_passwords_file"); - options.push_back(opts_.password_file.c_str()); + options.push_back(opts_.password_file); } options.push_back("listening_ports"); string listening_str; RETURN_NOT_OK(BuildListenSpec(&listening_str)); - options.push_back(listening_str.c_str()); + options.push_back(listening_str); // Num threads options.push_back("num_threads"); - string num_threads_str = SimpleItoa(opts_.num_worker_threads); - options.push_back(num_threads_str.c_str()); - - // Options must be a NULL-terminated list - options.push_back(nullptr); + options.push_back(std::to_string(opts_.num_worker_threads)); // mongoose ignores SIGCHLD and we need it to run kinit. This means that since // mongoose does not reap its own children CGI programs must be avoided. @@ -184,11 +204,18 @@ Status Webserver::Start() { callbacks.begin_request = &Webserver::BeginRequestCallbackStatic; callbacks.log_message = &Webserver::LogMessageCallbackStatic; + // Options must be a NULL-terminated list of C strings. + vector<const char*> c_options; + for (const auto& opt : options) { + c_options.push_back(opt.c_str()); + } + c_options.push_back(nullptr); + // To work around not being able to pass member functions as C callbacks, we store a // pointer to this server in the per-server state, and register a static method as the // default callback. That method unpacks the pointer to this and calls the real // callback. - context_ = sq_start(&callbacks, reinterpret_cast<void*>(this), &options[0]); + context_ = sq_start(&callbacks, reinterpret_cast<void*>(this), &c_options[0]); // Restore the child signal handler so wait() works properly. signal(SIGCHLD, sig_chld); http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/server/webserver_options.cc ---------------------------------------------------------------------- diff --git a/src/kudu/server/webserver_options.cc b/src/kudu/server/webserver_options.cc index 0730f06..020dc9d 100644 --- a/src/kudu/server/webserver_options.cc +++ b/src/kudu/server/webserver_options.cc @@ -51,9 +51,21 @@ DEFINE_bool(webserver_enable_doc_root, true, "If true, webserver may serve static files from the webserver_doc_root"); TAG_FLAG(webserver_enable_doc_root, advanced); +// SSL configuration. DEFINE_string(webserver_certificate_file, "", - "The location of the debug webserver's SSL certificate file, in .pem format. If " + "The location of the debug webserver's SSL certificate file, in PEM format. If " "empty, webserver SSL support is not enabled"); +DEFINE_string(webserver_private_key_file, "", "The full path to the private key used as a" + " counterpart to the public key contained in --ssl_server_certificate. If " + "--ssl_server_certificate is set, this option must be set as well."); +DEFINE_string(webserver_private_key_password_cmd, "", "A Unix command whose output " + "returns the password used to decrypt the Webserver's certificate private key file " + "specified in --webserver_private_key_file. If the PEM key file is not " + "password-protected, this command will not be invoked. The output of the command " + "will be truncated to 1024 bytes, and then all trailing whitespace will be trimmed " + "before it is used to decrypt the private key"); + + DEFINE_string(webserver_authentication_domain, "", "Domain used for debug webserver authentication"); DEFINE_string(webserver_password_file, "", @@ -84,6 +96,8 @@ WebserverOptions::WebserverOptions() doc_root(FLAGS_webserver_doc_root), enable_doc_root(FLAGS_webserver_enable_doc_root), certificate_file(FLAGS_webserver_certificate_file), + private_key_file(FLAGS_webserver_private_key_file), + private_key_password_cmd(FLAGS_webserver_private_key_password_cmd), authentication_domain(FLAGS_webserver_authentication_domain), password_file(FLAGS_webserver_password_file), num_worker_threads(FLAGS_webserver_num_worker_threads) { http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/server/webserver_options.h ---------------------------------------------------------------------- diff --git a/src/kudu/server/webserver_options.h b/src/kudu/server/webserver_options.h index ddc5079..d192637 100644 --- a/src/kudu/server/webserver_options.h +++ b/src/kudu/server/webserver_options.h @@ -33,6 +33,8 @@ struct WebserverOptions { std::string doc_root; bool enable_doc_root; std::string certificate_file; + std::string private_key_file; + std::string private_key_password_cmd; std::string authentication_domain; std::string password_file; uint32_t num_worker_threads; http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/util/curl_util.cc ---------------------------------------------------------------------- diff --git a/src/kudu/util/curl_util.cc b/src/kudu/util/curl_util.cc index d3265b8..c3bfdb6 100644 --- a/src/kudu/util/curl_util.cc +++ b/src/kudu/util/curl_util.cc @@ -68,6 +68,9 @@ Status EasyCurl::DoRequest(const std::string& url, faststring* dst) { CHECK_NOTNULL(dst)->clear(); + RETURN_NOT_OK(TranslateError(curl_easy_setopt( + curl_, CURLOPT_SSL_VERIFYPEER, + static_cast<long>(verify_peer_)))); // NOLINT(runtime/int) RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_URL, url.c_str()))); RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, WriteCallback))); RETURN_NOT_OK(TranslateError(curl_easy_setopt(curl_, CURLOPT_WRITEDATA, http://git-wip-us.apache.org/repos/asf/kudu/blob/2c052fcb/src/kudu/util/curl_util.h ---------------------------------------------------------------------- diff --git a/src/kudu/util/curl_util.h b/src/kudu/util/curl_util.h index b7e2da9..d758975 100644 --- a/src/kudu/util/curl_util.h +++ b/src/kudu/util/curl_util.h @@ -48,6 +48,12 @@ class EasyCurl { const std::string& post_data, faststring* dst); + // Set whether to verify the server's SSL certificate in the case of an HTTPS + // connection. + void set_verify_peer(bool verify) { + verify_peer_ = verify; + } + private: // Do a request. If 'post_data' is non-NULL, does a POST. // Otherwise, does a GET. @@ -55,6 +61,10 @@ class EasyCurl { const std::string* post_data, faststring* dst); CURL* curl_; + + // Whether to verify the server certificate. + bool verify_peer_ = true; + DISALLOW_COPY_AND_ASSIGN(EasyCurl); };
