ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilLocalUserPasswordSettingsGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
29 use ILIAS\UI\Component\Input\Field\Password as PasswordInput;
30 
32 {
33  private const string NEW_PASSWORD = 'new_password';
34  private const string CURRENT_PASSWORD = 'current_password';
35  public const string CMD_SHOW_PASSWORD = 'showPassword';
36  public const string CMD_SAVE_PASSWORD = 'savePassword';
37  private readonly ServerRequestInterface $request;
38  private readonly ilErrorHandling $error;
39  private readonly Refinery $refinery;
40  private readonly UIFactory $ui_factory;
41  private readonly UIRenderer $ui_renderer;
42  private readonly ilGlobalTemplateInterface $tpl;
43  private readonly ilLanguage $lng;
44  private readonly ilObjUser $user;
45  private readonly ilCtrlInterface $ctrl;
47 
48  public function __construct()
49  {
50  global $DIC;
51  $this->user = $DIC->user();
52  $this->ctrl = $DIC->ctrl();
53  $this->error = $DIC['ilErr'];
54  $this->lng = $DIC->language();
55  $this->refinery = $DIC->refinery();
56  $this->tpl = $DIC->ui()->mainTemplate();
57  $this->request = $DIC->http()->request();
58  $this->ui_factory = $DIC->ui()->factory();
59  $this->ui_renderer = $DIC->ui()->renderer();
60  $this->password_manager = LocalUserPasswordManager::getInstance();
61  $this->lng->loadLanguageModule('user');
62  }
63 
64  public function executeCommand(): void
65  {
66  $cmd = $this->ctrl->getCmd();
67  switch ($cmd) {
68  default:
69  if (method_exists($this, $cmd)) {
70  $this->$cmd();
71  } else {
72  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
73  }
74 
75  break;
76  }
77  }
78 
79  public function showPassword(
80  ?Form $form = null,
81  bool $hide_form = false,
82  ?MessageBox $message_box = null
83  ): void {
84  // check whether password of user have to be changed
85  // due to first login or password of user is expired
86  if ($this->user->isPasswordChangeDemanded()) {
87  $this->tpl->setOnScreenMessage(
88  $this->tpl::MESSAGE_TYPE_INFO,
89  $this->lng->txt('password_change_on_first_login_demand')
90  );
91  } elseif ($this->user->isPasswordExpired()) {
92  $msg = $this->lng->txt('password_expired');
93  $password_age = $this->user->getPasswordAge();
94  $this->tpl->setOnScreenMessage($this->tpl::MESSAGE_TYPE_INFO, sprintf($msg, $password_age));
95  }
96 
97  if (!$form && !$hide_form) {
98  $form = $this->getPasswordForm();
99  }
100  $this->tpl->setContent(
101  !$hide_form ? $this->ui_renderer->render($form) : $this->ui_renderer->render($message_box)
102  );
103  $this->tpl->printToStdout();
104  }
105 
106  public function getPasswordForm(
107  ?ServerRequestInterface $request = null,
108  array $errors = []
109  ): Form {
110  $items = [];
111  if ($this->password_manager->allowPasswordChange($this->user)) {
112  $pw_info_set = false;
113  if ((int) $this->user->getAuthMode(true) === ilAuthUtils::AUTH_LOCAL) {
114  $cpass = $this->ui_factory->input()->field()->password(
115  $this->lng->txt(self::CURRENT_PASSWORD),
117  );
118 
119  $pw_info_set = true;
120  if ($this->user->getPasswd()) {
121  $cpass = $cpass->withRequired(true);
122  }
123  $cpass = $cpass->withRevelation(true);
124  $cpass_error = $errors[self::CURRENT_PASSWORD] ?? [];
125  if ($cpass_error !== []) {
126  $cpass = $cpass->withError(implode('<br>', $cpass_error));
127  }
128  $cpass = $cpass->withAdditionalTransformation(
129  $this->refinery->custom()->constraint(function (Password $value): bool {
130  return
131  ((int) $this->user->getAuthMode(true) !== ilAuthUtils::AUTH_LOCAL) ||
132  LocalUserPasswordManager::getInstance()->verifyPassword(
133  $this->user,
134  $value->toString()
135  );
136  }, $this->lng->txt('passwd_wrong'))
137  );
138 
139  $items[self::CURRENT_PASSWORD] = $cpass;
140  }
141 
142  // new password
143  $ipass = $this->ui_factory->input()->field()->password(
144  $this->lng->txt('desired_password'),
145  );
146  if ($pw_info_set === false) {
147  $ipass = $ipass->withByline(ilSecuritySettingsChecker::getPasswordRequirementsInfo());
148  }
149  $ipass = $ipass->withRequired(true);
150  $ipass = $ipass->withRevelation(true);
151  $ipass_error = $errors[self::NEW_PASSWORD] ?? [];
152  if ($ipass_error !== []) {
153  $ipass = $ipass->withError(implode('<br>', $ipass_error));
154  }
155  $ipass = $ipass->withAdditionalTransformation(
156  $this->refinery->custom()->constraint(function (Password $value): bool {
157  return ilSecuritySettingsChecker::isPassword($value->toString(), $custom_error);
158  }, function (Closure $txt, Password $value): string {
159  $custom_error = '';
160  !ilSecuritySettingsChecker::isPassword($value->toString(), $custom_error);
161  if ($custom_error !== '' && $custom_error !== null) {
162  return $custom_error;
163  }
164 
165  return $this->lng->txt('passwd_invalid');
166  })
167  );
168  $ipass = $ipass->withAdditionalTransformation(
169  $this->refinery->custom()->constraint(
170  function (Password $value): bool {
172  $value->toString(),
173  $this->user,
174  $error_lng_var
175  );
176  },
177  function (Closure $cls, Password $value): string {
179  $value->toString(),
180  $this->user,
181  $error_lng_var
182  );
183 
184  return $this->lng->txt($error_lng_var ?? '');
185  }
186  )
187  );
188  $items[self::NEW_PASSWORD] = $ipass;
189 
190  switch ($this->user->getAuthMode(true)) {
192  $title = $this->lng->txt('chg_password');
193 
194  break;
196  default:
197  $title = $this->lng->txt('chg_ilias_password');
198 
199  break;
200  }
201  $section = $this->ui_factory->input()->field()->section($items, $title);
202  $items = ['password' => $section];
203  }
204 
205  return $this->ui_factory->input()->container()->form()->standard(
206  $this->ctrl->getLinkTarget($this, 'savePassword'),
207  $items
208  )->withSubmitLabel($this->lng->txt('save'));
209  }
210 
211  public function savePassword(): void
212  {
213  if (!$this->password_manager->allowPasswordChange($this->user)) {
214  $this->ctrl->redirect($this, 'showPersonalData');
215 
216  return;
217  }
218 
219  $form = $this->getPasswordForm()->withRequest($this->request);
220  $section = $form->getInputs()['password'];
225  $cp = $section->getInputs()[self::CURRENT_PASSWORD] ?? null;
226  $np = $section->getInputs()[self::NEW_PASSWORD];
227  $errors = [self::CURRENT_PASSWORD => [], self::NEW_PASSWORD => []];
228 
229  if (!$form->getError()) {
230  $error = false;
231  if ($cp && $cp->getError()) {
232  $error = true;
233  $errors[self::CURRENT_PASSWORD][] = $cp->getError();
234  }
235  if ($np->getError()) {
236  $error = true;
237  $errors[self::NEW_PASSWORD][] = $np->getError();
238  }
239 
240  $entered_current_password = $cp ? $cp->getValue() : '';
241  $entered_new_password = $np->getValue();
242 
243  if (
244  $entered_current_password === $entered_new_password &&
245  ($this->user->isPasswordExpired() || $this->user->isPasswordChangeDemanded())
246  ) {
247  $error = true;
248  $errors[self::NEW_PASSWORD][] = $this->lng->txt('new_pass_equals_old_pass');
249  }
250 
251  if (!$error) {
252  $this->user->resetPassword($entered_new_password, $entered_new_password);
253  if ($entered_current_password !== $entered_new_password) {
254  $this->user->setLastPasswordChangeToNow();
255  $this->user->setPasswordPolicyResetStatus(false);
256  $this->user->update();
257  }
258 
259  if (ilSession::get('orig_request_target')) {
260  $this->tpl->setOnScreenMessage(
261  $this->tpl::MESSAGE_TYPE_SUCCESS,
262  $this->lng->txt('saved_successfully'),
263  true
264  );
265  $target = ilSession::get('orig_request_target');
266  ilSession::set('orig_request_target', '');
267  $this->ctrl->redirectToURL($target);
268  } else {
269  $this->showPassword(
270  null,
271  true,
272  $this->ui_factory->messageBox()->success($this->lng->txt('saved_successfully'))
273  );
274 
275  return;
276  }
277  }
278  }
279 
280  $this->showPassword($this->getPasswordForm($this->request, $errors));
281  }
282 }
static get(string $a_var)
const int AUTH_SHIBBOLETH
static isPassword(string $a_passwd, ?string &$customError=null)
A password is used as part of credentials for authentication.
Definition: Password.php:30
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
readonly LocalUserPasswordManager $password_manager
const int AUTH_LOCAL
getPasswordForm(?ServerRequestInterface $request=null, array $errors=[])
static isPasswordValidForUserContext(string $clear_text_password, $user, ?string &$error_language_variable=null)
global $DIC
Definition: shib_login.php:26
$txt
Definition: error.php:31
static getPasswordRequirementsInfo()
infotext for ilPasswordInputGUI setInfo()
This describes password inputs.
Definition: Password.php:28
showPassword(?Form $form=null, bool $hide_form=false, ?MessageBox $message_box=null)
static set(string $a_var, $a_val)
Set a value.