Skip to content

Commit 303b640

Browse files
committed
Add session tracking to the devise contrib
1 parent 6bc684b commit 303b640

File tree

6 files changed

+383
-8
lines changed

6 files changed

+383
-8
lines changed

lib/datadog/appsec/contrib/devise/ext.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module Ext
1818
TAG_DD_LOGIN_FAILURE_MODE = '_dd.appsec.events.users.login.failure.auto.mode'
1919

2020
TAG_USR_ID = 'usr.id'
21+
TAG_SESSION_ID = 'usr.session_id'
2122
TAG_SIGNUP_TRACK = 'appsec.events.users.signup.track'
2223
TAG_SIGNUP_USR_ID = 'appsec.events.users.signup.usr.id'
2324
TAG_SIGNUP_USR_LOGIN = 'appsec.events.users.signup.usr.login'

lib/datadog/appsec/contrib/devise/tracking_middleware.rb

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Devise
1010
# A Rack middleware capable of tracking currently signed user
1111
class TrackingMiddleware
1212
WARDEN_KEY = 'warden'
13+
SESSION_ID_KEY = 'session_id'
1314

1415
def initialize(app)
1516
@app = app
@@ -32,16 +33,28 @@ def call(env)
3233
return @app.call(env)
3334
end
3435

36+
# NOTE: Rails session id will be set for unauthenticated users as well,
37+
# so we need to make sure we are tracking only authenticated users.
3538
id = transform(extract_id(env[WARDEN_KEY]))
39+
session_id = env[WARDEN_KEY].raw_session[SESSION_ID_KEY] if id
40+
3641
if id
37-
unless context.span.has_tag?(Ext::TAG_USR_ID)
38-
context.span[Ext::TAG_USR_ID] = id
42+
# NOTE: There is no option to set session id without setting user id via SDK.
43+
unless context.span.has_tag?(Ext::TAG_USR_ID) && context.span.has_tag?(Ext::TAG_SESSION_ID)
44+
user_id = context.span[Ext::TAG_USR_ID] || id
45+
user_session_id = context.span[Ext::TAG_SESSION_ID] || session_id
46+
47+
# FIXME: The current implementation of event arguments is forsing us
48+
# to bloat User class, and pass nil-value instead of skip
49+
# passing them at first place.
50+
# This is a temporary situation until we refactor events model.
3951
AppSec::Instrumentation.gateway.push(
40-
'identity.set_user', AppSec::Instrumentation::Gateway::User.new(id, nil)
52+
'identity.set_user', AppSec::Instrumentation::Gateway::User.new(user_id, nil, user_session_id)
4153
)
4254
end
4355

44-
context.span[Ext::TAG_DD_USR_ID] = id.to_s
56+
context.span[Ext::TAG_USR_ID] ||= id
57+
context.span[Ext::TAG_DD_USR_ID] = id
4558
context.span[Ext::TAG_DD_COLLECTION_MODE] ||= Configuration.auto_user_instrumentation_mode
4659
end
4760

lib/datadog/appsec/monitor/gateway/watcher.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,26 @@ def watch_user_id(gateway = Instrumentation.gateway)
2121
gateway.watch('identity.set_user', :appsec) do |stack, user|
2222
context = AppSec.active_context
2323

24-
if user.id.nil? && user.login.nil?
24+
if user.id.nil? && user.login.nil? && user.session_id.nil?
2525
Datadog.logger.debug { 'AppSec: skipping WAF check because no user information was provided' }
2626
next stack.call(user)
2727
end
2828

2929
persistent_data = {}
3030
persistent_data['usr.id'] = user.id if user.id
3131
persistent_data['usr.login'] = user.login if user.login
32+
persistent_data['usr.session_id'] = user.session_id if user.session_id
3233

3334
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
3435

35-
if result.match?
36-
AppSec::Event.tag_and_keep!(context, result)
37-
36+
if result.match? || !result.derivatives.empty?
3837
context.events.push(
3938
AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
4039
)
40+
end
4141

42+
if result.match?
43+
AppSec::Event.tag_and_keep!(context, result)
4244
AppSec::ActionsHandler.handle(result.actions)
4345
end
4446

sig/datadog/appsec/contrib/devise/ext.rbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ module Datadog
1111

1212
TAG_USR_ID: ::String
1313

14+
TAG_SESSION_ID: ::String
15+
1416
TAG_LOGIN_SUCCESS_TRACK: ::String
1517

1618
TAG_LOGIN_SUCCESS_USR_LOGIN: ::String

sig/datadog/appsec/contrib/devise/tracking_middleware.rbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ module Datadog
55
class TrackingMiddleware
66
WARDEN_KEY: ::String
77

8+
SESSION_ID_KEY: ::String
9+
810
@app: untyped
911

1012
def initialize: (untyped app) -> void

0 commit comments

Comments
 (0)