contrast-agent 7.0.0 → 7.1.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/contrast/agent/assess/policy/policy.rb +1 -1
  3. data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
  4. data/lib/contrast/agent/patching/policy/policy.rb +2 -2
  5. data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +3 -0
  6. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb +1 -1
  7. data/lib/contrast/agent/reporting/reporter.rb +19 -4
  8. data/lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb +32 -0
  9. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -0
  10. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +3 -1
  11. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +11 -7
  12. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +15 -7
  13. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +2 -1
  14. data/lib/contrast/agent/reporting/reporting_workers/application_server_worker.rb +3 -0
  15. data/lib/contrast/agent/reporting/reporting_workers/reporter_heartbeat.rb +3 -0
  16. data/lib/contrast/agent/reporting/reporting_workers/server_settings_worker.rb +3 -0
  17. data/lib/contrast/agent/telemetry/base.rb +37 -12
  18. data/lib/contrast/agent/telemetry/client.rb +1 -3
  19. data/lib/contrast/agent/telemetry/telemetry.rb +0 -7
  20. data/lib/contrast/agent/thread/thread_watcher.rb +2 -2
  21. data/lib/contrast/agent/version.rb +1 -1
  22. data/lib/contrast/components/agent.rb +1 -1
  23. data/lib/contrast/components/api.rb +2 -2
  24. data/lib/contrast/components/app_context.rb +1 -1
  25. data/lib/contrast/components/assess.rb +1 -1
  26. data/lib/contrast/components/assess_rules.rb +1 -1
  27. data/lib/contrast/components/base.rb +3 -3
  28. data/lib/contrast/components/config/sources.rb +12 -9
  29. data/lib/contrast/components/config.rb +2 -2
  30. data/lib/contrast/components/protect.rb +2 -2
  31. data/lib/contrast/components/sampling.rb +6 -4
  32. data/lib/contrast/components/settings.rb +1 -1
  33. data/lib/contrast/config/certification_configuration.rb +1 -1
  34. data/lib/contrast/config/configuration_files.rb +47 -0
  35. data/lib/contrast/config/diagnostics/command_line.rb +24 -0
  36. data/lib/contrast/config/{config.rb → diagnostics/config.rb} +21 -6
  37. data/lib/contrast/config/diagnostics/contrast_ui.rb +24 -0
  38. data/lib/contrast/config/diagnostics/effective_config.rb +28 -0
  39. data/lib/contrast/config/diagnostics/effective_config_value.rb +14 -0
  40. data/lib/contrast/config/diagnostics/environment_variables.rb +51 -0
  41. data/lib/contrast/config/{diagnostics.rb → diagnostics/monitor.rb} +10 -10
  42. data/lib/contrast/config/diagnostics/source_config_value.rb +51 -0
  43. data/lib/contrast/config/diagnostics/tools.rb +188 -0
  44. data/lib/contrast/config/diagnostics/user_configuration_file.rb +44 -0
  45. data/lib/contrast/config/request_audit_configuration.rb +1 -1
  46. data/lib/contrast/config/server_configuration.rb +1 -1
  47. data/lib/contrast/configuration.rb +90 -57
  48. data/lib/contrast/utils/hash_utils.rb +43 -0
  49. data/lib/contrast/utils/json.rb +46 -0
  50. data/lib/contrast/utils/net_http_base.rb +75 -26
  51. metadata +16 -7
  52. data/lib/contrast/config/diagnostics_tools.rb +0 -99
  53. data/lib/contrast/config/effective_config.rb +0 -131
  54. data/lib/contrast/config/effective_config_value.rb +0 -32
