tcell_agent 2.3.0 → 2.5.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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -2
  3. data/bin/tcell_agent +6 -11
  4. data/lib/tcell_agent/agent.rb +18 -13
  5. data/lib/tcell_agent/config_initializer.rb +2 -5
  6. data/lib/tcell_agent/configuration.rb +4 -4
  7. data/lib/tcell_agent/hooks/login_fraud.rb +1 -1
  8. data/lib/tcell_agent/instrumentation/cmdi.rb +32 -0
  9. data/lib/tcell_agent/instrumentation/lfi.rb +55 -9
  10. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/file.rb +21 -0
  11. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/io.rb +75 -0
  12. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/kernel.rb +80 -0
  13. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/file.rb +21 -0
  14. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/io.rb +75 -0
  15. data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/kernel.rb +80 -0
  16. data/lib/tcell_agent/instrumentation.rb +14 -6
  17. data/lib/tcell_agent/logger.rb +2 -2
  18. data/lib/tcell_agent/policies/dataloss_policy.rb +15 -8
  19. data/lib/tcell_agent/policies/headers_policy.rb +2 -2
  20. data/lib/tcell_agent/policies/patches_policy.rb +8 -4
  21. data/lib/tcell_agent/policies/policies_manager.rb +1 -0
  22. data/lib/tcell_agent/policies/policy_polling.rb +4 -3
  23. data/lib/tcell_agent/rails/auth/doorkeeper.rb +1 -0
  24. data/lib/tcell_agent/rails/better_ip.rb +7 -19
  25. data/lib/tcell_agent/rails/dlp/process_request.rb +5 -0
  26. data/lib/tcell_agent/rails/dlp.rb +48 -48
  27. data/lib/tcell_agent/rails/dlp_handler.rb +9 -10
  28. data/lib/tcell_agent/rails/js_agent_insert.rb +2 -3
  29. data/lib/tcell_agent/rails/middleware/context_middleware.rb +2 -1
  30. data/lib/tcell_agent/rails/middleware/global_middleware.rb +1 -5
  31. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +1 -0
  32. data/lib/tcell_agent/rails/routes/grape.rb +2 -1
  33. data/lib/tcell_agent/rails/settings_reporter.rb +3 -6
  34. data/lib/tcell_agent/rails/tcell_body_proxy.rb +4 -6
  35. data/lib/tcell_agent/routes/table.rb +3 -0
  36. data/lib/tcell_agent/rust/agent_config.rb +18 -0
  37. data/lib/tcell_agent/rust/{libtcellagent-alpine-6.2.1.so → libtcellagent-alpine.so} +0 -0
  38. data/lib/tcell_agent/rust/{tcellagent-6.2.1.dll → libtcellagent-x64.dll} +0 -0
  39. data/lib/tcell_agent/rust/{libtcellagent-6.2.1.dylib → libtcellagent.dylib} +0 -0
  40. data/lib/tcell_agent/rust/{libtcellagent-6.2.1.so → libtcellagent.so} +0 -0
  41. data/lib/tcell_agent/rust/native_agent.rb +51 -59
  42. data/lib/tcell_agent/rust/native_library.rb +7 -10
  43. data/lib/tcell_agent/sensor_events/server_agent.rb +3 -100
  44. data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +1 -0
  45. data/lib/tcell_agent/servers/puma.rb +25 -8
  46. data/lib/tcell_agent/servers/rack_puma_handler.rb +13 -3
  47. data/lib/tcell_agent/servers/webrick.rb +14 -4
  48. data/lib/tcell_agent/settings_reporter.rb +0 -14
  49. data/lib/tcell_agent/sinatra.rb +1 -0
  50. data/lib/tcell_agent/tcell_context.rb +15 -6
  51. data/lib/tcell_agent/utils/headers.rb +0 -1
  52. data/lib/tcell_agent/utils/strings.rb +2 -2
  53. data/lib/tcell_agent/version.rb +1 -1
  54. data/spec/cruby_spec_helper.rb +26 -0
  55. data/spec/lib/tcell_agent/instrument_servers_spec.rb +42 -7
  56. data/spec/lib/tcell_agent/instrumentation/cmdi/io_cmdi_spec.rb +2 -2
  57. data/spec/lib/tcell_agent/instrumentation/lfi/file_lfi_spec.rb +211 -272
  58. data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +207 -223
  59. data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +89 -70
  60. data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +73 -0
  61. data/spec/lib/tcell_agent/patches_spec.rb +2 -1
  62. data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +1 -2
  63. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +5 -6
  64. data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +21 -2
  65. data/spec/lib/tcell_agent/policies/policies_manager_spec.rb +1 -1
  66. data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +13 -8
  67. data/spec/lib/tcell_agent/rails/better_ip_spec.rb +9 -11
  68. data/spec/lib/tcell_agent/rails/csrf_exception_spec.rb +6 -6
  69. data/spec/lib/tcell_agent/rails/dlp_spec.rb +1 -0
  70. data/spec/lib/tcell_agent/rails/js_agent_insert_spec.rb +10 -2
  71. data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +2 -1
  72. data/spec/lib/tcell_agent/rails/routes/route_id_spec.rb +4 -4
  73. data/spec/lib/tcell_agent/settings_reporter_spec.rb +2 -16
  74. data/spec/lib/tcell_agent/tcell_context_spec.rb +6 -5
  75. data/spec/spec_helper.rb +3 -1
  76. data/spec/support/builders.rb +2 -1
  77. data/spec/support/server_mocks/{puma_mock.rb → puma_mock_1.rb} +5 -1
  78. data/spec/support/server_mocks/puma_mock_2.rb +26 -0
  79. data/spec/support/server_mocks/puma_mock_3.rb +22 -0
  80. data/spec/support/shared_spec.rb +29 -0
  81. data/tcell_agent.gemspec +14 -14
  82. metadata +29 -21
  83. data/Rakefile +0 -18
  84. data/lib/tcell_agent/instrumentation/monkey_patches/file.rb +0 -25
  85. data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +0 -131
  86. data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +0 -102
