contrast-agent 6.9.0 → 6.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/ext/build_funchook.rb +1 -1
  4. data/lib/contrast/agent/assess/policy/propagator/split.rb +1 -4
  5. data/lib/contrast/agent/assess/rule/response/body_rule.rb +1 -1
  6. data/lib/contrast/agent/middleware.rb +5 -3
  7. data/lib/contrast/agent/patching/policy/method_policy_extend.rb +6 -2
  8. data/lib/contrast/agent/patching/policy/trigger_node.rb +1 -1
  9. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +76 -83
  10. data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +40 -35
  11. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +2 -0
  12. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +6 -3
  13. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +5 -2
  14. data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +3 -0
  15. data/lib/contrast/agent/protect/policy/rule_applicator.rb +12 -0
  16. data/lib/contrast/agent/protect/rule/base.rb +19 -5
  17. data/lib/contrast/agent/protect/rule/base_service.rb +7 -2
  18. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +1 -1
  19. data/lib/contrast/agent/protect/rule/bot_blocker.rb +8 -0
  20. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +1 -1
  21. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +9 -1
  22. data/lib/contrast/agent/protect/rule/cmdi/cmdi_chained_command.rb +1 -1
  23. data/lib/contrast/agent/protect/rule/cmdi/cmdi_dangerous_path.rb +1 -1
  24. data/lib/contrast/agent/protect/rule/deserialization.rb +2 -2
  25. data/lib/contrast/agent/protect/rule/no_sqli.rb +24 -2
  26. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_input_classification.rb +1 -1
  27. data/lib/contrast/agent/protect/rule/path_traversal.rb +8 -0
  28. data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +0 -1
  29. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +0 -1
  30. data/lib/contrast/agent/protect/rule/sqli.rb +6 -10
  31. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +6 -2
  32. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +20 -0
  33. data/lib/contrast/agent/protect/rule/xss/reflected_xss_input_classification.rb +1 -1
  34. data/lib/contrast/agent/protect/rule/xss.rb +8 -0
  35. data/lib/contrast/agent/protect/rule/xxe.rb +2 -2
  36. data/lib/contrast/agent/protect/rule.rb +0 -3
  37. data/lib/contrast/agent/reporting/attack_result/user_input.rb +0 -1
  38. data/lib/contrast/agent/reporting/details/details.rb +0 -1
  39. data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +12 -0
  40. data/lib/contrast/agent/reporting/report.rb +1 -0
  41. data/lib/contrast/agent/reporting/reporter.rb +12 -15
  42. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +4 -5
  43. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +13 -1
  44. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +20 -5
  45. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +0 -1
  46. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +5 -0
  47. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +10 -1
  48. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +2 -1
  49. data/lib/contrast/agent/reporting/reporting_events/application_reporting_event.rb +10 -0
  50. data/lib/contrast/agent/reporting/reporting_events/application_settings.rb +40 -0
  51. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +9 -5
  52. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +8 -5
  53. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -7
  54. data/lib/contrast/agent/reporting/reporting_utilities/ng_response_extractor.rb +137 -0
  55. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +12 -4
  56. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +100 -107
  57. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +5 -4
  58. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +101 -67
  59. data/lib/contrast/agent/reporting/reporting_workers/application_server_worker.rb +46 -0
  60. data/lib/contrast/agent/reporting/reporting_workers/reporter_heartbeat.rb +51 -0
  61. data/lib/contrast/agent/reporting/reporting_workers/reporting_workers.rb +14 -0
  62. data/lib/contrast/agent/reporting/reporting_workers/server_settings_worker.rb +46 -0
  63. data/lib/contrast/agent/reporting/settings/assess.rb +14 -1
  64. data/lib/contrast/agent/reporting/settings/assess_rule.rb +18 -0
  65. data/lib/contrast/agent/reporting/settings/helpers.rb +4 -2
  66. data/lib/contrast/agent/reporting/settings/protect.rb +17 -12
  67. data/lib/contrast/agent/reporting/settings/protect_rule.rb +18 -0
  68. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +1 -1
  69. data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +1 -1
  70. data/lib/contrast/agent/reporting/settings/virtual_patch.rb +56 -0
  71. data/lib/contrast/agent/reporting/settings/virtual_patch_condition.rb +47 -0
  72. data/lib/contrast/agent/request_context_extend.rb +20 -0
  73. data/lib/contrast/agent/telemetry/base.rb +13 -15
  74. data/lib/contrast/agent/telemetry/events/exceptions/obfuscate.rb +108 -103
  75. data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +1 -1
  76. data/lib/contrast/agent/thread_watcher.rb +16 -10
  77. data/lib/contrast/agent/version.rb +1 -1
  78. data/lib/contrast/agent.rb +12 -0
  79. data/lib/contrast/agent_lib/api/init.rb +1 -7
  80. data/lib/contrast/agent_lib/api/input_tracing.rb +2 -4
  81. data/lib/contrast/agent_lib/interface.rb +1 -16
  82. data/lib/contrast/agent_lib/interface_base.rb +52 -39
  83. data/lib/contrast/agent_lib/return_types/eval_result.rb +2 -2
  84. data/lib/contrast/components/assess.rb +26 -4
  85. data/lib/contrast/components/config.rb +1 -1
  86. data/lib/contrast/components/polling.rb +4 -1
  87. data/lib/contrast/components/settings.rb +46 -3
  88. data/lib/contrast/config/config.rb +2 -2
  89. data/lib/contrast/config/protect_rule_configuration.rb +1 -1
  90. data/lib/contrast/config/protect_rules_configuration.rb +1 -1
  91. data/lib/contrast/extension/assess/array.rb +3 -3
  92. data/lib/contrast/extension/assess/regexp.rb +2 -2
  93. data/lib/contrast/framework/rack/patch/session_cookie.rb +2 -1
  94. data/lib/contrast/logger/aliased_logging.rb +48 -15
  95. data/lib/contrast/utils/duck_utils.rb +18 -0
  96. data/lib/contrast/utils/heap_dump_util.rb +1 -1
  97. data/lib/contrast/utils/input_classification_base.rb +21 -4
  98. data/lib/contrast/utils/log_utils.rb +1 -1
  99. data/lib/contrast/utils/middleware_utils.rb +1 -1
  100. data/lib/contrast/utils/patching/policy/patch_utils.rb +2 -2
  101. data/lib/contrast/utils/routes_sent.rb +6 -2
  102. data/lib/contrast/utils/telemetry.rb +2 -2
  103. data/lib/contrast/utils/telemetry_client.rb +1 -1
  104. data/resources/protect/policy.json +8 -0
  105. data/ruby-agent.gemspec +6 -6
  106. metadata +40 -30
  107. data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +0 -96
  108. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +0 -83
  109. data/lib/contrast/agent/reporting/details/http_method_tempering_details.rb +0 -27
  110. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +0 -47
  111. data/lib/contrast/agent/reporting/server_settings_worker.rb +0 -44
  112. data/lib/contrast/agent_lib/api/method_tempering.rb +0 -29
