Exchange changes:

- Fixed bug: Not possible to disable SSL certificate check for import but only for autodiscover.
- Improved SSL certificate error message to show domain of affected domain to prevent users from thinking that there is an issue with their Zammad installation.
This commit is contained in:
Thorsten Eckel 2017-11-03 11:40:11 +01:00
parent c87f75cc97
commit 3fc78c657c
5 changed files with 138 additions and 71 deletions

View file

@ -174,17 +174,18 @@ class ConnectionWizard extends App.WizardModal
'js-mapping': 'mappingShow' 'js-mapping': 'mappingShow'
events: events:
'submit form.js-discover': 'discover' 'submit form.js-discover': 'discover'
'submit form.js-discoverSsl': 'discover' 'submit form.js-discoverCertificateIssue': 'discover'
'submit form.js-bind': 'folders' 'submit form.js-bind': 'folders'
'submit form.js-folders': 'mapping' 'submit form.js-bindCertificateIssue': 'folders'
'click .js-cancelSsl': 'showSlideDiscover' 'submit form.js-folders': 'mapping'
'click .js-mapping .js-submitTry': 'mappingChange' 'click .js-cancelSsl': 'showSlideDiscover'
'click .js-try .js-submitSave': 'save' 'click .js-mapping .js-submitTry': 'mappingChange'
'click .js-close': 'hide' 'click .js-try .js-submitSave': 'save'
'click .js-remove': 'removeRow' 'click .js-close': 'hide'
'click .js-userMappingForm .js-add': 'addUserMapping' 'click .js-remove': 'removeRow'
'click .js-goToSlide': 'goToSlide' 'click .js-userMappingForm .js-add': 'addUserMapping'
'click .js-goToSlide': 'goToSlide'
elements: elements:
'.modal-body': 'body' '.modal-body': 'body'
@ -261,20 +262,17 @@ class ConnectionWizard extends App.WizardModal
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
if data.result isnt 'ok' if data.result isnt 'ok'
@handleCertificateIssue(
if data.message.indexOf('certificate') is -1 message: data.message
@showSlide('js-discover') wizardClass: 'js-discover'
@showAlert('js-discover', data.message) user: params.user
else password: params.password
@$('.js-discoverSsl input[name="user"]').val(params.user) )
@$('.js-discoverSsl input[name="password"]').val(params.password)
@showSlide('js-discoverSsl')
return return
@wizardConfig.endpoint = data.endpoint @wizardConfig.disable_ssl_verify = params.disable_ssl_verify
@wizardConfig.user = params.user @wizardConfig.user = params.user
@wizardConfig.password = params.password @wizardConfig.password = params.password
@showSlide('js-bind') @showSlide('js-bind')
@showBindDetails() @showBindDetails()
@ -300,13 +298,19 @@ class ConnectionWizard extends App.WizardModal
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
if data.result isnt 'ok' if data.result isnt 'ok'
@showSlide('js-bind') @handleCertificateIssue(
@showAlert('js-bind', data.message) message: data.message
wizardClass: 'js-bind'
endpoint: params.endpoint
user: params.user
password: params.password
)
return return
@wizardConfig.endpoint = params.endpoint @wizardConfig.disable_ssl_verify = params.disable_ssl_verify
@wizardConfig.user = params.user @wizardConfig.endpoint = params.endpoint
@wizardConfig.password = params.password @wizardConfig.user = params.user
@wizardConfig.password = params.password
# update wizard data # update wizard data
@wizardConfig.wizardData = {} @wizardConfig.wizardData = {}
@ -341,6 +345,45 @@ class ConnectionWizard extends App.WizardModal
@foldersSelectSubmit.addClass('is-disabled') @foldersSelectSubmit.addClass('is-disabled')
) )
handleCertificateIssue: (params) =>
if params.message.indexOf('certificate') is -1
@showSlide(params.wizardClass)
@showAlert(params.wizardClass, params.message)
else
wizardClass = "#{params.wizardClass}CertificateIssue"
domain = @domainFromMessageOrEmail(
message: params.message
user: params.user
)
wizardSlide = App.view('integration/exchange_certificate_issue')(
wizardClass: wizardClass
endpoint: params.endpoint
user: params.user
password: params.password
domain: domain
)
@$('.js-certificateIssuePlaceholder').html(wizardSlide)
@showSlide(wizardClass)
domainFromMessageOrEmail: (params) ->
# try to extract the hostname from the error message
hostname = params.message.match(/hostname[ ]\"([^\"]+)"/i)
if hostname
return hostname[1]
# try to extract it from the given user
emailDomain = params.user.match(/@(.*)$/)
if emailDomain
return emailDomain[1]
# fallback to user - better than no value?!
return user
mapping: (e) => mapping: (e) =>
e.preventDefault() e.preventDefault()
@showSlide('js-analyze') @showSlide('js-analyze')

View file

