newrelic_security 0.1.0 → 0.3.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/pr_ci.yml +2 -2
  3. data/CHANGELOG.md +82 -0
  4. data/THIRD_PARTY_NOTICES.md +8 -0
  5. data/lib/newrelic_security/agent/agent.rb +24 -4
  6. data/lib/newrelic_security/agent/configuration/manager.rb +51 -8
  7. data/lib/newrelic_security/agent/control/app_info.rb +2 -0
  8. data/lib/newrelic_security/agent/control/application_runtime_error.rb +95 -0
  9. data/lib/newrelic_security/agent/control/application_url_mappings.rb +2 -0
  10. data/lib/newrelic_security/agent/control/collector.rb +34 -3
  11. data/lib/newrelic_security/agent/control/control_command.rb +2 -3
  12. data/lib/newrelic_security/agent/control/critical_message.rb +2 -0
  13. data/lib/newrelic_security/agent/control/error_reporting.rb +74 -0
  14. data/lib/newrelic_security/agent/control/event.rb +26 -4
  15. data/lib/newrelic_security/agent/control/event_processor.rb +26 -0
  16. data/lib/newrelic_security/agent/control/event_subscriber.rb +2 -8
  17. data/lib/newrelic_security/agent/control/exit_event.rb +2 -0
  18. data/lib/newrelic_security/agent/control/grpc_context.rb +2 -1
  19. data/lib/newrelic_security/agent/control/health_check.rb +5 -0
  20. data/lib/newrelic_security/agent/control/http_context.rb +16 -7
  21. data/lib/newrelic_security/agent/control/iast_client.rb +24 -11
  22. data/lib/newrelic_security/agent/control/iast_data_transfer_request.rb +2 -0
  23. data/lib/newrelic_security/agent/control/scan_scheduler.rb +77 -0
  24. data/lib/newrelic_security/agent/control/websocket_client.rb +23 -0
  25. data/lib/newrelic_security/agent/utils/agent_utils.rb +14 -9
  26. data/lib/newrelic_security/constants.rb +2 -2
  27. data/lib/newrelic_security/instrumentation-security/async-http/instrumentation.rb +2 -13
  28. data/lib/newrelic_security/instrumentation-security/curb/instrumentation.rb +1 -14
  29. data/lib/newrelic_security/instrumentation-security/ethon/chain.rb +0 -6
  30. data/lib/newrelic_security/instrumentation-security/ethon/instrumentation.rb +7 -42
  31. data/lib/newrelic_security/instrumentation-security/ethon/prepend.rb +0 -4
  32. data/lib/newrelic_security/instrumentation-security/excon/instrumentation.rb +3 -13
  33. data/lib/newrelic_security/instrumentation-security/grape/chain.rb +7 -2
  34. data/lib/newrelic_security/instrumentation-security/grape/instrumentation.rb +3 -1
  35. data/lib/newrelic_security/instrumentation-security/grape/prepend.rb +7 -1
  36. data/lib/newrelic_security/instrumentation-security/grpc/server/instrumentation.rb +3 -2
  37. data/lib/newrelic_security/instrumentation-security/httpclient/instrumentation.rb +4 -28
  38. data/lib/newrelic_security/instrumentation-security/httprb/instrumentation.rb +1 -12
  39. data/lib/newrelic_security/instrumentation-security/httpx/instrumentation.rb +1 -15
  40. data/lib/newrelic_security/instrumentation-security/instrumentation_utils.rb +0 -17
  41. data/lib/newrelic_security/instrumentation-security/net_http/instrumentation.rb +6 -23
  42. data/lib/newrelic_security/instrumentation-security/net_ldap/instrumentation.rb +1 -1
  43. data/lib/newrelic_security/instrumentation-security/padrino/chain.rb +17 -0
  44. data/lib/newrelic_security/instrumentation-security/padrino/instrumentation.rb +15 -2
  45. data/lib/newrelic_security/instrumentation-security/padrino/prepend.rb +12 -0
  46. data/lib/newrelic_security/instrumentation-security/patron/instrumentation.rb +2 -15
  47. data/lib/newrelic_security/instrumentation-security/rails/chain.rb +26 -2
  48. data/lib/newrelic_security/instrumentation-security/rails/instrumentation.rb +29 -3
  49. data/lib/newrelic_security/instrumentation-security/rails/prepend.rb +18 -0
  50. data/lib/newrelic_security/instrumentation-security/roda/chain.rb +7 -2
  51. data/lib/newrelic_security/instrumentation-security/roda/instrumentation.rb +3 -1
  52. data/lib/newrelic_security/instrumentation-security/roda/prepend.rb +7 -1
  53. data/lib/newrelic_security/instrumentation-security/sinatra/chain.rb +6 -0
  54. data/lib/newrelic_security/instrumentation-security/sinatra/instrumentation.rb +9 -0
  55. data/lib/newrelic_security/instrumentation-security/sinatra/prepend.rb +4 -0
  56. data/lib/newrelic_security/instrumentation-security/sqlite3/instrumentation.rb +4 -4
  57. data/lib/newrelic_security/newrelic-security-api/api.rb +1 -1
  58. data/lib/newrelic_security/parse-cron/cron_parser.rb +294 -0
  59. data/lib/newrelic_security/version.rb +1 -1
  60. data/newrelic_security.gemspec +1 -1
  61. metadata +8 -4
