change the order in which the password challenge is performed (#4439)

this will force the user to always perform the challenge, meaning no
information on the account is leaked in case of failures
This commit is contained in:
ebbit1q 2021-10-24 02:18:08 +02:00 committed by GitHub
parent bbbf3e2a65
commit 6f360374cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 63 deletions

View file

@ -1320,32 +1320,47 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAccountPassword(const C
Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordRequest(const Command_ForgotPasswordRequest &cmd, Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordRequest(const Command_ForgotPasswordRequest &cmd,
ResponseContainer &rc) ResponseContainer &rc)
{ {
qDebug() << "Received reset password request from user: " << QString::fromStdString(cmd.user_name()); const QString userName = QString::fromStdString(cmd.user_name());
const QString clientId = QString::fromStdString(cmd.clientid());
qDebug() << "Received reset password request from user: " << userName;
if (!servatrice->getEnableForgotPassword()) { if (!servatrice->getEnableForgotPassword()) {
if (servatrice->getEnableForgotPasswordAudit()) if (servatrice->getEnableForgotPasswordAudit())
sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "PASSWORD_RESET_REQUEST", "Server functionality disabled", false);
"Server functionality disabled", false);
return Response::RespFunctionNotAllowed; return Response::RespFunctionNotAllowed;
} }
if (!sqlInterface->userExists(QString::fromStdString(cmd.user_name()))) { if (servatrice->getEnableForgotPasswordChallenge()) {
Response_ForgotPasswordRequest *re = new Response_ForgotPasswordRequest;
re->set_challenge_email(true);
rc.setResponseExtension(re);
return Response::RespOk;
}
if (!sqlInterface->userExists(userName)) {
if (servatrice->getEnableForgotPasswordAudit()) if (servatrice->getEnableForgotPasswordAudit())
sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "PASSWORD_RESET_REQUEST", "User does not exist", false);
"User does not exist", false);
return Response::RespFunctionNotAllowed; return Response::RespFunctionNotAllowed;
} }
if (sqlInterface->doesForgotPasswordExist(QString::fromStdString(cmd.user_name()))) { return continuePasswordRequest(userName, clientId, rc);
}
Response::ResponseCode AbstractServerSocketInterface::continuePasswordRequest(const QString &userName,
const QString &clientId,
ResponseContainer &rc,
bool challenged)
{
if (sqlInterface->doesForgotPasswordExist(userName)) {
if (servatrice->getEnableForgotPasswordAudit()) if (servatrice->getEnableForgotPasswordAudit())
sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "PASSWORD_RESET_REQUEST", "Request already exists", true);
"Request already exists", true);
Response_ForgotPasswordRequest *re = new Response_ForgotPasswordRequest; Response_ForgotPasswordRequest *re = new Response_ForgotPasswordRequest;
re->set_challenge_email(false); re->set_challenge_email(false);
@ -1355,43 +1370,33 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordRequest(c
QString banReason; QString banReason;
int banTimeRemaining; int banTimeRemaining;
if (sqlInterface->checkUserIsBanned(this->getAddress(), QString::fromStdString(cmd.user_name()), if (sqlInterface->checkUserIsBanned(this->getAddress(), userName, clientId, banReason, banTimeRemaining)) {
QString::fromStdString(cmd.clientid()), banReason, banTimeRemaining)) {
if (servatrice->getEnableForgotPasswordAudit()) if (servatrice->getEnableForgotPasswordAudit())
sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "PASSWORD_RESET_REQUEST", "User is banned", false);
"User is banned", false);
return Response::RespFunctionNotAllowed; return Response::RespFunctionNotAllowed;
} }
if (servatrice->getEnableForgotPasswordChallenge()) { if (!sqlInterface->addForgotPassword(userName)) {
if (servatrice->getEnableForgotPasswordAudit()) if (servatrice->getEnableForgotPasswordAudit()) {
sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
QString::fromStdString(cmd.clientid()).simplified(), "PASSWORD_RESET_REQUEST", "PASSWORD_RESET_REQUEST", "Failed to create password reset", false);
"Request does not exist, challenge requested", true);
Response_ForgotPasswordRequest *re = new Response_ForgotPasswordRequest;
re->set_challenge_email(true);
rc.setResponseExtension(re);
return Response::RespOk;
} 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);
return Response::RespOk;
} }
return Response::RespFunctionNotAllowed;
} }
return Response::RespFunctionNotAllowed; if (servatrice->getEnableForgotPasswordAudit()) {
QString details =
challenged ? "Request does not exist, challenge passed" : "Request does not exist, challenge not requested";
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
"PASSWORD_RESET_REQUEST", details, true);
}
Response_ForgotPasswordRequest *re = new Response_ForgotPasswordRequest;
re->set_challenge_email(false);
rc.setResponseExtension(re);
return Response::RespOk;
} }
Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordReset(const Command_ForgotPasswordReset &cmd, Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordReset(const Command_ForgotPasswordReset &cmd,
@ -1437,36 +1442,42 @@ Response::ResponseCode
AbstractServerSocketInterface::cmdForgotPasswordChallenge(const Command_ForgotPasswordChallenge &cmd, AbstractServerSocketInterface::cmdForgotPasswordChallenge(const Command_ForgotPasswordChallenge &cmd,
ResponseContainer &rc) ResponseContainer &rc)
{ {
Q_UNUSED(rc); const QString userName = QString::fromStdString(cmd.user_name());
qDebug() << "Received reset password challenge from user: " << QString::fromStdString(cmd.user_name()); const QString clientId = QString::fromStdString(cmd.clientid());
if (sqlInterface->doesForgotPasswordExist(QString::fromStdString(cmd.user_name()))) { qDebug() << "Received reset password challenge from user: " << userName;
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 (!servatrice->getEnableForgotPasswordChallenge()) {
if (servatrice->getEnableForgotPasswordAudit()) {
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
"PASSWORD_RESET_CHALLENGE", "Feature not enabled", false);
}
return Response::RespFunctionNotAllowed;
} }
if (sqlInterface->validateTableColumnStringData("{prefix}_users", "email", QString::fromStdString(cmd.user_name()), if (!sqlInterface->userExists(userName)) {
QString::fromStdString(cmd.email()))) { if (servatrice->getEnableForgotPasswordAudit()) {
if (servatrice->getEnableForgotPasswordAudit()) sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), "PASSWORD_RESET_CHALLENGE", "User does not exist", false);
QString::fromStdString(cmd.clientid()).simplified(), }
"PASSWORD_RESET_CHALLANGE", "", true); return Response::RespFunctionNotAllowed;
}
if (sqlInterface->addForgotPassword(QString::fromStdString(cmd.user_name()))) if (!sqlInterface->validateTableColumnStringData("{prefix}_users", "email", userName,
return Response::RespOk; QString::fromStdString(cmd.email()))) {
} else { if (servatrice->getEnableForgotPasswordAudit()) {
if (servatrice->getEnableForgotPasswordAudit()) sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), "PASSWORD_RESET_CHALLENGE", "Failed to answer email challenge question",
QString::fromStdString(cmd.clientid()).simplified(),
"PASSWORD_RESET_CHALLANGE", "Failed to answer email challenge question",
false); false);
}
return Response::RespFunctionNotAllowed;
} }
return Response::RespFunctionNotAllowed; if (servatrice->getEnableForgotPasswordAudit()) {
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
"PASSWORD_RESET_CHALLENGE", "", true);
}
return continuePasswordRequest(userName, clientId, rc, true);
} }
// ADMIN FUNCTIONS. // ADMIN FUNCTIONS.

