dolibarr  20.0.0-alpha
modGeneratePassPerso.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2006-2011 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2014 Teddy Andreotti <125155@supinfo.com>
4  * Copyright (C) 2017 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  * or see https://www.gnu.org/
20  */
21 
28 require_once DOL_DOCUMENT_ROOT.'/core/modules/security/generate/modules_genpassword.php';
29 
30 
35 {
39  public $id;
40 
41  public $picto = 'fa-shield-alt';
42 
43  public $NbMaj;
44  public $NbNum;
45  public $NbSpe;
46  public $NbRepeat;
47 
53  public $WithoutAmbi = 0;
54 
55  public $Maj;
56  public $Min;
57  public $Nb;
58  public $Spe;
59  public $Ambi;
60  public $All;
61 
70  public function __construct($db, $conf, $langs, $user)
71  {
72  $this->id = "Perso";
73  $this->length = $langs->trans("SetupPerso");
74 
75  $this->db = $db;
76  $this->conf = $conf;
77  $this->langs = $langs;
78  $this->user = $user;
79 
80  if (!getDolGlobalString('USER_PASSWORD_PATTERN')) {
81  // default value at auto generation (12 chars, 1 uppercase, 1 digit, 0 special char, 3 repeat max, exclude ambiguous characters).
82  dolibarr_set_const($db, "USER_PASSWORD_PATTERN", '12;1;1;0;3;1', 'chaine', 0, '', $conf->entity);
83  }
84 
85  $this->Maj = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
86  $this->Min = strtolower($this->Maj);
87  $this->Nb = "0123456789";
88  $this->Spe = "!@#$%&*()_-+={}[]\\|:;'/";
89  $this->Ambi = array("1", "I", "l", "|", "O", "0");
90 
91  $tabConf = explode(";", getDolGlobalString('USER_PASSWORD_PATTERN'));
92  $this->length2 = (int) $tabConf[0];
93  $this->NbMaj = $tabConf[1];
94  $this->NbNum = $tabConf[2];
95  $this->NbSpe = $tabConf[3];
96  $this->NbRepeat = $tabConf[4];
97  $this->WithoutAmbi = (int) $tabConf[5];
98  }
99 
105  private function initAll()
106  {
107  if ($this->WithoutAmbi) {
108  $this->Maj = str_replace($this->Ambi, "", $this->Maj);
109  $this->Min = str_replace($this->Ambi, "", $this->Min);
110  $this->Nb = str_replace($this->Ambi, "", $this->Nb);
111  $this->Spe = str_replace($this->Ambi, "", $this->Spe);
112  }
113 
114  $pattern = $this->Min.(!empty($this->NbMaj) ? $this->Maj : '').(!empty($this->NbNum) ? $this->Nb : '').(!empty($this->NbSpe) ? $this->Spe : '');
115  $this->All = str_shuffle($pattern);
116  }
117 
123  public function getDescription()
124  {
125  global $langs;
126  return $langs->trans("PasswordGenerationPerso");
127  }
128 
134  public function getExample()
135  {
136  return $this->getNewGeneratedPassword();
137  }
138 
146  public function getNewGeneratedPassword()
147  {
148  $this->initAll();
149 
150  $pass = "";
151  for ($i = 0; $i < $this->NbMaj; $i++) {
152  // Y
153  $pass .= $this->Maj[mt_rand(0, strlen($this->Maj) - 1)];
154  }
155 
156  for ($i = 0; $i < $this->NbNum; $i++) {
157  // X
158  $pass .= $this->Nb[mt_rand(0, strlen($this->Nb) - 1)];
159  }
160 
161  for ($i = 0; $i < $this->NbSpe; $i++) {
162  // @
163  $pass .= $this->Spe[mt_rand(0, strlen($this->Spe) - 1)];
164  }
165 
166  for ($i = strlen($pass); $i < $this->length2; $i++) {
167  // y
168  $pass .= $this->All[mt_rand(0, strlen($this->All) - 1)];
169  }
170 
171  $pass = str_shuffle($pass);
172 
173  if ($this->validatePassword($pass)) {
174  return $pass;
175  }
176 
177  return $this->getNewGeneratedPassword(); // warning, may generate infinite loop if conditions are not possible
178  }
179 
187  public function validatePassword($password)
188  {
189  global $langs;
190 
191  $this->initAll(); // For the case this method is called alone
192 
193  $password_a = preg_split('//u', $password, 0, PREG_SPLIT_NO_EMPTY);
194  $maj = preg_split('//u', $this->Maj, 0, PREG_SPLIT_NO_EMPTY);
195  $num = preg_split('//u', $this->Nb, 0, PREG_SPLIT_NO_EMPTY);
196  $spe = preg_split('//u', $this->Spe, 0, PREG_SPLIT_NO_EMPTY);
197  /*
198  $password_a = str_split($password);
199  $maj = str_split($this->Maj);
200  $num = str_split($this->Nb);
201  $spe = str_split($this->Spe);
202  */
203 
204  if (dol_strlen($password) < $this->length2) {
205  $langs->load("other");
206  $this->error = $langs->trans("YourPasswordMustHaveAtLeastXChars", $this->length2);
207  return 0;
208  }
209 
210  if (count(array_intersect($password_a, $maj)) < $this->NbMaj) {
211  $langs->load("other");
212  $this->error = $langs->trans('PasswordNeedAtLeastXUpperCaseChars', $this->NbMaj);
213  return 0;
214  }
215 
216  if (count(array_intersect($password_a, $num)) < $this->NbNum) {
217  $langs->load("other");
218  $this->error = $langs->trans('PasswordNeedAtLeastXDigitChars', $this->NbNum);
219  return 0;
220  }
221 
222  if (count(array_intersect($password_a, $spe)) < $this->NbSpe) {
223  $langs->load("other");
224  $this->error = $langs->trans('PasswordNeedAtLeastXSpecialChars', $this->NbSpe);
225  return 0;
226  }
227 
228  if (!$this->consecutiveIterationSameCharacter($password)) {
229  $langs->load("other");
230  $this->error = $langs->trans('PasswordNeedNoXConsecutiveChars', $this->NbRepeat);
231  return 0;
232  }
233 
234  return 1;
235  }
236 
243  public function consecutiveIterationSameCharacter($password)
244  {
245  $this->initAll();
246 
247  if (empty($this->NbRepeat)) {
248  return true;
249  }
250 
251  $char = preg_split('//u', $password, 0, PREG_SPLIT_NO_EMPTY);
252 
253  $last = "";
254  $count = 0;
255  foreach ($char as $c) {
256  if ($c != $last) {
257  $last = $c;
258  $count = 1;
259  //print "Char $c - count = $count\n";
260  continue;
261  }
262 
263  $count++;
264  //print "Char $c - count = $count\n";
265 
266  if ($count > $this->NbRepeat) {
267  return false;
268  }
269  }
270 
271  return true;
272  }
273 }
dolibarr_set_const($db, $name, $value, $type='chaine', $visible=0, $note='', $entity=1)
Insert a parameter (key,value) into database (delete old key then insert it again).
Definition: admin.lib.php:655
Parent class for password rules/management modules.
Class to generate a password according to personal rules.
validatePassword($password)
Validate a password.
consecutiveIterationSameCharacter($password)
Check the consecutive iterations of the same character.
__construct($db, $conf, $langs, $user)
Constructor.
getExample()
Return an example of password generated by this module.
initAll()
Init the property ->All and clean ->Maj, ->Min, ->Nb and ->Spe with list of valid chars.
getNewGeneratedPassword()
Build new password.
getDescription()
Return description of module.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
conf($dolibarr_main_document_root)
Load conf file (file must exists)
Definition: inc.php:419
$conf db user
Active Directory does not allow anonymous connections.
Definition: repair.php:126