@@ -7,46 +7,25 @@ module NewRelic::Security
7
7
  module Ethon
8
8
  module Easy
9
9
 
10
- def fabricate_on_enter(url, action_name, options)
11
- NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
12
- NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[self.object_id] = { :method => action_name } if NewRelic::Security::Agent::Control::HTTPContext.get_context
13
- NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[self.object_id][:body] = options[:body] if NewRelic::Security::Agent::Control::HTTPContext.get_context
14
- rescue => exception
15
- NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
16
- ensure
17
- yield
18
- end
19
-
20
10
  def headers_equals_on_enter(headers)
21
11
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
22
- NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[self.object_id][:headers] = headers if NewRelic::Security::Agent::Control::HTTPContext.get_context && NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[self.object_id]
12
+ NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[object_id][:headers] = headers if NewRelic::Security::Agent::Control::HTTPContext.get_context && NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[object_id]
23
13
  rescue => exception
24
14
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
25
15
  ensure
26
16
  yield
27
17
  end
28
18
 
29
- def perform_on_enter(*args)
19
+ def perform_on_enter(*_args)
30
20
  event = nil
31
21
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
32
- context = NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[self.object_id] if NewRelic::Security::Agent::Control::HTTPContext.get_context
22
+ context = NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[object_id] if NewRelic::Security::Agent::Control::HTTPContext.get_context
33
23
  uri = ::URI.parse(url)
34
- ob = {}
35
- ob[:Method] = context[:method] if context
36
- ob[:scheme] = uri.scheme
37
- ob[:host] = uri.host
38
- ob[:port] = uri.port
39
- ob[:URI] = uri.to_s
40
- ob[:path] = uri.path
41
- ob[:query] = uri.query
42
- ob[:Body] = context[:body] if context
43
- ob[:Headers] = context[:headers] if context
44
- ob.each { |_, value| value.dup.force_encoding(ISO_8859_1).encode(UTF_8) if value.is_a?(String) }
45
- event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [ob])
24
+ event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [uri.to_s])
46
25
  headers_copy = {}
47
26
  headers_copy.merge!(context[:headers]) if context&.key?(:headers)
48
27
  NewRelic::Security::Instrumentation::InstrumentationUtils.add_tracing_data(headers_copy, event) if event
49
- self.headers = headers_copy if self.headers
28
+ self.headers = headers_copy if headers
50
29
  event
51
30
  rescue => exception
52
31
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
@@ -67,27 +46,13 @@ module NewRelic::Security
67
46
 
68
47
  module Multi
69
48
 
70
- def perform_on_enter(*args)
49
+ def perform_on_enter(*_args)
71
50
  event = nil
72
51
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
73
52
  ic_args = []
74
53
  easy_handles.each do |easy|
75
- context = NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[easy.object_id] if NewRelic::Security::Agent::Control::HTTPContext.get_context
76
54
  uri = NewRelic::Security::Instrumentation::InstrumentationUtils.parse_uri(easy.url)