@@ -11,6 +11,7 @@ module Contrast
11
11
  # This is the new AttackerActivity class which will includes the attacker information discovered during this
12
12
  # activity period.
13
13
  class ApplicationDefendAttackerActivity
14
+ include Contrast::Components::Logger::InstanceMethods
14
15
  # @return [Hash<String,Contrast::Agent::Reporting::ApplicationDefendAttackActivity>] map of rule-id to violated
15
16
  # samples for that rule
16
17
  attr_accessor :protection_rules
@@ -32,8 +33,11 @@ module Contrast
32
33
  end
33
34
 
34
35
  def to_controlled_hash
36
+ processed_rules = process_protection_rules
37
+ validate(processed_rules)
38
+
35
39
  {
36
- protectionRules: process_protection_rules,
40
+ protectionRules: processed_rules,
37
41
  source: {
38
42
  ip: source_ip,
39
43
  xForwardedFor: source_forwarded_for
@@ -41,6 +45,11 @@ module Contrast
41
45
  }
42
46
  end
43
47
 
48
+ def validate processed_rules
49
+ raise(ArgumentError, 'Protection Rules are not presented') if processed_rules.empty?
50
+ raise(ArgumentError, 'Source is not presented') unless source_ip
51
+ end
52
+
44
53
  # @param attack_result [Contrast::Agent::Reporting::AttackResult]
45
54
  def attach_data attack_result
46
55
  @protection_rules[attack_result.rule_id] = Contrast::Agent::Reporting::ApplicationDefendAttackActivity.new.
@@ -22,7 +22,7 @@ module Contrast
22
22
  @event_method = :POST
23
23
  @event_endpoint = Contrast::Agent::Reporting::Endpoints.application_inventory
24
24
  # The API spec limits us to 500 routes, so we'll enforce that here to not hold on to superfulous data.
25
- @routes = Contrast::Agent.framework_manager.find_route_discovery_data.take(500)
25
+ @routes = Contrast::Agent.framework_manager.find_route_discovery_data&.take(500)
26
26
  super
27
27
  end
28
28
 
@@ -33,6 +33,7 @@ module Contrast
33
33
  def to_controlled_hash
34
34
  {
35
35
  session_id: ::Contrast::ASSESS.session_id,
36
+ # documentation lists routes as deprecated from the agent_ng_endpoints.yml
36
37
  routes: routes.map(&:to_controlled_hash)
37
38
  }
38
39
  end
@@ -17,10 +17,20 @@ module Contrast
17
17
  # The timestamp field is a bit of a misnomer. It's really the time, in ms, since the settings for this
18
18
  # application have been updated. If I've never updated, then it's been 0ms since then.
19
19
  #
20
+ #
20
21
  # @return [Integer]
21
22
  def since_last_update
22
23
  (update_time = Contrast::SETTINGS.last_app_update_ms) ? Contrast::Utils::Timer.now_ms - update_time : 0
23
24
  end
25
+
26
+ # Human readable last time update for header set. Set to 0 if the agent is just starting and have not received
27
+ # the latest header from TS.
28
+ #
29
+ #
30
+ # @return [String]
31
+ def since_last_update_httpdate
32
+ Contrast::SETTINGS.app_settings_last_httpdate || Contrast::Utils::Timer.ms_to_httpdate(0)
33
+ end
24
34
  end
25
35
  end
26
36
  end
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/agent/reporting/reporting_events/application_reporting_event'
5
+ require 'contrast/agent/reporting/reporting_utilities/endpoints'
6
+ require 'contrast/utils/timer'
7
+
8
+ module Contrast
9
+ module Agent
10
+ module Reporting
11
+ # This class will initialize a GET request to be send to TS. The application settings endpoint is the way
12
+ # the Agent receives application sittings
13
+ class ApplicationSettings < Contrast::Agent::Reporting::ApplicationReportingEvent
14
+ def initialize
15
+ @event_method = :GET
16
+ @event_endpoint = Contrast::Agent::Reporting::Endpoints.application_settings
17
+ super
18
+ end
19
+
20
+ def file_name
21
+ 'application-settings'
22
+ end
23
+
24
+ # Attach the last server settings received timestamp to the request as it is required.
25
+ #
26
+ # If-Modified-Since: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
27
+ # @param request [Net::HTTPRequest]
28
+ def attach_headers request
29
+ request['If-Modified-Since'] = since_last_update_httpdate
30
+ end
31
+
32
+ # @return [Hash]
33
+ # @raise [ArgumentError]
34
+ def to_controlled_hash
35
+ {}
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -5,6 +5,7 @@ require 'json'
5
5
  require 'contrast/components/logger'
6
6
  require 'contrast/agent/reporting/reporting_events/reporting_event'
7
7
  require 'contrast/utils/object_share'
8
+ require 'contrast/utils/duck_utils'
8
9
 
9
10
  module Contrast
10
11
  module Agent
@@ -16,9 +17,9 @@ module Contrast
16
17
  # includes the literal URL and HTTP Verb used to invoke them, as they must have been called at this point to be
17
18
  # recorded.
18
19
  class DiscoveredRoute < Contrast::Agent::Reporting::ObservedRoute
19
- include Contrast::Components::Logger::InstanceMethods
20
-
21
20
  class << self
21
+ include Contrast::Components::Logger::InstanceMethods
22
+
22
23
  # @param obj [Regexp, Object]
23
24
  # @return [String]
24
25
  def source_or_string obj
@@ -100,9 +101,7 @@ module Contrast
100
101
  def initialize
101
102
  super
102
103
  @event_type = :discovered_route
103
- @signature = Contrast::Utils::ObjectShare::EMPTY_STRING
104
104
  @verb = Contrast::Utils::ObjectShare::EMPTY_STRING
105
- @url = Contrast::Utils::ObjectShare::EMPTY_STRING
106
105
  end
107
106
 
108
107
  def to_controlled_hash
@@ -116,7 +115,12 @@ module Contrast
116
115
  end
117
116
 
118
117
  def validate
119
- raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.") unless signature
118
+ if Contrast::Utils::DuckUtils.empty_duck?(signature)
119
+ raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.")
120
+ end
121
+ if Contrast::Utils::DuckUtils.empty_duck?(url)
122
+ raise(ArgumentError, "#{ self } did not have a proper url. Unable to continue.")
123
+ end
120
124
 
121
125
  nil
122
126
  end
@@ -6,6 +6,7 @@ require 'json'
6
6
  require 'contrast/components/logger'
7
7
  require 'contrast/agent/reporting/reporting_events/application_reporting_event'
8
8
  require 'contrast/utils/object_share'
9
+ require 'contrast/utils/duck_utils'
9
10
 
10
11
  module Contrast
11
12
  module Agent
@@ -32,9 +33,7 @@ module Contrast
32
33
  def initialize
33
34
  @event_endpoint = Contrast::Agent::Reporting::Endpoints.observed_route
34
35
  @sources = []
35
- @signature = Contrast::Utils::ObjectShare::EMPTY_STRING
36
36
  @verb = Contrast::Utils::ObjectShare::EMPTY_STRING
37
- @url = Contrast::Utils::ObjectShare::EMPTY_STRING
38
37
  super()
39
38
  end
40
39
 
@@ -69,7 +68,7 @@ module Contrast
69
68
  # @return [String]
70
69
  #
71
70
  def hash_id
72
- hashable_data = to_controlled_hash.except(:session_id)
71
+ hashable_data = to_controlled_hash.reject { |key, _value| key == :session_id } # rubocop:disable Style/HashExcept
73
72
  hashable_data[:sources] = hashable_data[:sources].sort_by { |s| s[:name] }
74
73
 
75
74
  Digest::SHA2.new(256).hexdigest(hashable_data.to_s)
@@ -78,8 +77,12 @@ module Contrast
78
77
  # @raise [ArgumentError]
79
78
  def validate
80
79
  raise(ArgumentError, "#{ self } did not have a proper sources. Unable to continue.") if @sources.nil?
81
- raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.") unless signature
82
- raise(ArgumentError, "#{ self } did not have a proper url. Unable to continue.") unless url
80
+ if Contrast::Utils::DuckUtils.empty_duck?(signature)
81
+ raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.")
82
+ end
83
+ if Contrast::Utils::DuckUtils.empty_duck?(url)
84
+ raise(ArgumentError, "#{ self } did not have a proper url. Unable to continue.")
85
+ end
83
86
 
84
87
  nil
85
88
  end
@@ -89,7 +89,7 @@ module Contrast
89
89
  #
90
90
  # @return [String]
91
91
  def application_endpoint
92
- @_application_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/applications"\
92
+ @_application_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/applications" \
93
93
  "#{ server_path_segment }#{ application_path_segment }"
94
94
  end
95
95
 
@@ -97,7 +97,7 @@ module Contrast
97
97
  #
98
98
  # @return [String]
99
99
  def route_endpoint
100
- @_route_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/routes"\
100
+ @_route_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/routes" \
101
101
  "#{ server_path_segment }#{ application_path_segment }"
102
102
  end
103
103
 
@@ -105,7 +105,7 @@ module Contrast
105
105
  #
106
106
  # @return [String]
107
107
  def server_endpoint
108
- @_server_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/servers"\
108
+ @_server_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/servers" \
109
109
  "#{ server_path_segment }"
110
110
  end
111
111
 
@@ -113,7 +113,7 @@ module Contrast
113
113
  #
114
114
  # @return [String]
115
115
  def trace_endpoint
116
- @_trace_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/traces"\
116
+ @_trace_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/traces" \
117
117
  "#{ server_path_segment }#{ application_path_segment }"
118
118
  end
119
119
 
@@ -121,8 +121,8 @@ module Contrast
121
121
  #
122
122
  # @return [String]
123
123
  def server_path_segment
124
- @_server_path_segment ||= "/#{ Base64.urlsafe_encode64(server_host_name, padding: false) }"\
125
- "/#{ Base64.urlsafe_encode64(server_path, padding: false) }"\
124
+ @_server_path_segment ||= "/#{ Base64.urlsafe_encode64(server_host_name, padding: false) }" \
125
+ "/#{ Base64.urlsafe_encode64(server_path, padding: false) }" \
126
126
  "/#{ Base64.urlsafe_encode64(server_type, padding: false) }"
127
127
  end
128
128
 
@@ -130,7 +130,7 @@ module Contrast
130
130
  #
131
131
  # @return [String]
132
132
  def application_path_segment
133
- @_application_path_segment ||= "/#{ Base64.urlsafe_encode64(APP_LANGUAGE, padding: false) }"\
133
+ @_application_path_segment ||= "/#{ Base64.urlsafe_encode64(APP_LANGUAGE, padding: false) }" \
134
134
  "/#{ Base64.urlsafe_encode64(app_name, padding: false) }"
135
135
  end
136
136
 
@@ -0,0 +1,137 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ module Contrast
5
+ module Agent
6
+ module Reporting
7
+ # This module will hold the methods for TS response conversion to settings objects. It is used for those
8
+ # endpoints which have NG in their prefix.
9
+ module NgResponseExtractor
10
+ private
11
+
12
+ # @param response_data [Hash]
13
+ # @param res [Contrast::Agent::Reporting::Response]
14
+ def ng_extract_assess response_data, res
15
+ assessments = response_data[:settings][:assessment]
16
+ return unless assessments
17
+
18
+ res.application_settings.assess.session_id = assessments[:session_id]
19
+ disabled = assessments[:disabledRules]
20
+ return unless disabled
21
+
22
+ disabled.each do |rule_id|
23
+ rule_setting = Contrast::Agent::Reporting::Settings::AssessRule.new.tap { |setting| setting.enable = false }
24
+ res.application_settings.assess.rule_settings[rule_id] = rule_setting
25
+ end
26
+ end
27
+
28
+ # @param response_data [Hash]
29
+ # @param res [Contrast::Agent::Reporting::Response]
30
+ def ng_extract_protect response_data, res
31
+ protect = response_data[:settings][:defend]
32
+ return unless protect
33
+
34
+ res.application_settings.protect.protection_rules = protect[:protectionRules]
35
+ protect[:virtualPatches]&.each do |patch_json|
36
+ res.application_settings.protect.virtual_patches <<
37
+ Contrast::Agent::Reporting::Settings::VirtualPatch.new(patch_json)
38
+ end
39
+ end
40
+
41
+ # @param response_data [Hash]
42
+ # @param res [Contrast::Agent::Reporting::Response]
43
+ def ng_extract_exclusions response_data, res
44
+ exclusions = response_data[:settings][:exceptions]
45
+ return unless exclusions
46
+
47
+ res.application_settings.exclusions.code_exclusions = exclusions[:codeExceptions]
48
+ res.application_settings.exclusions.input_exclusions = exclusions[:inputExceptions]
49
+ res.application_settings.exclusions.url_exclusions = exclusions[:urlExceptions]
50
+ end
51
+
52
+ # The responses we receive for feature and settings from TS have different
53
+ # place to store these reactions: body.reactions vs body.settings.reactions.
54
+ #
55
+ # @param response_data [Hash]
56
+ # @param res [Contrast::Agent::Reporting::Response]
57
+ def ng_extract_reactions response_data, res
58
+ res.reactions = response_data[:settings][:reactions] if response_data[:settings]
59
+ res.reactions = response_data[:reactions] if response_data[:features]
60
+ end
61
+
62
+ # This method is universal and used for both ng endpoint of feature settings and the new
63
+ # Server settings endpoint. Used in both build_feature_settings and build_server_settings.
64
+ # Passing the ng_ flag determines the use of the endpoint and response used because some of
65
+ # the response fields are with different names or do not exist: [enabled vs enable]
66
+ #
67
+ # @param response_data [Hash]
68
+ # @param res [Contrast::Agent::Reporting::Response]
69
+ def ng_extract_assess_features response_data, res
70
+ assess = response_data[:features][:assessment]
71
+ return unless assess
72
+
73
+ res.server_features.assess.enabled = assess[:enabled]
74
+ res.server_features.assess.sampling = assess[:sampling]
75
+ res.server_features.assess.sanitizers = assess[:sanitizers]
76
+ res.server_features.assess.validators = assess[:validators]
77
+ end
78
+
79
+ # @param response_data [Hash]
80
+ # @param res [Contrast::Agent::Reporting::Response]
81
+ def ng_extract_protect_features response_data, res
82
+ protect = response_data[:features][:defend]
83
+ return unless protect
84
+
85
+ res.server_features.protect.enabled = protect[:enabled]
86
+ res.server_features.protect.bot_blocker.enable = protect[:'bot-blocker']
87
+ res.server_features.protect.bot_blocker.bots = protect[:botBlockers]
88
+ ng_extract_syslog(response_data, res)
89
+ end
90
+
91
+ # @param response_data [Hash]
92
+ # @param res [Contrast::Agent::Reporting::Response]
93
+ def ng_extract_syslog response_data, res
94
+ return unless (syslog = response_data[:features][:defend][:syslog])
95
+
96
+ res.server_features.protect.syslog.assign_array(syslog, ng_: true)
97
+ end
98
+
99
+ # @param response_data [Hash]
100
+ # @param res [Contrast::Agent::Reporting::Response]
101
+ def ng_extract_protect_lists response_data, res
102
+ protect = response_data[:features][:defend]
103
+ return unless protect
104
+
105
+ res.server_features.protect.ip_allowlist = protect[:ipAllowlist]
106
+ res.server_features.protect.ip_denylist = protect[:ipDenylist]
107
+ res.server_features.protect.log_enhancers = protect[:logEnhancers]
108
+ res.server_features.protect.ng_rule_definition_list(protect[:ruleDefinitionList])
109
+ end
110
+
111
+ # Here we extract the rules and state for the sensitive data masking policy
112
+ # received from TS.
113
+ #
114
+ # @param response_data [Hash]
115
+ # @param res [Contrast::Agent::Reporting::Response]
116
+ def ng_extract_sensitive_data_policy response_data, res
117
+ return unless (sensitive_data = response_data[:settings][:sensitive_data_masking_policy])
118
+
119
+ res.application_settings.sensitive_data_masking.mask_http_body = sensitive_data[:mask_http_body]
120
+ res.application_settings.sensitive_data_masking.mask_attack_vector = sensitive_data[:mask_attack_vector]
121
+ res.application_settings.sensitive_data_masking.build_rules_form_settings(sensitive_data[:rules])
122
+ end
123
+
124
+ # Here we extract the log settings received from TS.
125
+ #
126
+ # @param response_data [Hash]
127
+ # @param res [Contrast::Agent::Reporting::Response]
128
+ def ng_extract_log_settings response_data, res
129
+ return unless (log_level = response_data[:logLevel])
130
+
131
+ res.server_features.log_level = log_level
132
+ res.server_features.log_file = response_data[:logFile] if response_data[:logFile]
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -11,6 +11,7 @@ require 'contrast/agent/reporting/reporting_utilities/reporter_client_utils'
11
11
  require 'contrast/agent/reporting/reporting_utilities/endpoints'
12
12
  require 'contrast/agent/reporting/reporting_utilities/headers'
13
13
  require 'contrast/agent/reporting/reporting_events/server_settings'
14
+ require 'contrast/agent/reporting/reporting_events/application_settings'
14
15
  require 'contrast/config/diagnostics'
15
16
 
16
17
  module Contrast
@@ -25,8 +26,17 @@ module Contrast
25
26
  include Contrast::Agent::Reporting::ReporterClientUtils
26
27
  include Contrast::Agent::Reporting::ResponseHandlerUtils
27
28
  include Contrast::Components::Logger::InstanceMethods
29
+
30
+ # @return [Array<Class>] events that may result in configuration changes
31
+ RECORDABLE_EVENTS = [
32
+ Contrast::Agent::Reporting::ServerSettings,
33
+ Contrast::Agent::Reporting::ApplicationSettings,
34
+ Contrast::Agent::Reporting::AgentStartup,
35
+ Contrast::Agent::Reporting::ApplicationStartup
36
+ ].cs__freeze
28
37
  SERVICE_NAME = 'Reporter'
29
38
  REPORT_CONFIG_WHEN = %w[200 304].cs__freeze
39
+
30
40
  def initialize
31
41
  @headers = Contrast::Agent::Reporting::Headers.new
32
42
  super()
@@ -60,7 +70,7 @@ module Contrast
60
70
  def send_event event, connection
61
71
  return unless connection
62
72
 
63
- logger.debug('Preparing to send reporting event', event_class: event.cs__class)
73
+ logger.debug('[Reporter] Preparing to send reporting event', event_class: event.cs__class)
64
74
 
65
75
  request = build_request(event)
66
76
  response = connection.request(request)
@@ -97,9 +107,7 @@ module Contrast
97
107
  def record_configuration response, event
98
108
  return unless response
99
109
  return unless REPORT_CONFIG_WHEN.include?(response_handler.last_response_code)
100
- return unless event&.cs__class == Contrast::Agent::Reporting::ServerSettings ||
101
- event&.cs__class == Contrast::Agent::Reporting::AgentStartup ||
102
- event&.cs__class == Contrast::Agent::Reporting::ApplicationStartup
110
+ return unless RECORDABLE_EVENTS.include?(event&.cs__class)
103
111
 
104
112
  logger.info('[Reporter Diagnostics] last response code:', response_code: response_handler.last_response_code)
105
113
  diagnostics.write_to_file