tcell_agent 1.1.12 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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