77
- if uri
78
- ob = {}
79
- ob[:Method] = context[:method] if context
80
- ob[:scheme] = uri.scheme
81
- ob[:host] = uri.host
82
- ob[:port] = uri.port
83
- ob[:URI] = easy.url.to_s
84
- ob[:path] = uri.path
85
- ob[:query] = uri.query
86
- ob[:Body] = context[:body] if context
87
- ob[:Headers] = context[:headers] if context
88
- ob.each { |_, value| value.dup.force_encoding(ISO_8859_1).encode(UTF_8) if value.is_a?(String) }
89
- ic_args << ob
90
- end
55
+ ic_args << easy.url.to_s if uri
91
56
  end
92
57
  event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, ic_args) unless ic_args.empty?
93
58
  easy_handles.each do |easy|
@@ -4,10 +4,6 @@ module NewRelic::Security
4
4
  module Easy
5
5
  module Prepend
6
6
  include NewRelic::Security::Instrumentation::Ethon::Easy
7
-
8
- def fabricate(url, action_name, options)
9
- fabricate_on_enter(url, action_name, options) { return super }
10
- end
11
7
 
12
8
  def headers=(headers)
13
9
  headers_equals_on_enter(headers) { return super }
@@ -5,21 +5,11 @@ module NewRelic::Security
5
5
  module Instrumentation
6
6
  module Excon::Connection
7
7
 
8
- def request_on_enter(params)
8
+ def request_on_enter(_params)
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
- ob = {}
12
- ob[:Method] = params[:method]
13
- ob[:scheme] = self.data[:scheme]
14
- ob[:host] = self.data[:host]
15
- ob[:port] = self.data[:port]
16
- ob[:URI] = self.data[:query].nil? ? "#{self.data[:host]}#{self.data[:path]}" : "#{self.data[:host]}#{self.data[:path]}?#{self.data[:query]}"
17
- ob[:path] = self.data[:path]
18
- ob[:query] = self.data[:query]
19
- ob[:Body] = self.data[:body]
20
- ob[:Headers] = self.data[:headers]
21
- ob.each { |_, value| value.dup.force_encoding(ISO_8859_1).encode(UTF_8) if value.is_a?(String) }
22
- event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [ob])
11
+ uri = "#{self.data[:scheme]}://#{self.data[:host]}#{self.data[:path]}"
12
+ event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [uri])
23
13
  NewRelic::Security::Instrumentation::InstrumentationUtils.add_tracing_data(self.data[:headers], event) if event
24
14
  event
25
15
  rescue => exception
@@ -12,10 +12,15 @@ module NewRelic::Security
12
12
 
13
13
  def call(env)
14
14
  retval = nil
15
- event = call_on_enter(env) { retval = call_without_security(env) }
15
+ event = call_on_enter(env) do
16
+ begin
17
+ retval = call_without_security(env)
18
+ ensure
19
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, nil)
20
+ end
21
+ end
16
22
  call_on_exit(event, retval) { return retval }
17
23
  end
18
-
19
24
  end
20
25
  end
21
26
  end
@@ -8,6 +8,7 @@ module NewRelic::Security
8
8
  def call_on_enter(env)
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
+ return unless NewRelic::Security::Agent.config[:enabled]
11
12
  NewRelic::Security::Agent.config.update_port = NewRelic::Security::Agent::Utils.app_port(env) unless NewRelic::Security::Agent.config[:listen_port]
12
13
  NewRelic::Security::Agent::Utils.get_app_routes(:grape) if NewRelic::Security::Agent.agent.route_map.empty?
13
14
  NewRelic::Security::Agent::Control::HTTPContext.set_context(env)
@@ -24,6 +25,7 @@ module NewRelic::Security
24
25
  # NewRelic::Security::Agent.logger.debug "\n\nHTTP Context : #{::NewRelic::Agent::Tracer.current_transaction.instance_variable_get(:@security_context_data).inspect}\n\n"
25
26
  NewRelic::Security::Agent::Control::ReflectedXSS.check_xss(NewRelic::Security::Agent::Control::HTTPContext.get_context, retval) if NewRelic::Security::Agent.config[:'security.detection.rxss.enabled']
26
27
  NewRelic::Security::Agent::Utils.delete_created_files(NewRelic::Security::Agent::Control::HTTPContext.get_context)
28
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, retval[0])
27
29
  NewRelic::Security::Agent::Control::HTTPContext.reset_context
28
30
  NewRelic::Security::Agent.logger.debug "Exit event : #{event}"
29
31
  rescue => exception
@@ -40,7 +42,7 @@ module NewRelic::Security
40
42
  def prepare_env_from_route_on_enter(route)
