Skip to content

Commit 74cd014

Browse files
authored
Merge pull request #4352 from DataDog/appsec-56683-update-auto-user-instrumentation-mode-configuration
[APPSEC-56683] Add `appsec.auto_user_instrumentation.mode` setting
2 parents 5c1cea4 + 18e933f commit 74cd014

File tree

14 files changed

+906
-467
lines changed

14 files changed

+906
-467
lines changed

lib/datadog/appsec/configuration/settings.rb

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,29 @@ module Settings
1212
DEFAULT_OBFUSCATOR_KEY_REGEX = '(?i)pass|pw(?:or)?d|secret|(?:api|private|public|access)[_-]?key|token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization|jsessionid|phpsessid|asp\.net[_-]sessionid|sid|jwt'
1313
DEFAULT_OBFUSCATOR_VALUE_REGEX = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:[_-]?phrase)?|secret(?:[_-]?key)?|(?:(?:api|private|public|access)[_-]?)key(?:[_-]?id)?|(?:(?:auth|access|id|refresh)[_-]?)?token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?|jsessionid|phpsessid|asp\.net(?:[_-]|-)sessionid|sid|jwt)(?:\s*=[^;]|"\s*:\s*"[^"]+")|bearer\s+[a-z0-9\._\-]+|token:[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\w=-]+\.ey[I-L][\w=-]+(?:\.[\w.+\/=-]+)?|[\-]{5}BEGIN[a-z\s]+PRIVATE\sKEY[\-]{5}[^\-]+[\-]{5}END[a-z\s]+PRIVATE\sKEY|ssh-rsa\s*[a-z0-9\/\.+]{100,}'
1414
# rubocop:enable Layout/LineLength
15+
16+
DISABLED_AUTO_USER_INSTRUMENTATION_MODE = 'disabled'
17+
ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE = 'anonymization'
18+
IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE = 'identification'
19+
AUTO_USER_INSTRUMENTATION_MODES = [
20+
DISABLED_AUTO_USER_INSTRUMENTATION_MODE,
21+
ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE,
22+
IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
23+
].freeze
24+
AUTO_USER_INSTRUMENTATION_MODES_ALIASES = {
25+
'ident' => IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE,
26+
'anon' => ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE,
27+
}.freeze
28+
29+
# NOTE: These two constants are deprecated
30+
SAFE_TRACK_USER_EVENTS_MODE = 'safe'
31+
EXTENDED_TRACK_USER_EVENTS_MODE = 'extended'
1532
APPSEC_VALID_TRACK_USER_EVENTS_MODE = [
16-
'safe',
17-
'extended'
33+
SAFE_TRACK_USER_EVENTS_MODE, EXTENDED_TRACK_USER_EVENTS_MODE
1834
].freeze
19-
APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES = [
20-
'1',
21-
'true'
22-
].concat(APPSEC_VALID_TRACK_USER_EVENTS_MODE).freeze
35+
APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES = ['1', 'true'].concat(
36+
APPSEC_VALID_TRACK_USER_EVENTS_MODE
37+
).freeze
2338

2439
def self.extended(base)
2540
base = base.singleton_class unless base.is_a?(Class)
@@ -149,6 +164,29 @@ def self.add_settings!(base)
149164
end
150165
end
151166

167+
settings :auto_user_instrumentation do
168+
define_method(:enabled?) { get_option(:mode) != DISABLED_AUTO_USER_INSTRUMENTATION_MODE }
169+
170+
option :mode do |o|
171+
o.type :string
172+
o.env 'DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE'
173+
o.default IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
174+
o.setter do |value|
175+
mode = AUTO_USER_INSTRUMENTATION_MODES_ALIASES.fetch(value, value)
176+
next mode if AUTO_USER_INSTRUMENTATION_MODES.include?(mode)
177+
178+
Datadog.logger.warn(
179+
'The appsec.auto_user_instrumentation.mode value provided is not supported. ' \
180+
"Supported values are: #{AUTO_USER_INSTRUMENTATION_MODES.join(' | ')}. " \
181+
"Using default value: #{IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE}."
182+
)
183+
184+
IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
185+
end
186+
end
187+
end
188+
189+
# DEV-3.0: Remove `track_user_events.enabled` and `track_user_events.mode` options
152190
settings :track_user_events do
153191
option :enabled do |o|
154192
o.default true
@@ -161,24 +199,39 @@ def self.add_settings!(base)
161199
APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES.include?(env_value.strip.downcase)
162200
end
163201
end
202+
o.after_set do
203+
Core.log_deprecation(key: :appsec_track_user_events_enabled) do
204+
'The appsec.track_user_events.enabled setting has been deprecated for removal. ' \
205+
'Please remove it from your Datadog.configure block and use ' \
206+
'appsec.auto_user_instrumentation.mode instead.'
207+
end
208+
end
164209
end
165210

166211
option :mode do |o|
167212
o.type :string
168213
o.env 'DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING'
169-
o.default 'safe'
214+
o.default SAFE_TRACK_USER_EVENTS_MODE
170215
o.setter do |v|
171216
if APPSEC_VALID_TRACK_USER_EVENTS_MODE.include?(v)
172217
v
173218
elsif v == 'disabled'
174-
'safe'
219+
SAFE_TRACK_USER_EVENTS_MODE
175220
else
176221
Datadog.logger.warn(
177222
'The appsec.track_user_events.mode value provided is not supported.' \
178-
'Supported values are: safe | extended.' \
179-
'Using default value `safe`'
223+
"Supported values are: #{APPSEC_VALID_TRACK_USER_EVENTS_MODE.join(' | ')}." \
224+
"Using default value: #{SAFE_TRACK_USER_EVENTS_MODE}."
180225
)
181-
'safe'
226+
227+
SAFE_TRACK_USER_EVENTS_MODE
228+
end
229+
end
230+
o.after_set do
231+
Core.log_deprecation(key: :appsec_track_user_events_mode) do
232+
'The appsec.track_user_events.mode setting has been deprecated for removal. ' \
233+
'Please remove it from your Datadog.configure block and use ' \
234+
'appsec.auto_user_instrumentation.mode instead.'
182235
end
183236
end
184237
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
module Datadog
4+
module AppSec
5+
module Contrib
6+
module Devise
7+
# A temporary configuration module to accomodate new RFC changes.
8+
# NOTE: DEV-3 Remove module
9+
module Configuration
10+
module_function
11+
12+
# NOTE: DEV-3 Replace method use with `auto_user_instrumentation.enabled?`
13+
def auto_user_instrumentation_enabled?
14+
Datadog.configuration.appsec.auto_user_instrumentation.enabled? &&
15+
Datadog.configuration.appsec.track_user_events.enabled
16+
end
17+
18+
# NOTE: DEV-3 Replace method use with `auto_user_instrumentation.mode`
19+
def auto_user_instrumentation_mode
20+
case Datadog.configuration.appsec.track_user_events.mode
21+
when AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE
22+
AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
23+
when AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE
24+
AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
25+
else
26+
Datadog.configuration.appsec.auto_user_instrumentation.mode
27+
end
28+
end
29+
end
30+
end
31+
end
32+
end
33+
end

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ module Devise
88
class Event
99
UUID_REGEX = /^\h{8}-\h{4}-\h{4}-\h{4}-\h{12}$/.freeze
1010

11-
SAFE_MODE = 'safe'
12-
EXTENDED_MODE = 'extended'
13-
1411
attr_reader :user_id
1512

1613
def initialize(resource, mode)
@@ -38,15 +35,15 @@ def extract
3835
@user_id = @resource.id
3936

4037
case @mode
41-
when EXTENDED_MODE
38+
when AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
4239
@email = @resource.email
4340
@username = @resource.username
44-
when SAFE_MODE
41+
when AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
4542
@user_id = nil unless @user_id && @user_id.to_s =~ UUID_REGEX
4643
else
4744
Datadog.logger.warn(
48-
"Invalid automated user evenst mode: `#{@mode}`. "\
49-
'Supported modes are: `safe` and `extended`.'
45+
"Invalid auto_user_instrumentation.mode: `#{@mode}`. " \
46+
"Supported modes are: #{AppSec::Configuration::Settings::AUTO_USER_INSTRUMENTATION_MODES.join(' | ')}."
5047
)
5148
end
5249
end

lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
require_relative '../configuration'
34
require_relative '../tracking'
45
require_relative '../resource'
56
require_relative '../event'
@@ -14,33 +15,27 @@ module AuthenticatablePatch
1415
# rubocop:disable Metrics/MethodLength
1516
def validate(resource, &block)
1617
result = super
17-
return result unless AppSec.enabled?
18-
return result if @_datadog_skip_track_login_event
19-
20-
track_user_events_configuration = Datadog.configuration.appsec.track_user_events
21-
22-
return result unless track_user_events_configuration.enabled
23-
24-
automated_track_user_events_mode = track_user_events_configuration.mode
2518

26-
appsec_context = Datadog::AppSec.active_context
27-
28-
return result unless appsec_context
19+
return result unless AppSec.enabled?
20+
return result if @_datadog_appsec_skip_track_login_event
21+
return result unless Configuration.auto_user_instrumentation_enabled?
22+
return result unless AppSec.active_context
2923

3024
devise_resource = resource ? Resource.new(resource) : nil
31-
32-
event_information = Event.new(devise_resource, automated_track_user_events_mode)
25+
event_information = Event.new(devise_resource, Configuration.auto_user_instrumentation_mode)
3326

3427
if result
3528
if event_information.user_id
36-
Datadog.logger.debug { 'User Login Event success' }
29+
Datadog.logger.debug { 'AppSec: User successful login event' }
3730
else
38-
Datadog.logger.debug { 'User Login Event success, but can\'t extract user ID. Tracking empty event' }
31+
Datadog.logger.debug do
32+
"AppSec: User successful login event, but can't extract user ID. Tracking empty event"
33+
end
3934
end
4035

4136
Tracking.track_login_success(
42-
appsec_context.trace,
43-
appsec_context.span,
37+
AppSec.active_context.trace,
38+
AppSec.active_context.span,
4439
user_id: event_information.user_id,
4540
**event_information.to_h
4641
)
@@ -52,15 +47,15 @@ def validate(resource, &block)
5247

5348
if resource
5449
user_exists = true
55-
Datadog.logger.debug { 'User Login Event failure users exists' }
50+
Datadog.logger.debug { 'AppSec: User failed login event, but user exists' }
5651
else
5752
user_exists = false
58-
Datadog.logger.debug { 'User Login Event failure user do not exists' }
53+
Datadog.logger.debug { 'AppSec: User failed login event and user does not exist' }
5954
end
6055

6156
Tracking.track_login_failure(
62-
appsec_context.trace,
63-
appsec_context.span,
57+
AppSec.active_context.trace,
58+
AppSec.active_context.span,
6459
user_id: event_information.user_id,
6560
user_exists: user_exists,
6661
**event_information.to_h

lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
require_relative '../configuration'
34
require_relative '../tracking'
45
require_relative '../resource'
56
require_relative '../event'
@@ -13,31 +14,23 @@ module Patcher
1314
module RegistrationControllerPatch
1415
def create
1516
return super unless AppSec.enabled?
16-
17-
track_user_events_configuration = Datadog.configuration.appsec.track_user_events
18-
19-
return super unless track_user_events_configuration.enabled
20-
21-
automated_track_user_events_mode = track_user_events_configuration.mode
22-
23-
appsec_context = Datadog::AppSec.active_context
24-
return super unless appsec_context
17+
return super unless Configuration.auto_user_instrumentation_enabled?
18+
return super unless AppSec.active_context
2519

2620
super do |resource|
2721
if resource.persisted?
2822
devise_resource = Resource.new(resource)
29-
30-
event_information = Event.new(devise_resource, automated_track_user_events_mode)
23+
event_information = Event.new(devise_resource, Configuration.auto_user_instrumentation_mode)
3124

3225
if event_information.user_id
33-
Datadog.logger.debug { 'User Signup Event' }
26+
Datadog.logger.debug { 'AppSec: User signup event' }
3427
else
35-
Datadog.logger.warn { 'User Signup Event, but can\'t extract user ID. Tracking empty event' }
28+
Datadog.logger.warn { "AppSec: User signup event, but can't extract user ID. Tracking empty event" }
3629
end
3730

3831
Tracking.track_signup(
39-
appsec_context.trace,
40-
appsec_context.span,
32+
AppSec.active_context.trace,
33+
AppSec.active_context.span,
4134
user_id: event_information.user_id,
4235
**event_information.to_h
4336
)

lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ module Patcher
99
# Rememberable strategy as Login Success events.
1010
module RememberablePatch
1111
def validate(*args)
12-
@_datadog_skip_track_login_event = true
12+
@_datadog_appsec_skip_track_login_event = true
1313

1414
super
1515
end

sig/datadog/appsec/configuration/settings.rbs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
11
module Datadog
22
module AppSec
33
module Configuration
4-
# Settings
54
module Settings
65
extend Datadog::Core::Configuration::Base::ClassMethods
76
include Datadog::Core::Configuration::Base::InstanceMethods
87
extend Datadog::Core::Configuration::Options::ClassMethods
98
include Datadog::Core::Configuration::Options::InstanceMethods
109

1110
DEFAULT_OBFUSCATOR_KEY_REGEX: ::String
11+
1212
DEFAULT_OBFUSCATOR_VALUE_REGEX: ::String
13-
APPSEC_VALID_TRACK_USER_EVENTS_MODE: ::Array[String]
14-
APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES: ::Array[String]
13+
14+
DISABLED_AUTO_USER_INSTRUMENTATION_MODE: ::String
15+
16+
ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE: ::String
17+
18+
IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE: ::String
19+
20+
AUTO_USER_INSTRUMENTATION_MODES: ::Array[::String]
21+
22+
AUTO_USER_INSTRUMENTATION_MODES_ALIASES: ::Hash[::String, ::String]
23+
24+
SAFE_TRACK_USER_EVENTS_MODE: ::String
25+
26+
EXTENDED_TRACK_USER_EVENTS_MODE: ::String
27+
28+
APPSEC_VALID_TRACK_USER_EVENTS_MODE: ::Array[::String]
29+
30+
APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES: ::Array[::String]
1531

1632
def self.extended: (untyped base) -> untyped
1733

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module Datadog
2+
module AppSec
3+
module Contrib
4+
module Devise
5+
module Configuration
6+
def self?.auto_user_instrumentation_enabled?: () -> bool
7+
8+
def self?.auto_user_instrumentation_mode: () -> ::String
9+
end
10+
end
11+
end
12+
end
13+
end

0 commit comments

Comments
 (0)