Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
GustavoCaso committed Aug 31, 2023
1 parent 85ff055 commit d1bf510
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 15 deletions.
7 changes: 4 additions & 3 deletions lib/datadog/appsec/contrib/rack/gateway/watcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ def watch
def watch_request(gateway = Instrumentation.gateway)
gateway.watch('rack.request', :appsec) do |stack, gateway_request|
block = false
actions = []
event = nil
scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY]

AppSec::Reactive::Operation.new('rack.request') do |op|
Rack::Reactive::Request.subscribe(op, scope.processor_context) do |result, _block|
Rack::Reactive::Request.subscribe(op, scope.processor_context) do |result|
if result.status == :match
# TODO: should this hash be an Event instance instead?
event = {
Expand All @@ -48,10 +49,10 @@ def watch_request(gateway = Instrumentation.gateway)
end
end

_result, block = Rack::Reactive::Request.publish(op, gateway_request)
actions, block = Rack::Reactive::Request.publish(op, gateway_request)
end

next [nil, [[:block, event]]] if block
next [nil, [[:block, actions]]] if block

ret, res = stack.call(gateway_request.request)

Expand Down
8 changes: 4 additions & 4 deletions lib/datadog/appsec/contrib/rack/reactive/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ def self.subscribe(op, waf_context)
when :match
Datadog.logger.debug { "WAF: #{result.inspect}" }

block = result.actions.include?('block')
unless result.actions.empty?
yield result

yield [result, block]

throw(:block, [result, true]) if block
throw(:block, [result.actions, true])
end
when :ok
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
when :invalid_call
Expand Down
8 changes: 4 additions & 4 deletions lib/datadog/appsec/contrib/rack/reactive/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ def self.subscribe(op, waf_context)
when :match
Datadog.logger.debug { "WAF: #{result.inspect}" }

block = result.actions.include?('block')
unless result.actions.empty?
yield [result, result.actions]

yield [result, block]

throw(:block, [result, true]) if block
throw(:block, [result, true])
end
when :ok
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
when :invalid_call
Expand Down
5 changes: 3 additions & 2 deletions lib/datadog/appsec/contrib/rack/request_middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ def call(env)
end
end

if request_response && request_response.any? { |action, _event| action == :block }
request_return = AppSec::Response.negotiate(env).to_rack
if request_response
response_options = request_response.any? { |action, _options| action == :block }
request_return = AppSec::Response.negotiate(env, response_options.last).to_rack if response_options
end

gateway_response = Gateway::Response.new(
Expand Down
5 changes: 5 additions & 0 deletions lib/datadog/appsec/remote.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class << self
CAP_ASM_RESPONSE_BLOCKING,
CAP_ASM_DD_RULES,
CAP_ASM_CUSTOM_RULES,
CAP_ASM_CUSTOM_BLOCKING_RESPONSE,
].freeze

ASM_PRODUCTS = [
Expand Down Expand Up @@ -63,6 +64,7 @@ def receivers
data = []
overrides = []
exclusions = []
actions = []

repository.contents.each do |content|
parsed_content = parse_content(content)
Expand All @@ -76,6 +78,7 @@ def receivers
overrides << parsed_content['rules_override'] if parsed_content['rules_override']
exclusions << parsed_content['exclusions'] if parsed_content['exclusions']
custom_rules << parsed_content['custom_rules'] if parsed_content['custom_rules']
actions << parsed_content['actions'] if parsed_content['actions']
end
end

Expand All @@ -95,6 +98,8 @@ def receivers
custom_rules: custom_rules,
)

Datadog::AppSec::Processor.actions(actions) unless actions.empty?

Datadog::AppSec.reconfigure(ruleset: ruleset)
end

Expand Down
69 changes: 67 additions & 2 deletions lib/datadog/appsec/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,27 @@ def to_action_dispatch_response
end

class << self
def negotiate(env)
def negotiate(env, options)
actions = Processor.get_actions

configured_response = options.each do |action|
response_option = actions[action]
next unless response_option

case action
when 'block'
block_response
when 'redirect_request'
redirect_response
end
end

configured_response || default_response(env)
end

private

def default_response(env)
content_type = content_type(env)

Datadog.logger.debug { "negotiated response content type: #{content_type}" }
Expand All @@ -43,14 +63,59 @@ def negotiate(env)
)
end

private
def block_respons(env, options)
content_type = if options['type'] == 'auto'
content_type(env)
else
FORMAT_TO_CONTENT_TYPE[options['type']]
end

Datadog.logger.debug { "negotiated response content type: #{content_type}" }

body = []
body << content(options['type'])

Response.new(
status: options['status'] || 403,
headers: { 'Content-Type' => content_type },
body: body,
)
end

def redirect_response(env, options)
if options['location']
content_type = content_type(env)

status = options['status'].start_with?(3) ? options['status'] : 303

Datadog.logger.debug { "negotiated response content type: #{content_type}" }

headers = {
'Content-Type' => content_type,
'Location' => options['location']
}

Response.new(
status: status,
headers: headers,
body: [],
)
else
default_response(env)
end
end

CONTENT_TYPE_TO_FORMAT = {
'application/json' => :json,
'text/html' => :html,
'text/plain' => :text,
}.freeze

FORMAT_TO_CONTENT_TYPE = {
'json' => 'application/json',
'html' => 'text/html',
}.freeze

DEFAULT_CONTENT_TYPE = 'application/json'

def content_type(env)
Expand Down

0 comments on commit d1bf510

Please sign in to comment.