41
43
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
42
44
  ctxt = NewRelic::Security::Agent::Control::HTTPContext.get_context
43
- http_method = route.instance_variable_get(:@request_method) ? route.instance_variable_get(:@request_method) : route.instance_variable_get(:@options)[:method]
45
+ http_method = route.instance_variable_get(:@request_method) || route.instance_variable_get(:@options)[:method]
44
46
  ctxt.route = "#{http_method}@#{route.options[:namespace]}" unless ctxt.nil?
45
47
  rescue => exception
46
48
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
@@ -8,7 +8,13 @@ module NewRelic::Security
8
8
 
9
9
  def call(env)
10
10
  retval = nil
11
- event = call_on_enter(env) { retval = super(env) }
11
+ event = call_on_enter(env) do
12
+ begin
13
+ retval = super(env)
14
+ ensure
15
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, nil)
16
+ end
17
+ end
12
18
  call_on_exit(event, retval) { return retval }
13
19
  end
14
20
 
@@ -6,7 +6,7 @@ module NewRelic::Security
6
6
  module Instrumentation
7
7
  module GRPC
8
8
  module RpcDesc
9
- def grpc_server_on_enter(active_call, mth, inter_ctx, is_grpc_client_stream, is_grpc_server_stream)
9
+ def grpc_server_on_enter(active_call, mth, _inter_ctx, is_grpc_client_stream, is_grpc_server_stream)
10
10
  event = nil
11
11
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
12
12
  grpc_request = {}
@@ -14,10 +14,11 @@ module NewRelic::Security
14
14
  grpc_request[:peer] = active_call.peer
15
15
  # puts "mth : #{mth.class} #{mth.methods}"
16
16
  # puts "mth :#{mth.original_name}, #{mth.to_s}, #{mth.name}, #{mth.receiver}, #{mth.parameters}, #{mth.owner}, #{mth.unbind}, #{mth.super_method},, #{mth.instance_variables}"
17
+ NewRelic::Security::Agent::Utils.get_app_routes(:grpc, mth) if NewRelic::Security::Agent.agent.route_map.empty?
17
18
  grpc_request[:method] = "#{mth.owner}/#{mth.original_name}"
18
19
  grpc_request[:is_grpc_client_stream] = is_grpc_client_stream
19
20
  grpc_request[:is_grpc_server_stream] = is_grpc_server_stream
20
- is_grpc_client_stream ? grpc_request[:body] = [] : grpc_request[:body] = ::String.new
21
+ grpc_request[:body] = is_grpc_client_stream ? [] : ::String.new
21
22
  NewRelic::Security::Agent::Control::GRPCContext.set_context(grpc_request)
22
23
  NewRelic::Security::Agent::Utils.parse_fuzz_header(NewRelic::Security::Agent::Control::GRPCContext.get_context)
23
24
  rescue => exception
@@ -8,20 +8,8 @@ module NewRelic::Security
8
8
  def do_request_on_enter(method, uri, query, body, header)
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
- ob = {}
12
- ob[:Method] = method
13
- unless uri.nil?
14
- ob[:scheme] = uri.scheme
15
- ob[:host] = uri.host
16
- ob[:port] = uri.port
17
- ob[:URI] = uri.to_s
18
- ob[:path] = uri.path
19
- ob[:query] = uri.query
20
- end
21
- ob[:Body] = body
22
- ob[:Headers] = header
23
- ob.each { |_, value| value.dup.force_encoding(ISO_8859_1).encode(UTF_8) if value.is_a?(String) }
24
- event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [ob])
11
+ uri_s = uri.to_s unless uri.nil?
12
+ event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [uri_s])
25
13
  NewRelic::Security::Instrumentation::InstrumentationUtils.add_tracing_data(header, event) if event
26
14
  event
27
15
  rescue => exception
@@ -43,20 +31,8 @@ module NewRelic::Security
43
31
  def do_request_async_on_enter(method, uri, query, body, header)
44
32
  event = nil