@@ -65,7 +65,8 @@ module TCellAgent
65
65
  :password, :route_id, :path, :uri, :fullpath, :context_filters_by_term,
66
66
  :database_filters, :remote_address, :user_agent, :request_method,
67
67
  :path_parameters, :patches_blocking_triggered, :grape_mount_endpoint,
68
- :referrer, :csrf_exception_name, :sql_exceptions, :database_result_sizes
68
+ :referrer, :csrf_exception_name, :sql_exceptions, :database_result_sizes,
69
+ :reverse_proxy_header_value
69
70
 
70
71
  def self.filterx(sanitize_string, event_flag, replace_flag, term)
71
72
  send_event = false
@@ -91,26 +92,31 @@ module TCellAgent
91
92
 
92
93
  def valid_term?(term)
93
94
  return true if !term.nil? && term != '' && term.to_s.length >= 5
95
+
94
96
  false
95
97
  end
96
98
 
97
99
  def add_response_db_filter(term, action_obj, database, schema, table, field)
98
100
  return unless valid_term?(term)
101
+
99
102
  context_filters_by_term[term.to_s].add(ContextFilter.new.for_database(database, schema, table, field, action_obj))
100
103
  end
101
104
 
102
105
  def add_filter_for_request_parameter(term, rule, parameter_name)
103
106
  return unless valid_term?(term)
107
+
104
108
  context_filters_by_term[term.to_s].add(ContextFilter.new.for_request('form', parameter_name, rule))
105
109
  end
106
110
 
107
111
  def add_filter_for_header_value(term, rule, header_name)
108
112
  return unless valid_term?(term)
113
+
109
114
  context_filters_by_term[term.to_s].add(ContextFilter.new.for_request('header', header_name, rule))
110
115
  end
111
116
 
112
117
  def add_filter_for_cookie_value(term, rule, cookie_name)
113
118
  return unless valid_term?(term)
119
+
114
120
  context_filters_by_term[term.to_s].add(ContextFilter.new.for_request('cookie', cookie_name, rule))
115
121
  end
116
122
 
@@ -139,6 +145,7 @@ module TCellAgent
139
145
  send_flag = TCellData.filterx(body, !event_filters.empty?, !replace_filters.empty?, term)
140
146
  send_flag ||= TCellData.filterx(body, !event_filters.empty?, !replace_filters.empty?, CGI.escapeHTML(term))
141
147
  next unless send_flag
148
+
142
149
  (replace_filters + event_filters).each do |filter|
