immunio 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 88d0c7506de87c39b6c0c7dc765cb55da4948b64
4
- data.tar.gz: d38d7b83f8652eae78201c954215bf715fed31df
3
+ metadata.gz: 877a290ccd60b4a6e46fff24968cd223fae6ac56
4
+ data.tar.gz: 5e4c68c451a27e7de6590499dd427485d05ab577
5
5
  SHA512:
6
- metadata.gz: 98a9fddf1a26d59bd4491350613a2e016f9b4cc0697b038f96144793f33e9d01e88cafd1cf4d8ed92874e651d7af730eab7b87e73b814488cc0c17281ddae9e0
7
- data.tar.gz: 75a136f01c2ffe9bec4fda596502df66adbd2e858e25b7f8c04d5dda6653e57a2162f43601bc5e5bbe0c92d78904823443ecb9d7265a2ee9abcda74379894dc2
6
+ metadata.gz: 88c2d9d8c86bd24fa028e1c092524617f3bbc2e271f3fae53c50c8ae45f3ab6d5b1f5b8c1846be8fa7ede95441121426355b5960ed174269712a14f06883c9e6
7
+ data.tar.gz: 7a7bdc7a6cc3d85f5f226a8017061d22dda0bd9f9a6aeaae146f5f8df80b6f8d1e79b533bba2525e2ce8b245ebf52d9cb85e46d3221af0107b427114c1f421ea
data/lib/immunio.rb CHANGED
@@ -5,6 +5,7 @@ module Immunio
5
5
  require_relative "immunio/utils"
6
6
  require_relative "immunio/agent"
7
7
  require_relative "immunio/authentication"
8
+ require_relative "immunio/plugin"
8
9
 
9
10
  agent # Force load agent
10
11
  end
data/lib/immunio/agent.rb CHANGED
@@ -70,8 +70,6 @@ module Immunio
70
70
  # purposes.
71
71
  config_accessor :vm_data
72
72
 
73
- attr_reader :plugins
74
-
75
73
  def initialize
76
74
  Immunio.logger.info { "Initializing agent version #{VERSION} for process #{Process.pid}" }
77
75
 
@@ -104,8 +102,6 @@ module Immunio
104
102
  # Be sure all config attributes have a type before this call:
105
103
  load_config
106
104
 
107
- setup_plugin_registry
108
-
109
105
  Immunio::switch_to_real_logger(config.log_file, config.log_level)
110
106
 
111
107
  if !config.agent_enabled then
@@ -235,75 +231,6 @@ module Immunio
235
231
  def environment=(environment)
236
232
  @processor.environment = environment
237
233
  end
238
-
239
- def register_plugin(name, version = nil)
240
- @plugins[name] = {} unless @plugins.has_key?(name)
241
- @plugins[name]['status'] = 'loaded'
242
- @plugins[name]['version'] = version if version
243
-
244
- Immunio.logger.info do
245
- "Registering plugin '#{name}' => '#{@plugins[name]}'"
246
- end
247
- end
248
-
249
- RECOGNIZED_PLUGINS = [
250
- ## action_dispatch
251
- 'ActionDispatch::Cookies::SignedCookieJar',
252
- 'ActionDispatch::Cookies::UpgradeLegacySignedCookieJar',
253
- 'ActionDispatch::Cookies::EncryptedCookieJar',
254
- 'ActionDispatch::Cookies::UpgradeLegacyEncryptedCookieJar',
255
-
256
- ## action_view
257
- 'ActionView::Template::Handlers::Erubis',
258
- 'Haml::Compiler',
259
- 'Hash',
260
- 'ActionView::TemplateRenderer',
261
- 'ActionView::Template',
262
- 'ActionController::Caching::Fragments',
263
-
264
- ## active_record
265
- 'ActiveRecord',
266
- 'ActiveRecord::ConnectionAdapters::Mysql2Adapter',
267
- 'ActiveRecord::ConnectionAdapters::MysqlAdapter',
268
- 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter',
269
- 'ActiveRecord::ConnectionAdapters::SQLite3Adapter',
270
- 'ActiveRecord::ConnectionAdapters::SQLiteAdapter',
271
- 'ActiveRecord::Sanitization',
272
- 'Arel::Visitors::ToSql',
273
- 'ActiveRecord::ConnectionAdapters::AbstractAdapter',
274
-
275
- ## active_record_relation
276
- 'ActiveRecord::Relation',
277
- 'ActiveRecord::SpawnMethods',
278
- 'ActiveRecord::Querying',
279
- 'ActiveRecord::StatementCache',
280
- 'ActiveRecord::Associations::HasManyThroughAssociation',
281
-
282
- 'Authlogic',
283
- 'ActionController (CSRF)',
284
- 'Devise',
285
- 'Kernel (Eval)',
286
- 'Immunio::HTTPFinisher',
287
- 'Immunio::HTTPTracker',
288
-
289
- ## io
290
- 'IO',
291
- 'File',
292
- 'Kernel (Module)',
293
-
294
- 'ActionController (Redirect)',
295
- 'Warden'
296
- ].freeze
297
-
298
- private
299
-
300
- def setup_plugin_registry
301
- @plugins = {}
302
-
303
- RECOGNIZED_PLUGINS.each do |name|
304
- @plugins[name] = { 'status' => 'pending' }
305
- end
306
- end
307
234
  end