45
33
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
46
- ob = {}
47
- ob[:Method] = method
48
- unless uri.nil?
49
- ob[:scheme] = uri.scheme
50
- ob[:host] = uri.host
51
- ob[:port] = uri.port
52
- ob[:URI] = uri.to_s
53
- ob[:path] = uri.path
54
- ob[:query] = uri.query
55
- end
56
- ob[:Body] = body
57
- ob[:Headers] = header
58
- ob.each { |_, value| value.dup.force_encoding(ISO_8859_1).encode(UTF_8) if value.is_a?(String) }
59
- event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [ob])
34
+ uri_s = uri.to_s unless uri.nil?
35
+ event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [uri_s])
60
36
  NewRelic::Security::Instrumentation::InstrumentationUtils.add_tracing_data(header, event) if event
61
37
  event
62
38
  rescue => exception
@@ -8,19 +8,8 @@ module NewRelic::Security
8
8
  def perform_on_enter(request, options)
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
- ob = {}
12
- ob[:Method] = request.verb
13
- ob[:scheme] = request.scheme
14
- ob[:host] = request.uri.host
15
- ob[:port] = request.uri.port
16
- ob[:URI] = request.uri.to_s
17
- ob[:path] = request.uri.path
18
- ob[:query] = request.uri.query
19
- ob[:Body] = request.body.source.to_s
20
- ob[:Headers] = options.headers.to_h
21
- event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [ob])
11
+ event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [request.uri.to_s])
22
12
  NewRelic::Security::Instrumentation::InstrumentationUtils.add_tracing_data(options.headers, event) if event
23
- ob = nil
24
13
  event
25
14
  rescue => exception
26
15
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
@@ -9,21 +9,7 @@ module NewRelic::Security
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
11
  ic_args = []
12
- args.each do |arg|
13
- ob = {}
14
- ob[:Method] = arg.verb
15
- uri = arg.uri
16
- ob[:scheme] = uri.scheme
17
- ob[:host] = uri.host
18
- ob[:port] = uri.port
19
- ob[:URI] = uri.to_s
20
- ob[:path] = uri.path
21
- ob[:query] = uri.query
22
- ob[:Body] = arg.body.bytesize.positive? ? arg.body.to_s : ""
23
- ob[:Headers] = arg.headers
24
- ob.each { |_, value| value.dup.force_encoding(ISO_8859_1).encode(UTF_8) if value.is_a?(String) }
25
- ic_args << ob
26
- end
12
+ args.each { |arg| ic_args << arg.uri.to_s }
27
13
  event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, ic_args)
28
14
  args.each do |arg|
29
15
  NewRelic::Security::Instrumentation::InstrumentationUtils.add_tracing_data(arg.headers, event) if event
@@ -143,23 +143,6 @@ module NewRelic::Security
143
143
  return nil
144
144
  end
145
145
 
146
- def parse_typhoeus_request(request)
147
- ob = {}
148
- ob[:Method] = request.options[:method].nil? ? :get : request.options[:method]
149
- ob[:URI] = request.base_url
150
- ob[:Body] = request.options[:body]
151
- ob[:Headers] = request.options[:headers]
152
- uri_parsed = parse_uri(request.base_url)
153
- if !uri_parsed.nil?
154
- ob[:scheme] = uri_parsed.scheme
155
- ob[:host] = uri_parsed.host
156
- ob[:port] = uri_parsed.port
157
- ob[:path] = uri_parsed.path
158
- ob[:query] = uri_parsed.query
159
- end
160
- ob
161
- end
162
-
163
146
  end
164
147
  end
165
148
  end
@@ -13,30 +13,13 @@ module NewRelic::Security
13
13
  def transport_request_on_enter(req)
14
14
  event = nil
15
15
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
16
- ob = {}
17
- ob[:Method] = req.method
18
- if req.uri != nil && URI === req.uri
19
- uri = req.uri
20
- ob[:scheme] = uri.scheme
21
- ob[:host] = uri.host
22
- ob[:port] = uri.port
23
- ob[:URI] = uri.to_s
24
- ob[:path] = uri.path
25
- ob[:query] = uri.query
26
- else
27
- ob[:scheme] = self.use_ssl? ? HTTPS : HTTP
28
- ob[:host] = self.address
29
- ob[:port] = self.port
30
- ob[:path] = req.path
31
- ob[:query] = nil
32
- ob[:URI] = "#{self.use_ssl? ? HTTPS_COLON_SLASH_SLAH : HTTP_COLON_SLASH_SLAH }#{self.address}:#{self.port}#{req.path}"
33
- end
34
- ob[:Body] = req.body
35
- ob[:Headers] = req.to_hash.transform_values! { |v| v.join}
36
- ob.each { |_, value| value.dup.force_encoding(ISO_8859_1).encode(UTF_8) if value.is_a?(String) }
37
- event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [ob])
16
+ uri = if req.uri && URI === req.uri
17
+ req.uri.to_s
18
+ else
19
+ "#{self.use_ssl? ? HTTPS_COLON_SLASH_SLAH : HTTP_COLON_SLASH_SLAH }#{self.address}:#{self.port}#{req.path}"
20
+ end
21
+ event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [uri])
38
22
  NewRelic::Security::Instrumentation::InstrumentationUtils.add_tracing_data(req, event) if event
