Skip to content

Commit cca5e13

Browse files
author
Inbal Tako
committed
Add proxy headers and fix client ip parsing
1 parent c7d062d commit cca5e13

41 files changed

Lines changed: 737 additions & 319 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
securenative (0.1.22)
4+
securenative (0.1.23)
55

66
GEM
77
remote: https://rubygems.org/

lib/config/configuration_builder.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
require 'enums/failover_strategy'
44

55
class ConfigurationBuilder
6-
attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
7-
attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
6+
attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy, :proxy_headers
7+
attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy, :proxy_headers
88

99
def initialize(api_key: nil, api_url: 'https://api.securenative.com/collector/api/v1', interval: 1000,
1010
max_events: 1000, timeout: 1500, auto_send: true, disable: false, log_level: 'FATAL',
11-
fail_over_strategy: FailOverStrategy::FAIL_OPEN)
11+
fail_over_strategy: FailOverStrategy::FAIL_OPEN, proxy_headers: [])
1212
@api_key = api_key
1313
@api_url = api_url
1414
@interval = interval
@@ -18,6 +18,7 @@ def initialize(api_key: nil, api_url: 'https://api.securenative.com/collector/ap
1818
@disable = disable
1919
@log_level = log_level
2020
@fail_over_strategy = fail_over_strategy
21+
@proxy_headers = proxy_headers
2122
end
2223

2324
def self.default_securenative_options

lib/config/configuration_manager.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def self.load_config
5050
auto_send: _get_env_or_default(properties, 'SECURENATIVE_AUTO_SEND', options.auto_send),
5151
disable: _get_env_or_default(properties, 'SECURENATIVE_DISABLE', options.disable),
5252
log_level: _get_env_or_default(properties, 'SECURENATIVE_LOG_LEVEL', options.log_level),
53-
fail_over_strategy: _get_env_or_default(properties, 'SECURENATIVE_FAILOVER_STRATEGY', options.fail_over_strategy))
53+
fail_over_strategy: _get_env_or_default(properties, 'SECURENATIVE_FAILOVER_STRATEGY', options.fail_over_strategy),
54+
proxy_headers: _get_env_or_default(properties, 'SECURENATIVE_PROXY_HEADERS', options.proxy_headers))
5455
end
5556
end

lib/config/securenative_options.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
require 'enums/failover_strategy'
44

55
class SecureNativeOptions
6-
attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
7-
attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
6+
attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy, :proxy_headers
7+
attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy, :proxy_headers
88

