two_factor_authentication 1.1.4 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +13 -6
  3. data/CHANGELOG.md +109 -0
  4. data/Gemfile +8 -2
  5. data/README.md +182 -54
  6. data/app/controllers/devise/two_factor_authentication_controller.rb +1 -1
  7. data/config/locales/fr.yml +7 -0
  8. data/lib/generators/active_record/templates/migration.rb +6 -11
  9. data/lib/two_factor_authentication.rb +3 -0
  10. data/lib/two_factor_authentication/hooks/two_factor_authenticatable.rb +26 -2
  11. data/lib/two_factor_authentication/models/two_factor_authenticatable.rb +89 -23
  12. data/lib/two_factor_authentication/schema.rb +12 -4
  13. data/lib/two_factor_authentication/version.rb +1 -1
  14. data/spec/controllers/two_factor_authentication_controller_spec.rb +33 -0
  15. data/spec/features/two_factor_authenticatable_spec.rb +164 -28
  16. data/spec/generators/active_record/two_factor_authentication_generator_spec.rb +36 -0
  17. data/spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb +213 -117
  18. data/spec/rails_app/app/models/encrypted_user.rb +14 -0
  19. data/spec/rails_app/app/models/user.rb +1 -2
  20. data/spec/rails_app/config/environments/test.rb +3 -0
  21. data/spec/rails_app/config/initializers/devise.rb +3 -1
  22. data/spec/rails_app/db/migrate/20151224171231_add_encrypted_columns_to_user.rb +9 -0
  23. data/spec/rails_app/db/migrate/20151224180310_populate_otp_column.rb +19 -0
  24. data/spec/rails_app/db/migrate/20151228230340_remove_otp_secret_key_from_user.rb +5 -0
  25. data/spec/rails_app/db/schema.rb +16 -14
  26. data/spec/spec_helper.rb +1 -0
  27. data/spec/support/authenticated_model_helper.rb +26 -2
  28. data/spec/support/controller_helper.rb +16 -0
  29. data/spec/support/features_spec_helper.rb +24 -1
  30. data/two_factor_authentication.gemspec +1 -0
  31. metadata +25 -3
  32. data/spec/controllers/two_factor_auth_spec.rb +0 -18
@@ -224,7 +224,7 @@ Devise.setup do |config|
224
224
  # config.navigational_formats = ['*/*', :html]
225
225
 
226
226
  # The default HTTP method used to sign out a resource. Default is :delete.
227
- config.sign_out_via = :delete
227
+ config.sign_out_via = Rails.env.test? ? :get : :delete
228
228
 
229
229
  # ==> OmniAuth
230
230
  # Add a new OmniAuth provider. Check the wiki for more information on setting
@@ -253,4 +253,6 @@ Devise.setup do |config|
253
253
  # When using omniauth, Devise cannot automatically set Omniauth path,
254
254
  # so you need to do it manually. For the users scope, it would be:
255
255
  # config.omniauth_path_prefix = '/my_engine/users/auth'
256
+
257
+ config.otp_secret_encryption_key = '0a8283fba984da1de24e4df1e93046cb53c5787944ef037b2dbf3e61d20fe11f25e25a855cec605fdf65b162329890d7230afdf64f681b4c32020281054e73ec'
256
258
  end
@@ -0,0 +1,9 @@
1
+ class AddEncryptedColumnsToUser < ActiveRecord::Migration
2
+ def change
3
+ add_column :users, :encrypted_otp_secret_key, :string
4
+ add_column :users, :encrypted_otp_secret_key_iv, :string
5
+ add_column :users, :encrypted_otp_secret_key_salt, :string
6
+
7
+ add_index :users, :encrypted_otp_secret_key, unique: true
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ class PopulateOtpColumn < ActiveRecord::Migration
2
+ def up
3
+ User.reset_column_information
4
+
5
+ User.find_each do |user|
6
+ user.otp_secret_key = user.read_attribute('otp_secret_key')
7
+ user.save!
8
+ end
9
+ end
10
+
11
+ def down
12
+ User.reset_column_information
13
+
14
+ User.find_each do |user|
15
+ user.otp_secret_key = ROTP::Base32.random_base32
16
+ user.save!
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ class RemoveOtpSecretKeyFromUser < ActiveRecord::Migration
2
+ def change
3
+ remove_column :users, :otp_secret_key, :string
4
+ end
5
+ end
@@ -9,30 +9,32 @@
9
9
  # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
10
  # you'll amass, the slower it'll run and the greater likelihood for issues).
11
11
  #
12
- # It's strongly recommended to check this file into your version control system.
12
+ # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20140407215513) do
14
+ ActiveRecord::Schema.define(version: 20151228230340) do
15
15
 
16
- create_table "users", :force => true do |t|
17
- t.string "email", :default => "", :null => false
18
- t.string "encrypted_password", :default => "", :null => false
16
+ create_table "users", force: :cascade do |t|
17
+ t.string "email", default: "", null: false
18
+ t.string "encrypted_password", default: "", null: false
19
19
  t.string "reset_password_token"
