proxes 0.9.13 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ditty/components/proxes.rb +61 -16
- data/lib/proxes/controllers/permissions.rb +1 -6
- data/lib/proxes/controllers/search.rb +12 -10
- data/lib/proxes/controllers/status.rb +23 -86
- data/lib/proxes/controllers/status_checks.rb +18 -0
- data/lib/proxes/forwarder.rb +44 -20
- data/lib/proxes/middleware/error_handling.rb +5 -3
- data/lib/proxes/middleware/security.rb +4 -3
- data/lib/proxes/models/permission.rb +47 -3
- data/lib/proxes/models/status_check.rb +76 -0
- data/lib/proxes/models/status_checks/cluster_health_status_check.rb +19 -0
- data/lib/proxes/models/status_checks/cpu_status_check.rb +29 -0
- data/lib/proxes/models/status_checks/file_system_status_check.rb +32 -0
- data/lib/proxes/models/status_checks/jvm_heap_status_check.rb +28 -0
- data/lib/proxes/models/status_checks/memory_status_check.rb +29 -0
- data/lib/proxes/models/status_checks/nodes_status_check.rb +53 -0
- data/lib/proxes/policies/permission_policy.rb +3 -3
- data/lib/proxes/policies/request/bulk_policy.rb +0 -12
- data/lib/proxes/policies/request/create_policy.rb +0 -3
- data/lib/proxes/policies/request/index_policy.rb +0 -5
- data/lib/proxes/policies/request/mget_policy.rb +12 -0
- data/lib/proxes/policies/request/msearch_policy.rb +12 -0
- data/lib/proxes/policies/request/root_policy.rb +0 -3
- data/lib/proxes/policies/request/snapshot_policy.rb +0 -3
- data/lib/proxes/policies/request_policy.rb +24 -25
- data/lib/proxes/policies/search_policy.rb +6 -2
- data/lib/proxes/policies/status_check_policy.rb +37 -0
- data/lib/proxes/request.rb +19 -5
- data/lib/proxes/request/bulk.rb +8 -24
- data/lib/proxes/request/cat.rb +6 -0
- data/lib/proxes/request/create.rb +4 -0
- data/lib/proxes/request/index.rb +4 -0
- data/lib/proxes/request/mget.rb +24 -0
- data/lib/proxes/request/msearch.rb +24 -0
- data/lib/proxes/request/multi.rb +40 -0
- data/lib/proxes/request/search.rb +4 -0
- data/lib/proxes/request/stats.rb +4 -0
- data/lib/proxes/services/es.rb +5 -1
- data/lib/proxes/services/listener.rb +29 -6
- data/lib/proxes/services/search.rb +4 -1
- data/lib/proxes/version.rb +1 -1
- data/migrate/20180908_index_specific_permissions.rb +9 -0
- data/migrate/20190109_add_status_checks_table.rb +17 -0
- data/views/layout.haml +17 -6
- metadata +81 -25
- data/lib/proxes/helpers/indices.rb +0 -35
@@ -8,11 +8,6 @@ module ProxES
|
|
8
8
|
class Request
|
9
9
|
class IndexPolicy < RequestPolicy
|
10
10
|
class Scope < RequestPolicy::Scope
|
11
|
-
def resolve
|
12
|
-
result = super
|
13
|
-
return [] unless result.count > 0
|
14
|
-
%w[POST PUT].include?(request.request_method) ? request.index : result
|
15
|
-
end
|
16
11
|
end
|
17
12
|
end
|
18
13
|
end
|
@@ -4,60 +4,59 @@ require 'active_support'
|
|
4
4
|
require 'active_support/core_ext/object/blank'
|
5
5
|
require 'ditty/services/logger'
|
6
6
|
require 'proxes/models/permission'
|
7
|
-
require 'proxes/helpers/indices'
|
8
7
|
|
9
8
|
module ProxES
|
10
9
|
class RequestPolicy
|
11
|
-
include Helpers::Indices
|
12
|
-
|
13
10
|
attr_reader :user, :record
|
14
11
|
alias request record
|
15
12
|
|
16
13
|
def initialize(user, record)
|
17
|
-
@user = user
|
14
|
+
@user = user || Ditty::User.anonymous_user
|
18
15
|
@record = record
|
19
16
|
end
|
20
17
|
|
21
18
|
def method_missing(method_sym, *arguments, &block)
|
22
|
-
return super
|
19
|
+
return super unless respond_to_missing? method_sym
|
20
|
+
|
21
|
+
return false if permissions.empty?
|
22
|
+
|
23
|
+
return permissions.count.positive? unless request.indices?
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
# Only allow if all the indices match the given permissions
|
26
|
+
request.indices.find do |idx|
|
27
|
+
idx = idx[1..-1] if idx[0] == '-'
|
28
|
+
permissions.find { |perm| perm.index_regex.match idx }.nil?
|
29
|
+
end.nil?
|
27
30
|
end
|
28
31
|
|
29
32
|
def respond_to_missing?(name, _include_private = false)
|
30
33
|
name[-1] == '?'
|
31
34
|
end
|
32
35
|
|
33
|
-
def
|
34
|
-
|
35
|
-
return nil if permission.pattern.blank?
|
36
|
-
permission.pattern.gsub(/\{user.(.*)\}/) { |_match| user.send(Regexp.last_match[1].to_sym) }
|
37
|
-
end.compact
|
38
|
-
filter(request.index, patterns).count > 0
|
39
|
-
end
|
40
|
-
|
41
|
-
def action_allowed?(action)
|
42
|
-
# Give me all the user's permissions that match the verb
|
43
|
-
!!patterns_for(action).find { |permission| (request.path =~ /#{permission.pattern}/) }
|
36
|
+
def permissions
|
37
|
+
@permissions ||= Permission.for_user(user).for_request(request)
|
44
38
|
end
|
45
39
|
|
46
40
|
class Scope
|
47
|
-
include Helpers::Indices
|
48
|
-
|
49
41
|
attr_reader :user, :scope
|
50
42
|
alias request scope
|
51
43
|
|
52
44
|
def initialize(user, scope)
|
53
|
-
@user = user
|
45
|
+
@user = user || Ditty::User.anonymous_user
|
54
46
|
@scope = scope
|
55
47
|
end
|
56
48
|
|
57
49
|
def resolve
|
58
|
-
|
59
|
-
|
60
|
-
|
50
|
+
return permissions.map(&:index) if request.indices == ['*'] || request.indices == ['_all'] || request.indices.blank?
|
51
|
+
|
52
|
+
request.indices.select do |idx|
|
53
|
+
idx = idx[1..-1] if idx[0] == '-'
|
54
|
+
permissions.find { |perm| perm.index_regex.match idx }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def permissions
|
59
|
+
@permissions ||= Permission.for_user(user).for_request(request)
|
61
60
|
end
|
62
61
|
end
|
63
62
|
end
|
@@ -4,8 +4,12 @@ require 'ditty/policies/application_policy'
|
|
4
4
|
|
5
5
|
module ProxES
|
6
6
|
class SearchPolicy < Ditty::ApplicationPolicy
|
7
|
+
def list?
|
8
|
+
search?
|
9
|
+
end
|
10
|
+
|
7
11
|
def search?
|
8
|
-
user
|
12
|
+
user
|
9
13
|
end
|
10
14
|
|
11
15
|
def fields?
|
@@ -22,7 +26,7 @@ module ProxES
|
|
22
26
|
|
23
27
|
class Scope < Ditty::ApplicationPolicy::Scope
|
24
28
|
def resolve
|
25
|
-
user
|
29
|
+
user&.super_admin? ? scope : scope.where(id: -1)
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ditty/policies/application_policy'
|
4
|
+
|
5
|
+
module ProxES
|
6
|
+
class StatusCheckPolicy < Ditty::ApplicationPolicy
|
7
|
+
def create?
|
8
|
+
user && (user.super_admin? || user.admin?)
|
9
|
+
end
|
10
|
+
|
11
|
+
def list?
|
12
|
+
user && (user.super_admin? || user.admin?)
|
13
|
+
end
|
14
|
+
|
15
|
+
def read?
|
16
|
+
create?
|
17
|
+
end
|
18
|
+
|
19
|
+
def update?
|
20
|
+
read?
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete?
|
24
|
+
create?
|
25
|
+
end
|
26
|
+
|
27
|
+
def permitted_attributes
|
28
|
+
%i[type name source required_value order]
|
29
|
+
end
|
30
|
+
|
31
|
+
class Scope < Ditty::ApplicationPolicy::Scope
|
32
|
+
def resolve
|
33
|
+
user&.super_admin? ? scope : scope.where(id: -1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/proxes/request.rb
CHANGED
@@ -21,12 +21,18 @@ module ProxES
|
|
21
21
|
path_parts
|
22
22
|
end
|
23
23
|
|
24
|
+
# Indicate whether or not the request is index specific
|
24
25
|
def indices?
|
25
26
|
false
|
26
27
|
end
|
27
28
|
|
29
|
+
# Return the indices associated with the request as an array. [] if `#indices?` is false
|
30
|
+
def indices
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
|
28
34
|
def html?
|
29
|
-
get_header('HTTP_ACCEPT')
|
35
|
+
get_header('HTTP_ACCEPT')&.include?('text/html')
|
30
36
|
end
|
31
37
|
|
32
38
|
def duration
|
@@ -34,17 +40,22 @@ module ProxES
|
|
34
40
|
end
|
35
41
|
|
36
42
|
def user_id
|
37
|
-
return
|
38
|
-
|
43
|
+
return session['user_id'] if session['user_id']
|
44
|
+
|
45
|
+
env['omniauth.auth']&.uid
|
39
46
|
end
|
40
47
|
|
41
48
|
def user
|
42
49
|
return nil if user_id.nil?
|
50
|
+
|
43
51
|
@user ||= Ditty::User[user_id]
|
44
52
|
end
|
45
53
|
|
46
54
|
def detail
|
47
|
-
"#{request_method.upcase} #{fullpath} (#{self.class.name})"
|
55
|
+
detail = "#{request_method.upcase} #{fullpath} (#{self.class.name})"
|
56
|
+
return detail unless indices?
|
57
|
+
|
58
|
+
"#{detail} #{indices.join(',')}"
|
48
59
|
end
|
49
60
|
|
50
61
|
private
|
@@ -56,6 +67,7 @@ module ProxES
|
|
56
67
|
def check_part(val)
|
57
68
|
return val if val.nil?
|
58
69
|
return [] if [endpoint, '_all'].include?(val) && !WRITE_METHODS.include?(request_method)
|
70
|
+
|
59
71
|
val.split(',')
|
60
72
|
end
|
61
73
|
|
@@ -73,11 +85,13 @@ module ProxES
|
|
73
85
|
|
74
86
|
def path_endpoint(path)
|
75
87
|
return '_root' if ['', nil, '/'].include? path
|
88
|
+
|
76
89
|
path_parts = path[1..-1].split('/')
|
77
90
|
return path_parts[-1] if ID_ENDPOINTS.include? path_parts[-1]
|
78
91
|
return path_parts[-2] if path_parts[-1] == 'count' && path_parts[-2] == '_percolate'
|
79
92
|
return path_parts[-2] if path_parts[-1] == 'scroll' && path_parts[-2] == '_search'
|
80
|
-
|
93
|
+
|
94
|
+
path_parts.find { |part| part[0] == '_' && part != '_all' }
|
81
95
|
end
|
82
96
|
end
|
83
97
|
end
|
data/lib/proxes/request/bulk.rb
CHANGED
@@ -1,39 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'proxes/request'
|
3
|
+
require 'proxes/request/multi'
|
4
4
|
require 'proxes/policies/request/bulk_policy'
|
5
5
|
|
6
6
|
module ProxES
|
7
7
|
class Request
|
8
|
-
class Bulk <
|
9
|
-
|
10
|
-
|
11
|
-
REGEX = /"(index|delete|create|update)".*"_index"\s*:\s*"(.*?)"/
|
12
|
-
|
13
|
-
def bulk_indices
|
14
|
-
@bulk_indices ||= begin
|
15
|
-
body.read.scan(REGEX).tap { |_r| body.rewind }
|
16
|
-
end.map { |e| e[1] }.uniq
|
17
|
-
end
|
8
|
+
class Bulk < Multi
|
9
|
+
INDICES_REGEX = /"(index|delete|create|update)".*"_index"\s*:\s*"(.*?)"/
|
18
10
|
|
19
|
-
|
20
|
-
@index = idx
|
21
|
-
self.path_info = '/' + [index, type, endpoint].compact
|
22
|
-
.map { |v| v.is_a?(Array) ? v.join(',') : v }
|
23
|
-
.select { |v| !v.nil? && v != '' }.join('/')
|
24
|
-
end
|
11
|
+
attr_reader :index, :type
|
25
12
|
|
26
13
|
def endpoint
|
27
14
|
'_bulk'
|
28
15
|
end
|
29
16
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
def indices?
|
36
|
-
!@index.nil?
|
17
|
+
class << self
|
18
|
+
def indices_regex
|
19
|
+
INDICES_REGEX
|
20
|
+
end
|
37
21
|
end
|
38
22
|
end
|
39
23
|
end
|
data/lib/proxes/request/cat.rb
CHANGED
data/lib/proxes/request/index.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'proxes/request/multi'
|
4
|
+
require 'proxes/policies/request/mget_policy'
|
5
|
+
|
6
|
+
module ProxES
|
7
|
+
class Request
|
8
|
+
class Mget < Multi
|
9
|
+
INDICES_REGEX = /"(_index)"\s*:\s*"(.*?)"/
|
10
|
+
|
11
|
+
attr_reader :index, :type
|
12
|
+
|
13
|
+
def endpoint
|
14
|
+
'_mget'
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def indices_regex
|
19
|
+
INDICES_REGEX
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'proxes/request/multi'
|
4
|
+
require 'proxes/policies/request/msearch_policy'
|
5
|
+
|
6
|
+
module ProxES
|
7
|
+
class Request
|
8
|
+
class Msearch < Multi
|
9
|
+
INDICES_REGEX = /"(index)"\s*:\s*"(.*?)"/
|
10
|
+
|
11
|
+
attr_reader :index, :type
|
12
|
+
|
13
|
+
def endpoint
|
14
|
+
'_msearch'
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def indices_regex
|
19
|
+
INDICES_REGEX
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'proxes/request'
|
4
|
+
|
5
|
+
module ProxES
|
6
|
+
class Request
|
7
|
+
class Multi < Request
|
8
|
+
# Read up on URL-based access control - https://www.elastic.co/guide/en/elasticsearch/reference/current/url-access-control.html
|
9
|
+
# Setting `rest.action.multi.allow_explicit_index` to false will not allow the user to send an index in the request body
|
10
|
+
# which negates this. Depending on your needs, you can enable / disable this
|
11
|
+
def body_indices
|
12
|
+
# TODO: Do / Don't do this depending on rest.action.multi.allow_explicit_index
|
13
|
+
@body_indices ||= begin
|
14
|
+
body.read.scan(self.class.indices_regex).tap { |_r| body.rewind }
|
15
|
+
end.map { |e| e[1] }.compact.uniq
|
16
|
+
end
|
17
|
+
|
18
|
+
def index=(idx)
|
19
|
+
@body_indices = []
|
20
|
+
@index = idx
|
21
|
+
self.path_info = '/' + [index, type, endpoint].compact
|
22
|
+
.map { |v| v.is_a?(Array) ? v.join(',') : v }
|
23
|
+
.select { |v| !v.nil? && v != '' }.join('/')
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse
|
27
|
+
@index ||= check_part(path_parts[0]) unless path_parts[0] == endpoint
|
28
|
+
@type ||= check_part(path_parts[1]) unless path_parts[1] == endpoint
|
29
|
+
end
|
30
|
+
|
31
|
+
def indices?
|
32
|
+
indices.blank? == false
|
33
|
+
end
|
34
|
+
|
35
|
+
def indices
|
36
|
+
body_indices + (@index || [])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|