Implemented issue #439 - proxy support.

This commit is contained in:
Martin Edenhofer 2017-01-16 01:24:56 +01:00
parent e406c4bcee
commit a1a56f49c0
12 changed files with 377 additions and 2 deletions

View file

@ -196,7 +196,18 @@ test:integration:user_agent:
- rake db:migrate
- ruby -I test/ test/integration/user_agent_test.rb
- rake db:drop
allow_failure: true
test:integration:user_agent_proxy:
stage: test
tags:
- core
script:
- export ZAMMAD_PROXY_TEST=true
- export RAILS_ENV=test
- rake db:create
- rake db:migrate
- ruby -I test/ test/integration/user_agent_test.rb
- rake db:drop
test:integration:user_device:
stage: test

View file

@ -11,6 +11,8 @@ class System extends App.ControllerTabs
@tabs.push { name: 'Services', 'target': 'services', controller: App.SettingsArea, params: { area: 'System::Services' } }
if !App.Config.get('system_online_service')
@tabs.push { name: 'Storage', 'target': 'storage', controller: App.SettingsArea, params: { area: 'System::Storage' } }
if !App.Config.get('system_online_service')
@tabs.push { name: 'Network', 'target': 'network', controller: App.SettingsArea, params: { area: 'System::Network' } }
@tabs.push { name: 'Frontend', 'target': 'ui', controller: App.SettingsArea, params: { area: 'System::UI' } }
@render()

View file

@ -27,6 +27,12 @@ class App.SettingsArea extends App.Controller
)
return if _.isEmpty(settings)
# filter disabled settings
settings = _.filter(settings, (setting) ->
return if setting.preferences && setting.preferences.disabled
setting
)
# sort by prio
settings = _.sortBy( settings, (setting) ->
return if !setting.preferences

View file

@ -0,0 +1,58 @@
class App.SettingsAreaProxy extends App.Controller
events:
'submit form': 'update'
'click .js-submit': 'update'
'click .js-test': 'test2'
constructor: ->
super
@render()
render: =>
@html App.view('settings/proxy')(
setting: App.Setting.findByAttribute('name', 'proxy')
proxy: App.Setting.get('proxy')
proxy_username: App.Setting.get('proxy_username')
proxy_password: App.Setting.get('proxy_password')
)
update: (e) =>
e.preventDefault()
@formDisable(e)
params = @formParam(e)
console.log('params', params)
App.Setting.set('proxy', params.proxy)
App.Setting.set('proxy_username', params.proxy_username)
App.Setting.set('proxy_password', params.proxy_password)
@formEnable(e)
@render()
test2: (e) =>
e.preventDefault()
params = @formParam(e)
@ajax(
id: 'proxy_test'
type: 'POST'
url: "#{@apiPath}/proxy"
data: JSON.stringify(params)
processData: true
success: (data, status, xhr) =>
if data.result is 'success'
@$('.js-test').addClass('hide')
@$('.js-submit').removeClass('hide')
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent('Connection test successful')
timeout: 2000
}
return
new App.ControllerConfirm(
head: 'Error'
message: data.message
buttonClass: 'btn--success'
buttonCancel: false
buttonSubmit: 'Close'
container: @el.closest('.content')
)
)

View file