20
20
  t.datetime "reset_password_sent_at"
21
21
  t.datetime "remember_created_at"
22
- t.integer "sign_in_count", :default => 0, :null => false
22
+ t.integer "sign_in_count", default: 0, null: false
23
23
  t.datetime "current_sign_in_at"
24
24
  t.datetime "last_sign_in_at"
25
25
  t.string "current_sign_in_ip"
26
26
  t.string "last_sign_in_ip"
27
- t.datetime "created_at", :null => false
28
- t.datetime "updated_at", :null => false
29
- t.string "otp_secret_key"
30
- t.integer "second_factor_attempts_count", :default => 0
31
- t.string "nickname", :limit => 64
27
+ t.datetime "created_at", null: false
28
+ t.datetime "updated_at", null: false
29
+ t.integer "second_factor_attempts_count", default: 0
30
+ t.string "nickname", limit: 64
31
+ t.string "encrypted_otp_secret_key"
32
+ t.string "encrypted_otp_secret_key_iv"
33
+ t.string "encrypted_otp_secret_key_salt"
32
34
  end
33
35
 
34
- add_index "users", ["email"], :name => "index_users_on_email", :unique => true
35
- add_index "users", ["otp_secret_key"], :name => "index_users_on_otp_secret_key", :unique => true
36
- add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
36
+ add_index "users", ["email"], name: "index_users_on_email", unique: true
37
+ add_index "users", ["encrypted_otp_secret_key"], name: "index_users_on_encrypted_otp_secret_key", unique: true
38
+ add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
37
39
 
38
40
  end
@@ -3,6 +3,7 @@ require File.expand_path("../rails_app/config/environment.rb", __FILE__)
3
3
 
4
4
  require 'rspec/rails'
5
5
  require 'timecop'
6
+ require 'rack_session_access/capybara'
6
7
 
7
8
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
8
9
  RSpec.configure do |config|
@@ -1,10 +1,11 @@
1
1
  module AuthenticatedModelHelper
2
-
3
2
  def build_guest_user
4
3
  GuestUser.new
5
4
  end
6
5
 
7
- def create_user(attributes={})
6
+ def create_user(type = 'encrypted', attributes = {})
7
+ create_table_for_nonencrypted_user if type == 'not_encrypted'
8
+
8
9
  User.create!(valid_attributes(attributes))
9
10
  end
10
11
 
@@ -23,6 +24,29 @@ module AuthenticatedModelHelper
23
24
  "user#{@@email_count}@example.com"
24
25
  end
25
26
 
27
+ def create_table_for_nonencrypted_user
28
+ silence_stream(STDOUT) do
29
+ ActiveRecord::Schema.define(version: 1) do
30
+ create_table 'users', force: :cascade do |t|
31
+ t.string 'email', default: '', null: false
32
+ t.string 'encrypted_password', default: '', null: false
33
+ t.string 'reset_password_token'
34
+ t.datetime 'reset_password_sent_at'
35
+ t.datetime 'remember_created_at'
36
+ t.integer 'sign_in_count', default: 0, null: false
37
+ t.datetime 'current_sign_in_at'
38
+ t.datetime 'last_sign_in_at'
39
+ t.string 'current_sign_in_ip'
40
+ t.string 'last_sign_in_ip'
41
+ t.datetime 'created_at', null: false
42
+ t.datetime 'updated_at', null: false
43
+ t.integer 'second_factor_attempts_count', default: 0
44
+ t.string 'nickname', limit: 64
45
+ t.string 'otp_secret_key'
46
+ end
47
+ end
48
+ end
49
+ end
26
50
  end
27
51
 
28
52
  RSpec.configuration.send(:include, AuthenticatedModelHelper)
@@ -0,0 +1,16 @@
1
+ module ControllerHelper
2
+ def sign_in(user = create_user('not_encrypted'))
3
+ allow(warden).to receive(:authenticated?).with(:user).and_return(true)
4
+ allow(controller).to receive(:current_user).and_return(user)
5
+ warden.session(:user)[TwoFactorAuthentication::NEED_AUTHENTICATION] = true
6
+ end
7
+ end
8
+
9
+ RSpec.configure do |config|
10
+ config.include Devise::TestHelpers, type: :controller
11
+ config.include ControllerHelper, type: :controller
12
+
13
+ config.before(:example, type: :controller) do
14
+ @request.env['devise.mapping'] = Devise.mappings[:user]
15
+ end
16
+ end
@@ -10,10 +10,33 @@ module FeaturesSpecHelper
10
10
  fill_in "Password", with: 'password'
11
11
  find('.actions input').click # 'Sign in' or 'Log in'
12
12
  end
