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.
- checksums.yaml +4 -4
- data/lib/contrast/agent/assess/policy/policy.rb +1 -1
- data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
- data/lib/contrast/agent/patching/policy/policy.rb +2 -2
- data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +3 -0
- data/lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb +1 -1
- data/lib/contrast/agent/reporting/reporter.rb +19 -4
- data/lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb +32 -0
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -0
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +3 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +11 -7
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +15 -7
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +2 -1
- data/lib/contrast/agent/reporting/reporting_workers/application_server_worker.rb +3 -0
- data/lib/contrast/agent/reporting/reporting_workers/reporter_heartbeat.rb +3 -0
- data/lib/contrast/agent/reporting/reporting_workers/server_settings_worker.rb +3 -0
- data/lib/contrast/agent/telemetry/base.rb +37 -12
- data/lib/contrast/agent/telemetry/client.rb +1 -3
- data/lib/contrast/agent/telemetry/telemetry.rb +0 -7
- data/lib/contrast/agent/thread/thread_watcher.rb +2 -2
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/agent.rb +1 -1
- data/lib/contrast/components/api.rb +2 -2
- data/lib/contrast/components/app_context.rb +1 -1
- data/lib/contrast/components/assess.rb +1 -1
- data/lib/contrast/components/assess_rules.rb +1 -1
- data/lib/contrast/components/base.rb +3 -3
- data/lib/contrast/components/config/sources.rb +12 -9
- data/lib/contrast/components/config.rb +2 -2
- data/lib/contrast/components/protect.rb +2 -2
- data/lib/contrast/components/sampling.rb +6 -4
- data/lib/contrast/components/settings.rb +1 -1
- data/lib/contrast/config/certification_configuration.rb +1 -1
- data/lib/contrast/config/configuration_files.rb +47 -0
- data/lib/contrast/config/diagnostics/command_line.rb +24 -0
- data/lib/contrast/config/{config.rb → diagnostics/config.rb} +21 -6
- data/lib/contrast/config/diagnostics/contrast_ui.rb +24 -0
- data/lib/contrast/config/diagnostics/effective_config.rb +28 -0
- data/lib/contrast/config/diagnostics/effective_config_value.rb +14 -0
- data/lib/contrast/config/diagnostics/environment_variables.rb +51 -0
- data/lib/contrast/config/{diagnostics.rb → diagnostics/monitor.rb} +10 -10
- data/lib/contrast/config/diagnostics/source_config_value.rb +51 -0
- data/lib/contrast/config/diagnostics/tools.rb +188 -0
- data/lib/contrast/config/diagnostics/user_configuration_file.rb +44 -0
- data/lib/contrast/config/request_audit_configuration.rb +1 -1
- data/lib/contrast/config/server_configuration.rb +1 -1
- data/lib/contrast/configuration.rb +90 -57
- data/lib/contrast/utils/hash_utils.rb +43 -0
- data/lib/contrast/utils/json.rb +46 -0
- data/lib/contrast/utils/net_http_base.rb +75 -26
- metadata +16 -7
- data/lib/contrast/config/diagnostics_tools.rb +0 -99
- data/lib/contrast/config/effective_config.rb +0 -131
- 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::
|
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::
|
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
|
-
|
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
|
-
|
84
|
-
|
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(
|
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
|
-
|
146
|
-
|
147
|
-
|
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
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
167
|
+
extensions.each do |ext|
|
168
|
+
places = CONFIG_BASE_PATHS.product(["#{ basename }.#{ ext }"])
|
169
|
+
paths += places.map!(&:join)
|
157
170
|
end
|
158
|
-
|
159
|
-
@config_file = path
|
160
|
-
break
|
171
|
+
paths
|
161
172
|
end
|
173
|
+
end
|
162
174
|
|
163
|
-
|
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::
|
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
|
-
|
27
|
-
|
28
|
-
addr =
|
29
|
-
return
|
30
|
-
return
|
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 #{
|
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:
|
53
|
+
logger.debug('Client verified', service: client_name, url: url)
|
44
54
|
net_http_client
|
45
55
|
rescue StandardError => e
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
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.
|
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-
|
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/
|
1228
|
-
- lib/contrast/config/diagnostics.rb
|
1229
|
-
- lib/contrast/config/
|
1230
|
-
- lib/contrast/config/
|
1231
|
-
- lib/contrast/config/
|
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
|