Task #2309 mot de passe fort

This commit is contained in:
sparkyx 2023-12-02 18:01:53 +01:00
parent 86852bc425
commit a0d1c26eaf
10 changed files with 296 additions and 35 deletions

View file

@ -113,7 +113,22 @@ if ($op == "progressBar") {
return;
}
//-------------------------------------------------------------------------------------------
// check password
//-------------------------------------------------------------------------------------------
if ($op=='password_chk') {
$cnt = $http->request("pass");
$result=check_password_strength($cnt)['msg'];
if (count($result) == 0) {
echo json_response(["password" => "ok", "msg" => 0]);
} else {
$str="";
foreach ($result as $item) {$str.=sprintf("<li>%s</li>",$item);}
echo json_response(["password" => "nok", "msg" => '<ol>'.$str.'</ol>']);
}
return;
}
$html = var_export($_REQUEST, true);
set_language();
if ( LOGINPUT)

View file

@ -233,7 +233,19 @@ if (isset($_POST['save_config'])) {
$err++;
}
// check strenght password admin
$passw_error=check_password_strength($cpassword_admin);
if ( count($passw_error['msg'])>0) {
echo '<h2 class="warning">';
echo _("Mot de passe trop faible");
echo '</h2>';
echo '<ol>';
foreach ($passw_error['msg'] as $error) {
echo "<li>",$error,"</li>";
}
echo '</ol>';
$err++;
}
// check password and admin not containing quote or double quote
//
if ( strpos($cpassword_admin,'"') !== false

View file

@ -3786,9 +3786,13 @@ function updatePreference()
method: "post",
parameters: param,
onSuccess: function (req) {
var style = req.responseText.evalJSON();
var answer = req.responseText.evalJSON();
// $('pagestyle').setAttribute('href', style.style);
removeDiv('preference_div');
if ( answer['psw']=='NOK') {
smoke.alert(answer['msg']);
} else {
removeDiv('preference_div');
}
}
});
} catch (e)
@ -4224,4 +4228,50 @@ function event_display_main(p_dossier) {
{
alert_box(e.message);
}
}
/**
* @brief check if password is strong or not, update a DIV element
* @param p_pass_domid DOM ID of the INPUT element with the password
* @param p_result_domid DOM ID of the element to update
*/
function check_password_strength(p_pass_domid,p_result_domid,details)
{
try
{
if ( $(p_pass_domid).value=="") { $(p_result_domid).update("");return;}
var queryString= {
'op':"password_chk"
,pass:$(p_pass_domid).value
};
var action = new Ajax.Request(
"ajax_misc.php" ,
{
method:'GET',
parameters:queryString,
onFailure:ajax_misc_failure,
onSuccess:function(req){
remove_waiting_box();
if (req.responseText == 'NOCONX') {
return;
}
var answer=req.responseJSON;
console.debug(answer);
if (answer['password']=='nok') {
$(p_pass_domid).setStyle("background-color:red");
if ( details) {
$(p_result_domid).update(answer['msg'])
}
return;
}
$(p_pass_domid).setStyle("background-color: lightgreen");
$(p_result_domid).update("")
}
}
);
}catch( e)
{
alert_box(e.message);
}
}

View file

