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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/bin/tcell_agent +97 -32
  3. data/lib/tcell_agent.rb +4 -4
  4. data/lib/tcell_agent/agent.rb +68 -13
  5. data/lib/tcell_agent/agent/event_processor.rb +256 -79
  6. data/lib/tcell_agent/agent/fork_pipe_manager.rb +114 -0
  7. data/lib/tcell_agent/agent/policy_manager.rb +28 -16
  8. data/lib/tcell_agent/agent/policy_types.rb +3 -4
  9. data/lib/tcell_agent/agent/route_manager.rb +45 -0
  10. data/lib/tcell_agent/agent/static_agent.rb +48 -10
  11. data/lib/tcell_agent/api.rb +0 -2
  12. data/lib/tcell_agent/appsensor/path_traversal.rb +1 -1
  13. data/lib/tcell_agent/configuration.rb +19 -6
  14. data/lib/tcell_agent/instrumentation.rb +123 -0
  15. data/lib/tcell_agent/logger.rb +4 -1
  16. data/lib/tcell_agent/policies/content_security_policy.rb +44 -8
  17. data/lib/tcell_agent/policies/dataloss_policy.rb +122 -65
  18. data/lib/tcell_agent/rails.rb +19 -10
  19. data/{config/initializers/authlogic_auth.rb → lib/tcell_agent/rails/auth/authlogic.rb} +1 -0
  20. data/{config/initializers/devise_auth.rb → lib/tcell_agent/rails/auth/devise.rb} +2 -81
  21. data/lib/tcell_agent/rails/dlp.rb +40 -36
  22. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +2 -2
  23. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +8 -2
  24. data/lib/tcell_agent/rails/routes.rb +15 -19
  25. data/lib/tcell_agent/routes/table.rb +35 -0
  26. data/lib/tcell_agent/sensor_events/app_sensor.rb +22 -33
  27. data/lib/tcell_agent/sensor_events/discovery.rb +30 -0
  28. data/lib/tcell_agent/sensor_events/dlp.rb +9 -4
  29. data/lib/tcell_agent/sensor_events/sensor.rb +3 -0
  30. data/lib/tcell_agent/sensor_events/server_agent.rb +30 -6
  31. data/lib/tcell_agent/sensor_events/util/utils.rb +5 -1
  32. data/lib/tcell_agent/start_background_thread.rb +27 -22
  33. data/lib/tcell_agent/utils/queue_with_timeout.rb +65 -1
  34. data/lib/tcell_agent/version.rb +1 -1
  35. data/spec/lib/tcell_agent/instrumentation_spec.rb +198 -0
  36. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +37 -2
  37. data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +81 -8
  38. data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +3 -3
  39. data/spec/spec_helper.rb +16 -0
  40. metadata +11 -11
  41. data/config/initializers/init.rb +0 -8
  42. data/lib/tcell_agent/dataloss.rb +0 -0
  43. data/lib/tcell_agent/policies/add_script_tag_policy.rb +0 -47
  44. data/lib/tcell_agent/rails/devise.rb +0 -0
  45. data/spec/lib/tcell_agent/policies/add_script_tag_policy_spec.rb +0 -37
@@ -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
- def initialize(type, value, report_uri=nil)
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 value(transaction_id=nil, session_id=nil, user_id=nil)
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 user_id
51
- new_query_ar << ["uid", user_id.to_s]
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, hmac_session_id, user_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
- if session_id_protection.fetch("body",nil)
85
- if (session_id_protection["body"].include? "redact")
86
- policy.session_id_filter_actions ||= FilterActions.new
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('options', nil)
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
- if options.has_key?("log")
124
- if (options["log"].include? "redact")
125
- policy.request_filter_actions[context][variable].log_redact = true
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?("protections")
149
- protections_json = data_json["protections"]
150
- protections_json.each do |protection|
151
- _table = protection.fetch("table", nil)
152
- _field = protection.fetch("field", nil)
153
- actions = protection.fetch("actions", {})
154
- if actions.fetch("body",nil)
155
- if (actions["body"].include? "redact")
156
- if (_table && _field)
157
- (policy.table_field_actions["#{_table}.#{_field}"] ||= []) << "body_redact"
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
- end
161
- if actions.fetch("log",nil)
162
- if (actions["log"].include? "redact")
163
- if (_table && _field)
164
- (policy.table_field_actions["#{_table}.#{_field}"] ||= []) << "log_redact"
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
@@ -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