Skip to content

Commit

Permalink
Add AppSec::ActionHandler module
Browse files Browse the repository at this point in the history
  • Loading branch information
y9v committed Jan 16, 2025
1 parent b5cf594 commit 5152ba7
Show file tree
Hide file tree
Showing 16 changed files with 165 additions and 254 deletions.
36 changes: 36 additions & 0 deletions lib/datadog/appsec/action_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

module Datadog
module AppSec
# this module encapsulates functions for handling actions that libddawf returns
module ActionHandler
module_function

def handle(type, action_params)
case type
when 'block_request' then block_request(action_params)
when 'redirect_request' then redirect_request(action_params)
when 'generate_stack' then generate_stack(action_params)
when 'generate_schema' then generate_schema(action_params)
when 'monitor' then monitor(action_params)
else
Datadog.logger.error "Unknown action type: #{type}"
end
end

def block_request(action_params)
throw(Datadog::AppSec::Ext::INTERRUPT, action_params)
end

def redirect_request(action_params)
throw(Datadog::AppSec::Ext::INTERRUPT, action_params)
end

def generate_stack(_action_params); end

def generate_schema(_action_params); end

def monitor(_action_params); end
end
end
end
1 change: 1 addition & 0 deletions lib/datadog/appsec/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative 'processor'
require_relative 'processor/rule_merger'
require_relative 'processor/rule_loader'
require_relative 'action_handler'

module Datadog
module AppSec
Expand Down
21 changes: 15 additions & 6 deletions lib/datadog/appsec/contrib/rack/gateway/watcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,14 @@ def watch_request(gateway = Instrumentation.gateway)
context.trace.keep! if context.trace
Datadog::AppSec::Event.tag_and_keep!(context, result)
context.events << event

result.actions.each do |action_type, action_params|
Datadog::AppSec::ActionHandler.handle(action_type, action_params)
end
end
end

block = Rack::Reactive::Request.publish(engine, gateway_request)
throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
Rack::Reactive::Request.publish(engine, gateway_request)

stack.call(gateway_request.request)
end
Expand All @@ -75,11 +78,14 @@ def watch_response(gateway = Instrumentation.gateway)
context.trace.keep! if context.trace
Datadog::AppSec::Event.tag_and_keep!(context, result)
context.events << event

result.actions.each do |action_type, action_params|
Datadog::AppSec::ActionHandler.handle(action_type, action_params)
end
end
end

block = Rack::Reactive::Response.publish(engine, gateway_response)
throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
Rack::Reactive::Response.publish(engine, gateway_response)

stack.call(gateway_response.response)
end
Expand All @@ -106,11 +112,14 @@ def watch_request_body(gateway = Instrumentation.gateway)
context.trace.keep! if context.trace
Datadog::AppSec::Event.tag_and_keep!(context, result)
context.events << event

result.actions.each do |action_type, action_params|
Datadog::AppSec::ActionHandler.handle(action_type, action_params)
end
end
end

block = Rack::Reactive::RequestBody.publish(engine, gateway_request)
throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
Rack::Reactive::RequestBody.publish(engine, gateway_request)

stack.call(gateway_request.request)
end
Expand Down
4 changes: 2 additions & 2 deletions lib/datadog/appsec/contrib/rack/request_body_middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ def call(env)
# TODO: handle exceptions, except for @app.call

http_response = nil
block_actions = catch(::Datadog::AppSec::Ext::INTERRUPT) do
block_action_params = catch(::Datadog::AppSec::Ext::INTERRUPT) do
http_response, = Instrumentation.gateway.push('rack.request.body', Gateway::Request.new(env)) do
@app.call(env)
end

nil
end

return AppSec::Response.negotiate(env, block_actions).to_rack if block_actions
return AppSec::Response.build(block_action_params, env['HTTP_ACCEPT']).to_rack if block_action_params

http_response
end
Expand Down
4 changes: 2 additions & 2 deletions lib/datadog/appsec/contrib/rack/request_middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def call(env)
gateway_request = Gateway::Request.new(env)
gateway_response = nil

block_actions = catch(::Datadog::AppSec::Ext::INTERRUPT) do
block_action_params = catch(::Datadog::AppSec::Ext::INTERRUPT) do
http_response, = Instrumentation.gateway.push('rack.request', gateway_request) do
@app.call(env)
end
Expand All @@ -90,7 +90,7 @@ def call(env)
nil
end

http_response = AppSec::Response.negotiate(env, block_actions).to_rack if block_actions
http_response = AppSec::Response.build(block_action_params, env['HTTP_ACCEPT']).to_rack if block_action_params

