tcell_agent 1.1.12 → 2.2.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.
Files changed (169) hide show
  1. checksums.yaml +5 -5
  2. data/bin/tcell_agent +45 -137
  3. data/lib/tcell_agent.rb +12 -14
  4. data/lib/tcell_agent/agent.rb +108 -97
  5. data/lib/tcell_agent/agent/route_manager.rb +0 -16
  6. data/lib/tcell_agent/agent/static_agent.rb +9 -30
  7. data/lib/tcell_agent/config_initializer.rb +66 -0
  8. data/lib/tcell_agent/configuration.rb +69 -345
  9. data/lib/tcell_agent/hooks/login_fraud.rb +30 -33
  10. data/lib/tcell_agent/instrument_servers.rb +23 -0
  11. data/lib/tcell_agent/instrumentation.rb +12 -10
  12. data/lib/tcell_agent/instrumentation/cmdi.rb +29 -25
  13. data/lib/tcell_agent/instrumentation/lfi.rb +84 -0
  14. data/lib/tcell_agent/instrumentation/monkey_patches/file.rb +25 -0
  15. data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +131 -0
  16. data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +102 -0
  17. data/lib/tcell_agent/logger.rb +49 -114
  18. data/lib/tcell_agent/patches.rb +6 -7
  19. data/lib/tcell_agent/policies/appfirewall_policy.rb +26 -0
  20. data/lib/tcell_agent/policies/command_injection_policy.rb +28 -0
  21. data/lib/tcell_agent/policies/dataloss_policy.rb +44 -44
  22. data/lib/tcell_agent/policies/headers_policy.rb +25 -0
  23. data/lib/tcell_agent/policies/http_redirect_policy.rb +13 -79
  24. data/lib/tcell_agent/policies/js_agent_policy.rb +27 -0
  25. data/lib/tcell_agent/policies/local_file_access.rb +28 -0
  26. data/lib/tcell_agent/policies/login_policy.rb +43 -0
  27. data/lib/tcell_agent/policies/patches_policy.rb +27 -0
  28. data/lib/tcell_agent/policies/policies_manager.rb +68 -0
  29. data/lib/tcell_agent/policies/policy_polling.rb +58 -0
  30. data/lib/tcell_agent/policies/policy_types.rb +14 -0
  31. data/lib/tcell_agent/policies/system_enablements.rb +27 -0
  32. data/lib/tcell_agent/rails/auth/authlogic.rb +46 -75
  33. data/lib/tcell_agent/rails/auth/authlogic_helper.rb +20 -0
  34. data/lib/tcell_agent/rails/auth/devise.rb +100 -105
  35. data/lib/tcell_agent/rails/auth/devise_helper.rb +29 -0
  36. data/lib/tcell_agent/rails/auth/doorkeeper.rb +62 -76
  37. data/lib/tcell_agent/{userinfo.rb → rails/auth/userinfo.rb} +0 -0
  38. data/lib/tcell_agent/rails/csrf_exception.rb +2 -10
  39. data/lib/tcell_agent/rails/dlp.rb +35 -23
  40. data/lib/tcell_agent/rails/dlp_handler.rb +1 -2
  41. data/lib/tcell_agent/rails/js_agent_insert.rb +12 -13
  42. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +4 -25
  43. data/lib/tcell_agent/rails/middleware/context_middleware.rb +2 -12
  44. data/lib/tcell_agent/rails/middleware/global_middleware.rb +1 -2
  45. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +14 -34
  46. data/lib/tcell_agent/{rails.rb → rails/railties/tcell_agent_railties.rb} +11 -16
  47. data/lib/tcell_agent/rails/railties/tcell_agent_unicorn_railties.rb +8 -0
  48. data/lib/tcell_agent/rails/routes.rb +10 -12
  49. data/lib/tcell_agent/rails/routes/grape.rb +4 -14
  50. data/lib/tcell_agent/rails/routes/route_id.rb +3 -1
  51. data/lib/tcell_agent/rails/settings_reporter.rb +23 -36
  52. data/lib/tcell_agent/rails/tcell_body_proxy.rb +5 -4
  53. data/lib/tcell_agent/rust/agent_config.rb +60 -0
  54. data/lib/tcell_agent/rust/{libtcellagent-alpine-1.3.2.so → libtcellagent-5.0.2.dylib} +0 -0
  55. data/lib/tcell_agent/rust/{libtcellagent-1.3.2.so → libtcellagent-5.0.2.so} +0 -0
  56. data/lib/tcell_agent/rust/libtcellagent-alpine-5.0.2.so +0 -0
  57. data/lib/tcell_agent/rust/models.rb +6 -52
  58. data/lib/tcell_agent/rust/native_agent.rb +549 -0
  59. data/lib/tcell_agent/rust/native_agent_response.rb +42 -0
  60. data/lib/tcell_agent/rust/native_library.rb +69 -0
  61. data/lib/tcell_agent/rust/tcellagent-5.0.2.dll +0 -0
  62. data/lib/tcell_agent/sensor_events/agent_setting_event.rb +12 -0
  63. data/lib/tcell_agent/sensor_events/{app_config.rb → app_config_setting_event.rb} +0 -6
  64. data/lib/tcell_agent/sensor_events/dlp.rb +2 -6
  65. data/lib/tcell_agent/sensor_events/sensor.rb +0 -62
  66. data/lib/tcell_agent/sensor_events/server_agent.rb +13 -18
  67. data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +0 -108
  68. data/lib/tcell_agent/sensor_events/util/utils.rb +0 -2
  69. data/lib/tcell_agent/servers/passenger.rb +1 -28
  70. data/lib/tcell_agent/servers/puma.rb +3 -21
  71. data/lib/tcell_agent/servers/rails_server.rb +1 -2
  72. data/lib/tcell_agent/servers/thin.rb +2 -2
  73. data/lib/tcell_agent/servers/unicorn.rb +19 -80
  74. data/lib/tcell_agent/servers/webrick.rb +1 -2
  75. data/lib/tcell_agent/settings_reporter.rb +11 -90
  76. data/lib/tcell_agent/sinatra.rb +14 -16
  77. data/lib/tcell_agent/tcell_context.rb +40 -14
  78. data/lib/tcell_agent/utils/headers.rb +14 -0
  79. data/lib/tcell_agent/version.rb +1 -1
  80. data/spec/lib/tcell_agent/configuration_spec.rb +55 -346
  81. data/spec/lib/tcell_agent/hooks/login_fraud_spec.rb +46 -173
  82. data/spec/lib/tcell_agent/instrumentation/cmdi/io_cmdi_spec.rb +504 -0
  83. data/spec/lib/tcell_agent/instrumentation/cmdi/kernel_cmdi_spec.rb +435 -0
  84. data/spec/lib/tcell_agent/instrumentation/cmdi_spec.rb +201 -0
  85. data/spec/lib/tcell_agent/instrumentation/lfi/file_lfi_spec.rb +326 -0
  86. data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +562 -0
  87. data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +264 -0
  88. data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +150 -0
  89. data/spec/lib/tcell_agent/patches_spec.rb +25 -43
  90. data/spec/lib/tcell_agent/policies/appfirewall_policy_spec.rb +183 -0
  91. data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +57 -0
  92. data/spec/lib/tcell_agent/policies/command_injection_policy_spec.rb +84 -773
  93. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +161 -0
  94. data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +9 -9
  95. data/spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb +243 -198
  96. data/spec/lib/tcell_agent/policies/js_agent_policy_spec.rb +75 -0
  97. data/spec/lib/tcell_agent/policies/login_policy_spec.rb +165 -33
  98. data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +84 -277
  99. data/spec/lib/tcell_agent/policies/policies_manager_spec.rb +104 -0
  100. data/spec/lib/tcell_agent/policies/policy_polling_spec.rb +6 -0
  101. data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +56 -0
  102. data/spec/lib/tcell_agent/rails/csrf_exception_spec.rb +9 -18
  103. data/spec/lib/tcell_agent/rails/js_agent_insert_spec.rb +13 -30
  104. data/spec/lib/tcell_agent/rails/logger_spec.rb +27 -7
  105. data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +17 -12
  106. data/spec/lib/tcell_agent/rails/routes/routes_spec.rb +14 -14
  107. data/spec/lib/tcell_agent/rust/agent_config_spec.rb +27 -0
  108. data/spec/lib/tcell_agent/sensor_events/util/sanitizer_utilities_spec.rb +0 -35
  109. data/spec/lib/tcell_agent/settings_reporter_spec.rb +56 -155
  110. data/spec/spec_helper.rb +1 -1
  111. data/spec/support/builders.rb +103 -0
  112. data/spec/support/force_logger_mocking.rb +38 -0
  113. data/spec/support/resources/lfi_sample_file.txt +2 -0
  114. data/spec/support/static_agent_overrides.rb +0 -15
  115. metadata +72 -83
  116. data/lib/tcell_agent/agent/event_processor.rb +0 -326
  117. data/lib/tcell_agent/agent/fork_pipe_manager.rb +0 -113
  118. data/lib/tcell_agent/agent/policy_manager.rb +0 -219
  119. data/lib/tcell_agent/agent/policy_types.rb +0 -30
  120. data/lib/tcell_agent/api.rb +0 -91
  121. data/lib/tcell_agent/appsensor/injections_reporter.rb +0 -24
  122. data/lib/tcell_agent/authlogic.rb +0 -26
  123. data/lib/tcell_agent/config/child_process_events.rb +0 -8
  124. data/lib/tcell_agent/config/unknown_options.rb +0 -123
  125. data/lib/tcell_agent/devise.rb +0 -35
  126. data/lib/tcell_agent/instrumentation/cmdi/backtick.rb +0 -10
  127. data/lib/tcell_agent/instrumentation/cmdi/exec.rb +0 -14
  128. data/lib/tcell_agent/instrumentation/cmdi/popen.rb +0 -28
  129. data/lib/tcell_agent/instrumentation/cmdi/spawn.rb +0 -11
  130. data/lib/tcell_agent/instrumentation/cmdi/system.rb +0 -11
  131. data/lib/tcell_agent/policies/http_tx_policy.rb +0 -60
  132. data/lib/tcell_agent/policies/login_fraud_policy.rb +0 -45
  133. data/lib/tcell_agent/policies/rust_policies.rb +0 -110
  134. data/lib/tcell_agent/rails/on_start.rb +0 -41
  135. data/lib/tcell_agent/rust/libtcellagent-1.3.2.dylib +0 -0
  136. data/lib/tcell_agent/rust/tcellagent-1.3.2.dll +0 -0
  137. data/lib/tcell_agent/rust/whisperer.rb +0 -308
  138. data/lib/tcell_agent/sensor_events/appsensor_event.rb +0 -52
  139. data/lib/tcell_agent/sensor_events/appsensor_meta_event.rb +0 -45
  140. data/lib/tcell_agent/sensor_events/command_injection.rb +0 -75
  141. data/lib/tcell_agent/sensor_events/honeytokens.rb +0 -16
  142. data/lib/tcell_agent/sensor_events/login_fraud.rb +0 -60
  143. data/lib/tcell_agent/sensor_events/metrics.rb +0 -123
  144. data/lib/tcell_agent/sensor_events/patches.rb +0 -21
  145. data/lib/tcell_agent/start_background_thread.rb +0 -55
  146. data/lib/tcell_agent/system_info.rb +0 -11
  147. data/lib/tcell_agent/utils/io.rb +0 -38
  148. data/lib/tcell_agent/utils/passwords.rb +0 -28
  149. data/lib/tcell_agent/utils/queue_with_timeout.rb +0 -142
  150. data/spec/lib/tcell_agent/agent/fork_pipe_manager_spec.rb +0 -100
  151. data/spec/lib/tcell_agent/agent/policy_manager_spec.rb +0 -535
  152. data/spec/lib/tcell_agent/agent/static_agent_spec.rb +0 -133
  153. data/spec/lib/tcell_agent/api/api_spec.rb +0 -39
  154. data/spec/lib/tcell_agent/appsensor/injections_reporter_spec.rb +0 -187
  155. data/spec/lib/tcell_agent/cmdi_spec.rb +0 -736
  156. data/spec/lib/tcell_agent/config/unknown_options_spec.rb +0 -213
  157. data/spec/lib/tcell_agent/instrumentation_spec.rb +0 -225
  158. data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +0 -517
  159. data/spec/lib/tcell_agent/policies/http_tx_policy_spec.rb +0 -22
  160. data/spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb +0 -293
  161. data/spec/lib/tcell_agent/rails/middleware/dlp_middleware_spec.rb +0 -198
  162. data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +0 -180
  163. data/spec/lib/tcell_agent/rails/middleware/redirect_middleware_spec.rb +0 -116
  164. data/spec/lib/tcell_agent/rust/models_spec.rb +0 -120
  165. data/spec/lib/tcell_agent/rust/whisperer_spec.rb +0 -704
  166. data/spec/lib/tcell_agent/sensor_events/appsensor_meta_event_spec.rb +0 -45
  167. data/spec/lib/tcell_agent/sensor_events/sessions_metric_spec.rb +0 -272
  168. data/spec/lib/tcell_agent/utils/bounded_queue_spec.rb +0 -52
  169. data/spec/lib/tcell_agent/utils/passwords_spec.rb +0 -143
