mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-23 22:38:54 +01:00
* Mail: OAuth authentication for Microsoft (Office365, outlook.com, ...) and GMail
This commit is contained in:
parent
8a43d88ffe
commit
c49f7849bb
@ -1243,7 +1243,7 @@ class admin_mail
|
|||||||
$sel_options['acc_smtp_ssl'] = self::$ssl_types;
|
$sel_options['acc_smtp_ssl'] = self::$ssl_types;
|
||||||
|
|
||||||
// admin access to account with no credentials available
|
// admin access to account with no credentials available
|
||||||
if ($this->is_admin && (empty($content['acc_imap_username']) || empty($content['acc_imap_host']) || $content['called_for']))
|
if ($this->is_admin && (!empty($content['called_for']) || empty($content['acc_imap_host']) || $content['called_for']))
|
||||||
{
|
{
|
||||||
// can't connection to imap --> allow free entries in taglists
|
// can't connection to imap --> allow free entries in taglists
|
||||||
foreach(array('acc_folder_sent', 'acc_folder_trash', 'acc_folder_draft', 'acc_folder_template', 'acc_folder_junk') as $folder)
|
foreach(array('acc_folder_sent', 'acc_folder_trash', 'acc_folder_draft', 'acc_folder_template', 'acc_folder_junk') as $folder)
|
||||||
@ -1254,6 +1254,11 @@ class admin_mail
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
if (empty($content['acc_imap_username']) && ($oauth = OpenIDConnectClient::providerByDomain(
|
||||||
|
$content['acc_oauth_username'] ?? $content['acc_imap_username'] ?? $content['ident_email'], $content['acc_imap_host'])))
|
||||||
|
{
|
||||||
|
$content += self::oauth2content($oauth);
|
||||||
|
}
|
||||||
$sel_options['acc_folder_sent'] = $sel_options['acc_folder_trash'] =
|
$sel_options['acc_folder_sent'] = $sel_options['acc_folder_trash'] =
|
||||||
$sel_options['acc_folder_draft'] = $sel_options['acc_folder_template'] =
|
$sel_options['acc_folder_draft'] = $sel_options['acc_folder_template'] =
|
||||||
$sel_options['acc_folder_junk'] = $sel_options['acc_folder_archive'] =
|
$sel_options['acc_folder_junk'] = $sel_options['acc_folder_archive'] =
|
||||||
@ -1482,9 +1487,10 @@ class admin_mail
|
|||||||
'timeout' => $timeout > 0 ? $timeout : Mail\Imap::getTimeOut(),
|
'timeout' => $timeout > 0 ? $timeout : Mail\Imap::getTimeOut(),
|
||||||
'debug' => self::DEBUG_LOG,
|
'debug' => self::DEBUG_LOG,
|
||||||
];
|
];
|
||||||
if (!empty($content['acc_oauth_provider_url']))
|
if (!empty($content['acc_oauth_provider_url']) || !empty($content['acc_oauth_access_token']))
|
||||||
{
|
{
|
||||||
$config['xoauth2_token'] = self::oauthToken($content);
|
$config['xoauth2_token'] = self::oauthToken($content);
|
||||||
|
$config['username'] = $content['acc_oauth_username'] ?? $content['acc_imap_username'];
|
||||||
if (empty($config['password'])) $config['password'] = '**oauth**'; // some password is required, even if not used
|
if (empty($config['password'])) $config['password'] = '**oauth**'; // some password is required, even if not used
|
||||||
}
|
}
|
||||||
return new Horde_Imap_Client_Socket($config);
|
return new Horde_Imap_Client_Socket($config);
|
||||||
@ -1495,28 +1501,36 @@ class admin_mail
|
|||||||
*/
|
*/
|
||||||
protected static function oauthToken(array &$content, bool $smtp=false)
|
protected static function oauthToken(array &$content, bool $smtp=false)
|
||||||
{
|
{
|
||||||
if (empty($content['acc_oauth_client_secret']))
|
if (empty($content['acc_oauth_access_token']))
|
||||||
{
|
{
|
||||||
throw new Exception(lang("No OAuth client secret for provider '%1'!", $content['acc_oauth_provider_url']));
|
if (empty($content['acc_oauth_client_secret']) &&
|
||||||
}
|
($oauth = OpenIDConnectClient::providerByDomain($content['acc_oauth_username'] ?? $content['acc_imap_username'] ?? $content['ident_email'], $content['acc_imap_host'])))
|
||||||
$oidc = new OpenIDConnectClient($content['acc_oauth_provider_url'],
|
{
|
||||||
$content['acc_oauth_client_id'], $content['acc_oauth_client_secret']);
|
$content += self::oauth2content($oauth);
|
||||||
|
}
|
||||||
|
if (empty($content['acc_oauth_client_secret']))
|
||||||
|
{
|
||||||
|
throw new Exception(lang("No OAuth client secret for provider '%1'!", $content['acc_oauth_provider_url']));
|
||||||
|
}
|
||||||
|
$oidc = new OpenIDConnectClient($content['acc_oauth_provider_url'],
|
||||||
|
$content['acc_oauth_client_id'], $content['acc_oauth_client_secret']);
|
||||||
|
|
||||||
// Office365 requires client-ID as appid GET parameter (https://github.com/jumbojett/OpenID-Connect-PHP/issues/190)
|
// Office365 requires client-ID as appid GET parameter (https://github.com/jumbojett/OpenID-Connect-PHP/issues/190)
|
||||||
if (!empty($content[OpenIDConnectClient::ADD_CLIENT_TO_WELL_KNOWN]))
|
if (!empty($content[OpenIDConnectClient::ADD_CLIENT_TO_WELL_KNOWN]))
|
||||||
{
|
{
|
||||||
$oidc->setWellKnownConfigParameters([$content[OpenIDConnectClient::ADD_CLIENT_TO_WELL_KNOWN] => $content['acc_oauth_client_id']]);
|
$oidc->setWellKnownConfigParameters([$content[OpenIDConnectClient::ADD_CLIENT_TO_WELL_KNOWN] => $content['acc_oauth_client_id']]);
|
||||||
}
|
}
|
||||||
// Google requires access_type=offline&prompt=consent to return a refresh-token
|
// Google requires access_type=offline&prompt=consent to return a refresh-token
|
||||||
if (!empty($content[OpenIDConnectClient::ADD_AUTH_PARAM]))
|
if (!empty($content[OpenIDConnectClient::ADD_AUTH_PARAM]))
|
||||||
{
|
{
|
||||||
$oidc->addAuthParam(str_replace('$username', $content['acc_oauth_username'] ?? $content['acc_imap_username'], $content[OpenIDConnectClient::ADD_AUTH_PARAM]));
|
$oidc->addAuthParam(str_replace('$username', $content['acc_oauth_username'] ?? $content['acc_imap_username'], $content[OpenIDConnectClient::ADD_AUTH_PARAM]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to use response_code=query / GET request to keep our session token!
|
// we need to use response_code=query / GET request to keep our session token!
|
||||||
$oidc->setResponseTypes(['code']); // to be able to use query, not 'id_token'
|
$oidc->setResponseTypes(['code']); // to be able to use query, not 'id_token'
|
||||||
//$oidc->setAllowImplicitFlow(true);
|
//$oidc->setAllowImplicitFlow(true);
|
||||||
$oidc->addScope($content['acc_oauth_scopes']);
|
$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']))
|
||||||
{
|
{
|
||||||
@ -1545,7 +1559,7 @@ class admin_mail
|
|||||||
{
|
{
|
||||||
if (empty($content['acc_oauth_username']))
|
if (empty($content['acc_oauth_username']))
|
||||||
{
|
{
|
||||||
$content['acc_oauth_username'] = $content['acc_imap_username'];
|
$content['acc_oauth_username'] = $content['acc_imap_username'] ?? $oidc->getVerifiedClaims('email') ?? $content['ident_email'];
|
||||||
}
|
}
|
||||||
if (empty($content['acc_oauth_refresh_token'] = $oidc->getRefreshToken()))
|
if (empty($content['acc_oauth_refresh_token'] = $oidc->getRefreshToken()))
|
||||||
{
|
{
|
||||||
@ -1557,7 +1571,14 @@ class admin_mail
|
|||||||
$GLOBALS['egw_info']['flags']['currentapp'] = 'admin';
|
$GLOBALS['egw_info']['flags']['currentapp'] = 'admin';
|
||||||
|
|
||||||
$obj = new self;
|
$obj = new self;
|
||||||
$obj->autoconfig($content);
|
if (!empty($content['acc_id']))
|
||||||
|
{
|
||||||
|
$obj->edit($content, lang('Use save or apply to store the received OAuth token!'), 'info');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$obj->autoconfig($content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1568,12 +1589,20 @@ class admin_mail
|
|||||||
*/
|
*/
|
||||||
public static function oauthFailure(Throwable $exception=null, array $content)
|
public static function oauthFailure(Throwable $exception=null, array $content)
|
||||||
{
|
{
|
||||||
$content['output'] .= lang('OAuth Authentiction').': '.($exception ? $exception->getMessage() : lang('failed'));
|
|
||||||
$content['connected'] = false;
|
|
||||||
|
|
||||||
$GLOBALS['egw_info']['flags']['currentapp'] = 'admin';
|
$GLOBALS['egw_info']['flags']['currentapp'] = 'admin';
|
||||||
|
|
||||||
$obj = new self;
|
$obj = new self;
|
||||||
|
if (!empty($content['acc_id']))
|
||||||
|
{
|
||||||
|
$obj->edit($content, lang('OAuth Authentiction').': '.($exception ? $exception->getMessage() : lang('failed')), 'error');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$content['output'] .= lang('OAuth Authentiction').': '.($exception ? $exception->getMessage() : lang('failed'));
|
||||||
|
$content['connected'] = false;
|
||||||
|
|
||||||
|
$obj->autoconfig($content);
|
||||||
|
}
|
||||||
$obj->autoconfig($content);
|
$obj->autoconfig($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -949,6 +949,7 @@ use default admin de Vorgabe verwenden
|
|||||||
use ldap defaults admin de LDAP Standardeinstellungen benutzen
|
use ldap defaults admin de LDAP Standardeinstellungen benutzen
|
||||||
use predefined username and password defined below admin de Verwende den unten vordefinierten Benutzernamen und Passwort
|
use predefined username and password defined below admin de Verwende den unten vordefinierten Benutzernamen und Passwort
|
||||||
use pure html compliant code (not fully working yet) admin de Vollständig HTML kompatiblen Code verwenden (nicht vollständig implementiert)
|
use pure html compliant code (not fully working yet) admin de Vollständig HTML kompatiblen Code verwenden (nicht vollständig implementiert)
|
||||||
|
use save or apply to store the received oauth token! admin de Benutze Speicher oder Übernehmen um das erhaltene OAuth Token zu speichern!
|
||||||
use secure cookies (transmitted only via https) admin de Benutze sichere Cookies (werden nur per https übertragen)
|
use secure cookies (transmitted only via https) admin de Benutze sichere Cookies (werden nur per https übertragen)
|
||||||
use smtp auth admin de SMTP Authentifizierung benutzen
|
use smtp auth admin de SMTP Authentifizierung benutzen
|
||||||
use theme admin de Benutztes Farbschema
|
use theme admin de Benutztes Farbschema
|
||||||
|
@ -952,6 +952,7 @@ use default admin en use default
|
|||||||
use ldap defaults admin en Use LDAP defaults
|
use ldap defaults admin en Use LDAP defaults
|
||||||
use predefined username and password defined below admin en Use predefined username and password defined below
|
use predefined username and password defined below admin en Use predefined username and password defined below
|
||||||
use pure html compliant code (not fully working yet) admin en Use pure HTML compliant code
|
use pure html compliant code (not fully working yet) admin en Use pure HTML compliant code
|
||||||
|
use save or apply to store the received oauth token! admin en Use save or apply to store the received OAuth token!
|
||||||
use secure cookies (transmitted only via https) admin en Use secure cookies (transmitted only via https)
|
use secure cookies (transmitted only via https) admin en Use secure cookies (transmitted only via https)
|
||||||
use smtp auth admin en Use SMTP authentication
|
use smtp auth admin en Use SMTP authentication
|
||||||
use theme admin en Use theme
|
use theme admin en Use theme
|
||||||
|
@ -122,11 +122,12 @@ class OpenIDConnectClient extends \Jumbojett\OpenIDConnectClient
|
|||||||
* Get OIDC client object for the given domain/email
|
* Get OIDC client object for the given domain/email
|
||||||
*
|
*
|
||||||
* @param string $domain domain or email address
|
* @param string $domain domain or email address
|
||||||
|
* @param string|null $mailserver
|
||||||
* @return self|null
|
* @return self|null
|
||||||
*/
|
*/
|
||||||
public static function byDomain($domain)
|
public static function byDomain($domain, $mailserver=null)
|
||||||
{
|
{
|
||||||
if (!($provider = self::providerByDomain($domain)))
|
if (!($provider = self::providerByDomain($domain, $mailserver)))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ abstract class Extra
|
|||||||
// if we have real push available and a regular single-entry refresh of a push supporting app, no need to refresh
|
// if we have real push available and a regular single-entry refresh of a push supporting app, no need to refresh
|
||||||
if (!Json\Push::onlyFallback() &&
|
if (!Json\Push::onlyFallback() &&
|
||||||
!empty($type) && !empty($id) && // $type === null --> full reload
|
!empty($type) && !empty($id) && // $type === null --> full reload
|
||||||
Link::get_registry($app, 'push_data') !== null)
|
Link::get_registry($app, 'push_data'))
|
||||||
{
|
{
|
||||||
$app = 'msg-only-push-refresh';
|
$app = 'msg-only-push-refresh';
|
||||||
}
|
}
|
||||||
|
@ -469,10 +469,17 @@ class Account implements \ArrayAccess
|
|||||||
*/
|
*/
|
||||||
public function is_imap($try_connect=true)
|
public function is_imap($try_connect=true)
|
||||||
{
|
{
|
||||||
if (empty($this->acc_imap_host) || ( empty($this->acc_imap_username) && empty($this->acc_imap_password) ) )
|
if (empty($this->acc_imap_host) ||
|
||||||
|
empty($this->acc_imap_username) && empty($this->acc_imap_password) &&
|
||||||
|
!($oauth = Api\Auth\OpenIDConnectClient::providerByDomain($this->acc_imap_username ?: $this->ident_email, $this->acc_imap_host)))
|
||||||
{
|
{
|
||||||
return false; // no imap host or credentials
|
return false; // no imap host or credentials
|
||||||
}
|
}
|
||||||
|
if (isset($oauth))
|
||||||
|
{
|
||||||
|
$this->params['acc_imap_username'] = $this->acc_imap_username ?: $this->ident_email;
|
||||||
|
$this->params['acc_imap_password'] = '**oauth**';
|
||||||
|
}
|
||||||
// if we are not managing the mail-server, we do NOT need to check deliveryMode and accountStatus
|
// if we are not managing the mail-server, we do NOT need to check deliveryMode and accountStatus
|
||||||
if ($this->acc_smtp_type == __NAMESPACE__.'\\Smtp')
|
if ($this->acc_smtp_type == __NAMESPACE__.'\\Smtp')
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user