@ -84,8 +84,9 @@ if ( $action == 'display_form' )
<tr><td>
Mot de passe :
</td>
<td><input type="password" value="" class="input_text" name="pass_1" nohistory>
<td><input type="password" value="" class="input_text" name="pass_1" id="pass_1" nohistory onkeyup=check_password_strength('pass_1','info_passid',1)>
<input type="password" value="" class="input_text" name="pass_2" nohistory>
<span id="info_passid"></span>
</td>
</tr>
@ -321,20 +322,32 @@ if ($action == 'save')
$csv_decimal=$http->post("csv_decimal","number");
$csv_encoding=$http->post("csv_encoding");
$firstday=$http->post("selFirstDay","number");
$password="OK";
$msg ="";
if (noalyss_strlentrim($pass_1) != 0 && noalyss_strlentrim($pass_2) != 0)
{
if ( $g_user->save_password($_POST['pass_1'],$pass_2) )
{ $g_user->password_to_session() ;
{
$g_user->password_to_session() ;
} else {
/**
* password not changed
*/
*/
$password="NOK";
$msg="";
if ( $_POST['pass_1'] !== $pass_2) {
$msg = _("Mot de passe ne correspondent pas");
$msg .="<br/>";
}
$a_pass_error=check_password_strength($_POST['pass_1']);
if ( count($a_pass_error['msg']) != 0 ) {
foreach($a_pass_error['msg'] as $pass_error) {
$msg.=$pass_error."<br/>";
}
}
}
}
if ( $inside_dossier)
{
@ -366,6 +379,6 @@ if ($action == 'save')
{
$style = "style-classic7.css";
}
json_response(["style"=>$style]);
json_response(["style"=>$style,'psw'=>$password,'msg'=>$msg]);
}

View file

@ -1635,11 +1635,12 @@ class Noalyss_User
* @brief Save the password of the current user
* @param string $p_pass1 password (clear)
* @param string $p_pass2 for confirming password (clear)
* @see check_password_strength()
* @return true : password successfully changed otherwise false
*/
function save_password($p_pass1, $p_pass2)
{
if ($p_pass1==$p_pass2)
if ($p_pass1==$p_pass2 && count(check_password_strength($p_pass1)['msg'])==0)
{
$repo=new Database();
$l_pass=md5($p_pass1);

View file

@ -1416,10 +1416,13 @@ function remove_divide_zero($p_formula)
* @brief Create randomly a string
* @param int $p_length length of the generate string
*/
function generate_random_string($p_length)
function generate_random_string($p_length,$special=1)
{
$string="";
$chaine="abcdefghijklmnpqrstuvwxyABCDEFGHIJKLMNPQRSTUVWXY0123456789*/+-=";
if ($special == 1)
$chaine="abcdefghijklmnpqrstuvwxyABCDEFGHIJKLMNPQRSTUVWXY0123456789*/+-=";
if ($special == 0)
$chaine="abcdefghijklmnpqrstuvwxyABCDEFGHIJKLMNPQRSTUVWXY0123456789";
$microtime=microtime(true)*microtime(true)*100;
srand(0);
srand((int)$microtime);
@ -1663,3 +1666,111 @@ function MaintenanceMode($p_file)
exit;
}
}
/**
* @brief returns an double array with the error found and code , if the count is 0 then the password is very string, 5 means it is
* empty ,4 weak, ... the array contains the errors, [msg]=>array message [code] => array of code
* Codes are
* - 1 : too short
* - 2 : missing digit
* - 3 : missing lowercase letter
* - 4 : missing uppercase letter
* - 5 : too many time same letter or symbol..
* - 6 : missing special char
*
* If the password is strong returns an empty array
*
* @param $password string
* @code
$error = check_password_strength($password);
if ( count($error['msg']) > 0 ) {
echo "password to weak";
foreach ($error['msg'] as $item_error) {
echo "error $item_error";
}
} else {
echo "OK password strong";
}
* @endcode
*/
function check_password_strength($password) {
$errors=array();
$error_code=array();
$len=strlen($password??"");
if ( $len < 8) {
$errors[] = _("mot de passe de 8 lettres minimum");
$error_code[]=1;
}
if (!preg_match("#[0-9]+#", $password)) {
$errors[] = _("mot de passe doit inclure au moins un chiffre");
$error_code[]=2;
}
if (!preg_match("#[a-z]+#", $password)) {
$errors[] = _("mot de passe doit inclure au moins une minuscule");
$error_code[]=3;
}
if (!preg_match("#[A-Z]+#", $password)) {
$errors[] = _("mot de passe doit inclure au moins une majuscule");
$error_code[]=4;
}
if ( $len > 0 ) {
$cnt_diff=count(count_chars($password,1));
$ratio_diff=$len/$cnt_diff;
if ($ratio_diff > 2) {
$errors[] = _("Trop souvent le(s) même(s) symbole(s)");
$error_code[]=5;
}
$special_char=preg_replace('/[[:alnum:]]/','',$password);
if ( strlen($special_char??"")==0)
{
$errors[] = _("mot de passe doit inclure au moins un caractére spécial '+-/*[...'");
$error_code[]=6;
}
}
return array( 'msg'=>$errors, 'code'=>$error_code);
}
/**
* @brief generate a strong random password
* @param $car int length of the password, minimum 8
*
*/
function generate_random_password($car):string
{
$string="";
$car=($car < 8 )?8:$car;
$max_loop=20;$loop=0;
do
{
$loop++;
$string="";
$chaine="abcdefghijklmnpqrstuvwxy";
// srand( (int)microtime()*1020030);
for ($i=0; $i<$car; $i++)
{
$string .= $chaine[rand()%strlen($chaine)];
}
$chaine="ABCDEFGHIJKLMNPQRSTUVWXY";
for ($i=0;$i<2;$i++) {
$string[rand()%$car]=$chaine[rand()%strlen($chaine)];;
}
$chaine="0123456789";
for ($i=0;$i<2;$i++) {
$string[rand()%$car]=$chaine[rand()%strlen($chaine)];;
}
$special_set="+-/*;,.=:&()[]";
$special_car=$special_set[rand()%strlen($special_set)];
$string[rand()%$car]=$special_car;
// echo $string."\n";
}while ( count(check_password_strength($string)['msg'])> 0 && $loop<$max_loop);
return $string;
}

View file

@ -17,27 +17,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Copyright (2014) Author Dany De Bontridder <dany@alchimerys.be>
require_once NOALYSS_INCLUDE.'/lib/ac_common.php';
if (!defined('RECOVER'))
die('Appel direct ne sont pas permis');
define('SIZE_REQUEST', 70);
/**
* @brief generate a random string of char
* @param $car int length of the string
*/
function generate_random($car)
{
$string="";
$chaine="abcdefghijklmnpqrstuvwxyABCDEFGHIJKLMNPQRSTUVWXY0123456789";
srand((double) microtime()*1020030);
for ($i=0; $i<$car; $i++)
{
$string .= $chaine[rand()%strlen($chaine)];
}
return $string;
}
$http=new HttpInput();
/**
* @file
@ -89,8 +76,8 @@ elseif ($action=="send_email") :
if ($valid==true):
$request_id=generate_random(SIZE_REQUEST);
$user_password=generate_random(10);
$request_id=generate_random_string(SIZE_REQUEST,special: 0);
$user_password=generate_random_password(10);
// exist a valid request for this user ?
$exist_request= $cn->get_array("select request , password from recover_pass
where use_id=$1 and created_on > now() - interval '12 hours'",[$user_id]);

View file

@ -35,6 +35,7 @@ echo '<div class="content" >';
if ( isset ($_POST["ADD"]) )
{
$cn=new Database();
$a_result =check_password_strength($_POST['PASS']);
$pass5=md5($_POST['PASS']);
$new_user=new Noalyss_user($cn,0);
$new_user->first_name=$http->post('FNAME');
@ -45,11 +46,18 @@ if ( isset ($_POST["ADD"]) )
$login=str_replace(" ","",$login);
$login=strtolower($login);
$new_user->login=$login;
$new_user->setPassword($pass5);
$new_user->email=$http->post('EMAIL',"string",'');
if ( trim($login)=="")
{
alert(_("Le login ne peut pas être vide"));
}elseif (count($a_result['msg']) > 0){
// password too weak
$msg='<span class="warning">'._("Mot de passe inchangé").'</span>';
foreach ($a_result['msg'] as $result ) {
$msg.="$result <br/>";
}
alert($msg);
}
else
{
@ -101,8 +109,18 @@ if ($sbaction == "save")
}
if ( trim($_POST['password'])<>'')
{
$UserChange->setPassword(md5($_POST['password']));
$UserChange->save();
$a_result =check_password_strength($_POST['password']);
if (count($a_result['msg']) > 0){
// password too weak
$msg='<span class="warning">'._("Mot de passe inchangé").'</span>';
foreach ($a_result['msg'] as $result ) {
$msg.="$result <br/>";
}
alert($msg);
} else {
$UserChange->setPassword(md5($_POST['password']));
$UserChange->save();
}
}
else
{
@ -168,9 +186,19 @@ if ( isset($_REQUEST['det']) && $sbaction=="")
<TR><TD style="text-align: right"> <?php echo _('login')?></TD><TD><INPUT id="input_login" class="input_text" TYPE="TEXT" NAME="LOGIN"></TD></tr>
<TR><TD style="text-align: right"> <?php echo _('Prénom')?></TD><TD><INPUT class="input_text" TYPE="TEXT" NAME="FNAME"></TD></tr>
<TR><TD style="text-align: right"> <?php echo _('Nom')?></TD><TD><INPUT class="input_text" TYPE="TEXT" NAME="LNAME"></TD></TR>
<TR><TD style="text-align: right"> <?php echo _('Mot de passe')?></TD><TD> <INPUT id="input_password" class="input_text" TYPE="TEXT" NAME="PASS"></TD></TR>
<TR>
<TD style="text-align: right"> <?php echo _('Mot de passe')?>
<?=\Icon_Action::tips("Mot de passe : longueur minimale = 8 dont au moins 1 majuscule, 1 minuscule,1 chiffre et 1 car.spécial")?>
</TD>
<TD> <INPUT id="input_password" class="input_text" TYPE="TEXT" NAME="PASS"
onkeyup=check_password_strength('input_password','info_passid')
>
<span id="info_passid"></span>
</TD></TR>
<TR><TD style="text-align: right"> <?php echo _('Email')?></TD><TD> <INPUT class="input_text" TYPE="TEXT" NAME="EMAIL"></TD></TR>
</TABLE>
<?php
echo HtmlInput::submit("ADD",_('Créer Utilisateur'),"",'button');
echo HtmlInput::button_action(_("Fermer"), "$('create_user').style.display='none';");

View file

@ -42,6 +42,7 @@ if ($UserChange->id == false)
$UserChange->load();
$it_pass=new IText('password');
$it_pass->javascript='onkeyup="check_password_strength(\'password\',\'password_info\',1)"';
$it_pass->value="";
?>
<FORM id="user_detail_frm" METHOD="POST">
@ -81,6 +82,7 @@ $it_pass->value="";
</td>
<td>
<?php echo $it_pass->input();?>
<span id="password_info" style="background-color: yellow;color:red;position:absolute"></span>
</td>
</tr>
<tr>

View file

@ -424,4 +424,46 @@ EOF;
$this->assertEquals(strtoupper($expect),strtoupper(preg_replace("/\s+/",'',faxTo('123'))),);
}
/**
* supply data for user password
* @return array[$password, $weakness] 0 means strong password
*/
public function dataCheck_password_strength()
{
return array(
["AAAAAAA",5]
,["123456789",3]
,["Az123456789",1]
,["",4]
,["+",4]
,["AAAA121212abx",2]
,["Az&123456789",0]
,["l5F8Cny=",0]
);
}
/**
* @testDoc test the check_password_strength function
* @dataProvider dataCheck_password_strength()
*/
public function testCheck_password_strength($p_password,$p_cnt)
{
$count=count(check_password_strength($p_password)['msg']);
$this->assertTrue($count ==$p_cnt,"error : $p_password weak password $count" );
}
public function testGenerate_strong_password()
{
for ($i = 0; $i < 100; $i++)
{
$pass=generate_random_password(5);
$this->assertTrue( count(check_password_strength($pass)['msg'])==0
,"error cannot generate strong password get $pass");
}
}
}