Add 'form->addPasswordRule' in order to centralize pass validation

- Add password validation in user_add.php/user_edit.php
- New security functions added: getPasswordRequirements/getPasswordRequirementsToString
- See BT#12571
pull/2487/head
jmontoyaa 9 years ago
parent dae7793b9f
commit e19d6b1d5b
  1. 4
      main/admin/configure_inscription.php
  2. 3
      main/admin/user_add.php
  3. 2
      main/admin/user_edit.php
  4. 10
      main/auth/inscription.php
  5. 4
      main/auth/profile.php
  6. 56
      main/inc/lib/api.lib.php
  7. 41
      main/inc/lib/formvalidator/FormValidator.class.php
  8. 54
      main/inc/lib/security.lib.php

@ -218,9 +218,7 @@ if ($display_all_form) {
$form->addRule('pass1', get_lang('ThisFieldIsRequired'), 'required'); $form->addRule('pass1', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule('pass2', get_lang('ThisFieldIsRequired'), 'required'); $form->addRule('pass2', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule(array('pass1', 'pass2'), get_lang('PassTwo'), 'compare'); $form->addRule(array('pass1', 'pass2'), get_lang('PassTwo'), 'compare');
if (CHECK_PASS_EASY_TO_FIND === true) { $form->addPasswordRule('pass1');
$form->addRule('pass1', get_lang('PassTooEasy').': '.api_generate_password(), 'callback', 'api_check_password');
}
// PHONE // PHONE
$form->addElement('text', 'phone', get_lang('Phone'), array('size' => 40, 'disabled' => 'disabled')); $form->addElement('text', 'phone', get_lang('Phone'), array('size' => 40, 'disabled' => 'disabled'));

@ -210,6 +210,7 @@ $group[] = $form->createElement(
); );
$form->addGroup($group, 'password', get_lang('Password')); $form->addGroup($group, 'password', get_lang('Password'));
$form->addPasswordRule('password', 'password');
$form->addGroupRule('password', get_lang('EnterPassword'), 'required', null, 1); $form->addGroupRule('password', get_lang('EnterPassword'), 'required', null, 1);
if ($checkPass) { if ($checkPass) {
@ -472,3 +473,5 @@ $tpl = new Template($tool_name);
$tpl->assign('message', $message); $tpl->assign('message', $message);
$tpl->assign('content', $content); $tpl->assign('content', $content);
$tpl->display_one_col_template(); $tpl->display_one_col_template();

@ -231,7 +231,9 @@ $group[] = $form->createElement(
null, null,
array('onkeydown' => 'javascript: password_switch_radio_button();') array('onkeydown' => 'javascript: password_switch_radio_button();')
); );
$form->addGroup($group, 'password', null, null, false); $form->addGroup($group, 'password', null, null, false);
$form->addPasswordRule('password', 'password');
// Status // Status
$status = array(); $status = array();

@ -178,15 +178,7 @@ if ($user_already_registered_show_terms === false) {
$form->addRule('pass1', get_lang('ThisFieldIsRequired'), 'required'); $form->addRule('pass1', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule('pass2', get_lang('ThisFieldIsRequired'), 'required'); $form->addRule('pass2', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule(array('pass1', 'pass2'), get_lang('PassTwo'), 'compare'); $form->addRule(array('pass1', 'pass2'), get_lang('PassTwo'), 'compare');
$form->addPasswordRule('pass1');
if (CHECK_PASS_EASY_TO_FIND === true) {
$form->addRule(
'pass1',
get_lang('PassTooEasy') . ': ' . api_generate_password(),
'callback',
'api_check_password'
);
}
// PHONE // PHONE
if (in_array('phone', $allowedFields)) { if (in_array('phone', $allowedFields)) {

@ -316,9 +316,7 @@ if (is_platform_authentication() &&
$form->addElement('password', 'password2', get_lang('Confirmation'), array('size' => 40)); $form->addElement('password', 'password2', get_lang('Confirmation'), array('size' => 40));
// user must enter identical password twice so we can prevent some user errors // user must enter identical password twice so we can prevent some user errors
$form->addRule(array('password1', 'password2'), get_lang('PassTwo'), 'compare'); $form->addRule(array('password1', 'password2'), get_lang('PassTwo'), 'compare');
if (CHECK_PASS_EASY_TO_FIND === true) { $form->addPasswordRule('password1');
$form->addRule('password1', get_lang('CurrentPasswordEmptyOrIncorrect'), 'callback', 'api_check_password');
}
} }
$extraField = new ExtraField('user'); $extraField = new ExtraField('user');

@ -2008,29 +2008,24 @@ function api_generate_password($length = 8)
* 2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed. * 2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
* 3. The password should contain at least 3 letters. * 3. The password should contain at least 3 letters.
* 4. It should contain at least 2 digits. * 4. It should contain at least 2 digits.
* 5. It should not contain 3 or more consequent (according to ASCII table) characters.
* Settings will change if the configuration value is set: password_requirements * Settings will change if the configuration value is set: password_requirements
*/ */
function api_check_password($password) function api_check_password($password)
{ {
$passwordRequirements = api_get_configuration_value('password_requirements'); $passwordRequirements = Security::getPasswordRequirements();
$minLength = 5;
$minLetters = 3;
$minNumbers = 2;
$minLowerCase = 0; // Is only use if password_requirements is set
$minUpperCase = 0; // Is only use if password_requirements is set
if (!empty($passwordRequirements)) {
$minLength = $passwordRequirements['min']['length']; $minLength = $passwordRequirements['min']['length'];
$minNumbers = $passwordRequirements['min']['numeric']; $minNumbers = $passwordRequirements['min']['numeric'];
// Optional
$minLowerCase = $passwordRequirements['min']['lowercase']; $minLowerCase = $passwordRequirements['min']['lowercase'];
$minUpperCase = $passwordRequirements['min']['uppercase']; $minUpperCase = $passwordRequirements['min']['uppercase'];
$minLetters = $minLowerCase + $minUpperCase; $minLetters = $minLowerCase + $minUpperCase;
}
$passwordLength = api_strlen($password); $passwordLength = api_strlen($password);
if ($passwordLength < $minLength) {
return false; $conditions = [
} 'min_length' => $passwordLength >= $minLength
];
$digits = 0; $digits = 0;
$lowerCase = 0; $lowerCase = 0;
@ -2049,17 +2044,40 @@ function api_check_password($password)
$digits++; $digits++;
} }
} }
// Min number of digits
$conditions['min_numeric'] = $digits >= $minNumbers;
if (!empty($minUpperCase)) {
// Uppercase
$conditions['min_uppercase'] = $upperCase >= $minUpperCase;
}
if (!empty($minLowerCase)) {
// Lowercase
$conditions['min_lowercase'] = $upperCase >= $minLowerCase;
}
// Min letters
$letters = $upperCase + $lowerCase; $letters = $upperCase + $lowerCase;
$conditions['min_letters'] = $letters >= $minLetters;
if (!empty($passwordRequirements)) { $isPasswordOk = true;
return ( foreach ($conditions as $condition) {
$upperCase >= $minUpperCase && if ($condition === false) {
$lowerCase >= $minLowerCase && $isPasswordOk = false;
$digits >= $minNumbers break;
); }
}
if ($isPasswordOk === false) {
$output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
$output .= Security::getPasswordRequirementsToString($conditions);
Display::addFlash(Display::return_message($output, 'warning', false));
} }
return $letters >= $minLetters && $digits >= $minNumbers; return $isPasswordOk;
} }
/** /**

@ -1679,6 +1679,47 @@ EOT;
}); });
</script>"); </script>");
} }
/**
* @param string $elementName
* @param string $groupName if element is inside a group
* @throws Exception
*/
public function addPasswordRule($elementName, $groupName = '')
{
// Constant defined in old config/profile.conf.php
if (CHECK_PASS_EASY_TO_FIND === true) {
$message = get_lang('PassTooEasy').': '.api_generate_password();
if (!empty($groupName)) {
$groupObj = $this->getElement($groupName);
if ($groupObj instanceof HTML_QuickForm_group) {
$elementName = $groupObj->getElementName($elementName);
if ($elementName === false) {
throw new Exception("The $groupName doesn't have the element $elementName");
}
$this->_rules[$elementName][] = array(
'type' => 'callback',
'format' => 'api_check_password',
'message' => $message,
'validation' => '',
'reset' => false,
'group' => $groupName
);
}
} else {
$this->addRule(
$elementName,
$message,
'callback',
'api_check_password'
);
}
}
}
} }
/** /**

@ -432,4 +432,58 @@ class Security
} }
return $image_path; return $image_path;
} }
/**
* Get password requirements
* It checks config value 'password_requirements' or uses the "classic"
* Chamilo password requirements.
*
* @return array
*/
public static function getPasswordRequirements()
{
// Default
$requirements = [
'min' => [
'lowercase' => 0,
'uppercase' => 0,
'numeric' => 2,
'length' => 5
]
];
$passwordRequirements = api_get_configuration_value('password_requirements');
if (!empty($passwordRequirements)) {
$requirements = $passwordRequirements;
}
return $requirements;
}
/**
* Gets password requirements in the platform language using get_lang
* based in platform settings. See function 'self::getPasswordRequirements'
* @return string
*/
public static function getPasswordRequirementsToString($passedConditions = [])
{
$output = '';
$setting = Security::getPasswordRequirements();
foreach ($setting as $type => $rules) {
foreach ($rules as $rule => $parameter) {
if (empty($parameter)) {
continue;
}
$output .= sprintf(
get_lang(
'NewPasswordRequirement'.ucfirst($type).'X'.ucfirst($rule)
),
$parameter
);
$output .= '<br />';
}
}
return $output;
}
} }

Loading…
Cancel
Save