@@ -0,0 +1,44 @@
1
+ # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/config/diagnostics/effective_config_value'
5
+ require 'contrast/config/diagnostics/tools'
6
+ require 'contrast/utils/object_share'
7
+
8
+ module Contrast
9
+ module Config
10
+ module Diagnostics
11
+ # Reads all config files
12
+ class UserConfigurationFile
13
+ # Returns all source values from all configuration files read from the Agent int {path => values} format.
14
+ #
15
+ # @return source_values [Hash<String =>Contrast::Config::Diagnostics::SourceConfigValue>]
16
+ def source_values
17
+ @_source_values ||= begin
18
+ sources = {}
19
+ Contrast::CONFIG.config.origin.source_files.each do |file|
20
+ config = Contrast::Utils::HashUtils.deep_symbolize_all_keys(file.values)
21
+ # Assign each source to it's file path
22
+ sources[file.path] = Contrast::Config::Diagnostics::Tools.
23
+ to_config_values(Contrast::Config::Diagnostics::Tools.
24
+ flatten_settings(Contrast::Config::Diagnostics::Tools.
25
+ value_to_s(config), config: config), source: true)
26
+ end
27
+ sources
28
+ end
29
+ end
30
+
31
+ def to_controlled_hash
32
+ arr = []
33
+ source_values.each do |k, v|
34
+ hsh = {}
35
+ hsh[:path] = k
36
+ hsh[:values] = v.map(&:to_source_hash)
37
+ arr << hsh
38
+ end
39
+ arr
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -48,7 +48,7 @@ module Contrast
48
48
  # Converts current configuration to effective config values class and appends them to
49
49
  # EffectiveConfig class.
50
50
  #
51
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
51
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
52
52
  def to_effective_config effective_config
53
53
  add_effective_config_values(effective_config, CONFIG_VALUES, CANON_NAME, "#{ CONTRAST }.#{ CANON_NAME }")
54
54
  end
@@ -51,7 +51,7 @@ module Contrast
51
51
  # Converts current configuration to effective config values class and appends them to
52
52
  # EffectiveConfig class.
53
53
  #
54
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
54
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
55
55
  def to_effective_config effective_config
56
56
  super