143
150
  base_event = TCellAgent::SensorEvents::DlpEvent.new(
144
151
  route_id,
@@ -183,6 +190,7 @@ module TCellAgent
183
190
  event_filters = (context_filters.select { |context_filter| (context_filter.rule.log_redact != true && context_filter.rule.log_event == true) })
184
191
  send_flag = TCellData.filterx(log_msg, !event_filters.empty?, !replace_filters.empty?, term)
185
192
  next unless send_flag
193
+
186
194
  (replace_filters + event_filters).each do |filter|
187
195
  base_event = TCellAgent::SensorEvents::DlpEvent.new(
188
196
  route_id,
@@ -213,7 +221,7 @@ module TCellAgent
213
221
  end
214
222
  end
215
223
 
216
- # Note: mock for tests
224
+ # NOTE: mock for tests
217
225
  def self.get_safe_block_logger
218
226
  unless defined?(@safe_block_logger)
219
227
  @safe_block_logger = TCellAgent::ModuleLogger.new(TCellAgent.logger, name)
@@ -224,15 +232,15 @@ module TCellAgent
224
232
 
225
233
  def self.safe_block(message, &block)
226
234
  block.call
227
- rescue StandardError => ex
235
+ rescue StandardError => e
228
236
  logger = get_safe_block_logger
229
- logger.error("Error #{message} (#{ex.class}): #{ex.message}")
230
- logger.exception(ex)
237
+ logger.error("Error #{message} (#{e.class}): #{e.message}")
238
+ logger.exception(e)
231
239
  end
232
240
 
233
241
  def self.safe_block_no_log(_message, &block)
234
242
  block.call
235
- rescue StandardError # rubocop:disable Lint/HandleExceptions
243
+ rescue StandardError
236
244
  # do nothing
237
245
  end
238
246
  end
@@ -31,13 +31,13 @@ module TCellAgent
31
31
  end
32
32
  end
33
33
 
34
- # Note: since the agent waits until native agent
34
+ # NOTE: since the agent waits until native agent
35
35
  # is available, this is only used in errors
36
36
  # throwned while the agent is instrumenting or starting up
37
37
  # so it's ok to send those to STDOUT always
38
38
  class RubyLogger
39
39
  def initialize
40
- @logger = Logger.new(STDOUT)
40
+ @logger = Logger.new(STDOUT) # rubocop:disable Style/GlobalStdStream
41
41
  end
42
42
 
43
43
  def exception(module_name, exception)
@@ -110,24 +110,22 @@ module TCellAgent
110
110
 
111
111
  def get_actions_for_request(context, variable, route_id = nil)
112
112
  return nil if context.nil? || variable.nil?
113
+
113
114
  route_id = '*' if route_id.nil?
114
115
  if context != RequestProtectionManager::COOKIE
115
116
  variable = variable.downcase
116
117
  end
117
118
  actions = Set.new
118
119
  if @request_filter_actions.key?(context)
119
- if @request_filter_actions[context].key?(route_id)
120
- if @request_filter_actions[context][route_id].key?(variable)
121
- actions.merge(@request_filter_actions[context][route_id][variable])
122
- end
120
+ if @request_filter_actions[context].key?(route_id) && @request_filter_actions[context][route_id].key?(variable)
121
+ actions.merge(@request_filter_actions[context][route_id][variable])
123
122
  end
124
- if route_id != '*' && @request_filter_actions[context].key?('*')
125
- if @request_filter_actions[context]['*'].key?(variable)
126
- actions.merge(@request_filter_actions[context]['*'][variable])
127
- end
123
+ if route_id != '*' && @request_filter_actions[context].key?('*') && @request_filter_actions[context]['*'].key?(variable)
124
+ actions.merge(@request_filter_actions[context]['*'][variable])
128
125
  end
129
126
  end
130
127
  return nil if actions.size <= 0
128
+
131
129
  actions
132
130
  end
133
131
 
@@ -136,12 +134,16 @@ module TCellAgent
136
134
  actions = Set.new
137
135
  [database, '*'].each do |d|
138
136
  next if @database_actions.key?(d) == false
137
+
139
138
  [schema, '*'].each do |s|
140
139
  next if @database_actions[d].key?(s) == false
140
+
141
141
  [table, '*'].each do |t|
142
142
  next if @database_actions[d][s].key?(t) == false
143
+
143
144
  [field, '*'].each do |f|
144
145
  next if @database_actions[d][s][t].key?(f) == false
146
+
145
147
  route_id_rules = @database_actions[d][s][t][f]
146
148
  if route_id_rules.key?(route_id)
147
149
  actions.merge(@database_actions[d][s][t][f][route_id])
@@ -154,6 +156,7 @@ module TCellAgent
154
156
  end
155
157
  end
156
158
  return nil if actions.empty?
159
+
157
160
  actions
158
161
  end
159
162
 
@@ -240,8 +243,10 @@ module TCellAgent
240
243
  end
241
244
 
242
245
  next unless context && @request_filter_actions.key?(context) && variables && options
246
+
243
247
  filter_actions = DataLossPolicy.actions_from_json(options)
244
248
  next if filter_actions.nil?
249
+
245
250
  @enabled = true
246
251
  filter_actions.action_id = rule_id
247
252
  variables.each do |variable|
@@ -258,8 +263,10 @@ module TCellAgent
258
263
  end
259
264
 
260
265
  return unless data_json.key?('db_protections')
266
+
261
267
  protections = data_json['db_protections']
262
268
  return unless protections
269
+
263
270
  protections.each do |protection_json|
264
271
  scope = protection_json.fetch('scope', nil)
265
272
  databases = protection_json.fetch('databases', ['*'])
@@ -14,10 +14,10 @@ module TCellAgent
14
14
  @enabled = enablements['headers'] || false
15
15
  end
16
16
 
17
- def get_headers(tcell_context)
17
+ def get_headers(content_type, tcell_context)
18
18
  return [] unless @enabled
19
19
 
20
- response = @native_agent.get_headers(tcell_context)
20
+ response = @native_agent.get_headers(content_type, tcell_context)
21
21
  response['headers'] || []
22
22
  end
23
23
  end
@@ -17,10 +17,14 @@ module TCellAgent
17
17
  def block_request?(appsensor_meta)
18
18
  return false unless @enabled
19
19
 
20
- response = @native_agent.apply_patches(
21
- appsensor_meta
22
- )
23
- !response['apply_response'].nil? && response['apply_response']['status'] == 'Blocked'
20
+ quick_check_response = @native_agent.apply_suspicious_quick_check(appsensor_meta)
21
+
22
+ if quick_check_response == 1
23
+ response = @native_agent.apply_patches(appsensor_meta)
24
+ return !response['apply_response'].nil? && response['apply_response']['status'] == 'Blocked'
25
+ end
26
+
27
+ quick_check_response == 2
24
28
  end
25
29
  end
26
30
  end
@@ -47,6 +47,7 @@ module TCellAgent
47
47
  TCellAgent::Instrumentation.safe_block('Setting DLP policy') do
48
48
  dlp_api_identifier = TCellAgent::Policies::DataLossPolicy.api_identifier
49
49
  return unless policies_json.key?(dlp_api_identifier)
50
+
50
51
  @policies[dlp_api_identifier] = TCellAgent::Policies::DataLossPolicy.new(
51
52
  policies_json[dlp_api_identifier]
52
53
  )
@@ -20,6 +20,7 @@ module TCellAgent
20
20
 
21
21
  @policy_polling_worker_mutex.synchronize do
22
22
  return if policy_polling_running?
23
+
23
24
  start_policy_polling_loop(native_agent)
24
25
  end
25
26
  end
@@ -44,9 +45,9 @@ module TCellAgent
44
45
  policies_and_enablements['enablements'],
45
46
  policies_and_enablements['policies']
46
47
  )
47
- rescue StandardError => standard_error
48
- module_logger.error("Error in polling policies: #{standard_error.message}")
49
- module_logger.exception(standard_error)
48
+ rescue StandardError => e
49
+ module_logger.error("Error in polling policies: #{e.message}")
50
+ module_logger.exception(e)
50
51
  end
51
52
 
52
53
  # TODO(ralba): this might need to be changed to see how it affects performance
@@ -14,6 +14,7 @@ module TCellAgent
14
14
  tcell_data = request.env[TCellAgent::Instrumentation::TCELL_ID]
15
15
 
16
16
  return unless tcell_data
17
+
17
18
  headers = request.env
18
19
 
19
20
  if result.is_a?(Doorkeeper::OAuth::TokenResponse)
@@ -4,28 +4,16 @@ require 'tcell_agent/instrumentation'
4
4
  module TCellAgent
5
5
  module Utils
6
6
  module Rails
7
- def self.better_ip(request)
8
- if TCellAgent.configuration.reverse_proxy
9
- TCellAgent::Instrumentation.safe_block('Extracting reverse proxy IP') do
10
- reverse_proxy_header = TCellAgent.configuration.reverse_proxy_ip_address_header
11
- reverse_proxy_header = if TCellAgent::Utils::Strings.present?(reverse_proxy_header)
12
- 'HTTP_' + reverse_proxy_header.upcase.tr('-', '_')
13
- else
14
- 'HTTP_X_FORWARDED_FOR'
15
- end
7
+ def self.reverse_proxy_header(request)
8
+ return unless TCellAgent.configuration.reverse_proxy
16
9
 
17
- x_forwarded_for = request.env[reverse_proxy_header]
18
- ip = if TCellAgent::Utils::Strings.present?(x_forwarded_for)
19
- x_forwarded_for.split(',')[0].strip
20
- else
21
- request.ip
22
- end
10
+ TCellAgent::Instrumentation.safe_block('Extracting reverse proxy header') do
11
+ reverse_proxy_header = TCellAgent.configuration.reverse_proxy_ip_address_header
23
12
 
24
- return ip
25
- end
26
- end
13
+ return if reverse_proxy_header.nil? || reverse_proxy_header.empty?
27
14
 
28
- request.ip
15
+ return request.env["HTTP_#{reverse_proxy_header.upcase.tr('-', '_')}"]
16
+ end
29
17
  end
30
18
  end
31
19
  end
@@ -37,6 +37,7 @@ module TCellAgent
37
37
  dataex_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
38
38
  tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
39
39
  return unless tcell_context && dataex_policy && dataex_policy.actions_for_form_parameter?
40
+
40
41
  for_params(request) do |_method, param_name, param_value|
41
42
  actions = dataex_policy.get_actions_for_form_parameter(param_name, tcell_context.route_id)
42
43
  if actions
@@ -51,11 +52,13 @@ module TCellAgent
51
52
  dataex_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
52
53
  tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
53
54
  return unless tcell_context && dataex_policy && dataex_policy.actions_for_headers?
55
+
54
56
  headers = request.env.select { |k, _v| k.start_with? 'HTTP_' }
55
57
  headers.each do |header_name, header_value|
56
58
  header_name = header_name.sub(/^HTTP_/, '').tr('_', '-')
57
59
  actions = dataex_policy.get_actions_for_header(header_name)
58
60
  next unless actions
61
+
59
62
  actions.each do |action|
60
63
  tcell_context.add_filter_for_header_value(header_value, action, header_name)
61
64
  end
@@ -66,9 +69,11 @@ module TCellAgent
66
69
  dataex_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
67
70
  tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
68
71
  return unless tcell_context && dataex_policy && dataex_policy.actions_for_cookie?
72
+
69
73
  request.cookies.each do |cookie_name, cookie_value|
70
74
  actions = dataex_policy.get_actions_for_cookie(cookie_name)
71
75
  next unless actions
76
+
72
77
  actions.each do |action|
73
78
  tcell_context.add_filter_for_cookie_value(cookie_value, action, cookie_name)
74
79
  end
@@ -80,6 +80,7 @@ module TCellAgent
80
80
  normalized_column_names[namespaced_column_name] = column_name
81
81
 
82
82
  next unless column_name && (!namespace || namespace == table_name)
83
+
83
84
  rules = dlp_policy.get_actions_for_table(
84
85
  database_name,
85
86
  '*',
@@ -190,6 +191,7 @@ module TCellAgent
190
191
  results[0...TCellAgent.configuration.max_data_ex_db_records_per_request].each do |record|
191
192
  column_name_to_rules.each do |column_name, rules|
192
193
  next unless rules
194
+
193
195
  rules.each do |rule|
194
196
  tcell_context.add_response_db_filter(
195
197
  record[column_name.to_sym],
@@ -301,31 +303,29 @@ module TCellAgent
301
303
  def log_enforce(tcell_context, sanitize_string)
302
304
  if TCellAgent.configuration.should_instrument? &&
303
305
  TCellAgent.configuration.should_intercept_requests?
304
- if tcell_context && tcell_context.session_id
305
- session_id_actions = get_actions_for_session_id
306
- if session_id_actions
307
- send_event = false
308
- sanitize_string.gsub!(tcell_context.session_id) do |m|
309
- if session_id_actions.log_redact
310
- send_event = true
311
- m = '[session_id]'
312
- elsif session_id_actions.log_hash
313
- send_event = true
314
- m = '[hash]'
315
- elsif session_id_actions.log_event
316
- send_event = true
317
- end
318
- m
319
- end
320
- if send_event
321
- TCellAgent.send_event(
322
- TCellAgent::SensorEvents::DlpEvent.new(
323
- tcell_context.route_id,
324
- tcell_context.uri,
325
- TCellAgent::SensorEvents::DlpEvent::FOUND_IN_LOG
326
- ).for_framework(TCellAgent::SensorEvents::DlpEvent::FRAMEWORK_VARIABLE_SESSION_ID)
327
- )
306
+ session_id_actions = get_actions_for_session_id
307
+ if tcell_context && tcell_context.session_id && session_id_actions
308
+ send_event = false
309
+ sanitize_string.gsub!(tcell_context.session_id) do |m|
310
+ if session_id_actions.log_redact
311
+ send_event = true
312
+ m = '[session_id]'
313
+ elsif session_id_actions.log_hash
314
+ send_event = true
315
+ m = '[hash]'
316
+ elsif session_id_actions.log_event
317
+ send_event = true
328
318
  end
319
+ m
320
+ end
321
+ if send_event
322
+ TCellAgent.send_event(
323
+ TCellAgent::SensorEvents::DlpEvent.new(
324
+ tcell_context.route_id,
325
+ tcell_context.uri,
326
+ TCellAgent::SensorEvents::DlpEvent::FOUND_IN_LOG
327
+ ).for_framework(TCellAgent::SensorEvents::DlpEvent::FRAMEWORK_VARIABLE_SESSION_ID)
328
+ )
329
329
  end
330
330
  end
331
331
  end
@@ -336,32 +336,32 @@ module TCellAgent
336
336
  def response_body_enforce(tcell_context, sanitize_string)
337
337
  if TCellAgent.configuration.should_instrument? &&
338
338
  TCellAgent.configuration.should_intercept_requests?
339
- if tcell_context && tcell_context.session_id
340
- session_id_actions = get_actions_for_session_id
341
- if session_id_actions
342
- send_event = false
343
- sanitize_string.gsub!(tcell_context.session_id) do |m|
344
- if session_id_actions.body_redact
345
- # m = "[session_id]"
346
- send_event = true
347
- elsif session_id_actions.body_hash
348
- # m = "[hash]"
349
- send_event = true
350
- elsif session_id_actions.body_event
351
- send_event = true
352
- end
353
- m
339
+ session_id_actions = get_actions_for_session_id
340
+ if tcell_context && tcell_context.session_id && session_id_actions
341
+ send_event = false
342
+ sanitize_string.gsub!(tcell_context.session_id) do |m|
343
+ # rubocop:disable Lint/DuplicateBranch
344
+ if session_id_actions.body_redact
345
+ # m = "[session_id]"
346
+ send_event = true
347
+ elsif session_id_actions.body_hash
348
+ # m = "[hash]"
349
+ send_event = true
350
+ elsif session_id_actions.body_event
351
+ send_event = true
354
352
  end
353
+ # rubocop:enable Lint/DuplicateBranch
354
+ m
355
355
  end
356
- if send_event
357
- TCellAgent.send_event(
358
- TCellAgent::SensorEvents::DlpEvent.new(
359
- tcell_context.route_id,
360
- tcell_context.uri,
361
- TCellAgent::SensorEvents::DlpEvent::FOUND_IN_BODY
362
- ).for_framework(TCellAgent::SensorEvents::DlpEvent::FRAMEWORK_VARIABLE_SESSION_ID)
363
- )
364
- end
356
+ end
357
+ if send_event
358
+ TCellAgent.send_event(
359
+ TCellAgent::SensorEvents::DlpEvent.new(
360
+ tcell_context.route_id,
361
+ tcell_context.uri,
362
+ TCellAgent::SensorEvents::DlpEvent::FOUND_IN_BODY
363
+ ).for_framework(TCellAgent::SensorEvents::DlpEvent::FRAMEWORK_VARIABLE_SESSION_ID)
364
+ )
365
365
  end
366
366
  end
367
367
 
@@ -39,19 +39,18 @@ module TCellAgent
39
39
 
40
40
  TCellAgent::Instrumentation.safe_block('DLP Handler get handler and context') do
41
41
  if TCellAgent.configuration.should_instrument? &&
42
- TCellAgent.configuration.should_intercept_requests?
42
+ TCellAgent.configuration.should_intercept_requests? &&
43
+ TCellAgent::Utils::Rails.processable_response?(response_headers)
43
44
 
44
45
  # do all this work so that dlp doesn't run at all unless it's on and there
45
46
  # are rules to run
46
- if TCellAgent::Utils::Rails.processable_response?(response_headers)
47
- dlp_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
48
- if dlp_policy && dlp_policy.get_actions_for_session_id
49
- tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
50
- if tcell_context && tcell_context.session_id
51
- dlp_handler = proc { |tc, resp|
52
- handle_dlp!(tc, resp)
53
- }
54
- end
47
+ dlp_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
48
+ if dlp_policy && dlp_policy.get_actions_for_session_id
49
+ tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
50
+ if tcell_context && tcell_context.session_id
51
+ dlp_handler = proc { |tc, resp|
52
+ handle_dlp!(tc, resp)
53
+ }
55
54
  end
56
55
  end
57
56
  end
@@ -4,8 +4,7 @@ module TCellAgent
4
4
  module Instrumentation
5
5
  module Rails
6
6
  module JSAgent
7
- HEAD_SEARCH_REGEX = /<head>/
8
-
7
+ HEAD_SEARCH_REGEX = Regexp.new('(<head>|<head( |\n).*?>)', Regexp::IGNORECASE)
9
8
  def self.insert_now(js_agent_handler, script_insert, rack_body, content_length)
10
9
  TCellAgent::Instrumentation.safe_block('Handling JSAgent Insert Now') do
11
10
  if js_agent_handler
@@ -32,7 +31,7 @@ module TCellAgent
32
31
  TCellAgent::Instrumentation.safe_block('Handling JSAgent insert') do
33
32
  new_response = response.sub(
34
33
  TCellAgent::Instrumentation::Rails::JSAgent::HEAD_SEARCH_REGEX,
35
- "<head>#{script_insert}"
34
+ "\\1#{script_insert}"
36
35
  )
37
36
  end
38
37
 
@@ -26,7 +26,8 @@ module TCellAgent
26
26
  env[TCellAgent::Instrumentation::TCELL_ID].path = request.path
27
27
  env[TCellAgent::Instrumentation::TCELL_ID].user_agent = request.user_agent
28
28
  env[TCellAgent::Instrumentation::TCELL_ID].referrer = request.referrer
29
- env[TCellAgent::Instrumentation::TCELL_ID].remote_address = TCellAgent::Utils::Rails.better_ip(request)
29
+ env[TCellAgent::Instrumentation::TCELL_ID].remote_address = request.ip
30
+ env[TCellAgent::Instrumentation::TCELL_ID].reverse_proxy_header_value = TCellAgent::Utils::Rails.reverse_proxy_header(request)
30
31
  if request.request_method
31
32
  env[TCellAgent::Instrumentation::TCELL_ID].request_method = request.request_method
32
33
  end
@@ -25,8 +25,6 @@ module TCellAgent
25
25
  if TCellAgent.configuration.should_intercept_requests?
26
26
  request = Rack::Request.new(env)
27
27
 
28
- request['init'] = true
29
-
30
28
  TCellAgent::Instrumentation.safe_block('Setting session_id & user_id') do
31
29
  if request.session
32
30
  env[TCellAgent::Instrumentation::TCELL_ID].session_id =
@@ -44,9 +42,7 @@ module TCellAgent
44
42
  end
45
43
  end
46
44
 
47
- response = @app.call(env)
48
-
49
- response
45
+ @app.call(env)
50
46
  end
51
47
  end
52
48
  end
@@ -39,6 +39,7 @@ module TCellAgent
39
39
  TCellAgent::Instrumentation.safe_block('Handling headers') do
40
40
  headers_policy = TCellAgent.policy(TCellAgent::PolicyTypes::HEADERS)
41
41
  policy_headers = headers_policy.get_headers(
42
+ headers['Content-Type'],
42
43
  request.env[TCellAgent::Instrumentation::TCELL_ID]
43
44
  )
44
45
  policy_headers.each do |header_info|
@@ -7,8 +7,9 @@ module TCellAgent
7
7
  begin
8
8
  return route.app < Grape::API if ::Rails::VERSION::MAJOR == 4 &&
9
9
  ::Rails::VERSION::MINOR < 2
10
+
10
11
  return route.app.app < Grape::API
11
- rescue StandardError # rubocop:disable Lint/HandleExceptions
12
+ rescue StandardError
12
13
  # do nothing
13
14
  end
14
15
  end
@@ -6,12 +6,9 @@ require 'tcell_agent/sensor_events/server_agent'
6
6
  module TCellAgent
7
7
  module Instrumentation
8
8
  module Rails
9
- def self.send_framework_info
10
- TCellAgent.send_event(
11
- TCellAgent::SensorEvents::ServerAgentAppFrameworkEvent.new(
12
- 'Rails', ::Rails.version
13
- )
14
- )
9
+ def self.framework_details
10
+ { 'app_framework' => 'Rails',
11
+ 'app_framework_version' => ::Rails.version }
15
12
  end
16
13
 
17
14
  def self.send_settings
@@ -53,18 +53,16 @@ module TCellAgent
53
53
  @body.respond_to?(method_name, include_all)
54
54
  end
55
55
 
56
- def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissing
56
+ def method_missing(method_name, *args, &block)
57
57
  @body.__send__(method_name, *args, &block)
58
58
  end
59
59
 
60
60
  def process_body(body)
61
61
  TCellAgent::Instrumentation.safe_block('Processing tcell body proxy body') do
62
62
  chunked_response_match = nil
63
- if body.class.name == 'String'
64
- if body =~ /^([[:xdigit:]]+)(;.+)?\r\n/
65
- chunked_response_match = Regexp.last_match(1)
66
- @content_length += chunked_response_match.to_i(16)
67
- end
63
+ if body.class.name == 'String' && body =~ /^([[:xdigit:]]+)(;.+)?\r\n/
64
+ chunked_response_match = Regexp.last_match(1)
65
+ @content_length += chunked_response_match.to_i(16)
68
66
  end
69
67
 
70
68
  new_body = body
@@ -2,6 +2,7 @@ module TCellAgent
2
2
  module Routes
3
3
  class FieldEndpoint
4
4
  attr_accessor :discovered
5
+
5
6
  def initialize
6
7
  super()
7
8
  @discovered = false
@@ -11,6 +12,7 @@ module TCellAgent
11
12
  class RouteEndpoint
12
13
  attr_accessor :database
13
14
  attr_accessor :database_queries_discovered
15
+
14
16
  def initialize
15
17
  @database_queries_discovered = {}
16
18
  @database = Hash.new do |d_h, d_k| # Database
@@ -27,6 +29,7 @@ module TCellAgent
27
29
 
28
30
  class RouteTable
29
31
  attr_accessor :routes
32
+
30
33
  def initialize
31
34
  @routes = Hash.new { |h, k| h[k] = RouteEndpoint.new }
32
35
  end
@@ -21,6 +21,21 @@ module TCellAgent
21
21
  self['overrides'] = { 'applications' => [{ :enable_json_body_inspection => true }],
22
22
  'config_file_path' => configuration.get_config_file_path }
23
23
  end
24
+
25
+ set_agent_details
26
+ end
27
+
28
+ def set_agent_details
29
+ framework_details = if defined?(Rails)
30
+ TCellAgent::Instrumentation::Rails.framework_details
31
+ else
32
+ {}
33
+ end
34
+
35
+ self['agent_details'] = { 'language' => 'Ruby',
36
+ 'language_version' => RUBY_VERSION,
37
+ 'app_framework' => framework_details['app_framework'],
38
+ 'app_framework_version' => framework_details['app_framework_version'] }
24
39
  end
25
40
  end
26
41
 
@@ -53,6 +68,9 @@ module TCellAgent
53
68
  self['log_enabled'] = configuration.logging_options[:enabled]
54
69
  self['log_filename'] = configuration.logging_options[:log_filename]
55
70
  self['log_level'] = configuration.logging_options[:level]
71
+ self['proxy_url'] = configuration.proxy_url
72
+ self['proxy_username'] = configuration.proxy_username
73
+ self['proxy_password'] = configuration.proxy_password
56
74
  self['update_policy'] = configuration.fetch_policies_from_tcell
57
75
  end
58
76
  end