tcell_agent 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/tcell_agent +97 -32
- data/lib/tcell_agent.rb +4 -4
- data/lib/tcell_agent/agent.rb +68 -13
- data/lib/tcell_agent/agent/event_processor.rb +256 -79
- data/lib/tcell_agent/agent/fork_pipe_manager.rb +114 -0
- data/lib/tcell_agent/agent/policy_manager.rb +28 -16
- data/lib/tcell_agent/agent/policy_types.rb +3 -4
- data/lib/tcell_agent/agent/route_manager.rb +45 -0
- data/lib/tcell_agent/agent/static_agent.rb +48 -10
- data/lib/tcell_agent/api.rb +0 -2
- data/lib/tcell_agent/appsensor/path_traversal.rb +1 -1
- data/lib/tcell_agent/configuration.rb +19 -6
- data/lib/tcell_agent/instrumentation.rb +123 -0
- data/lib/tcell_agent/logger.rb +4 -1
- data/lib/tcell_agent/policies/content_security_policy.rb +44 -8
- data/lib/tcell_agent/policies/dataloss_policy.rb +122 -65
- data/lib/tcell_agent/rails.rb +19 -10
- data/{config/initializers/authlogic_auth.rb → lib/tcell_agent/rails/auth/authlogic.rb} +1 -0
- data/{config/initializers/devise_auth.rb → lib/tcell_agent/rails/auth/devise.rb} +2 -81
- data/lib/tcell_agent/rails/dlp.rb +40 -36
- data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +2 -2
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +8 -2
- data/lib/tcell_agent/rails/routes.rb +15 -19
- data/lib/tcell_agent/routes/table.rb +35 -0
- data/lib/tcell_agent/sensor_events/app_sensor.rb +22 -33
- data/lib/tcell_agent/sensor_events/discovery.rb +30 -0
- data/lib/tcell_agent/sensor_events/dlp.rb +9 -4
- data/lib/tcell_agent/sensor_events/sensor.rb +3 -0
- data/lib/tcell_agent/sensor_events/server_agent.rb +30 -6
- data/lib/tcell_agent/sensor_events/util/utils.rb +5 -1
- data/lib/tcell_agent/start_background_thread.rb +27 -22
- data/lib/tcell_agent/utils/queue_with_timeout.rb +65 -1
- data/lib/tcell_agent/version.rb +1 -1
- data/spec/lib/tcell_agent/instrumentation_spec.rb +198 -0
- data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +37 -2
- data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +81 -8
- data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +3 -3
- data/spec/spec_helper.rb +16 -0
- metadata +11 -11
- data/config/initializers/init.rb +0 -8
- data/lib/tcell_agent/dataloss.rb +0 -0
- data/lib/tcell_agent/policies/add_script_tag_policy.rb +0 -47
- data/lib/tcell_agent/rails/devise.rb +0 -0
- data/spec/lib/tcell_agent/policies/add_script_tag_policy_spec.rb +0 -37
data/lib/tcell_agent/logger.rb
CHANGED
@@ -4,6 +4,7 @@ require 'logger'
|
|
4
4
|
require 'tcell_agent/configuration'
|
5
5
|
|
6
6
|
module TCellAgent
|
7
|
+
@@logger_pid = Process.pid
|
7
8
|
def self.loggingLevelFromString(levelString)
|
8
9
|
if (levelString == "DEBUG")
|
9
10
|
return Logger::DEBUG
|
@@ -19,11 +20,13 @@ module TCellAgent
|
|
19
20
|
return Logger::ERROR
|
20
21
|
end
|
21
22
|
def self.logger
|
22
|
-
if defined?(@logger)
|
23
|
+
if defined?(@logger) and @logger_pid == Process.pid
|
23
24
|
return @logger
|
24
25
|
end
|
26
|
+
@logger_pid = Process.pid
|
25
27
|
logging_options = TCellAgent.configuration.logging_options
|
26
28
|
if logging_options && logging_options["enabled"]
|
29
|
+
FileUtils.mkdir_p 'tcell/logs'
|
27
30
|
level = loggingLevelFromString(logging_options["level"])
|
28
31
|
logging_file = logging_options["filename"] || TCellAgent.configuration.default_log_filename
|
29
32
|
# limit the total log file to about 9 * 5 = 45 mb
|
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
require 'uri'
|
5
5
|
require 'tcell_agent/sensor_events/util/sanitizer_utilities'
|
6
|
+
require 'tcell_agent/configuration'
|
6
7
|
|
7
8
|
module TCellAgent
|
8
9
|
module Policies
|
@@ -15,7 +16,8 @@ module TCellAgent
|
|
15
16
|
attr_accessor :type
|
16
17
|
attr_accessor :raw_value
|
17
18
|
attr_accessor :report_uri
|
18
|
-
|
19
|
+
attr_accessor :policy_id
|
20
|
+
def initialize(type, value, report_uri=nil, policy_id=nil)
|
19
21
|
if !(type && value)
|
20
22
|
raise "Type and value were not set"
|
21
23
|
end
|
@@ -30,11 +32,19 @@ module TCellAgent
|
|
30
32
|
if value != value.gsub(/[^\p{L}\w\d\-_\ :\/,;.'\*"%?@#=$]/,'')
|
31
33
|
raise "Value is not valid"
|
32
34
|
end
|
35
|
+
if policy_id
|
36
|
+
self.policy_id = policy_id
|
37
|
+
end
|
33
38
|
self.type = type
|
34
39
|
self.raw_value = value
|
35
40
|
self.report_uri = report_uri
|
36
41
|
end
|
37
|
-
def
|
42
|
+
def self.jhash(str)
|
43
|
+
str.each_char.reduce(0) do |result, char|
|
44
|
+
[((result << 5) - result) + char.ord].pack('L').unpack('l').first
|
45
|
+
end
|
46
|
+
end
|
47
|
+
def value(transaction_id=nil, route_id=nil, session_id=nil, user_id=nil)
|
38
48
|
if !self.report_uri
|
39
49
|
return self.raw_value
|
40
50
|
end
|
@@ -44,16 +54,25 @@ module TCellAgent
|
|
44
54
|
if transaction_id
|
45
55
|
new_query_ar << ["tid", transaction_id]
|
46
56
|
end
|
47
|
-
if session_id
|
57
|
+
if session_id and session_id.length > 0
|
48
58
|
new_query_ar << ["sid", session_id]
|
49
59
|
end
|
50
|
-
if
|
51
|
-
new_query_ar << ["
|
60
|
+
if route_id
|
61
|
+
new_query_ar << ["rid", route_id]
|
52
62
|
end
|
53
63
|
if new_query_ar != []
|
54
64
|
uri.query = URI.encode_www_form(new_query_ar)
|
55
65
|
end
|
56
66
|
report_uri = uri.to_s
|
67
|
+
if self.policy_id
|
68
|
+
checksum = ContentSecurityPolicyHeader.jhash(self.policy_id + report_uri)
|
69
|
+
if new_query_ar != []
|
70
|
+
report_uri = report_uri + "&"
|
71
|
+
else
|
72
|
+
report_uri = report_uri + "?"
|
73
|
+
end
|
74
|
+
report_uri = report_uri + "c=" + checksum.to_s
|
75
|
+
end
|
57
76
|
return "#{self.raw_value}; report-uri #{report_uri}"
|
58
77
|
rescue Exception=>e
|
59
78
|
return self.raw_value
|
@@ -63,11 +82,12 @@ module TCellAgent
|
|
63
82
|
|
64
83
|
attr_accessor :headers
|
65
84
|
attr_accessor :policy_id
|
85
|
+
attr_accessor :js_agent_api_key
|
66
86
|
|
67
|
-
def each(transaction_id=nil, hmac_session_id=nil, user_id=nil, &block)
|
87
|
+
def each(transaction_id=nil, route_id=nil, hmac_session_id=nil, user_id=nil, &block)
|
68
88
|
result = []
|
69
89
|
headers.each do | header |
|
70
|
-
header_value = header.value(transaction_id,
|
90
|
+
header_value = header.value(transaction_id, route_id, hmac_session_id)
|
71
91
|
header_names = ContentSecurityPolicy.cspHeadersForType(header.type)
|
72
92
|
header_names.each do | header_name |
|
73
93
|
result.push( {"name"=>header_name, "value"=>header_value} )
|
@@ -85,13 +105,20 @@ module TCellAgent
|
|
85
105
|
else
|
86
106
|
raise "Policy ID missing"
|
87
107
|
end
|
108
|
+
if policy_json.has_key?("data")
|
109
|
+
data_json = policy_json["data"]
|
110
|
+
if data_json.has_key?("options")
|
111
|
+
options_json = data_json["options"]
|
112
|
+
csp.js_agent_api_key = options_json.fetch("js_agent_api_key", nil)
|
113
|
+
end
|
114
|
+
end
|
88
115
|
if policy_json.has_key?("headers")
|
89
116
|
headers = policy_json["headers"]
|
90
117
|
csp_headers = []
|
91
118
|
headers.each do |header|
|
92
119
|
if header.has_key?("name") && header.has_key?("value")
|
93
120
|
begin
|
94
|
-
csp_header = ContentSecurityPolicyHeader.new(header["name"], header["value"], header["report-uri"])
|
121
|
+
csp_header = ContentSecurityPolicyHeader.new(header["name"], header["value"], header["report-uri"], csp.policy_id)
|
95
122
|
csp_headers.push(csp_header)
|
96
123
|
rescue Exception => secure_header_exception
|
97
124
|
#pass
|
@@ -114,6 +141,15 @@ module TCellAgent
|
|
114
141
|
return []
|
115
142
|
end
|
116
143
|
end
|
144
|
+
def js_agent_app_id
|
145
|
+
return TCellAgent.configuration.app_id
|
146
|
+
end
|
147
|
+
def js_agent_api_base_url
|
148
|
+
return TCellAgent.configuration.js_agent_api_base_url
|
149
|
+
end
|
150
|
+
def js_agent_url
|
151
|
+
return TCellAgent.configuration.js_agent_url
|
152
|
+
end
|
117
153
|
end
|
118
154
|
end
|
119
155
|
end
|
@@ -11,6 +11,8 @@ module TCellAgent
|
|
11
11
|
attr_accessor :log_event
|
12
12
|
attr_accessor :log_redact
|
13
13
|
attr_accessor :log_hash
|
14
|
+
|
15
|
+
attr_accessor :action_id
|
14
16
|
end
|
15
17
|
|
16
18
|
attr_accessor :session_id_filter_actions
|
@@ -25,6 +27,9 @@ module TCellAgent
|
|
25
27
|
|
26
28
|
attr_accessor :table_field_actions
|
27
29
|
attr_accessor :session_id_actions
|
30
|
+
attr_accessor :database_actions
|
31
|
+
|
32
|
+
attr_accessor :database_discovery_enabled
|
28
33
|
|
29
34
|
attr_accessor :field_redact_body
|
30
35
|
attr_accessor :field_alerts
|
@@ -38,6 +43,8 @@ module TCellAgent
|
|
38
43
|
@table_field_actions = {}
|
39
44
|
@session_id_actions = []
|
40
45
|
|
46
|
+
@database_discovery_enabled = false
|
47
|
+
|
41
48
|
@field_redact_body = Set.new #["work_infos.SSN"].to_set #
|
42
49
|
@field_alerts = Set.new
|
43
50
|
|
@@ -47,6 +54,8 @@ module TCellAgent
|
|
47
54
|
"cookie"=>Hash.new{|h,k| h[k] = FilterActions.new},
|
48
55
|
"header"=>Hash.new{|h,k| h[k] = FilterActions.new}
|
49
56
|
}
|
57
|
+
@database_actions = Hash.new{|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new{|h,k| h[k] = Set.new}}}}}
|
58
|
+
|
50
59
|
@log_actions = nil
|
51
60
|
end
|
52
61
|
def get_actions_for_session_id(route_id=nil)
|
@@ -55,6 +64,44 @@ module TCellAgent
|
|
55
64
|
def get_actions_for_request(context, route_id=nil)
|
56
65
|
return @request_filter_actions.fetch(context)
|
57
66
|
end
|
67
|
+
def get_actions_for_table(database, schema, table, field, route_id="*")
|
68
|
+
if route_id == nil
|
69
|
+
route_id = "*"
|
70
|
+
end
|
71
|
+
actions = Set.new
|
72
|
+
[database, "*"].each do |d|
|
73
|
+
if (@database_actions.has_key?(d) == false)
|
74
|
+
next
|
75
|
+
end
|
76
|
+
[schema, "*"].each do |s|
|
77
|
+
if (@database_actions[d].has_key?(s) == false)
|
78
|
+
next
|
79
|
+
end
|
80
|
+
[table, "*"].each do |t|
|
81
|
+
if (@database_actions[d][s].has_key?(t) == false)
|
82
|
+
next
|
83
|
+
end
|
84
|
+
[field, "*"].each do |f|
|
85
|
+
if (@database_actions[d][s][t].has_key?(f) == false)
|
86
|
+
next
|
87
|
+
end
|
88
|
+
route_id_rules = @database_actions[d][s][t][f]
|
89
|
+
if (route_id_rules.has_key?(route_id))
|
90
|
+
actions.merge(@database_actions[d][s][t][f][route_id])
|
91
|
+
end
|
92
|
+
if (route_id != "*" && route_id_rules.has_key?("*"))
|
93
|
+
actions.merge(@database_actions[d][s][t][f]["*"])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
if (actions.size == 0)
|
100
|
+
return nil
|
101
|
+
end
|
102
|
+
actions
|
103
|
+
end
|
104
|
+
|
58
105
|
def get_actions_for(table, field)
|
59
106
|
actions = Set.new
|
60
107
|
key = "#{table}.#{field}"
|
@@ -67,6 +114,38 @@ module TCellAgent
|
|
67
114
|
#end
|
68
115
|
return actions
|
69
116
|
end
|
117
|
+
def self.actions_from_json(options)
|
118
|
+
actions = nil
|
119
|
+
if options.has_key?("log")
|
120
|
+
if (options["log"].include? "redact")
|
121
|
+
actions ||= FilterActions.new
|
122
|
+
actions.log_redact = true
|
123
|
+
end
|
124
|
+
if (options["log"].include? "event")
|
125
|
+
actions ||= FilterActions.new
|
126
|
+
actions.log_event = true
|
127
|
+
end
|
128
|
+
if (options["log"].include? "hash")
|
129
|
+
actions ||= FilterActions.new
|
130
|
+
actions.log_hash = true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
if options.has_key?("body")
|
134
|
+
if (options["body"].include? "redact")
|
135
|
+
actions ||= FilterActions.new
|
136
|
+
actions.body_redact = true
|
137
|
+
end
|
138
|
+
if (options["body"].include? "event")
|
139
|
+
actions ||= FilterActions.new
|
140
|
+
actions.body_event = true
|
141
|
+
end
|
142
|
+
if (options["body"].include? "hash")
|
143
|
+
actions ||= FilterActions.new
|
144
|
+
actions.body_hash = true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
actions
|
148
|
+
end
|
70
149
|
def self.fromJson(policy_json)
|
71
150
|
if (!policy_json)
|
72
151
|
return nil
|
@@ -79,35 +158,15 @@ module TCellAgent
|
|
79
158
|
end
|
80
159
|
if policy_json.has_key?("data")
|
81
160
|
data_json = policy_json["data"]
|
161
|
+
if data_json.has_key?("data_discovery")
|
162
|
+
data_discovery_json = data_json["data_discovery"]
|
163
|
+
policy.database_discovery_enabled = data_discovery_json.fetch('database_enabled', false)
|
164
|
+
end
|
82
165
|
if data_json.has_key?("session_id_protection")
|
83
166
|
session_id_protection = data_json["session_id_protection"]
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
policy.session_id_filter_actions.body_redact = true
|
88
|
-
end
|
89
|
-
if (session_id_protection["body"].include? "event")
|
90
|
-
policy.session_id_filter_actions ||= FilterActions.new
|
91
|
-
policy.session_id_filter_actions.body_event = true
|
92
|
-
end
|
93
|
-
if (session_id_protection["body"].include? "hash")
|
94
|
-
policy.session_id_filter_actions ||= FilterActions.new
|
95
|
-
policy.session_id_filter_actions.body_hash = true
|
96
|
-
end
|
97
|
-
end
|
98
|
-
if session_id_protection.fetch("log",nil)
|
99
|
-
if (session_id_protection["log"].include? "redact")
|
100
|
-
policy.session_id_filter_actions ||= FilterActions.new
|
101
|
-
policy.session_id_filter_actions.log_redact = true
|
102
|
-
end
|
103
|
-
if (session_id_protection["log"].include? "event")
|
104
|
-
policy.session_id_filter_actions ||= FilterActions.new
|
105
|
-
policy.session_id_filter_actions.log_event = true
|
106
|
-
end
|
107
|
-
if (session_id_protection["log"].include? "hash")
|
108
|
-
policy.session_id_filter_actions ||= FilterActions.new
|
109
|
-
policy.session_id_filter_actions.log_hash = true
|
110
|
-
end
|
167
|
+
filter_actions = DataLossPolicy.actions_from_json(session_id_protection)
|
168
|
+
if filter_actions != nil
|
169
|
+
policy.session_id_filter_actions = filter_actions
|
111
170
|
end
|
112
171
|
end
|
113
172
|
if data_json.has_key?("request_protections")
|
@@ -115,53 +174,51 @@ module TCellAgent
|
|
115
174
|
context = protection.fetch('context', nil)
|
116
175
|
variable = protection.fetch('variable', nil)
|
117
176
|
scope = protection.fetch('scope', "global")
|
118
|
-
options = protection.fetch('
|
177
|
+
options = protection.fetch('actions', nil)
|
119
178
|
if scope != "global"
|
120
179
|
next
|
121
|
-
end
|
180
|
+
end
|
122
181
|
if context && policy.request_filter_actions.has_key?(context) && variable && options
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
127
|
-
if (options["log"].include? "event")
|
128
|
-
policy.request_filter_actions[context][variable].log_event = true
|
129
|
-
end
|
130
|
-
if (options["log"].include? "hash")
|
131
|
-
policy.request_filter_actions[context][variable].log_hash = true
|
132
|
-
end
|
133
|
-
end
|
134
|
-
if options.has_key?("body")
|
135
|
-
if (options["body"].include? "redact")
|
136
|
-
policy.request_filter_actions[context][variable].body_redact = true
|
137
|
-
end
|
138
|
-
if (options["body"].include? "event")
|
139
|
-
policy.request_filter_actions[context][variable].body_event = true
|
140
|
-
end
|
141
|
-
if (options["body"].include? "hash")
|
142
|
-
policy.request_filter_actions[context][variable].body_hash = true
|
143
|
-
end
|
182
|
+
filter_actions = DataLossPolicy.actions_from_json(options)
|
183
|
+
if filter_actions != nil
|
184
|
+
policy.request_filter_actions[context][variable] = filter_actions
|
144
185
|
end
|
145
186
|
end
|
146
187
|
end
|
147
188
|
end
|
148
|
-
if data_json.has_key?("
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
189
|
+
if data_json.has_key?("db_protections")
|
190
|
+
protections = data_json["db_protections"]
|
191
|
+
if protections
|
192
|
+
protections.each do |protection_json|
|
193
|
+
scope = protection_json.fetch("scope",nil)
|
194
|
+
_databases = protection_json.fetch("databases",["*"])
|
195
|
+
_schemas = protection_json.fetch("schemas",["*"])
|
196
|
+
_tables = protection_json.fetch("tables",["*"])
|
197
|
+
_fields = protection_json.fetch("fields",nil)
|
198
|
+
rule_id = protection_json.fetch("rule_id",nil)
|
199
|
+
actions = protection_json.fetch("actions",{})
|
200
|
+
filter_actions = DataLossPolicy.actions_from_json(actions)
|
201
|
+
_route_ids = ["*"]
|
202
|
+
if (scope != nil and scope != "global")
|
203
|
+
if scope=="route"
|
204
|
+
_route_ids = protection_json.fetch("route_ids",[])
|
158
205
|
end
|
159
206
|
end
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
207
|
+
if _fields == nil
|
208
|
+
next
|
209
|
+
elsif filter_actions == nil
|
210
|
+
next
|
211
|
+
end
|
212
|
+
filter_actions.action_id = rule_id
|
213
|
+
_databases.each do |_database|
|
214
|
+
_schemas.each do |_schema|
|
215
|
+
_tables.each do |_table|
|
216
|
+
_fields.each do |_field|
|
217
|
+
_route_ids.each do |_route_id|
|
218
|
+
policy.database_actions[_database][_schema][_table][_field][_route_id].add(filter_actions)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
165
222
|
end
|
166
223
|
end
|
167
224
|
end
|
data/lib/tcell_agent/rails.rb
CHANGED
@@ -28,7 +28,25 @@ require 'tcell_agent/userinfo'
|
|
28
28
|
require 'cgi'
|
29
29
|
require 'thread'
|
30
30
|
|
31
|
+
|
32
|
+
|
31
33
|
# ensure ActiveRecord's version has been required already
|
34
|
+
module TCellAgent
|
35
|
+
class MyRailtie < Rails::Railtie
|
36
|
+
initializer 'activeservice.autoload', :after => :set_autoload_paths do |app|
|
37
|
+
if (TCellAgent.configuration.enabled)
|
38
|
+
Rails.application.config.to_prepare do
|
39
|
+
require 'tcell_agent/rails/auth/devise'
|
40
|
+
require 'tcell_agent/rails/auth/authlogic'
|
41
|
+
end
|
42
|
+
Rails.application.config.after_initialize do
|
43
|
+
TCellAgent::Instrumentation::Rails.send_framework_info
|
44
|
+
TCellAgent::Instrumentation::Rails.send_settings(Rails.application)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
32
50
|
|
33
51
|
module TCellAgent
|
34
52
|
class Railtie < Rails::Railtie
|
@@ -38,16 +56,8 @@ module TCellAgent
|
|
38
56
|
app.config.middleware.use "TCellAgent::Instrumentation::Rails::Middleware::BodyFilterMiddleware"
|
39
57
|
app.config.middleware.use "TCellAgent::Instrumentation::Rails::Middleware::GlobalMiddleware"
|
40
58
|
end
|
41
|
-
config.after_initialize do
|
42
|
-
TCellAgent::Instrumentation::Rails.send_framework_info
|
43
|
-
TCellAgent::Instrumentation::Rails.send_settings(Rails.application)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
class Engine < Rails::Engine
|
47
|
-
config.after_initialize do
|
48
|
-
TCellAgent::Instrumentation::Rails.get_routes()
|
49
|
-
end
|
50
59
|
end
|
60
|
+
end
|
51
61
|
# # if (Rails::VERSION::MAJOR == 3)
|
52
62
|
# # config.after_initialize do
|
53
63
|
# # Rails.application.reload_routes!
|
@@ -143,4 +153,3 @@ module TCellAgent
|
|
143
153
|
# end #ac classeval
|
144
154
|
# end #as onload
|
145
155
|
# end #class
|
146
|
-
end #module
|
@@ -17,6 +17,7 @@ module TCellAgent
|
|
17
17
|
success = original_save
|
18
18
|
user_logged_in_after = (user != nil)
|
19
19
|
TCellAgent::Instrumentation.safe_block("Authlogic login info") {
|
20
|
+
|
20
21
|
login_fraud_policy = TCellAgent.policy(TCellAgent::PolicyTypes::LoginFraud)
|
21
22
|
if (login_fraud_policy && login_fraud_policy.enabled)
|
22
23
|
user_id = nil
|