pulsar-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From iv...@apache.org
Subject [pulsar] branch master updated: Add host name verification for C/C++ (#2475)
Date Fri, 01 Feb 2019 12:25:58 GMT
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 <alahmed.se@gmail.com>
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 <boost/iostreams/stream.hpp>
+#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
+
+using boost::asio::ip::tcp;
+namespace ssl = boost::asio::ssl;
+typedef ssl::stream<tcp::socket> ssl_socket;
 
 DECLARE_LOG_OBJECT()
 
@@ -37,6 +46,30 @@ Future<Result, ClientConnectionWeakPtr> ConnectionPool::getConnectionAsync(
     const std::string& logicalAddress, const std::string& physicalAddress) {
     std::unique_lock<std::mutex> 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<Result, ClientConnectionWeakPtr> 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>("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<Result, Producer> producerPromise;
+        client.createProducerAsync(topicName, WaitForCallbackValue<Producer>(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<Result, Producer> producerPromise;
+        client.createProducerAsync(topicName, WaitForCallbackValue<Producer>(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) {


Mime
View raw message