39
- ob = nil
40
23
  event
41
24
  rescue => exception
42
25
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
@@ -18,7 +18,7 @@ module NewRelic::Security
18
18
  # to know the capabilities of Ldap server. In these
19
19
  # situations they don't provide the query parameter, so we filter
20
20
  # this event
21
- NewRelic::Security::Agent.logger.info "Filtered #{self.class}.#{__method__} because of insufficient args. args : #{args}\n"
21
+ NewRelic::Security::Agent.logger.debug "Filtered #{self.class}.#{__method__} because of insufficient args. args : #{args}\n"
22
22
  end
23
23
  rescue => exception
24
24
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
@@ -21,6 +21,23 @@ module NewRelic::Security
21
21
  end
22
22
  end
23
23
  end
24
+
25
+ module Router
26
+ module Chain
27
+ def self.instrument!
28
+ ::Padrino::Router.class_eval do
29
+ include NewRelic::Security::Instrumentation::Padrino::Router
30
+
31
+ alias_method :call_without_security, :call
32
+
33
+ def call(env, &block)
34
+ retval = call_without_security(env, &block)
35
+ call_on_exit(retval) { return retval }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
24
41
  end
25
42
  end
26
43
  end
@@ -8,12 +8,13 @@ module NewRelic::Security
8
8
  def call_on_enter(env)
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
+ return unless NewRelic::Security::Agent.config[:enabled]
11
12
  NewRelic::Security::Agent.config.update_port = NewRelic::Security::Agent::Utils.app_port(env) unless NewRelic::Security::Agent.config[:listen_port]
12
13
  NewRelic::Security::Agent::Utils.get_app_routes(:padrino, self) if NewRelic::Security::Agent.agent.route_map.empty?
13
14
  extracted_env = env.instance_variable_get(:@env)
14
15
  NewRelic::Security::Agent::Control::HTTPContext.set_context(extracted_env)
15
16
  ctxt = NewRelic::Security::Agent::Control::HTTPContext.get_context
16
- ctxt.route = "#{extracted_env[REQUEST_METHOD].to_s}@#{extracted_env[PATH_INFO].to_s}" if ctxt
17
+ ctxt.route = "#{extracted_env[REQUEST_METHOD]}@#{extracted_env[PATH_INFO]}" if ctxt
17
18
  NewRelic::Security::Agent::Utils.parse_fuzz_header(NewRelic::Security::Agent::Control::HTTPContext.get_context)
18
19
  rescue => exception
19
20
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
@@ -27,6 +28,7 @@ module NewRelic::Security
27
28
  # NewRelic::Security::Agent.logger.debug "\n\nHTTP Context : #{::NewRelic::Agent::Tracer.current_transaction.instance_variable_get(:@security_context_data).inspect}\n\n"
28
29
  NewRelic::Security::Agent::Control::ReflectedXSS.check_xss(NewRelic::Security::Agent::Control::HTTPContext.get_context, retval) if NewRelic::Security::Agent.config[:'security.detection.rxss.enabled']
29
30
  NewRelic::Security::Agent::Utils.delete_created_files(NewRelic::Security::Agent::Control::HTTPContext.get_context)
31
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, retval[0])
30
32
  NewRelic::Security::Agent::Control::HTTPContext.reset_context
31
33
  NewRelic::Security::Agent.logger.debug "Exit event : #{event}"
32
34
  rescue => exception
@@ -34,9 +36,20 @@ module NewRelic::Security
34
36
  ensure
35
37
  yield
36
38
  end
37
-
39
+ end
40
+
41
+ module Padrino::Router
42
+ def call_on_exit(retval)
43
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
44
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, retval[0])
45
+ rescue => exception
46
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
47
+ ensure
48
+ yield
49
+ end
38
50
  end
