diff --git a/admin/inc/class.admin_mail.inc.php b/admin/inc/class.admin_mail.inc.php index 144016cb81..45fa0a008a 100644 --- a/admin/inc/class.admin_mail.inc.php +++ b/admin/inc/class.admin_mail.inc.php @@ -1263,7 +1263,7 @@ class admin_mail else { try { - if (empty($content['acc_imap_username']) && ($oauth = OpenIDConnectClient::providerByDomain( + if (($oauth = OpenIDConnectClient::providerByDomain( $content['acc_oauth_username'] ?? $content['acc_imap_username'] ?? $content['ident_email'], $content['acc_imap_host']))) { $content += self::oauth2content($oauth); @@ -1541,17 +1541,21 @@ class admin_mail $oidc->addScope($content['acc_oauth_scopes']); } - if (!empty($content['acc_oauth_access_token']) || !empty($content['acc_oauth_refresh_token'])) + if (!empty($content['acc_oauth_access_token']) || + !empty($content['acc_oauth_refresh_token']) && $content['acc_oauth_refresh_token'] !== Mail\Credentials::UNAVAILABLE) { if (empty($content['acc_oauth_access_token'])) { - $content['acc_oauth_access_token'] = $oidc->refreshToken($content['acc_oauth_refresh_token']); + $content['acc_oauth_access_token'] = $oidc->refreshToken($content['acc_oauth_refresh_token'])->access_token; } - if ($smtp) + if (!empty($content['acc_oauth_access_token'])) { - return new Horde_Smtp_Password_Xoauth2($content['acc_oauth_username'] ?? $content['acc_smtp_username'], $content['acc_oauth_access_token']); + if ($smtp) + { + return new Horde_Smtp_Password_Xoauth2($content['acc_oauth_username'] ?? $content['acc_smtp_username'], $content['acc_oauth_access_token']); + } + return new Horde_Imap_Client_Password_Xoauth2($content['acc_oauth_username'] ?? $content['acc_imap_username'], $content['acc_oauth_access_token']); } - return new Horde_Imap_Client_Password_Xoauth2($content['acc_oauth_username'] ?? $content['acc_imap_username'], $content['acc_oauth_access_token']); } // Run OAuth authentication, will NOT return, but call success or failure callbacks below $oidc->authenticateThen(__CLASS__.'::oauthAuthenticated', [$content], __CLASS__.'::oauthFailure', [$content]); diff --git a/api/src/Mail/Credentials.php b/api/src/Mail/Credentials.php index 081843a8aa..c821f8f2e2 100644 --- a/api/src/Mail/Credentials.php +++ b/api/src/Mail/Credentials.php @@ -244,7 +244,7 @@ class Credentials { unset($results[$prefix.'password']); $results[$prefix.'refresh_token'] = self::UNAVAILABLE; // no need to make it available - $results[$prefix.'access_token'] = self::getAccessToken($row['cred_username'], $password, $mailserver); + $results[$prefix.'access_token'] = self::getAccessToken($row['cred_username'], $password, $mailserver, $acc_id, $row['account_id']); // if no extra imap&smtp username set, set the oauth one foreach(['acc_imap_', 'acc_smtp_'] as $pre) { @@ -267,11 +267,13 @@ class Credentials * @param string $username * @param string $refresh_token * @param string|null $mailserver mailserver to detect oauth hosts + * @param ?int $acc_id to store updated refresh-token + * @param ?int $account_id ----------- " ------------ * @return string|null */ - static protected function getAccessToken($username, $refresh_token, $mailserver=null) + static protected function getAccessToken(string $username, string $refresh_token, string $mailserver=null, int $acc_id=null, int $account_id=null) { - return Api\Cache::getInstance(__CLASS__, 'access-token-'.$username.'-'.md5($refresh_token), static function() use ($username, $refresh_token, $mailserver) + return Api\Cache::getInstance(__CLASS__, 'access-token-'.$username.'-'.md5($refresh_token), static function() use ($acc_id, $account_id, $username, $refresh_token, $mailserver) { if (!($oidc = Api\Auth\OpenIDConnectClient::byDomain($username, $mailserver))) { @@ -280,13 +282,24 @@ class Credentials try { $token = $oidc->refreshToken($refresh_token); - return $token->access_token; + // if we got a new refresh-token, store it + if (isset($token->refresh_token) && $refresh_token !== $token->refresh_token && $acc_id > 0 && $account_id > 0) + { + self::write($acc_id, $username, $token->refresh_token, self::OAUTH_REFRESH_TOKEN, $account_id); + //error_log("Mail\\Credentials::getAccessToken($acc_id, $account_id, '$username', ..., ".json_encode($mailserver).") stored new refresh-token: ".json_encode($token)); + } + if (isset($token->access_token)) + { + return $token->access_token; + } + // we did NOT get an access-token + error_log("Mail\\Credentials::getAccessToken($acc_id, $account_id, '$username', '$refresh_token', ".json_encode($mailserver).") got NO access-token: ".json_encode($token)); } catch (OpenIDConnectClientException $e) { _egw_log_exception($e); } return null; - }, [], 3500); // access-token have a livetime of 3600s, give it some margin + }, [], 3500); // access-token have a lifetime of 3600s, give it some margin } /** diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 54008d67e5..ead339b782 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -599,7 +599,7 @@ class mail_ui catch (Exception $e) { // do not exit here. mail-tree should be build. if we exit here, we never get there. - error_log(__METHOD__.__LINE__.$e->getMessage().($e->details?', '.$e->details:'').' Menuaction:'.$_GET['menuaction'].'.'.function_backtrace()); + _egw_log_exception($e); if (isset($this->mail_bo)) { if (empty($etpl))