newrelic_security 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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