308
235
 
309
236
  AGENT_INIT_MUTEX = Mutex.new
@@ -0,0 +1,94 @@
1
+ require "msgpack"
2
+
3
+ module Immunio
4
+ # Holds the status of a plugin.
5
+ #
6
+ # A plugin can have one of four statuses:
7
+ #
8
+ # - pending: initial state, waiting to be loaded
9
+ # - loaded: successfully loaded
10
+ # - failed: error while loading
11
+ # - disabled: disabled in config, will never be loaded
12
+ #
13
+ # Each registered plugin is reported to the backend via the `EnvironmentReporter`.
14
+ class Plugin
15
+ attr_reader :status
16
+ attr_accessor :version
17
+
18
+ def initialize(name)
19
+ @name = name
20
+ @status = 'pending'
21
+ @version = nil
22
+ end
23
+
24
+ def loaded!(version)
25
+ @status = 'loaded'
26
+ @version = version
27
+ Immunio.logger.debug "Plugin #{@name} v#{version} loaded successfully"
28
+ end
29
+
30
+ def disabled!
31
+ @status = 'disabled'
32
+ Immunio.logger.debug "Plugin #{@name} is disabled"
33
+ end
34
+
35
+ def failed!(error)
36
+ @status = 'failed'
37
+ Immunio.logger.error "Plugin #{@name} failed to load: #{error}"
38
+ end
39
+
40
+ def inspect
41
+ "<#{self.class} name=#{@name.inspect} status=#{@status.inspect} version=#{@version.inspect}>"
42
+ end
43
+
44
+ def to_msgpack(packer)
45
+ packer.write_map_header 2
46
+ # `name` is provided as the key in `registered`
47
+ packer.write('status').write(@status)
48
+ packer.write('version').write(@version)
49
+ end
50
+
51
+ def self.registered
52
+ @registered ||= {}
53
+ end
54
+
55
+ # DSL to register a plugin, its status and version.
56
+ #
57
+ # A `feature` name can be passed to determine if the plugin should be enabled. If the
58
+ # plugin is disabled, the block will not run.
59
+ #
60
+ # You MUST explicitly call `plugin.loaded!` in the block to indicate that the plugin was
61
+ # loaded successfully, or else it will be kept as 'pending'.
62
+ #
63
+ # Eg.:
64
+ #
65
+ # Immunio::Plugin.load 'SomePluginName', feature: 'xss' do |plugin|
66
+ # if defined? SomePlugin
67
+ # # Your loading code here ...
68
+ # plugin.loaded! SomePluginName::VERSION
69
+ # end
70
+ # end
71
+ #
72
+ def self.load(name, options = {})
73
+ if options.key? :feature
74
+ enabled = Immunio.agent.plugin_enabled?(options[:feature])
75
+ else
76
+ enabled = true
77
+ end
78
+
79
+ plugin = registered[name] = new(name)
80
+
81
+ unless enabled # plugin is disabled
82
+ plugin.disabled!
83
+ return
84
+ end
85
+
86
+ Immunio.logger.debug "Loading plugin #{name} ..."
87
+ begin
88
+ yield plugin
89
+ rescue StandardError, LoadError => e
90
+ plugin.failed! e
91
+ end
92
+ end
93
+ end
94
+ end
@@ -29,36 +29,23 @@ module Immunio
29
29
  end
30
30
  end
31
31
 
32
- class ActionDispatch::Cookies
33
- if defined? SignedCookieJar
34
- SignedCookieJar.send :include, Immunio::CookieHooks
35
-
36
- Immunio.agent.register_plugin(
37
- 'ActionDispatch::Cookies::SignedCookieJar',
38
- ActionPack::VERSION::STRING)
39
- end
40
-
41
- if defined? UpgradeLegacySignedCookieJar
42
- UpgradeLegacySignedCookieJar.send :include, Immunio::CookieHooks
43
-
44
- Immunio.agent.register_plugin(
45
- 'ActionDispatch::Cookies::UpgradeLegacySignedCookieJar',
46
- ActionPack::VERSION::STRING)
47
- end
48
-
49
- if defined? EncryptedCookieJar
50
- EncryptedCookieJar.send :include, Immunio::CookieHooks
32
+ Immunio::Plugin.load 'ActionDispatch (Cookie)' do |plugin|
33
+ class ActionDispatch::Cookies
34
+ if defined? SignedCookieJar
35
+ SignedCookieJar.send :include, Immunio::CookieHooks
36
+ end
51
37
 