@ -0,0 +1,25 @@
<form class="modal-content setup wizard hide <%= @wizardClass %>">
<input type="hidden" name="disable_ssl_verify" value="1">
<input type="hidden" name="endpoint" value="<%= @endpoint %>">
<input type="hidden" name="user" value="<%= @user %>">
<input type="hidden" name="password" value="<%= @password %>">
<div class="modal-header">
<div class="modal-close js-close">
<%- @Icon('diagonal-cross') %>
</div>
<h1 class="modal-title"><%- @T('Your connection is not private') %></h1>
</div>
<div class="modal-body">
<div class="wizard-body vertical">
<p><%- @T('The certificate of the domain |%s| could not be verified. This may allow hackers to steal your credentials. If you are sure that you are using a self-signed certificate, you can press "Proceed". Otherwise, please "Cancel".', @domain) %></p>
</div>
</div>
<div class="modal-footer">
<div class="modal-leftFooter">
<button class="btn btn--text btn--danger btn--secondary js-submit"><%- @T('Proceed') %></button>
</div>
<div class="modal-rightFooter">
<a class="btn btn--primary align-right js-cancelSsl"><%- @T('Cancel') %></a>
</div>
</div>
</form>

View file

@ -34,30 +34,7 @@
</div> </div>
</form> </form>
<form class="modal-content setup wizard hide js-discoverSsl"> <div class="js-certificateIssuePlaceholder"></div>
<input type="hidden" name="disable_ssl_verify" value="1">
<input type="hidden" name="user" value="">
<input type="hidden" name="password" value="">
<div class="modal-header">
<div class="modal-close js-close">
<%- @Icon('diagonal-cross') %>
</div>
<h1 class="modal-title"><%- @T('Your connection is not private') %></h1>
</div>
<div class="modal-body">
<div class="wizard-body vertical">
<p><%- @T('The certificate of the domain could not be verified. Hackers could steal the credentials or redirect the connection. Or maybe you are using a self-signed certificate.') %></p>
</div>
</div>
<div class="modal-footer">
<div class="modal-leftFooter">
<button class="btn btn--text btn--danger btn--secondary js-submit"><%- @T('Proceed') %></button>
</div>
<div class="modal-rightFooter">
<a class="btn btn--primary align-right js-cancelSsl"><%- @T('Cancel') %></a>
</div>
</div>
</form>
<form class="modal-content setup wizard hide js-connect"> <form class="modal-content setup wizard hide js-connect">
<div class="modal-header"> <div class="modal-header">

View file

@ -26,11 +26,7 @@ class Integration::ExchangeController < ApplicationController
answer_with do answer_with do
Sequencer.process('Import::Exchange::AvailableFolders', Sequencer.process('Import::Exchange::AvailableFolders',
parameters: { parameters: {
ews_config: { ews_config: ews_config
endpoint: params[:endpoint],
user: params[:user],
password: params[:password],
}
}) })
end end
end end
@ -42,11 +38,7 @@ class Integration::ExchangeController < ApplicationController
examples = Sequencer.process('Import::Exchange::AttributesExamples', examples = Sequencer.process('Import::Exchange::AttributesExamples',
parameters: { parameters: {
ews_folder_ids: params[:folders], ews_folder_ids: params[:folders],
ews_config: { ews_config: ews_config
endpoint: params[:endpoint],
user: params[:user],
password: params[:password],
}
}) })
examples.tap do |result| examples.tap do |result|
raise 'No entries found in selected folder(s).' if result[:attributes].blank? raise 'No entries found in selected folder(s).' if result[:attributes].blank?
@ -61,15 +53,20 @@ class Integration::ExchangeController < ApplicationController
{ {
ews_attributes: params[:attributes].permit!.to_h, ews_attributes: params[:attributes].permit!.to_h,
ews_folder_ids: params[:folders], ews_folder_ids: params[:folders],
ews_config: { ews_config: ews_config
endpoint: params[:endpoint],
user: params[:user],
password: params[:password],
}
} }
end end
def payload_import def payload_import
nil nil
end end
def ews_config
{
disable_ssl_verify: params[:disable_ssl_verify],
endpoint: params[:endpoint],
user: params[:user],
password: params[:password],
}
end
end end

View file

@ -11,12 +11,37 @@ class Sequencer
return if state.provided?(:ews_connection) return if state.provided?(:ews_connection)
state.provide(:ews_connection) do state.provide(:ews_connection) do
config = ews_config Viewpoint::EWSClient.new(
config ||= ::Import::Exchange.config config[:endpoint],
config[:user],
Viewpoint::EWSClient.new(config[:endpoint], config[:user], config[:password]) config[:password],
additional_opts
)
end end
end end
private
def config
@config ||= begin
ews_config || ::Import::Exchange.config
end
end
def additional_opts
@additional_opts ||= begin
http_opts
end
end
def http_opts
return {} if config[:disable_ssl_verify].blank?
{
http_opts: {
ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE
}
}
end
end end
end end
end end