39
51
  end
40
52
  end
41
53
 
42
54
  NewRelic::Security::Instrumentation::InstrumentationLoader.install_instrumentation(:padrino, ::Padrino::PathRouter::Router, ::NewRelic::Security::Instrumentation::Padrino::PathRouter::Router)
55
+ NewRelic::Security::Instrumentation::InstrumentationLoader.install_instrumentation(:padrino, ::Padrino::Router, ::NewRelic::Security::Instrumentation::Padrino::Router)
@@ -15,6 +15,18 @@ module NewRelic::Security
15
15
  end
16
16
  end
17
17
  end
18
+
19
+ module Router
20
+ module Prepend
21
+ include NewRelic::Security::Instrumentation::Padrino::Router
22
+
23
+ def call(env, &block)
24
+ retval = super
25
+ call_on_exit(retval) { return retval }
26
+ end
27
+
28
+ end
29
+ end
18
30
  end
19
31
  end
20
32
  end
@@ -7,25 +7,12 @@ module NewRelic::Security
7
7
  module Instrumentation
8
8
  module Patron::Session
9
9
 
10
- def request_on_enter(action, url, headers, options)
10
+ def request_on_enter(_action, url, headers, _options)
11
11
  event = nil
12
12
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
13
- ob = {}
14
- ob[:Method] = action
15
13
  final_url = self.base_url.nil? ? url : "#{self.base_url}#{url}"
16
14
  uri = NewRelic::Security::Instrumentation::InstrumentationUtils.parse_uri(final_url)
17
- if uri
18
- ob[:scheme] = uri.scheme
19
- ob[:host] = uri.host
20
- ob[:port] = uri.port
21
- ob[:URI] = uri.to_s
22
- ob[:path] = uri.path
23
- ob[:query] = uri.query
24
- ob[:Body] = options[:data]
25
- ob[:Headers] = headers
26
- ob.each { |_, value| value.dup.force_encoding(ISO_8859_1).encode(UTF_8) if value.is_a?(String) }
27
- event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [ob])
28
- end
15
+ event = NewRelic::Security::Agent::Control::Collector.collect(HTTP_REQUEST, [uri.to_s]) if uri
29
16
  NewRelic::Security::Instrumentation::InstrumentationUtils.add_tracing_data(headers, event) if event
30
17
  event
31
18
  rescue => exception
@@ -29,12 +29,36 @@ module NewRelic::Security
29
29
  include NewRelic::Security::Instrumentation::ActionDispatch::Journey::Router
30
30
 
31
31
  alias_method :find_routes_without_security, :find_routes
32
-
32
+
33
33
  def find_routes(req)
34
34
  retval = nil
35
35
  event = find_routes_on_enter(req) { retval = find_routes_without_security(req) }
36
36
  find_routes_on_exit(event, retval) { return retval }
37
- end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ module ActionDispatch
46
+ module Routing
47
+ module RouteSet
48
+ module Dispatcher
49
+ module Chain
50
+ def self.instrument!
51
+ ::ActionDispatch::Routing::RouteSet::Dispatcher.class_eval do
52
+ include NewRelic::Security::Instrumentation::ActionDispatch::Routing::RouteSet::Dispatcher
53
+
54
+ alias_method :serve_without_security, :serve
55
+
56
+ def serve(req)
57
+ retval = nil
58
+ event = serve_on_enter(req) { retval = serve_without_security(req) }
59
+ serve_on_exit(event, retval) { return retval }
60
+ end
61
+ end
38
62
  end
39
63
  end
40
64
  end
@@ -8,6 +8,7 @@ module NewRelic::Security
8
8
  def call_on_enter(env)
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
+ return unless NewRelic::Security::Agent.config[:enabled]
11
12
  NewRelic::Security::Agent.config.update_port = NewRelic::Security::Agent::Utils.app_port(env) unless NewRelic::Security::Agent.config[:listen_port]
12
13
  NewRelic::Security::Agent::Utils.get_app_routes(:rails) if NewRelic::Security::Agent.agent.route_map.empty?
13
14
  NewRelic::Security::Agent::Control::HTTPContext.set_context(env)
