diff --git a/api/src/Auth.php b/api/src/Auth.php index 478bd5d26d..7e8aef3dcf 100644 --- a/api/src/Auth.php +++ b/api/src/Auth.php @@ -65,13 +65,13 @@ class Auth * * @return string */ - public function backendType() + public static function backendType() { return Cache::getSession(__CLASS__, 'backend'); } /** - * Instanciate a backend + * Instantiate a backend * * Type will be stored in session, to automatic use the same type eg. for conditional use of SAML. * @@ -83,7 +83,7 @@ class Auth { if (is_null($type)) { - $type = Cache::getSession(__CLASS__, 'backend') ?: null; + $type = self::backendType() ?: null; } // do we have a hostname specific auth type set if (is_null($type) && !empty($GLOBALS['egw_info']['server']['auth_type_host']) && @@ -93,24 +93,53 @@ class Auth } if (is_null($type)) $type = $GLOBALS['egw_info']['server']['auth_type']; - $backend_class = __CLASS__.'\\'.ucfirst($type); - - // try old location / name, if not found - if (!class_exists($backend_class)) + $account_storage = $GLOBALS['egw_info']['server']['account_storage'] ?? $type; + if (!empty($GLOBALS['egw_info']['server']['auth_fallback']) && $type !== $account_storage) { - $backend_class = 'auth_'.$type; + $backend = new Auth\Fallback($type, $account_storage); + self::log("Instantiated Auth\\Fallback('$type', '$account_storage')"); + } + else + { + $backend_class = __CLASS__.'\\'.ucfirst($type); + + // try old location / name, if not found + if (!class_exists($backend_class) && class_exists('auth_'.$type)) + { + $backend_class = 'auth_'.$type; + } + $backend = new $backend_class; + self::log("Instantiated $backend_class() (for type '$type')"); } - $backend = new $backend_class; if (!($backend instanceof Auth\Backend)) { throw new Exception\AssertionFailed("Auth backend class $backend_class is NO EGroupware\\Api\Auth\\Backend!"); } - if ($save_in_session) Cache::setSession(__CLASS__, 'backend', $type); + if ($save_in_session) + { + Cache::setSession(__CLASS__, 'backend', $type); + } return $backend; } + /** + * Log $message to auth.log, if enabled + * + * @param string $message + * @return void + */ + public static function log(string $message) + { + if (!empty($GLOBALS['egw_info']['server']['auth_log']) && + ($fp = fopen($GLOBALS['egw_info']['server']['files_dir'].'/auth.log', 'a'))) + { + fwrite($fp, date('Y-m-d H:i:s: ').$message."\n"); + fclose($fp); + } + } + /** * Attempt a SSO login * @@ -318,11 +347,24 @@ class Auth */ function authenticate($username, $passwd, $passwd_type='text') { - return Cache::getCache($GLOBALS['egw_info']['server']['install_id'], - __CLASS__, sha1($username.':'.$passwd.':'.$passwd_type), function($username, $passwd, $passwd_type) + if (preg_match(Auth\Token::TOKEN_REGEXP, $passwd, $matches)) { - return $this->backend->authenticate($username, $passwd, $passwd_type); + $log_passwd = substr($passwd, 0, strlen(Auth\Token::PREFIX)+1+strlen($matches[1])); + $log_passwd .= str_repeat('*', strlen($passwd)-strlen($log_passwd)); + } + else + { + $log_passwd = str_repeat('*', strlen($passwd)); + } + $ret = Cache::getCache($GLOBALS['egw_info']['server']['install_id'], + __CLASS__, sha1($username.':'.$passwd.':'.$passwd_type), function($username, $passwd, $passwd_type) use ($log_passwd) + { + $ret = $this->backend->authenticate($username, $passwd, $passwd_type); + self::log(get_class($this->backend)."('$username', '$log_passwd', '$passwd_type') returned ".json_encode($ret)); + return $ret; }, [$username, $passwd, $passwd_type], self::AUTH_CACHE_TIME); + self::log(__METHOD__."('$username', '$log_passwd', '$passwd_type') returned ".json_encode($ret)); + return $ret; } /** @@ -339,6 +381,7 @@ class Auth { if (($err = self::crackcheck($new_passwd,null,null,null,$account_id))) { + self::log(__METHOD__."(..., $account_id) new password rejected by crackcheck: $err"); throw new Exception\WrongUserinput($err); } if (($ret = $this->backend->change_password($old_passwd, $new_passwd, $account_id))) @@ -360,6 +403,7 @@ class Auth Cache::unsetCache($GLOBALS['egw_info']['server']['install_id'], __CLASS__, sha1(Accounts::id2name($account_id).':'.$old_passwd.':text')); } + self::log(__METHOD__."(..., $account_id) returned ".json_encode($ret)); return $ret; } diff --git a/api/src/Auth/Fallback.php b/api/src/Auth/Fallback.php index a3d0caa1c4..a14ff2c50f 100644 --- a/api/src/Auth/Fallback.php +++ b/api/src/Auth/Fallback.php @@ -66,18 +66,21 @@ class Fallback implements Backend { $backup_currentapp = $GLOBALS['egw_info']['flags']['currentapp']; $GLOBALS['egw_info']['flags']['currentapp'] = 'admin'; // otherwise - $this->fallback_backend->change_password('', $passwd, $account_id); + $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 ($this->fallback_backend->authenticate($username,$passwd, $passwd_type)) + if (($ret = $this->fallback_backend->authenticate($username,$passwd, $passwd_type))) { Api\Cache::setInstance(__CLASS__,'backend_used-'.$username,'fallback'); - return true; } - return false; + Api\Auth::log(__METHOD__."('$username', ...) fallback_backend(".get_class($this->fallback_backend). + ")->authenticate('$username', '".str_repeat('*', strlen($passwd))."', ...) returned ".json_encode($ret)); + return $ret; } /** @@ -107,12 +110,16 @@ class Fallback implements Backend if (($ret = $this->primary_backend->change_password($old_passwd, $new_passwd, $account_id))) { // if password successfully changed on primary, also update fallback - $this->fallback_backend->change_password($old_passwd, $new_passwd, $account_id); + $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; @@ -172,4 +179,4 @@ class Fallback implements Backend } return false; } -} +} \ No newline at end of file diff --git a/api/src/Auth/Token.php b/api/src/Auth/Token.php index d7457d6764..0ead8b4ea8 100644 --- a/api/src/Auth/Token.php +++ b/api/src/Auth/Token.php @@ -51,6 +51,8 @@ class Token extends APi\Storage\Base return null; // not a token } try { + $log_passwd = substr($token, 0, strlen(Auth\Token::PREFIX)+1+strlen($matches[1])); + $log_passwd .= str_repeat('*', strlen($token)-strlen($log_passwd)); $data = self::getInstance()->read([ 'token_id' => $matches[1], 'account_id' => [0, Api\Accounts::getInstance()->name2id($user)], @@ -59,12 +61,15 @@ class Token extends APi\Storage\Base ]); if (!password_verify($matches[2], $data['token_hash'])) { + Api\Auth::log(__METHOD__."('$user', '$log_passwd', ...') returned false (no active token found)"); return false; // invalid token password } $limits = $data['token_limits']; + Api\Auth::log(__METHOD__."('$user', '$log_passwd', ...) returned true"); return true; } catch (Api\Exception\NotFound $e) { + Api\Auth::log(__METHOD__."('$user', '$log_passwd, ...) returned false: ".$e->getMessage()); return false; // token not found } } diff --git a/setup/config.php b/setup/config.php index d1569e6a41..98ce4b8c71 100644 --- a/setup/config.php +++ b/setup/config.php @@ -104,28 +104,29 @@ if(@$_POST['submit'] && @$newsettings) $GLOBALS['egw_setup']->html->show_header(lang('Configuration'),False,'config',$GLOBALS['egw_setup']->ConfigDomain . '(' . $GLOBALS['egw_domain'][$GLOBALS['egw_setup']->ConfigDomain]['db_type'] . ')'); +$current_config = []; // if we have an validation error, use the new settings made by the user and not the stored config if($GLOBALS['error'] && is_array($newsettings)) { - $GLOBALS['current_config'] = $newsettings; + $current_config = $newsettings; } else { foreach($GLOBALS['egw_setup']->db->select($GLOBALS['egw_setup']->config_table,'*',false,__LINE__,__FILE__) as $row) { - $GLOBALS['current_config'][$row['config_name']] = $row['config_value']; + $current_config[$row['config_name']] = $row['config_value']; } } $setup_tpl->pparse('out','T_config_pre_script'); /* Now parse each of the templates we want to show here */ -class phpgw +class egw { var $accounts; var $applications; var $db; } -$GLOBALS['egw'] = new phpgw; +$GLOBALS['egw'] = new egw; $GLOBALS['egw']->db =& $GLOBALS['egw_setup']->db; $t = new Framework\Template(Framework\Template::get_dir('setup')); @@ -157,17 +158,18 @@ foreach($vars as $value) } else { - $t->set_var($value,@$current_config[$newval]); + $t->set_var($value, $current_config[$newval]); } break; case 'selected': + case 'checked': $newvals = explode(' ',$newval); $setting = array_pop($newvals); $config = implode('_',$newvals); /* echo $config . '=' . $current_config[$config]; */ - if(@$current_config[$config] == $setting) + if($current_config[$config] == $setting) { - $t->set_var($value,' selected'); + $t->set_var($value,' '.$type); } else { @@ -206,4 +208,4 @@ $setup_tpl->set_var('lang_submit',lang('Save')); $setup_tpl->set_var('lang_cancel',lang('Cancel')); $setup_tpl->pparse('out','T_config_post_script'); -$GLOBALS['egw_setup']->html->show_footer(); +$GLOBALS['egw_setup']->html->show_footer(); \ No newline at end of file diff --git a/setup/lang/egw_de.lang b/setup/lang/egw_de.lang index 14713c0d53..24cf57c3a0 100644 --- a/setup/lang/egw_de.lang +++ b/setup/lang/egw_de.lang @@ -15,8 +15,8 @@ %1 not allowed to create in univention. setup de Es ist nicht erlaubt unter Univention %1 anzulegen. %1 password set in %2. setup de %1 Passwort gesetzt in %2. %1 passwords updated, %3 errors setup de %1 Passwörter aktualisiert, %3 Fehler -%1 users and %2 groups created, %3 errors setup de %1 Benutzer und %2 Gruppen angelegt, %3 Fehler %1 the configuration file. setup de %1 der Konfigurationsdatei. +%1 users and %2 groups created, %3 errors setup de %1 Benutzer und %2 Gruppen angelegt, %3 Fehler '%1' is no valid domain name! setup de '%1' ist kein gültiger Domainname! '%1' is not allowed as %2. arguments of option %3 !!! setup de '%1' ist nicht erlaubt als %2. Parameter für die Option %3 !!! '%1' must be integer setup de %1 muß ein Integer-Wert sein. @@ -291,6 +291,7 @@ email (standard maildomain should be set) setup de email (Standard Maildomaine m email-address setup de EMail Adresse emailadmin profile updated: setup de EMailAdmin Profil aktualisiert: enable for extra debug-messages setup de ankreuzen für zusätzliche Diagnosemeldungen +enable logging of authentication to files-directory setup de Aktiviere Logging der Authentifizierung in das Datei Verzeichnis enable mcrypt setup de MCrypt einschalten enforce ssl (allows to specify just a path above) setup de Erzwinge SSL (erlaubt darüber nur einen Pfad anzugeben) enter some random text for app session encryption setup de Zufallstext zur Verschlüsselung der Anwendungssitzung @@ -322,6 +323,7 @@ export has been completed! setup de Export ist abgeschlossen! failed to mount backup directory! setup de Konnte Datensicherungsverzeichnis nicht mounten! failed updating user "%1" dn="%2"! setup de Konnte Benutzer "%1" dn="%2" nicht aktualisieren! failed writing configuration file header.inc.php, check the permissions !!! setup de Fehler beim Schreiben der Konfigurationsdatei header.inc.php, bitte überprüfen Sie die Zugriffsrechte !!! +fallback authentication setup de Rückfall Authentifizierung false setup de Falsch file setup de DATEI file type, size, version, etc. setup de Dateityp, Größe, Version usw. @@ -367,6 +369,7 @@ however, the application may still work setup de Wie auch immer, die Anwendung m http auth types (comma-separated) to use without login-page, eg. "ntlm" setup de HTTP Authetifizierungs Typen (Komma-getrennt) die ohne Login Seite benutzt werden sollen, zB. "NTLM" identity provider setup de Identitätsprovider if no acl records for user or any group the user is a member of setup de Wenn es keinen ACL-Eintrag für einen Benutzer oder eine Gruppe, der er angehört gibt +if primary authentication is not successful fall back to passwords synced into account-storage setup de Wenn die primäre Authentifizierung NICHT erfolgreich ist, falle auf die synchronisierten Passwörter des Benutzer Storage zurück if safe_mode is turned on, egw is not able to change certain settings on runtime, nor can we load any not yet loaded module. setup de Wenn safe_mode eingeschaltet ist, kann EGw verschiedene Einstellungen nicht mehr zur Laufzeit ändern, noch können wir nicht geladene Erweiterungen (php extensions) laden. if the application has no defined tables, selecting upgrade should remedy the problem setup de Wenn die Anwendung keine definierten Tabellen hat, wählen Sie überarbeiten. Das Problem sollte damit behoben werden. if using ads (active directory) setup de Wenn Sie ADS (Active Directory) benutzen @@ -827,4 +830,4 @@ your tables are current setup de Ihre Tabellen sind aktuell your tables will be dropped and you will lose data setup de Ihre Tabellen werden gelöscht werden und Sie werden alle Daten verlieren! your temporary directory '%1' %2 setup de Ihr temporäres Verzeichnis '%1' %2 {db | php(default) | php-restore} setup de {db | php(Vorgabe) | php-restore} -{off(default) | on} setup de {off(Vorgabe) | on} \ No newline at end of file +{off(default) | on} setup de {off(Vorgabe) | on} diff --git a/setup/lang/egw_en.lang b/setup/lang/egw_en.lang index 45989e539a..a1ad33f5b5 100644 --- a/setup/lang/egw_en.lang +++ b/setup/lang/egw_en.lang @@ -15,8 +15,8 @@ %1 not allowed to create in univention. setup en %1 not allowed to create in Univention. %1 password set in %2. setup en %1 password set in %2. %1 passwords updated, %3 errors setup en %1 passwords updated, %3 errors -%1 users and %2 groups created, %3 errors setup en %1 users and %2 groups created, %3 errors. %1 the configuration file. setup en %1 the configuration file. +%1 users and %2 groups created, %3 errors setup en %1 users and %2 groups created, %3 errors. '%1' is no valid domain name! setup en '%1' is no valid domain name! '%1' is not allowed as %2. arguments of option %3 !!! setup en '%1' is not allowed as %2. arguments of option %3 !!! '%1' must be integer setup en %1 must be an integer value. @@ -293,6 +293,7 @@ email-address setup en EMail-address emailadmin mail account saved: setup en EMailAdmin mail account saved: emailadmin profile updated: setup en eMailAdmin profile updated: enable for extra debug-messages setup en Enable for extra debug messages +enable logging of authentication to files-directory setup en Enable logging of authentication to files-directory enable mcrypt setup en Enable MCrypt enforce ssl (allows to specify just a path above) setup en Enforce SSL (allows to specify just a path above) enter some random text for app session encryption setup en Enter some random text for app session encryption @@ -324,6 +325,7 @@ export has been completed! setup en Export has been completed! failed to mount backup directory! setup en Failed to mount Backup directory! failed updating user "%1" dn="%2"! setup en Failed updating user "%1" dn="%2"! failed writing configuration file header.inc.php, check the permissions !!! setup en Failed writing configuration file header.inc.php, check the permissions! +fallback authentication setup en Fallback Authentication false setup en False file setup en FILE file type, size, version, etc. setup en File type, size, version, etc. @@ -370,6 +372,7 @@ however, the application may still work setup en The application may still work http auth types (comma-separated) to use without login-page, eg. "ntlm" setup en HTTP auth types, comma-separated to use without login page, eg. "NTLM" identity provider setup en Identity Provider if no acl records for user or any group the user is a member of setup en If no ACL records for user or any group the user is a member of +if primary authentication is not successful fall back to passwords synced into account-storage setup en If primary authentication is NOT successful fall back to passwords synced into account-storage if safe_mode is turned on, egw is not able to change certain settings on runtime, nor can we load any not yet loaded module. setup en If safe_mode is turned on, EGw is not able to change certain settings on runtime, nor can we load any not yet loaded module. if the application has no defined tables, selecting upgrade should remedy the problem setup en If the application has no defined tables, selecting upgrade should remedy the problem if using ads (active directory) setup en If using ADS (Active Directory) authentication @@ -831,4 +834,4 @@ your tables are current setup en Your tables are current your tables will be dropped and you will lose data setup en Your tables will be dropped and you will lose data! your temporary directory '%1' %2 setup en Your temporary directory '%1' %2 {db | php(default) | php-restore} setup en {db | php(default) | php-restore} -{off(default) | on} setup en {off(default) | on} \ No newline at end of file +{off(default) | on} setup en {off(default) | on} diff --git a/setup/templates/default/config.tpl b/setup/templates/default/config.tpl index 1e85b9dc05..31fcc1ed59 100644 --- a/setup/templates/default/config.tpl +++ b/setup/templates/default/config.tpl @@ -129,6 +129,8 @@ + @@ -172,7 +174,14 @@ -