@ -30,6 +30,12 @@ class App.SettingsForm extends App.Controller
)
return if _.isEmpty(settings)
# filter disabled settings
settings = _.filter(settings, (setting) ->
return if setting.preferences && setting.preferences.disabled
setting
)
# sort by prio
settings = _.sortBy( settings, (setting) ->
return if !setting.preferences

View file

@ -0,0 +1,25 @@
<form class="settings-entry" id="<%= @setting.name %>">
<h2><%- @T(@setting.title) %></h2>
<p class="help-text"><%- @T('Proxy address.') %></p>
<div class="horizontal end">
<div class="form-item flex">
<input type="text" name="proxy" value="<%= @proxy %>" placeholder="proxy.example.com:3128" class="form-control">
</div>
</div>
<p class="help-text"><%- @T('Username for proxy connection.') %></p>
<div class="horizontal end">
<div class="form-item flex">
<input type="text" name="proxy_username" value="<%= @proxy_username %>" class="form-control">
</div>
</div>
<p class="help-text"><%- @T('Password for proxy connection.') %></p>
<div class="horizontal end">
<div class="form-item flex">
<input type="text" name="proxy_password" value="<%= @proxy_password %>" class="form-control">
</div>
</div>
<div class="horizontal justify-end form-controls">
<button class="btn btn js-test"><%- @T('Test Connection') %></button>
<button class="btn btn--primary js-submit hide"><%- @T('Submit') %></button>
<div>
</form>

View file

@ -0,0 +1,37 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ProxyController < ApplicationController
before_action { authentication_check(permission: 'admin.system') }
# POST /api/v1/proxy
def test
url = 'http://zammad.org'
options = params
options[:open_timeout] = 12
options[:read_timeout] = 24
begin
result = UserAgent.get(
url,
{},
options,
)
rescue => e
render json: {
result: 'failed',
message: e.inspect
}
return
end
if result.success?
render json: {
result: 'success'
}
return
end
render json: {
result: 'failed',
message: result.body || result.error || result.code
}
end
end

6
config/routes/proxy.rb Normal file
View file

@ -0,0 +1,6 @@
Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
match api_path + '/proxy', to: 'proxy#test', via: :post
end

View file

@ -0,0 +1,82 @@
class AddProxySettings439 < ActiveRecord::Migration
def up
# return if it's a new setup
return if !Setting.find_by(name: 'system_init_done')
Setting.create_if_not_exists(
title: 'Proxy Settings',
name: 'proxy',
area: 'System::Network',
description: 'Address of the proxy server for http and https resources.',
options: {
form: [
{
display: '',
null: false,
name: 'proxy',
tag: 'input',
placeholder: 'proxy.example.com:3128',
},
],
},
state: '',
preferences: {
online_service_disable: true,
controller: 'SettingsAreaProxy',
prio: 1,
permission: ['admin.system'],
},
frontend: false
)
Setting.create_if_not_exists(
title: 'Proxy User',
name: 'proxy_username',
area: 'System::Network',
description: 'Username for proxy connection.',
options: {
form: [
{
display: '',
null: false,
name: 'proxy_username',
tag: 'input',
},
],
},
state: '',
preferences: {
disabled: true,
online_service_disable: true,
prio: 2,
permission: ['admin.system'],
},
frontend: false
)
Setting.create_if_not_exists(
title: 'Proxy Password',
name: 'proxy_password',
area: 'System::Network',
description: 'Password for proxy connection.',
options: {
form: [
{
display: '',
null: false,
name: 'proxy_passowrd',
tag: 'input',
},
],
},
state: '',
preferences: {
disabled: true,
online_service_disable: true,
prio: 3,
permission: ['admin.system'],
},
frontend: false
)
end
end

View file

@ -394,6 +394,80 @@ Setting.create_if_not_exists(
frontend: false
)
Setting.create_if_not_exists(
title: 'Proxy Settings',
name: 'proxy',
area: 'System::Network',
description: 'Address of the proxy server for http and https resources.',
options: {
form: [
{
display: '',
null: false,
name: 'proxy',
tag: 'input',
placeholder: 'proxy.example.com:3128',
},
],
},
state: '',
preferences: {
online_service_disable: true,
controller: 'SettingsAreaProxy',
prio: 1,
permission: ['admin.system'],
},
frontend: false
)
Setting.create_if_not_exists(
title: 'Proxy User',
name: 'proxy_username',
area: 'System::Network',
description: 'Username for proxy connection.',
options: {
form: [
{
display: '',
null: false,
name: 'proxy_username',
tag: 'input',
},
],
},
state: '',
preferences: {
disabled: true,
online_service_disable: true,
prio: 2,
permission: ['admin.system'],
},
frontend: false
)
Setting.create_if_not_exists(
title: 'Proxy Password',
name: 'proxy_password',
area: 'System::Network',
description: 'Password for proxy connection.',
options: {
form: [
{
display: '',
null: false,
name: 'proxy_passowrd',
tag: 'input',
},
],
},
state: '',
preferences: {
disabled: true,
online_service_disable: true,
prio: 3,
permission: ['admin.system'],
},
frontend: false
)
Setting.create_if_not_exists(
title: 'Send client stats',
name: 'ui_send_client_stats',

View file

@ -262,7 +262,29 @@ returns
end
def self.get_http(uri, options)
http = Net::HTTP.new(uri.host, uri.port)
proxy = options['proxy'] || Setting.get('proxy')
if proxy.present?
if proxy =~ /^(.+?):(.+?)$/
proxy_host = $1
proxy_port = $2
else
raise "Invalid proxy address: #{proxy} - expect e.g. proxy.example.com:3128"
end
proxy_username = options['proxy_username'] || Setting.get('proxy_username')
if proxy_username.blank?
proxy_username = nil
end
proxy_password = options['proxy_password'] || Setting.get('proxy_password')
if proxy_password.blank?
proxy_password = nil
end
http = Net::HTTP::Proxy(proxy_host, proxy_port, proxy_username, proxy_password).new(uri.host, uri.port)
else
http = Net::HTTP.new(uri.host, uri.port)
end
http.open_timeout = options[:open_timeout] || 4
http.read_timeout = options[:read_timeout] || 10

View file

@ -5,6 +5,13 @@ class UserAgentTest < ActiveSupport::TestCase
host = 'https://r2d2.znuny.com'
#host = 'http://127.0.0.1:3003'
setup do
return if ENV['ZAMMAD_PROXY_TEST'] != 'true'
Setting.set('proxy', ENV['ZAMMAD_PROXY'])
Setting.set('proxy_username', ENV['ZAMMAD_PROXY_USERNAME'])
Setting.set('proxy_password', ENV['ZAMMAD_PROXY_PASSWORD'])
end
# check
test 'check some results' do
@ -19,6 +26,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"get"/)
assert(result.body =~ /"123"/)
assert(result.body =~ /"content_type_requested":null/)
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# get / 404
result = UserAgent.get(
@ -43,6 +53,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"post"/)
assert(result.body =~ /"some value"/)
assert(result.body =~ %r{"application/x-www-form-urlencoded"})
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# post / 404
result = UserAgent.post(
@ -70,6 +83,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"put"/)
assert(result.body =~ /"some value"/)
assert(result.body =~ %r{"application/x-www-form-urlencoded"})
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# put / 404
result = UserAgent.put(
@ -93,6 +109,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert_equal(String, result.body.class)
assert(result.body =~ /"delete"/)
assert(result.body =~ /"content_type_requested":null/)
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# delete / 404
result = UserAgent.delete(
@ -121,6 +140,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"get"/)
assert(result.body =~ /"123"/)
assert(result.body =~ /"content_type_requested":null/)
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# get / 401
result = UserAgent.get(
@ -154,6 +176,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"post"/)
assert(result.body =~ /"some value"/)
assert(result.body =~ %r{"application/x-www-form-urlencoded"})
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# post / 401
result = UserAgent.post(
@ -189,6 +214,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"put"/)
assert(result.body =~ /"some value"/)
assert(result.body =~ %r{"application/x-www-form-urlencoded"})
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# put / 401
result = UserAgent.put(
@ -220,6 +248,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert_equal(String, result.body.class)
assert(result.body =~ /"delete"/)
assert(result.body =~ /"content_type_requested":null/)
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# delete / 401
result = UserAgent.delete(
@ -249,6 +280,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"get"/)
assert(result.body =~ /"abc"/)
assert(result.body =~ /"content_type_requested":null/)
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# get / 301
result = UserAgent.request(
@ -265,6 +299,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"get"/)
assert(result.body =~ /"abc"/)
assert(result.body =~ /"content_type_requested":null/)
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# get / 401
result = UserAgent.request(
@ -294,6 +331,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"get"/)
assert(result.body =~ /"123"/)
assert(result.body =~ /"content_type_requested":null/)
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# ftp / 200
result = UserAgent.request(
@ -434,6 +474,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"content_type_requested"/)
assert(result.body =~ %r{"application/json"})
assert_equal('some value ', result.data['submitted']['key'])
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
# get / 401
result = UserAgent.get(
@ -468,6 +511,9 @@ class UserAgentTest < ActiveSupport::TestCase
assert(result.body =~ /"content_type_requested"/)
assert(result.body =~ %r{"application/json"})
assert_equal('some value ', result.data['submitted']['key'])
if ENV['ZAMMAD_PROXY_TEST'] == 'true' && ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']
assert(result.body =~ /"remote_ip":"#{ENV['ZAMMAD_PROXY_REMOTE_IP_CHECK']}"/)
end
end
end