@@ -24,6 +25,7 @@ module NewRelic::Security
24
25
  # NewRelic::Security::Agent.logger.debug "\n\nHTTP Context : #{::NewRelic::Agent::Tracer.current_transaction.instance_variable_get(:@security_context_data).inspect}\n\n"
25
26
  NewRelic::Security::Agent::Control::ReflectedXSS.check_xss(NewRelic::Security::Agent::Control::HTTPContext.get_context, retval) if NewRelic::Security::Agent.config[:'security.detection.rxss.enabled']
26
27
  NewRelic::Security::Agent::Utils.delete_created_files(NewRelic::Security::Agent::Control::HTTPContext.get_context)
28
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, retval[0])
27
29
  NewRelic::Security::Agent::Control::HTTPContext.reset_context
28
30
  NewRelic::Security::Agent.logger.debug "Exit event : #{event}"
29
31
  rescue => exception
@@ -31,11 +33,11 @@ module NewRelic::Security
31
33
  ensure
32
34
  yield
33
35
  end
34
-
36
+
35
37
  end
36
38
 
37
39
  module ActionDispatch::Journey::Router
38
-
40
+
39
41
  def find_routes_on_enter(req)
40
42
  event = nil
41
43
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
@@ -45,7 +47,7 @@ module NewRelic::Security
45
47
  yield
46
48
  return event
47
49
  end
48
-
50
+
49
51
  def find_routes_on_exit(event, retval)
50
52
  NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
51
53
 
@@ -60,8 +62,32 @@ module NewRelic::Security
60
62
  yield
61
63
  end
62
64
  end
65
+
66
+ module ActionDispatch::Routing::RouteSet::Dispatcher
67
+
68
+ def serve_on_enter(req)
69
+ event = nil
70
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
71
+ ctxt = NewRelic::Security::Agent::Control::HTTPContext.get_context
72
+ ctxt.route = "#{ctxt.method}@#{req.route_uri_pattern.to_s.gsub(/\(\.:format\)/, EMPTY_STRING)}" if ctxt && req.respond_to?(:route_uri_pattern)
73
+ rescue => exception
74
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
75
+ ensure
76
+ yield
77
+ return event
78
+ end
79
+
80
+ def serve_on_exit(event, retval)
81
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
82
+ rescue => exception
83
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
84
+ ensure
85
+ yield
86
+ end
87
+ end
63
88
  end
64
89
  end
65
90
 
66
91
  NewRelic::Security::Instrumentation::InstrumentationLoader.install_instrumentation(:rails, ::Rails::Engine, ::NewRelic::Security::Instrumentation::Rails::Engine)
67
92
  NewRelic::Security::Instrumentation::InstrumentationLoader.install_instrumentation(:rails, ::ActionDispatch::Journey::Router, ::NewRelic::Security::Instrumentation::ActionDispatch::Journey::Router)
93
+ NewRelic::Security::Instrumentation::InstrumentationLoader.install_instrumentation(:rails, ::ActionDispatch::Routing::RouteSet::Dispatcher, ::NewRelic::Security::Instrumentation::ActionDispatch::Routing::RouteSet::Dispatcher)
@@ -29,5 +29,23 @@ module NewRelic::Security
29
29
  end
30
30
  end
31
31
  end
32
+
33
+ module ActionDispatch
34
+ module Routing
35
+ module RouteSet
36
+ module Dispatcher
37
+ module Prepend
38
+ include NewRelic::Security::Instrumentation::ActionDispatch::Routing::RouteSet::Dispatcher
39
+
40
+ def serve(req)
41
+ retval = nil
42
+ event = serve_on_enter(req) { retval = super }
43
+ serve_on_exit(event, retval) { return retval }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
32
50
  end
33
51
  end
@@ -10,10 +10,15 @@ module NewRelic::Security
10
10
 
11
11
  def _roda_handle_main_route(*args)
12
12
  retval = nil
13
- event = _roda_handle_main_route_on_enter(self.env) { retval = _roda_handle_main_route_without_security(*args) }
13
+ event = _roda_handle_main_route_on_enter(env) do
14
+ begin
15
+ retval = _roda_handle_main_route_without_security(*args)
16
+ ensure
17
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, nil)
18
+ end
19
+ end
14
20
  _roda_handle_main_route_on_exit(event, retval) { return retval }
15
21
  end
16
-
17
22
  end
18
23
  end
19
24
  end