if AppSec.api_security_enabled?
ctx.events << {
Expand Down
7 changes: 5 additions & 2 deletions lib/datadog/appsec/contrib/rails/gateway/watcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ def watch_request_action(gateway = Instrumentation.gateway)
context.trace.keep! if context.trace
Datadog::AppSec::Event.tag_and_keep!(context, result)
context.events << event

result.actions.each do |action_type, action_params|
Datadog::AppSec::ActionHandler.handle(action_type, action_params)
end
end
end

block = Rails::Reactive::Action.publish(engine, gateway_request)
next [nil, [[:block, event]]] if block
Rails::Reactive::Action.publish(engine, gateway_request)

stack.call(gateway_request.request)
end
Expand Down
16 changes: 3 additions & 13 deletions lib/datadog/appsec/contrib/rails/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,12 @@ def process_action(*args)
# TODO: handle exceptions, except for super

gateway_request = Gateway::Request.new(request)
request_return, request_response = Instrumentation.gateway.push('rails.request.action', gateway_request) do
super
end

if request_response
blocked_event = request_response.find { |action, _options| action == :block }
if blocked_event
@_response = AppSec::Response.negotiate(
env,
blocked_event.last[:actions]
).to_action_dispatch_response
request_return = @_response.body
end
http_response, = Instrumentation.gateway.push('rails.request.action', gateway_request) do
super
end

request_return
http_response
end
end

Expand Down
14 changes: 0 additions & 14 deletions lib/datadog/appsec/contrib/sinatra/ext.rb

This file was deleted.

14 changes: 10 additions & 4 deletions lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ def watch_request_dispatch(gateway = Instrumentation.gateway)
context.trace.keep! if context.trace
Datadog::AppSec::Event.tag_and_keep!(context, result)
context.events << event

result.actions.each do |action_type, action_params|
Datadog::AppSec::ActionHandler.handle(action_type, action_params)
end
end
end

block = Rack::Reactive::RequestBody.publish(engine, gateway_request)
next [nil, [[:block, event]]] if block
Rack::Reactive::RequestBody.publish(engine, gateway_request)

stack.call(gateway_request.request)
end
Expand All @@ -73,11 +76,14 @@ def watch_request_routed(gateway = Instrumentation.gateway)
context.trace.keep! if context.trace
Datadog::AppSec::Event.tag_and_keep!(context, result)
context.events << event

result.actions.each do |action_type, action_params|
Datadog::AppSec::ActionHandler.handle(action_type, action_params)
end
end
end

block = Sinatra::Reactive::Routed.publish(engine, [gateway_request, gateway_route_params])
next [nil, [[:block, event]]] if block
Sinatra::Reactive::Routed.publish(engine, [gateway_request, gateway_route_params])

stack.call(gateway_request.request)
end
Expand Down
29 changes: 3 additions & 26 deletions lib/datadog/appsec/contrib/sinatra/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
require_relative '../../response'
require_relative '../rack/request_middleware'
require_relative 'framework'
require_relative 'ext'
require_relative 'gateway/watcher'
require_relative 'gateway/route_params'
require_relative 'gateway/request'
Expand Down Expand Up @@ -62,17 +61,8 @@ def dispatch!

gateway_request = Gateway::Request.new(env)

request_return, request_response = Instrumentation.gateway.push('sinatra.request.dispatch', gateway_request) do
# handle process_route interruption
catch(Datadog::AppSec::Contrib::Sinatra::Ext::ROUTE_INTERRUPT) { super }
end

if request_response
blocked_event = request_response.find { |action, _options| action == :block }
if blocked_event
self.response = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_sinatra_response
request_return = nil
end
request_return, = Instrumentation.gateway.push('sinatra.request.dispatch', gateway_request) do
super
end

request_return
Expand Down Expand Up @@ -103,20 +93,7 @@ def process_route(*)
gateway_request = Gateway::Request.new(env)
gateway_route_params = Gateway::RouteParams.new(route_params)

_, request_response = Instrumentation.gateway.push(
'sinatra.request.routed',
[gateway_request, gateway_route_params]
)

if request_response
blocked_event = request_response.find { |action, _options| action == :block }
if blocked_event
self.response = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_sinatra_response

# interrupt request and return response to dispatch! for consistency
throw(Datadog::AppSec::Contrib::Sinatra::Ext::ROUTE_INTERRUPT, response)
end
end
Instrumentation.gateway.push('sinatra.request.routed', [gateway_request, gateway_route_params])

yield(*args)
end
Expand Down
7 changes: 5 additions & 2 deletions lib/datadog/appsec/monitor/gateway/watcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@ def watch_user_id(gateway = Instrumentation.gateway)
context.trace.keep! if context.trace
Datadog::AppSec::Event.tag_and_keep!(context, result)
context.events << event

result.actions.each do |action_type, action_params|
Datadog::AppSec::ActionHandler.handle(action_type, action_params)
end
end
end

block = Monitor::Reactive::SetUser.publish(engine, user)
throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
Monitor::Reactive::SetUser.publish(engine, user)

stack.call(user)
end
Expand Down
Loading

0 comments on commit 5152ba7

Please sign in to comment.