Unverified Commit a98fb01a authored by Côme Chilliet's avatar Côme Chilliet
Browse files

:ambulance: fix(login) Fix ppolicy force password change check

userinfo::loginUser now throws exceptions on failure, webservice code
 will need to be adapted to take them into account as well

issue #6001
Showing with 32 additions and 26 deletions
+32 -26
...@@ -78,3 +78,11 @@ class UnknownClassException extends FusionDirectoryException ...@@ -78,3 +78,11 @@ class UnknownClassException extends FusionDirectoryException
class LDAPFailureException extends FusionDirectoryException class LDAPFailureException extends FusionDirectoryException
{ {
} }
class LoginFailureException extends FusionDirectoryException
{
}
class LoginFailurePpolicyException extends LoginFailureException
{
}
...@@ -30,7 +30,6 @@ define('POSIX_ACCOUNT_EXPIRED', 1); ...@@ -30,7 +30,6 @@ define('POSIX_ACCOUNT_EXPIRED', 1);
define('POSIX_WARN_ABOUT_EXPIRATION', 2); define('POSIX_WARN_ABOUT_EXPIRATION', 2);
define('POSIX_FORCE_PASSWORD_CHANGE', 4); define('POSIX_FORCE_PASSWORD_CHANGE', 4);
define('POSIX_DISALLOW_PASSWORD_CHANGE', 8); define('POSIX_DISALLOW_PASSWORD_CHANGE', 8);
define('PPOLICY_ACCOUNT_EXPIRED', 16);
/*! /*!
* \brief Class userinfo * \brief Class userinfo
...@@ -912,12 +911,6 @@ class userinfo ...@@ -912,12 +911,6 @@ class userinfo
$ldap = $config->get_ldap_link(); $ldap = $config->get_ldap_link();
if (class_available('ppolicyAccount')) { if (class_available('ppolicyAccount')) {
$ldap->cd($config->current['BASE']);
$ldap->search('(objectClass=*)', [], 'one');
if (!$ldap->success()) {
return PPOLICY_ACCOUNT_EXPIRED;
}
try { try {
list($policy, $attrs) = user::fetchPpolicy($this->dn); list($policy, $attrs) = user::fetchPpolicy($this->dn);
if ( if (
...@@ -1209,17 +1202,17 @@ class userinfo ...@@ -1209,17 +1202,17 @@ class userinfo
* *
* \return TRUE on SUCCESS, NULL or FALSE on error * \return TRUE on SUCCESS, NULL or FALSE on error
*/ */
public static function loginUser (string $username, string $password) public static function loginUser (string $username, string $password): userinfo
{ {
global $config; global $config;
$ui = static::getLdapUser($username); $ui = static::getLdapUser($username);
if ($ui === FALSE) { if ($ui === FALSE) {
return NULL; throw new LoginFailureException('User not found');
} elseif (is_string($ui)) { } elseif (is_string($ui)) {
msg_dialog::display(_('Internal error'), $ui, FATAL_ERROR_DIALOG); msg_dialog::display(_('Internal error'), $ui, FATAL_ERROR_DIALOG);
return NULL; exit();
} }
/* password check, bind as user with supplied password */ /* password check, bind as user with supplied password */
...@@ -1229,7 +1222,15 @@ class userinfo ...@@ -1229,7 +1222,15 @@ class userinfo
); );
$ldap = new ldapMultiplexer($ldapObj); $ldap = new ldapMultiplexer($ldapObj);
if (!$ldap->success()) { if (!$ldap->success()) {
return NULL; throw new LoginFailureException($ldap->get_error());
}
if (class_available('ppolicyAccount')) {
$ldap->cd($config->current['BASE']);
$ldap->search('(objectClass=*)', [], 'one');
if (!$ldap->success()) {
throw new LoginFailurePpolicyException(_('It seems your user password has expired. Please use <a href="recovery.php">password recovery</a> to change it.'));
}
} }
/* Username is set, load subtreeACL's now */ /* Username is set, load subtreeACL's now */
......
...@@ -95,13 +95,21 @@ class LoginMethod ...@@ -95,13 +95,21 @@ class LoginMethod
{ {
global $ui, $config, $message, $smarty; global $ui, $config, $message, $smarty;
/* Login as user, initialize user ACL's */ /* Login as user, initialize user ACL's */
$ui = userinfo::loginUser(static::$username, static::$password); try {
if ($ui === NULL) { $ui = userinfo::loginUser(static::$username, static::$password);
} catch (LoginFailurePpolicyException $e) {
msg_dialog::display(_('Authentication error'), $e->getMessage(), ERROR_DIALOG);
logging::log('security', 'login', '', [], 'Account for user "'.static::$username.'" has expired (ppolicy)');
$message = _('Password expired');
$smarty->assign('focusfield', 'username');
return FALSE;
} catch (LoginFailureException $e) {
if (isset($_SERVER['REMOTE_ADDR'])) { if (isset($_SERVER['REMOTE_ADDR'])) {
logging::log('security', 'login', '', [], 'Authentication failed for user "'.static::$username.'" [from '.$_SERVER['REMOTE_ADDR'].']'); logging::log('security', 'login', '', [], 'Authentication failed for user "'.static::$username.'" [from '.$_SERVER['REMOTE_ADDR'].']: '.$e->getMessage());
} else { } else {
logging::log('security', 'login', '', [], 'Authentication failed for user "'.static::$username.'"'); logging::log('security', 'login', '', [], 'Authentication failed for user "'.static::$username.'": '.$e->getMessage());
} }
/* Show the same message whether the user exists or not to avoid information leak */
$message = _('Please check the username/password combination.'); $message = _('Please check the username/password combination.');
$smarty->assign('focusfield', 'password'); $smarty->assign('focusfield', 'password');
return FALSE; return FALSE;
...@@ -133,17 +141,6 @@ class LoginMethod ...@@ -133,17 +141,6 @@ class LoginMethod
/* Check account expiration */ /* Check account expiration */
$expired = $ui->expired_status(); $expired = $ui->expired_status();
if ($expired == PPOLICY_ACCOUNT_EXPIRED) {
msg_dialog::display(
_('Authentication error'),
_('It seems your user password has expired. Please use <a href="recovery.php">password recovery</a> to change it.'),
ERROR_DIALOG
);
logging::log('security', 'login', '', [], 'Account for user "'.static::$username.'" has expired (ppolicy)');
$message = _('Password expired');
$smarty->assign('focusfield', 'username');
return FALSE;
}
if ($expired == POSIX_ACCOUNT_EXPIRED) { if ($expired == POSIX_ACCOUNT_EXPIRED) {
logging::log('security', 'login', '', [], 'Account for user "'.static::$username.'" has expired'); logging::log('security', 'login', '', [], 'Account for user "'.static::$username.'" has expired');
......
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