Verified Commit a6fa5aaf authored by Côme Chilliet's avatar Côme Chilliet
Browse files

:sparkles: feat(webauthn) Make sure each recovery code is only usable once

issue #6019
Showing with 28 additions and 6 deletions
+28 -6
...@@ -37,7 +37,7 @@ class SecondFactorRecoveryCode ...@@ -37,7 +37,7 @@ class SecondFactorRecoveryCode
if (!$attrs) { if (!$attrs) {
throw new FusionDirectoryException(_('Could not fetch user')); throw new FusionDirectoryException(_('Could not fetch user'));
} }
unset($attrs['fdWebauthnRecoveryCode']['fdWebauthnRecoveryCode']); unset($attrs['fdWebauthnRecoveryCode']['count']);
if (empty($attrs['fdWebauthnRecoveryCode'])) { if (empty($attrs['fdWebauthnRecoveryCode'])) {
return FALSE; return FALSE;
} }
...@@ -50,16 +50,38 @@ class SecondFactorRecoveryCode ...@@ -50,16 +50,38 @@ class SecondFactorRecoveryCode
/*! \brief Process POST */ /*! \brief Process POST */
static function earlyProcess () static function earlyProcess ()
{ {
global $message; global $message, $config, $ui;
if (isset($_POST['recoverycode'])) { if (isset($_POST['recoverycode'])) {
$fdWebauthnRecoveryCodes = session::get('fdWebauthnRecoveryCode'); $fdWebauthnRecoveryCodes = session::get('fdWebauthnRecoveryCode');
foreach ($fdWebauthnRecoveryCodes as $fdWebauthnRecoveryCode) { foreach ($fdWebauthnRecoveryCodes as $key => $fdWebauthnRecoveryCode) {
list(, $hash) = explode('|', $fdWebauthnRecoveryCode, 2); list(, $hash) = explode('|', $fdWebauthnRecoveryCode, 2);
if (password_verify($_POST['recoverycode'], $hash)) { if (password_verify($_POST['recoverycode'], $hash)) {
/* TODO: /* Delete this recovery code so that it can only be used once */
* delete this recovery code so that it can only be used once unset($fdWebauthnRecoveryCodes[$key]);
* Warn the user that he needs to generate a new one */ $ldap = $config->get_ldap_link();
$ldap->cd($ui->dn);
$ldap->modify(['fdWebauthnRecoveryCode' => array_values($fdWebauthnRecoveryCodes)]);
/* Warn the user that he needs to generate a new one */
if ($ldap->success()) {
msg_dialog::display(
_('Recovery code'),
_('You connected using a recovery code as second factor. This code has been deleted and will not be usable again in the future. Generate a new one if you need.'),
INFO_DIALOG
);
} else {
msg_dialog::display(
_('Recovery code'),
sprintf(
_('You connected using a recovery code as second factor, but we failed to delete it for future use: %s'),
msgPool::ldaperror($ldap->get_error(), $ui->dn, LDAP_MOD)
),
ERROR_DIALOG
);
}
static::redirect(); static::redirect();
} }
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment