Browse Source

Fixes #4607 - Reauthenticating an existing Microsoft365 channel with the wrong email account changes the used email address.

Florian Liebe 1 year ago
parent
commit
a89341f69d

+ 16 - 0
app/assets/javascripts/app/controllers/_channel/microsoft365.coffee

@@ -131,6 +131,10 @@ class ChannelAccountOverview extends App.ControllerSubContent
       @error_code = undefined
       new App.AdminConsentInfo(container: @container)
 
+    if @error_code is 'user_mismatch'
+      @error_code = undefined
+      new App.UserMismatchInfo(container: @container)
+
   show: (params) =>
     for key, value of params
       if key isnt 'el' && key isnt 'shown' && key isnt 'match'
@@ -448,4 +452,16 @@ class App.AdminConsentInfo extends App.ControllerModal
   onSubmit: =>
     @close()
 
+class App.UserMismatchInfo extends App.ControllerModal
+  buttonClose: true
+  small: true
+  buttonSubmit: __('Close')
+  head: __('User Mismatch')
+
+  content: ->
+    App.view('microsoft365/user_mismatch')()
+
+  onSubmit: =>
+    @close()
+
 App.Config.set('microsoft365', { prio: 5000, name: __('Microsoft 365'), parent: '#channels', target: '#channels/microsoft365', controller: App.ChannelMicrosoft365, permission: ['admin.channel_microsoft365'] }, 'NavBarAdmin')

+ 5 - 0
app/assets/javascripts/app/views/microsoft365/user_mismatch.jst.eco

@@ -0,0 +1,5 @@
+<p>
+  <%- @T('The entered user for reauthentication differs from the user that was used for setting up your Microsoft365 initially.') %><br><br>
+  <%- @T('To avoid fetching an incorrect Microsoft365 mailbox, the reauthentication process was aborted.') %><br><br>
+  <%- @T('Please start the reauthentication again and enter the correct credentials.') %>
+</p>

+ 16 - 0
i18n/zammad.pot

@@ -8501,6 +8501,10 @@ msgstr ""
 msgid "Please select the authentication method that should be used to establish the connection to your Exchange server."
 msgstr ""
 
+#: app/assets/javascripts/app/views/microsoft365/user_mismatch.jst.eco
+msgid "Please start the reauthentication again and enter the correct credentials."
+msgstr ""
+
 #: app/controllers/knowledge_base/manage_controller.rb
 msgid "Please submit custom address before generating the snippet"
 msgstr ""
@@ -10658,6 +10662,10 @@ msgstr ""
 msgid "The divider between TicketHook and ticket number. E. g. ': '."
 msgstr ""
 
+#: app/assets/javascripts/app/views/microsoft365/user_mismatch.jst.eco
+msgid "The entered user for reauthentication differs from the user that was used for setting up your Microsoft365 initially."
+msgstr ""
+
 #: app/assets/javascripts/app/controllers/_channel/facebook.coffee
 #: app/assets/javascripts/app/controllers/_channel/google.coffee
 #: app/assets/javascripts/app/controllers/_channel/microsoft365.coffee
@@ -11833,6 +11841,10 @@ msgstr ""
 msgid "To archive all outgoing emails from Zammad to external, you can store a BCC email address here."
 msgstr ""
 
+#: app/assets/javascripts/app/views/microsoft365/user_mismatch.jst.eco
+msgid "To avoid fetching an incorrect Microsoft365 mailbox, the reauthentication process was aborted."
+msgstr ""
+
 #: app/assets/javascripts/app/controllers/chat.coffee
 msgid "To be able to chat you need to select at least one chat topic from below!"
 msgstr ""
@@ -12442,6 +12454,10 @@ msgstr ""
 msgid "User Filter"
 msgstr ""
 
+#: app/assets/javascripts/app/controllers/_channel/microsoft365.coffee
+msgid "User Mismatch"
+msgstr ""
+
 #: db/seeds/settings.rb
 msgid "User Organization Selector - email"
 msgstr ""

+ 12 - 0
lib/external_credential/microsoft365.rb

@@ -82,6 +82,14 @@ class ExternalCredential::Microsoft365
     if params[:channel_id]
       existing_channel = Channel.where(area: 'Microsoft365::Account').find(params[:channel_id])
 
+      # Check if current user of the channel is matching the user from the token.
+      token_user    = user_data[:preferred_username]&.downcase
+      inbound_user  = channel_user(existing_channel, :inbound)&.downcase
+      outbound_user = channel_user(existing_channel, :outbound)&.downcase
+      if (inbound_user.present? && inbound_user != token_user) || (outbound_user.present? && outbound_user != token_user)
+        return "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/#channels/microsoft365/error/user_mismatch"
+      end
+
       channel_options[:inbound][:options][:folder]         = existing_channel.options[:inbound][:options][:folder]
       channel_options[:inbound][:options][:keep_on_server] = existing_channel.options[:inbound][:options][:keep_on_server]
 
@@ -275,4 +283,8 @@ class ExternalCredential::Microsoft365
     JSON.parse(Base64.decode64(split)).symbolize_keys
   end
 
+  def self.channel_user(channel, key)
+    channel.options.dig(key.to_sym, :options, :user)
+  end
+
 end

+ 20 - 0
spec/lib/external_credential/microsoft365_spec.rb

@@ -117,6 +117,26 @@ RSpec.describe ExternalCredential::Microsoft365 do
         channel = described_class.link_account(request_token, authorization_payload.merge(channel_id: channel.id))
         expect(channel.reload.options[:inbound][:options][:keep_on_server]).to be(true)
       end
+
+      context 'when users do not match', :aggregate_failures do
+        let(:existing_channel) do
+          ENV['MICROSOFT365_USER']          = 'zammad@outlook.com'
+          ENV['MICROSOFT365_CLIENT_ID']     = 'xxx'
+          ENV['MICROSOFT365_CLIENT_SECRET'] = 'xxx'
+          ENV['MICROSOFT365_CLIENT_TENANT'] = 'xxx'
+
+          create(:microsoft365_channel)
+        end
+
+        it 'generates a link to an error dialog & does not update the channel' do
+          link_account_response = described_class.link_account(request_token, authorization_payload.merge(channel_id: existing_channel.id))
+
+          expect(link_account_response).to eq("#{Setting.get('http_type')}://#{Setting.get('fqdn')}/#channels/microsoft365/error/user_mismatch")
+
+          expect(existing_channel.reload.options.dig(:inbound, :options, :user)).to eq('zammad@outlook.com')
+          expect(existing_channel.reload.options.dig(:outbound, :options, :user)).to eq('zammad@outlook.com')
+        end
+      end
     end
 
     context 'API errors' do