proxes 0.9.2 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/Dockerfile +1 -2
- data/Gemfile.deploy.lock +2 -2
- data/Gemfile.dev +4 -4
- data/config.ru +8 -2
- data/config/logger.yml +2 -0
- data/docker-compose.yml +5 -5
- data/lib/proxes/controllers/permissions.rb +1 -1
- data/lib/proxes/controllers/status.rb +18 -9
- data/lib/proxes/forwarder.rb +0 -11
- data/lib/proxes/helpers/indices.rb +17 -1
- data/lib/proxes/middleware/error_handling.rb +74 -0
- data/lib/proxes/middleware/metrics.rb +25 -0
- data/lib/proxes/middleware/security.rb +60 -0
- data/lib/proxes/models/permission.rb +6 -0
- data/lib/proxes/policies/request/bulk_policy.rb +5 -16
- data/lib/proxes/policies/request/cat_policy.rb +0 -8
- data/lib/proxes/policies/request/create_policy.rb +1 -6
- data/lib/proxes/policies/request/index_policy.rb +1 -7
- data/lib/proxes/policies/request/search_policy.rb +2 -8
- data/lib/proxes/policies/request/stats_policy.rb +0 -8
- data/lib/proxes/policies/request_policy.rb +6 -15
- data/lib/proxes/request.rb +45 -20
- data/lib/proxes/services/es.rb +2 -2
- data/lib/proxes/version.rb +1 -1
- data/public/js/bundle.js +422 -216
- data/startup.sh +3 -2
- data/views/index.haml +1 -0
- data/views/layout.haml +60 -0
- data/views/partials/navbar.haml +25 -0
- metadata +9 -4
- data/lib/proxes/security.rb +0 -89
data/startup.sh
CHANGED
@@ -4,14 +4,15 @@ set -e
|
|
4
4
|
echo "DATABASE_URL: $DATABASE_URL"
|
5
5
|
echo "ELASTICSEARCH_URL: $ELASTICSEARCH_URL"
|
6
6
|
echo "APP_ROOT: $APP_ROOT"
|
7
|
+
bundle show ditty
|
8
|
+
bundle show proxes
|
7
9
|
|
8
10
|
if [ "$1" = 'web-proxes' ]
|
9
11
|
then
|
10
|
-
cd
|
12
|
+
cd $APP_ROOT
|
11
13
|
bundle exec rake ditty:generate_tokens
|
12
14
|
bundle exec rake ditty:migrate
|
13
15
|
bundle exec rake ditty:seed
|
14
|
-
crond
|
15
16
|
exec bundle exec pumactl start "$@"
|
16
17
|
fi
|
17
18
|
|
data/views/index.haml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
#react-dashboard{ 'data-elasticsearch-url' => '..'}
|
data/views/layout.haml
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
!!! 5
|
2
|
+
%html{ lang: 'en' }
|
3
|
+
%head
|
4
|
+
%meta{ charset: 'utf-8' }
|
5
|
+
%meta{ 'http-equiv' => 'X-UA-Compatible', 'content' => 'IE=edge,chrome=1' }
|
6
|
+
%meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
7
|
+
%meta{ name: 'theme-color', content: '#ffffff' }
|
8
|
+
%link{ rel: 'manifest', href: '/_proxes/manifest.json' }
|
9
|
+
%link{ rel: 'icon', type: 'image/png', sizes: '32x32', href: '/_proxes/images/favicon-32x32.png' }
|
10
|
+
%link{ rel: 'icon', type: 'image/png', sizes: '16x16', href: '/_proxes/images/favicon-16x16.png' }
|
11
|
+
%link{ rel: 'apple-touch-icon', sizes: '76x76', href: '/_proxes/images/apple-icon.png' }
|
12
|
+
%link{ rel: 'mask-icon', href: '/_proxes/images/safari-pinned-tab.svg', color: '#5bbad5' }
|
13
|
+
|
14
|
+
%title
|
15
|
+
ProxES
|
16
|
+
- if defined? title
|
17
|
+
= "- #{title}"
|
18
|
+
|
19
|
+
%meta{ name: 'description', content: '' }
|
20
|
+
%meta{ name: 'author', content: '' }
|
21
|
+
|
22
|
+
/ Le styles
|
23
|
+
%link{ rel: 'stylesheet', href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', media: 'screen' }
|
24
|
+
%link{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/startbootstrap-sb-admin-2/3.3.7+1/css/sb-admin-2.min.css', media: 'screen' }
|
25
|
+
%link{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/metisMenu/2.5.2/metisMenu.min.css', media: 'screen' }
|
26
|
+
%link{ rel: 'stylesheet', href: 'https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css', media: 'screen' }
|
27
|
+
/[if lt IE 9] <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
|
28
|
+
/[if lt IE 9] <script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
|
29
|
+
|
30
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js' }
|
31
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/startbootstrap-sb-admin-2/3.3.7+1/js/sb-admin-2.min.js' }
|
32
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/metisMenu/2.5.2/metisMenu.min.js' }
|
33
|
+
%body
|
34
|
+
#wrapper
|
35
|
+
= haml :'partials/navbar', locals: { title: (defined?(title) ? title : 'ProxES') }
|
36
|
+
#page-wrapper{ style: 'opacity: 0.8' }
|
37
|
+
.row
|
38
|
+
.col-md-12
|
39
|
+
-if defined? title
|
40
|
+
%h1.page-header= title
|
41
|
+
= haml :'partials/notifications'
|
42
|
+
|
43
|
+
= yield
|
44
|
+
%footer.footer.text-muted.text-center
|
45
|
+
%hr
|
46
|
+
.copyright
|
47
|
+
:plain
|
48
|
+
© <script>document.write(new Date().getFullYear())</script>, DataTools.io
|
49
|
+
|
50
|
+
|
51
|
+
/ Placed at the end of the document so the pages load faster
|
52
|
+
%script{ type: 'text/javascript', src: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js' }
|
53
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.min.js' }
|
54
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.min.js' }
|
55
|
+
%script{ type: 'text/javascript', src: '/_proxes/js/bundle.js' }
|
56
|
+
:javascript
|
57
|
+
$(function() {
|
58
|
+
$('.sidebar-nav').metisMenu();
|
59
|
+
});
|
60
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
.navbar.navbar-default.navbar-static-top{ role: 'navigation', style: 'margin-bottom: 0' }
|
2
|
+
.navbar-header
|
3
|
+
%button.navbar-toggle.collapsed{ 'type' => 'button', 'data-toggle' => 'collapse', 'data-target' => '.navbar-collapse' }
|
4
|
+
%span.sr-only Toggle navigation
|
5
|
+
%span.icon-bar
|
6
|
+
%span.icon-bar
|
7
|
+
%span.icon-bar
|
8
|
+
%span.navbar-brand
|
9
|
+
%a{ href: "#{settings.map_path}" }
|
10
|
+
ProxES
|
11
|
+
|
12
|
+
-if authenticated?
|
13
|
+
%form.nav.navbar-top-links.navbar-form.navbar-right{ action: "#{settings.map_path}/auth/identity", method: 'post' }
|
14
|
+
%a.btn.btn-default{ href: "#{settings.map_path}/users/profile" } My Account
|
15
|
+
%input{ name: '_method', value: 'DELETE', type: 'hidden' }
|
16
|
+
%button.btn.btn-default{ type: 'submit' }
|
17
|
+
/ %i.ti-panel
|
18
|
+
Logout
|
19
|
+
- else
|
20
|
+
%ul.nav.navbar-top-links.navbar-right
|
21
|
+
%li
|
22
|
+
%a.btn.btn-link{ href: "#{settings.map_path}/auth/identity" }
|
23
|
+
Log In
|
24
|
+
.navbar-default.sidebar{ role: 'navigation' }
|
25
|
+
= haml :'partials/sidebar'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: proxes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jurgens du Toit
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -457,6 +457,9 @@ files:
|
|
457
457
|
- lib/proxes/forwarder.rb
|
458
458
|
- lib/proxes/helpers/indices.rb
|
459
459
|
- lib/proxes/loggers/elasticsearch.rb
|
460
|
+
- lib/proxes/middleware/error_handling.rb
|
461
|
+
- lib/proxes/middleware/metrics.rb
|
462
|
+
- lib/proxes/middleware/security.rb
|
460
463
|
- lib/proxes/models/permission.rb
|
461
464
|
- lib/proxes/policies/permission_policy.rb
|
462
465
|
- lib/proxes/policies/request/bulk_policy.rb
|
@@ -478,7 +481,6 @@ files:
|
|
478
481
|
- lib/proxes/request/search.rb
|
479
482
|
- lib/proxes/request/snapshot.rb
|
480
483
|
- lib/proxes/request/stats.rb
|
481
|
-
- lib/proxes/security.rb
|
482
484
|
- lib/proxes/services/es.rb
|
483
485
|
- lib/proxes/version.rb
|
484
486
|
- migrate/20170209_permissions.rb
|
@@ -499,6 +501,9 @@ files:
|
|
499
501
|
- public/manifest.json
|
500
502
|
- src/scripts/app.js
|
501
503
|
- startup.sh
|
504
|
+
- views/index.haml
|
505
|
+
- views/layout.haml
|
506
|
+
- views/partials/navbar.haml
|
502
507
|
- views/permissions/display.haml
|
503
508
|
- views/permissions/edit.haml
|
504
509
|
- views/permissions/form.haml
|
@@ -525,7 +530,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
525
530
|
version: '0'
|
526
531
|
requirements: []
|
527
532
|
rubyforge_project:
|
528
|
-
rubygems_version: 2.7.
|
533
|
+
rubygems_version: 2.7.6
|
529
534
|
signing_key:
|
530
535
|
specification_version: 4
|
531
536
|
summary: Rack wrapper around Elasticsearch to provide security and management features
|
data/lib/proxes/security.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'proxes/request'
|
4
|
-
require 'proxes/policies/request_policy'
|
5
|
-
require 'ditty/services/logger'
|
6
|
-
require 'ditty/helpers/pundit'
|
7
|
-
require 'ditty/helpers/authentication'
|
8
|
-
require 'ditty/helpers/wisper'
|
9
|
-
|
10
|
-
module ProxES
|
11
|
-
class Security
|
12
|
-
attr_reader :env, :logger
|
13
|
-
|
14
|
-
include Ditty::Helpers::Authentication
|
15
|
-
include Ditty::Helpers::Pundit
|
16
|
-
include Ditty::Helpers::Wisper
|
17
|
-
include Wisper::Publisher
|
18
|
-
|
19
|
-
def initialize(app, logger = nil)
|
20
|
-
@app = app
|
21
|
-
@logger = logger || ::Ditty::Services::Logger.instance
|
22
|
-
end
|
23
|
-
|
24
|
-
def error(message, code = 500)
|
25
|
-
headers = { 'Content-Type' => 'application/json' }
|
26
|
-
headers['WWW-Authenticate'] = 'Basic realm="security"' if code == 401
|
27
|
-
[code, headers, ['{"error":"' + message + '"}']]
|
28
|
-
end
|
29
|
-
|
30
|
-
def redirect(destination, code = 302)
|
31
|
-
[code, { 'Location' => destination}, []]
|
32
|
-
end
|
33
|
-
|
34
|
-
def check(request)
|
35
|
-
check_basic request
|
36
|
-
authorize request, request.request_method.downcase
|
37
|
-
rescue Pundit::NotAuthorizedError
|
38
|
-
return redirect '/_proxes/' if request.get_header('HTTP_ACCEPT') && request.get_header('HTTP_ACCEPT').include?('text/html')
|
39
|
-
|
40
|
-
log_action(:es_request_denied, details: "#{request.request_method.upcase} #{request.fullpath} (#{request.class.name})")
|
41
|
-
logger.debug "Access denied for #{current_user ? current_user.email : 'Anonymous User'} by security layer: #{request.request_method.upcase} #{request.fullpath} (#{request.class.name})"
|
42
|
-
error 'Not Authorized', 401
|
43
|
-
rescue ::Ditty::Helpers::NotAuthenticated
|
44
|
-
logger.warn "Access denied for unauthenticated request by security layer: #{request.request_method.upcase} #{request.fullpath} (#{request.class.name})"
|
45
|
-
error 'Not Authenticated', 401
|
46
|
-
rescue StandardError => e
|
47
|
-
raise e if env['RACK_ENV'] != 'production'
|
48
|
-
logger.error "Access denied for #{current_user ? current_user.email : 'Anonymous User'} by security exception: #{request.request_method.upcase} #{request.fullpath} (#{request.class.name})"
|
49
|
-
logger.error e
|
50
|
-
error 'Forbidden', 403
|
51
|
-
end
|
52
|
-
|
53
|
-
def forward(request)
|
54
|
-
start = Time.now.to_f
|
55
|
-
result = @app.call request.env
|
56
|
-
broadcast(:call_completed, request, Time.now.to_f - start) if result[0].to_i >= 200 && result[0].to_i < 300
|
57
|
-
result
|
58
|
-
rescue Errno::EHOSTUNREACH
|
59
|
-
error 'Could not reach Elasticsearch at ' + ENV['ELASTICSEARCH_URL']
|
60
|
-
rescue Errno::ECONNREFUSED
|
61
|
-
error 'Elasticsearch not listening at ' + ENV['ELASTICSEARCH_URL']
|
62
|
-
end
|
63
|
-
|
64
|
-
def log(request, stage)
|
65
|
-
logger.debug '============' + stage.ljust(56) + '============'
|
66
|
-
logger.debug '= ' + "Request: #{request.request_method} #{request.fullpath} (#{request.class.name})".ljust(76) + ' ='
|
67
|
-
logger.debug '= ' + "Endpoint: #{request.endpoint}".ljust(76) + ' ='
|
68
|
-
logger.debug '================================================================================'
|
69
|
-
end
|
70
|
-
|
71
|
-
def call(env)
|
72
|
-
@env = env
|
73
|
-
|
74
|
-
request = Request.from_env(env)
|
75
|
-
broadcast(:call_started, request)
|
76
|
-
|
77
|
-
log(request, 'BEFORE')
|
78
|
-
unless env['PROXES_PASSTHROUGH']
|
79
|
-
result = check(request)
|
80
|
-
return result if result.is_a?(Array) # Rack Response
|
81
|
-
|
82
|
-
request.index = policy_scope(request) if request.indices?
|
83
|
-
log(request, 'AFTER')
|
84
|
-
end
|
85
|
-
|
86
|
-
forward request
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|