52
- Immunio.agent.register_plugin(
53
- 'ActionDispatch::Cookies::EncryptedCookieJar',
54
- ActionPack::VERSION::STRING)
55
- end
38
+ if defined? UpgradeLegacySignedCookieJar
39
+ UpgradeLegacySignedCookieJar.send :include, Immunio::CookieHooks
40
+ end
56
41
 
57
- if defined? UpgradeLegacyEncryptedCookieJar
58
- UpgradeLegacyEncryptedCookieJar.send :include, Immunio::CookieHooks
42
+ if defined? EncryptedCookieJar
43
+ EncryptedCookieJar.send :include, Immunio::CookieHooks
44
+ end
59
45
 
60
- Immunio.agent.register_plugin(
61
- 'ActionDispatch::Cookies::UpgradeLegacyEncryptedCookieJar',
62
- ActionPack::VERSION::STRING)
46
+ if defined? UpgradeLegacyEncryptedCookieJar
47
+ UpgradeLegacyEncryptedCookieJar.send :include, Immunio::CookieHooks
48
+ end
63
49
  end
50
+ plugin.loaded! ActionPack::VERSION::STRING
64
51
  end
@@ -531,51 +531,33 @@ module Immunio
531
531
  end
532
532
  end
533
533
 
534
- # Add XSS hooks if enabled
535
- if Immunio::agent.plugin_enabled?("xss") then
536
- action_view_version =
537
- if ActionView.respond_to?(:version)
538
- ActionView.version.to_s
539
- else
540
- Rails.version
541
- end
534
+ # Load the plugins
542
535
 
543
- # Hook into template engines.
536
+ Immunio::Plugin.load 'Erubis', feature: 'xss' do |plugin|
544
537
  ActionView::Template::Handlers::Erubis.send :include, Immunio::ErubisHooks
538
+ plugin.loaded! Rails.version
539
+ end
545
540
 
546
- Immunio.agent.register_plugin(
547
- 'ActionView::Template::Handlers::Erubis',
548
- action_view_version)
549
-
550
- ActiveSupport.on_load(:after_initialize) do
551
- # Wait after Rails initialization to patch custom template engines.
541
+ ActiveSupport.on_load(:after_initialize) do
542
+ # Wait after Rails initialization to patch custom template engines.
543
+ Immunio::Plugin.load 'Haml', feature: 'xss' do |plugin|
552
544
  if defined? Haml::Compiler
553
545
  Haml::Compiler.send :include, Immunio::HamlHooks
554
- Immunio.agent.register_plugin('Haml::Compiler', Haml::VERSION)
546
+ plugin.loaded! Haml::VERSION
555
547
  end
556
-
557
- Hash.send :include, Immunio::ActiveSupportHooks
558
- Immunio.agent.register_plugin('Hash', RUBY_VERSION)
559
548
  end
560
549
 
561
- # Hook into rendering process of Rails.
562
- ActionView::TemplateRenderer.send :include, Immunio::TemplateRendererHooks
563
-
564
- Immunio.agent.register_plugin(
565
- 'ActionView::TemplateRenderer',
566
- action_view_version)
550
+ # Wait for ActiveSupport core ext to load
551
+ Hash.send :include, Immunio::ActiveSupportHooks
552
+ end
567
553
 
554
+ # Hook into rendering process of Rails.
555
+ Immunio::Plugin.load 'ActionView', feature: 'xss' do |plugin|
556
+ ActionView::TemplateRenderer.send :include, Immunio::TemplateRendererHooks
568
557
  ActionView::Template.send :include, Immunio::TemplateHooks
569
-
570
- Immunio.agent.register_plugin(
571
- 'ActionView::Template',
572
- action_view_version)
573
-
574
558
  ActionController::Caching::Fragments.send(
575
559
  :include,
576
560
  Immunio::FragmentCachingHooks)
577
561
 
578
- Immunio.agent.register_plugin(
579
- 'ActionController::Caching::Fragments',
580
- action_view_version)
562
+ plugin.loaded! Rails.version
581
563
  end
@@ -681,66 +681,35 @@ module Immunio
681
681
  end
682
682
  end
683
683
 
684
- Immunio.agent.register_plugin('ActiveRecord', ActiveRecord::VERSION::STRING)
685
-
686
684
  # Hook into quoting methods at the highest level possible in the ancestors chain.
687
685
  # In case the quote methods were overridden in a child class.
686
+ #
687
+ # NOTE: ActiveRecord plugin status is set in lib/immunio/rails.rb where this file is required.
688
+ #
688
689
  module ActiveRecord::ConnectionAdapters
689
690
  if defined? Mysql2Adapter
