google-authenticator-rails 1.3.0 → 1.4.0

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: 6e07d6a504c407dcba055225bbf2104d5983bf25
4
- data.tar.gz: 93f1201bd747aa4347a29451eaca75aafd47d592
3
+ metadata.gz: 1b0e27a878d00efaf2b62b132ee490bed3b51135
4
+ data.tar.gz: 20d199184ac7af414fa73af13f2ca25f09df9818
5
5
  SHA512:
6
- metadata.gz: d0669bb6d3a4ab9302f5949e04a8c55ae773897616677df1e41c7d822ba96d378a76db1c6fa9d4ef737542407523ec138926ddbcfd0c2741d0048a5e3927b001
7
- data.tar.gz: 8b6d963870e3c18b50cc4b4869e84d8caf147f098589e43981291678bb4eb6920176d4899278ca4d4b194a43ab6c5abc26fa5c683e467fdebf7aed3506c97326
6
+ metadata.gz: 17402d2412a5d8eef21fc856f3db1c50df5258e141144b2680842836429e5ef69d286246519296d6a0112de3150c30e2203e1b6b543635632dcca4f756dc7f94
7
+ data.tar.gz: 139193758c98d494c3b143edf136190b0d4f90ab6800af6d077464c8e2d0ed464b205d1c2089803e5296ea396c0045038e49fa686fbc74c3dc00329e623893df
@@ -0,0 +1,46 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ ## Our Standards
8
+
9
+ Examples of behavior that contributes to creating a positive environment include:
10
+
11
+ * Using welcoming and inclusive language
12
+ * Being respectful of differing viewpoints and experiences
13
+ * Gracefully accepting constructive criticism
14
+ * Focusing on what is best for the community
15
+ * Showing empathy towards other community members
16
+
17
+ Examples of unacceptable behavior by participants include:
18
+
19
+ * The use of sexualized language or imagery and unwelcome sexual attention or advances
20
+ * Trolling, insulting/derogatory comments, and personal or political attacks
21
+ * Public or private harassment
22
+ * Publishing others' private information, such as a physical or electronic address, without explicit permission
23
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
24
+
25
+ ## Our Responsibilities
26
+
27
+ Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28
+
29
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ ## Scope
32
+
33
+ This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34
+
35
+ ## Enforcement
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jared.online@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38
+
39
+ Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40
+
41
+ ## Attribution
42
+
43
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44
+
45
+ [homepage]: http://contributor-covenant.org
46
+ [version]: http://contributor-covenant.org/version/1/4/
data/README.md CHANGED
@@ -327,6 +327,33 @@ If you want to manually destroy the MFA cookie (for example, when a user logs ou
327
327
  UserMfaSession::destroy
328
328
  ```
329
329
 
330
+ ## Storing Secrets in Encrypted Form
331
+
332
+ Normally, if an attacker gets access to the application database, they will be able to generate correct authentication codes,
333
+ elmininating the security gains from two-factor authentication. If the application's ```secret_key_base``` is handled more securely
334
+ than the database (by, for example, never putting it on the server filesystem), protection against database compromise can
335
+ be gained by setting the ```:encrypt_secrets``` option to ```true```. Newly-created secrets will then be stored in encrypted
336
+ form.
337
+
338
+ Existing non-encrypted secrets for all models for which the ```:encrypt_secrets``` option has been set to ```true```
339
+ can be encrypted by running
340
+ ```bash
341
+ rails google_authenticator:encrypt_secrets
342
+ ```
343
+ This may be reversed by running
344
+ ```bash
345
+ rails google_authenticator:decrypt_secrets
346
+ ```
347
+ then by removing, or setting ```false```, the ```:encrypt_secrets``` option.
348
+
349
+ If ```secret_key_base``` needs to change, set ```old_secret_key_base``` to the old key in ```config/secrets.yml``` before generating the new key.
350
+ Then run
351
+ ```bash
352
+ rails google_authenticator:reencrypt_secrets
353
+ ```
354
+ to change all encrypted google secret fields to use the new key.
355
+
356
+
330
357
  ## Contributing
331
358
 
332
359
  1. Fork it
@@ -22,6 +22,7 @@ Gem::Specification.new do |gem|
22
22
  gem.version = Google::Authenticator::Rails::VERSION
23
23
 
24
24
  gem.add_dependency "rotp", "= 1.6.1"
25
+ gem.add_dependency "rails"
25
26
  gem.add_dependency "activerecord"
26
27
  gem.add_dependency "google-qr"
27
28
  gem.add_dependency "actionpack"
@@ -1,5 +1,6 @@
1
1
  # Stuff the gem requires
2
2
  #
3
+ require 'rails'
3
4
  require 'active_support'
4
5
  require 'active_record'
5
6
  require 'openssl'
@@ -23,6 +24,12 @@ GOOGLE_AUTHENTICATOR_RAILS_PATH = File.dirname(__FILE__) + "/google-authenticato
23
24
  # Sets up some basic accessors for use with the ROTP module
24
25
  #
25
26
  module GoogleAuthenticatorRails
27
+ class Railtie < Rails::Railtie
28
+ rake_tasks do
29
+ load 'tasks/google_authenticator.rake'
30
+ end
31
+ end
32
+
26
33
  # Drift is set to 6 because ROTP drift is not inclusive. This allows a drift of 5 seconds.
27
34
  DRIFT = 6
28
35
 
@@ -20,6 +20,7 @@ module GoogleAuthenticatorRails # :nodoc:
20
20
  #
21
21
  # @user = user.new
22
22
  # @user.set_google_secret # => true
23
+ # @user.google_secret_value # => 16-character decrypted secret
23
24
  # @user.google_qr_uri # => http://path.to.google/qr?with=params
24
25
  # @user.google_authentic?(123456) # => true
25
26
  #
@@ -84,18 +85,22 @@ module GoogleAuthenticatorRails # :nodoc:
84
85
  # to ""
85
86
  # [:qr_size] the size of the QR code generated by `google_qr_uri`, defaults
86
87
  # to "200x200"
88
+ # If [:encrypt_secrets] is true, secrets will be encrypted with a key derived from
89
+ # `secret_key_base`.
90
+ #
87
91
  def acts_as_google_authenticated(options = {})
88
- @google_label_column = options[:column_name] || :email
89
- @google_label_method = options[:method] || :default_google_label_method
90
- @google_secret_column = options[:google_secret_column] || :google_secret
91
- @google_lookup_token = options[:lookup_token] || :persistence_token
92
- @google_drift = options[:drift] || GoogleAuthenticatorRails::DRIFT
93
- @google_issuer = options[:issuer]
94
- @google_qr_size = options[:qr_size] || '200x200'
92
+ @google_label_column = options[:column_name] || :email
93
+ @google_label_method = options[:method] || :default_google_label_method
94
+ @google_secret_column = options[:google_secret_column] || :google_secret
95
+ @google_lookup_token = options[:lookup_token] || :persistence_token
96
+ @google_drift = options[:drift] || GoogleAuthenticatorRails::DRIFT
97
+ @google_issuer = options[:issuer]
98
+ @google_qr_size = options[:qr_size] || '200x200'
99
+ @google_secrets_encrypted = !!options[:encrypt_secrets]
95
100
 
96
101
  puts ":skip_attr_accessible is no longer required. Called from #{Kernel.caller[0]}}" if options.has_key?(:skip_attr_accessible)
97
102
 
98
- [:google_label_column, :google_label_method, :google_secret_column, :google_lookup_token, :google_drift, :google_issuer, :google_qr_size].each do |cattr|
103
+ [:google_label_column, :google_label_method, :google_secret_column, :google_lookup_token, :google_drift, :google_issuer, :google_qr_size, :google_secrets_encrypted].each do |cattr|
99
104
  self.singleton_class.class_eval { attr_reader cattr }
100
105
  end
101
106
 
@@ -1,9 +1,19 @@
1
1
  module GoogleAuthenticatorRails # :nodoc:
2
+ mattr_accessor :secret_encryptor
2
3
  module ActiveRecord # :nodoc:
3
4
  module Helpers
5
+ def google_secret_value
6
+ if @google_secret_value_cached
7
+ @google_secret_value
8
+ else
9
+ @google_secret_value_cached = true
10
+ secret_in_db = google_secret_column_value
11
+ @google_secret_value = secret_in_db && self.class.google_secrets_encrypted ? google_secret_encryptor.decrypt_and_verify(secret_in_db) : secret_in_db
12
+ end
13
+ end
14
+
4
15
  def set_google_secret
5
- self.__send__("#{self.class.google_secret_column}=", GoogleAuthenticatorRails::generate_secret)
6
- save
16
+ change_google_secret_to!(GoogleAuthenticatorRails::generate_secret)
7
17
  end
8
18
 
9
19
  def google_authentic?(code)
@@ -29,19 +39,38 @@ module GoogleAuthenticatorRails # :nodoc:
29
39
  def google_token_value
30
40
  self.__send__(self.class.google_lookup_token)
31
41
  end
42
+
43
+ def encrypt_google_secret!
44
+ change_google_secret_to!(google_secret_column_value)
45
+ end
32
46
 
33
47
  private
34
48
  def default_google_label_method
35
49
  self.__send__(self.class.google_label_column)
36
50
  end
37
-
38
- def google_secret_value
51
+
52
+ def google_secret_column_value
39
53
  self.__send__(self.class.google_secret_column)
40
54
  end
41
55
 
56
+ def change_google_secret_to!(secret, encrypt = self.class.google_secrets_encrypted)
57
+ @google_secret_value = secret
58
+ self.__send__("#{self.class.google_secret_column}=", secret && encrypt ? google_secret_encryptor.encrypt_and_sign(secret) : secret)
59
+ @google_secret_value_cached = true
60
+ save!
61
+ end
62
+
42
63
  def google_issuer
43
64
  self.class.google_issuer
44
65
  end
66
+
67
+ def google_secret_encryptor
68
+ GoogleAuthenticatorRails.secret_encryptor ||= GoogleAuthenticatorRails::ActiveRecord::Helpers.get_google_secret_encryptor
69
+ end
70
+
71
+ def self.get_google_secret_encryptor
72
+ ActiveSupport::MessageEncryptor.new(Rails.application.key_generator.generate_key('Google-secret encryption key', 32))
73
+ end
45
74
  end
46
75
  end
47
76
  end
@@ -1,7 +1,7 @@
1
1
  module Google
2
2
  module Authenticator
3
3
  module Rails
4
- VERSION = "1.3.0"
4
+ VERSION = "1.4.0"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,46 @@
1
+ namespace :google_authenticator do
2
+
3
+ def do_encrypt(already_encrypted, op_name)
4
+ ActiveRecord::Base.transaction do
5
+ match_op = " #{already_encrypted ? '>' : '='} 16"
6
+ # Adapted from https://stackoverflow.com/a/8248849/7478194
7
+ Dir[Rails.root.join('app/models/*.rb').to_s].each do |filename|
8
+ klass = File.basename(filename, '.rb').camelize.constantize
9
+ next unless klass.ancestors.include?(ActiveRecord::Base) && klass.try(:google_secrets_encrypted)
10
+ puts "#{op_name} model #{klass.name.inspect} (table #{klass.table_name.inspect})"
11
+ klass.where("LENGTH(#{klass.google_secret_column})#{match_op}").find_each do |record|
12
+ yield record
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ desc 'Encrypt all secret columns (add the :encrypt_secret options *before* running)'
19
+ task encrypt_secrets: :environment do
20
+ do_encrypt(false, 'Encrypting') { |record| record.encrypt_google_secret! }
21
+ end
22
+
23
+ desc 'Re-encrypt all secret columns from old_secret_key_base to secret_key_base'
24
+ task reencrypt_secrets: :environment do
25
+ if Rails.application.secrets.old_secret_key_base.blank?
26
+ puts 'old_secret_key_base is not set in config/secrets.yml'
27
+ else
28
+ secret_encryptor = GoogleAuthenticatorRails::ActiveRecord::Helpers.get_google_secret_encryptor
29
+ Rails.application.secrets[:secret_key_base] = Rails.application.secrets.old_secret_key_base
30
+ Rails.application.instance_eval { @caching_key_generator = nil }
31
+ old_secret_encryptor = GoogleAuthenticatorRails::ActiveRecord::Helpers.get_google_secret_encryptor
32
+ do_encrypt(true, 'Re-encrypting') do |record|
33
+ GoogleAuthenticatorRails.secret_encryptor = old_secret_encryptor
34
+ plain_secret = record.google_secret_value
35
+ GoogleAuthenticatorRails.secret_encryptor = secret_encryptor
36
+ record.send(:change_google_secret_to!, plain_secret)
37
+ end
38
+ end
39
+ end
40
+
41
+ desc 'Decrypt all secret columns (remove the :encrypt_secret options *after* running)'
42
+ task decrypt_secrets: :environment do
43
+ do_encrypt(true, 'Decrypting') { |record| record.send(:change_google_secret_to!, record.google_secret_value, false) }
44
+ end
45
+
46
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-authenticator-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jared McFarland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-10 00:00:00.000000000 Z
11
+ date: 2017-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rotp
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.6.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: activerecord
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -133,6 +147,7 @@ files:
133
147
  - ".rspec"
134
148
  - ".travis.yml"
135
149
  - Appraisals
150
+ - CODE_OF_CONDUCT.md
136
151
  - CONTRIBUTING.md
137
152
  - Gemfile
138
153
  - LICENSE
@@ -157,6 +172,7 @@ files:
157
172
  - lib/google-authenticator-rails/session/base.rb
158
173
  - lib/google-authenticator-rails/session/persistence.rb
159
174
  - lib/google-authenticator-rails/version.rb
175
+ - lib/tasks/google_authenticator.rake
160
176
  - spec/action_controller/integration_spec.rb
161
177
  - spec/action_controller/rails_adapter_spec.rb
162
178
  - spec/google_authenticator_spec.rb
@@ -182,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
198
  version: '0'
183
199
  requirements: []
184
200
  rubyforge_project:
185
- rubygems_version: 2.4.8
201
+ rubygems_version: 2.6.14
186
202
  signing_key:
187
203
  specification_version: 4
188
204
  summary: Add the ability to use the Google Authenticator with ActiveRecord.