@@ -5,15 +5,9 @@ module TCellAgent
5
5
  def self.grape_route?(route)
6
6
  if defined?(Grape::API)
7
7
  begin
8
- if ::Rails::VERSION::MAJOR == 4 && ::Rails::VERSION::MINOR < 2
9
- # does app inherit from Grape::API?
10
- route.app < Grape::API
11
- else
12
- # does app inherit from Grape::API?
13
- route.app.app < Grape::API
14
- end
15
-
16
- return true
8
+ return route.app < Grape::API if ::Rails::VERSION::MAJOR == 4 &&
9
+ ::Rails::VERSION::MINOR < 2
10
+ return route.app.app < Grape::API
17
11
  rescue StandardError # rubocop:disable Lint/HandleExceptions
18
12
  # do nothing
19
13
  end
@@ -76,10 +70,7 @@ module TCellAgent
76
70
  Grape::Endpoint.class_eval do
77
71
  alias_method :tcell_call!, :call!
78
72
  def call!(env)
79
- if TCellAgent.configuration.enabled &&
80
- TCellAgent.configuration.should_instrument? &&
81
- TCellAgent.configuration.should_intercept_requests?
82
-
73
+ if TCellAgent.configuration.should_intercept_requests?
83
74
  TCellAgent::Instrumentation.safe_block('Determining Rails Route ID') do