690
691
  Mysql2Adapter.send :include, Immunio::QuotingHooks
691
-
692
- Immunio.agent.register_plugin(
693
- 'ActiveRecord::ConnectionAdapters::Mysql2Adapter',
694
- ActiveRecord::VERSION::STRING)
695
692
  elsif defined? MysqlAdapter
696
693
  MysqlAdapter.send :include, Immunio::QuotingHooks
697
-
698
- Immunio.agent.register_plugin(
699
- 'ActiveRecord::ConnectionAdapters::MysqlAdapter',
700
- ActiveRecord::VERSION::STRING)
701
694
  end
702
695
 
703
696
  if defined? PostgreSQLAdapter
704
697
  PostgreSQLAdapter.send :include, Immunio::QuotingHooks
705
-
706
- Immunio.agent.register_plugin(
707
- 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter',
708
- ActiveRecord::VERSION::STRING)
709
698
  end
710
699
 
711
700
  if defined? SQLite3Adapter
712
701
  SQLite3Adapter.send :include, Immunio::QuotingHooks
713
-
714
- Immunio.agent.register_plugin(
715
- 'ActiveRecord::ConnectionAdapters::SQLite3Adapter',
716
- ActiveRecord::VERSION::STRING)
717
702
  elsif defined? SQLiteAdapter
718
703
  SQLiteAdapter.send :include, Immunio::QuotingHooks
719
-
720
- Immunio.agent.register_plugin(
721
- 'ActiveRecord::ConnectionAdapters::SQLiteAdapter',
722
- ActiveRecord::VERSION::STRING)
723
704
  end
724
705
  end
725
706
 
726
707
  module ActiveRecord::Sanitization
727
708
  ClassMethods.send :include, Immunio::SanitizeHooks
728
-
729
- Immunio.agent.register_plugin(
730
- 'ActiveRecord::Sanitization',
731
- ActiveRecord::VERSION::STRING)
732
709
  end
733
710
 
734
711
  Arel::Visitors::ToSql.send :include, Immunio::ArelToSqlHooks
735
712
 
736
- Immunio.agent.register_plugin(
737
- 'Arel::Visitors::ToSql',
738
- ActiveRecord::VERSION::STRING)
739
-
740
713
  ActiveRecord::ConnectionAdapters::AbstractAdapter.send(
741
714
  :include,
742
715
  Immunio::QueryExecutionHooks)
743
-
744
- Immunio.agent.register_plugin(
745
- 'ActiveRecord::ConnectionAdapters::AbstractAdapter',
746
- ActiveRecord::VERSION::STRING)
@@ -365,34 +365,24 @@ module Immunio
365
365
  end
366
366
  end
367
367
 
368
+ # NOTE: ActiveRecord plugin status is set in lib/immunio/rails.rb
369
+
368
370
  module ActiveRecord
369
371
  if defined? Relation
370
372
  Relation.send(
371
373
  :include,
372
374
  Immunio::RelationHooks)
373
375
 
374
- Immunio.agent.register_plugin(
375
- 'ActiveRecord::Relation',
376
- ActiveRecord::VERSION::STRING)
377
-
378
376
  if defined? SpawnMethods
379
377
  Relation.send(
380
378
  :include,
381
379
  Immunio::SpawnHooks)
382
-
383
- Immunio.agent.register_plugin(
384
- 'ActiveRecord::SpawnMethods',
385
- ActiveRecord::VERSION::STRING)
386
380
  end
387
381
 
388
382
  if defined? Querying
389
383
  Relation.send(
390
384
  :include,
391
385
  Immunio::QueryingHooks)
392
-
393
- Immunio.agent.register_plugin(
394
- 'ActiveRecord::Querying',
395
- ActiveRecord::VERSION::STRING)
396
386
  end
397
387
  end
398
388
 
@@ -400,10 +390,6 @@ module ActiveRecord
400
390
  StatementCache.send(
401
391
  :include,
402
392
  Immunio::StatementCacheHooks)
403
-
404
- Immunio.agent.register_plugin(
405
- 'ActiveRecord::StatementCache',
406
- ActiveRecord::VERSION::STRING)
407
393
  end
408
394
 
409
395
  module Associations
@@ -411,10 +397,6 @@ module ActiveRecord
411
397
  HasManyThroughAssociation.send(
412
398
  :include,
413
399
  Immunio::HasManyThroughAssociationHooks)
414
-
415
- Immunio.agent.register_plugin(
416
- 'ActiveRecord::Associations::HasManyThroughAssociation',
417
- ActiveRecord::VERSION::STRING)
418
400
  end
419
401
  end
420
402
  end
@@ -6,79 +6,79 @@ rescue LoadError # rubocop:disable Lint/HandleExceptions
6
6
  # Ignore
7
7
  end
8
8
 