13
+
14
+ def set_cookie key, value
15
+ page.driver.browser.set_cookie [key, value].join('=')
16
+ end
17
+
18
+ def get_cookie key
19
+ Capybara.current_session.driver.request.cookies[key]
20
+ end
21
+
22
+ def set_tfa_cookie value
23
+ set_cookie TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME, value
24
+ end
25
+
26
+ def get_tfa_cookie
27
+ get_cookie TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME
28
+ end
13
29
  end
14
30
 
15
31
  RSpec.configure do |config|
16
32
  config.include Warden::Test::Helpers, type: :feature
17
33
  config.include FeaturesSpecHelper, type: :feature
18
- end
19
34
 
35
+ config.before(:each) do
36
+ Warden.test_mode!
37
+ end
38
+
39
+ config.after(:each) do
40
+ Warden.test_reset!
41
+ end
42
+ end
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
28
28
  s.add_runtime_dependency 'devise'
29
29
  s.add_runtime_dependency 'randexp'
30
30
  s.add_runtime_dependency 'rotp'
31
+ s.add_runtime_dependency 'encryptor'
31
32
 
32
33
  s.add_development_dependency 'bundler'
33
34
  s.add_development_dependency 'rake'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: two_factor_authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitrii Golub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-01 00:00:00.000000000 Z
11
+ date: 2016-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: encryptor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +178,7 @@ extra_rdoc_files: []
164
178
  files:
165
179
  - ".gitignore"
166
180
  - ".travis.yml"
181
+ - CHANGELOG.md
167
182
  - Gemfile
168
183
  - LICENSE
169
184
  - README.md
@@ -172,6 +187,7 @@ files:
172
187
  - app/views/devise/two_factor_authentication/max_login_attempts_reached.html.erb
173
188
  - app/views/devise/two_factor_authentication/show.html.erb
174
189
  - config/locales/en.yml
190
+ - config/locales/fr.yml
175
191
  - config/locales/ru.yml
176
192
  - lib/generators/active_record/templates/migration.rb
177
193
  - lib/generators/active_record/two_factor_authentication_generator.rb
@@ -185,8 +201,9 @@ files:
185
201
  - lib/two_factor_authentication/routes.rb
186
202
  - lib/two_factor_authentication/schema.rb
187
203
  - lib/two_factor_authentication/version.rb
188
- - spec/controllers/two_factor_auth_spec.rb
204
+ - spec/controllers/two_factor_authentication_controller_spec.rb
189
205
  - spec/features/two_factor_authenticatable_spec.rb
206
+ - spec/generators/active_record/two_factor_authentication_generator_spec.rb
190
207
  - spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb
191
208
  - spec/rails_app/.gitignore
192
209
  - spec/rails_app/README.md
@@ -198,6 +215,7 @@ files:
198
215
  - spec/rails_app/app/helpers/application_helper.rb
199
216
  - spec/rails_app/app/mailers/.gitkeep
200
217
  - spec/rails_app/app/models/.gitkeep
218
+ - spec/rails_app/app/models/encrypted_user.rb
201
219
  - spec/rails_app/app/models/guest_user.rb
202
220
  - spec/rails_app/app/models/user.rb
203
221
  - spec/rails_app/app/views/home/dashboard.html.erb
@@ -225,6 +243,9 @@ files:
225
243
  - spec/rails_app/db/migrate/20140403184646_devise_create_users.rb
226
244
  - spec/rails_app/db/migrate/20140407172619_two_factor_authentication_add_to_users.rb
227
245
  - spec/rails_app/db/migrate/20140407215513_add_nickanme_to_users.rb
246
+ - spec/rails_app/db/migrate/20151224171231_add_encrypted_columns_to_user.rb
247
+ - spec/rails_app/db/migrate/20151224180310_populate_otp_column.rb
248
+ - spec/rails_app/db/migrate/20151228230340_remove_otp_secret_key_from_user.rb
228
249
  - spec/rails_app/db/schema.rb
229
250
  - spec/rails_app/lib/assets/.gitkeep
230
251
  - spec/rails_app/lib/sms_provider.rb
@@ -236,6 +257,7 @@ files:
236
257
  - spec/spec_helper.rb
237
258
  - spec/support/authenticated_model_helper.rb
238
259
  - spec/support/capybara.rb
260
+ - spec/support/controller_helper.rb
239
261
  - spec/support/features_spec_helper.rb
240
262
  - spec/support/sms_provider.rb
241
263
  - two_factor_authentication.gemspec
@@ -1,18 +0,0 @@
1
- require 'spec_helper'
2
-
3
- include Warden::Test::Helpers
4
-
5
- describe HomeController, :type => :controller do
6
- context "passed only 1st factor auth" do
7
- let(:user) { create_user }
8
-
9
- describe "is_fully_authenticated helper" do
10
- it "should be true" do
11
- login_as user, scope: :user
12
- visit user_two_factor_authentication_path
13
-
14
- expect(controller.is_fully_authenticated?).to be_truthy
15
- end
16
- end
17
- end
18
- end