Mercurial > malikania
changeset 175:a23758dda37d
Server: implement authentication, closes #869
While here, cleanup client class to match new conventions.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 20 Aug 2018 22:21:11 +0200 |
parents | 80b1638aa154 |
children | e7f3f477a896 |
files | libserver/malikania/server/client.cpp libserver/malikania/server/client.hpp libserver/malikania/server/net/auth_handler.cpp libserver/malikania/server/net/auth_handler.hpp libserver/malikania/server/net/handler.hpp libserver/malikania/server/server.cpp libserver/malikania/server/server.hpp server/main.cpp |
diffstat | 8 files changed, 138 insertions(+), 63 deletions(-) [+] |
line wrap: on
line diff
--- a/libserver/malikania/server/client.cpp Mon Aug 20 13:25:18 2018 +0200 +++ b/libserver/malikania/server/client.cpp Mon Aug 20 22:21:11 2018 +0200 @@ -24,12 +24,12 @@ namespace mlk::server { -void client::handle_read(boost::system::error_code code, std::size_t xfer) +void client::handle_read(std::error_code code, std::size_t xfer) { // TODO: use fixed size stream + verify exceed. - if (code) { + if (code) server_.handle_disconnect(shared_from_this()); - } else { + else { std::string message( boost::asio::buffers_begin(input_.data()), boost::asio::buffers_begin(input_.data()) + xfer - 4 @@ -48,7 +48,7 @@ } } -void client::handle_write(boost::system::error_code code, std::size_t) +void client::handle_write(std::error_code code, std::size_t) { if (code) { server_.handle_disconnect(shared_from_this()); @@ -65,7 +65,7 @@ void client::do_read() { - auto self = shared_from_this(); + const auto self = shared_from_this(); boost::asio::async_read_until(socket_, input_, "\r\n\r\n", [self] (auto code, auto xfer) { self->handle_read(code, xfer); @@ -76,22 +76,16 @@ { assert(!output_.empty()); - auto self = shared_from_this(); + const auto self = shared_from_this(); boost::asio::async_write(socket_, boost::asio::buffer(output_[0]), [self] (auto code, auto xfer) { self->handle_write(code, xfer); }); } -client::client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context) - : server_(server) - , socket_(service, context) -{ -} - void client::handshake() { - auto self = shared_from_this(); + const auto self = shared_from_this(); socket_.async_handshake(boost::asio::ssl::stream_base::server, [self] (auto code) { if (code) { @@ -107,6 +101,41 @@ do_read(); } +client::client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context) + : server_(server) + , socket_(service, context) +{ +} + +auto client::get_state() const noexcept -> state +{ + return state_; +} + +void client::set_state(state state) noexcept +{ + state_ = state; +} + +auto client::get_account() const noexcept -> const db::account& +{ + assert(state_ == state::ready); + + return *account_; +} + +auto client::get_account() noexcept -> db::account& +{ + assert(state_ == state::ready); + + return *account_; +} + +void client::set_account(db::account account) noexcept +{ + account_ = std::move(account); +} + void client::send(nlohmann::json message) { assert(message.is_object()); @@ -115,7 +144,7 @@ return; } - auto in_progress = !output_.empty(); + const auto in_progress = !output_.empty(); output_.push_back(message.dump() + "\r\n\r\n");
--- a/libserver/malikania/server/client.hpp Mon Aug 20 13:25:18 2018 +0200 +++ b/libserver/malikania/server/client.hpp Mon Aug 20 22:21:11 2018 +0200 @@ -27,8 +27,9 @@ #include <cstdint> #include <deque> #include <memory> +#include <optional> +#include <sstream> #include <string> -#include <sstream> #include <boost/asio.hpp> #include <boost/asio/ssl.hpp> @@ -78,10 +79,10 @@ boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; boost::asio::streambuf input_; std::deque<std::string> output_; - std::shared_ptr<class account> account_; + std::optional<db::account> account_; - void handle_read(boost::system::error_code, std::size_t); - void handle_write(boost::system::error_code, std::size_t); + void handle_read(std::error_code, std::size_t); + void handle_write(std::error_code, std::size_t); void do_read(); void do_write(); @@ -104,30 +105,37 @@ * * \return the state */ - inline enum state state() const noexcept - { - return state_; - } + auto get_state() const noexcept -> state; /** * Set the client state. * * \param new_state the state */ - inline void set_state(enum state new_state) noexcept - { - state_ = new_state; - } + void set_state(state state) noexcept; + + /** + * Get the underlying account database object. + * + * \pre get_state() == ready + * \return the account + */ + auto get_account() const noexcept -> const db::account&; + + /** + * Overloaded function. + * + * \pre get_state() == ready + * \return the account + */ + auto get_account() noexcept -> db::account&; /** * Set the client account. * * \param account the account */ - inline void set_account(std::shared_ptr<class account> account) noexcept - { - account_ = std::move(account); - } + void set_account(db::account account) noexcept; /** * Send a command and its arguments.
--- a/libserver/malikania/server/net/auth_handler.cpp Mon Aug 20 13:25:18 2018 +0200 +++ b/libserver/malikania/server/net/auth_handler.cpp Mon Aug 20 22:21:11 2018 +0200 @@ -18,7 +18,6 @@ #include <util.hpp> -#include "db/database.hpp" #include "db/account.hpp" #include "auth_handler.hpp" @@ -27,29 +26,39 @@ namespace mlk::server { -void auth_handler::exec(server& server, std::shared_ptr<client> clt, nlohmann::json object) noexcept +namespace { + +auto is_connected(const server& server, const db::account& account) noexcept -> bool { - (void)server; - (void)clt; - (void)object; -#if 0 - try { - // TODO: VERIFY ALREADY LOGGED IN! - auto ac = server.database().accounts().authenticate( - util::json::require_string(object, "/login"_json_pointer), - util::json::require_string(object, "/password"_json_pointer) - ); + const auto& clients = server.get_clients(); + const auto it = std::find_if(clients.begin(), clients.end(), [&] (const auto& c) { + if (c->get_state() != client::state::ready) + return false; + + return c->get_account().get_login() == account.get_login(); + }); + + return it != clients.end(); +} + +} // !namespace - if (ac) - clt->error("auth", "invalid credentials"); - else { - clt->set_state(client::state::ready); - clt->ok("auth"); - } - } catch (const std::exception& ex) { - clt->error("auth", ex.what()); +void auth_handler::exec(server& server, client& clt, nlohmann::json object) noexcept +{ + auto ac = db::account::authenticate( + util::json::require_string(object, "/login"_json_pointer), + util::json::require_string(object, "/password"_json_pointer) + ); + + if (!ac) + clt.error("auth", "invalid credentials"); + else if (is_connected(server, *ac)) + clt.error("auth", "already connected"); + else { + clt.set_account(std::move(*ac)); + clt.set_state(client::state::ready); + clt.ok("auth"); } -#endif } } // !mlk::server
--- a/libserver/malikania/server/net/auth_handler.hpp Mon Aug 20 13:25:18 2018 +0200 +++ b/libserver/malikania/server/net/auth_handler.hpp Mon Aug 20 22:21:11 2018 +0200 @@ -36,7 +36,7 @@ /** * \copydoc handler::exec */ - void exec(server &server, std::shared_ptr<client> clt, nlohmann::json object) noexcept override; + void exec(server& server, client& clt, nlohmann::json object) noexcept override; }; } // !mlk::server
--- a/libserver/malikania/server/net/handler.hpp Mon Aug 20 13:25:18 2018 +0200 +++ b/libserver/malikania/server/net/handler.hpp Mon Aug 20 22:21:11 2018 +0200 @@ -55,9 +55,7 @@ * \param client the client * \param message the network message */ - virtual void exec(server& server, - std::shared_ptr<client> client, - nlohmann::json message) noexcept = 0; + virtual void exec(server& server, client& client, nlohmann::json message) noexcept = 0; }; } // !mlk::server
--- a/libserver/malikania/server/server.cpp Mon Aug 20 13:25:18 2018 +0200 +++ b/libserver/malikania/server/server.cpp Mon Aug 20 22:21:11 2018 +0200 @@ -60,12 +60,22 @@ start(); } +auto server::get_clients() const noexcept -> const clients& +{ + return clients_; +} + +auto server::get_clients() noexcept -> clients& +{ + return clients_; +} + void server::handle(std::string name, std::unique_ptr<handler> handler) { assert(!name.empty()); assert(handler); - handlers_.emplace(std::move(name), std::move(handler)); + commands_.emplace(std::move(name), std::move(handler)); } void server::handle_disconnect(std::shared_ptr<client> clt) @@ -84,15 +94,15 @@ return; } - const auto it = handlers_.find(*cmd); + const auto it = commands_.find(*cmd); - if (it == handlers_.end()) { + if (it == commands_.end()) { // TODO: log error. return; } try { - it->second->exec(*this, std::move(clt), std::move(message)); + it->second->exec(*this, *clt, std::move(message)); } catch (const std::exception&) { // TODO: log error. }
--- a/libserver/malikania/server/server.hpp Mon Aug 20 13:25:18 2018 +0200 +++ b/libserver/malikania/server/server.hpp Mon Aug 20 22:21:11 2018 +0200 @@ -57,13 +57,17 @@ * \brief Malikania basic server. */ class server { +public: + using clients = std::unordered_set<std::shared_ptr<client>>; + using commands = std::unordered_map<std::string, std::unique_ptr<handler>>; + private: boost::asio::io_service& service_; boost::asio::ip::tcp::acceptor acceptor_; boost::asio::ssl::context context_; - std::unordered_set<std::shared_ptr<client>> clients_; - std::unordered_map<std::string, std::unique_ptr<handler>> handlers_; + clients clients_; + commands commands_; void load(); void start(); @@ -78,6 +82,20 @@ server(boost::asio::io_service& service, const settings& settings); /** + * Get the set of connected clients. + * + * \return the clients + */ + auto get_clients() const noexcept -> const clients&; + + /** + * Overloaded function. + * + * \return the clients + */ + auto get_clients() noexcept -> clients&; + + /** * Add network handler. * * If a handler is already present, it will be replaced with the new one.
--- a/server/main.cpp Mon Aug 20 13:25:18 2018 +0200 +++ b/server/main.cpp Mon Aug 20 22:21:11 2018 +0200 @@ -32,11 +32,14 @@ try { server::settings settings; - settings.key = ""; - settings.certificate = ""; + settings.key = "/home/markand/server.key"; + settings.certificate = "/home/markand/server.crt"; settings.port = 3320; server::server sv(ctx, settings); + + server::db::open("", "", "markand", "malikaniadb", ""); + server::db::init(); ctx.run(); } catch (const std::exception& ex) {