9
- if defined? Authlogic
10
- module Immunio
11
- module Authlogic
12
- module SessionHooks
13
- def self.included(klass)
14
- klass.class_eval do
15
- include InstanceMethods
16
- after_create :immunio_login
17
- validate :immunio_check_failed_login
18
- before_destroy :immunio_logout
19
- after_persisting :immunio_set_user
9
+ Immunio::Plugin.load 'Authlogic' do |plugin|
10
+ if defined? Authlogic
11
+ module Immunio
12
+ module Authlogic
13
+ module SessionHooks
14
+ def self.included(klass)
15
+ klass.class_eval do
16
+ include InstanceMethods
17
+ after_create :immunio_login
18
+ validate :immunio_check_failed_login
19
+ before_destroy :immunio_logout
20
+ after_persisting :immunio_set_user
21
+ end
20
22
  end
21
- end
22
-
23
- module InstanceMethods
24
- private
25
- def opts
26
- info = {plugin: "authlogic"}
27
23
 
28
- if defined?(:record) && record
29
- # record is set when already logged in, e.g. you are now logging out
30
- info[:user_record] = record
31
- elsif defined?(:attempted_record) && attempted_record
32
- # attempted_record is set when attempting to log in and the user record has been fetched
33
- info[:user_record] = attempted_record
34
- end
24
+ module InstanceMethods
25
+ private
26
+ def opts
27
+ info = {plugin: "authlogic"}
35
28
 
36
- # credentials are set when the user attempts to log in
37
- if defined?(:credentials) && defined?(:login_field)
38
- login = credentials[login_field.to_sym]
39
- info[:username] = login if login
40
- end
29
+ if defined?(:record) && record
30
+ # record is set when already logged in, e.g. you are now logging out
31
+ info[:user_record] = record
32
+ elsif defined?(:attempted_record) && attempted_record
33
+ # attempted_record is set when attempting to log in and the user record has been fetched
34
+ info[:user_record] = attempted_record
35
+ end
41
36
 
42
- info
43
- end
37
+ # credentials are set when the user attempts to log in
38
+ if defined?(:credentials) && defined?(:login_field)
39
+ login = credentials[login_field.to_sym]
40
+ info[:username] = login if login
41
+ end
44
42
 
45
- def immunio_login
46
- Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
47
- Immunio.logger.debug {"Authlogic instrumentation fired for login with opts #{opts}"}
48
- Immunio.login opts
43
+ info
49
44
  end
50
- end
51
45
 
52
- def immunio_check_failed_login
53
- if errors.any?
46
+ def immunio_login
54
47
  Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
55
- Immunio.logger.debug { "Authlogic instrumentation fired for before_failure with opts #{opts}" }
56
- Immunio.failed_login opts
48
+ Immunio.logger.debug {"Authlogic instrumentation fired for login with opts #{opts}"}
49
+ Immunio.login opts
57
50
  end
58
51
  end
59
- end
60
52
 
61
- def immunio_logout
62
- Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
63
- Immunio.logger.debug { "Authlogic instrumentation fired for logout with opts #{opts}" }
64
- Immunio.logout opts
53
+ def immunio_check_failed_login
54
+ if errors.any?
55
+ Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
56
+ Immunio.logger.debug { "Authlogic instrumentation fired for before_failure with opts #{opts}" }
57
+ Immunio.failed_login opts
58
+ end
59
+ end
65
60
  end
66
- end
67
61
 
68
- def immunio_set_user
69
- Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
70
- Immunio.logger.debug { "Authlogic instrumentation fired for after_set_user with opts #{opts}" }
71
- Immunio.set_user opts
62
+ def immunio_logout
63
+ Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
64
+ Immunio.logger.debug { "Authlogic instrumentation fired for logout with opts #{opts}" }
65
+ Immunio.logout opts
66
+ end
72
67
  end
73
- end
68
+
69
+ def immunio_set_user
70
+ Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
71
+ Immunio.logger.debug { "Authlogic instrumentation fired for after_set_user with opts #{opts}" }
72
+ Immunio.set_user opts
73
+ end
74
+ end
75
+ end
74
76
  end
75
77
  end
76
78
  end
77
- end
78
79
 
79
- Authlogic::Session::Base.send :include, Immunio::Authlogic::SessionHooks
80
+ Authlogic::Session::Base.send :include, Immunio::Authlogic::SessionHooks
80
81
 
81
- Immunio.agent.register_plugin(
82
- 'Authlogic',
83
- Gem.loaded_specs['authlogic'].version.to_s)
84
- end
82
+ plugin.loaded! Gem.loaded_specs['authlogic'].version.to_s
83
+ end
84
+ end
@@ -23,8 +23,7 @@ module Immunio
23
23
  end
24
24
  end
25
25
 