View file

@ -109,6 +109,10 @@ private:
Response::ResponseCode cmdReloadConfig(const Command_ReloadConfig & /* cmd */, ResponseContainer & /*rc*/); Response::ResponseCode cmdReloadConfig(const Command_ReloadConfig & /* cmd */, ResponseContainer & /*rc*/);
Response::ResponseCode cmdAdjustMod(const Command_AdjustMod &cmd, ResponseContainer & /*rc*/); Response::ResponseCode cmdAdjustMod(const Command_AdjustMod &cmd, ResponseContainer & /*rc*/);
Response::ResponseCode cmdForgotPasswordRequest(const Command_ForgotPasswordRequest &cmd, ResponseContainer &rc); Response::ResponseCode cmdForgotPasswordRequest(const Command_ForgotPasswordRequest &cmd, ResponseContainer &rc);
Response::ResponseCode continuePasswordRequest(const QString &userName,
const QString &clientId,
ResponseContainer &rc,
bool challenged = false);
Response::ResponseCode cmdForgotPasswordReset(const Command_ForgotPasswordReset &cmd, ResponseContainer &rc); Response::ResponseCode cmdForgotPasswordReset(const Command_ForgotPasswordReset &cmd, ResponseContainer &rc);
Response::ResponseCode cmdForgotPasswordChallenge(const Command_ForgotPasswordChallenge &cmd, Response::ResponseCode cmdForgotPasswordChallenge(const Command_ForgotPasswordChallenge &cmd,
ResponseContainer &rc); ResponseContainer &rc);