Rewrite generate password and check password - requires composer update

- Added ircmaxell/random-lib lib to improve security.
- Add 'password_requirements' setting see BT#12571 to customize min
requirements.
pull/2487/head
jmontoyaa 9 years ago
parent 9105ea5cf7
commit 807cf5697b
  1. 3
      composer.json
  2. 119
      main/inc/lib/api.lib.php
  3. 3
      main/inc/lib/internationalization.lib.php
  4. 9
      main/install/configuration.dist.php

@ -104,7 +104,8 @@
"kigkonsult/icalcreator" : "0.1.0", "kigkonsult/icalcreator" : "0.1.0",
"essence/essence": "2.6.1", "essence/essence": "2.6.1",
"pclzip/pclzip": "2.8.2", "pclzip/pclzip": "2.8.2",
"chamilo/chash": "dev-master" "chamilo/chash": "dev-master",
"ircmaxell/random-lib": "^1.2"
}, },
"require-dev": { "require-dev": {
"behat/behat": "@stable", "behat/behat": "@stable",

@ -1953,22 +1953,49 @@ function api_format_course_array($course_data)
*/ */
function api_generate_password($length = 8) function api_generate_password($length = 8)
{ {
$characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$numbers = '23456789';
if ($length < 2) { if ($length < 2) {
$length = 2; $length = 2;
} }
$charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
$charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
$minNumbers = 2;
$length = $length - $minNumbers;
$minLowerCase = round($length/2);
$minUpperCase = $length - $minLowerCase;
$password = ''; $password = '';
for ($i = 0; $i < $length; $i ++) { $passwordRequirements = api_get_configuration_value('password_requirements');
$password .= $characters[rand() % strlen($characters)];
$factory = new RandomLib\Factory();
$generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
if (!empty($passwordRequirements)) {
$length = $passwordRequirements['min']['length'];
$minNumbers = $passwordRequirements['min']['numeric'];
$minLowerCase = $passwordRequirements['min']['lowercase'];
$minUpperCase = $passwordRequirements['min']['uppercase'];
$rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
// Add the rest to fill the length requirement
if ($rest > 0) {
$password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
}
} }
// At least 2 digits // Min digits default 2
for ($i = 0; $i < 2; $i ++) { for ($i = 0; $i < $minNumbers; $i ++) {
$password .= $numbers[rand() % strlen($numbers)]; $password .= $generator->generateInt(2, 9);
} }
// Min lowercase
$password .= $generator->generateString($minLowerCase, $charactersLowerCase);
// Min uppercase
$password .= $generator->generateString($minUpperCase, $charactersUpperCase);
$password = str_shuffle($password);
return $password; return $password;
} }
@ -1982,37 +2009,57 @@ function api_generate_password($length = 8)
* 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. * 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) { */
$password_length = api_strlen($password); function api_check_password($password)
if ($password_length < 5) { {
$passwordRequirements = api_get_configuration_value('password_requirements');
$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;
}
$passwordLength = api_strlen($password);
if ($passwordLength < $minLength) {
return false; return false;
} }
$password = api_strtolower($password);
$letters = 0;
$digits = 0; $digits = 0;
$consequent_characters = 0; $lowerCase = 0;
$previous_character_code = 0; $upperCase = 0;
for ($i = 0; $i < $password_length; $i ++) {
$current_character_code = api_ord(api_substr($password, $i, 1)); for ($i = 0; $i < $passwordLength; $i++) {
if ($i && abs($current_character_code - $previous_character_code) <= 1) { $currentCharacterCode = api_ord(api_substr($password, $i, 1));
$consequent_characters ++; if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
if ($consequent_characters == 3) { $upperCase++;
return false;
}
} else {
$consequent_characters = 1;
} }
if ($current_character_code >= 97 && $current_character_code <= 122) {
$letters ++; if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
} elseif ($current_character_code >= 48 && $current_character_code <= 57) { $lowerCase++;
$digits ++; }
} else { if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
return false; $digits++;
} }
$previous_character_code = $current_character_code;
} }
return ($letters >= 3 && $digits >= 2); $letters = $upperCase + $lowerCase;
if (!empty($passwordRequirements)) {
return (
$upperCase >= $minUpperCase &&
$lowerCase >= $minLowerCase &&
$digits >= $minNumbers
);
}
return $letters >= $minLetters && $digits >= $minNumbers;
} }
/** /**
@ -2040,7 +2087,8 @@ function api_clear_anonymous($db_check = false)
* @author Noel Dieschburg * @author Noel Dieschburg
* @param the int status code * @param the int status code
*/ */
function get_status_from_code($status_code) { function get_status_from_code($status_code)
{
switch ($status_code) { switch ($status_code) {
case STUDENT: case STUDENT:
return get_lang('Student', ''); return get_lang('Student', '');
@ -2062,7 +2110,8 @@ function get_status_from_code($status_code) {
* time we get on a course homepage or on a neutral page (index, admin, my space) * time we get on a course homepage or on a neutral page (index, admin, my space)
* @return bool true if set user as anonymous, false if user was already logged in or anonymous id could not be found * @return bool true if set user as anonymous, false if user was already logged in or anonymous id could not be found
*/ */
function api_set_anonymous() { function api_set_anonymous()
{
global $_user; global $_user;
if (!empty($_user['user_id'])) { if (!empty($_user['user_id'])) {

@ -1092,7 +1092,8 @@ function api_transliterate($string, $unknown = '?', $from_encoding = null)
* @link http://php.net/manual/en/function.ord.php * @link http://php.net/manual/en/function.ord.php
* Note the difference with the original funtion ord(): ord('') returns 0, api_ord('') returns 0xFFFD (unknown character). * Note the difference with the original funtion ord(): ord('') returns 0, api_ord('') returns 0xFFFD (unknown character).
*/ */
function api_ord($character, $encoding = null) { function api_ord($character, $encoding = 'UTF-8')
{
return Utf8::ord(api_utf8_encode($character, $encoding)); return Utf8::ord(api_utf8_encode($character, $encoding));
} }

@ -310,3 +310,12 @@ $_configuration['system_stable'] = NEW_VERSION_STABLE;
// $_configuration['hide_lp_time'] = false; // $_configuration['hide_lp_time'] = false;
// Hide rating elements in pages ("Courses catalog" & "Most Popular courses") // Hide rating elements in pages ("Courses catalog" & "Most Popular courses")
// $_configuration['hide_course_rating'] = false; // $_configuration['hide_course_rating'] = false;
// Customize password generation and verification
/*$_configuration['password_requirements'] = [
'min' => [
'lowercase' => 2,
'uppercase' => 2,
'numeric' => 2,
'length' => 8
]
];*/

Loading…
Cancel
Save