26
- ActionController::Base.send :include, Immunio::CsrfHook
27
-
28
- Immunio.agent.register_plugin(
29
- 'ActionController (CSRF)',
30
- ActionPack::VERSION::STRING)
26
+ Immunio::Plugin.load 'ActionController (CSRF)' do |plugin|
27
+ ActionController::Base.send :include, Immunio::CsrfHook
28
+ plugin.loaded! ActionPack::VERSION::STRING
29
+ end
@@ -6,38 +6,40 @@ rescue LoadError # rubocop:disable Lint/HandleExceptions
6
6
  # Ignore
7
7
  end
8
8
 
9
- if defined? Devise
10
- module Immunio
11
- # Hook into password recovery feature to trigger the `framework_password_reset` hook.
12
- module DeviseRecoverableHooks
13
- extend ActiveSupport::Concern
14
-
15
- included do
16
- Immunio::Utils.alias_method_chain self, :send_reset_password_instructions, :immunio
17
- end
9
+ Immunio::Plugin.load 'Devise' do |plugin|
10
+ if defined? Devise
11
+ module Immunio
12
+ # Hook into password recovery feature to trigger the `framework_password_reset` hook.
13
+ module DeviseRecoverableHooks
14
+ extend ActiveSupport::Concern
15
+
16
+ included do
17
+ Immunio::Utils.alias_method_chain self, :send_reset_password_instructions, :immunio
18
+ end
18
19
 
19
- def send_reset_password_instructions_with_immunio(attributes={})
20
- Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
21
- Immunio.logger.debug { "Devise instrumentation fired for send_reset_password_instructions" }
20
+ def send_reset_password_instructions_with_immunio(attributes={})
21
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
22
+ Immunio.logger.debug { "Devise instrumentation fired for send_reset_password_instructions" }
22
23
 
23
- recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
24
+ recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
24
25
 
25
- if recoverable.persisted? # Found
26
- Immunio.password_reset user_record: recoverable, plugin: 'devise'
27
- else
28
- Immunio.failed_password_reset email: recoverable.email, plugin: 'devise'
29
- end
26
+ if recoverable.persisted? # Found
27
+ Immunio.password_reset user_record: recoverable, plugin: 'devise'
28
+ else
29
+ Immunio.failed_password_reset email: recoverable.email, plugin: 'devise'
30
+ end
30
31
 
31
- Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
32
- send_reset_password_instructions_without_immunio(attributes)
32
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
33
+ send_reset_password_instructions_without_immunio(attributes)
34
+ end
33
35
  end
34
36
  end
35
37
  end
36
38
  end
37
- end
38
39
 
39
- Devise::Models::Recoverable::ClassMethods.send :include, Immunio::DeviseRecoverableHooks
40
+ Devise::Models::Recoverable::ClassMethods.send :include, Immunio::DeviseRecoverableHooks
40
41
 
41
- require 'devise/version'
42
- Immunio.agent.register_plugin('Devise', Devise::VERSION)
43
- end
42
+ require 'devise/version'
43
+ plugin.loaded! Devise::VERSION
44
+ end
45
+ end
@@ -56,6 +56,10 @@ module Immunio
56
56
  Addrinfo.getaddrinfo(hostname, nil).first.ip_address rescue SocketError
57
57
  end
58
58
 
59
+ def plugins
60
+ Immunio::Plugin.registered
61
+ end
62
+
59
63
  def report
60
64
  @reported = true
61
65
 
@@ -76,7 +80,7 @@ module Immunio
76
80
  hostname_ip: hostname_ip,
77
81
  ips: ips
78
82
  },
79
- plugins: Immunio.agent.plugins
83
+ plugins: plugins
80
84
  }
81
85
 
82
86
  Immunio.agent.environment = info
@@ -37,9 +37,8 @@ module Immunio
37
37
  end
38
38
  end
39
39
 
40
- if Immunio::agent.plugin_enabled?("eval") then
40
+ Immunio::Plugin.load 'Kernel (Eval)', feature: 'eval' do |plugin|
41
41
  Kernel.send :include, Immunio::KernelEvalHook
42
42
  Kernel.extend Immunio::KernelEvalHook
43
- Immunio.logger.debug { "Eval: All hooks installed." }
44
- Immunio.agent.register_plugin('Kernel (Eval)', RUBY_VERSION)
43
+ plugin.loaded! RUBY_VERSION
45
44
  end
@@ -4,7 +4,6 @@ module Immunio
4
4
  # Rack middleware running at the very end of the stack to finish HTTP requests.
5
5
  class HTTPFinisher
6
6
  def initialize(app)
7
- Immunio.agent.register_plugin(self.class.name)
8
7
  @app = app
9
8
  end
10
9
 
@@ -5,7 +5,6 @@ module Immunio
5
5
  # Rack middleware tracking HTTP requests and responses and triggers the proper hooks.
6
6
  class HTTPTracker
7
7
  def initialize(app)
