From 587c5feabab23edf4565b1225b741812c2a7f189 Mon Sep 17 00:00:00 2001 From: Marcelo Zimbres Date: Sun, 31 Dec 2023 16:15:41 +0100 Subject: [PATCH 1/2] Provides a way of passing a custom ssl context to the connection. --- README.md | 12 +++--- include/boost/redis/connection.hpp | 28 ++++++------- .../boost/redis/detail/connection_base.hpp | 8 +--- include/boost/redis/impl/connection.ipp | 8 ++-- test/test_conn_tls.cpp | 42 +++++++++++++++---- 5 files changed, 60 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index aa6d550d..25e5817b 100644 --- a/README.md +++ b/README.md @@ -686,12 +686,12 @@ https://lists.boost.org/Archives/boost/2023/01/253944.php. not. * ([Issue 168](https://github.com/boostorg/redis/issues/168)). - Provides SSL context getters. The user wants to be able to pass the - `ssl::context` in the connection constructor as is done in Boost.Beast - and Boost.MySql. However, doing so would penalize users on plain - connections, which would have to start passing a dummy context on - every instantiation. If there is more convincing argument I will - change this in the future. + Provides a way of passing a custom SSL context to the connection. + The design here differs from that of Boost.Beast and Boost.MySql + since in Boost.Redis the connection owns the context instead of only + storing a reference to a user provided one. This is ok so because + apps need only one connection for their entire application, which + makes the overhead of one ssl-context per connection negligible. ### Boost 1.84 (First release in Boost) diff --git a/include/boost/redis/connection.hpp b/include/boost/redis/connection.hpp index 36131c3a..71348f33 100644 --- a/include/boost/redis/connection.hpp +++ b/include/boost/redis/connection.hpp @@ -86,13 +86,19 @@ class basic_connection { using other = basic_connection; }; - /// Contructs from an executor. + /** @brief Constructor + * + * @param ex Executor on which connection operation will run. + * @param ctx SSL context. + * @param max_read_size Maximum read size that is passed to + * the internal `asio::dynamic_buffer` constructor. + */ explicit basic_connection( executor_type ex, - asio::ssl::context::method method = asio::ssl::context::tls_client, + asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client}, std::size_t max_read_size = (std::numeric_limits::max)()) - : impl_{ex, method, max_read_size} + : impl_{ex, std::move(ctx), max_read_size} , timer_{ex} { } @@ -100,9 +106,9 @@ class basic_connection { explicit basic_connection( asio::io_context& ioc, - asio::ssl::context::method method = asio::ssl::context::tls_client, + asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client}, std::size_t max_read_size = (std::numeric_limits::max)()) - : basic_connection(ioc.get_executor(), method, max_read_size) + : basic_connection(ioc.get_executor(), std::move(ctx), max_read_size) { } /** @brief Starts underlying connection operations. @@ -286,10 +292,6 @@ class basic_connection { auto const& get_ssl_context() const noexcept { return impl_.get_ssl_context();} - /// Returns the ssl context. - auto& get_ssl_context() noexcept - { return impl_.get_ssl_context();} - /// Resets the underlying stream. void reset_stream() { impl_.reset_stream(); } @@ -343,14 +345,14 @@ class connection { explicit connection( executor_type ex, - asio::ssl::context::method method = asio::ssl::context::tls_client, + asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client}, std::size_t max_read_size = (std::numeric_limits::max)()); /// Contructs from a context. explicit connection( asio::io_context& ioc, - asio::ssl::context::method method = asio::ssl::context::tls_client, + asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client}, std::size_t max_read_size = (std::numeric_limits::max)()); /// Returns the underlying executor. @@ -427,10 +429,6 @@ class connection { auto const& get_ssl_context() const noexcept { return impl_.get_ssl_context();} - /// Returns the ssl context. - auto& get_ssl_context() noexcept - { return impl_.get_ssl_context();} - private: void async_run_impl( diff --git a/include/boost/redis/detail/connection_base.hpp b/include/boost/redis/detail/connection_base.hpp index 3e9a461a..043203bc 100644 --- a/include/boost/redis/detail/connection_base.hpp +++ b/include/boost/redis/detail/connection_base.hpp @@ -394,9 +394,9 @@ class connection_base { /// Constructs from an executor. connection_base( executor_type ex, - asio::ssl::context::method method, + asio::ssl::context ctx, std::size_t max_read_size) - : ctx_{method} + : ctx_{std::move(ctx)} , stream_{std::make_unique(ex, ctx_)} , writer_timer_{ex} , receive_channel_{ex, 256} @@ -411,10 +411,6 @@ class connection_base { auto const& get_ssl_context() const noexcept { return ctx_;} - /// Returns the ssl context. - auto& get_ssl_context() noexcept - { return ctx_;} - /// Resets the underlying stream. void reset_stream() { diff --git a/include/boost/redis/impl/connection.ipp b/include/boost/redis/impl/connection.ipp index 796573e9..12abc996 100644 --- a/include/boost/redis/impl/connection.ipp +++ b/include/boost/redis/impl/connection.ipp @@ -10,16 +10,16 @@ namespace boost::redis { connection::connection( executor_type ex, - asio::ssl::context::method method, + asio::ssl::context ctx, std::size_t max_read_size) -: impl_{ex, method, max_read_size} +: impl_{ex, std::move(ctx), max_read_size} { } connection::connection( asio::io_context& ioc, - asio::ssl::context::method method, + asio::ssl::context ctx, std::size_t max_read_size) -: impl_{ioc.get_executor(), method, max_read_size} +: impl_{ioc.get_executor(), std::move(ctx), max_read_size} { } void diff --git a/test/test_conn_tls.cpp b/test/test_conn_tls.cpp index 5e38ef3c..eb45dde3 100644 --- a/test/test_conn_tls.cpp +++ b/test/test_conn_tls.cpp @@ -25,7 +25,7 @@ bool verify_certificate(bool, net::ssl::verify_context&) return true; } -BOOST_AUTO_TEST_CASE(ping) +config make_tls_config() { config cfg; cfg.use_ssl = true; @@ -34,7 +34,12 @@ BOOST_AUTO_TEST_CASE(ping) cfg.addr.host = "db.occase.de"; cfg.addr.port = "6380"; //cfg.health_check_interval = std::chrono::seconds{0}; + return cfg; +} +BOOST_AUTO_TEST_CASE(ping_internal_ssl_context) +{ + auto const cfg = make_tls_config(); std::string const in = "Kabuf"; request req; @@ -59,14 +64,37 @@ BOOST_AUTO_TEST_CASE(ping) BOOST_CHECK_EQUAL(in, std::get<0>(resp).value()); } +BOOST_AUTO_TEST_CASE(ping_custom_ssl_context) +{ + auto const cfg = make_tls_config(); + std::string const in = "Kabuf"; + + request req; + req.push("PING", in); + + response resp; + + net::io_context ioc; + net::ssl::context ctx{boost::asio::ssl::context::tls_client}; + connection conn{ioc, std::move(ctx)}; + conn.next_layer().set_verify_mode(net::ssl::verify_peer); + conn.next_layer().set_verify_callback(verify_certificate); + + conn.async_exec(req, resp, [&](auto ec, auto) { + BOOST_TEST(!ec); + conn.cancel(); + }); + + conn.async_run(cfg, {}, [](auto) { }); + + ioc.run(); + + BOOST_CHECK_EQUAL(in, std::get<0>(resp).value()); +} + BOOST_AUTO_TEST_CASE(acl_does_not_allow_select) { - config cfg; - cfg.use_ssl = true; - cfg.username = "aedis"; - cfg.password = "aedis"; - cfg.addr.host = "db.occase.de"; - cfg.addr.port = "6380"; + auto cfg = make_tls_config(); cfg.database_index = 22; cfg.reconnect_wait_interval = std::chrono::seconds::zero(); From 1160347f6aabf409a5623103bb379d003aff9f97 Mon Sep 17 00:00:00 2001 From: Marcelo Zimbres Date: Mon, 1 Jan 2024 12:35:16 +0100 Subject: [PATCH 2/2] Fixes the CMake file. --- example/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index a727b75b..a400d21b 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -10,8 +10,8 @@ macro(make_example EXAMPLE_NAME STANDARD) if (${STANDARD} STREQUAL "20") target_link_libraries(${EXAMPLE_NAME} PRIVATE examples_main) endif() - if (${STANDARD} STREQUAL "20") - target_link_libraries(${EXAMPLE_NAME} PRIVATE Boost::json) + if (${EXAMPLE_NAME} STREQUAL "cpp20_json") + target_link_libraries(${EXAMPLE_NAME} PRIVATE Boost::json Boost::container_hash) endif() endmacro()