From commits-return-21665-archive-asf-public=cust-asf.ponee.io@pulsar.apache.org Fri Feb 1 12:26:01 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 4BB5D180627 for ; Fri, 1 Feb 2019 13:26:00 +0100 (CET) Received: (qmail 60394 invoked by uid 500); 1 Feb 2019 12:25:59 -0000 Mailing-List: contact commits-help@pulsar.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@pulsar.apache.org Delivered-To: mailing list commits@pulsar.apache.org Received: (qmail 60385 invoked by uid 99); 1 Feb 2019 12:25:59 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Feb 2019 12:25:59 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id CC4198578F; Fri, 1 Feb 2019 12:25:58 +0000 (UTC) Date: Fri, 01 Feb 2019 12:25:58 +0000 To: "commits@pulsar.apache.org" Subject: [pulsar] branch master updated: Add host name verification for C/C++ (#2475) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <154902395852.22441.13622071248619218224@gitbox.apache.org> From: ivank@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: pulsar X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 3791dfef4d5b880e97fe32d926235ad6214f42ed X-Git-Newrev: 0781cf47a81d3de7a6ec64243afd9d1a7815a092 X-Git-Rev: 0781cf47a81d3de7a6ec64243afd9d1a7815a092 X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated This is an automated email from the ASF dual-hosted git repository. ivank pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/pulsar.git The following commit(s) were added to refs/heads/master by this push: new 0781cf4 Add host name verification for C/C++ (#2475) 0781cf4 is described below commit 0781cf47a81d3de7a6ec64243afd9d1a7815a092 Author: Ali Ahmed AuthorDate: Fri Feb 1 04:25:53 2019 -0800 Add host name verification for C/C++ (#2475) This adds ssl host name verification as an optional client configuration for the C/C++ client library This brings it to parity with the java client --- .../include/pulsar/ClientConfiguration.h | 3 ++ .../include/pulsar/c/client_configuration.h | 5 +++ pulsar-client-cpp/lib/ClientConfiguration.cc | 7 ++++ pulsar-client-cpp/lib/ClientConfigurationImpl.h | 4 +- pulsar-client-cpp/lib/ConnectionPool.cc | 34 +++++++++++++++++ pulsar-client-cpp/lib/LogUtils.h | 2 +- pulsar-client-cpp/lib/c/c_ClientConfiguration.cc | 9 +++++ pulsar-client-cpp/python/src/config.cc | 1 + pulsar-client-cpp/tests/AuthPluginTest.cc | 44 ++++++++++++++++++++++ 9 files changed, 107 insertions(+), 2 deletions(-) diff --git a/pulsar-client-cpp/include/pulsar/ClientConfiguration.h b/pulsar-client-cpp/include/pulsar/ClientConfiguration.h index de2da49..0827b75 100644 --- a/pulsar-client-cpp/include/pulsar/ClientConfiguration.h +++ b/pulsar-client-cpp/include/pulsar/ClientConfiguration.h @@ -135,6 +135,9 @@ class ClientConfiguration { ClientConfiguration& setTlsAllowInsecureConnection(bool allowInsecure); bool isTlsAllowInsecureConnection() const; + ClientConfiguration& setValidateHostName(bool validateHostName); + bool isValidateHostName() const; + /* * Initialize stats interval in seconds. Stats are printed and reset after every 'statsIntervalInSeconds'. * Set to 0 in order to disable stats collection. diff --git a/pulsar-client-cpp/include/pulsar/c/client_configuration.h b/pulsar-client-cpp/include/pulsar/c/client_configuration.h index d1979c4..5b1c880 100644 --- a/pulsar-client-cpp/include/pulsar/c/client_configuration.h +++ b/pulsar-client-cpp/include/pulsar/c/client_configuration.h @@ -130,6 +130,11 @@ int pulsar_client_configuration_is_tls_allow_insecure_connection(pulsar_client_c void pulsar_client_configuration_set_stats_interval_in_seconds(pulsar_client_configuration_t *conf, const unsigned int interval); +int pulsar_client_configuration_is_validate_hostname(pulsar_client_configuration_t *conf); + +void pulsar_client_configuration_set_validate_hostname(pulsar_client_configuration_t *conf, + const unsigned int validateHostName); + /* * Get the stats interval set in the client. */ diff --git a/pulsar-client-cpp/lib/ClientConfiguration.cc b/pulsar-client-cpp/lib/ClientConfiguration.cc index 29b1362..aac7296 100644 --- a/pulsar-client-cpp/lib/ClientConfiguration.cc +++ b/pulsar-client-cpp/lib/ClientConfiguration.cc @@ -68,6 +68,13 @@ ClientConfiguration& ClientConfiguration::setUseTls(bool useTls) { bool ClientConfiguration::isUseTls() const { return impl_->useTls; } +ClientConfiguration& ClientConfiguration::setValidateHostName(bool validateHostName) { + impl_->validateHostName = validateHostName; + return *this; +} + +bool ClientConfiguration::isValidateHostName() const { return impl_->validateHostName; } + ClientConfiguration& ClientConfiguration::setTlsTrustCertsFilePath(const std::string& filePath) { impl_->tlsTrustCertsFilePath = filePath; return *this; diff --git a/pulsar-client-cpp/lib/ClientConfigurationImpl.h b/pulsar-client-cpp/lib/ClientConfigurationImpl.h index cb23a14..60e4ae6 100644 --- a/pulsar-client-cpp/lib/ClientConfigurationImpl.h +++ b/pulsar-client-cpp/lib/ClientConfigurationImpl.h @@ -35,6 +35,7 @@ struct ClientConfigurationImpl { bool tlsAllowInsecureConnection; unsigned int statsIntervalInSeconds; LoggerFactoryPtr loggerFactory; + bool validateHostName; ClientConfigurationImpl() : authenticationPtr(AuthFactory::Disabled()), @@ -46,7 +47,8 @@ struct ClientConfigurationImpl { useTls(false), tlsAllowInsecureConnection(false), statsIntervalInSeconds(600), // 10 minutes - loggerFactory() {} + loggerFactory(), + validateHostName(false) {} }; } // namespace pulsar diff --git a/pulsar-client-cpp/lib/ConnectionPool.cc b/pulsar-client-cpp/lib/ConnectionPool.cc index 993731e..598fe95 100644 --- a/pulsar-client-cpp/lib/ConnectionPool.cc +++ b/pulsar-client-cpp/lib/ConnectionPool.cc @@ -19,6 +19,15 @@ #include "ConnectionPool.h" #include "LogUtils.h" +#include "Url.h" + +#include +#include +#include + +using boost::asio::ip::tcp; +namespace ssl = boost::asio::ssl; +typedef ssl::stream ssl_socket; DECLARE_LOG_OBJECT() @@ -37,6 +46,30 @@ Future ConnectionPool::getConnectionAsync( const std::string& logicalAddress, const std::string& physicalAddress) { std::unique_lock lock(mutex_); + if (clientConfiguration_.isValidateHostName()) { + // Create a context that uses the default paths for + // finding CA certificates. + ssl::context ctx(ssl::context::sslv23); + ctx.set_default_verify_paths(); + + // Open a socket and connect it to the remote host. + boost::asio::io_service io_service; + ssl_socket sock(io_service, ctx); + tcp::resolver resolver(io_service); + Url service_url; + Url::parse(physicalAddress, service_url); + LOG_DEBUG("Validating hostname for " << service_url.host() << ":" << service_url.port()); + tcp::resolver::query query(service_url.host(), std::to_string(service_url.port())); + boost::asio::connect(sock.lowest_layer(), resolver.resolve(query)); + sock.lowest_layer().set_option(tcp::no_delay(true)); + + // Perform SSL handshake and verify the remote host's + // certificate. + sock.set_verify_mode(ssl::verify_peer); + sock.set_verify_callback(ssl::rfc2818_verification(physicalAddress)); + sock.handshake(ssl_socket::client); + } + if (poolConnections_) { PoolMap::iterator cnxIt = pool_.find(logicalAddress); if (cnxIt != pool_.end()) { @@ -70,4 +103,5 @@ Future ConnectionPool::getConnectionAsync( cnx->tcpConnectAsync(); return future; } + } // namespace pulsar diff --git a/pulsar-client-cpp/lib/LogUtils.h b/pulsar-client-cpp/lib/LogUtils.h index e4d94ca..59469fd 100644 --- a/pulsar-client-cpp/lib/LogUtils.h +++ b/pulsar-client-cpp/lib/LogUtils.h @@ -91,4 +91,4 @@ class LogUtils { }; #pragma GCC visibility pop -} +} // namespace pulsar diff --git a/pulsar-client-cpp/lib/c/c_ClientConfiguration.cc b/pulsar-client-cpp/lib/c/c_ClientConfiguration.cc index 935e908..13b4bf9 100644 --- a/pulsar-client-cpp/lib/c/c_ClientConfiguration.cc +++ b/pulsar-client-cpp/lib/c/c_ClientConfiguration.cc @@ -110,6 +110,15 @@ int pulsar_client_configuration_is_use_tls(pulsar_client_configuration_t *conf) return conf->conf.isUseTls(); } +void pulsar_client_configuration_set_validate_hostname(pulsar_client_configuration_t *conf, + int validateHostName) { + conf->conf.setValidateHostName(validateHostName); +} + +int pulsar_client_configuration_is_validate_hostname(pulsar_client_configuration_t *conf) { + return conf->conf.isValidateHostName(); +} + void pulsar_client_configuration_set_tls_trust_certs_file_path(pulsar_client_configuration_t *conf, const char *tlsTrustCertsFilePath) { conf->conf.setTlsTrustCertsFilePath(tlsTrustCertsFilePath); diff --git a/pulsar-client-cpp/python/src/config.cc b/pulsar-client-cpp/python/src/config.cc index 9b1d6d0..5c54f45 100644 --- a/pulsar-client-cpp/python/src/config.cc +++ b/pulsar-client-cpp/python/src/config.cc @@ -95,6 +95,7 @@ void export_config() { .def("tls_trust_certs_file_path", &ClientConfiguration::setTlsTrustCertsFilePath, return_self<>()) .def("tls_allow_insecure_connection", &ClientConfiguration::isTlsAllowInsecureConnection) .def("tls_allow_insecure_connection", &ClientConfiguration::setTlsAllowInsecureConnection, return_self<>()) + .def("tls_validate_hostname", &ClientConfiguration::setValidateHostName, return_self<>()) ; class_("ProducerConfiguration") diff --git a/pulsar-client-cpp/tests/AuthPluginTest.cc b/pulsar-client-cpp/tests/AuthPluginTest.cc index b2169e0..86a6acb 100644 --- a/pulsar-client-cpp/tests/AuthPluginTest.cc +++ b/pulsar-client-cpp/tests/AuthPluginTest.cc @@ -139,6 +139,27 @@ TEST(AuthPluginTest, testTlsDetectPulsarSsl) { ASSERT_EQ(ResultOk, result); } +TEST(AuthPluginTest, testTlsDetectPulsarSslWithHostNameValidation) { + try { + ClientConfiguration config = ClientConfiguration(); + config.setTlsTrustCertsFilePath(caPath); + config.setTlsAllowInsecureConnection(false); + config.setAuth(pulsar::AuthTls::create(clientPublicKeyPath, clientPrivateKeyPath)); + config.setValidateHostName(true); + + Client client(serviceUrlTls, config); + std::string topicName = "persistent://private/auth/test-tls-detect"; + + Producer producer; + Promise producerPromise; + client.createProducerAsync(topicName, WaitForCallbackValue(producerPromise)); + } catch (const std::exception& ex) { + EXPECT_EQ(ex.what(), std::string("handshake: certificate verify failed")); + } catch (...) { + FAIL() << "Expected handshake: certificate verify failed"; + } +} + TEST(AuthPluginTest, testTlsDetectHttps) { ClientConfiguration config = ClientConfiguration(); config.setUseTls(true); // shouldn't be needed soon @@ -158,6 +179,29 @@ TEST(AuthPluginTest, testTlsDetectHttps) { ASSERT_EQ(ResultOk, result); } +TEST(AuthPluginTest, testTlsDetectHttpsWithHostNameValidation) { + try { + ClientConfiguration config = ClientConfiguration(); + config.setUseTls(true); // shouldn't be needed soon + config.setTlsTrustCertsFilePath(caPath); + config.setTlsAllowInsecureConnection(false); + config.setAuth(pulsar::AuthTls::create(clientPublicKeyPath, clientPrivateKeyPath)); + config.setValidateHostName(true); + + Client client(serviceUrlHttps, config); + + std::string topicName = "persistent://private/auth/test-tls-detect-https"; + + Producer producer; + Promise producerPromise; + client.createProducerAsync(topicName, WaitForCallbackValue(producerPromise)); + } catch (const std::exception& ex) { + EXPECT_EQ(ex.what(), std::string("handshake: certificate verify failed")); + } catch (...) { + FAIL() << "Expected handshake: certificate verify failed"; + } +} + namespace testAthenz { std::string principalToken; void mockZTS(int port) {