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. 66
      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('pass2', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule(array('pass1', 'pass2'), get_lang('PassTwo'), 'compare');
if (CHECK_PASS_EASY_TO_FIND === true) {
$form->addRule('pass1', get_lang('PassTooEasy').': '.api_generate_password(), 'callback', 'api_check_password');
}
$form->addPasswordRule('pass1');
// PHONE
$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->addPasswordRule('password', 'password');
$form->addGroupRule('password', get_lang('EnterPassword'), 'required', null, 1);
if ($checkPass) {
@ -472,3 +473,5 @@ $tpl = new Template($tool_name);
$tpl->assign('message', $message);
$tpl->assign('content', $content);
$tpl->display_one_col_template();

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

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

@ -316,9 +316,7 @@ if (is_platform_authentication() &&
$form->addElement('password', 'password2', get_lang('Confirmation'), array('size' => 40));
// user must enter identical password twice so we can prevent some user errors
$form->addRule(array('password1', 'password2'), get_lang('PassTwo'), 'compare');
if (CHECK_PASS_EASY_TO_FIND === true) {
$form->addRule('password1', get_lang('CurrentPasswordEmptyOrIncorrect'), 'callback', 'api_check_password');
}
$form->addPasswordRule('password1');
}
$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.
* 3. The password should contain at least 3 letters.
* 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
*/
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'];
$minNumbers = $passwordRequirements['min']['numeric'];
$minLowerCase = $passwordRequirements['min']['lowercase'];
$minUpperCase = $passwordRequirements['min']['uppercase'];
$minLetters = $minLowerCase + $minUpperCase;
}
$minLength = $passwordRequirements['min']['length'];
$minNumbers = $passwordRequirements['min']['numeric'];
// Optional
$minLowerCase = $passwordRequirements['min']['lowercase'];
$minUpperCase = $passwordRequirements['min']['uppercase'];
$minLetters = $minLowerCase + $minUpperCase;
$passwordLength = api_strlen($password);
if ($passwordLength < $minLength) {
return false;
}
$conditions = [
'min_length' => $passwordLength >= $minLength
];
$digits = 0;
$lowerCase = 0;
@ -2049,17 +2044,40 @@ function api_check_password($password)
$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;
$conditions['min_letters'] = $letters >= $minLetters;
if (!empty($passwordRequirements)) {
return (
$upperCase >= $minUpperCase &&
$lowerCase >= $minLowerCase &&
$digits >= $minNumbers
);
$isPasswordOk = true;
foreach ($conditions as $condition) {
if ($condition === false) {
$isPasswordOk = false;
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>");
}
/**
* @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;
}
/**
* 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