84
75
  tcell_context = env[TCellAgent::Instrumentation::TCELL_ID]
85
76
  if tcell_context && tcell_context.grape_mount_endpoint && respond_to?(:routes)
@@ -102,7 +93,6 @@ module TCellAgent
102
93
  tcell_call!(env)
103
94
  end
104
95
  end
105
-
106
96
  end
107
97
  end
108
98
  end
@@ -16,7 +16,9 @@ module TCellAgent
16
16
  tcell_context.grape_mount_endpoint = grape_mount_endpoint
17
17
 
18
18
  else
19
- tcell_context.route_id = TCellAgent::SensorEvents::Util.calculate_route_id(tcell_context.request_method, route_path)
19
+ tcell_context.route_id = TCellAgent::SensorEvents::Util.calculate_route_id(
20
+ tcell_context.request_method, route_path
21
+ )
20
22
  end
21
23
  end
22
24
  end
@@ -1,15 +1,12 @@
1
1
  require 'rails'
2
2
  require 'tcell_agent'
3
- require 'tcell_agent/sensor_events/app_config'
3
+ require 'tcell_agent/sensor_events/app_config_setting_event'
4
4
  require 'tcell_agent/sensor_events/server_agent'
5
- require 'tcell_agent/system_info'
6
5
 
7
6
  module TCellAgent
8
7
  module Instrumentation
9
8
  module Rails
10
9
  def self.send_framework_info