8
- Immunio.agent.register_plugin(self.class.name)
9
8
  @app = app
10
9
  end
11
10
 
@@ -100,19 +100,16 @@ module Immunio
100
100
  end
101
101
 
102
102
  # Add FileIO hooks if enabled
103
- if Immunio.agent.plugin_enabled?("file_io")
103
+ Immunio::Plugin.load 'IO', feature: 'file_io' do |plugin|
104
104
  IO.extend Immunio::IOClassHooks
105
105
  File.extend Immunio::FileClassHooks
106
- Immunio.logger.debug { "IO: All hooks installed." }
107
- Immunio.agent.register_plugin('IO', RUBY_VERSION)
108
- Immunio.agent.register_plugin('File', RUBY_VERSION)
106
+ plugin.loaded! RUBY_VERSION
109
107
  end
110
108
 
111
109
  # Add Kernel hooks if enabled
112
- if Immunio.agent.plugin_enabled?("shell_command")
110
+ Immunio::Plugin.load 'Kernel (shell_command)', feature: 'shell_command' do |plugin|
113
111
  # Both are necessary to hook calling both Kernel.open() and open() etc.
114
112
  Kernel.send :include, Immunio::KernelModuleHooks
115
113
  Kernel.extend Immunio::KernelModuleHooks
116
- Immunio.logger.debug { "Shell: All hooks installed." }
117
- Immunio.agent.register_plugin('Kernel (Module)', RUBY_VERSION)
114
+ plugin.loaded! RUBY_VERSION
118
115
  end
@@ -36,11 +36,8 @@ module Immunio
36
36
  end
37
37
  end
38
38
 
39
- if Immunio::agent.plugin_enabled?("redirect") then
39
+ Immunio::Plugin.load 'ActionController (Redirect)', feature: 'redirect' do |plugin|
40
40
  ActionController::Base.send :include, Immunio::RedirectHook
41
- Immunio.logger.debug { "Redirect: All hooks installed." }
42
41
 
43
- Immunio.agent.register_plugin(
44
- 'ActionController (Redirect)',
45
- ActionPack::VERSION::STRING)
42
+ plugin.loaded! ActionPack::VERSION::STRING
46
43
  end
@@ -6,67 +6,69 @@ rescue LoadError # rubocop:disable Lint/HandleExceptions
6
6
  # Ignore
7
7
  end
8
8
 
9
- if defined?(Warden::Manager)
10
- class Warden::Manager
11
- after_authentication do |user|
12
- Immunio::Request.time "plugin", "Warden::Manager.after_authentication" do
13
- Immunio.logger.debug { "Warden instrumentation fired for after_authentication" }
14
- Immunio.login user_record: user, plugin: "warden"
9
+ Immunio::Plugin.load 'Warden' do |plugin|
10
+ if defined?(Warden::Manager)
11
+ class Warden::Manager
12
+ after_authentication do |user|
13
+ Immunio::Request.time "plugin", "Warden::Manager.after_authentication" do
14
+ Immunio.logger.debug { "Warden instrumentation fired for after_authentication" }
15
+ Immunio.login user_record: user, plugin: "warden"
16
+ end
15
17
  end
16
- end
17
18
 
18
- before_failure do |env|
19
- Immunio::Request.time "plugin", "Warden::Manager.before_failure" do
20
- info = {plugin: "warden"}
19
+ before_failure do |env|
20
+ Immunio::Request.time "plugin", "Warden::Manager.before_failure" do
21
+ info = {plugin: "warden"}
21
22
 
22
- # Devise uses these specific form fields for authentication by default
23
- user_found = false
24
- [:username, :email].each do |attr|
25
- value = env.fetch("rack.request.form_hash", {}).fetch("user", {})[attr.to_s]
26
- if value
27
- info[attr] = value
28
- user_found = true
23
+ # Devise uses these specific form fields for authentication by default
24
+ user_found = false
25
+ [:username, :email].each do |attr|
26
+ value = env.fetch("rack.request.form_hash", {}).fetch("user", {})[attr.to_s]
27
+ if value
28
+ info[attr] = value
29
+ user_found = true
30
+ end
29
31
  end
30
- end
31
32
 
32
- # before_failure is called under many circumstances, but unfortunately
33
- # there's no easy way to tell why. If we can't figure out who the
34
- # attempted user was, don't report it as a failed login.
35
- if user_found
36
- Immunio.logger.debug { "Warden instrumentation fired for before_failure" }
37
- Immunio.failed_login info
38
- else
39
- Immunio.logger.debug { "Failed to find user info for Warden failure, ignoring instead of reporting as failed login" }
33
+ # before_failure is called under many circumstances, but unfortunately
34
+ # there's no easy way to tell why. If we can't figure out who the
35
+ # attempted user was, don't report it as a failed login.
36
+ if user_found
37
+ Immunio.logger.debug { "Warden instrumentation fired for before_failure" }
38
+ Immunio.failed_login info
39
+ else
40
+ Immunio.logger.debug { "Failed to find user info for Warden failure, ignoring instead of reporting as failed login" }
41
+ end
40
42
  end
