tcell_agent 2.1.1 → 2.4.0
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/LICENSE +2 -2
- data/bin/tcell_agent +41 -150
- data/lib/tcell_agent.rb +8 -16
- data/lib/tcell_agent/agent.rb +87 -52
- data/lib/tcell_agent/config_initializer.rb +62 -0
- data/lib/tcell_agent/configuration.rb +72 -267
- data/lib/tcell_agent/hooks/login_fraud.rb +1 -1
- data/lib/tcell_agent/instrument_servers.rb +14 -18
- data/lib/tcell_agent/instrumentation.rb +14 -6
- data/lib/tcell_agent/instrumentation/cmdi.rb +47 -15
- data/lib/tcell_agent/instrumentation/lfi.rb +68 -11
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/file.rb +21 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/io.rb +75 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/kernel.rb +80 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/file.rb +21 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/io.rb +75 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/kernel.rb +80 -0
- data/lib/tcell_agent/logger.rb +3 -4
- data/lib/tcell_agent/policies/dataloss_policy.rb +15 -8
- data/lib/tcell_agent/policies/headers_policy.rb +2 -2
- data/lib/tcell_agent/policies/patches_policy.rb +8 -4
- data/lib/tcell_agent/policies/policies_manager.rb +1 -0
- data/lib/tcell_agent/policies/policy_polling.rb +4 -3
- data/lib/tcell_agent/rails/auth/authlogic.rb +49 -44
- data/lib/tcell_agent/rails/auth/authlogic_helper.rb +20 -0
- data/lib/tcell_agent/rails/auth/devise.rb +103 -102
- data/lib/tcell_agent/rails/auth/devise_helper.rb +29 -0
- data/lib/tcell_agent/rails/auth/doorkeeper.rb +54 -57
- data/lib/tcell_agent/{userinfo.rb → rails/auth/userinfo.rb} +0 -0
- data/lib/tcell_agent/rails/better_ip.rb +7 -19
- data/lib/tcell_agent/rails/csrf_exception.rb +0 -8
- data/lib/tcell_agent/rails/dlp.rb +48 -52
- data/lib/tcell_agent/rails/dlp/process_request.rb +5 -0
- data/lib/tcell_agent/rails/dlp_handler.rb +9 -10
- data/lib/tcell_agent/rails/js_agent_insert.rb +2 -3
- data/lib/tcell_agent/rails/middleware/context_middleware.rb +2 -1
- data/lib/tcell_agent/rails/middleware/global_middleware.rb +3 -4
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +1 -0
- data/lib/tcell_agent/rails/{on_start.rb → railties/tcell_agent_railties.rb} +9 -16
- data/lib/tcell_agent/rails/railties/tcell_agent_unicorn_railties.rb +8 -0
- data/lib/tcell_agent/rails/routes.rb +3 -6
- data/lib/tcell_agent/rails/routes/grape.rb +5 -12
- data/lib/tcell_agent/rails/settings_reporter.rb +0 -8
- data/lib/tcell_agent/rails/tcell_body_proxy.rb +4 -7
- data/lib/tcell_agent/routes/table.rb +3 -0
- data/lib/tcell_agent/rust/agent_config.rb +52 -32
- data/lib/tcell_agent/rust/{libtcellagent-4.18.0.so → libtcellagent-alpine.so} +0 -0
- data/lib/tcell_agent/rust/libtcellagent-x64.dll +0 -0
- data/lib/tcell_agent/rust/{libtcellagent-4.18.0.dylib → libtcellagent.dylib} +0 -0
- data/lib/tcell_agent/rust/{libtcellagent-alpine-4.18.0.so → libtcellagent.so} +0 -0
- data/lib/tcell_agent/rust/models.rb +9 -0
- data/lib/tcell_agent/rust/native_agent.rb +58 -50
- data/lib/tcell_agent/rust/native_library.rb +8 -10
- data/lib/tcell_agent/sensor_events/server_agent.rb +3 -100
- data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +1 -0
- data/lib/tcell_agent/servers/puma.rb +30 -13
- data/lib/tcell_agent/servers/rack_puma_handler.rb +33 -0
- data/lib/tcell_agent/servers/rails_server.rb +4 -4
- data/lib/tcell_agent/servers/unicorn.rb +1 -1
- data/lib/tcell_agent/servers/webrick.rb +12 -3
- data/lib/tcell_agent/settings_reporter.rb +0 -93
- data/lib/tcell_agent/sinatra.rb +1 -0
- data/lib/tcell_agent/tcell_context.rb +16 -7
- data/lib/tcell_agent/utils/headers.rb +0 -1
- data/lib/tcell_agent/utils/strings.rb +2 -2
- data/lib/tcell_agent/version.rb +1 -1
- data/spec/cruby_spec_helper.rb +26 -0
- data/spec/lib/tcell_agent/configuration_spec.rb +62 -212
- data/spec/lib/tcell_agent/instrument_servers_spec.rb +95 -0
- data/spec/lib/tcell_agent/instrumentation/cmdi/io_cmdi_spec.rb +2 -2
- data/spec/lib/tcell_agent/instrumentation/cmdi_spec.rb +46 -4
- data/spec/lib/tcell_agent/instrumentation/lfi/file_lfi_spec.rb +211 -272
- data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +207 -223
- data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +89 -70
- data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +120 -2
- data/spec/lib/tcell_agent/patches_spec.rb +2 -1
- data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +1 -2
- data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +5 -6
- data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +21 -2
- data/spec/lib/tcell_agent/policies/policies_manager_spec.rb +1 -1
- data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +14 -8
- data/spec/lib/tcell_agent/rails/better_ip_spec.rb +9 -11
- data/spec/lib/tcell_agent/rails/csrf_exception_spec.rb +6 -6
- data/spec/lib/tcell_agent/rails/dlp_spec.rb +1 -0
- data/spec/lib/tcell_agent/rails/js_agent_insert_spec.rb +10 -2
- data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +2 -1
- data/spec/lib/tcell_agent/rails/routes/route_id_spec.rb +4 -4
- data/spec/lib/tcell_agent/rust/agent_config_spec.rb +27 -0
- data/spec/lib/tcell_agent/settings_reporter_spec.rb +2 -89
- data/spec/lib/tcell_agent/tcell_context_spec.rb +6 -5
- data/spec/spec_helper.rb +9 -1
- data/spec/support/builders.rb +8 -7
- data/spec/support/server_mocks/passenger_mock.rb +7 -0
- data/spec/support/server_mocks/puma_mock.rb +21 -0
- data/spec/support/server_mocks/rails_mock.rb +7 -0
- data/spec/support/server_mocks/thin_mock.rb +7 -0
- data/spec/support/server_mocks/unicorn_mock.rb +11 -0
- data/spec/support/shared_spec.rb +29 -0
- data/tcell_agent.gemspec +14 -14
- metadata +44 -27
- data/Rakefile +0 -18
- data/lib/tcell_agent/authlogic.rb +0 -23
- data/lib/tcell_agent/config/unknown_options.rb +0 -119
- data/lib/tcell_agent/devise.rb +0 -33
- data/lib/tcell_agent/instrumentation/monkey_patches/file.rb +0 -25
- data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +0 -131
- data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +0 -163
- data/lib/tcell_agent/rails/start_agent_after_initializers.rb +0 -12
- data/lib/tcell_agent/rust/tcellagent-4.18.0.dll +0 -0
- data/spec/lib/tcell_agent/config/unknown_options_spec.rb +0 -195
|
@@ -1,38 +1,55 @@
|
|
|
1
1
|
if defined?(Puma.cli_config)
|
|
2
2
|
if Puma.cli_config.options[:preload_app]
|
|
3
|
-
if Puma.cli_config.options[:workers] == 0
|
|
3
|
+
if Puma.cli_config.options[:workers] == 0
|
|
4
4
|
# Puma is running in single mode, so run both the initial instrumentation and
|
|
5
5
|
# start the agent
|
|
6
6
|
Puma::Runner.class_eval do
|
|
7
|
-
alias_method :
|
|
7
|
+
alias_method :tcell_original_start_server, :start_server
|
|
8
8
|
def start_server
|
|
9
|
-
TCellAgent.thread_agent.start('Puma
|
|
9
|
+
TCellAgent.thread_agent.start('Puma')
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
tcell_original_start_server
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
else
|
|
16
16
|
Puma::Server.class_eval do
|
|
17
|
-
alias_method :
|
|
18
|
-
def run(background = true)
|
|
19
|
-
TCellAgent.thread_agent.start('Puma Cluster Mode (Worker)')
|
|
17
|
+
alias_method :tcell_original_run, :run
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
if defined?(Gem::Version) &&
|
|
20
|
+
defined?(Puma::Const::PUMA_VERSION) &&
|
|
21
|
+
(Gem::Version.new(Puma::Const::PUMA_VERSION) < Gem::Version.new('5.1.0'))
|
|
22
|
+
def run(background = true)
|
|
23
|
+
TCellAgent.thread_agent.start('Puma')
|
|
24
|
+
original_run(background, options)
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
def run(background = true, thread_name: 'server')
|
|
28
|
+
TCellAgent.thread_agent.start('Puma')
|
|
29
|
+
original_run(background, :thread_name => thread_name)
|
|
30
|
+
end
|
|
22
31
|
end
|
|
23
32
|
end
|
|
24
33
|
end
|
|
25
|
-
|
|
26
34
|
else
|
|
27
35
|
# this ensures instrumentation runs for preload_app = false.
|
|
28
36
|
# Instrumentation will run for each worker but there's
|
|
29
37
|
# nothing we can do about that (Unicorn's preload_app behaves the same way)
|
|
30
38
|
Puma::Server.class_eval do
|
|
31
|
-
alias_method :
|
|
32
|
-
def run(background = true)
|
|
33
|
-
TCellAgent.thread_agent.start('Puma Cluster Mode (Worker)')
|
|
39
|
+
alias_method :tcell_original_run, :run
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
if defined?(Gem::Version) &&
|
|
42
|
+
defined?(Puma::Const::PUMA_VERSION) &&
|
|
43
|
+
(Gem::Version.new(Puma::Const::PUMA_VERSION) < Gem::Version.new('5.1.0'))
|
|
44
|
+
def run(background = true)
|
|
45
|
+
TCellAgent.thread_agent.start('Puma')
|
|
46
|
+
tcell_original_run(background)
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
def run(background = true, thread_name: 'server')
|
|
50
|
+
TCellAgent.thread_agent.start('Puma')
|
|
51
|
+
original_run(background, :thread_name => thread_name)
|
|
52
|
+
end
|
|
36
53
|
end
|
|
37
54
|
end
|
|
38
55
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Rack::Handler::Puma.class_eval do
|
|
4
|
+
class << self
|
|
5
|
+
alias_method :tcell_original_config, :config
|
|
6
|
+
def config(app, options = {})
|
|
7
|
+
conf = tcell_original_config(app, options)
|
|
8
|
+
|
|
9
|
+
if defined?(Puma::Server) && !Puma::Server.instance_methods.include?(:tcell_original_run)
|
|
10
|
+
Puma::Server.class_eval do
|
|
11
|
+
alias_method :tcell_original_run, :run
|
|
12
|
+
|
|
13
|
+
if defined?(Gem::Version) &&
|
|
14
|
+
defined?(Puma::Const::PUMA_VERSION) &&
|
|
15
|
+
(Gem::Version.new(Puma::Const::PUMA_VERSION) >= Gem::Version.new('5.1.0'))
|
|
16
|
+
def run(background = true, thread_name: 'server')
|
|
17
|
+
TCellAgent.thread_agent.start('Puma')
|
|
18
|
+
original_run(background, :thread_name => thread_name)
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
def run(background = true)
|
|
22
|
+
TCellAgent.thread_agent.start('Puma')
|
|
23
|
+
|
|
24
|
+
tcell_original_run(background)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
conf
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
Rails::Server.class_eval do
|
|
6
6
|
alias_method :tcell_build_app, :build_app
|
|
7
7
|
def build_app(app)
|
|
8
|
+
require('tcell_agent/servers/rack_puma_handler') if defined?(Rack::Handler::Puma)
|
|
8
9
|
require('tcell_agent/servers/unicorn') if defined?(Unicorn::HttpServer)
|
|
9
10
|
require('tcell_agent/servers/webrick') if defined?(Rack::Handler::WEBrick)
|
|
10
11
|
require('tcell_agent/servers/thin') if defined?(Thin::Server)
|
|
11
12
|
|
|
12
13
|
if defined?(Puma::Server)
|
|
13
14
|
Puma::Server.class_eval do
|
|
14
|
-
alias_method :
|
|
15
|
+
alias_method :tcell_original_run, :run
|
|
15
16
|
def run(background = true)
|
|
16
|
-
TCellAgent.thread_agent.start('Puma
|
|
17
|
-
|
|
18
|
-
original_run(background)
|
|
17
|
+
TCellAgent.thread_agent.start('Puma')
|
|
18
|
+
tcell_original_run(background)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -3,7 +3,7 @@ Unicorn::HttpServer.class_eval do
|
|
|
3
3
|
# - This check also ensures that a server is running as opposed to a different command such
|
|
4
4
|
# as `bundle exec rails runner User.count`.
|
|
5
5
|
unless Unicorn::HttpServer::START_CTX && Unicorn::HttpServer::START_CTX[0]
|
|
6
|
-
require 'tcell_agent/rails/
|
|
6
|
+
require 'tcell_agent/rails/railties/tcell_agent_unicorn_railties'
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
# This only gets instrumented when preload_app is true
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
Rack::Handler::WEBrick.class_eval do
|
|
2
2
|
class << self
|
|
3
3
|
alias_method :original_run, :run
|
|
4
|
-
def run(app, options = {})
|
|
5
|
-
TCellAgent.thread_agent.start('WEBrick')
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
if defined?(Gem::Version) &&
|
|
6
|
+
defined?(Rack.release) &&
|
|
7
|
+
Gem::Version.new(Rack.release) < Gem::Version.new('2.2.0')
|
|
8
|
+
def run(app, options = {})
|
|
9
|
+
TCellAgent.thread_agent.start('WEBrick')
|
|
10
|
+
original_run(app, options)
|
|
11
|
+
end
|
|
12
|
+
else
|
|
13
|
+
def run(app, **options)
|
|
14
|
+
TCellAgent.thread_agent.start('WEBrick')
|
|
15
|
+
original_run(app, **options)
|
|
16
|
+
end
|
|
8
17
|
end
|
|
9
18
|
end
|
|
10
19
|
end
|
|
@@ -7,25 +7,11 @@ require 'thread'
|
|
|
7
7
|
module TCellAgent
|
|
8
8
|
def self.report_settings
|
|
9
9
|
Thread.new do
|
|
10
|
-
TCellAgent::Instrumentation.safe_block('Instrumenting Agent Details') do
|
|
11
|
-
event = TCellAgent::SensorEvents::ServerAgentDetailsSensorEvent.new
|
|
12
|
-
TCellAgent.send_event(event)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
10
|
TCellAgent::Instrumentation.safe_block('Instrumenting Server Packages') do
|
|
16
11
|
event = TCellAgent::SensorEvents::ServerAgentPackagesSensorEvent.new
|
|
17
12
|
TCellAgent.send_event(event)
|
|
18
13
|
end
|
|
19
14
|
|
|
20
|
-
TCellAgent::Instrumentation.safe_block('Instrumenting Language Info') do
|
|
21
|
-
TCellAgent.send_event(
|
|
22
|
-
TCellAgent::SensorEvents::ServerAgentDetailsLanguageEvent.new(
|
|
23
|
-
'Ruby',
|
|
24
|
-
RUBY_VERSION
|
|
25
|
-
)
|
|
26
|
-
)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
15
|
TCellAgent::Instrumentation.safe_block('Instrumenting Native Lib Status') do
|
|
30
16
|
require 'tcell_agent/rust/native_agent'
|
|
31
17
|
|
|
@@ -37,85 +23,6 @@ module TCellAgent
|
|
|
37
23
|
)
|
|
38
24
|
end
|
|
39
25
|
|
|
40
|
-
TCellAgent::Instrumentation.safe_block('Instrumenting Initial Config') do
|
|
41
|
-
TCellAgent.send_event(
|
|
42
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new(
|
|
43
|
-
'allow_payloads',
|
|
44
|
-
(!!TCellAgent.configuration.allow_payloads).to_s # rubocop:disable Style/DoubleNegation
|
|
45
|
-
)
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
TCellAgent.send_event(
|
|
49
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new(
|
|
50
|
-
'reverse_proxy',
|
|
51
|
-
(!!TCellAgent.configuration.reverse_proxy).to_s # rubocop:disable Style/DoubleNegation
|
|
52
|
-
)
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
# Because of all the diff ways to initialize the agent
|
|
56
|
-
# some some of the following vars might not be set until
|
|
57
|
-
# we call this method, so call this method to set all
|
|
58
|
-
# the variables
|
|
59
|
-
TCellAgent.configuration.log_filename
|
|
60
|
-
|
|
61
|
-
TCellAgent.send_event(
|
|
62
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new(
|
|
63
|
-
'config_filename',
|
|
64
|
-
TCellAgent.configuration.config_filename
|
|
65
|
-
)
|
|
66
|
-
)
|
|
67
|
-
TCellAgent.send_event(
|
|
68
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new(
|
|
69
|
-
'logging_directory',
|
|
70
|
-
TCellAgent.configuration.agent_log_dir
|
|
71
|
-
)
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
TCellAgent.send_event(
|
|
75
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new(
|
|
76
|
-
'agent_home_directory',
|
|
77
|
-
TCellAgent.configuration.agent_home_dir
|
|
78
|
-
)
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
logging_options = TCellAgent.configuration.logging_options || {}
|
|
82
|
-
use_default_setting = !logging_options.key?(:enabled) && !logging_options.key?('enabled')
|
|
83
|
-
if use_default_setting || logging_options[:enabled] || logging_options['enabled']
|
|
84
|
-
TCellAgent.send_event(
|
|
85
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new('logging_enabled', 'true')
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
TCellAgent.send_event(
|
|
89
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new(
|
|
90
|
-
'logging_level',
|
|
91
|
-
logging_options[:level] || logging_options['level'] || 'INFO'
|
|
92
|
-
)
|
|
93
|
-
)
|
|
94
|
-
else
|
|
95
|
-
TCellAgent.send_event(
|
|
96
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new('logging_enabled', 'false')
|
|
97
|
-
)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
if TCellAgent.configuration.hmac_key
|
|
101
|
-
TCellAgent.send_event(
|
|
102
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new(
|
|
103
|
-
'hmac_key_present',
|
|
104
|
-
(!!TCellAgent.configuration.hmac_key).to_s # rubocop:disable Style/DoubleNegation
|
|
105
|
-
)
|
|
106
|
-
)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
if TCellAgent.configuration.reverse_proxy
|
|
110
|
-
TCellAgent.send_event(
|
|
111
|
-
TCellAgent::SensorEvents::AgentSettingEvent.new(
|
|
112
|
-
'reverse_proxy_ip_address_header',
|
|
113
|
-
TCellAgent.configuration.reverse_proxy_ip_address_header
|
|
114
|
-
)
|
|
115
|
-
)
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
26
|
if defined?(::Rails)
|
|
120
27
|
TCellAgent::Instrumentation.safe_block('Instrumenting routes') do
|
|
121
28
|
TCellAgent::Instrumentation::Rails.instrument_routes
|
data/lib/tcell_agent/sinatra.rb
CHANGED
|
@@ -16,6 +16,7 @@ module TCellAgent
|
|
|
16
16
|
TCellAgent::Instrumentation.safe_block('Setting Headers') do
|
|
17
17
|
headers_policy = TCellAgent.policy(TCellAgent::PolicyTypes::HEADERS)
|
|
18
18
|
policy_headers = headers_policy.get_headers(
|
|
19
|
+
headers['Content-Type'],
|
|
19
20
|
request.env[TCellAgent::Instrumentation::TCELL_ID]
|
|
20
21
|
)
|
|
21
22
|
policy_headers.each do |header_info|
|
|
@@ -40,10 +40,11 @@ module TCellAgent
|
|
|
40
40
|
tcell_context.request_method,
|
|
41
41
|
tcell_context.remote_address,
|
|
42
42
|
tcell_context.route_id,
|
|
43
|
-
tcell_context.
|
|
43
|
+
tcell_context.session_id,
|
|
44
44
|
tcell_context.user_id,
|
|
45
45
|
tcell_context.transaction_id,
|
|
46
|
-
tcell_context.uri
|
|
46
|
+
tcell_context.uri,
|
|
47
|
+
tcell_context.reverse_proxy_header_value
|
|
47
48
|
)
|
|
48
49
|
meta_data.path = tcell_context.path
|
|
49
50
|
|
|
@@ -70,7 +71,8 @@ module TCellAgent
|
|
|
70
71
|
:response_headers,
|
|
71
72
|
:csrf_exception_name,
|
|
72
73
|
:sql_exceptions,
|
|
73
|
-
:database_result_sizes
|
|
74
|
+
:database_result_sizes,
|
|
75
|
+
:reverse_proxy_header_value
|
|
74
76
|
|
|
75
77
|
attr_reader :flattened_get_dict,
|
|
76
78
|
:flattened_cookie_dict,
|
|
@@ -85,7 +87,8 @@ module TCellAgent
|
|
|
85
87
|
session_id,
|
|
86
88
|
user_id,
|
|
87
89
|
transaction_id,
|
|
88
|
-
location
|
|
90
|
+
location,
|
|
91
|
+
reverse_proxy_header_value)
|
|
89
92
|
@method = method
|
|
90
93
|
@remote_address = remote_address
|
|
91
94
|
@route_id = route_id
|
|
@@ -93,7 +96,7 @@ module TCellAgent
|
|
|
93
96
|
@user_id = user_id
|
|
94
97
|
@transaction_id = transaction_id
|
|
95
98
|
@location = location
|
|
96
|
-
@
|
|
99
|
+
@reverse_proxy_header_value = reverse_proxy_header_value
|
|
97
100
|
|
|
98
101
|
@flattened_get_dict = {}
|
|
99
102
|
@flattened_cookie_dict = {}
|
|
@@ -148,6 +151,7 @@ module TCellAgent
|
|
|
148
151
|
if !content_length.nil? && content_length > TCELL_MAX_BODY_LENGTH || request.content_type.nil?
|
|
149
152
|
return nil
|
|
150
153
|
end
|
|
154
|
+
|
|
151
155
|
raw_post_data = nil
|
|
152
156
|
# Positions strio to the beginning of input, resetting lineno to zero.
|
|
153
157
|
# rails 4.1 seems to read the stringIO directly and so body.gets is empty
|
|
@@ -171,10 +175,15 @@ module TCellAgent
|
|
|
171
175
|
self.get_dict = request.GET
|
|
172
176
|
self.cookie_dict = request.cookies
|
|
173
177
|
|
|
174
|
-
self.post_dict = if @content_type.start_with?('application/json', 'application/xml')
|
|
178
|
+
self.post_dict = if @content_type.start_with?('application/json', 'application/xml') ||
|
|
179
|
+
(@content_type.start_with?('multipart/form-data') && @request_content_bytes_len == 0)
|
|
175
180
|
{}
|
|
176
181
|
else
|
|
177
|
-
|
|
182
|
+
begin
|
|
183
|
+
request.POST
|
|
184
|
+
rescue EOFError
|
|
185
|
+
{}
|
|
186
|
+
end
|
|
178
187
|
end
|
|
179
188
|
|
|
180
189
|
self.headers_dict = request.env
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module TCellAgent
|
|
2
2
|
module Utils
|
|
3
3
|
module Strings
|
|
4
|
-
BLANK_RE = /\A[[:space:]]*\z
|
|
4
|
+
BLANK_RE = /\A[[:space:]]*\z/.freeze
|
|
5
5
|
|
|
6
6
|
def self.blank?(str)
|
|
7
|
-
str.nil? || str.empty? || BLANK_RE === str
|
|
7
|
+
str.nil? || str.empty? || BLANK_RE === str
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def self.present?(str)
|
data/lib/tcell_agent/version.rb
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'tcell_agent'
|
|
2
|
+
|
|
3
|
+
TCellAgent.configuration.enabled = true
|
|
4
|
+
TCellAgent.configuration.instrument = true
|
|
5
|
+
TCellAgent.configuration.enable_intercept_requests = true
|
|
6
|
+
TCellAgent.configuration.disabled_instrumentation = []
|
|
7
|
+
TCellAgent.thread_agent.instrument_built_ins
|
|
8
|
+
|
|
9
|
+
# This monkey patch turns off blocking for LFI/CMDI when run in CRuby specs/
|
|
10
|
+
# test suite. The original method also depends on a Rails installation,
|
|
11
|
+
# which CRuby does not have installed.
|
|
12
|
+
module TCellAgent
|
|
13
|
+
module Instrumentation
|
|
14
|
+
module Lfi
|
|
15
|
+
def self.block_file_access?(_path, _mode)
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module Cmdi
|
|
22
|
+
def self.block_command?(_cmd)
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -2,228 +2,78 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
module TCellAgent
|
|
4
4
|
describe Configuration do
|
|
5
|
-
describe '
|
|
6
|
-
context '
|
|
7
|
-
it 'should
|
|
8
|
-
|
|
5
|
+
describe 'should_instrument?' do
|
|
6
|
+
context 'with the agent disabled' do
|
|
7
|
+
it 'should return false' do
|
|
8
|
+
config = Configuration.new
|
|
9
|
+
config.enabled = false
|
|
9
10
|
|
|
10
|
-
expect(
|
|
11
|
-
File.join(Dir.getwd, 'tcell/logs/tcell_agent.log')
|
|
12
|
-
)
|
|
13
|
-
expect(configuration.config_filename).to eq(
|
|
14
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
15
|
-
)
|
|
11
|
+
expect(config.should_instrument?).to be_falsey
|
|
16
12
|
end
|
|
17
13
|
end
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
it 'should set config filename to default, cache file and log file are updated' do
|
|
40
|
-
old_tcell_agent_home = ENV['TCELL_AGENT_HOME']
|
|
41
|
-
old_tcell_agent_log_dir = ENV['TCELL_AGENT_LOG_DIR']
|
|
42
|
-
|
|
43
|
-
ENV['TCELL_AGENT_HOME'] = 'spec_tcell_home'
|
|
44
|
-
ENV['TCELL_AGENT_LOG_DIR'] = 'spec_tcell_log_dir'
|
|
45
|
-
|
|
46
|
-
configuration = Configuration.new
|
|
47
|
-
|
|
48
|
-
expect(configuration.log_filename).to eq(
|
|
49
|
-
'spec_tcell_log_dir/tcell_agent.log'
|
|
50
|
-
)
|
|
51
|
-
expect(configuration.config_filename).to eq(
|
|
52
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
ENV['TCELL_AGENT_HOME'] = old_tcell_agent_home
|
|
56
|
-
ENV['TCELL_AGENT_LOG_DIR'] = old_tcell_agent_log_dir
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
context 'TCELL_AGENT_HOME, TCELL_AGENT_LOG_DIR, and TCELL_AGENT_CONFIG defined ' do
|
|
61
|
-
it 'should update config filename, cache file, and log file' do
|
|
62
|
-
old_tcell_agent_home = ENV['TCELL_AGENT_HOME']
|
|
63
|
-
old_tcell_agent_log_dir = ENV['TCELL_AGENT_LOG_DIR']
|
|
64
|
-
old_config_filename = ENV['TCELL_AGENT_CONFIG']
|
|
65
|
-
|
|
66
|
-
ENV['TCELL_AGENT_HOME'] = 'spec_tcell_home'
|
|
67
|
-
ENV['TCELL_AGENT_LOG_DIR'] = 'spec_tcell_log_dir'
|
|
68
|
-
ENV['TCELL_AGENT_CONFIG'] = 'spec_config/tcell_agent.config'
|
|
69
|
-
|
|
70
|
-
configuration = Configuration.new
|
|
71
|
-
|
|
72
|
-
expect(configuration.log_filename).to eq(
|
|
73
|
-
'spec_tcell_log_dir/tcell_agent.log'
|
|
74
|
-
)
|
|
75
|
-
expect(configuration.config_filename).to eq(
|
|
76
|
-
'spec_config/tcell_agent.config'
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
ENV['TCELL_AGENT_HOME'] = old_tcell_agent_home
|
|
80
|
-
ENV['TCELL_AGENT_LOG_DIR'] = old_tcell_agent_log_dir
|
|
81
|
-
ENV['TCELL_AGENT_CONFIG'] = old_config_filename
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
describe '#data_exposure' do
|
|
87
|
-
context 'no data_exposure defined' do
|
|
88
|
-
it 'should set max_data_ex_db_records_per_request to default' do
|
|
89
|
-
no_data_ex = double(
|
|
90
|
-
'no_data_ex',
|
|
91
|
-
:read => {
|
|
92
|
-
:version => 1,
|
|
93
|
-
:applications => [
|
|
94
|
-
:app_id => 'app_id',
|
|
95
|
-
:name => 'test',
|
|
96
|
-
:api_key => 'api_key'
|
|
97
|
-
]
|
|
98
|
-
}.to_json
|
|
99
|
-
)
|
|
100
|
-
expect(File).to receive(:file?).with(
|
|
101
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
102
|
-
).and_return(true)
|
|
103
|
-
expect(File).to receive(:open).with(
|
|
104
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
105
|
-
).and_return(no_data_ex)
|
|
106
|
-
configuration = Configuration.new('no_data_ex.config')
|
|
107
|
-
|
|
108
|
-
expect(configuration.max_data_ex_db_records_per_request).to eq(1000)
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
context 'data_exposure is empty' do
|
|
113
|
-
it 'should set max_data_ex_db_records_per_request to default' do
|
|
114
|
-
no_data_ex = double(
|
|
115
|
-
'no_data_ex',
|
|
116
|
-
:read => {
|
|
117
|
-
:version => 1,
|
|
118
|
-
:applications => [
|
|
119
|
-
:app_id => 'app_id',
|
|
120
|
-
:name => 'test',
|
|
121
|
-
:api_key => 'api_key',
|
|
122
|
-
:data_exposure => {}
|
|
123
|
-
]
|
|
124
|
-
}.to_json
|
|
125
|
-
)
|
|
126
|
-
expect(File).to receive(:file?).with(
|
|
127
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
128
|
-
).and_return(true)
|
|
129
|
-
expect(File).to receive(:open).with(
|
|
130
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
131
|
-
).and_return(no_data_ex)
|
|
132
|
-
configuration = Configuration.new('no_data_ex.config')
|
|
133
|
-
|
|
134
|
-
expect(configuration.max_data_ex_db_records_per_request).to eq(1000)
|
|
14
|
+
context 'with the agent enabled' do
|
|
15
|
+
context 'with all instrumentation enabled' do
|
|
16
|
+
context 'with no parameters' do
|
|
17
|
+
it 'should return true' do
|
|
18
|
+
config = Configuration.new
|
|
19
|
+
config.enabled = true
|
|
20
|
+
config.instrument = true
|
|
21
|
+
|
|
22
|
+
expect(config.should_instrument?).to be_truthy
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
context 'with parameters' do
|
|
26
|
+
it 'should return true' do
|
|
27
|
+
config = Configuration.new
|
|
28
|
+
config.enabled = true
|
|
29
|
+
config.instrument = true
|
|
30
|
+
config.disabled_instrumentation = Set.new
|
|
31
|
+
|
|
32
|
+
expect(config.should_instrument?('devise')).to be_truthy
|
|
33
|
+
end
|
|
34
|
+
end
|
|
135
35
|
end
|
|
136
|
-
|
|
36
|
+
context 'with auth frameworks disabled' do
|
|
37
|
+
it 'should return false' do
|
|
38
|
+
config = Configuration.new
|
|
39
|
+
config.disabled_instrumentation = Set.new(%w[authlogic devise doorkeeper])
|
|
137
40
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
no_data_ex = double(
|
|
141
|
-
'no_data_ex',
|
|
142
|
-
:read => {
|
|
143
|
-
:version => 1,
|
|
144
|
-
:applications => [
|
|
145
|
-
:app_id => 'app_id',
|
|
146
|
-
:name => 'test',
|
|
147
|
-
:api_key => 'api_key',
|
|
148
|
-
:data_exposure => {
|
|
149
|
-
:max_data_ex_db_records_per_request => 5000
|
|
150
|
-
}
|
|
151
|
-
]
|
|
152
|
-
}.to_json
|
|
153
|
-
)
|
|
154
|
-
expect(File).to receive(:file?).with(
|
|
155
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
156
|
-
).and_return(true)
|
|
157
|
-
expect(File).to receive(:open).with(
|
|
158
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
159
|
-
).and_return(no_data_ex)
|
|
160
|
-
configuration = Configuration.new('no_data_ex.config')
|
|
161
|
-
|
|
162
|
-
expect(configuration.max_data_ex_db_records_per_request).to eq(5000)
|
|
41
|
+
expect(config.should_instrument?('devise')).to be_falsey
|
|
42
|
+
end
|
|
163
43
|
end
|
|
164
44
|
end
|
|
165
45
|
end
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
:applications => [
|
|
176
|
-
:app_id => 'app_id',
|
|
177
|
-
:api_key => 'api_key',
|
|
178
|
-
:allow_payloads => false
|
|
179
|
-
]
|
|
180
|
-
}.to_json
|
|
181
|
-
)
|
|
182
|
-
expect(File).to receive(:file?).with(
|
|
183
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
184
|
-
).and_return(true)
|
|
185
|
-
expect(File).to receive(:open).with(
|
|
186
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
187
|
-
).and_return(allow_payloads_enabled)
|
|
188
|
-
|
|
189
|
-
configuration = Configuration.new
|
|
190
|
-
|
|
191
|
-
expect(configuration.allow_payloads).to eq(false)
|
|
192
|
-
end
|
|
46
|
+
describe 'populate_configuration' do
|
|
47
|
+
context 'with a poor native_agent_config_response' do
|
|
48
|
+
it 'should not throw an error' do
|
|
49
|
+
native_agent_config_response = {}
|
|
50
|
+
|
|
51
|
+
config = Configuration.new
|
|
52
|
+
expect do
|
|
53
|
+
config.populate_configuration(native_agent_config_response)
|
|
54
|
+
end.not_to raise_error
|
|
193
55
|
end
|
|
194
56
|
end
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
216
|
-
).and_return(true)
|
|
217
|
-
expect(File).to receive(:open).with(
|
|
218
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
219
|
-
).and_return(allow_payloads_enabled)
|
|
220
|
-
|
|
221
|
-
configuration = Configuration.new
|
|
222
|
-
|
|
223
|
-
ENV['TCELL_AGENT_ALLOW_PAYLOADS'] = old_tcell_agent_allow_payloads
|
|
224
|
-
|
|
225
|
-
expect(configuration.allow_payloads).to eq(false)
|
|
226
|
-
end
|
|
57
|
+
context 'with an elaborate native_agent_config_response' do
|
|
58
|
+
it 'should set all the correct configurations' do
|
|
59
|
+
native_agent_config_response = { 'enabled' => true,
|
|
60
|
+
'disabled_instrumentation' => %w[devise doorkeeper],
|
|
61
|
+
'update_policy' => 'true',
|
|
62
|
+
'applications' => { 'first' => { 'app_id' => 'app_id_placeholder',
|
|
63
|
+
'api_key' => 'api_key_paceholder',
|
|
64
|
+
'hmac_key' => 'hmac_key_placeholder',
|
|
65
|
+
'password_hmac_key' => 'password_hmac_key_placeholder',
|
|
66
|
+
'proxy_config' => { 'reverse_proxy' => true,
|
|
67
|
+
'reverse_proxy_ip_address_header' => 'X-Forwarded-For' } } },
|
|
68
|
+
'endpoint_config' => { 'api_url' => 'https://us.agent.tcell.insight.rapid7.com/api/v1' },
|
|
69
|
+
'ruby_config' => { 'enable_policy_polling' => true } }
|
|
70
|
+
|
|
71
|
+
config = Configuration.new
|
|
72
|
+
config.populate_configuration(native_agent_config_response)
|
|
73
|
+
|
|
74
|
+
expect(config.disabled_instrumentation).to be_a(Set)
|
|
75
|
+
expect(config.disabled_instrumentation).to include('devise', 'doorkeeper')
|
|
76
|
+
expect(config.enable_intercept_requests).to be_truthy
|
|
227
77
|
end
|
|
228
78
|
end
|
|
229
79
|
end
|