diff options
author | Jacob Keeler <jacob.keeler@livioradio.com> | 2019-03-05 22:25:18 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-05 22:25:18 -0500 |
commit | f4a510e575be083a6e9f6e944a908c968d65d5c5 (patch) | |
tree | 23e3cf36a4564189ed927bb7eb0a1e63764321cb | |
parent | 74af264f3dc62cd48f15b6d3269b17936b5aede6 (diff) | |
parent | 799220d37076e9da4900e97fe634ee5343a095ae (diff) | |
download | sdl_core-f4a510e575be083a6e9f6e944a908c968d65d5c5.tar.gz |
Merge pull request #2781 from smartdevicelink/feature/secure_websocket_connection
Cloud App WSS connection
14 files changed, 219 insertions, 46 deletions
diff --git a/src/components/application_manager/src/application_manager_impl.cc b/src/components/application_manager/src/application_manager_impl.cc index 364887ad3f..36309fa2f9 100644 --- a/src/components/application_manager/src/application_manager_impl.cc +++ b/src/components/application_manager/src/application_manager_impl.cc @@ -905,10 +905,16 @@ void ApplicationManagerImpl::DisconnectCloudApp(ApplicationSharedPtr app) { // Delete the cloud device connection_handler().RemoveCloudAppDevice(app->device()); + transport_manager::transport_adapter::CloudAppProperties properties{ + endpoint, + certificate, + enabled, + auth_token, + cloud_transport_type, + hybrid_app_preference}; // Create device in pending state LOG4CXX_DEBUG(logger_, "Re-adding the cloud app device"); - connection_handler().AddCloudAppDevice( - policy_app_id, endpoint, cloud_transport_type); + connection_handler().AddCloudAppDevice(policy_app_id, properties); } void ApplicationManagerImpl::RefreshCloudAppInformation() { @@ -948,9 +954,16 @@ void ApplicationManagerImpl::RefreshCloudAppInformation() { old_device_map.erase(old_device_it); } + transport_manager::transport_adapter::CloudAppProperties properties{ + endpoint, + certificate, + enabled, + auth_token, + cloud_transport_type, + hybrid_app_preference}; + // If the device was disconnected, this will reinitialize the device - connection_handler().AddCloudAppDevice( - policy_id, endpoint, cloud_transport_type); + connection_handler().AddCloudAppDevice(policy_id, properties); // Look for app icon url data and add to app_icon_url_map std::string url = GetPolicyHandler().GetIconUrl(policy_id); diff --git a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h index 16a3190315..06eb4f232d 100644 --- a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h +++ b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h @@ -81,7 +81,7 @@ class ConnectionHandlerImpl ConnectionHandlerImpl(const ConnectionHandlerSettings& settings, transport_manager::TransportManager& tm); /** - * \brief Destructor + * @brief Destructor */ ~ConnectionHandlerImpl(); @@ -130,9 +130,10 @@ class ConnectionHandlerImpl void ConnectToAllDevices() OVERRIDE; - void AddCloudAppDevice(const std::string& policy_app_id, - const std::string& endpoint, - const std::string& cloud_transport_type) OVERRIDE; + void AddCloudAppDevice( + const std::string& policy_app_id, + const transport_manager::transport_adapter::CloudAppProperties& + cloud_properties) OVERRIDE; void RemoveCloudAppDevice(const DeviceHandle device_id) OVERRIDE; diff --git a/src/components/connection_handler/src/connection_handler_impl.cc b/src/components/connection_handler/src/connection_handler_impl.cc index 8afc3e885f..7e93e04047 100644 --- a/src/components/connection_handler/src/connection_handler_impl.cc +++ b/src/components/connection_handler/src/connection_handler_impl.cc @@ -1351,12 +1351,13 @@ void ConnectionHandlerImpl::ConnectToAllDevices() { void ConnectionHandlerImpl::AddCloudAppDevice( const std::string& policy_app_id, - const std::string& endpoint, - const std::string& cloud_transport_type) { + const transport_manager::transport_adapter::CloudAppProperties& + cloud_properties) { cloud_app_id_map_lock_.Acquire(); - cloud_app_id_map_[policy_app_id] = std::make_pair(endpoint, 0); + cloud_app_id_map_[policy_app_id] = + std::make_pair(cloud_properties.endpoint, 0); cloud_app_id_map_lock_.Release(); - transport_manager_.AddCloudDevice(endpoint, cloud_transport_type); + transport_manager_.AddCloudDevice(cloud_properties); } void ConnectionHandlerImpl::RemoveCloudAppDevice(const DeviceHandle device_id) { diff --git a/src/components/include/connection_handler/connection_handler.h b/src/components/include/connection_handler/connection_handler.h index 234a7c1b76..ea9cc6c039 100644 --- a/src/components/include/connection_handler/connection_handler.h +++ b/src/components/include/connection_handler/connection_handler.h @@ -103,9 +103,10 @@ class ConnectionHandler { virtual void ConnectToAllDevices() = 0; - virtual void AddCloudAppDevice(const std::string& policy_app_id, - const std::string& endpoint, - const std::string& cloud_transport_type) = 0; + virtual void AddCloudAppDevice( + const std::string& policy_app_id, + const transport_manager::transport_adapter::CloudAppProperties& + cloud_properties) = 0; virtual void RemoveCloudAppDevice(const DeviceHandle device_id) = 0; diff --git a/src/components/include/test/connection_handler/mock_connection_handler.h b/src/components/include/test/connection_handler/mock_connection_handler.h index 3027fd5cb4..8cc439c78a 100644 --- a/src/components/include/test/connection_handler/mock_connection_handler.h +++ b/src/components/include/test/connection_handler/mock_connection_handler.h @@ -66,10 +66,10 @@ class MockConnectionHandler : public connection_handler::ConnectionHandler { MOCK_CONST_METHOD2(RunAppOnDevice, void(const std::string&, const std::string&)); MOCK_METHOD0(ConnectToAllDevices, void()); - MOCK_METHOD3(AddCloudAppDevice, - void(const std::string& policy_app_id, - const std::string& endpoint, - const std::string& cloud_transport_type)); + MOCK_METHOD2( + AddCloudAppDevice, + void(const std::string& policy_app_id, + const transport_manager::transport_adapter::CloudAppProperties&)); MOCK_METHOD1(RemoveCloudAppDevice, void(const DeviceHandle device_id)); MOCK_METHOD1(CloseRevokedConnection, void(uint32_t connection_key)); MOCK_METHOD1(CloseConnection, void(ConnectionHandle connection_handle)); diff --git a/src/components/include/test/transport_manager/mock_transport_manager.h b/src/components/include/test/transport_manager/mock_transport_manager.h index 40168c9c37..0581d4f375 100644 --- a/src/components/include/test/transport_manager/mock_transport_manager.h +++ b/src/components/include/test/transport_manager/mock_transport_manager.h @@ -59,9 +59,9 @@ class MockTransportManager : public ::transport_manager::TransportManager, MOCK_METHOD1(Init, int(resumption::LastState& last_state)); MOCK_METHOD0(Reinit, int()); MOCK_METHOD0(SearchDevices, int()); - MOCK_METHOD2(AddCloudDevice, - void(const std::string& endpoint, - const std::string& cloud_transport_type)); + MOCK_METHOD1( + AddCloudDevice, + void(const transport_manager::transport_adapter::CloudAppProperties)); MOCK_METHOD1(RemoveCloudDevice, void(const DeviceHandle device_id)); MOCK_METHOD1(ConnectDevice, int(const DeviceHandle)); MOCK_CONST_METHOD1( diff --git a/src/components/include/transport_manager/transport_adapter/transport_adapter.h b/src/components/include/transport_manager/transport_adapter/transport_adapter.h index 2b3efd3624..eaa1fa9955 100644 --- a/src/components/include/transport_manager/transport_adapter/transport_adapter.h +++ b/src/components/include/transport_manager/transport_adapter/transport_adapter.h @@ -71,6 +71,15 @@ enum DeviceType { UNKNOWN }; +struct CloudAppProperties { + std::string endpoint; + std::string certificate; + bool enabled; + std::string auth_token; + std::string cloud_transport_type; + std::string hybrid_app_preference; +}; + typedef std::map<DeviceType, std::string> DeviceTypes; /** @@ -89,6 +98,7 @@ typedef std::list<TransportAdapterListener*> TransportAdapterListenerList; */ typedef std::map<std::string, std::string> TransportConfig; +typedef std::map<std::string, CloudAppProperties> CloudAppTransportConfig; /** * @brief TransportConfig keys */ diff --git a/src/components/include/transport_manager/transport_manager.h b/src/components/include/transport_manager/transport_manager.h index 2596ba1b77..4ccc78cd1b 100644 --- a/src/components/include/transport_manager/transport_manager.h +++ b/src/components/include/transport_manager/transport_manager.h @@ -75,8 +75,9 @@ class TransportManager { **/ virtual int SearchDevices() = 0; - virtual void AddCloudDevice(const std::string& endpoint, - const std::string& cloud_transport_type) = 0; + virtual void AddCloudDevice( + const transport_manager::transport_adapter::CloudAppProperties + cloud_properties) = 0; virtual void RemoveCloudDevice(const DeviceHandle device_id) = 0; diff --git a/src/components/transport_manager/include/transport_manager/cloud/cloud_websocket_transport_adapter.h b/src/components/transport_manager/include/transport_manager/cloud/cloud_websocket_transport_adapter.h index d52e4b307d..138f9ca895 100644 --- a/src/components/transport_manager/include/transport_manager/cloud/cloud_websocket_transport_adapter.h +++ b/src/components/transport_manager/include/transport_manager/cloud/cloud_websocket_transport_adapter.h @@ -58,6 +58,23 @@ class CloudWebsocketTransportAdapter : public TransportAdapterImpl { */ virtual ~CloudWebsocketTransportAdapter(); + /** + * @brief Set CloudTransportConfig for specified app_id + * + * @param app_id app ID string + * @param properties New cloud app properties for the app + */ + void SetAppCloudTransportConfig(std::string app_id, + CloudAppProperties properties); + + /** + * @brief Get CloudTransportConfig for specified app_id + * + * @param app_id app ID string + * @return CloudAppProperties for the app + */ + const CloudAppProperties& GetAppCloudTransportConfig(std::string app_id); + protected: /** * @brief Return type of device. @@ -81,6 +98,7 @@ class CloudWebsocketTransportAdapter : public TransportAdapterImpl { void CreateDevice(const std::string& uid) OVERRIDE; private: + CloudAppTransportConfig transport_config_; }; } // namespace transport_adapter diff --git a/src/components/transport_manager/include/transport_manager/cloud/websocket_client_connection.h b/src/components/transport_manager/include/transport_manager/cloud/websocket_client_connection.h index d4319dfe0f..aa608312a0 100644 --- a/src/components/transport_manager/include/transport_manager/cloud/websocket_client_connection.h +++ b/src/components/transport_manager/include/transport_manager/cloud/websocket_client_connection.h @@ -50,6 +50,7 @@ #include <string> #include <thread> #include "transport_manager/transport_adapter/connection.h" +#include "transport_manager/cloud/cloud_websocket_transport_adapter.h" #include "utils/threads/thread.h" #include "utils/threads/message_loop_thread.h" #include "utils/message_queue.h" @@ -62,6 +63,8 @@ using ::utils::MessageQueue; typedef std::queue<protocol_handler::RawMessagePtr> AsyncQueue; typedef protocol_handler::RawMessagePtr Message; +typedef websocket::stream<tcp::socket> WS; +typedef websocket::stream<ssl::stream<tcp::socket> > WSS; namespace transport_manager { namespace transport_adapter { @@ -118,6 +121,13 @@ class WebsocketClientConnection */ TransportAdapter::Error Disconnect(); + /** + * @brief Attempt to add provided certificate to the ssl::context + * + * @param cert Certificate string from policy table + */ + void AddCertificateAuthority(std::string cert, boost::system::error_code& ec); + void Shutdown(); void Recv(boost::system::error_code ec); @@ -127,14 +137,17 @@ class WebsocketClientConnection private: TransportAdapterController* controller_; boost::asio::io_context ioc_; + ssl::context ctx_; tcp::resolver resolver_; - websocket::stream<tcp::socket> ws_; boost::beast::flat_buffer buffer_; std::string host_; std::string text_; + WS ws_; + WSS wss_; std::atomic_bool shutdown_; + CloudAppProperties cloud_properties; typedef std::queue<protocol_handler::RawMessagePtr> FrameQueue; FrameQueue frames_to_send_; mutable sync_primitives::Lock frames_to_send_mutex_; diff --git a/src/components/transport_manager/include/transport_manager/transport_manager_impl.h b/src/components/transport_manager/include/transport_manager/transport_manager_impl.h index 4b75f4aaa8..118439bd4a 100644 --- a/src/components/transport_manager/include/transport_manager/transport_manager_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_manager_impl.h @@ -139,8 +139,9 @@ class TransportManagerImpl **/ int SearchDevices() OVERRIDE; - void AddCloudDevice(const std::string& endpoint, - const std::string& cloud_transport_type) OVERRIDE; + void AddCloudDevice( + const transport_manager::transport_adapter::CloudAppProperties + cloud_properties) OVERRIDE; void RemoveCloudDevice(const DeviceHandle device_id) OVERRIDE; diff --git a/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc b/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc index ecef25f4f7..dd575979b2 100644 --- a/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc +++ b/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc @@ -53,6 +53,16 @@ CloudWebsocketTransportAdapter::CloudWebsocketTransportAdapter( CloudWebsocketTransportAdapter::~CloudWebsocketTransportAdapter() {} +void CloudWebsocketTransportAdapter::SetAppCloudTransportConfig( + std::string app_id, CloudAppProperties properties) { + transport_config_[app_id] = properties; +} + +const CloudAppProperties& +CloudWebsocketTransportAdapter::GetAppCloudTransportConfig(std::string app_id) { + return transport_config_[app_id]; +} + DeviceType CloudWebsocketTransportAdapter::GetDeviceType() const { return CLOUD_WEBSOCKET; } diff --git a/src/components/transport_manager/src/cloud/websocket_client_connection.cc b/src/components/transport_manager/src/cloud/websocket_client_connection.cc index 2947c510ff..5c9553a970 100644 --- a/src/components/transport_manager/src/cloud/websocket_client_connection.cc +++ b/src/components/transport_manager/src/cloud/websocket_client_connection.cc @@ -47,8 +47,10 @@ WebsocketClientConnection::WebsocketClientConnection( const ApplicationHandle& app_handle, TransportAdapterController* controller) : controller_(controller) + , ctx_(ssl::context::sslv23_client) , resolver_(ioc_) , ws_(ioc_) + , wss_(ioc_, ctx_) , shutdown_(false) , thread_delegate_(new LoopThreadDelegate(&message_queue_, this)) , write_thread_(threads::CreateThread("WS Async Send", thread_delegate_)) @@ -61,20 +63,55 @@ WebsocketClientConnection::~WebsocketClientConnection() { io_pool_.join(); } +void WebsocketClientConnection::AddCertificateAuthority( + const std::string cert, boost::system::error_code& ec) { + ctx_.add_certificate_authority(boost::asio::buffer(cert.data(), cert.size()), + ec); + if (ec) { + return; + } + + wss_.next_layer().set_verify_mode(ssl::verify_peer); +} + TransportAdapter::Error WebsocketClientConnection::Start() { LOG4CXX_AUTO_TRACE(logger_); DeviceSptr device = controller_->FindDevice(device_uid_); CloudDevice* cloud_device = static_cast<CloudDevice*>(device.get()); + CloudWebsocketTransportAdapter* cloud_ta = + static_cast<CloudWebsocketTransportAdapter*>(controller_); + cloud_properties = cloud_ta->GetAppCloudTransportConfig(device_uid_); auto const host = cloud_device->GetHost(); auto const port = cloud_device->GetPort(); boost::system::error_code ec; + + LOG4CXX_DEBUG(logger_, "Cloud app endpoint: " << cloud_properties.endpoint); + LOG4CXX_DEBUG(logger_, + "Cloud app certificate: " << cloud_properties.certificate); + LOG4CXX_DEBUG( + logger_, + "Cloud app authentication token: " << cloud_properties.auth_token); + LOG4CXX_DEBUG( + logger_, + "Cloud app transport type: " << cloud_properties.cloud_transport_type); + LOG4CXX_DEBUG(logger_, + "Cloud app hybrid app preference: " + << cloud_properties.hybrid_app_preference); + auto const results = resolver_.resolve(host, port, ec); if (ec) { std::string str_err = "ErrorMessage: " + ec.message(); LOG4CXX_ERROR(logger_, "Could not resolve host/port: " << str_err); return TransportAdapter::FAIL; } - boost::asio::connect(ws_.next_layer(), results.begin(), results.end(), ec); + + // Make Connection to host IP Address over TCP + if (cloud_properties.cloud_transport_type == "WSS") { + boost::asio::connect( + wss_.next_layer().next_layer(), results.begin(), results.end(), ec); + } else { + boost::asio::connect(ws_.next_layer(), results.begin(), results.end(), ec); + } if (ec) { std::string str_err = "ErrorMessage: " + ec.message(); LOG4CXX_ERROR(logger_, @@ -82,7 +119,40 @@ TransportAdapter::Error WebsocketClientConnection::Start() { LOG4CXX_ERROR(logger_, str_err); return TransportAdapter::FAIL; } - ws_.handshake(host, "/", ec); + + if (cloud_properties.cloud_transport_type == "WSS") { + AddCertificateAuthority(cloud_properties.certificate, ec); + + if (ec) { + std::string str_err = "ErrorMessage: " + ec.message(); + LOG4CXX_ERROR(logger_, + "Failed to add certificate authority: " + << cloud_properties.certificate); + LOG4CXX_ERROR(logger_, str_err); + Shutdown(); + return TransportAdapter::FAIL; + } + + // Perform SSL Handshake + wss_.next_layer().handshake(ssl::stream_base::client, ec); + + if (ec) { + std::string str_err = "ErrorMessage: " + ec.message(); + LOG4CXX_ERROR(logger_, + "Could not complete SSL Handshake failed with host/port: " + << host << ":" << port); + LOG4CXX_ERROR(logger_, str_err); + Shutdown(); + return TransportAdapter::FAIL; + } + } + + // Perform websocket handshake + if (cloud_properties.cloud_transport_type == "WSS") { + wss_.handshake(host, "/", ec); + } else { + ws_.handshake(host, "/", ec); + } if (ec) { std::string str_err = "ErrorMessage: " + ec.message(); LOG4CXX_ERROR(logger_, @@ -91,16 +161,30 @@ TransportAdapter::Error WebsocketClientConnection::Start() { LOG4CXX_ERROR(logger_, str_err); return TransportAdapter::FAIL; } - ws_.binary(true); + + // Set the binary message write option + if (cloud_properties.cloud_transport_type == "WSS") { + wss_.binary(true); + } else { + ws_.binary(true); + } write_thread_->start(threads::ThreadOptions()); controller_->ConnectDone(device_uid_, app_handle_); // Start async read - ws_.async_read(buffer_, - std::bind(&WebsocketClientConnection::OnRead, - this, - std::placeholders::_1, - std::placeholders::_2)); + if (cloud_properties.cloud_transport_type == "WSS") { + wss_.async_read(buffer_, + std::bind(&WebsocketClientConnection::OnRead, + this, + std::placeholders::_1, + std::placeholders::_2)); + } else { + ws_.async_read(buffer_, + std::bind(&WebsocketClientConnection::OnRead, + this, + std::placeholders::_1, + std::placeholders::_2)); + } boost::asio::post(io_pool_, [&]() { ioc_.run(); }); @@ -121,12 +205,19 @@ void WebsocketClientConnection::Recv(boost::system::error_code ec) { Shutdown(); return; } - - ws_.async_read(buffer_, - std::bind(&WebsocketClientConnection::OnRead, - this, - std::placeholders::_1, - std::placeholders::_2)); + if (cloud_properties.cloud_transport_type == "WSS") { + wss_.async_read(buffer_, + std::bind(&WebsocketClientConnection::OnRead, + this, + std::placeholders::_1, + std::placeholders::_2)); + } else { + ws_.async_read(buffer_, + std::bind(&WebsocketClientConnection::OnRead, + this, + std::placeholders::_1, + std::placeholders::_2)); + } } void WebsocketClientConnection::OnRead(boost::system::error_code ec, @@ -209,8 +300,13 @@ void WebsocketClientConnection::LoopThreadDelegate::DrainQueue() { message_queue_.pop(message_ptr); if (!shutdown_) { boost::system::error_code ec; - handler_.ws_.write( - boost::asio::buffer(message_ptr->data(), message_ptr->data_size())); + if (handler_.cloud_properties.cloud_transport_type == "WSS") { + handler_.wss_.write( + boost::asio::buffer(message_ptr->data(), message_ptr->data_size())); + } else { + handler_.ws_.write( + boost::asio::buffer(message_ptr->data(), message_ptr->data_size())); + } if (ec) { LOG4CXX_ERROR(logger_, "Error writing to websocket"); handler_.controller_->DataSendFailed(handler_.device_uid_, diff --git a/src/components/transport_manager/src/transport_manager_impl.cc b/src/components/transport_manager/src/transport_manager_impl.cc index 0b8724ff85..0c74602f6b 100644 --- a/src/components/transport_manager/src/transport_manager_impl.cc +++ b/src/components/transport_manager/src/transport_manager_impl.cc @@ -50,6 +50,7 @@ #include "transport_manager/transport_manager_listener.h" #include "transport_manager/transport_manager_listener_empty.h" #include "transport_manager/transport_adapter/transport_adapter.h" +#include "transport_manager/cloud/cloud_websocket_transport_adapter.h" #include "transport_manager/transport_adapter/transport_adapter_event.h" #include "config_profile/profile.h" @@ -130,10 +131,13 @@ void TransportManagerImpl::ReconnectionTimeout() { } void TransportManagerImpl::AddCloudDevice( - const std::string& endpoint, const std::string& cloud_transport_type) { + const transport_manager::transport_adapter::CloudAppProperties + cloud_properties) { // todo put conversion into own function + transport_adapter::DeviceType type = transport_adapter::DeviceType::UNKNOWN; - if (cloud_transport_type == "WS") { + if ((cloud_properties.cloud_transport_type == "WS") || + (cloud_properties.cloud_transport_type == "WSS")) { type = transport_adapter::DeviceType::CLOUD_WEBSOCKET; } else { return; @@ -142,7 +146,11 @@ void TransportManagerImpl::AddCloudDevice( std::vector<TransportAdapter*>::iterator ta = transport_adapters_.begin(); for (; ta != transport_adapters_.end(); ++ta) { if ((*ta)->GetDeviceType() == type) { - (*ta)->CreateDevice(endpoint); + (*ta)->CreateDevice(cloud_properties.endpoint); + transport_adapter::CloudWebsocketTransportAdapter* cta = + static_cast<transport_adapter::CloudWebsocketTransportAdapter*>(*ta); + cta->SetAppCloudTransportConfig(cloud_properties.endpoint, + cloud_properties); } } |