ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilSecuritySettingsChecker.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 {
26  public static function isPassword(string $a_passwd, ?string &$customError = null): bool
27  {
28  global $DIC;
29 
30  $lng = $DIC->language();
31 
33 
34  // check if password is empty
35  if (empty($a_passwd)) {
36  $customError = $lng->txt('password_empty');
37  return false;
38  }
39 
40  $isPassword = true;
41  $errors = [];
42 
43  // check if password to short
44  if ($security->getPasswordMinLength() > 0 && strlen($a_passwd) < $security->getPasswordMinLength()) {
45  $errors[] = sprintf($lng->txt('password_to_short'), $security->getPasswordMinLength());
46  $isPassword = false;
47  }
48 
49  // check if password not to long
50  // Hmmmmm, maybe we should discuss this limitation. In my opinion it is stupid to limit the password length ;-). There should only be a technical limitation (field size in database).
51  if ($security->getPasswordMaxLength() > 0 && strlen($a_passwd) > $security->getPasswordMaxLength()) {
52  $errors[] = sprintf($lng->txt('password_to_long'), $security->getPasswordMaxLength());
53  $isPassword = false;
54  }
55 
56  // if password must contains Chars and Numbers
57  if ($security->isPasswordCharsAndNumbersEnabled()) {
58  $hasCharsAndNumbers = true;
59 
60  // check password for existing chars
61  if (!preg_match('/[A-Za-z]+/', $a_passwd)) {
62  $hasCharsAndNumbers = false;
63  }
64 
65  // check password for existing numbers
66  if (!preg_match('/[0-9]+/', $a_passwd)) {
67  $hasCharsAndNumbers = false;
68  }
69 
70  if (!$hasCharsAndNumbers) {
71  $errors[] = $lng->txt('password_must_chars_and_numbers');
72  $isPassword = false;
73  }
74  }
75 
76  if ($security->getPasswordNumberOfUppercaseChars() > 0) {
77  if (ilStr::strLen($a_passwd) - ilStr::strLen(
78  preg_replace('/[A-Z]/', '', $a_passwd)
79  ) < $security->getPasswordNumberOfUppercaseChars()) {
80  $errors[] = sprintf(
81  $lng->txt('password_must_contain_ucase_chars'),
82  $security->getPasswordNumberOfUppercaseChars()
83  );
84  $isPassword = false;
85  }
86  }
87 
88  if ($security->getPasswordNumberOfLowercaseChars() > 0) {
89  if (ilStr::strLen($a_passwd) - ilStr::strLen(
90  preg_replace('/[a-z]/', '', $a_passwd)
91  ) < $security->getPasswordNumberOfLowercaseChars()) {
92  $errors[] = sprintf(
93  $lng->txt('password_must_contain_lcase_chars'),
94  $security->getPasswordNumberOfLowercaseChars()
95  );
96  $isPassword = false;
97  }
98  }
99 
100  // if password must contains Special-Chars
101  if ($security->isPasswordSpecialCharsEnabled()) {
102  // check password for existing special-chars
103  if (!preg_match(self::getPasswordValidChars(true, true), $a_passwd)) {
104  $errors[] = $lng->txt('password_must_special_chars');
105  $isPassword = false;
106  }
107  }
108 
109  // ensure password matches the positive list of chars/special-chars
110  if (!preg_match(self::getPasswordValidChars(), $a_passwd)) {
111  $errors[] = $lng->txt('password_contains_invalid_chars');
112  $isPassword = false;
113  }
114 
115  // build custom error message
116  if (count($errors) == 1) {
117  $customError = $errors[0];
118  } elseif (count($errors) > 1) {
119  $customError = $lng->txt('password_multiple_errors');
120  $customError .= '<br />' . implode('<br />', $errors);
121  }
122 
123  return $isPassword;
124  }
125 
133  public static function getPasswordValidChars(bool $a_as_regex = true, bool $a_only_special_chars = false): ?string
134  {
135  if ($a_as_regex) {
136  if ($a_only_special_chars) {
137  return '/[_\.\+\?\#\-\*\@!\$\%\~\/\:\;]+/';
138  } else {
139  return '/^[A-Za-z0-9_\.\+\?\#\-\*\@!\$\%\~\/\:\;]+$/';
140  }
141  } else {
142  return 'A-Z a-z 0-9 _.+?#-*@!$%~/:;';
143  }
144  }
145 
152  public static function isPasswordValidForUserContext(
153  string $clear_text_password,
154  $user,
155  ?string &$error_language_variable = null
156  ): bool {
157  $security = ilSecuritySettings::_getInstance();
158 
159  $login = null;
160 
161  if (is_string($user)) {
162  $login = $user;
163  } elseif (is_array($user)) {
164  // Try to get loginname and user_id from array
165  $login = $user['login'];
166  $userId = $user['id'];
167  } elseif ($user instanceof ilObjUser) {
168  $login = $user->getLogin();
169  $userId = $user->getId();
170  }
171 
172  // The user context (user instance or id) can be used for further validation (e.g. compare a password with the users' password history, etc.) in future releases.
173 
174  if ($login && (int) $security->getPasswordMustNotContainLoginnameStatus() &&
175  strpos(strtolower($clear_text_password), strtolower($login)) !== false
176  ) {
177  $error_language_variable = 'password_contains_parts_of_login_err';
178  return false;
179  }
180 
181  return true;
182  }
183 
190  public static function getPasswordRequirementsInfo(): string
191  {
192  global $DIC;
193 
194  $lng = $DIC->language();
195 
196  $security = ilSecuritySettings::_getInstance();
197 
198  $infos = [sprintf($lng->txt('password_allow_chars'), self::getPasswordValidChars(false))];
199 
200  // check if password to short
201  if ($security->getPasswordMinLength() > 0) {
202  $infos[] = sprintf($lng->txt('password_to_short'), $security->getPasswordMinLength());
203  }
204 
205  // check if password not to long
206  if ($security->getPasswordMaxLength() > 0) {
207  $infos[] = sprintf($lng->txt('password_to_long'), $security->getPasswordMaxLength());
208  }
209 
210  // if password must contains Chars and Numbers
211  if ($security->isPasswordCharsAndNumbersEnabled()) {
212  $infos[] = $lng->txt('password_must_chars_and_numbers');
213  }
214 
215  // if password must contains Special-Chars
216  if ($security->isPasswordSpecialCharsEnabled()) {
217  $infos[] = $lng->txt('password_must_special_chars');
218  }
219 
220  if ($security->getPasswordNumberOfUppercaseChars() > 0) {
221  $infos[] = sprintf(
222  $lng->txt('password_must_contain_ucase_chars'),
223  $security->getPasswordNumberOfUppercaseChars()
224  );
225  }
226 
227  if ($security->getPasswordNumberOfLowercaseChars() > 0) {
228  $infos[] = sprintf(
229  $lng->txt('password_must_contain_lcase_chars'),
230  $security->getPasswordNumberOfLowercaseChars()
231  );
232  }
233 
234  return implode('<br />', $infos);
235  }
236 
243  public static function generatePasswords(int $a_number): array
244  {
245  $ret = [];
246  srand((int) microtime() * 1000000);
247 
248  $security = ilSecuritySettings::_getInstance();
249 
250  for ($i = 1; $i <= $a_number; $i++) {
251  $min = ($security->getPasswordMinLength() > 0)
252  ? $security->getPasswordMinLength()
253  : 6;
254  $max = ($security->getPasswordMaxLength() > 0)
255  ? max($security->getPasswordMaxLength(), $min)
256  : max($min, 10);
257 
258  $random = new ilRandom();
259  $length = $random->int($min, $max);
260  $next = $random->int(1, 2);
261  $vowels = "aeiou";
262  $vowels_uc = strtoupper($vowels);
263  $consonants = "bcdfghjklmnpqrstvwxyz";
264  $consonants_uc = strtoupper($consonants);
265  $numbers = "1234567890";
266  $special = "_.+?#-*@!$%~";
267  $pw = "";
268 
269  if ($security->getPasswordNumberOfUppercaseChars() > 0) {
270  for ($j = 0; $j < $security->getPasswordNumberOfUppercaseChars(); $j++) {
271  switch ($next) {
272  case 1:
273  $pw .= $consonants_uc[$random->getInt(0, strlen($consonants_uc) - 1)];
274  $next = 2;
275  break;
276 
277  case 2:
278  $pw .= $vowels_uc[$random->getInt(0, strlen($vowels_uc) - 1)];
279  $next = 1;
280  break;
281  }
282  }
283  }
284 
285  if ($security->isPasswordCharsAndNumbersEnabled()) {
286  $pw .= $numbers[$random->getInt(0, strlen($numbers) - 1)];
287  }
288 
289  if ($security->isPasswordSpecialCharsEnabled()) {
290  $pw .= $special[$random->getInt(0, strlen($special) - 1)];
291  }
292 
293  $num_lcase_chars = max($security->getPasswordNumberOfLowercaseChars(), $length - strlen($pw));
294  for ($j = 0; $j < $num_lcase_chars; $j++) {
295  switch ($next) {
296  case 1:
297  $pw .= $consonants[$random->getInt(0, strlen($consonants) - 1)];
298  $next = 2;
299  break;
300 
301  case 2:
302  $pw .= $vowels[$random->getInt(0, strlen($vowels) - 1)];
303  $next = 1;
304  break;
305  }
306  }
307 
308  $pw = str_shuffle($pw);
309 
310  $ret[] = $pw;
311  }
312  return $ret;
313  }
314 }
static isPassword(string $a_passwd, ?string &$customError=null)
static getPasswordValidChars(bool $a_as_regex=true, bool $a_only_special_chars=false)
All valid chars for password.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
static strLen(string $a_string)
Definition: class.ilStr.php:60
static isPasswordValidForUserContext(string $clear_text_password, $user, ?string &$error_language_variable=null)
global $DIC
Definition: shib_login.php:26
static getPasswordRequirementsInfo()
infotext for ilPasswordInputGUI setInfo()
static generatePasswords(int $a_number)
Generate a number of passwords.
global $lng
Definition: privfeed.php:31
static _getInstance()
Get instance of ilSecuritySettings.