moesif_rack 1.4.19 → 2.0.1
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/moesif_rack/app_config.rb +76 -113
- data/lib/moesif_rack/client_ip.rb +61 -102
- data/lib/moesif_rack/governance_rules.rb +480 -0
- data/lib/moesif_rack/moesif_helpers.rb +33 -6
- data/lib/moesif_rack/moesif_middleware.rb +159 -148
- data/lib/moesif_rack/regex_config_helper.rb +96 -104
- data/lib/moesif_rack/update_company.rb +44 -48
- data/lib/moesif_rack/update_user.rb +44 -48
- data/moesif_capture_outgoing/httplog/adapters/net_http.rb +18 -21
- data/moesif_capture_outgoing/httplog/http_log.rb +57 -107
- data/moesif_capture_outgoing/httplog.rb +2 -2
- data/test/config_example.json +1473 -0
- data/test/govrule_example.json +20 -0
- data/test/test_governance_rules.rb +213 -0
- data/test/{moesif_rack_test.rb → test_moesif_rack.rb} +18 -16
- metadata +30 -6
@@ -1,119 +1,111 @@
|
|
1
1
|
require 'moesif_api'
|
2
2
|
|
3
|
-
require_relative './moesif_helpers
|
3
|
+
require_relative './moesif_helpers'
|
4
4
|
|
5
5
|
class RegexConfigHelper
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
def initialize(debug)
|
7
|
+
@debug = debug
|
8
|
+
end
|
9
|
+
|
10
|
+
def prepare_config_mapping(event)
|
11
|
+
# Function to prepare config mapping
|
12
|
+
# Params:
|
13
|
+
# - event: Event to be logged
|
14
|
+
# Return:
|
15
|
+
# - regex_config: Regex config mapping
|
16
|
+
regex_config = {}
|
17
|
+
|
18
|
+
# Config mapping for request.verb
|
19
|
+
if defined? event.request.verb
|
20
|
+
regex_config['request.verb'] = event.request.verb
|
9
21
|
end
|
10
22
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
regex_config["request.verb"] = event.request.verb
|
22
|
-
end
|
23
|
-
|
24
|
-
# Config mapping for request.uri
|
25
|
-
if defined? event.request.uri
|
26
|
-
extracted = /http[s]*:\/\/[^\/]+(\/[^?]+)/.match(event.request.uri)
|
27
|
-
if !extracted.nil?
|
28
|
-
route_mapping = extracted.captures[0]
|
29
|
-
else
|
30
|
-
route_mapping = '/'
|
31
|
-
end
|
32
|
-
regex_config["request.route"] = route_mapping
|
33
|
-
end
|
34
|
-
|
35
|
-
# Config mapping for request.ip_address
|
36
|
-
if defined? event.request.ip_address
|
37
|
-
regex_config["request.ip_address"] = event.request.ip_address
|
38
|
-
end
|
39
|
-
|
40
|
-
# Config mapping for response.status
|
41
|
-
if defined? event.response.status
|
42
|
-
regex_config["response.status"] = event.response.status
|
43
|
-
end
|
23
|
+
# Config mapping for request.uri
|
24
|
+
if defined? event.request.uri
|
25
|
+
extracted = %r{https*://[^/]+(/[^?]+)}.match(event.request.uri)
|
26
|
+
route_mapping = if !extracted.nil?
|
27
|
+
extracted.captures[0]
|
28
|
+
else
|
29
|
+
'/'
|
30
|
+
end
|
31
|
+
regex_config['request.route'] = route_mapping
|
32
|
+
end
|
44
33
|
|
45
|
-
|
34
|
+
# Config mapping for request.ip_address
|
35
|
+
if defined? event.request.ip_address
|
36
|
+
regex_config['request.ip_address'] = event.request.ip_address
|
37
|
+
end
|
46
38
|
|
39
|
+
# Config mapping for response.status
|
40
|
+
if defined? event.response.status
|
41
|
+
regex_config['response.status'] = event.response.status
|
47
42
|
end
|
48
43
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
44
|
+
regex_config
|
45
|
+
end
|
46
|
+
|
47
|
+
def regex_match(event_value, condition_value)
|
48
|
+
# Function to perform the regex matching with event value and condition value
|
49
|
+
# Params:
|
50
|
+
# - event_value: Value associated with event (request)
|
51
|
+
# - condition_value: Value associated with the regex config condition
|
52
|
+
# Return:
|
53
|
+
# - regex_matched: Regex matched value to determine if the regex match was successful
|
54
|
+
|
55
|
+
extracted = Regexp.new(condition_value).match(event_value)
|
56
|
+
return if extracted.nil?
|
57
|
+
|
58
|
+
extracted.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
def fetch_sample_rate_on_regex_match(regex_configs, config_mapping)
|
62
|
+
# Function to fetch the sample rate and determine if request needs to be block or not
|
63
|
+
# Args:
|
64
|
+
# - regex_configs: Regex configs
|
65
|
+
# - config_mapping: Config associated with the request
|
66
|
+
# Return:
|
67
|
+
# - sample_rate: Sample rate
|
68
|
+
|
69
|
+
# Iterate through the list of regex configs
|
70
|
+
regex_configs.each do |regex_rule|
|
71
|
+
# Fetch the sample rate
|
72
|
+
sample_rate = regex_rule['sample_rate']
|
73
|
+
# Fetch the conditions
|
74
|
+
conditions = regex_rule['conditions']
|
75
|
+
# Bool flag to determine if the regex conditions are matched
|
76
|
+
regex_matched = false
|
77
|
+
# Create a table to hold the conditions mapping (path and value)
|
78
|
+
condition_table = {}
|
79
|
+
|
80
|
+
# Iterate through the regex rule conditions and map the path and value
|
81
|
+
conditions.each do |condition|
|
82
|
+
# Add condition path -> value to the condition table
|
83
|
+
condition_table[condition['path']] = condition['value']
|
84
|
+
end
|
85
|
+
|
86
|
+
# Iterate through conditions table and perform `and` operation between each conditions
|
87
|
+
condition_table.each do |path, values|
|
88
|
+
# Check if the path exists in the request config mapping
|
89
|
+
if !config_mapping[path].nil?
|
90
|
+
# Fetch the value of the path in request config mapping
|
91
|
+
event_data = config_mapping[path]
|
92
|
+
|
93
|
+
# Perform regex matching with event value
|
94
|
+
regex_matched = regex_match(event_data, values)
|
95
|
+
else
|
96
|
+
# Path does not exists in request config mapping, so no need to match regex condition rule
|
97
|
+
regex_matched = false
|
60
98
|
end
|
61
|
-
end
|
62
99
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
# - sample_rate: Sample rate
|
70
|
-
|
71
|
-
# Iterate through the list of regex configs
|
72
|
-
regex_configs.each { |regex_rule|
|
73
|
-
# Fetch the sample rate
|
74
|
-
sample_rate = regex_rule["sample_rate"]
|
75
|
-
# Fetch the conditions
|
76
|
-
conditions = regex_rule["conditions"]
|
77
|
-
# Bool flag to determine if the regex conditions are matched
|
78
|
-
regex_matched = false
|
79
|
-
# Create a table to hold the conditions mapping (path and value)
|
80
|
-
condition_table = {}
|
81
|
-
|
82
|
-
# Iterate through the regex rule conditions and map the path and value
|
83
|
-
conditions.each { |condition|
|
84
|
-
# Add condition path -> value to the condition table
|
85
|
-
condition_table[condition["path"]] = condition["value"]
|
86
|
-
}
|
87
|
-
|
88
|
-
# Iterate through conditions table and perform `and` operation between each conditions
|
89
|
-
condition_table.each do |path, values|
|
90
|
-
|
91
|
-
# Check if the path exists in the request config mapping
|
92
|
-
if !config_mapping[path].nil?
|
93
|
-
# Fetch the value of the path in request config mapping
|
94
|
-
event_data = config_mapping[path]
|
95
|
-
|
96
|
-
# Perform regex matching with event value
|
97
|
-
regex_matched = regex_match(event_data, values)
|
98
|
-
else
|
99
|
-
# Path does not exists in request config mapping, so no need to match regex condition rule
|
100
|
-
regex_matched = false
|
101
|
-
end
|
102
|
-
|
103
|
-
# If one of the rule does not match, skip the condition & avoid matching other rules for the same condition
|
104
|
-
if !regex_matched
|
105
|
-
break
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# If regex conditions matched, return sample rate
|
110
|
-
if regex_matched
|
111
|
-
return sample_rate
|
112
|
-
end
|
113
|
-
}
|
114
|
-
|
115
|
-
# If regex conditions are not matched, return sample rate as None and will use default sample rate
|
116
|
-
return nil
|
100
|
+
# If one of the rule does not match, skip the condition & avoid matching other rules for the same condition
|
101
|
+
break unless regex_matched
|
102
|
+
end
|
103
|
+
|
104
|
+
# If regex conditions matched, return sample rate
|
105
|
+
return sample_rate if regex_matched
|
117
106
|
end
|
118
107
|
|
108
|
+
# If regex conditions are not matched, return sample rate as None and will use default sample rate
|
109
|
+
nil
|
110
|
+
end
|
119
111
|
end
|
@@ -1,56 +1,52 @@
|
|
1
1
|
class CompanyHelper
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
puts e.response_code
|
17
|
-
end
|
18
|
-
end
|
19
|
-
else
|
20
|
-
puts "To update a company, a company_id field is required"
|
21
|
-
end
|
22
|
-
else
|
23
|
-
puts "Expecting the input to be of the type - dictionary while updating user"
|
2
|
+
def update_company(api_controller, debug, company_profile)
|
3
|
+
if company_profile.any?
|
4
|
+
if company_profile.key?('company_id')
|
5
|
+
begin
|
6
|
+
api_controller.update_company(MoesifApi::CompanyModel.from_hash(company_profile))
|
7
|
+
puts 'Update Company Successfully' if debug
|
8
|
+
rescue MoesifApi::APIException => e
|
9
|
+
if e.response_code.between?(401, 403)
|
10
|
+
puts 'Unathorized accesss updating company to Moesif. Please verify your Application Id.'
|
11
|
+
end
|
12
|
+
if debug
|
13
|
+
puts 'Error updating company to Moesif, with status code: '
|
14
|
+
puts e.response_code
|
15
|
+
end
|
24
16
|
end
|
17
|
+
else
|
18
|
+
puts 'To update a company, a company_id field is required'
|
19
|
+
end
|
20
|
+
else
|
21
|
+
puts 'Expecting the input to be of the type - dictionary while updating user'
|
25
22
|
end
|
23
|
+
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
def update_companies_batch(api_controller, debug, company_profiles)
|
26
|
+
companyModels = []
|
27
|
+
company_profiles.each do |company|
|
28
|
+
if company.key?('company_id')
|
29
|
+
companyModels << MoesifApi::CompanyModel.from_hash(company)
|
30
|
+
else
|
31
|
+
puts 'To update a company, a company_id field is required'
|
32
|
+
end
|
33
|
+
end
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
puts "Error updating companies to Moesif, with status code: "
|
49
|
-
puts e.response_code
|
50
|
-
end
|
51
|
-
end
|
52
|
-
else
|
53
|
-
puts "Expecting the input to be of the type - Array of hashes while updating companies in batch"
|
35
|
+
if companyModels.any?
|
36
|
+
begin
|
37
|
+
api_controller.update_companies_batch(companyModels)
|
38
|
+
puts 'Update Companies Successfully' if debug
|
39
|
+
rescue MoesifApi::APIException => e
|
40
|
+
if e.response_code.between?(401, 403)
|
41
|
+
puts 'Unathorized accesss updating companies to Moesif. Please verify your Application Id.'
|
42
|
+
end
|
43
|
+
if debug
|
44
|
+
puts 'Error updating companies to Moesif, with status code: '
|
45
|
+
puts e.response_code
|
54
46
|
end
|
47
|
+
end
|
48
|
+
else
|
49
|
+
puts 'Expecting the input to be of the type - Array of hashes while updating companies in batch'
|
55
50
|
end
|
51
|
+
end
|
56
52
|
end
|
@@ -1,56 +1,52 @@
|
|
1
1
|
class UserHelper
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
puts e.response_code
|
17
|
-
end
|
18
|
-
end
|
19
|
-
else
|
20
|
-
puts "To update an user, an user_id field is required"
|
21
|
-
end
|
22
|
-
else
|
23
|
-
puts "Expecting the input to be of the type - dictionary while updating user"
|
2
|
+
def update_user(api_controller, debug, user_profile)
|
3
|
+
if user_profile.any?
|
4
|
+
if user_profile.key?('user_id')
|
5
|
+
begin
|
6
|
+
api_controller.update_user(MoesifApi::UserModel.from_hash(user_profile))
|
7
|
+
puts 'Update User Successfully' if debug
|
8
|
+
rescue MoesifApi::APIException => e
|
9
|
+
if e.response_code.between?(401, 403)
|
10
|
+
puts 'Unathorized accesss updating user to Moesif. Please verify your Application Id.'
|
11
|
+
end
|
12
|
+
if debug
|
13
|
+
puts 'Error updating user to Moesif, with status code: '
|
14
|
+
puts e.response_code
|
15
|
+
end
|
24
16
|
end
|
17
|
+
else
|
18
|
+
puts 'To update an user, an user_id field is required'
|
19
|
+
end
|
20
|
+
else
|
21
|
+
puts 'Expecting the input to be of the type - dictionary while updating user'
|
25
22
|
end
|
23
|
+
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
def update_users_batch(api_controller, debug, user_profiles)
|
26
|
+
userModels = []
|
27
|
+
user_profiles.each do |user|
|
28
|
+
if user.key?('user_id')
|
29
|
+
userModels << MoesifApi::UserModel.from_hash(user)
|
30
|
+
else
|
31
|
+
puts 'To update an user, an user_id field is required'
|
32
|
+
end
|
33
|
+
end
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
puts "Error updating user to Moesif, with status code: "
|
49
|
-
puts e.response_code
|
50
|
-
end
|
51
|
-
end
|
52
|
-
else
|
53
|
-
puts "Expecting the input to be of the type - Array of hashes while updating users in batch"
|
35
|
+
if userModels.any?
|
36
|
+
begin
|
37
|
+
api_controller.update_users_batch(userModels)
|
38
|
+
puts 'Update Users Successfully' if debug
|
39
|
+
rescue MoesifApi::APIException => e
|
40
|
+
if e.response_code.between?(401, 403)
|
41
|
+
puts 'Unathorized accesss updating user to Moesif. Please verify your Application Id.'
|
42
|
+
end
|
43
|
+
if debug
|
44
|
+
puts 'Error updating user to Moesif, with status code: '
|
45
|
+
puts e.response_code
|
54
46
|
end
|
47
|
+
end
|
48
|
+
else
|
49
|
+
puts 'Expecting the input to be of the type - Array of hashes while updating users in batch'
|
55
50
|
end
|
51
|
+
end
|
56
52
|
end
|
@@ -1,29 +1,26 @@
|
|
1
1
|
require 'time'
|
2
2
|
|
3
3
|
module Net
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def request(request, body = nil, &block)
|
4
|
+
class HTTP
|
5
|
+
alias orig_request request unless method_defined?(:orig_request)
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# URL
|
13
|
-
url = "https://#{@address}#{request.path}"
|
7
|
+
def request(request, body = nil, &block)
|
8
|
+
# Request Start Time
|
9
|
+
request_time = Time.now.utc.iso8601(3)
|
14
10
|
|
15
|
-
|
16
|
-
|
11
|
+
# URL
|
12
|
+
url = "https://#{@address}#{request.path}"
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
14
|
+
# Response
|
15
|
+
@response = orig_request(request, body, &block)
|
16
|
+
|
17
|
+
# Response Time
|
18
|
+
response_time = Time.now.utc.iso8601(3)
|
19
|
+
|
20
|
+
# Log Event to Moesif
|
21
|
+
MoesifCaptureOutgoing.call(url, request, request_time, @response, response_time) if started?
|
22
|
+
|
23
|
+
@response
|
28
24
|
end
|
29
25
|
end
|
26
|
+
end
|