Revert "feat: Support Azure single-tenant application using the Graph… (#7436)
This commit is contained in:
@@ -4,7 +4,13 @@ class Api::V1::Accounts::Microsoft::AuthorizationsController < Api::V1::Accounts
|
||||
|
||||
def create
|
||||
email = params[:authorization][:email]
|
||||
redirect_url = microsoft_client.auth_code.authorize_url(auth_params)
|
||||
redirect_url = microsoft_client.auth_code.authorize_url(
|
||||
{
|
||||
redirect_uri: "#{base_url}/microsoft/callback",
|
||||
scope: 'offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send openid profile',
|
||||
prompt: 'consent'
|
||||
}
|
||||
)
|
||||
if redirect_url
|
||||
email = email.downcase
|
||||
::Redis::Alfred.setex(email, Current.account.id, 5.minutes)
|
||||
@@ -19,31 +25,4 @@ class Api::V1::Accounts::Microsoft::AuthorizationsController < Api::V1::Accounts
|
||||
def check_authorization
|
||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||
end
|
||||
|
||||
# SMTP, Pop and IMAP are being deprecated by Outlook.
|
||||
# https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online
|
||||
#
|
||||
# As such, Microsoft has made it a real pain to use them.
|
||||
# If AZURE_TENANT_ID is set, we will use the MS Graph API instead.
|
||||
def auth_params
|
||||
return graph_auth_params if ENV.fetch('AZURE_TENANT_ID', false)
|
||||
|
||||
standard_auth_params
|
||||
end
|
||||
|
||||
def standard_auth_params
|
||||
{
|
||||
redirect_uri: "#{base_url}/microsoft/callback",
|
||||
scope: 'offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send openid profile',
|
||||
prompt: 'consent'
|
||||
}
|
||||
end
|
||||
|
||||
def graph_auth_params
|
||||
{
|
||||
redirect_uri: "#{base_url}/microsoft/callback",
|
||||
scope: 'offline_access https://graph.microsoft.com/Mail.Read https://graph.microsoft.com/Mail.Send openid profile',
|
||||
prompt: 'consent'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,8 +5,8 @@ module MicrosoftConcern
|
||||
::OAuth2::Client.new(ENV.fetch('AZURE_APP_ID', nil), ENV.fetch('AZURE_APP_SECRET', nil),
|
||||
{
|
||||
site: 'https://login.microsoftonline.com',
|
||||
authorize_url: "https://login.microsoftonline.com/#{azure_tenant_id}/oauth2/v2.0/authorize",
|
||||
token_url: "https://login.microsoftonline.com/#{azure_tenant_id}/oauth2/v2.0/token"
|
||||
authorize_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
|
||||
token_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
|
||||
})
|
||||
end
|
||||
|
||||
@@ -19,8 +19,4 @@ module MicrosoftConcern
|
||||
def base_url
|
||||
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
|
||||
end
|
||||
|
||||
def azure_tenant_id
|
||||
MicrosoftGraphAuth.azure_tenant_id
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,19 +2,8 @@ class Inboxes::FetchImapEmailInboxesJob < ApplicationJob
|
||||
queue_as :scheduled_jobs
|
||||
|
||||
def perform
|
||||
# check imap_enabled for channel
|
||||
Inbox.where(channel_type: 'Channel::Email').all.find_each(batch_size: 100) do |inbox|
|
||||
next unless inbox.channel.imap_enabled?
|
||||
|
||||
fetch_emails(inbox)
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_emails(inbox)
|
||||
if inbox.channel.microsoft? && ENV.fetch('AZURE_TENANT_ID', false)
|
||||
::Inboxes::FetchMsGraphEmailForTenantJob.perform_later(inbox.channel)
|
||||
else
|
||||
::Inboxes::FetchImapEmailsJob.perform_later(inbox.channel)
|
||||
::Inboxes::FetchImapEmailsJob.perform_later(inbox.channel) if inbox.channel.imap_enabled
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
require 'net/http'
|
||||
|
||||
class Inboxes::FetchMsGraphEmailForTenantJob < ApplicationJob
|
||||
queue_as :scheduled_jobs
|
||||
|
||||
def perform(channel)
|
||||
process_email_for_channel(channel)
|
||||
rescue EOFError => e
|
||||
Rails.logger.error e
|
||||
rescue StandardError => e
|
||||
ChatwootExceptionTracker.new(e, account: channel.account).capture_exception
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def should_fetch_email?(channel)
|
||||
channel.imap_enabled? && channel.microsoft? && !channel.reauthorization_required?
|
||||
end
|
||||
|
||||
def process_email_for_channel(channel)
|
||||
# fetching email for microsoft provider
|
||||
fetch_mail_for_channel(channel)
|
||||
|
||||
# clearing old failures like timeouts since the mail is now successfully processed
|
||||
channel.reauthorized!
|
||||
end
|
||||
|
||||
def fetch_mail_for_channel(channel)
|
||||
return if channel.provider_config['access_token'].blank?
|
||||
|
||||
access_token = valid_access_token channel
|
||||
|
||||
return unless access_token
|
||||
|
||||
graph = graph_authenticate(access_token)
|
||||
|
||||
process_mails(graph, channel)
|
||||
end
|
||||
|
||||
def process_mails(graph, channel)
|
||||
response = graph.get_from_api('me/messages', {}, graph_query)
|
||||
|
||||
unless response.is_a?(Net::HTTPSuccess)
|
||||
channel.authorization_error!
|
||||
return false
|
||||
end
|
||||
|
||||
json_response = JSON.parse(response.body)
|
||||
json_response['value'].each do |message|
|
||||
inbound_mail = Mail.read_from_string retrieve_mail_mime(graph, message['id'])
|
||||
|
||||
next if channel.inbox.messages.find_by(source_id: inbound_mail.message_id).present?
|
||||
|
||||
process_mail(inbound_mail, channel)
|
||||
end
|
||||
end
|
||||
|
||||
def retrieve_mail_mime(graph, id)
|
||||
response = graph.get_from_api("me/messages/#{id}/$value")
|
||||
return unless response.is_a?(Net::HTTPSuccess)
|
||||
|
||||
response.body
|
||||
end
|
||||
|
||||
def graph_authenticate(access_token)
|
||||
MicrosoftGraphApi.new(access_token)
|
||||
end
|
||||
|
||||
def yesterday
|
||||
(Time.zone.today - 1).strftime('%FT%TZ')
|
||||
end
|
||||
|
||||
def tomorrow
|
||||
(Time.zone.today + 1).strftime('%FT%TZ')
|
||||
end
|
||||
|
||||
# Query to replicate the IMAP search used in Inboxes::FetchImapEmailsJob
|
||||
# Selects the top 1000 records within the given filter, as that is the maximum
|
||||
# page size for the API. Might need to look into paginating the requests later,
|
||||
# for inboxes that receive more than 1000 emails a day?
|
||||
#
|
||||
# 1. https://learn.microsoft.com/en-us/graph/api/user-list-messages
|
||||
# 2. https://learn.microsoft.com/en-us/graph/query-parameters
|
||||
def graph_query
|
||||
{
|
||||
'$filter': "receivedDateTime ge #{yesterday} and receivedDateTime le #{tomorrow}",
|
||||
'$top': '1000', '$select': 'id'
|
||||
}
|
||||
end
|
||||
|
||||
def process_mail(inbound_mail, channel)
|
||||
Imap::ImapMailbox.new.process(inbound_mail, channel)
|
||||
rescue StandardError => e
|
||||
ChatwootExceptionTracker.new(e, account: channel.account).capture_exception
|
||||
end
|
||||
|
||||
# Making sure the access token is valid for microsoft provider
|
||||
def valid_access_token(channel)
|
||||
Microsoft::RefreshOauthTokenService.new(channel: channel).access_token
|
||||
end
|
||||
end
|
||||
@@ -23,7 +23,6 @@ module ConversationReplyMailerHelper
|
||||
|
||||
def ms_smtp_settings
|
||||
return unless @inbox.email? && @channel.imap_enabled && @inbox.channel.provider == 'microsoft'
|
||||
return ms_graph_settings if ENV.fetch('AZURE_TENANT_ID', false)
|
||||
|
||||
smtp_settings = {
|
||||
address: 'smtp.office365.com',
|
||||
@@ -41,15 +40,6 @@ module ConversationReplyMailerHelper
|
||||
@options[:delivery_method_options] = smtp_settings
|
||||
end
|
||||
|
||||
def ms_graph_settings
|
||||
graph_settings = {
|
||||
token: @channel.provider_config['access_token']
|
||||
}
|
||||
|
||||
@options[:delivery_method] = :microsoft_graph
|
||||
@options[:delivery_method_options] = graph_settings
|
||||
end
|
||||
|
||||
def set_delivery_method
|
||||
return unless @inbox.inbox_type == 'Email' && @channel.smtp_enabled
|
||||
|
||||
|
||||
Reference in New Issue
Block a user