From d0088f6a18517c02b2533ec42e99057738be64aa Mon Sep 17 00:00:00 2001 From: woogerboy21 Date: Sat, 25 Feb 2017 13:48:31 -0500 Subject: [PATCH] Server audit table (#2423) * Creating of server side audit table for auditing actions such as password resets, account registrations and log queries. * Add migration script Add migration script for database * Update database script Update database script to reflect new audit table * Creating of server side audit table for auditing actions such as password resets, account registrations and log queries. * Add migration script Add migration script for database * Update database script Update database script to reflect new audit table * Corrected results column possible value(s). * Fixed migration script. * Added boolean audit logic Added enable/disable audit options Added audit functionality for forgot password * Added registration auditing Added registration auditing * Updated ActivateAccount Function Created clientid variable and used it in preporation for future potential protocol expansion. * Extended activation protocol Added clientid to activation command protocol * Typo correction Fix typo's * Missed type fix Found the infamous E! * Updated database function syntax Updated if/else syntax in db add audit function * Untabify content Untab files changed in PR --- cockatrice/src/remoteclient.cpp | 1 + common/pb/session_commands.proto | 1 + .../migrations/servatrice_0021_to_0022.sql | 16 +++ servatrice/servatrice.ini.example | 16 +++ servatrice/servatrice.sql | 16 ++- servatrice/src/servatrice.cpp | 104 ++++++++------ servatrice/src/servatrice.h | 3 + .../src/servatrice_database_interface.cpp | 23 +++ .../src/servatrice_database_interface.h | 3 +- servatrice/src/serversocketinterface.cpp | 135 +++++++++++++++--- 10 files changed, 256 insertions(+), 62 deletions(-) create mode 100644 servatrice/migrations/servatrice_0021_to_0022.sql diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index bc47bb30..5f15d1ea 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -139,6 +139,7 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica Command_Activate cmdActivate; cmdActivate.set_user_name(userName.toStdString()); cmdActivate.set_token(token.toStdString()); + cmdActivate.set_clientid(getSrvClientID(lastHostname).toStdString()); PendingCommand *pend = prepareSessionCommand(cmdActivate); connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(activateResponse(Response))); diff --git a/common/pb/session_commands.proto b/common/pb/session_commands.proto index 9494577a..f231abef 100644 --- a/common/pb/session_commands.proto +++ b/common/pb/session_commands.proto @@ -137,6 +137,7 @@ message Command_Activate { required string user_name = 1; // Activation token required string token = 2; + optional string clientid = 3; } message Command_AccountEdit { diff --git a/servatrice/migrations/servatrice_0021_to_0022.sql b/servatrice/migrations/servatrice_0021_to_0022.sql new file mode 100644 index 00000000..10ed3078 --- /dev/null +++ b/servatrice/migrations/servatrice_0021_to_0022.sql @@ -0,0 +1,16 @@ + +CREATE TABLE IF NOT EXISTS `cockatrice_audit` ( + `id` int(7) unsigned zerofill NOT NULL auto_increment, + `id_server` tinyint(3) NOT NULL, + `name` varchar(35) NOT NULL, + `ip_address` varchar(255) NOT NULL, + `clientid` varchar(15) NOT NULL, + `incidentDate` datetime NOT NULL default '0000-00-00 00:00:00', + `action` varchar(35) NOT NULL, + `results` ENUM('fail', 'success') NOT NULL DEFAULT 'fail', + `details` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + KEY `user_name` (`name`) +) ENGINE=INNODB DEFAULT CHARSET=utf8; + +UPDATE cockatrice_schema_version SET version=22 WHERE version=21; \ No newline at end of file diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index 46412eab..5cd5f7c3 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -353,6 +353,22 @@ log_user_msg_chat=false ; Log user messages coming from other servers in the network log_user_msg_isl=false +[audit] + +; Servatrice can record certain actions being performed in the database for server operators to better understand +; if some one may be abusing application functionality. Enabling auditing will allow servatrice to record any +; of the below enabled audit functionality to be recorded. +; Default: true +enable_audit=true + +; Servatrice can record when users attempt a new account registration. Should we enable auditing for this action? +; Default: true +enable_registration_audit=true + +; Servatrice can record when a users attempts to reset the account password. Should we enable auditing for this action? +; Default: true +enable_forgotpassword_audit=true + ; EXPERIMENTAL - NOT WORKING YET ; The following settings are relative to the server network functionality, that is not yet complete. diff --git a/servatrice/servatrice.sql b/servatrice/servatrice.sql index 9496da99..d3f2a36d 100644 --- a/servatrice/servatrice.sql +++ b/servatrice/servatrice.sql @@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_schema_version` ( PRIMARY KEY (`version`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; -INSERT INTO cockatrice_schema_version VALUES(21); +INSERT INTO cockatrice_schema_version VALUES(22); -- users and user data tables CREATE TABLE IF NOT EXISTS `cockatrice_users` ( @@ -267,3 +267,17 @@ CREATE TABLE IF NOT EXISTS `cockatrice_forgot_password` ( PRIMARY KEY (`id`), KEY `user_name` (`name`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `cockatrice_audit` ( + `id` int(7) unsigned zerofill NOT NULL auto_increment, + `id_server` tinyint(3) NOT NULL, + `name` varchar(35) NOT NULL, + `ip_address` varchar(255) NOT NULL, + `clientid` varchar(15) NOT NULL, + `incidentDate` datetime NOT NULL default '0000-00-00 00:00:00', + `action` varchar(35) NOT NULL, + `results` ENUM('fail', 'success') NOT NULL DEFAULT 'fail', + `details` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + KEY `user_name` (`name`) +) ENGINE=INNODB DEFAULT CHARSET=utf8; diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 18242cd1..7d7bfc04 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -252,11 +252,17 @@ bool Servatrice::initServer() } } - qDebug() << "Forgot password enabled: " << getEnableForgotPassword(); - if (getEnableForgotPassword()) { - qDebug() << "Forgot password token life (in minutes): " << getForgotPasswordTokenLife(); - qDebug() << "Forgot password challenge on: " << getEnableForgotPasswordChallenge(); - } + qDebug() << "Forgot password enabled: " << getEnableForgotPassword(); + if (getEnableForgotPassword()) { + qDebug() << "Forgot password token life (in minutes): " << getForgotPasswordTokenLife(); + qDebug() << "Forgot password challenge on: " << getEnableForgotPasswordChallenge(); + } + + qDebug() << "Auditing enabled: " << getEnableAudit(); + if (getEnableAudit()) { + qDebug() << "Audit registration attempts enabled: " << getEnableRegistrationAudit(); + qDebug() << "Audit forgot password attepts enabled: " << getEnableForgotPasswordAudit(); + } if (getDBTypeString() == "mysql") { databaseType = DatabaseMySql; @@ -550,49 +556,49 @@ void Servatrice::statusUpdate() if (getRegistrationEnabled() && getEnableInternalSMTPClient()) { - if (getRequireEmailActivationEnabled()) - { - QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select a.name, b.email, b.token from {prefix}_activation_emails a left join {prefix}_users b on a.name = b.name"); - if (!servatriceDatabaseInterface->execSqlQuery(query)) - return; + if (getRequireEmailActivationEnabled()) + { + QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select a.name, b.email, b.token from {prefix}_activation_emails a left join {prefix}_users b on a.name = b.name"); + if (!servatriceDatabaseInterface->execSqlQuery(query)) + return; - QSqlQuery *queryDelete = servatriceDatabaseInterface->prepareQuery("delete from {prefix}_activation_emails where name = :name"); + QSqlQuery *queryDelete = servatriceDatabaseInterface->prepareQuery("delete from {prefix}_activation_emails where name = :name"); - while (query->next()) { - const QString userName = query->value(0).toString(); - const QString emailAddress = query->value(1).toString(); - const QString token = query->value(2).toString(); + while (query->next()) { + const QString userName = query->value(0).toString(); + const QString emailAddress = query->value(1).toString(); + const QString token = query->value(2).toString(); - if (smtpClient->enqueueActivationTokenMail(userName, emailAddress, token)) - { - queryDelete->bindValue(":name", userName); - servatriceDatabaseInterface->execSqlQuery(queryDelete); - } - } - } + if (smtpClient->enqueueActivationTokenMail(userName, emailAddress, token)) + { + queryDelete->bindValue(":name", userName); + servatriceDatabaseInterface->execSqlQuery(queryDelete); + } + } + } - if (getEnableForgotPassword()) - { - QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select a.name, b.email, b.token from {prefix}_forgot_password a left join {prefix}_users b on a.name = b.name where a.emailed = 0"); - if (!servatriceDatabaseInterface->execSqlQuery(query)) - return; + if (getEnableForgotPassword()) + { + QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select a.name, b.email, b.token from {prefix}_forgot_password a left join {prefix}_users b on a.name = b.name where a.emailed = 0"); + if (!servatriceDatabaseInterface->execSqlQuery(query)) + return; - QSqlQuery *queryDelete = servatriceDatabaseInterface->prepareQuery("update {prefix}_forgot_password set emailed = 1 where name = :name"); + QSqlQuery *queryDelete = servatriceDatabaseInterface->prepareQuery("update {prefix}_forgot_password set emailed = 1 where name = :name"); - while (query->next()) { - const QString userName = query->value(0).toString(); - const QString emailAddress = query->value(1).toString(); - const QString token = query->value(2).toString(); + while (query->next()) { + const QString userName = query->value(0).toString(); + const QString emailAddress = query->value(1).toString(); + const QString token = query->value(2).toString(); - if (smtpClient->enqueueForgotPasswordTokenMail(userName, emailAddress, token)) - { - queryDelete->bindValue(":name", userName); - servatriceDatabaseInterface->execSqlQuery(queryDelete); - } - } - } + if (smtpClient->enqueueForgotPasswordTokenMail(userName, emailAddress, token)) + { + queryDelete->bindValue(":name", userName); + servatriceDatabaseInterface->execSqlQuery(queryDelete); + } + } + } - smtpClient->sendAllEmails(); + smtpClient->sendAllEmails(); } } @@ -877,17 +883,29 @@ bool Servatrice::getEnableInternalSMTPClient() const { } bool Servatrice::getEnableForgotPassword() const { - return settingsCache->value("forgotpassword/enable", false).toBool(); + return settingsCache->value("forgotpassword/enable", false).toBool(); } int Servatrice::getForgotPasswordTokenLife() const { - return settingsCache->value("forgotpassword/tokenlife", 60).toInt(); + return settingsCache->value("forgotpassword/tokenlife", 60).toInt(); } bool Servatrice::getEnableForgotPasswordChallenge() const { - return settingsCache->value("forgotpassword/enablechallenge", false).toBool(); + return settingsCache->value("forgotpassword/enablechallenge", false).toBool(); } QString Servatrice::getEmailBlackList() const { return settingsCache->value("registration/emailproviderblacklist").toString(); +} + +bool Servatrice::getEnableAudit() const { + return settingsCache->value("audit/enable_audit", true).toBool(); +} + +bool Servatrice::getEnableRegistrationAudit() const { + return settingsCache->value("audit/enable_registration_audit", true).toBool(); +} + +bool Servatrice::getEnableForgotPasswordAudit() const { + return settingsCache->value("audit/enable_forgotpassword_audit", true).toBool(); } \ No newline at end of file diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 5a6479d0..97c4ddba 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -193,6 +193,9 @@ public: bool getEnableLogQuery() const; bool getEnableForgotPassword() const; bool getEnableForgotPasswordChallenge() const; + bool getEnableAudit() const; + bool getEnableRegistrationAudit() const; + bool getEnableForgotPasswordAudit() const; int getIdleClientTimeout() const; int getServerID() const; int getMaxGameInactivityTime() const; diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index 49ec04f1..7cb00840 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -1218,3 +1218,26 @@ bool Servatrice_DatabaseInterface::validateTableColumnStringData(const QString & return false; } + +void Servatrice_DatabaseInterface::addAuditRecord(const QString &user, const QString &ipaddress, const QString &clientid, const QString &action, const QString &details, const bool &results = false) +{ + if (!checkSql()) + return; + + if (!server->getEnableAudit()) + return; + + if (user.isEmpty() || ipaddress.isEmpty() || clientid.isEmpty() || action.isEmpty()) + return; + + QSqlQuery *query = prepareQuery("insert into {prefix}_audit (id_server,name,ip_address,clientid,incidentDate,action,results,details) values (:idserver,:username,:ipaddress,:clientid,NOW(),:action,:results,:details)"); + query->bindValue(":idserver", server->getServerID()); + query->bindValue(":username", user); + query->bindValue(":ipaddress", ipaddress); + query->bindValue(":clientid", clientid); + query->bindValue(":action", action); + query->bindValue(":results", results ? "success" : "fail"); + + query->bindValue(":details", details); + execSqlQuery(query); +} \ No newline at end of file diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index 89ea3152..bfdb7810 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -9,7 +9,7 @@ #include "server.h" #include "server_database_interface.h" -#define DATABASE_SCHEMA_VERSION 21 +#define DATABASE_SCHEMA_VERSION 22 class Servatrice; @@ -86,6 +86,7 @@ public: bool doesForgotPasswordExist(const QString &user); bool updateUserToken(const QString &token, const QString &user); bool validateTableColumnStringData(const QString &table, const QString &column, const QString &_user, const QString &_datatocheck); + void addAuditRecord(const QString &user, const QString &ipaddress, const QString &clientid, const QString &action, const QString &details, const bool &results); }; #endif diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 92f28896..1227182b 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -881,8 +881,12 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C qDebug() << "Got register command: " << userName; bool registrationEnabled = settingsCache->value("registration/enabled", false).toBool(); - if (!registrationEnabled) + if (!registrationEnabled) { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Server functionality disabled", false); + return Response::RespRegistrationDisabled; + } QString emailBlackList = servatrice->getEmailBlackList(); QString emailAddress = QString::fromStdString(cmd.email()); @@ -892,6 +896,9 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C if (!emailBlackList.trimmed().isEmpty()) { foreach(QString blackListEmailAddress, emailBlackListFilters) { if (emailAddress.contains(blackListEmailAddress, Qt::CaseInsensitive)) { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Email used is blacklisted", false); + return Response::RespEmailBlackListed; } } @@ -909,20 +916,34 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C QString errorString; if (!sqlInterface->usernameIsValid(userName, errorString)) { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Username is invalid", false); + Response_Register *re = new Response_Register; re->set_denied_reason_str(errorString.toStdString()); rc.setResponseExtension(re); return Response::RespUsernameInvalid; } - if (userName.toLower().simplified() == "servatrice") - return Response::RespUsernameInvalid; + if (userName.toLower().simplified() == "servatrice") { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Username is invalid", false); + + return Response::RespUsernameInvalid; + } + + if (sqlInterface->userExists(userName)) { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Username already exists", false); - if(sqlInterface->userExists(userName)) return Response::RespUserAlreadyExists; + } if (servatrice->getMaxAccountsPerEmail() && !(sqlInterface->checkNumberOfUserAccounts(emailAddress) < servatrice->getMaxAccountsPerEmail())) { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Too many usernames registered with this email address", false); + return Response::RespTooManyRequests; } @@ -930,6 +951,9 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C int banSecondsRemaining; if (sqlInterface->checkUserIsBanned(this->getAddress(), userName, clientId, banReason, banSecondsRemaining)) { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "User is banned", false); + Response_Register *re = new Response_Register; re->set_denied_reason_str(banReason.toStdString()); if (banSecondsRemaining != 0) @@ -938,8 +962,12 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C return Response::RespUserIsBanned; } - if (tooManyRegistrationAttempts(this->getAddress())) + if (tooManyRegistrationAttempts(this->getAddress())) { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Too many registration attempts from this ip address", false); + return Response::RespTooManyRequests; + } QString realName = QString::fromStdString(cmd.real_name()); ServerInfo_User_Gender gender = cmd.gender(); @@ -947,8 +975,12 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C QString password = QString::fromStdString(cmd.password()); // TODO make this configurable? - if(password.length() < 6) + if (password.length() < 6) { + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Password is too short", false); + return Response::RespPasswordTooShort; + } QString token; bool requireEmailActivation = settingsCache->value("registration/requireemailactivation", true).toBool(); @@ -964,11 +996,22 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C if (!sqlInterface->execSqlQuery(query)) return Response::RespRegistrationFailed; + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "", true); + return Response::RespRegistrationAcceptedNeedsActivation; } else { + + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "", true); + return Response::RespRegistrationAccepted; } } else { + + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", "Unknown reason for failure", false); + return Response::RespRegistrationFailed; } } @@ -984,13 +1027,25 @@ Response::ResponseCode AbstractServerSocketInterface::cmdActivateAccount(const C { QString userName = QString::fromStdString(cmd.user_name()); QString token = QString::fromStdString(cmd.token()); - + QString clientID = QString::fromStdString(cmd.clientid()); + + if (clientID.isEmpty()) + clientID = "UNKNOWN"; + if(sqlInterface->activateUser(userName, token)) { qDebug() << "Accepted activation for user" << QString::fromStdString(cmd.user_name()); + + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), clientID, "ACTIVATE_ACCOUNT", "", true); + return Response::RespActivationAccepted; } else { qDebug() << "Failed activation for user" << QString::fromStdString(cmd.user_name()); + + if (servatrice->getEnableRegistrationAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), clientID, "ACTIVATE_ACCOUNT", "Failed to activate account, incorrect activation token", false); + return Response::RespActivationFailed; } } @@ -1067,13 +1122,25 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordRequest(c { qDebug() << "Received forgot password request from user: " << QString::fromStdString(cmd.user_name()); - if (!servatrice->getEnableForgotPassword()) - return Response::RespFunctionNotAllowed; + if (!servatrice->getEnableForgotPassword()) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "Server functionality disabled", false); - if (!sqlInterface->userExists(QString::fromStdString(cmd.user_name()))) return Response::RespFunctionNotAllowed; + } + + if (!sqlInterface->userExists(QString::fromStdString(cmd.user_name()))) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "User does not exist", false); + + return Response::RespFunctionNotAllowed; + } if (sqlInterface->doesForgotPasswordExist(QString::fromStdString(cmd.user_name()))) { + + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "Request already exists", true); + Response_ForgotPasswordRequest *re = new Response_ForgotPasswordRequest; re->set_challenge_email(false); rc.setResponseExtension(re); @@ -1081,10 +1148,17 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordRequest(c } QString banReason; int banTimeRemaining; - if (sqlInterface->checkUserIsBanned(this->getAddress(), QString::fromStdString(cmd.user_name()), QString::fromStdString(cmd.clientid()), banReason, banTimeRemaining)) + if (sqlInterface->checkUserIsBanned(this->getAddress(), QString::fromStdString(cmd.user_name()), QString::fromStdString(cmd.clientid()), banReason, banTimeRemaining)) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "User is banned", false); + return Response::RespFunctionNotAllowed; + } if (servatrice->getEnableForgotPasswordChallenge()) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "Request does not exist, challenge requested", true); + Response_ForgotPasswordRequest *re = new Response_ForgotPasswordRequest; re->set_challenge_email(true); rc.setResponseExtension(re); @@ -1092,6 +1166,10 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordRequest(c } else { if (sqlInterface->addForgotPassword(QString::fromStdString(cmd.user_name()))) { + + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "Request does not exist, challenge not requested", true); + Response_ForgotPasswordRequest *re = new Response_ForgotPasswordRequest; re->set_challenge_email(false); rc.setResponseExtension(re); @@ -1107,13 +1185,24 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordReset(con Q_UNUSED(rc); qDebug() << "Received forgot password reset from user: " << QString::fromStdString(cmd.user_name()); - if (!sqlInterface->doesForgotPasswordExist(QString::fromStdString(cmd.user_name()))) - return Response::RespFunctionNotAllowed; + if (!sqlInterface->doesForgotPasswordExist(QString::fromStdString(cmd.user_name()))) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET", "Request does not exist for user", false); - if (!sqlInterface->validateTableColumnStringData("{prefix}_users","token", QString::fromStdString(cmd.user_name()),QString::fromStdString(cmd.token()))) return Response::RespFunctionNotAllowed; + } + + if (!sqlInterface->validateTableColumnStringData("{prefix}_users", "token", QString::fromStdString(cmd.user_name()), QString::fromStdString(cmd.token()))) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET", "Failed token validation", false); + + return Response::RespFunctionNotAllowed; + } if (sqlInterface->changeUserPassword(QString::fromStdString(cmd.user_name()), "", QString::fromStdString(cmd.new_password()), true)) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET", "", true); + sqlInterface->removeForgotPassword(QString::fromStdString(cmd.user_name())); return Response::RespOk; } @@ -1126,12 +1215,24 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordChallenge Q_UNUSED(rc); qDebug() << "Received forgot password challenge from user: " << QString::fromStdString(cmd.user_name()); - if (sqlInterface->doesForgotPasswordExist(QString::fromStdString(cmd.user_name()))) - return Response::RespOk; + if (sqlInterface->doesForgotPasswordExist(QString::fromStdString(cmd.user_name()))) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_CHALLANGE", "Request does not exist for user", false); + + return Response::RespOk; + } + + if (sqlInterface->validateTableColumnStringData("{prefix}_users", "email", QString::fromStdString(cmd.user_name()), QString::fromStdString(cmd.email()))) { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_CHALLANGE", "", true); - if (sqlInterface->validateTableColumnStringData("{prefix}_users","email", QString::fromStdString(cmd.user_name()), QString::fromStdString(cmd.email()))) if (sqlInterface->addForgotPassword(QString::fromStdString(cmd.user_name()))) return Response::RespOk; + } + else { + if (servatrice->getEnableForgotPasswordAudit()) + sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_CHALLANGE", "Failed to answer email challenge question", false); + } return Response::RespFunctionNotAllowed; }