* @license http://opensource.org/licenses/lgpl-license.php LGPL - GNU Lesser General Public License * @package api * @subpackage auth * @version $Id$ */ namespace EGroupware\Api\Auth; use EGroupware\Api; /** * Authentication against an LDAP Server (or other authentication type) with fallback to SQL */ class Fallback implements Backend { /** * Primary auth backend * * @var Backend */ private $primary_backend; /** * Fallback auth backend * * @var Backend */ private $fallback_backend; /** * Constructor * * @param string $primary ='ldap' * @param string $fallback ='sql' */ function __construct($primary='ldap',$fallback='sql') { // do NOT save our backends in session, as we want "fallback" to be saved $this->primary_backend = Api\Auth::backend(str_replace('auth_', '', $primary ?: 'ldap'), false); $this->fallback_backend = Api\Auth::backend(str_replace('auth_', '', $fallback ?: 'sql'), false); } /** * authentication against LDAP with fallback to SQL * * @param string $username username of account to authenticate * @param string $passwd corresponding password * @return boolean true if successful authenticated, false otherwise */ function authenticate($username, $passwd, $passwd_type='text') { $ret = $this->primary_backend->authenticate($username, $passwd, $passwd_type); Api\Auth::log(__METHOD__."('$username', ...) primary_backend(".get_class($this->primary_backend). ")->authenticate('$username', '".str_repeat('*', strlen($passwd))."', ...) returned ".json_encode($ret)); if ($ret) { Api\Cache::setInstance(__CLASS__,'backend_used-'.$username,'primary'); // check if fallback has correct password, if not update it if (($account_id = $GLOBALS['egw']->accounts->name2id($username)) && !$this->fallback_backend->authenticate($username,$passwd, $passwd_type)) { $backup_currentapp = $GLOBALS['egw_info']['flags']['currentapp']; $GLOBALS['egw_info']['flags']['currentapp'] = 'admin'; // otherwise $ret = $this->fallback_backend->change_password('', $passwd, $account_id); Api\Auth::log(__METHOD__."('$username', ...) fallback_backend(".get_class($this->fallback_backend). ")->change_password('', '".str_repeat('*', strlen($passwd))."', $account_id) returned ".json_encode($ret)); $GLOBALS['egw_info']['flags']['currentapp'] = $backup_currentapp; //error_log(__METHOD__."('$username', \$passwd) updated password for #$account_id on fallback ".($ret ? 'successfull' : 'failed!')); } return true; } if (($ret = $this->fallback_backend->authenticate($username,$passwd, $passwd_type))) { Api\Cache::setInstance(__CLASS__,'backend_used-'.$username,'fallback'); } Api\Auth::log(__METHOD__."('$username', ...) fallback_backend(".get_class($this->fallback_backend). ")->authenticate('$username', '".str_repeat('*', strlen($passwd))."', ...) returned ".json_encode($ret)); return $ret; } /** * changes password in LDAP * * If $old_passwd is given, the password change is done binded as user and NOT with the * "root" dn given in the configurations. * * @param string $old_passwd must be cleartext or empty to not to be checked * @param string $new_passwd must be cleartext * @param int $account_id account id of user whose passwd should be changed * @return boolean true if password successful changed, false otherwise */ function change_password($old_passwd, $new_passwd, $account_id=0) { if(!$account_id) { $account_id = $GLOBALS['egw_info']['user']['account_id']; $username = $GLOBALS['egw_info']['user']['account_lid']; } else { $username = $GLOBALS['egw']->accounts->id2name($account_id); } if (Api\Cache::getInstance(__CLASS__,'backend_used-'.$username) == 'primary') { if (($ret = $this->primary_backend->change_password($old_passwd, $new_passwd, $account_id))) { // if password successfully changed on primary, also update fallback $change_pwd = $this->fallback_backend->change_password($old_passwd, $new_passwd, $account_id); Api\Auth::log(__METHOD__."(..., $account_id) fallback_backend(".get_class($this->fallback_backend). ")->change_password('', '".str_repeat('*', strlen($new_passwd))."', $account_id) returned ".json_encode($change_pwd)); } } else { $ret = $this->fallback_backend->change_password($old_passwd, $new_passwd, $account_id); Api\Auth::log(__METHOD__."(..., $account_id) fallback_backend(".get_class($this->fallback_backend). ")->change_password('', '".str_repeat('*', strlen($new_passwd))."', $account_id) returned ".json_encode($ret)); } //error_log(__METHOD__."('$old_passwd', '$new_passwd', $account_id) username='$username', backend=".Api\Cache::getInstance(__CLASS__,'backend_used-'.$username)." returning ".array2string($ret)); return $ret; } /** * fetch the last pwd change for the user * * @param string $username username of account to authenticate * @return mixed false or account_lastpwd_change */ function getLastPwdChange($username) { if (Api\Cache::getInstance(__CLASS__,'backend_used-'.$username) == 'primary') { if (method_exists($this->primary_backend,'getLastPwdChange')) { return $this->primary_backend->getLastPwdChange($username); } } if (method_exists($this->fallback_backend,'getLastPwdChange')) { return $this->fallback_backend->getLastPwdChange($username); } return false; } /** * changes account_lastpwd_change in sql datababse * * @param int $account_id account id of user whose passwd should be changed * @param string $passwd must be cleartext, usually not used, but may be used to authenticate as user to do the change -> ldap * @param int $lastpwdchange must be a unixtimestamp * @return boolean true if account_lastpwd_change successful changed, false otherwise */ function setLastPwdChange($account_id=0, $passwd=NULL, $lastpwdchange=NULL) { if(!$account_id || $GLOBALS['egw_info']['flags']['currentapp'] == 'login') { $account_id = $GLOBALS['egw_info']['user']['account_id']; $username = $GLOBALS['egw_info']['user']['account_lid']; } else { $username = $GLOBALS['egw']->accounts->id2name($account_id); } if (Api\Cache::getInstance(__CLASS__,'backend_used-'.$username) == 'primary') { if (method_exists($this->primary_backend,'setLastPwdChange')) { return $this->primary_backend->setLastPwdChange($username); } } if (method_exists($this->fallback_backend,'setLastPwdChange')) { return $this->fallback_backend->setLastPwdChange($account_id, $passwd, $lastpwdchange); } return false; } }