41
43
  end
42
- end
43
44
 
44
- after_set_user do |user|
45
- Immunio::Request.time "plugin", "Warden::Manager.after_set_user" do
46
- Immunio.logger.debug { "Warden instrumentation fired for after_set_user" }
47
- Immunio.set_user user_record: user, plugin: "warden"
45
+ after_set_user do |user|
46
+ Immunio::Request.time "plugin", "Warden::Manager.after_set_user" do
47
+ Immunio.logger.debug { "Warden instrumentation fired for after_set_user" }
48
+ Immunio.set_user user_record: user, plugin: "warden"
49
+ end
48
50
  end
49
- end
50
51
 
51
- before_logout do |user|
52
- Immunio::Request.time "plugin", "Warden::Manager.before_logout" do
53
- Immunio.logger.debug { "Warden instrumentation fired for before_logout" }
54
- Immunio.logout user_record: user, plugin: "warden"
52
+ before_logout do |user|
53
+ Immunio::Request.time "plugin", "Warden::Manager.before_logout" do
54
+ Immunio.logger.debug { "Warden instrumentation fired for before_logout" }
55
+ Immunio.logout user_record: user, plugin: "warden"
56
+ end
55
57
  end
56
- end
57
58
 
58
- # Force lookup of user info for all requests.
59
- def call_with_immunio(env)
60
- call_without_immunio(env)
61
- ensure
62
- Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
63
- env['warden'].user if env['warden']
59
+ # Force lookup of user info for all requests.
60
+ def call_with_immunio(env)
61
+ call_without_immunio(env)
62
+ ensure
63
+ Immunio::Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
64
+ env['warden'].user if env['warden']
65
+ end
64
66
  end
67
+ alias :call_without_immunio :call
68
+ alias :call :call_with_immunio
65
69
  end
66
- alias :call_without_immunio :call
67
- alias :call :call_with_immunio
68
- end
69
70
 
70
- require 'warden/version'
71
- Immunio.agent.register_plugin('Warden', Warden::VERSION)
72
- end
71
+ require 'warden/version'
72
+ plugin.loaded! Warden::VERSION
73
+ end
74
+ end
data/lib/immunio/rails.rb CHANGED
@@ -7,17 +7,21 @@ require_relative "plugins/warden"
7
7
 
8
8
  module Immunio
9
9
  class Engine < ::Rails::Engine
10
- config.app_middleware.insert 0, HTTPFinisher
11
- config.app_middleware.insert_before ActionDispatch::ShowExceptions, HTTPTracker
12
- config.app_middleware.insert_after ActionDispatch::DebugExceptions, ExceptionHandler
13
- config.app_middleware.use EnvironmentReporter
10
+ Immunio::Plugin.load 'Middlewares' do |plugin|
11
+ config.app_middleware.insert 0, HTTPFinisher
12
+ config.app_middleware.insert_before ActionDispatch::ShowExceptions, HTTPTracker
13
+ config.app_middleware.insert_after ActionDispatch::DebugExceptions, ExceptionHandler
14
+ config.app_middleware.use EnvironmentReporter
15
+ plugin.loaded! Rails.version
16
+ end
14
17
 
15
18
  config.action_dispatch.rescue_responses.merge!('Immunio::RequestBlocked' => :forbidden)
16
19
 
17
- if Immunio::agent.plugin_enabled?("sqli") then
20
+ Immunio::Plugin.load 'ActionRecord', feature: 'sqli' do |plugin|
18
21
  initializer "immunio.active_record", after: "active_record.initialize_database" do
19
22
  ActiveSupport.on_load(:active_record) do
20
23
  require_relative "plugins/active_record"
24
+ plugin.loaded! ActiveRecord::VERSION::STRING
21
25
  end
22
26
  end
23
27
  end
@@ -1,5 +1,5 @@
1
1
  module Immunio
2
2
  AGENT_TYPE = "agent-ruby"
3
- VERSION = "1.1.1"
3
+ VERSION = "1.1.2"
4
4
  VM_VERSION = "2.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: immunio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Immunio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-07 00:00:00.000000000 Z
11
+ date: 2016-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -138,6 +138,7 @@ files:
138
138
  - lib/immunio/errors.rb
139
139
  - lib/immunio/immunio_ca.crt
140
140
  - lib/immunio/logger.rb
141
+ - lib/immunio/plugin.rb
141
142
  - lib/immunio/plugins/action_dispatch.rb
142
143
  - lib/immunio/plugins/action_view.rb
143
144
  - lib/immunio/plugins/active_record.rb