From b0c18d244ecfb8de95f2768c3f677c4595331afb Mon Sep 17 00:00:00 2001 From: zhao liwei Date: Wed, 19 Aug 2020 10:38:49 +0800 Subject: [PATCH 1/3] feat(security): handle SASL_LIST_MECHANISMS by server_negotiation (#588) --- include/dsn/tool-api/network.h | 3 ++ include/dsn/utility/strings.h | 4 +- src/runtime/rpc/asio_rpc_session.cpp | 10 ---- src/runtime/rpc/asio_rpc_session.h | 1 - src/runtime/rpc/network.cpp | 20 ++++++++ src/runtime/security/client_negotiation.cpp | 22 ++++++--- src/runtime/security/client_negotiation.h | 3 +- src/runtime/security/negotiation.cpp | 4 +- src/runtime/security/negotiation.h | 3 ++ src/runtime/security/negotiation_service.cpp | 51 ++++++++++++++++++++ src/runtime/security/negotiation_service.h | 40 +++++++++++++++ src/runtime/security/negotiation_utils.h | 32 +++++++++++- src/runtime/security/security.thrift | 2 +- src/runtime/security/security_types.cpp | 4 +- src/runtime/security/security_types.h | 2 +- src/runtime/security/server_negotiation.cpp | 35 ++++++++++++++ src/runtime/security/server_negotiation.h | 6 +++ src/runtime/service_api_c.cpp | 6 ++- src/utils/strings.cpp | 4 +- 19 files changed, 222 insertions(+), 30 deletions(-) create mode 100644 src/runtime/security/negotiation_service.cpp create mode 100644 src/runtime/security/negotiation_service.h diff --git a/include/dsn/tool-api/network.h b/include/dsn/tool-api/network.h index 8e630b1af6..ca90a2390c 100644 --- a/include/dsn/tool-api/network.h +++ b/include/dsn/tool-api/network.h @@ -234,6 +234,7 @@ class rpc_session : public ref_counter /// for negotiation void start_negotiation(); + security::negotiation *get_negotiation() const; public: /// @@ -300,6 +301,8 @@ class rpc_session : public ref_counter void clear_send_queue(bool resend_msgs); bool on_disconnected(bool is_write); + void on_failure(bool is_write = false); + void on_success(); protected: // constant info diff --git a/include/dsn/utility/strings.h b/include/dsn/utility/strings.h index 175ce3561e..92eb64cbd4 100644 --- a/include/dsn/utility/strings.h +++ b/include/dsn/utility/strings.h @@ -49,5 +49,5 @@ char *trim_string(char *s); // calculate the md5 checksum of buffer std::string string_md5(const char *buffer, unsigned int length); -} -} +} // namespace utils +} // namespace dsn diff --git a/src/runtime/rpc/asio_rpc_session.cpp b/src/runtime/rpc/asio_rpc_session.cpp index b18122f985..91d7637eb4 100644 --- a/src/runtime/rpc/asio_rpc_session.cpp +++ b/src/runtime/rpc/asio_rpc_session.cpp @@ -167,13 +167,6 @@ asio_rpc_session::asio_rpc_session(asio_network_provider &net, set_options(); } -void asio_rpc_session::on_failure(bool is_write) -{ - if (on_disconnected(is_write)) { - close(); - } -} - void asio_rpc_session::close() { utils::auto_write_lock socket_guard(_socket_lock); @@ -202,9 +195,6 @@ void asio_rpc_session::connect() // start auth negotiation when client is connecting to server start_negotiation(); - - set_connected(); - on_send_completed(); start_read_next(); } else { derror("client session connect to %s failed, error = %s", diff --git a/src/runtime/rpc/asio_rpc_session.h b/src/runtime/rpc/asio_rpc_session.h index 574eb23054..6b76ee6bd1 100644 --- a/src/runtime/rpc/asio_rpc_session.h +++ b/src/runtime/rpc/asio_rpc_session.h @@ -56,7 +56,6 @@ class asio_rpc_session : public rpc_session private: void do_read(int read_next) override; - void on_failure(bool is_write = false); void set_options(); void on_message_read(message_ex *msg) { diff --git a/src/runtime/rpc/network.cpp b/src/runtime/rpc/network.cpp index 5e047790ee..7cf2293f50 100644 --- a/src/runtime/rpc/network.cpp +++ b/src/runtime/rpc/network.cpp @@ -391,6 +391,21 @@ bool rpc_session::on_disconnected(bool is_write) return ret; } +void rpc_session::on_failure(bool is_write) +{ + if (on_disconnected(is_write)) { + close(); + } +} + +void rpc_session::on_success() +{ + if (is_client()) { + set_connected(); + on_send_completed(); + } +} + bool rpc_session::on_recv_message(message_ex *msg, int delay_ms) { if (msg->header->from_address.is_invalid()) @@ -442,6 +457,9 @@ void rpc_session::start_negotiation() } auth_negotiation(); + } else { + // set negotiation success if auth is disabled + on_success(); } } @@ -451,6 +469,8 @@ void rpc_session::auth_negotiation() _negotiation->start(); } +security::negotiation *rpc_session::get_negotiation() const { return _negotiation.get(); } + //////////////////////////////////////////////////////////////////////////////////////////////// network::network(rpc_engine *srv, network *inner_provider) : _engine(srv), _client_hdr_format(NET_HDR_DSN), _unknown_msg_header_format(NET_HDR_INVALID) diff --git a/src/runtime/security/client_negotiation.cpp b/src/runtime/security/client_negotiation.cpp index f3cb6684fa..5cd31b2231 100644 --- a/src/runtime/security/client_negotiation.cpp +++ b/src/runtime/security/client_negotiation.cpp @@ -19,6 +19,8 @@ #include "negotiation_utils.h" #include +#include +#include namespace dsn { namespace security { @@ -34,18 +36,24 @@ void client_negotiation::start() list_mechanisms(); } +void client_negotiation::handle_response(error_code err, const negotiation_response &&response) +{ + // TBD(zlw) +} + void client_negotiation::list_mechanisms() { - negotiation_request request; - _status = request.status = negotiation_status::type::SASL_LIST_MECHANISMS; - send(request); + auto request = dsn::make_unique(); + _status = request->status = negotiation_status::type::SASL_LIST_MECHANISMS; + send(std::move(request)); } -void client_negotiation::send(const negotiation_request &request) +void client_negotiation::send(std::unique_ptr request) { - message_ptr req = message_ex::create_request(RPC_NEGOTIATION); - dsn::marshall(req, request); - _session->send_message(req); + negotiation_rpc rpc(std::move(request), RPC_NEGOTIATION); + rpc.call(_session->remote_address(), nullptr, [this, rpc](error_code err) mutable { + handle_response(err, std::move(rpc.response())); + }); } } // namespace security diff --git a/src/runtime/security/client_negotiation.h b/src/runtime/security/client_negotiation.h index 244bf542d8..2db368f522 100644 --- a/src/runtime/security/client_negotiation.h +++ b/src/runtime/security/client_negotiation.h @@ -30,8 +30,9 @@ class client_negotiation : public negotiation void start(); private: + void handle_response(error_code err, const negotiation_response &&response); void list_mechanisms(); - void send(const negotiation_request &request); + void send(std::unique_ptr request); }; } // namespace security diff --git a/src/runtime/security/negotiation.cpp b/src/runtime/security/negotiation.cpp index 2cf8f16c3b..5315ce13a8 100644 --- a/src/runtime/security/negotiation.cpp +++ b/src/runtime/security/negotiation.cpp @@ -24,7 +24,9 @@ namespace dsn { namespace security { - +/// TODO(zlw):we can't get string list from cflags now, +/// so we should get supported mechanisms from config in the later +const std::set supported_mechanisms{"GSSAPI"}; DSN_DEFINE_bool("security", enable_auth, false, "whether open auth or not"); negotiation::~negotiation() {} diff --git a/src/runtime/security/negotiation.h b/src/runtime/security/negotiation.h index cd8db56e60..25492c80e0 100644 --- a/src/runtime/security/negotiation.h +++ b/src/runtime/security/negotiation.h @@ -18,12 +18,15 @@ #pragma once #include "security_types.h" + #include +#include namespace dsn { class rpc_session; namespace security { +typedef rpc_holder negotiation_rpc; class negotiation { diff --git a/src/runtime/security/negotiation_service.cpp b/src/runtime/security/negotiation_service.cpp new file mode 100644 index 0000000000..eef8bd3b32 --- /dev/null +++ b/src/runtime/security/negotiation_service.cpp @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "negotiation_service.h" +#include "negotiation_utils.h" +#include "server_negotiation.h" + +namespace dsn { +namespace security { +extern bool FLAGS_enable_auth; + +negotiation_service::negotiation_service() : serverlet("negotiation_service") {} + +void negotiation_service::open_service() +{ + register_rpc_handler_with_rpc_holder( + RPC_NEGOTIATION, "Negotiation", &negotiation_service::on_negotiation_request); +} + +void negotiation_service::on_negotiation_request(negotiation_rpc rpc) +{ + dassert(!rpc.dsn_request()->io_session->is_client(), + "only server session receive negotiation request"); + + // reply SASL_AUTH_DISABLE if auth is not enable + if (!security::FLAGS_enable_auth) { + rpc.response().status = negotiation_status::type::SASL_AUTH_DISABLE; + return; + } + + server_negotiation *srv_negotiation = + static_cast(rpc.dsn_request()->io_session->get_negotiation()); + srv_negotiation->handle_request(rpc); +} + +} // namespace security +} // namespace dsn diff --git a/src/runtime/security/negotiation_service.h b/src/runtime/security/negotiation_service.h new file mode 100644 index 0000000000..fcc4d587d9 --- /dev/null +++ b/src/runtime/security/negotiation_service.h @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#pragma once + +#include "server_negotiation.h" + +#include + +namespace dsn { +namespace security { + +class negotiation_service : public serverlet, + public utils::singleton +{ +public: + void open_service(); + +private: + negotiation_service(); + void on_negotiation_request(negotiation_rpc rpc); + friend class utils::singleton; +}; + +} // namespace security +} // namespace dsn diff --git a/src/runtime/security/negotiation_utils.h b/src/runtime/security/negotiation_utils.h index 0c6a145646..d695d085f5 100644 --- a/src/runtime/security/negotiation_utils.h +++ b/src/runtime/security/negotiation_utils.h @@ -17,10 +17,40 @@ #pragma once +#include "security_types.h" + namespace dsn { namespace security { +inline const char *enum_to_string(negotiation_status::type s) +{ + switch (s) { + case negotiation_status::type::SASL_LIST_MECHANISMS: + return "negotiation_list_mechanisms"; + case negotiation_status::type::SASL_LIST_MECHANISMS_RESP: + return "negotiation_list_mechanisms_resp"; + case negotiation_status::type::SASL_SELECT_MECHANISMS: + return "negotiation_select_mechanisms"; + case negotiation_status::type::SASL_SELECT_MECHANISMS_OK: + return "negotiation_select_mechanisms_ok"; + case negotiation_status::type::SASL_SUCC: + return "negotiation_succ"; + case negotiation_status::type::SASL_AUTH_FAIL: + return "negotiation_auth_fail"; + case negotiation_status::type::SASL_INITIATE: + return "negotiation_initiate"; + case negotiation_status::type::SASL_CHALLENGE: + return "negotiation_challenge"; + case negotiation_status::type::SASL_CHALLENGE_RESP: + return "negotiation_challenge_response"; + case negotiation_status::type::SASL_AUTH_DISABLE: + return "negotiation_auth_disable"; + case negotiation_status::type::INVALID: + return "negotiation_invalid"; + default: + return "negotiation-unknown"; + } +} DEFINE_TASK_CODE_RPC(RPC_NEGOTIATION, TASK_PRIORITY_COMMON, dsn::THREAD_POOL_DEFAULT) - } // namespace security } // namespace dsn diff --git a/src/runtime/security/security.thrift b/src/runtime/security/security.thrift index 174b09efb1..c30b47c418 100644 --- a/src/runtime/security/security.thrift +++ b/src/runtime/security/security.thrift @@ -35,7 +35,7 @@ enum negotiation_status { SASL_SELECT_MECHANISMS_OK SASL_INITIATE SASL_CHALLENGE - SASL_CHANLLENGE_RESP + SASL_CHALLENGE_RESP SASL_SUCC SASL_AUTH_DISABLE SASL_AUTH_FAIL diff --git a/src/runtime/security/security_types.cpp b/src/runtime/security/security_types.cpp index 580fe642fe..af31d13fc8 100644 --- a/src/runtime/security/security_types.cpp +++ b/src/runtime/security/security_types.cpp @@ -21,7 +21,7 @@ int _knegotiation_statusValues[] = {negotiation_status::INVALID, negotiation_status::SASL_SELECT_MECHANISMS_OK, negotiation_status::SASL_INITIATE, negotiation_status::SASL_CHALLENGE, - negotiation_status::SASL_CHANLLENGE_RESP, + negotiation_status::SASL_CHALLENGE_RESP, negotiation_status::SASL_SUCC, negotiation_status::SASL_AUTH_DISABLE, negotiation_status::SASL_AUTH_FAIL}; @@ -32,7 +32,7 @@ const char *_knegotiation_statusNames[] = {"INVALID", "SASL_SELECT_MECHANISMS_OK", "SASL_INITIATE", "SASL_CHALLENGE", - "SASL_CHANLLENGE_RESP", + "SASL_CHALLENGE_RESP", "SASL_SUCC", "SASL_AUTH_DISABLE", "SASL_AUTH_FAIL"}; diff --git a/src/runtime/security/security_types.h b/src/runtime/security/security_types.h index 5cda590bcc..cb339df0d7 100644 --- a/src/runtime/security/security_types.h +++ b/src/runtime/security/security_types.h @@ -31,7 +31,7 @@ struct negotiation_status SASL_SELECT_MECHANISMS_OK = 4, SASL_INITIATE = 5, SASL_CHALLENGE = 6, - SASL_CHANLLENGE_RESP = 7, + SASL_CHALLENGE_RESP = 7, SASL_SUCC = 8, SASL_AUTH_DISABLE = 9, SASL_AUTH_FAIL = 10 diff --git a/src/runtime/security/server_negotiation.cpp b/src/runtime/security/server_negotiation.cpp index 53f1f11052..f7044d06d9 100644 --- a/src/runtime/security/server_negotiation.cpp +++ b/src/runtime/security/server_negotiation.cpp @@ -16,7 +16,10 @@ // under the License. #include "server_negotiation.h" +#include "negotiation_utils.h" +#include +#include #include namespace dsn { @@ -33,5 +36,37 @@ void server_negotiation::start() ddebug_f("{}: start negotiation", _name); } +void server_negotiation::handle_request(negotiation_rpc rpc) +{ + if (_status == negotiation_status::type::SASL_LIST_MECHANISMS) { + on_list_mechanisms(rpc); + return; + } +} + +void server_negotiation::on_list_mechanisms(negotiation_rpc rpc) +{ + if (rpc.request().status == negotiation_status::type::SASL_LIST_MECHANISMS) { + std::string mech_list = boost::join(supported_mechanisms, ","); + negotiation_response &response = rpc.response(); + _status = response.status = negotiation_status::type::SASL_LIST_MECHANISMS_RESP; + response.msg = std::move(mech_list); + } else { + ddebug_f("{}: got message({}) while expect({})", + _name, + enum_to_string(rpc.request().status), + enum_to_string(negotiation_status::type::SASL_LIST_MECHANISMS)); + fail_negotiation(rpc, "invalid_client_message_status"); + } + return; +} + +void server_negotiation::fail_negotiation(negotiation_rpc rpc, const std::string &reason) +{ + negotiation_response &response = rpc.response(); + _status = response.status = negotiation_status::type::SASL_AUTH_FAIL; + response.msg = reason; +} + } // namespace security } // namespace dsn diff --git a/src/runtime/security/server_negotiation.h b/src/runtime/security/server_negotiation.h index ef6dc97211..9337efc28a 100644 --- a/src/runtime/security/server_negotiation.h +++ b/src/runtime/security/server_negotiation.h @@ -21,6 +21,7 @@ namespace dsn { namespace security { +extern const std::set supported_mechanisms; class server_negotiation : public negotiation { @@ -28,6 +29,11 @@ class server_negotiation : public negotiation server_negotiation(rpc_session *session); void start(); + void handle_request(negotiation_rpc rpc); + +private: + void on_list_mechanisms(negotiation_rpc rpc); + void fail_negotiation(negotiation_rpc rpc, const std::string &reason); }; } // namespace security diff --git a/src/runtime/service_api_c.cpp b/src/runtime/service_api_c.cpp index 194f3a8c40..026120fa0c 100644 --- a/src/runtime/service_api_c.cpp +++ b/src/runtime/service_api_c.cpp @@ -42,6 +42,7 @@ #include "runtime/rpc/rpc_engine.h" #include "runtime/task/task_engine.h" #include "utils/coredump.h" +#include "runtime/security/negotiation_service.h" // // global state @@ -543,7 +544,10 @@ service_app *service_app::new_service_app(const std::string &type, type.c_str(), dsn::PROVIDER_TYPE_MAIN, info); } -service_app::service_app(const dsn::service_app_info *info) : _info(info), _started(false) {} +service_app::service_app(const dsn::service_app_info *info) : _info(info), _started(false) +{ + security::negotiation_service::instance().open_service(); +} const service_app_info &service_app::info() const { return *_info; } diff --git a/src/utils/strings.cpp b/src/utils/strings.cpp index a53ff2698c..83f6a4dbbd 100644 --- a/src/utils/strings.cpp +++ b/src/utils/strings.cpp @@ -183,5 +183,5 @@ std::string string_md5(const char *buffer, unsigned length) return result; } -} -} +} // namespace utils +} // namespace dsn From f4f1d5d450acffbd5b314b06626d8fa01f2508b7 Mon Sep 17 00:00:00 2001 From: levy Date: Wed, 19 Aug 2020 16:14:10 +0800 Subject: [PATCH 2/3] refactor --- src/runtime/security/init.cpp | 5 +++-- src/runtime/security/kinit_context.cpp | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/runtime/security/init.cpp b/src/runtime/security/init.cpp index 672b61240b..53698557f9 100644 --- a/src/runtime/security/init.cpp +++ b/src/runtime/security/init.cpp @@ -18,11 +18,12 @@ #include "kinit_context.h" #include +#include namespace dsn { namespace security { -extern char *FLAGS_krb5_config; -extern char *FLAGS_krb5_keytab; +DSN_DECLARE_string(krb5_config); +DSN_DECLARE_string(krb5_keytab); /*** * set kerberos envs(for more details: diff --git a/src/runtime/security/kinit_context.cpp b/src/runtime/security/kinit_context.cpp index 8870ab0554..5ae403b331 100644 --- a/src/runtime/security/kinit_context.cpp +++ b/src/runtime/security/kinit_context.cpp @@ -101,6 +101,7 @@ class kinit_context // keytab file with absolute path krb5_keytab _keytab; // credential cache + // TODO(zlw): reuse ticket from ccache krb5_ccache _ccache; krb5_get_init_creds_opt *_opt = nullptr; @@ -158,9 +159,7 @@ void kinit_context::init_krb5_ctx() static std::once_flag once; std::call_once(once, [&]() { int64_t err = krb5_init_context(&_krb5_context); - if (err != 0) { - dassert_f(false, "init kerberos context failed, with kerberos error_code = {}", err); - } + dcheck_eq(err, 0); }); } From ee19b831e1b7c9195cc5153892c49fa8e764fd5f Mon Sep 17 00:00:00 2001 From: levy Date: Wed, 19 Aug 2020 16:15:40 +0800 Subject: [PATCH 3/3] refactor --- src/runtime/rpc/network.cpp | 3 ++- src/runtime/security/kinit_context.cpp | 2 +- src/runtime/security/negotiation_service.cpp | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/runtime/rpc/network.cpp b/src/runtime/rpc/network.cpp index 7cf2293f50..fa5f91a8ec 100644 --- a/src/runtime/rpc/network.cpp +++ b/src/runtime/rpc/network.cpp @@ -30,6 +30,7 @@ #include #include +#include namespace dsn { /*static*/ join_point @@ -38,7 +39,7 @@ namespace dsn { rpc_session::on_rpc_session_disconnected("rpc.session.disconnected"); namespace security { -extern bool FLAGS_enable_auth; +DSN_DECLARE_bool(enable_auth); } // namespace security rpc_session::~rpc_session() diff --git a/src/runtime/security/kinit_context.cpp b/src/runtime/security/kinit_context.cpp index 5ae403b331..a9a479a773 100644 --- a/src/runtime/security/kinit_context.cpp +++ b/src/runtime/security/kinit_context.cpp @@ -32,7 +32,7 @@ namespace dsn { namespace security { -extern bool FLAGS_enable_auth; +DSN_DECLARE_bool(enable_auth); #define KRB5_RETURN_NOT_OK(err, msg) \ do { \ diff --git a/src/runtime/security/negotiation_service.cpp b/src/runtime/security/negotiation_service.cpp index eef8bd3b32..2661114ee4 100644 --- a/src/runtime/security/negotiation_service.cpp +++ b/src/runtime/security/negotiation_service.cpp @@ -19,9 +19,11 @@ #include "negotiation_utils.h" #include "server_negotiation.h" +#include + namespace dsn { namespace security { -extern bool FLAGS_enable_auth; +DSN_DECLARE_bool(enable_auth); negotiation_service::negotiation_service() : serverlet("negotiation_service") {}