11
- return unless TCellAgent.configuration.exp_config_settings
12
-
13
10
  TCellAgent.send_event(
14
11
  TCellAgent::SensorEvents::ServerAgentAppFrameworkEvent.new(
15
12
  'Rails', ::Rails.version
@@ -17,44 +14,34 @@ module TCellAgent
17
14
  )
18
15
  end
19
16
 
20
- def self.send_language_info
21
- return unless TCellAgent.configuration.exp_config_settings
17
+ def self.send_settings
18
+ TCellAgent::Instrumentation.safe_block('Reporting Rails settings') do
19
+ rails_config = ::Rails.application.config
22
20
 
23
- language = TCellAgent::SystemInfo.get_language
24
- language_version = TCellAgent::SystemInfo.get_language_version
25
- TCellAgent.send_event(
26
- TCellAgent::SensorEvents::ServerAgentDetailsLanguageEvent.new(
27
- language, language_version
21
+ # Defaults to true
22
+ csrf_protection = rails_config.action_controller.allow_forgery_protection || true
23
+ TCellAgent.send_event(
24
+ TCellAgent::SensorEvents::AppConfigSettingEvent.new(
25
+ 'Rails', 'core', '', 'csrf_protection', csrf_protection
26
+ )
28
27
  )
29
- )
30
- end
31
28
 
32
- def self.send_settings(application)
33
- return unless TCellAgent.configuration.exp_config_settings
34
-
35
- # Defaults to true
36
- csrf_protection = application.config.action_controller.allow_forgery_protection || true
37
- TCellAgent.send_event(
38
- TCellAgent::SensorEvents::AppConfigSettingEvent.new(
39
- 'Rails', 'core', '', 'csrf_protection', csrf_protection
29
+ # Defaults to false if nil
30
+ mass_assignment_allowed = rails_config.action_controller.permit_all_parameters || false
31
+ TCellAgent.send_event(
32
+ TCellAgent::SensorEvents::AppConfigSettingEvent.new(
33
+ 'Rails', 'core', '', 'mass_assignment_allowed', mass_assignment_allowed
34
+ )
40
35
  )
41
- )
42
36
 
43
- # Defaults to false if nil
44
- mass_assignment_allowed = application.config.action_controller.permit_all_parameters || false
45
- TCellAgent.send_event(
46
- TCellAgent::SensorEvents::AppConfigSettingEvent.new(
47
- 'Rails', 'core', '', 'mass_assignment_allowed', mass_assignment_allowed
48
- )
49
- )
50
-
51
- # Defaults to never
52
- session_expire = application.config.session_options[:expire_after] || -1
53
- TCellAgent.send_event(
54
- TCellAgent::SensorEvents::AppConfigSettingEvent.new(
55
- 'Rails', 'session', '', 'timeout', session_expire
37
+ # Defaults to never
38
+ session_expire = rails_config.session_options[:expire_after] || -1
39
+ TCellAgent.send_event(
40
+ TCellAgent::SensorEvents::AppConfigSettingEvent.new(
41
+ 'Rails', 'session', '', 'timeout', session_expire
42
+ )
56
43
  )
57
- )
44
+ end
58
45
  end
59
46
  end
60
47
  end
@@ -4,7 +4,7 @@ module TCellAgent
4
4
  module Instrumentation
5
5
  module Rails
6
6
  class TCellBodyProxy
7
- attr_accessor :appsensor_meta_event
7
+ attr_accessor :meta_data
8
8
 
9
9
  # for specs
10
10
  attr_accessor :content_length
@@ -29,9 +29,10 @@ module TCellAgent
29
29
 
30
30
  def close
31
31
  TCellAgent::Instrumentation.safe_block('Running AppSensor deferred due to streaming') do
32
- if @appsensor_meta_event
33
- @appsensor_meta_event.meta_data.response_content_bytes_len = @content_length
34
- TCellAgent.send_event(@appsensor_meta_event)
32
+ if @meta_data
33
+ @meta_data.response_content_bytes_len = @content_length
34
+ appfirewall_policy = TCellAgent.policy(TCellAgent::PolicyTypes::APPSENSOR)
35
+ appfirewall_policy.check_appfirewall_injections(@meta_data)
35
36
  end
36
37
  end
37
38
 
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tcell_agent/version'
4
+ require 'tcell_agent/rust/models'
5
+
6
+ module TCellAgent
7
+ module Rust
8
+ class AgentConfig < Hash
9
+ def initialize(configuration)
10
+ self['agent_type'] = 'Ruby'
11
+ self['agent_version'] = TCellAgent::VERSION
12
+ self['default_cache_dir'] = File.join(Dir.getwd, 'tcell/cache')
13
+ self['default_config_file_dir'] = File.join(Dir.getwd, 'config')
14
+ self['default_log_dir'] = File.join(Dir.getwd, 'tcell/logs')
15
+ self['default_preload_policy_file_dir'] = Dir.getwd
16
+
17
+ if defined?(ConfigInitializer)
18
+ overrides = Models.clean_nils(AgentConfigOverrides.new(configuration))
19
+ self['overrides'] = overrides
20
+ else
21
+ self['overrides'] = { 'applications' => [{ :enable_json_body_inspection => true }],
22
+ 'config_file_dir' => configuration.get_config_file_dir }
23
+ end
24
+ end
25
+ end
26
+
27
+ class AgentConfigOverrides < Hash
28
+ def initialize(configuration)
29
+ applications = {
30
+ :allow_payloads => configuration.allow_payloads,
31
+ :api_key => configuration.api_key,
32
+ :app_id => configuration.app_id,
33
+ :enable_json_body_inspection => true,
34
+ :hmac_key => configuration.hmac_key,
35
+ :max_header_size => configuration.max_csp_header_bytes,
36
+ :password_hmac_key => configuration.password_hmac_key,
37
+ :reverse_proxy => configuration.reverse_proxy,
38
+ :reverse_proxy_ip_address_header => configuration.reverse_proxy_ip_address_header
39
+ }
40
+
41
+ self['api_url'] = configuration.tcell_api_url
42
+ self['applications'] = [Models.clean_nils(applications)]
43
+ self['config_file_dir'] = configuration.get_config_file_dir
44
+ self['disabled_instrumentation'] = configuration.disabled_instrumentation
45
+ self['enabled'] = configuration.enabled
46
+ self['host_identifier'] = configuration.host_identifier
47
+ self['input_url'] = configuration.tcell_input_url
48
+ self['instrument'] = configuration.instrument
49
+ self['js_agent_api_url'] = configuration.js_agent_api_base_url
50
+ self['js_agent_url'] = configuration.js_agent_url
51
+ self['log_destination'] = configuration.logging_options[:destination]
52
+ self['log_dir'] = configuration.log_dir
53
+ self['log_enabled'] = configuration.logging_options[:enabled]
54
+ self['log_filename'] = configuration.logging_options[:log_filename]
55
+ self['log_level'] = configuration.logging_options[:level]
56
+ self['update_policy'] = configuration.fetch_policies_from_tcell
57
+ end
58
+ end
59
+ end
60
+ end
@@ -14,59 +14,13 @@ module TCellAgent
14
14
  flattened_params
15
15
  end
16
16
 
17
- def self.create_request_response(appsensor_meta)
18
- post_params = convert_params(appsensor_meta.flattened_post_dict)
19
-
20
- request_response = {
21
- 'method' => appsensor_meta.method,
22
- 'status_code' => appsensor_meta.response_code.to_i,
23
- 'route_id' => appsensor_meta.route_id,
24
- 'path' => appsensor_meta.path,
25
- 'query_params' => convert_params(appsensor_meta.flattened_get_dict),
26
- 'post_params' => post_params,
27
- 'headers' => convert_params(appsensor_meta.flattened_headers_dict),
28
- 'cookies' => convert_params(appsensor_meta.flattened_cookie_dict),
29
- 'path_params' => convert_params(appsensor_meta.flattened_path_parameters),
30
- 'remote_address' => appsensor_meta.remote_address,
31
- 'full_uri' => appsensor_meta.location,
32
- 'session_id' => appsensor_meta.session_id,
33
- 'user_id' => appsensor_meta.user_id,
34
- 'user_agent' => appsensor_meta.user_agent,
35
- :content_type => appsensor_meta.content_type,
36
- :request_body => appsensor_meta.raw_request_body,
37
- 'request_bytes_length' => appsensor_meta.request_content_bytes_len,
38
- 'response_bytes_length' => appsensor_meta.response_content_bytes_len
39
- }
40
-
41
- if TCellAgent::Utils::Strings.present?(appsensor_meta.csrf_exception_name)
42
- request_response['csrf_exception'] = { 'exception_name' => appsensor_meta.csrf_exception_name }
43
- end
44
-
45
- if appsensor_meta.sql_exceptions
46
- request_response['sql_exceptions'] = appsensor_meta.sql_exceptions
47
- end
48
-
49
- if appsensor_meta.database_result_sizes
50
- request_response['database_result_sizes'] = appsensor_meta.database_result_sizes
17
+ def self.clean_nils(hash)
18
+ if hash.respond_to?(:compact!)
19
+ hash.compact!
20
+ else
21
+ hash.delete_if { |_, v| v.nil? }
51
22
  end
52
-
53
- request_response
54
- end
55
-
56
- def self.create_patches_request(appsensor_meta)
57
- post_params = convert_params(appsensor_meta.flattened_post_dict)
58
-
59
- {
60
- 'method' => appsensor_meta.method,
61
- 'path' => appsensor_meta.path,
62
- 'remote_address' => appsensor_meta.remote_address,
63
- 'request_bytes_length' => appsensor_meta.request_content_bytes_len,
64
- 'query_params' => convert_params(appsensor_meta.flattened_get_dict),
65
- 'post_params' => post_params,
66
- 'headers' => convert_params(appsensor_meta.flattened_headers_dict),
67
- 'cookies' => convert_params(appsensor_meta.flattened_cookie_dict),
68
- :content_type => appsensor_meta.content_type
69
- }
23
+ hash
70
24
  end
71
25
  end
72
26
  end
@@ -0,0 +1,549 @@
1
+ require 'json'
2
+ require 'tcell_agent/rust/agent_config'
3
+ require 'tcell_agent/rust/models'
4
+ require 'tcell_agent/rust/native_library'
5
+ require 'tcell_agent/rust/native_agent_response'
6
+ require 'tcell_agent/version'
7
+
8
+ require 'tcell_agent/utils/headers'
9
+ module TCellAgent
10
+ module Rust
11
+ class NativeAgent # rubocop:disable Metrics/ClassLength
12
+ def self.test_event_sender(events)
13
+ config = TCellAgent.configuration
14
+ event_sender = {
15
+ :uuid => config.uuid,
16
+ :hostname => config.host_identifier,
17
+ :agent_type => 'Ruby',
18
+ :agent_version => TCellAgent::VERSION,
19
+ :app_id => config.app_id,
20
+ :api_key => config.api_key,
21
+ :tcell_input_url => config.tcell_input_url,
22
+ :events => events
23
+ }
24
+ event_sender_pointer = FFI::MemoryPointer.from_string(
25
+ JSON.dump(event_sender)
26
+ )
27
+
28
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
29
+ # config_pointer.size - 1: strips null terminator
30
+ result_size = TCellAgent::Rust::NativeLibrary.test_event_sender(
31
+ event_sender_pointer, event_sender_pointer.size - 1, buf, buf.size
32
+ )
33
+
34
+ response = NativeAgentResponse.new('test_event_sender', buf, result_size)
35
+
36
+ response.errors
37
+ end
38
+
39
+ def self.test_policies
40
+ config = TCellAgent.configuration
41
+ policies_info = {
42
+ :app_id => config.app_id,
43
+ :api_key => config.api_key,
44
+ :tcell_api_url => config.tcell_api_url
45
+ }
46
+ policies_info_pointer = FFI::MemoryPointer.from_string(
47
+ JSON.dump(policies_info)
48
+ )
49
+
50
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
51
+ # config_pointer.size - 1: strips null terminator
52
+ result_size = TCellAgent::Rust::NativeLibrary.test_policies(
53
+ policies_info_pointer, policies_info_pointer.size - 1, buf, buf.size
54
+ )
55
+
56
+ response = NativeAgentResponse.new('test_event_sender', buf, result_size)
57
+
58
+ response.errors
59
+ end
60
+
61
+ def self.test_agent(config)
62
+ agent_config = TCellAgent::Rust::AgentConfig.new(config)
63
+
64
+ config_pointer = FFI::MemoryPointer.from_string(
65
+ JSON.dump(agent_config)
66
+ )
67
+
68
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
69
+ # config_pointer.size - 1: strips null terminator
70
+ TCellAgent::Rust::NativeLibrary.test_agent(
71
+ config_pointer, config_pointer.size - 1, buf, buf.size
72
+ )
73
+ end
74
+
75
+ def self.free_agent(agent_ptr)
76
+ if TCellAgent::Rust::NativeLibrary.common_lib_available? &&
77
+ agent_ptr
78
+ TCellAgent::Rust::NativeLibrary.free_agent(
79
+ FFI::Pointer.new(agent_ptr)
80
+ )
81
+ end
82
+ end
83
+
84
+ def self.create_agent(config)
85
+ return nil unless TCellAgent::Rust::NativeLibrary.common_lib_available?
86
+
87
+ agent_config = TCellAgent::Rust::AgentConfig.new(config)
88
+ config_pointer = FFI::MemoryPointer.from_string(
89
+ JSON.dump(agent_config)
90
+ )
91
+
92
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
93
+ # config_pointer.size - 1: strips null terminator
94
+ result_size = TCellAgent::Rust::NativeLibrary.create_agent(
95
+ config_pointer, config_pointer.size - 1, buf, buf.size
96
+ )
97
+
98
+ response = JSON.parse(buf.get_string(0, result_size))
99
+ if response['error']
100
+ logger = TCellAgent::ModuleLogger.new(TCellAgent::RubyLogger.new, name)
101
+ logger.error("Error creating native agent: #{response['error']}")
102
+ return nil
103
+ end
104
+
105
+ return unless response['config'] && response['agent_enabled']
106
+
107
+ TCellAgent.configuration.populate_configuration(response['config'])
108
+ NativeAgent.new(response['agent_ptr'])
109
+ end
110
+
111
+ attr_reader :agent_ptr
112
+
113
+ def initialize(agent_ptr)
114
+ @agent_ptr = agent_ptr
115
+ end
116
+
117
+ def apply_appfirewall(appsensor_meta)
118
+ return {} unless appsensor_meta
119
+
120
+ post_params = Models.convert_params(appsensor_meta.flattened_post_dict)
121
+ query_params = Models.convert_params(appsensor_meta.flattened_get_dict)
122
+ header_params = Models.convert_params(appsensor_meta.flattened_headers_dict)
123
+ cookie_params = Models.convert_params(appsensor_meta.flattened_cookie_dict)
124
+ path_params = Models.convert_params(appsensor_meta.flattened_path_parameters)
125
+
126
+ request_response_json = {
127
+ :method => appsensor_meta.method,
128
+ :status_code => appsensor_meta.response_code.to_i,
129
+ :route_id => appsensor_meta.route_id,
130
+ :path => appsensor_meta.path,
131
+ :query_params => query_params,
132
+ :post_params => post_params,
133
+ :headers => header_params,
134
+ :cookies => cookie_params,
135
+ :path_params => path_params,
136
+ :remote_address => appsensor_meta.remote_address,
137
+ :full_uri => appsensor_meta.location,
138
+ :session_id => appsensor_meta.session_id,
139
+ :user_id => appsensor_meta.user_id,
140
+ :user_agent => appsensor_meta.user_agent,
141
+ :request_bytes_length => appsensor_meta.request_content_bytes_len,
142
+ :response_bytes_length => appsensor_meta.response_content_bytes_len,
143
+ :content_type => appsensor_meta.content_type,
144
+ :request_body => appsensor_meta.raw_request_body
145
+ }
146
+
147
+ request_response_json[:sql_exceptions] = appsensor_meta.sql_exceptions if appsensor_meta.sql_exceptions
148
+ request_response_json[:database_result_sizes] = appsensor_meta.database_result_sizes if appsensor_meta.database_result_sizes
149
+
150
+ if TCellAgent::Utils::Strings.present?(appsensor_meta.csrf_exception_name)
151
+ request_response_json[:csrf_exception] = {
152
+ :exception_name => appsensor_meta.csrf_exception_name
153
+ }
154
+ end
155
+
156
+ request_response_pointer = FFI::MemoryPointer.from_string(
157
+ JSON.dump(request_response_json)
158
+ )
159
+
160
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
161
+ # request_response_pointer.size - 1: strips null terminator
162
+ result_size = TCellAgent::Rust::NativeLibrary.appfirewall_apply(
163
+ FFI::Pointer.new(@agent_ptr),
164
+ request_response_pointer,
165
+ request_response_pointer.size - 1,
166
+ buf,
167
+ buf.size
168
+ )
169
+
170
+ response = NativeAgentResponse.new('apply_appfirewall', buf, result_size)
171
+ log_response_errors(response.errors)
172
+ response.response
173
+ end
174
+
175
+ def apply_patches(appsensor_meta)
176
+ return {} unless appsensor_meta
177
+
178
+ post_params = Models.convert_params(appsensor_meta.flattened_post_dict)
179
+ query_params = Models.convert_params(appsensor_meta.flattened_get_dict)
180
+ header_params = Models.convert_params(appsensor_meta.flattened_headers_dict)
181
+ cookie_params = Models.convert_params(appsensor_meta.flattened_cookie_dict)
182
+
183
+ patches_request_json = {
184
+ :method => appsensor_meta.method,
185
+ :path => appsensor_meta.path,
186
+ :remote_address => appsensor_meta.remote_address,
187
+ :request_bytes_length => appsensor_meta.request_content_bytes_len,
188
+ :query_params => query_params,
189
+ :post_params => post_params,
190
+ :headers => header_params,
191
+ :cookies => cookie_params,
192
+ :content_type => appsensor_meta.content_type,
193
+ :full_uri => appsensor_meta.location
194
+ }
195
+
196
+ patches_request_pointer = FFI::MemoryPointer.from_string(
197
+ JSON.dump(patches_request_json)
198
+ )
199
+
200
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
201
+ # patches_request_pointer.size - 1: strips null terminator
202
+ result_size = TCellAgent::Rust::NativeLibrary.patches_apply(
203
+ FFI::Pointer.new(@agent_ptr),
204
+ patches_request_pointer,
205
+ patches_request_pointer.size - 1,
206
+ buf,
207
+ buf.size
208
+ )
209
+
210
+ response = NativeAgentResponse.new('apply_patches', buf, result_size)
211
+ log_response_errors(response.errors)
212
+
213
+ response.response
214
+ end
215
+
216
+ def apply_cmdi(command, tcell_context)
217
+ return unless TCellAgent::Utils::Strings.present?(command)
218
+
219
+ command_info = {
220
+ :command => command,
221
+ :method => tcell_context.request_method,
222
+ :path => tcell_context.path,
223
+ :remote_address => tcell_context.remote_address,
224
+ :route_id => tcell_context.route_id,
225
+ :session_id => tcell_context.session_id,
226
+ :user_id => tcell_context.user_id,
227
+ :full_uri => tcell_context.uri
228
+ }
229
+
230
+ command_pointer = FFI::MemoryPointer.from_string(
231
+ JSON.dump(command_info)
232
+ )
233
+
234
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
235
+ # command_pointer.size - 1: strips null terminator
236
+ result_size = TCellAgent::Rust::NativeLibrary.cmdi_apply(
237
+ FFI::Pointer.new(@agent_ptr),
238
+ command_pointer,
239
+ command_pointer.size - 1,
240
+ buf,
241
+ buf.size
242
+ )
243
+
244
+ response = NativeAgentResponse.new('apply_cmdi', buf, result_size)
245
+ log_response_errors(response.errors)
246
+
247
+ response.response
248
+ end
249
+
250
+ def get_headers(tcell_context)
251
+ return unless tcell_context
252
+
253
+ headers_request = {
254
+ :method => tcell_context.request_method,
255
+ :path => tcell_context.path,
256
+ :route_id => tcell_context.route_id.to_s,
257
+ :session_id => tcell_context.session_id.to_s
258
+ }
259
+ headers_request_pointer = FFI::MemoryPointer.from_string(
260
+ JSON.dump(headers_request)
261
+ )
262
+
263
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 16)
264
+ # headers_request_pointer.size - 1: strips null terminator
265
+ result_size = TCellAgent::Rust::NativeLibrary.get_headers(
266
+ FFI::Pointer.new(@agent_ptr),
267
+ headers_request_pointer,
268
+ headers_request_pointer.size - 1,
269
+ buf,
270
+ buf.size
271
+ )
272
+
273
+ response = NativeAgentResponse.new('get_headers', buf, result_size)
274
+ log_response_errors(response.errors)
275
+
276
+ response.response
277
+ end
278
+
279
+ def check_http_redirect(location_header,
280
+ from_domain,
281
+ status_code,
282
+ tcell_context)
283
+ return {} unless tcell_context
284
+
285
+ http_redirect_request = {
286
+ :location_header => location_header,
287
+ :local_server => from_domain,
288
+ :status_code => status_code,
289
+ :method => tcell_context.request_method,
290
+ :path => tcell_context.path,
291
+ :remote_addr => tcell_context.remote_address,
292
+ :full_uri => tcell_context.fullpath,
293
+ :route_id => tcell_context.route_id,
294
+ :session_id => tcell_context.session_id,
295
+ :user_id => tcell_context.user_id
296
+ }
297
+ http_redirect_request_pointer = FFI::MemoryPointer.from_string(
298
+ JSON.dump(http_redirect_request)
299
+ )
300
+
301
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
302
+ # http_redirect_request_pointer.size - 1: strips null terminator
303
+ result_size = TCellAgent::Rust::NativeLibrary.check_http_redirect(
304
+ FFI::Pointer.new(@agent_ptr),
305
+ http_redirect_request_pointer,
306
+ http_redirect_request_pointer.size - 1,
307
+ buf,
308
+ buf.size
309
+ )
310
+
311
+ response = NativeAgentResponse.new('check_http_redirect', buf, result_size)
312
+ log_response_errors(response.errors)
313
+
314
+ response.response
315
+ end
316
+
317
+ def get_js_agent_script_tag(tcell_context)
318
+ return {} unless tcell_context
319
+
320
+ jsagent_request = {
321
+ :method => tcell_context.request_method,
322
+ :path => tcell_context.path
323
+ }
324
+ jsagent_request_pointer = FFI::MemoryPointer.from_string(
325
+ JSON.dump(jsagent_request)
326
+ )
327
+
328
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
329
+ # jsagent_request_pointer.size - 1: strips null terminator
330
+ result_size = TCellAgent::Rust::NativeLibrary.get_js_agent_script_tag(
331
+ FFI::Pointer.new(@agent_ptr),
332
+ jsagent_request_pointer,
333
+ jsagent_request_pointer.size - 1,
334
+ buf,
335
+ buf.size
336
+ )
337
+
338
+ response = NativeAgentResponse.new('get_js_agent_script_tag', buf, result_size)
339
+ log_response_errors(response.errors)
340
+
341
+ response.response
342
+ end
343
+
344
+ def login_fraud_apply(success,
345
+ user_id,
346
+ password,
347
+ headers,
348
+ user_valid,
349
+ tcell_context)
350
+ event_name = success ? :Success : :Failure
351
+ header_keys = TCellAgent::Utils::Headers.clean_keys(headers)
352
+ login_info = {
353
+ :event_name => event_name,
354
+ :user_id => user_id,
355
+ :user_agent => tcell_context.user_agent,
356
+ :remote_address => tcell_context.remote_address,
357
+ :header_keys => header_keys,
358
+ :passsword => password,
359
+ :session_id => tcell_context.session_id,
360
+ :full_uri => tcell_context.fullpath,
361
+ :referrer => tcell_context.referrer,
362
+ :user_valid => user_valid
363
+ }
364
+
365
+ login_info_pointer = FFI::MemoryPointer.from_string(
366
+ JSON.dump(login_info)
367
+ )
368
+
369
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
370
+ # login_info_pointer.size - 1: strips null terminator
371
+ result_size = TCellAgent::Rust::NativeLibrary.login_fraud_apply(
372
+ FFI::Pointer.new(@agent_ptr),
373
+ login_info_pointer,
374
+ login_info_pointer.size - 1,
375
+ buf,
376
+ buf.size
377
+ )
378
+
379
+ response = NativeAgentResponse.new('login_fraud_apply', buf, result_size)
380
+ log_response_errors(response.errors)
381
+
382
+ response.response
383
+ end
384
+
385
+ def file_access_apply(file_path,
386
+ mode,
387
+ tcell_context)
388
+
389
+ file_access_info = {
390
+ :dir_classification => 'Unknown',
391
+ :file_path => file_path,
392
+ :mode => mode
393
+ }
394
+
395
+ if tcell_context
396
+ file_access_info = file_access_info.merge(
397
+ {
398
+ :full_uri => tcell_context.fullpath,
399
+ :remote_address => tcell_context.remote_address,
400
+ :route_id => tcell_context.route_id,
401
+ :session_id => tcell_context.session_id,
402
+ :user_id => tcell_context.user_id
403
+ }
404
+ )
405
+ end
406
+
407
+ file_access_pointer = FFI::MemoryPointer.from_string(
408
+ JSON.dump(file_access_info)
409
+ )
410
+
411
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
412
+ # login_info_pointer.size - 1: strips null terminator
413
+ result_size = TCellAgent::Rust::NativeLibrary.file_access_apply(
414
+ FFI::Pointer.new(@agent_ptr),
415
+ file_access_pointer,
416
+ file_access_pointer.size - 1,
417
+ buf,
418
+ buf.size
419
+ )
420
+
421
+ response = NativeAgentResponse.new('file_access_apply', buf, result_size)
422
+ log_response_errors(response.errors)
423
+
424
+ response.response
425
+ end
426
+
427
+ def poll_new_policies
428
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 32)
429
+ result_size = TCellAgent::Rust::NativeLibrary.poll_new_policies(
430
+ FFI::Pointer.new(@agent_ptr),
431
+ buf,
432
+ buf.size
433
+ )
434
+
435
+ response = NativeAgentResponse.new('poll_new_policies', buf, result_size)
436
+ log_response_errors(response.errors)
437
+
438
+ response.response
439
+ end
440
+
441
+ def send_sanitized_events(events)
442
+ return {} unless events
443
+
444
+ events = { :events => events }
445
+ events_pointer = FFI::MemoryPointer.from_string(
446
+ JSON.dump(events)
447
+ )
448
+
449
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
450
+ # events_pointer.size - 1: strips null terminator
451
+ result_size = TCellAgent::Rust::NativeLibrary.send_sanitized_events(
452
+ FFI::Pointer.new(@agent_ptr),
453
+ events_pointer,
454
+ events_pointer.size - 1,
455
+ buf,
456
+ buf.size
457
+ )
458
+
459
+ response = NativeAgentResponse.new('send_sanitized_events', buf, result_size)
460
+ log_response_errors(response.errors)
461
+
462
+ response.response
463
+ end
464
+
465
+ def report_metrics(request_time, tcell_context)
466
+ return {} unless request_time
467
+
468
+ message = {
469
+ :elapsed_time => request_time,
470
+ :route_id => tcell_context && tcell_context.route_id,
471
+ :session_id => tcell_context && tcell_context.session_id,
472
+ :user_id => tcell_context && tcell_context.user_id,
473
+ :user_agent => tcell_context && tcell_context.user_agent,
474
+ :remote_address => tcell_context && tcell_context.remote_address
475
+ }
476
+ message_pointer = FFI::MemoryPointer.from_string(
477
+ JSON.dump(message)
478
+ )
479
+
480
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
481
+ # message_pointer.size - 1: strips null terminator
482
+ result_size = TCellAgent::Rust::NativeLibrary.report_metrics(
483
+ FFI::Pointer.new(@agent_ptr),
484
+ message_pointer,
485
+ message_pointer.size - 1,
486
+ buf,
487
+ buf.size
488
+ )
489
+
490
+ response = NativeAgentResponse.new('report_metrics', buf, result_size)
491
+ log_response_errors(response.errors)
492
+
493
+ response.response
494
+ end
495
+
496
+ def log_message(level, message, thread)
497
+ return unless level && message
498
+
499
+ message_json = {
500
+ :level => level,
501
+ :message => message,
502
+ :thread => thread
503
+ }
504
+ message_json_pointer = FFI::MemoryPointer.from_string(
505
+ JSON.dump(message_json)
506
+ )
507
+
508
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
509
+ # message_json_pointer.size - 1: strips null terminator
510
+ TCellAgent::Rust::NativeLibrary.log_message(
511
+ FFI::Pointer.new(@agent_ptr),
512
+ message_json_pointer,
513
+ message_json_pointer.size - 1,
514
+ buf,
515
+ buf.size
516
+ )
517
+ end
518
+
519
+ def log_response_errors(errors)
520
+ errors.each do |error|
521
+ log_message('error', error, self.class.name)
522
+ end
523
+ end
524
+
525
+ # Note: for tests
526
+ def update_policies(policies)
527
+ return {} unless TCellAgent::Utils::Strings.present?(policies)
528
+
529
+ policies_pointer = FFI::MemoryPointer.from_string(
530
+ JSON.dump(policies)
531
+ )
532
+
533
+ buf = FFI::MemoryPointer.new(:uint8, 1024 * 8)
534
+ # policies_pointer.size - 1: strips null terminator
535
+ result_size = TCellAgent::Rust::NativeLibrary.update_policies(
536
+ FFI::Pointer.new(agent_ptr),
537
+ policies_pointer,
538
+ policies_pointer.size - 1,
539
+ buf,
540
+ buf.size
541
+ )
542
+
543
+ NativeAgentResponse.new(
544
+ 'update_policies', buf, result_size
545
+ ).response
546
+ end
547
+ end
548
+ end
549
+ end