Skip to content

Commit

Permalink
dev: new service class for password reset and new admin user (sending…
Browse files Browse the repository at this point in the history
… no email with password)
  • Loading branch information
Trischi80 committed Apr 1, 2021
1 parent ee912b4 commit 43dc20f
Show file tree
Hide file tree
Showing 10 changed files with 391 additions and 38 deletions.
82 changes: 48 additions & 34 deletions application/controllers/UserManagementController.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function actionAddEditUser($userid = null)
);
}
$oUser = $userid === null ? new User() : User::model()->findByPk($userid);
$randomPassword = $this->getRandomPassword();
$randomPassword = \LimeSurvey\Models\Services\PasswordManagement::getRandomPassword();
return $this->renderPartial('partial/addedituser', ['oUser' => $oUser, 'randomPassword' => $randomPassword]);
}

Expand Down Expand Up @@ -161,19 +161,23 @@ public function actionApplyEdit()

//generate random password when password is empty
if (empty($aUser['password'])) {
$newPassword = $this->getRandomPassword(8);
$newPassword = \LimeSurvey\Models\Services\PasswordManagement::getRandomPassword();
$aUser['password'] = $newPassword;
}

//retrive the raw password to show up in registration email
//retrive the raw password
$aUser['rawPassword'] = $aUser['password'];

$passwordSetByUser = Yii::app()->request->getParam('preset_password');
if($passwordSetByUser == 0){ //in this case admin has not set a password, email with link will be sent
$this->createAdminUser($aUser);
$data = $this->createAdminUser($aUser);
}else{ //in this case admin has set a password, no email will be send ...just create user with given credentials
$this->createAdminUser($aUser, false);
$data = $this->createAdminUser($aUser, false);
}

return App()->getController()->renderPartial('/admin/super/_renderJson', [
"data" => $data
]);
}
}

