diff --git a/htdocs/admin/mails.php b/htdocs/admin/mails.php index 67bf775bdd9..7c72825ad60 100644 --- a/htdocs/admin/mails.php +++ b/htdocs/admin/mails.php @@ -89,6 +89,12 @@ if ($action == 'update' && !$cancel) { dolibarr_set_const($db, "MAIN_MAIL_SMTP_SERVER", GETPOST("MAIN_MAIL_SMTP_SERVER", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_MAIL_SMTPS_ID", GETPOST("MAIN_MAIL_SMTPS_ID", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_MAIL_SMTPS_PW", GETPOST("MAIN_MAIL_SMTPS_PW", 'none'), 'chaine', 0, '', $conf->entity); + if (GETPOSTISSET("MAIN_MAIL_SMTPS_USE_OAUTH")) { + dolibarr_set_const($db, "MAIN_MAIL_SMTPS_USE_OAUTH", GETPOST("MAIN_MAIL_SMTPS_USE_OAUTH", 'none'), 'chaine', 0, '', $conf->entity); + $method = GETPOST("MAIN_MAIL_SMTPS_USE_OAUTH", 'aZ09') == 1 ? 'XOAUTH2' : 'LOGIN'; + dolibarr_set_const($db, "MAIL_SMTP_AUTH_TYPE", $method, 'chaine', 0, '', $conf->entity); + } + dolibarr_set_const($db, "MAIN_MAIL_SMTPS_OAUTH_SERVICE", GETPOST("MAIN_MAIL_SMTPS_OAUTH_SERVICE", 'none'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_MAIL_EMAIL_TLS", GETPOST("MAIN_MAIL_EMAIL_TLS", 'int'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_MAIL_EMAIL_STARTTLS", GETPOST("MAIN_MAIL_EMAIL_STARTTLS", 'int'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED", GETPOST("MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED", 'int'), 'chaine', 0, '', $conf->entity); @@ -171,6 +177,23 @@ if (version_compare(phpversion(), '7.0', '>=')) { $listofmethods['swiftmailer'] = 'Swift Mailer socket library'; } +// List of oauth services +$oauthservices = array(); + +foreach ($conf->global as $key => $val) { + if (!empty($val) && preg_match('/^OAUTH_.*_ID$/', $key)) { + $key = preg_replace('/^OAUTH_/', '', $key); + $key = preg_replace('/_ID$/', '', $key); + if (preg_match('/^.*-/', $key)) { + $name = preg_replace('/^.*-/', '', $key); + } else { + $name = $langs->trans("NoName"); + } + $provider = preg_replace('/-.*$/', '', $key); + + $oauthservices[$key] = $name." (".$provider.")"; + } +} if ($action == 'edit') { if ($conf->use_javascript_ajax) { @@ -195,6 +218,8 @@ if ($action == 'edit') { jQuery("#MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY").prop("disabled", true); jQuery(".smtp_method").hide(); jQuery(".dkim").hide(); + jQuery(".smtp_oauth_service").hide(); + jQuery(".smtp_use_oauth").hide(); '; if ($linuxlike) { print ' @@ -237,6 +262,8 @@ if ($action == 'edit') { jQuery("#smtp_port_mess").hide(); jQuery(".smtp_method").show(); jQuery(".dkim").hide(); + jQuery(".smtp_oauth_service").show(); + jQuery(".smtp_use_oauth").show(); } if (jQuery("#MAIN_MAIL_SENDMODE").val()==\'swiftmailer\') { @@ -264,12 +291,28 @@ if ($action == 'edit') { jQuery("#smtp_port_mess").hide(); jQuery(".smtp_method").show(); jQuery(".dkim").show(); + jQuery(".smtp_oauth_service").hide(); + jQuery(".smtp_use_oauth").hide(); } } + function change_smtp_oauth_service() { + console.log(jQuery("#MAIN_MAIL_SMTPS_USE_OAUTH").val()); + if (jQuery("#MAIN_MAIL_SMTPS_USE_OAUTH").val() == 1) { + jQuery(".smtp_oauth_service").show(); + jQuery(".smtp_pw").hide(); + } else { + jQuery(".smtp_oauth_service").hide(); + jQuery(".smtp_pw").show(); + } + } initfields(); + change_smtp_oauth_service(); jQuery("#MAIN_MAIL_SENDMODE").change(function() { initfields(); }); + jQuery("#MAIN_MAIL_SMTPS_USE_OAUTH").change(function() { + change_smtp_oauth_service(); + }); jQuery("#MAIN_MAIL_EMAIL_TLS").change(function() { if (jQuery("#MAIN_MAIL_EMAIL_TLS").val() == 1) jQuery("#MAIN_MAIL_EMAIL_STARTTLS").val(0); @@ -369,6 +412,20 @@ if ($action == 'edit') { } print ''; + // OAUTH + if (!empty($conf->use_javascript_ajax) || (isset($conf->global->MAIN_MAIL_SENDMODE) && in_array($conf->global->MAIN_MAIL_SENDMODE, array('smtps', 'swiftmailer')))) { + print ''.$form->textwithpicto($langs->trans("MAIN_MAIL_SMTPS_USE_OAUTH"), $langs->trans("OauthNotAvailableForAll")).''; + if (empty($conf->multicompany->enabled) || ($user->admin && !$user->entity)) { + print $form->selectyesno('MAIN_MAIL_SMTPS_USE_OAUTH', (!empty($conf->global->MAIN_MAIL_SMTPS_USE_OAUTH) ? $conf->global->MAIN_MAIL_SMTPS_USE_OAUTH : 0), 1); + } else { + $value = yn($conf->global->MAIN_MAIL_SMTPS_USE_OAUTH); + $htmltext = $langs->trans("ContactSuperAdminForChange"); + print $form->textwithpicto($text, $htmltext, 1, 'superadmin'); + print ''; + } + print ''; + } + // Port print ''; if (!$conf->use_javascript_ajax && $linuxlike && $conf->global->MAIN_MAIL_SENDMODE == 'mail') { @@ -416,7 +473,7 @@ if ($action == 'edit') { // PW if (!empty($conf->use_javascript_ajax) || (isset($conf->global->MAIN_MAIL_SENDMODE) && in_array($conf->global->MAIN_MAIL_SENDMODE, array('smtps', 'swiftmailer')))) { $mainsmtppw = (!empty($conf->global->MAIN_MAIL_SMTPS_PW) ? $conf->global->MAIN_MAIL_SMTPS_PW : ''); - print ''; + print ''; print $form->textwithpicto($langs->trans("MAIN_MAIL_SMTPS_PW"), $langs->trans("WithGMailYouCanCreateADedicatedPassword")); print ''; // SuperAdministrator access only @@ -430,6 +487,24 @@ if ($action == 'edit') { print ''; } + // OAUTH service provider + if (!empty($conf->use_javascript_ajax) || (isset($conf->global->MAIN_MAIL_SENDMODE) && in_array($conf->global->MAIN_MAIL_SENDMODE, array('smtps')))) { + print ''.$form->textwithpicto($langs->trans("MAIN_MAIL_SMTPS_OAUTH_SERVICE"), $langs->trans("DontForgetCreateTokenOauthMod")).''; + + // SuperAdministrator access only + if ((empty($conf->global->MAIN_MODULE_MULTICOMPANY)) || ($user->admin && !$user->entity)) { + print $form->selectarray('MAIN_MAIL_SMTPS_OAUTH_SERVICE', $oauthservices, $conf->global->MAIN_MAIL_SMTPS_OAUTH_SERVICE); + } else { + $text = $oauthservices[$conf->global->MAIN_MAIL_SMTPS_OAUTH_SERVICE]; + if (empty($text)) { + $text = $langs->trans("Undefined"); + } + $htmltext = $langs->trans("ContactSuperAdminForChange"); + print $form->textwithpicto($text, $htmltext, 1, 'superadmin'); + print ''; + } + print ''; + } // TLS print ''.$langs->trans("MAIN_MAIL_EMAIL_TLS").''; if (!empty($conf->use_javascript_ajax) || (isset($conf->global->MAIN_MAIL_SENDMODE) && in_array($conf->global->MAIN_MAIL_SENDMODE, array('smtps', 'swiftmailer')))) { @@ -601,6 +676,11 @@ if ($action == 'edit') { print ''.$langs->trans("MAIN_MAIL_SMTP_SERVER", ini_get('SMTP') ?ini_get('SMTP') : $langs->transnoentities("Undefined")).''.(!empty($conf->global->MAIN_MAIL_SMTP_SERVER) ? $conf->global->MAIN_MAIL_SMTP_SERVER : '').''; } + // Use OAUTH + if (isset($conf->global->MAIN_MAIL_SENDMODE) && in_array($conf->global->MAIN_MAIL_SENDMODE, array('smtps'))) { + print ''.$langs->trans("MAIN_MAIL_SMTPS_USE_OAUTH").''.yn($conf->global->MAIN_MAIL_SMTPS_USE_OAUTH).''; + } + // Port if ($linuxlike && (isset($conf->global->MAIN_MAIL_SENDMODE) && $conf->global->MAIN_MAIL_SENDMODE == 'mail')) { print ''.$langs->trans("MAIN_MAIL_SMTP_PORT_NotAvailableOnLinuxLike").''.$langs->trans("SeeLocalSendMailSetup").''; @@ -614,10 +694,19 @@ if ($action == 'edit') { } // SMTPS PW - if (isset($conf->global->MAIN_MAIL_SENDMODE) && in_array($conf->global->MAIN_MAIL_SENDMODE, array('smtps', 'swiftmailer'))) { + if (isset($conf->global->MAIN_MAIL_SENDMODE) && in_array($conf->global->MAIN_MAIL_SENDMODE, array('smtps', 'swiftmailer')) && (!(isset($conf->global->MAIL_SMTP_AUTH_TYPE) && $conf->global->MAIL_SMTP_AUTH_TYPE === "XOAUTH2"))) { print ''.$langs->trans("MAIN_MAIL_SMTPS_PW").''.preg_replace('/./', '*', $conf->global->MAIN_MAIL_SMTPS_PW).''; } + // SMTPS oauth service + if (isset($conf->global->MAIL_SMTP_AUTH_TYPE) && $conf->global->MAIL_SMTP_AUTH_TYPE === "XOAUTH2") { + $text = $oauthservices[$conf->global->MAIN_MAIL_SMTPS_OAUTH_SERVICE]; + if (empty($text)) { + $text = $langs->trans("Undefined").img_warning(); + } + print ''.$langs->trans("MAIN_MAIL_SMTPS_OAUTH_SERVICE").''.$text.''; + } + // TLS print ''.$langs->trans("MAIN_MAIL_EMAIL_TLS").''; if (isset($conf->global->MAIN_MAIL_SENDMODE) && in_array($conf->global->MAIN_MAIL_SENDMODE, array('smtps', 'swiftmailer'))) { diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index 94fb05d5346..24c27b47795 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -30,6 +30,7 @@ * \brief File of class to send emails (with attachments or not) */ +use OAuth\Common\Storage\DoliStorage; /** * Class to send emails (with attachments or not) * Usage: $mailfile = new CMailFile($subject,$sendto,$replyto,$message,$filepath,$mimetype,$filename,$cc,$ccc,$deliveryreceipt,$msgishtml,$errors_to,$css,$trackid,$moreinheader,$sendcontext,$replyto); @@ -657,6 +658,8 @@ class CMailFile } $keyforsmtpserver = 'MAIN_MAIL_SMTP_SERVER'; + $keyforsmtpuseoauth = "MAIN_MAIL_SMTPS_USE_OAUTH"; + $keyforsmtpoauthservice = "MAIN_MAIL_SMTPS_OAUTH_SERVICE"; $keyforsmtpport = 'MAIN_MAIL_SMTP_PORT'; $keyforsmtpid = 'MAIN_MAIL_SMTPS_ID'; $keyforsmtppw = 'MAIN_MAIL_SMTPS_PW'; @@ -832,6 +835,36 @@ class CMailFile $this->smtps->setPW($loginpass); } + if (!empty($conf->global->$keyforsmtpuseoauth)) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/oauth.lib.php'; // define $supportedoauth2array + $keyforsupportedoauth2array = $conf->global->$keyforsmtpoauthservice; + if (preg_match('/^.*-/', $keyforsupportedoauth2array)) { + $keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array); + } else { + $keyforprovider = ''; + } + $keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array); + $keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME'; + + $OAUTH_SERVICENAME = (empty($supportedoauth2array[$keyforsupportedoauth2array]['name']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['name'].($keyforprovider ? '-'.$keyforprovider : '')); + + require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php'; + + $storage = new DoliStorage($db, $conf); + try { + $tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME); + if (is_object($tokenobj)) { + $this->smtps->setToken($tokenobj->getAccessToken()); + } else { + $this->error = "Token not found"; + } + } catch (Exception $e) { + // Return an error if token not found + $this->error = $e->getMessage(); + dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR); + } + } + $res = true; $from = $this->smtps->getFrom('org'); if ($res && !$from) { diff --git a/htdocs/core/class/smtps.class.php b/htdocs/core/class/smtps.class.php index 1f5a48a517d..05248e89143 100644 --- a/htdocs/core/class/smtps.class.php +++ b/htdocs/core/class/smtps.class.php @@ -68,6 +68,11 @@ class SMTPs */ private $_smtpsPW = null; + /** + * Token in case we use OAUTH2 + */ + private $_smtpsToken = null; + /** * Who sent the Message * This can be defined via a INI file or via a setter method @@ -583,9 +588,10 @@ class SMTPs break; case 'XOAUTH2': // "user=$email\1auth=Bearer $token\1\1" - $token = 'xxx'; - $xxxx = "user=".$this->_smtpsID."\1auth=Bearer ".$token."\1\1"; - $_retVal = $this->socket_send_str('AUTH XOAUTH2 '.base64_encode($xxxx), '235'); + $user = $this->_smtpsID; + $token = $this->_smtpsToken; + $initRes = "user=".$user."\001auth=Bearer ".$token."\001\001"; + $_retVal = $this->socket_send_str('AUTH XOAUTH2 '.base64_encode($initRes), '235'); if (!$_retVal) { $this->_setErr(130, 'Error when asking for AUTH XOAUTH2'); } @@ -631,7 +637,7 @@ class SMTPs // Connect to Server if ($this->socket = $this->_server_connect()) { // If a User ID *and* a password is given, assume Authentication is desired - if (!empty($this->_smtpsID) && !empty($this->_smtpsPW)) { + if (!empty($this->_smtpsID) && (!empty($this->_smtpsPW) || !empty($this->_smtpsToken))) { // Send the RFC2554 specified EHLO. $_retVal = $this->_server_authenticate(); } else { @@ -923,6 +929,27 @@ class SMTPs return $this->_smtpsPW; } + /** + * User token for OAUTH2 + * + * @param string $_strToken User token + * @return void + */ + public function setToken($_strToken) + { + $this->_smtpsToken = $_strToken; + } + + /** + * Retrieves the User token for OAUTH2 + * + * @return string User token for OAUTH2 + */ + public function getToken() + { + return $this->_smtpsToken; + } + /** * Character set used for current message * Character set is defaulted to 'iso-8859-1'; @@ -1866,7 +1893,7 @@ class SMTPs } if (!(substr($server_response, 0, 3) == $response)) { - $this->_setErr(120, "Ran into problems sending Mail.\r\nResponse: $server_response"); + $this->_setErr(120, "Ran into problems sending Mail.\r\nResponse:".$server_response); $_retVal = false; } diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index c1f01ae85d9..e5b8fe597bc 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2286,4 +2286,8 @@ DoesNotWorkWithAllThemes=Will not work with all themes NoName=No name ShowAdvancedOptions= Show advanced options HideAdvancedoptions= Hide advanced options -CIDLookupURL=The module brings an URL that can be used by an external tool to get the name of a thirdparty or contact from its phone number. URL to use is: +CIDLookupURL=The module brings an URL that can be used by an external tool to get the name of a thirdparty or contact from its phone number. URL to use is: +MAIN_MAIL_SMTPS_USE_OAUTH=Use OAUTH2 authentication +OauthNotAvailableForAll=OAUTH2 authentication is not available for all hosts +MAIN_MAIL_SMTPS_OAUTH_SERVICE=OAUTH2 authentication service +DontForgetCreateTokenOauthMod=A token with the right permissions must have been created upstream with the OAUTH module \ No newline at end of file diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index f374349d72f..6302377b449 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -2286,3 +2286,8 @@ NoName=Sans nom ShowAdvancedOptions= Show advanced options HideAdvancedoptions= Hide advanced options CIDLookupURL=The module brings an URL that can be used by an external tool to get the name of a thirdparty or contact from its phone number. URL to use is: +DoesNotWorkWithAllThemes=Ne fonctionne pas avec tous les thèmes +MAIN_MAIL_SMTPS_USE_OAUTH=Utilisation de l'authentification OAUTH2 +OauthNotAvailableForAll=L'authentification OAUTH2 n'est pas disponible pour tous les hôtes +MAIN_MAIL_SMTPS_OAUTH_SERVICE=Service d'authentification OAUTH2 +DontForgetCreateTokenOauthMod=Un jeton avec les bonnes permissions doit avoir été créé en amont avec le module OAUTH