99
def initialize(api_key: nil, api_url: "https://api.securenative.com/collector/api/v1", interval: 1000,
1010
max_events: 1000, timeout: 1500, auto_send: true, disable: false, log_level: "FATAL",
11-
fail_over_strategy: FailOverStrategy::FAIL_OPEN)
11+
fail_over_strategy: FailOverStrategy::FAIL_OPEN, proxy_headers: [])
1212
@api_key = api_key
1313
@api_url = api_url
1414
@interval = interval
@@ -18,5 +18,6 @@ def initialize(api_key: nil, api_url: "https://api.securenative.com/collector/ap
1818
@disable = disable
1919
@log_level = log_level
2020
@fail_over_strategy = fail_over_strategy
21+
@proxy_headers = proxy_headers
2122
end
2223
end

lib/utils/request_utils.rb

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,49 @@ def self.get_secure_header_from_request(headers)
1313
[]
1414
end
1515

16-
def self.get_client_ip_from_request(request)
16+
def self.get_client_ip_from_request(request, options = nil)
1717
begin
1818
return request.ip unless request.ip.nil?
1919
rescue NoMethodError
2020
end
2121

2222
begin
2323
x_forwarded_for = request.env['HTTP_X_FORWARDED_FOR']
24-
return x_forwarded_for unless x_forwarded_for.nil?
24+
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
2525
rescue NoMethodError
2626
begin
2727
x_forwarded_for = request['HTTP_X_FORWARDED_FOR']
28-
return x_forwarded_for unless x_forwarded_for.nil?
28+
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
2929
rescue NoMethodError
3030
end
3131
end
3232

3333
begin
3434
x_forwarded_for = request.env['REMOTE_ADDR']
35-
return x_forwarded_for unless x_forwarded_for.nil?
35+
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
3636
rescue NoMethodError
3737
begin
3838
x_forwarded_for = request['REMOTE_ADDR']
39-
return x_forwarded_for unless x_forwarded_for.nil?
39+
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
4040
rescue NoMethodError
4141
end
4242
end
4343

44+
unless options.nil?
45+
for header in options.proxy_headers do
46+
begin
47+
h = request.env[header]
48+
return h.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless h.nil?
49+
rescue NoMethodError
50+
begin
51+
h = request[header]
52+
return h.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless h.nil?
53+
rescue NoMethodError
54+
end
55+
end
56+
end
57+
end
58+
4459
''
4560
end
4661

out/production/securenative-ruby/api_manager.rb

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# frozen_string_literal: true
22

3+
require 'models/sdk_event'
4+
require 'enums/failover_strategy'
5+
require 'enums/risk_level'
6+
require 'enums/api_route'
7+
require 'models/verify_result'
38
require 'json'
49

510
class ApiManager
@@ -19,13 +24,16 @@ def verify(event_options)
1924
event = SDKEvent.new(event_options, @options)
2025

2126
begin
22-
res = JSON.parse(@event_manager.send_sync(event, ApiRoute::VERIFY, false))
23-
return VerifyResult.new(res['riskLevel'], res['score'], res['triggers'])
27+
res = @event_manager.send_sync(event, ApiRoute::VERIFY, false)
28+
ver_result = JSON.parse(res.body)
29+
return VerifyResult.new(risk_level: ver_result['riskLevel'], score: ver_result['score'], triggers: ver_result['triggers'])
2430
rescue StandardError => e
25-
SecureNativeLogger.debug('Failed to call verify; {}'.format(e))
31+
SecureNativeLogger.debug("Failed to call verify; #{e}")
32+
end
33+
if @options.fail_over_strategy == FailOverStrategy::FAIL_OPEN
34+
return VerifyResult.new(risk_level: RiskLevel::LOW, score: 0, triggers: nil)
2635
end
27-
return VerifyResult.new(RiskLevel::LOW, 0, nil) if @options.fail_over_strategy == FailOverStrategy::FAIL_OPEN
2836

29-
VerifyResult.new(RiskLevel::HIGH, 1, nil)
37+
VerifyResult.new(risk_level: RiskLevel::HIGH, score: 1, triggers: nil)
3038
end
3139
end

out/production/securenative-ruby/config/configuration_builder.rb

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
require 'enums/failover_strategy'
44

55
class ConfigurationBuilder
6-
attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
7-
attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
6+
attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy, :proxy_headers
7+
attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy, :proxy_headers
88

9-
def initialize(api_key = nil, api_url = 'https://api.securenative.com/collector/api/v1', interval = 1000,
10-
max_events = 1000, timeout = 1500, auto_send = true, disable = false, log_level = 'FATAL',
11-
fail_over_strategy = FailOverStrategy::FAIL_OPEN)
9+
def initialize(api_key: nil, api_url: 'https://api.securenative.com/collector/api/v1', interval: 1000,
10+
max_events: 1000, timeout: 1500, auto_send: true, disable: false, log_level: 'FATAL',
11+
fail_over_strategy: FailOverStrategy::FAIL_OPEN, proxy_headers: [])
1212
@api_key = api_key
1313
@api_url = api_url
1414
@interval = interval
@@ -18,10 +18,7 @@ def initialize(api_key = nil, api_url = 'https://api.securenative.com/collector/
1818
@disable = disable
1919
@log_level = log_level
2020
@fail_over_strategy = fail_over_strategy
21-
end
22-
23-
def self.default_config_builder
24-
ConfigurationBuilder.new
21+
@proxy_headers = proxy_headers
2522
end
2623

2724
def self.default_securenative_options
Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
# frozen_string_literal: true
22

3-
require 'parseconfig'
3+
require 'yaml'
4+
require 'config/configuration_builder'
45

56
class ConfigurationManager
6-
DEFAULT_CONFIG_FILE = 'securenative.cfg'
7-
CUSTOM_CONFIG_FILE_ENV_NAME = 'SECURENATIVE_COMFIG_FILE'
7+
DEFAULT_CONFIG_FILE = 'securenative.yml'
8+
CUSTOM_CONFIG_FILE_ENV_NAME = 'SECURENATIVE_CONFIG_FILE'
89
@config = nil
910

1011
def self.read_resource_file(resource_path)
11-
@config = ParseConfig.new(resource_path)
12-
1312
properties = {}
14-
@config.get_groups.each { |group|
15-
group.each do |key, value|
16-
properties[key.upcase] = value
17-
end
18-
}
13+
begin
14+
@config = YAML.load_file(resource_path)
15+
properties = @config unless @config.nil?
16+
rescue StandardError => e
17+
SecureNativeLogger.error("Could not parse config file #{resource_path}; #{e}")
18+
end
1919
properties
2020
end
2121

@@ -24,32 +24,33 @@ def self._get_resource_path(env_name)
2424
end
2525

2626
def self.config_builder
27-
ConfigurationBuilder.default_config_builder
27+
ConfigurationBuilder.new
2828
end
2929

3030
def self._get_env_or_default(properties, key, default)
31-
return Env[key] if Env[key]
31+
return ENV[key] if ENV[key]
3232
return properties[key] if properties[key]
3333

3434
default
3535
end
3636

3737
def self.load_config
38-
options = ConfigurationBuilder().default_securenative_options
38+
options = ConfigurationBuilder.default_securenative_options
3939

4040
resource_path = DEFAULT_CONFIG_FILE
41-
resource_path = Env[CUSTOM_CONFIG_FILE_ENV_NAME] if Env[CUSTOM_CONFIG_FILE_ENV_NAME]
41+
resource_path = ENV[CUSTOM_CONFIG_FILE_ENV_NAME] unless ENV[CUSTOM_CONFIG_FILE_ENV_NAME].nil?
4242

4343
properties = read_resource_file(resource_path)
4444

45-
ConfigurationBuilder(_get_env_or_default(properties, 'SECURENATIVE_API_KEY', options.api_key),
46-
_get_env_or_default(properties, 'SECURENATIVE_API_URL', options.api_url),
47-
_get_env_or_default(properties, 'SECURENATIVE_INTERVAL', options.interval),
48-
_get_env_or_default(properties, 'SECURENATIVE_MAX_EVENTS', options.max_events),
49-
_get_env_or_default(properties, 'SECURENATIVE_TIMEOUT', options.timeout),
50-
_get_env_or_default(properties, 'SECURENATIVE_AUTO_SEND', options.auto_send),
51-
_get_env_or_default(properties, 'SECURENATIVE_DISABLE', options.disable),
52-
_get_env_or_default(properties, 'SECURENATIVE_LOG_LEVEL', options.log_level),
53-
_get_env_or_default(properties, 'SECURENATIVE_FAILOVER_STRATEGY', options.fail_over_strategy))
45+
ConfigurationBuilder.new(api_key: _get_env_or_default(properties, 'SECURENATIVE_API_KEY', options.api_key),
46+
api_url: _get_env_or_default(properties, 'SECURENATIVE_API_URL', options.api_url),
47+
interval: _get_env_or_default(properties, 'SECURENATIVE_INTERVAL', options.interval),
48+
max_events: _get_env_or_default(properties, 'SECURENATIVE_MAX_EVENTS', options.max_events),
49+
timeout: _get_env_or_default(properties, 'SECURENATIVE_TIMEOUT', options.timeout),
50+
auto_send: _get_env_or_default(properties, 'SECURENATIVE_AUTO_SEND', options.auto_send),
51+
disable: _get_env_or_default(properties, 'SECURENATIVE_DISABLE', options.disable),
52+
log_level: _get_env_or_default(properties, 'SECURENATIVE_LOG_LEVEL', options.log_level),
53+
fail_over_strategy: _get_env_or_default(properties, 'SECURENATIVE_FAILOVER_STRATEGY', options.fail_over_strategy),
54+
proxy_headers: _get_env_or_default(properties, 'SECURENATIVE_PROXY_HEADERS', options.proxy_headers))
5455
end
5556
end
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# frozen_string_literal: true
22

3+
require 'enums/failover_strategy'
4+
35
class SecureNativeOptions
4-
attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
5-
attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
6+
attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy, :proxy_headers
7+
attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy, :proxy_headers
68

7-
def initialize(api_key = nil, api_url = "https://api.securenative.com/collector/api/v1", interval = 1000,
8-
max_events = 1000, timeout = 1500, auto_send = true, disable = false, log_level = "FATAL",
9-
fail_over_strategy = FailOverStrategy::FAIL_OPEN)
9+
def initialize(api_key: nil, api_url: "https://api.securenative.com/collector/api/v1", interval: 1000,
10+
max_events: 1000, timeout: 1500, auto_send: true, disable: false, log_level: "FATAL",
11+
fail_over_strategy: FailOverStrategy::FAIL_OPEN, proxy_headers: [])
1012
@api_key = api_key
1113
@api_url = api_url
1214
@interval = interval
@@ -16,5 +18,6 @@ def initialize(api_key = nil, api_url = "https://api.securenative.com/collector/
1618
@disable = disable
1719
@log_level = log_level
1820
@fail_over_strategy = fail_over_strategy
21+
@proxy_headers = proxy_headers
1922
end
2023
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
class HanamiContext
4+
SECURENATIVE_COOKIE = '_sn'
5+
6+
def self.get_client_token(request)
7+
begin
8+
request.env[SECURENATIVE_COOKIE]
9+
rescue StandardError
10+
begin
11+
request.cookies[SECURENATIVE_COOKIE]
12+
rescue StandardError
13+
nil
14+
end
15+
end
16+
end
17+
18+
def self.get_url(request)
19+
begin
20+
request.env['REQUEST_PATH']
21+
rescue StandardError
22+
nil
23+
end
24+
end
25+
26+
def self.get_method(request)
27+
begin
28+
request.request_method
29+
rescue StandardError
30+
nil
31+
end
32+
end
33+
34+
def self.get_headers(request)
35+
begin
36+
# Note: At the moment we're filtering out everything but user-agent since ruby's payload is way too big
37+
{ 'user-agent' => request.env['HTTP_USER_AGENT'] }
38+
rescue StandardError
39+
nil
40+
end
41+
end
42+
end

0 commit comments

Comments
 (0)