Expand Down Expand Up @@ -659,7 +663,7 @@ public function actionImportUsers(string $importFormat = 'csv')
}
}
} else {
$password = $this->getRandomPassword(8);
$password = \LimeSurvey\Models\Services\PasswordManagement::getRandomPassword();
$passwordText = $password;
if ($aNewUser['password'] != ' ') {
$password = password_hash($aNewUser['password'], PASSWORD_DEFAULT);
Expand Down Expand Up @@ -1114,6 +1118,8 @@ public function loadModel($id)
* @param int $length Length of the password
* @return string
*/
/*
* --> moved to service class PasswordManagement
protected function getRandomPassword($length = 8)
{
$oGetPasswordEvent = new PluginEvent('createRandomPassword');
Expand All @@ -1122,6 +1128,7 @@ protected function getRandomPassword($length = 8)
return $oGetPasswordEvent->get('password');
}
*/

/**
* Update admin-user
Expand Down Expand Up @@ -1158,37 +1165,30 @@ public function updateAdminUser($aUser)
}

/**
* this method creates a new admin user
* this method creates a new admin user and returns success or error message
*
* @param array $aUser array with attributes from user model
* @param boolean $sendEmail true if email should be send, false otherwise
*
* @return array
*
* @param array $aUser
* @param boolean $sendEmail
* @return string
* @throws CException
* @throws \PHPMailer\PHPMailer\Exception
*/
private function createAdminUser($aUser, $sendEmail=true)
{
if (!isset($aUser['uid']) || $aUser['uid'] == null) {
$newUser = $this->createNewUser($aUser);
$sReturnMessage = gT('User successfully created');
$success = true;
$sReturnMessage = gT('User successfully created');

if (Yii::app()->getConfig("sendadmincreationemail") && $sendEmail) {
$mailer = $this->sendAdminMail($aUser, 'registration');

if ($mailer->getError()) {
$sReturnMessage = CHtml::tag("h4", array(), gT("Error"));
$sReturnMessage .= CHtml::tag("p", array(), sprintf(gT("Email to %s (%s) failed."), "<strong>" . $newUser['users_name'] . "</strong>", $newUser['email']));
$sReturnMessage .= CHtml::tag("p", array(), $mailer->getError());
$success = false;
} else {
// has to be sent again or no other way
$sReturnMessage = CHtml::tag("h4", array(), gT("Success"));
$sReturnMessage .= CHtml::tag("p", array(), sprintf(gT("Username : %s - Email : %s."), $newUser['users_name'], $newUser['email']));
$sReturnMessage .= CHtml::tag("p", array(), gT("An email with a generated password was sent to the user."));
}
}else{
$user = User::model()->findByPk($newUser['uid']);
$passwordManagement = new \LimeSurvey\Models\Services\PasswordManagement($user);
$successData = $passwordManagement->sendPasswordLinkViaEmail();

$sReturnMessage = $successData['sReturnMessage'];
$success = $successData['success'];
}

if ($success) {
Expand All @@ -1203,10 +1203,13 @@ private function createAdminUser($aUser, $sendEmail=true)
];
}

return App()->getController()->renderPartial('/admin/super/_renderJson', [
"data" => $data
]);
return $data;
}

return [
'success' => false,
'errors' => CHtml::tag("p", array(), gT("Error: no user was created"))
];
}

/**
Expand Down Expand Up @@ -1275,14 +1278,16 @@ public function createNewUser($aUser)

/**
* Send the registration email to a new survey administrator
* @TODO: make this user configurable by TWIG, or similar
*
* REFACTORED moved to service class PasswordManagement
*
* @param string $type two types are available 'resetPassword' or 'registration', default is 'registration'
* @param array $aUser
* @param null $newPassword
* @return LimeMailer if send is successfull
* @throws \PHPMailer\PHPMailer\Exception
*/
/*
public function sendAdminMail($aUser, $type = 'registration')
{
Expand Down Expand Up @@ -1327,16 +1332,20 @@ public function sendAdminMail($aUser, $type = 'registration')
$mailer->sendMessage();
return $mailer;
}
*/

/**
* Resets the password for one user
*
* REFACTORED moved to service class PasswordManagement
*
* @param User $oUser User model
* @param bool $sendMail Send a mail to the user
* @return array [success, uid, username, password]
* @throws CException
* @throws \PHPMailer\PHPMailer\Exception
*/
/*
public function resetLoginData(&$oUser, $sendMail = false)
{
$newPassword = $this->getRandomPassword(8);
Expand All @@ -1350,7 +1359,7 @@ public function resetLoginData(&$oUser, $sendMail = false)
return [
'success' => $success, 'uid' => $oUser->uid, 'username' => $oUser->users_name, 'password' => $newPassword,
];
}
}*/

/**
* todo this should not be in a controller, find a better place for it (view)
Expand Down Expand Up @@ -1411,16 +1420,22 @@ protected function getRandomString()
/**
*
* This function prepare the email template to send to the new created user
*
* REFACTORED NOW IN service class PasswordManagement
*
*
* @param string $fullname
* @param string $username
* @param string $password
* @return mixed $aAdminEmail array with subject and email nody
*/
/*
public function generateAdminCreationEmail($fullname, $username, $password, $iNewUID)
{
$aAdminEmail = [];
$siteName = Yii::app()->getConfig("sitename");
$loginUrl = $this->createAbsoluteUrl("/admin");
//todo instead of login url it should be link for setting a password
//$loginUrl = $this->createAbsoluteUrl("/admin");
$siteAdminEmail = Yii::app()->getConfig("siteadminemail");
$emailSubject = Yii::app()->getConfig("admincreationemailsubject");
$emailTemplate = Yii::app()->getConfig("admincreationemailtemplate");
Expand All @@ -1442,14 +1457,13 @@ public function generateAdminCreationEmail($fullname, $username, $password, $iNe
$emailTemplate = str_replace("{SITEADMINEMAIL}", $siteAdminEmail, $emailTemplate);
$emailTemplate = str_replace("{FULLNAME}", $fullname, $emailTemplate);
$emailTemplate = str_replace("{USERNAME}", $username, $emailTemplate);
$emailTemplate = str_replace("{PASSWORD}", $password, $emailTemplate);
$emailTemplate = str_replace("{LOGINURL}", $loginUrl, $emailTemplate);
// $emailTemplate = str_replace("{LOGINURL}", $loginUrl, $emailTemplate);
$aAdminEmail['subject'] = $emailSubject;
$aAdminEmail['body'] = $emailTemplate;
return $aAdminEmail;
}
} */

/**
* Adds permission to a users
Expand Down
43 changes: 43 additions & 0 deletions application/controllers/admin/authentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,49 @@ public static function prepareLogin()
return $aData;
}

/**
* This action sets a password for new user or resets a password for an existing user.
* If validation time is expired, no password will be changed.
*
* @param $param string the validation key
*/
public function newPassword($param){

$errorExists = false;
$errorMsg = '';
$user = User::model()->findByAttributes([],'validation_key=:validation_key', ['validation_key' => $param]);
if($user===null){
$errorExists = true;
$errorMsg = gT('The validation key is invalid. Please contact the administrator.');
}else{
//check if validation time is expired
$dateNow = new DateTime();
$expirationDate = new DateTime($user->validation_key_expiration);
$dateDiff = $expirationDate->diff($dateNow);
$differenceInHours = $dateDiff->format('h');
if($differenceInHours > User::MAX_EXPIRATION_TIME){
$errorExists = true;
$errorMsg = gT('The validation key expired. Please contact the administrator.');
}
}

if(!$errorExists){
//check if password is set correctly
$password = Yii::app()->request->getPost('password');
$passwordRepeat = Yii::app()->request->getPost('passwordRepeat');
if($password!==null && $passwordRepeat!==null){

}
$randomPassword = $this->getRandomPassword();
}

$this->$this->render('newPassword',[
'errorExists' => $errorExists,
'errorMasg' => $errorMsg,
'randomPassword', $randomPassword
]);
}

/**
* Logout user
* @return void
Expand Down
9 changes: 6 additions & 3 deletions application/core/LsDefaultDataSets.php
Original file line number Diff line number Diff line change
Expand Up @@ -2859,19 +2859,22 @@ public static function mockTranslateArrayContainer()
}

/**
* Email content for registration email (subject and body)
* Default user administration global configuration settings
*
* @return array with user administration default setting
* ['sendadmincreationemail'] set to 1, to indicate that email should be send?
*/
public static function getDefaultUserAdministrationSettings()
{
$default = [];
$template = "<p>" . gT("Hello") . " {FULLNAME}, </p>";
$template .= "<p>" . gT("this is an automated email to notify that a user has been created for you on the website") . "<strong> '{SITENAME}'</strong>.</p>";
$template .= "<p></p><p>" . gT("You can use now the following credentials to log in") . ":</p>";
$template .= "<p></p><p>" . gT("You can use now the following link to create your own password") . ":</p>";
$template .= "<p><strong>" . gT("Username") . "</strong>: {USERNAME}</p>";
$template .= "<p><strong>" . gt("Password") . "</strong>: {PASSWORD}</p>";
$template .= '<p><a href="{LOGINURL}">' . gT("Click here to login") . '</a></p>';
//don't send password anymore, just send a link for the new admin to generate his own password
//$template .= "<p><strong>" . gt("Password") . "</strong>: {PASSWORD}</p>";
$template .= '<p><a href="{LOGINURL}">' . gT("Click here to set your password") . '</a></p>';
$template .= "<p>" . gT("If you have any questions regarding this email, please do not hesitate to contact the site administrator at") . " {SITEADMINEMAIL}.</p><p> </p>";
$template .= "<p>" . gT("Thank you") . "!</p>";

Expand Down
18 changes: 18 additions & 0 deletions application/helpers/update/updatedb_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -3763,6 +3763,24 @@ function ($v) {
$oDB->createCommand()->addColumn('{{users}}', 'validation_key', 'string(38)');
$oDB->createCommand()->addColumn('{{users}}', 'validation_key_expiration', 'datetime');

//override existing email text (take out password there)
$sqlGetAdminCreationEmailTemplat = 'SELECT stg_value FROM {{settings_global}} WHERE stg_name="admincreationemailtemplate"';
$adminCreationEmailTemplateValue = $oDB->createCommand($sqlGetAdminCreationEmailTemplat)->queryAll();
if($adminCreationEmailTemplateValue){
if($adminCreationEmailTemplateValue[0]['stg_value'] === null || $adminCreationEmailTemplateValue[0]['stg_value']===''){
// if text in admincreationemailtemplate is empty use the default from LsDafaultDataSets
$defaultCreationEmailContent = LsDefaultDataSets::getDefaultUserAdministrationSettings();
$replaceValue = $defaultCreationEmailContent['admincreationemailtemplate'];
}else{ // if not empty replace PASSWORD with *** and write it back to DB
$replaceValue = str_replace('PASSWORD','***',$adminCreationEmailTemplateValue[0]['stg_value']);
}
$oDB->createCommand()->update(
'{{settings_global}}',
array('stg_value' => $replaceValue),
"stg_name='admincreationemailtemplate'"
);
}

$oDB->createCommand()->update('{{settings_global}}', array('stg_value' => 442), "stg_name='DBVersion'");
$oTransaction->commit();
}
Expand Down
26 changes: 26 additions & 0 deletions application/models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -927,4 +927,30 @@ public function search()
)
));
}

/**
* Creates a validation key and saves it in table user for this user.
*
* @return bool true if validation_key could be saved in db, false otherwise
*/
public function setValidationKey(){
$this->validation_key = randomChars(self::MAX_VALIDATION_KEY_LENGTH);

return $this->save();
}

/**
* Creates the validation key expiration date and save it in db
*
* @return bool true if datetime could be saved, false otherwise
* @throws Exception
*/
public function setValidationExpiration(){
$datePlusMaxExpiration = new DateTime();
$datePlusMaxExpiration->add(new DateInterval('P'. self::MAX_EXPIRATION_TIME . 'h'));

$this->validation_key_expiration = $datePlusMaxExpiration->format('Y-m-d H:i:s');

return $this->save();
}
}

0 comments on commit 43dc20f

Please sign in to comment.