mirror of
https://github.com/freescout-helpdesk/freescout.git
synced 2024-11-23 10:52:31 +01:00
Microsoft Exchange oAuth for SMTP - closes #4072
This commit is contained in:
parent
fb3b0d3a49
commit
7e8e514e7b
@ -853,6 +853,7 @@ class MailboxesController extends Controller
|
||||
{
|
||||
$mailbox_id = $request->id ?? '';
|
||||
$provider = $request->provider ?? '';
|
||||
$in_out = $request->in_out ?? 'in';
|
||||
|
||||
$state_data = [];
|
||||
if (!empty($request->state)) {
|
||||
@ -863,6 +864,9 @@ class MailboxesController extends Controller
|
||||
if (!empty($state_data['provider'])) {
|
||||
$provider = $state_data['provider'];
|
||||
}
|
||||
if (!empty($state_data['in_out'])) {
|
||||
$in_out = $state_data['in_out'];
|
||||
}
|
||||
}
|
||||
|
||||
// MS Exchange.
|
||||
@ -880,10 +884,17 @@ class MailboxesController extends Controller
|
||||
if (empty($mailbox)) {
|
||||
return __('Mailbox not found').': '.$mailbox_id;
|
||||
}
|
||||
if (empty($mailbox->in_username)) {
|
||||
if ($in_out == 'in') {
|
||||
$username = $mailbox->in_username;
|
||||
$password = $mailbox->in_password;
|
||||
} else {
|
||||
$username = $mailbox->out_username;
|
||||
$password = $mailbox->out_password;
|
||||
}
|
||||
if (empty($username)) {
|
||||
return 'Enter oAuth Client ID as Username and save mailbox settings';
|
||||
}
|
||||
if (empty($mailbox->in_password)) {
|
||||
if (empty($password)) {
|
||||
return 'Enter oAuth Client Secret as Password and save mailbox settings';
|
||||
}
|
||||
|
||||
@ -893,14 +904,16 @@ class MailboxesController extends Controller
|
||||
}
|
||||
|
||||
if (empty($request->code)) {
|
||||
// Start.
|
||||
$state = [
|
||||
'provider' => $provider,
|
||||
'mailbox_id' => $mailbox_id,
|
||||
'state' => crc32($mailbox->in_username.$mailbox->in_password),
|
||||
'in_out' => $in_out,
|
||||
'state' => crc32($username.$password),
|
||||
];
|
||||
$url = \MailHelper::oauthGetAuthorizationUrl(\MailHelper::OAUTH_PROVIDER_MICROSOFT, [
|
||||
'state' => json_encode($state),
|
||||
'client_id' => $mailbox->in_username,
|
||||
'client_id' => $username,
|
||||
]);
|
||||
if ($url) {
|
||||
\Session::put('mailbox_oauth_'.$provider.'_'.$mailbox_id, $state);
|
||||
@ -921,21 +934,35 @@ class MailboxesController extends Controller
|
||||
return 'Invalid oAuth state';
|
||||
|
||||
} else {
|
||||
|
||||
// state is set.
|
||||
// Try to get an access token (using the authorization code grant)
|
||||
$token_data = \MailHelper::oauthGetAccessToken(\MailHelper::OAUTH_PROVIDER_MICROSOFT, [
|
||||
'client_id' => $mailbox->in_username,
|
||||
'client_secret' => $mailbox->in_password,
|
||||
'client_id' => $username,
|
||||
'client_secret' => $password,
|
||||
'code' => $request->code,
|
||||
]);
|
||||
|
||||
if (!empty($token_data['a_token'])) {
|
||||
// Set username and password for the oppozite in_out.
|
||||
if ($in_out == 'in') {
|
||||
$mailbox->out_username = $username;
|
||||
$mailbox->out_password = $password;
|
||||
//$mailbox->out_method = Mailbox::OUT_METHOD_SMTP;
|
||||
} else {
|
||||
$mailbox->in_username = $username;
|
||||
$mailbox->in_password = $password;
|
||||
}
|
||||
$mailbox->setMetaParam('oauth', $token_data, true);
|
||||
} elseif (!empty($token_data['error'])) {
|
||||
return __('Error occurred').': '.htmlspecialchars($token_data['error']);
|
||||
}
|
||||
|
||||
return redirect()->route('mailboxes.connection.incoming', ['id' => $mailbox_id]);
|
||||
if ($in_out == 'in') {
|
||||
$route = 'mailboxes.connection.incoming';
|
||||
} else {
|
||||
$route = 'mailboxes.connection';
|
||||
}
|
||||
return redirect()->route($route, ['id' => $mailbox_id]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -943,12 +970,20 @@ class MailboxesController extends Controller
|
||||
{
|
||||
$mailbox_id = $request->id ?? '';
|
||||
$provider = $request->provider ?? '';
|
||||
$in_out = $request->in_out ?? 'in';
|
||||
|
||||
$mailbox = Mailbox::findOrFail($mailbox_id);
|
||||
$this->authorize('admin', $mailbox);
|
||||
|
||||
// oAuth Disconnect.
|
||||
$mailbox->removeMetaParam('oauth', true);
|
||||
return \MailHelper::oauthDisconnect($provider, route('mailboxes.connection.incoming', ['id' => $mailbox_id]));
|
||||
|
||||
if ($in_out == 'in') {
|
||||
$route = 'mailboxes.connection.incoming';
|
||||
} else {
|
||||
$route = 'mailboxes.connection';
|
||||
}
|
||||
|
||||
return \MailHelper::oauthDisconnect($provider, route($route, ['id' => $mailbox_id]));
|
||||
}
|
||||
}
|
||||
|
@ -100,20 +100,52 @@ class Mail
|
||||
public static function setMailDriver($mailbox = null, $user_from = null, $conversation = null)
|
||||
{
|
||||
if ($mailbox) {
|
||||
// Configure mail driver according to Mailbox settings
|
||||
// Configure mail driver according to Mailbox settings.
|
||||
$oauth = $mailbox->oauthEnabled();
|
||||
|
||||
// Refresh Access Token.
|
||||
if ($oauth) {
|
||||
if ((strtotime($mailbox->oauthGetParam('issued_on')) + (int)$mailbox->oauthGetParam('expires_in')) < time()) {
|
||||
// Try to get an access token (using the authorization code grant)
|
||||
$token_data = \MailHelper::oauthGetAccessToken(\MailHelper::OAUTH_PROVIDER_MICROSOFT, [
|
||||
'client_id' => $mailbox->out_username,
|
||||
'client_secret' => $mailbox->out_password,
|
||||
'refresh_token' => $mailbox->oauthGetParam('r_token'),
|
||||
]);
|
||||
|
||||
if (!empty($token_data['a_token'])) {
|
||||
$mailbox->setMetaParam('oauth', $token_data, true);
|
||||
} elseif (!empty($token_data['error'])) {
|
||||
$error_message = 'Error occurred refreshing oAuth Access Token: '.$token_data['error'];
|
||||
\Helper::log(\App\ActivityLog::NAME_EMAILS_SENDING,
|
||||
\App\ActivityLog::DESCRIPTION_EMAILS_SENDING_ERROR_TO_CUSTOMER, [
|
||||
'error' => $error_message,
|
||||
'mailbox' => $mailbox->name,
|
||||
]);
|
||||
//throw new \Exception($error_message, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\Config::set('mail.driver', $mailbox->getMailDriverName());
|
||||
\Config::set('mail.from', $mailbox->getMailFrom($user_from, $conversation));
|
||||
|
||||
// SMTP
|
||||
// SMTP.
|
||||
if ($mailbox->out_method == Mailbox::OUT_METHOD_SMTP) {
|
||||
\Config::set('mail.host', $mailbox->out_server);
|
||||
\Config::set('mail.port', $mailbox->out_port);
|
||||
if (!$mailbox->out_username) {
|
||||
\Config::set('mail.username', null);
|
||||
\Config::set('mail.password', null);
|
||||
if ($oauth) {
|
||||
\Config::set('mail.auth_mode', 'XOAUTH2');
|
||||
\Config::set('mail.username', $mailbox->email);
|
||||
\Config::set('mail.password', $mailbox->oauthGetParam('a_token'));
|
||||
} else {
|
||||
\Config::set('mail.username', $mailbox->out_username);
|
||||
\Config::set('mail.password', $mailbox->out_password);
|
||||
if (!$mailbox->out_username) {
|
||||
\Config::set('mail.username', null);
|
||||
\Config::set('mail.password', null);
|
||||
} else {
|
||||
\Config::set('mail.username', $mailbox->out_username);
|
||||
\Config::set('mail.password', $mailbox->out_password);
|
||||
}
|
||||
}
|
||||
\Config::set('mail.encryption', $mailbox->getOutEncryptionName());
|
||||
}
|
||||
|
@ -88,6 +88,17 @@ return [
|
||||
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auth mode
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 'login' or 'XOAUTH2'
|
||||
|
|
||||
*/
|
||||
|
||||
'auth_mode' => env('MAIL_AUTH_MODE', 'login'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Sendmail System Path
|
||||
|
@ -31,7 +31,7 @@ class TransportManager extends Manager
|
||||
// The Swift SMTP transport instance will allow us to use any SMTP backend
|
||||
// for delivering mail such as Sendgrid, Amazon SES, or a custom server
|
||||
// a developer has available. We will just pass this configured host.
|
||||
$transport = new SmtpTransport($config['host'], $config['port']);
|
||||
$transport = new SmtpTransport($config['host'], $config['port'], null, $config['auth_mode']);
|
||||
|
||||
if (isset($config['encryption'])) {
|
||||
$transport->setEncryption($config['encryption']);
|
||||
|
@ -27,7 +27,7 @@ class Swift_SmtpTransport extends Swift_Transport_EsmtpTransport
|
||||
* @param int $port
|
||||
* @param string $encryption
|
||||
*/
|
||||
public function __construct($host = 'localhost', $port = 25, $encryption = null)
|
||||
public function __construct($host = 'localhost', $port = 25, $encryption = null, $auth_mode = 'login')
|
||||
{
|
||||
parent::__construct(...Swift_DependencyContainer::getInstance()->createDependenciesFor('transport.smtp'));
|
||||
// call_user_func_array(
|
||||
@ -39,5 +39,6 @@ class Swift_SmtpTransport extends Swift_Transport_EsmtpTransport
|
||||
$this->setHost($host);
|
||||
$this->setPort($port);
|
||||
$this->setEncryption($encryption);
|
||||
$this->setAuthMode($auth_mode);
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@
|
||||
<label for="out_username" class="col-sm-2 control-label">{{ __('Username') }}</label>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<input id="out_username" type="text" class="form-control input-sized" name="out_username" value="{{ old('out_username', $mailbox->out_username) }}" maxlength="100" @if ($mailbox->out_method == App\Mailbox::OUT_METHOD_SMTP) @endif autofocus {{-- This added to prevent autocomplete in Chrome --}}autocomplete="new-password">
|
||||
<input id="out_username" type="text" class="form-control input-sized @if ($mailbox->oauthEnabled()) disabled @endif" name="out_username" value="{{ old('out_username', $mailbox->out_username) }}" maxlength="100" @if ($mailbox->out_method == App\Mailbox::OUT_METHOD_SMTP) @endif autofocus {{-- This added to prevent autocomplete in Chrome --}}autocomplete="new-password" @if ($mailbox->oauthEnabled()) readonly @endif>
|
||||
|
||||
@include('partials/field_error', ['field'=>'out_username'])
|
||||
</div>
|
||||
@ -97,9 +97,19 @@
|
||||
<label for="out_password" class="col-sm-2 control-label">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<input id="out_password" type="password" class="form-control input-sized" name="out_password" value="{{ old('out_password', $mailbox->outPasswordSafe()) }}" maxlength="255" @if ($mailbox->out_method == App\Mailbox::OUT_METHOD_SMTP) @endif autofocus {{-- This added to prevent autocomplete in Chrome --}}autocomplete="new-password">
|
||||
<input id="out_password" type="password" class="form-control input-sized @if ($mailbox->oauthEnabled()) disabled @endif" name="out_password" value="{{ old('out_password', $mailbox->outPasswordSafe()) }}" maxlength="255" @if ($mailbox->out_method == App\Mailbox::OUT_METHOD_SMTP) @endif autofocus {{-- This added to prevent autocomplete in Chrome --}}autocomplete="new-password" @if ($mailbox->oauthEnabled()) readonly @endif>
|
||||
|
||||
@include('partials/field_error', ['field'=>'out_password'])
|
||||
<p class="form-help">
|
||||
<small @if ($mailbox->oauthGetParam('provider') == \MailHelper::OAUTH_PROVIDER_MICROSOFT) class="text-success" @endif>Microsoft Exchange</small>
|
||||
@if (!$mailbox->oauthEnabled())
|
||||
@if ($mailbox->out_username && $mailbox->out_password && !strstr($mailbox->out_username, '@'))
|
||||
– <a href="{{ route('mailboxes.oauth', ['id' => $mailbox->id, 'provider' => \MailHelper::OAUTH_PROVIDER_MICROSOFT, 'in_out' => 'out']) }}" target="_blank">{{ __('Connect') }}</a>
|
||||
@endif
|
||||
@elseif ($mailbox->oauthGetParam('provider') == \MailHelper::OAUTH_PROVIDER_MICROSOFT)
|
||||
– <a href="{{ route('mailboxes.oauth_disconnect', ['id' => $mailbox->id, 'provider' => \MailHelper::OAUTH_PROVIDER_MICROSOFT, 'in_out' => 'out']) }}">{{ __('Disconnect') }}</a>
|
||||
@endif
|
||||
<small>(<a href="https://github.com/freescout-helpdesk/freescout/wiki/Connect-FreeScout-to-Microsoft-365-Exchange-via-oAuth" target="_blank">{{ __('Help') }}</a>)</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group{{ $errors->has('out_encryption') ? ' has-error' : '' }}">
|
||||
|
@ -109,10 +109,10 @@
|
||||
<small @if ($mailbox->oauthGetParam('provider') == \MailHelper::OAUTH_PROVIDER_MICROSOFT) class="text-success" @endif>Microsoft Exchange</small>
|
||||
@if (!$mailbox->oauthEnabled())
|
||||
@if ($mailbox->in_username && $mailbox->in_password && !strstr($mailbox->in_username, '@'))
|
||||
– <a href="{{ route('mailboxes.oauth', ['id' => $mailbox->id, 'provider' => \MailHelper::OAUTH_PROVIDER_MICROSOFT]) }}" target="_blank">{{ __('Connect') }}</a>
|
||||
– <a href="{{ route('mailboxes.oauth', ['id' => $mailbox->id, 'provider' => \MailHelper::OAUTH_PROVIDER_MICROSOFT, 'in_out' => 'in']) }}" target="_blank">{{ __('Connect') }}</a>
|
||||
@endif
|
||||
@elseif ($mailbox->oauthGetParam('provider') == \MailHelper::OAUTH_PROVIDER_MICROSOFT)
|
||||
– <a href="{{ route('mailboxes.oauth_disconnect', ['id' => $mailbox->id, 'provider' => \MailHelper::OAUTH_PROVIDER_MICROSOFT]) }}">{{ __('Disconnect') }}</a>
|
||||
– <a href="{{ route('mailboxes.oauth_disconnect', ['id' => $mailbox->id, 'provider' => \MailHelper::OAUTH_PROVIDER_MICROSOFT, 'in_out' => 'in']) }}">{{ __('Disconnect') }}</a>
|
||||
@endif
|
||||
<small>(<a href="https://github.com/freescout-helpdesk/freescout/wiki/Connect-FreeScout-to-Microsoft-365-Exchange-via-oAuth" target="_blank">{{ __('Help') }}</a>)</small>
|
||||
</p>
|
||||
|
@ -89,9 +89,9 @@ Route::post('/mailbox/connection-settings/{id}/incoming', 'MailboxesController@c
|
||||
Route::get('/mailbox/settings/{id}/auto-reply', 'MailboxesController@autoReply')->name('mailboxes.auto_reply');
|
||||
Route::post('/mailbox/settings/{id}/auto-reply', 'MailboxesController@autoReplySave')->name('mailboxes.auto_reply.save');
|
||||
Route::post('/mailbox/ajax', ['uses' => 'MailboxesController@ajax', 'laroute' => true])->name('mailboxes.ajax');
|
||||
Route::get('/mailbox/oauth/{id}/{provider}', ['uses' => 'MailboxesController@oauth'])->name('mailboxes.oauth');
|
||||
Route::get('/mailbox/oauth/{id}/{in_out}/{provider}', ['uses' => 'MailboxesController@oauth'])->name('mailboxes.oauth');
|
||||
Route::get('/mailbox/oauth', ['uses' => 'MailboxesController@oauth'])->name('mailboxes.oauth_callback');
|
||||
Route::get('/mailbox/oauth-disconnect/{id}/{provider}', ['uses' => 'MailboxesController@oauthDisconnect'])->name('mailboxes.oauth_disconnect');
|
||||
Route::get('/mailbox/oauth-disconnect/{id}/{in_out}/{provider}', ['uses' => 'MailboxesController@oauthDisconnect'])->name('mailboxes.oauth_disconnect');
|
||||
|
||||
// Customers
|
||||
Route::get('/customers/{id}/edit', 'CustomersController@update')->name('customers.update');
|
||||
|
Loading…
Reference in New Issue
Block a user