57
57
  add_single_effective_value(effective_config,
@@ -15,6 +15,8 @@ require 'contrast/components/protect'
15
15
  require 'contrast/components/assess'
16
16
  require 'contrast/components/config/sources'
17
17
  require 'contrast/config/server_configuration'
18
+ require 'contrast/config/configuration_files'
19
+ require 'contrast/utils/hash_utils'
18
20
 
19
21
  module Contrast
20
22
  # This is how we read in the local settings for the Agent, both ENV/ CMD line
@@ -57,7 +59,8 @@ module Contrast
57
59
  DEFAULT_YAML_PATH = 'contrast_security.yaml'
58
60
  MILLISECOND_MARKER = '_ms'
59
61
  CONVERSION = {}.cs__freeze
60
- CONFIG_BASE_PATHS = ['', 'config/', '/etc/contrast/ruby/', '/etc/contrast/', '/etc/'].cs__freeze
62
+ # Precedence of paths, shift if config file values needs to go up the chain.
63
+ CONFIG_BASE_PATHS = %w[./ config/ /etc/contrast/ruby/ /etc/contrast/ /etc/].cs__freeze
61
64
  KEYS_TO_REDACT = %i[api_key url service_key user_name].cs__freeze
62
65
  REDACTED = '**REDACTED**'
63
66
 
@@ -65,9 +68,7 @@ module Contrast
65
68
  @default_name = default_name
66
69
 
67
70
  # Load config_kv from file
68
- config_kv = deep_symbolize_all_keys(load_config)
69
- config_sources = assign_source_to(config_kv, Contrast::Components::Config::Sources::YAML)
70
-
71
+ config_kv = Contrast::Utils::HashUtils.deep_symbolize_all_keys(load_config)
71
72
  unless cli_options
72
73
  cli_options = {}
73
74
  ENV.each do |key, value|
@@ -76,19 +77,22 @@ module Contrast
76
77
  cli_options[key] = value
77
78
  end
78
79
  end
80
+
79
81
  # Overlay CLI options - they take precedence over config file
80
- cli_options = deep_symbolize_all_keys(cli_options)
82
+ cli_options = Contrast::Utils::HashUtils.deep_symbolize_all_keys(cli_options)
81
83
  if cli_options
82
- config_kv = deep_merge(cli_options, config_kv)
83
- config_sources = deep_merge(assign_source_to(cli_options, Contrast::Components::Config::Sources::CLI),
84
- config_sources)
84
+ config_kv = Contrast::Utils::HashUtils.deep_merge(cli_options, config_kv)
85
+ @_source_file_extensions = Contrast::Utils::HashUtils.
86
+ deep_merge(assign_source_to(cli_options,
87
+ Contrast::Components::Config::Sources::COMMAND_LINE),
88
+ @_source_file_extensions)
85
89
  end
86
90
 
87
91
  # Some in-flight rewrites to maintain backwards compatibility
88
92
  config_kv = update_prop_keys(config_kv)
89
93
  @loaded_config = config_kv
90
94
 
91
- @sources = Contrast::Components::Config::Sources.new(config_sources)
95
+ @sources = Contrast::Components::Config::Sources.new(@_source_file_extensions)
92
96
 
93
97
  @api = Contrast::Components::Api::Interface.new(config_kv[:api])
94
98
  @enable = config_kv[:enable]
@@ -107,6 +111,11 @@ module Contrast
107
111
  convert_to_hash.to_yaml
108
112
  end
109
113
 
114
+ # @return [Hash] map of all extensions for each config key.
115
+ def source_file_extensions
116
+ @_source_file_extensions ||= {}
117
+ end
118
+
110
119
  # @return [Contrast::Components::Api::Interface]
111
120
  def api
112
121
  @api ||= Contrast::Components::Api::Interface.new # rubocop:disable Naming/MemoizedInstanceVariableName
@@ -142,27 +151,36 @@ module Contrast
142
151
  @protect ||= Contrast::Components::Protect::Interface.new # rubocop:disable Naming/MemoizedInstanceVariableName
143
152
  end
144
153
 
145
- protected
146
-
147
- # TODO: RUBY-546 move utility methods to auxiliary classes
154
+ # Base paths to check for the contrast configuration file, sorted by
155
+ # reverse order of precedence (first is most important).
156
+ def configuration_paths
157
+ @_configuration_paths ||= begin
158
+ basename = default_name.split('.').first
159
+ # Order of extensions comes from here:
160
+ extensions = Contrast::Components::Config::Sources::APP_CONFIGURATION_FILE.map(&:downcase)
148
161
 
149
- def load_config
150
- config = {}
151
- configuration_paths.find do |path|
152
- next unless File.exist?(path)
162
+ paths = []
163
+ # Environment paths takes precedence here. Look first through them.
164
+ paths << ENV['CONTRAST_CONFIG_PATH'] if ENV['CONTRAST_CONFIG_PATH']
165
+ paths << ENV['CONTRAST_SECURITY_CONFIG'] if ENV['CONTRAST_SECURITY_CONFIG']
153
166
 
154
- unless File.readable?(path)
155
- log_file_read_error(path)
156
- next
167
+ extensions.each do |ext|
168
+ places = CONFIG_BASE_PATHS.product(["#{ basename }.#{ ext }"])
169
+ paths += places.map!(&:join)
157
170
  end
158
- config = yaml_to_hash(path) || {}
159
- @config_file = path
160
- break
171
+ paths
161
172
  end
173
+ end
162
174
 
163
- config
175
+ # List of all read configuration files.
176
+ #
177
+ # @return [Contrast::Config::ConfigurationFiles] of paths
178
+ def origin
179
+ @_origin ||= Contrast::Config::ConfigurationFiles.new
164
180
  end
165
181
 
182
+ protected
183
+
166
184
  def yaml_to_hash path
167
185
  if path && File.readable?(path)
168
186
  begin
@@ -179,6 +197,45 @@ module Contrast
179
197
  {}
180
198
  end
181
199
 
200
+ # TODO: RUBY-546 move utility methods to auxiliary classes
201
+
202
+ # Read through all the paths we know config may live. Merge all values from all files found.
203
+ # Priority is given to yaml over yml. If same keys are found on two configs with different extensions,
204
+ # the Agent will read first from the yaml file and ignore the values for same key on the yml file.
205
+ #
206
+ # @return config [Hash] All source configurations from files.
207
+ def load_config
208
+ config = {}
209
+ @_source_file_extensions = {}
210
+ configuration_paths.each do |path|
211
+ next unless File.exist?(path)
212
+
213
+ unless File.readable?(path)
214
+ log_file_read_error(path)
215
+ next
216
+ end
217
+ origin.add_source_file(path, (yaml_to_hash(path) || {}))
218
+ end
219
+
220
+ # Legacy usage: Assign main configuration file for reference.
221
+ @config_file = origin.main_file
222
+ # merge all settings keeping the top yaml files values as priority.
223
+ # If in top file a key exists it's value won't be changed if same key has different value in one
224
+ # of the other config files. Only unique values will be taken in consideration.w
225
+ # precedence of paths: see Contrast::Configuration::CONFIG_BASE_PATHS
226
+ extensions_maps = []
227
+ origin.source_files.each do |file|
228
+ # config.merge!(file.values) { |_key, oldval, _newval| oldval = oldval }
229
+ precedence_merge!(config, file.values)
230
+ # assign source values extentions:
231
+ extensions_maps << assign_source_to(Contrast::Utils::HashUtils.deep_symbolize_all_keys(file.values), file.path)
232
+ end
233
+ # merge all origin paths to be used as extension classification to preserve the precedence of config files:
234
+ extensions_maps.each { |path| @_source_file_extensions = precedence_merge!(@_source_file_extensions, path) }
235
+
236
+ config
237
+ end
238
+
182
239
  # We're updating properties loaded from the configuration files to match the new agreed upon standard configuration
183
240
  # names, so that one file works for all agents
184
241
  def update_prop_keys config
@@ -203,39 +260,6 @@ module Contrast
203
260
  config
204
261
  end
205
262
 
206
- # Base paths to check for the contrast configuration file, sorted by
207
- # reverse order of precedence (first is most important).
208
- def configuration_paths
209
- @_configuration_paths ||= begin
210
- basename = default_name.split('.').first
211
- names = %w[yml yaml].map { |suffix| "#{ basename }.#{ suffix }" }
212
-
213
- paths = []
214
- paths << ENV['CONTRAST_CONFIG_PATH'] if ENV['CONTRAST_CONFIG_PATH']
215
- paths << ENV['CONTRAST_SECURITY_CONFIG'] if ENV['CONTRAST_SECURITY_CONFIG']
216
-
217
- tmp = CONFIG_BASE_PATHS.product(names)
218
- paths += tmp.map!(&:join)
219
- paths
220
- end
221
- end
222
-
223
- def deep_merge cli_config, file_config
224
- cli_config.merge(file_config) do |_key, cli_value, file_value|
225
- cli_value.is_a?(Hash) && file_value.is_a?(Hash) ? deep_merge(cli_value, file_value) : cli_value
226
- end
227
- end
228
-
229
- def deep_symbolize_all_keys hash
230
- return if hash.nil?
231
-
232
- new_hash = {}
233
- hash.each do |key, value|
234
- new_hash[key.to_sym] = value.is_a?(Hash) ? deep_symbolize_all_keys(value) : value
235
- end
236
- new_hash
237
- end
238
-
239
263
  private
240
264
 
241
265
  # We cannot use all access components at this point, unfortunately, as they
@@ -333,7 +357,7 @@ module Contrast
333
357
  KEYS_TO_REDACT.include?(key.to_sym)
334
358
  end
335
359
 
336
- def assign_source_to hash, source = Contrast::Components::Config::Sources::YAML
360
+ def assign_source_to hash, source = Contrast::Components::Config::Sources::APP_CONFIGURATION_FILE[0]
337
361
  hash.transform_values do |value|
338
362
  if value.is_a?(Hash)
339
363
  assign_source_to(value, source)
@@ -342,5 +366,14 @@ module Contrast
342
366
  end
343
367
  end
344
368
  end
369
+
370
+ # Merges two hashes, first hash will preserve it's values and will only add unique values.
371
+ #
372
+ # @param hsh [Hash]
373
+ # @param other_hsh [Hash]
374
+ # @return [Hash]
375
+ def precedence_merge! hsh, other_hsh
376
+ hsh.merge!(other_hsh) { |_key, old_val, _new_val| old_val }
377
+ end
345
378
  end
346
379
  end
@@ -0,0 +1,43 @@
1
+ # Copyright (c) 2023 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 Utils
6
+ # Module to hold various hash utils methods
7
+ module HashUtils
8
+ class << self
9
+ # Merges two hashes, first hash will preserve it's values and will only add unique values.
10
+ #
11
+ # @param hsh [Hash]
12
+ # @param other_hsh [Hash]
13
+ def deep_merge hsh, other_hsh
14
+ hsh.merge(other_hsh) do |_key, old_value, new_value|
15
+ old_value.is_a?(Hash) || new_value.is_a?(Hash) ? deep_merge(old_value, new_value) : old_value
16
+ end
17
+ end
18
+
19
+ # Deep symbolizes all keys
20
+ # @param value [Hash]
21
+ # @return [Hash]
22
+ def deep_symbolize_all_keys value
23
+ new_hash = {}
24
+ value.each { |key, v| new_hash[key.to_sym] = map_value(v) }
25
+ new_hash
26
+ end
27
+
28
+ private
29
+
30
+ def map_value value
31
+ case value
32
+ when Hash
33
+ deep_symbolize_all_keys(value)
34
+ when Array
35
+ value.map { |v| map_value(v) }
36
+ else
37
+ value
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,46 @@
1
+ # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'json'
5
+ require 'contrast/utils/hash_utils'
6
+ require 'contrast/components/logger'
7
+
8
+ module Contrast
9
+ module Utils
10
+ # Module to hold Agent's custom JSON.parse logic.
11
+ module Json
12
+ class << self
13
+ include Contrast::Components::Logger::InstanceMethods
14
+
15
+ # Add any known cases where parsing error might arise from older json parser:
16
+ # @return [Array<String>]
17
+ SPECIAL_CASES = ["\"\""].cs__freeze # rubocop:disable Style/StringLiterals
18
+
19
+ # Parses a string using JSON.parser. This method is used instead of standard JSON.parse to
20
+ # support older versions of json gem => not supporting key-value second parameter, which is
21
+ # supported after json 2.3.0.
22
+ #
23
+ # @param string [String]
24
+ # @param deep_symbolize [Boolean] flag to set if keys needs to be deep symbolized.
25
+ # @return [Hash]
26
+ def parse string, deep_symbolize: false
27
+ # The Agent receives empty responses from TS sometimes.
28
+ # There is a special case to handle this.
29
+ return {} if SPECIAL_CASES.include?(string)
30
+
31
+ symbolized_hash = {}
32
+ hash = JSON::Parser.new(string).parse
33
+ symbolized_hash = Contrast::Utils::HashUtils.deep_symbolize_all_keys(hash) if deep_symbolize
34
+ return hash unless deep_symbolize
35
+
36
+ symbolized_hash
37
+ rescue JSON::ParserError => e
38
+ # Any parsing error will produce empty {}. Since older JSON might pose support issues with newer Ruby,
39
+ # We might just log any miss-parsings and allow Agent to continue.
40
+ logger.warn("[JSON] parse error: #{ e }")
41
+ {}
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'net/http'
5
+ require 'resolv'
5
6
  require 'contrast/components/logger'
6
7
  require 'contrast/utils/object_share'
7
8
  require 'socket'
@@ -10,8 +11,25 @@ module Contrast
10
11
  module Utils
11
12
  # This module creates a Net::HTTP client base to be used by different services
12
13
  # All HTTP clients reporting to Telemetry or TS should inherit from this
13
- class NetHttpBase
14
+ class NetHttpBase # rubocop:disable Metrics/ClassLength
14
15
  include Contrast::Components::Logger::InstanceMethods
16
+
17
+ class << self
18
+ # Last recorded error
19
+ # @return [StandardError]
20
+ def last_error
21
+ @_last_error
22
+ end
23
+
24
+ # @param [StandardError]
25
+ def last_error= error
26
+ @_last_error = error
27
+ end
28
+ end
29
+
30
+ # @return [String]
31
+ attr_reader :client_name
32
+
15
33
  # This method initializes the Net::HTTP client we'll need. it will validate
16
34
  # the connection and make the first request. If connection is valid and response
17
35
  # is available then the open connection is returned.
@@ -23,29 +41,22 @@ module Contrast
23
41
  # self signed certificates provided by config [default = false]
24
42
  # @return [Net::HTTP, nil] Return open connection or nil
25
43
  def initialize_connection service_name, url, use_proxy: false, use_custom_cert: false
26
- return unless url
27
-
28
- addr = URI(url)
29
- return if addr.host.nil? || addr.port.nil?
30
- return if addr.scheme != 'https' && !addr.host.to_s.include?('localhost')
31
-
32
- # the proxy is enabled only if there is provided url even if the enable is set to true
33
- proxy_addr = URI(Contrast::API.proxy_url) if proxy_enabled?
34
- net_http_client = initialize_client(addr, proxy_addr, use_proxy, use_custom_cert)
35
- return if net_http_client.nil?
36
-
37
- net_http_client.start
38
- return unless net_http_client.started?
44
+ Contrast::Utils::NetHttpBase.last_error = nil
45
+ @client_name = service_name
46
+ return unless (addr = retrieve_address(url))
47
+ return unless (net_http_client = configure_new_client(addr, use_proxy, use_custom_cert))
48
+ return unless client_started?(net_http_client)
39
49
 
40
- logger.debug("Starting #{ service_name } connection test")
50
+ logger.debug("Starting #{ client_name } connection test")
41
51
  return unless connection_verified?(net_http_client, url)
42
52
 
43
- logger.debug('Client verified', service: service_name, url: url)
53
+ logger.debug('Client verified', service: client_name, url: url)
44
54
  net_http_client
45
55
  rescue StandardError => e
46
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
47
- # an infinite loop w/ telemetry
48
- logger.debug('Connection failed', e, service: service_name, url: url)
56
+ Contrast::Utils::NetHttpBase.last_error = e
57
+ return if client_name == Contrast::Agent::Telemetry::Client::SERVICE_NAME
58
+
59
+ logger.error('Connection failed', e, service: client_name, url: url)
49
60
  nil
50
61
  end
51
62
 
@@ -74,14 +85,51 @@ module Contrast
74
85
  Errno::ETIMEDOUT, Errno::ESHUTDOWN, Errno::EHOSTDOWN, Errno::EHOSTUNREACH, Errno::EISCONN,
75
86
  Errno::ECONNABORTED, Errno::ENETRESET, Errno::ENETUNREACH => e
76
87
 
77
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
78
- # an infinite loop w/ telemetry
79
- logger.debug("#{ service_name } connection failed", e.message)
80
- false
88
+ Contrast::Utils::NetHttpBase.last_error = e
89
+ unless client_name == Contrast::Agent::Telemetry::Client::SERVICE_NAME
90
+ logger.error("#{ client_name } connection failed", e.message)
91
+ end
92
+ @_connection_verified = false
81
93
  end
82
94
 
83
95
  private
84
96
 
97
+ # Starts connection and return started status.
98
+ #
99
+ # @param client [Net::HTTP] client instance.
100
+ # @return [Boolean] status indicates whether connection has started.
101
+ def client_started? client
102
+ return false unless client
103
+
104
+ client.start
105
+ client.started?
106
+ end
107
+
108
+ # @param url
109
+ # @return [URI::Generic, nil]
110
+ def retrieve_address url
111
+ return unless (addr = URI(url))
112
+ return if addr.host.nil? || addr.port.nil?
113
+ return if addr.scheme != 'https' && !addr.host.to_s.include?('localhost')
114
+
115
+ addr
116
+ end
117
+
118
+ # Assigns proxy and custom certificates if enabled, and initializes new client.
119
+ #
120
+ # @param addr [URI::Generic, nil]
121
+ # @param use_proxy [Boolean] flag used to indicate proxy connections [default = false]
122
+ # @param use_custom_cert [Boolean] flag used to indicate whether the client is to use
123
+ # @return client [Net::HTTP, nil] initialized client.
124
+ def configure_new_client addr, use_proxy, use_custom_cert
125
+ # the proxy is enabled only if there is provided url even if the enable is set to true
126
+ proxy_addr = URI(Contrast::API.proxy_url) if proxy_enabled?
127
+ net_http_client = initialize_client(addr, proxy_addr, use_proxy, use_custom_cert)
128
+ return if net_http_client.nil?
129
+
130
+ net_http_client
131
+ end
132
+
85
133
  # Resolves the address of the assigned domain to array of corresponding IPs (if more than one)
86
134
  # and runs a matcher to see if current connection IP is in the list.
87
135
  # This is called within #verify_connection, if called on it's own there will be no
@@ -114,9 +162,10 @@ module Contrast
114
162
  client.key = OpenSSL::PKey::RSA.new(File.read(Contrast::API.certification_key_file)).to_s
115
163
  end
116
164
  rescue Errno::ENOENT => e
117
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
118
- # an infinite loop w/ telemetry
119
- logger.debug('Custom certificates failed', e.message)
165
+ Contrast::Utils::NetHttpBase.last_error = e
166
+ unless client_name == Contrast::Agent::Telemetry::Client::SERVICE_NAME
167
+ logger.error('Custom certificates failed', e.message)
168
+ end
120
169
  end
121
170
 
122
171
  # sets default setting for client validation of certificates and
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contrast-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.0
4
+ version: 7.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - galen.palmer@contrastsecurity.com
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: exe
15
15
  cert_chain: []
16
- date: 2023-04-03 00:00:00.000000000 Z
16
+ date: 2023-04-13 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: bundler
@@ -1079,6 +1079,7 @@ files:
1079
1079
  - lib/contrast/agent/reporting/masker/masker_utils.rb
1080
1080
  - lib/contrast/agent/reporting/report.rb
1081
1081
  - lib/contrast/agent/reporting/reporter.rb
1082
+ - lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb
1082
1083
  - lib/contrast/agent/reporting/reporting_events/agent_startup.rb
1083
1084
  - lib/contrast/agent/reporting/reporting_events/application_activity.rb
1084
1085
  - lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb
@@ -1224,11 +1225,17 @@ files:
1224
1225
  - lib/contrast/config/api_proxy_configuration.rb
1225
1226
  - lib/contrast/config/base_configuration.rb
1226
1227
  - lib/contrast/config/certification_configuration.rb
1227
- - lib/contrast/config/config.rb
1228
- - lib/contrast/config/diagnostics.rb
1229
- - lib/contrast/config/diagnostics_tools.rb
1230
- - lib/contrast/config/effective_config.rb
1231
- - lib/contrast/config/effective_config_value.rb
1228
+ - lib/contrast/config/configuration_files.rb
1229
+ - lib/contrast/config/diagnostics/command_line.rb
1230
+ - lib/contrast/config/diagnostics/config.rb
1231
+ - lib/contrast/config/diagnostics/contrast_ui.rb
1232
+ - lib/contrast/config/diagnostics/effective_config.rb
1233
+ - lib/contrast/config/diagnostics/effective_config_value.rb
1234
+ - lib/contrast/config/diagnostics/environment_variables.rb
1235
+ - lib/contrast/config/diagnostics/monitor.rb
1236
+ - lib/contrast/config/diagnostics/source_config_value.rb
1237
+ - lib/contrast/config/diagnostics/tools.rb
1238
+ - lib/contrast/config/diagnostics/user_configuration_file.rb
1232
1239
  - lib/contrast/config/env_variables.rb
1233
1240
  - lib/contrast/config/exception_configuration.rb
1234
1241
  - lib/contrast/config/protect_rule_configuration.rb
@@ -1297,12 +1304,14 @@ files:
1297
1304
  - lib/contrast/utils/findings.rb
1298
1305
  - lib/contrast/utils/hash_digest.rb
1299
1306
  - lib/contrast/utils/hash_digest_extend.rb
1307
+ - lib/contrast/utils/hash_utils.rb
1300
1308
  - lib/contrast/utils/head_dump_utils_extend.rb
1301
1309
  - lib/contrast/utils/heap_dump_util.rb
1302
1310
  - lib/contrast/utils/input_classification_base.rb
1303
1311
  - lib/contrast/utils/invalid_configuration_util.rb
1304
1312
  - lib/contrast/utils/io_util.rb
1305
1313
  - lib/contrast/utils/job_servers_running.rb
1314
+ - lib/contrast/utils/json.rb
1306
1315
  - lib/contrast/utils/log_utils.rb
1307
1316
  - lib/contrast/utils/lru_cache.rb
1308
1317
  - lib/contrast/utils/metrics_hash.rb