From b0d33f094ddd7402f66fc4ff090be7ea19639d72 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 4 Aug 2019 04:16:14 -0500 Subject: [PATCH] Add local credential validation logic --- common/eqemu_logsys.cpp | 3 +- loginserver/account_management.cpp | 55 +++++++++++++++++++++ loginserver/account_management.h | 11 +++++ loginserver/database.cpp | 37 ++++++++++++++ loginserver/database.h | 18 +++++++ loginserver/loginserver_command_handler.cpp | 36 ++++++++++++-- loginserver/loginserver_command_handler.h | 1 + loginserver/loginserver_webserver.cpp | 37 ++++++++++++-- 8 files changed, 189 insertions(+), 9 deletions(-) diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp index 36246ae32..f9b9bcb81 100644 --- a/common/eqemu_logsys.cpp +++ b/common/eqemu_logsys.cpp @@ -143,6 +143,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults() log_settings[Logs::Warning].log_to_console = static_cast(Logs::General); log_settings[Logs::Notice].log_to_console = static_cast(Logs::General); log_settings[Logs::Info].log_to_console = static_cast(Logs::General); + log_settings[Logs::Debug].log_to_console = static_cast(Logs::General); /** * Set Category enabled status on defaults @@ -470,7 +471,7 @@ void EQEmuLogSys::Out( prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line); } - auto msg_cstr = message.c_str(); + auto msg_cstr = message.c_str(); va_list args; va_start(args, msg_cstr); std::string output_message = vStringFormat(msg_cstr, args); diff --git a/loginserver/account_management.cpp b/loginserver/account_management.cpp index 61c57c68e..be17ac149 100644 --- a/loginserver/account_management.cpp +++ b/loginserver/account_management.cpp @@ -134,3 +134,58 @@ bool AccountManagement::CreateLoginserverWorldAdminAccount( return false; } + +/** + * @param in_account_username + * @param in_account_password + * @return + */ +bool AccountManagement::CheckLoginserverUserCredentials( + const std::string &in_account_username, + const std::string &in_account_password, + const std::string &source_loginserver +) +{ + auto mode = server.options.GetEncryptionMode(); + + Database::DbLoginServerAccount + login_server_admin = server.db->GetLoginServerAccountByAccountName( + in_account_username, + source_loginserver + ); + + if (!login_server_admin.loaded) { + LogError( + "CheckLoginUserCredentials account [{0}] source_loginserver [{1}] not found!", + in_account_username, + source_loginserver + ); + + return false; + } + + bool validated_credentials = eqcrypt_verify_hash( + in_account_username, + in_account_password, + login_server_admin.account_password, + mode + ); + + if (!validated_credentials) { + LogError( + "CheckLoginUserCredentials account [{0}] source_loginserver [{1}] invalid credentials!", + in_account_username, + source_loginserver + ); + + return false; + } + + LogDebug( + "CheckLoginUserCredentials account [{0}] source_loginserver [{1}] credentials validated success!", + in_account_username, + source_loginserver + ); + + return validated_credentials; +} diff --git a/loginserver/account_management.h b/loginserver/account_management.h index 3bd14873a..64b22349c 100644 --- a/loginserver/account_management.h +++ b/loginserver/account_management.h @@ -48,6 +48,17 @@ public: const std::string &last_name = "", const std::string &ip_address = "" ); + + /** + * @param in_account_username + * @param in_account_password + * @return + */ + static bool CheckLoginserverUserCredentials( + const std::string &in_account_username, + const std::string &in_account_password, + const std::string &source_loginserver = "local" + ); }; diff --git a/loginserver/database.cpp b/loginserver/database.cpp index 9f8e5a6c7..b795f708a 100644 --- a/loginserver/database.cpp +++ b/loginserver/database.cpp @@ -730,3 +730,40 @@ Database::DbLoginServerAdmin Database::GetLoginServerAdmin(const std::string &ac return login_server_admin; } + +/** + * @param account_name + * @return + */ +Database::DbLoginServerAccount Database::GetLoginServerAccountByAccountName( + const std::string &account_name, + const std::string &source_loginserver +) +{ + auto query = fmt::format( + "SELECT id, account_name, account_password, account_email, source_loginserver, last_ip_address, last_login_date, " + "created_at, updated_at" + " FROM login_accounts WHERE account_name = '{0}' and source_loginserver = '{1}' LIMIT 1", + EscapeString(account_name), + EscapeString(source_loginserver) + ); + + auto results = QueryDatabase(query); + + Database::DbLoginServerAccount login_server_account{}; + if (results.RowCount() == 1) { + auto row = results.begin(); + login_server_account.loaded = true; + login_server_account.id = std::stoi(row[0]); + login_server_account.account_name = row[1]; + login_server_account.account_password = row[2]; + login_server_account.account_email = row[3]; + login_server_account.source_loginserver = row[4]; + login_server_account.last_ip_address = row[5]; + login_server_account.last_login_date = row[6]; + login_server_account.created_at = row[7]; + login_server_account.updated_at = row[8]; + } + + return login_server_account; +} \ No newline at end of file diff --git a/loginserver/database.h b/loginserver/database.h index aa3d2911b..5d8237fbd 100644 --- a/loginserver/database.h +++ b/loginserver/database.h @@ -248,6 +248,24 @@ public: Database::DbLoginServerAdmin GetLoginServerAdmin(const std::string &account_name); + struct DbLoginServerAccount { + bool loaded = false; + uint32 id; + std::string account_name; + std::string account_password; + std::string account_email; + std::string source_loginserver; + std::string last_login_date; + std::string last_ip_address; + std::string created_at; + std::string updated_at; + }; + + Database::DbLoginServerAccount GetLoginServerAccountByAccountName( + const std::string &account_name, + const std::string &source_loginserver = "local" + ); + /** * @param name * @param password diff --git a/loginserver/loginserver_command_handler.cpp b/loginserver/loginserver_command_handler.cpp index c8a60037d..2ba40f264 100644 --- a/loginserver/loginserver_command_handler.cpp +++ b/loginserver/loginserver_command_handler.cpp @@ -50,10 +50,11 @@ namespace LoginserverCommandHandler { /** * Register commands */ - function_map["login-user:create"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount; - function_map["web-api-token:create"] = &LoginserverCommandHandler::CreateLoginserverApiToken; - function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens; - function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount; + function_map["login-user:create"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount; + function_map["login-user:check-credentials"] = &LoginserverCommandHandler::CheckLoginserverUserCredentials; + function_map["web-api-token:create"] = &LoginserverCommandHandler::CreateLoginserverApiToken; + function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens; + function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount; EQEmuCommand::HandleMenu(function_map, cmd, argc, argv); } @@ -179,4 +180,31 @@ namespace LoginserverCommandHandler { ); } + /** + * @param argc + * @param argv + * @param cmd + * @param description + */ + void CheckLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description) + { + description = "Check user login credentials"; + + std::vector arguments = { + "--username", + "--password" + }; + std::vector options = {}; + + if (cmd[{"-h", "--help"}]) { + return; + } + + EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv); + + AccountManagement::CheckLoginserverUserCredentials( + cmd("--username").str(), + cmd("--password").str() + ); + } } diff --git a/loginserver/loginserver_command_handler.h b/loginserver/loginserver_command_handler.h index 44d46e83e..0e46b78eb 100644 --- a/loginserver/loginserver_command_handler.h +++ b/loginserver/loginserver_command_handler.h @@ -30,6 +30,7 @@ namespace LoginserverCommandHandler { void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd, std::string &description); void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd, std::string &description); void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description); + void CheckLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description); }; diff --git a/loginserver/loginserver_webserver.cpp b/loginserver/loginserver_webserver.cpp index 925e03430..a9d38a736 100644 --- a/loginserver/loginserver_webserver.cpp +++ b/loginserver/loginserver_webserver.cpp @@ -87,6 +87,37 @@ namespace LoginserverWebserver { LoginserverWebserver::SendResponse(response, res); } ); + + api.Post( + "/account/credentials/validate/local", [](const httplib::Request &request, httplib::Response &res) { + LoginserverWebserver::TokenManager::AuthCanRead(request, res); + Json::Value request_body = LoginserverWebserver::ParseRequestBody(request); + std::string username = request_body.get("username", "").asString(); + std::string password = request_body.get("password", "").asString(); + std::string email = request_body.get("email", "").asString(); + + Json::Value response; + if (username.empty() || password.empty()) { + response["message"] = "Username or password not set"; + LoginserverWebserver::SendResponse(response, res); + return; + } + + bool credentials_valid = AccountManagement::CheckLoginserverUserCredentials( + username, + password + ); + + if (credentials_valid) { + response["message"] = "Credentials valid!"; + } + else { + response["error"] = "Credentials invalid!"; + } + + LoginserverWebserver::SendResponse(response, res); + } + ); } /** @@ -146,8 +177,7 @@ namespace LoginserverWebserver { res.set_header("response_set", "true"); LogWarning( - "AuthCanRead access failure | token [{0}] remote_address [{1}] user_agent [{2}]", - user_token.token, + "AuthCanRead access failure remote_address [{0}] user_agent [{1}]", user_token.remote_address, user_token.user_agent ); @@ -174,8 +204,7 @@ namespace LoginserverWebserver { res.set_header("response_set", "true"); LogWarning( - "AuthCanWrite access failure | token [{0}] remote_address [{1}] user_agent [{2}]", - user_token.token, + "AuthCanWrite access failure remote_address [{0}] user_agent [{1}]", user_token.remote_address, user_token.user_agent );