two_factor_authentication 2.2.0 → 3.0.0

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 +5 -5
  2. data/.github/workflows/ci.yml +77 -0
  3. data/.gitignore +3 -0
  4. data/CHANGELOG.md +37 -2
  5. data/Gemfile +29 -8
  6. data/MIGRATION_GUIDE.md +143 -0
  7. data/README.md +145 -93
  8. data/app/controllers/devise/two_factor_authentication_controller.rb +3 -2
  9. data/app/views/devise/two_factor_authentication/show.html.erb +4 -4
  10. data/config/locales/de.yml +8 -0
  11. data/lib/generators/active_record/templates/migration.rb +9 -1
  12. data/lib/generators/active_record/two_factor_authentication_generator.rb +18 -0
  13. data/lib/generators/two_factor_authentication/two_factor_authentication_generator.rb +1 -1
  14. data/lib/two_factor_authentication/controllers/helpers.rb +7 -3
  15. data/lib/two_factor_authentication/models/two_factor_authenticatable.rb +8 -5
  16. data/lib/two_factor_authentication/routes.rb +1 -1
  17. data/lib/two_factor_authentication/schema.rb +7 -7
  18. data/lib/two_factor_authentication/version.rb +1 -1
  19. data/spec/controllers/two_factor_authentication_controller_spec.rb +84 -7
  20. data/spec/features/two_factor_authenticatable_spec.rb +119 -14
  21. data/spec/generators/active_record/two_factor_authentication_generator_spec.rb +52 -4
  22. data/spec/generators/two_factor_authentication/two_factor_authentication_generator_spec.rb +37 -0
  23. data/spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb +89 -7
  24. data/spec/lib/two_factor_authentication/schema_spec.rb +41 -0
  25. data/spec/rails_app/app/assets/config/manifest.js +2 -0
  26. data/spec/rails_app/app/controllers/home_controller.rb +6 -1
  27. data/spec/rails_app/app/models/guest_user.rb +1 -1
  28. data/spec/rails_app/app/models/secure_user.rb +13 -0
  29. data/spec/rails_app/config/application.rb +1 -1
  30. data/spec/rails_app/config/environments/test.rb +3 -8
  31. data/spec/rails_app/config/initializers/inflections.rb +4 -0
  32. data/spec/rails_app/config/routes.rb +2 -0
  33. data/spec/rails_app/db/migrate/20260929000000_add_otp_columns_to_users.rb +8 -0
  34. data/spec/rails_app/db/migrate/20260929000001_devise_create_secure_users.rb +22 -0
  35. data/spec/rails_app/db/schema.rb +26 -8
  36. data/spec/rails_app/lib/sms_provider.rb +2 -4
  37. data/spec/requests/two_factor_authentication_helpers_spec.rb +48 -0
  38. data/spec/spec_helper.rb +1 -0
  39. data/spec/support/authenticated_model_helper.rb +5 -30
  40. data/spec/support/controller_helper.rb +5 -4
  41. data/spec/support/features_spec_helper.rb +1 -0
  42. data/two_factor_authentication.gemspec +4 -5
  43. metadata +43 -26
  44. data/.travis.yml +0 -28
  45. data/spec/rails_app/config/initializers/secret_token.rb +0 -7
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Requests from a user who has not completed two factor authentication', type: :request do
4
+ let(:user) { create_user }
5
+
6
+ before { login_as user, scope: :user }
7
+
8
+ it 'redirects HTML requests to the two factor page' do
9
+ get secret_path
10
+
11
+ expect(response).to redirect_to(user_two_factor_authentication_path)
12
+ end
13
+
14
+ it 'responds to JSON requests with 401 and the two factor path' do
15
+ get secret_path(format: :json)
16
+
17
+ expect(response).to have_http_status(:unauthorized)
18
+ expect(response.parsed_body).to eq('redirect_to' => user_two_factor_authentication_path)
19
+ end
20
+
21
+ it 'responds to other formats with 401 without running the action' do
22
+ get secret_path(format: :xml)
23
+
24
+ expect(response).to have_http_status(:unauthorized)
25
+ expect(response.body).not_to include('top secret')
26
+ end
27
+
28
+ it 'responds with 401 when the format comes from the Accept header' do
29
+ get secret_path, headers: { 'Accept' => 'text/csv' }
30
+
31
+ expect(response).to have_http_status(:unauthorized)
32
+ expect(response.body).not_to include('top secret')
33
+ end
34
+
35
+ context 'when the user does not need two factor authentication' do
36
+ before do
37
+ allow_any_instance_of(User).to receive(:need_two_factor_authentication?).and_return(false)
38
+ end
39
+
40
+ it 'runs the action and sends no code' do
41
+ get secret_path(format: :xml)
42
+
43
+ expect(response).to have_http_status(:ok)
44
+ expect(response.body).to eq('top secret')
45
+ expect(SMSProvider.messages).to be_empty
46
+ end
47
+ end
48
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  ENV["RAILS_ENV"] ||= "test"
2
2
  require File.expand_path("../rails_app/config/environment.rb", __FILE__)
3
+ require File.expand_path("../rails_app/lib/sms_provider.rb", __FILE__)
3
4
 
4
5
  require 'rspec/rails'
5
6
  require 'timecop'
@@ -3,9 +3,7 @@ module AuthenticatedModelHelper
3
3
  GuestUser.new
4
4
  end
5
5
 
6
- def create_user(type = 'encrypted', attributes = {})
7
- create_table_for_nonencrypted_user if type == 'not_encrypted'
8
-
6
+ def create_user(attributes = {})
9
7
  User.create!(valid_attributes(attributes))
10
8
  end
11
9
 
@@ -13,6 +11,10 @@ module AuthenticatedModelHelper
13
11
  Admin.create!(valid_attributes.except(:nickname))
14
12
  end
15
13
 
14
+ def create_secure_user(attributes = {})
15
+ SecureUser.create!(valid_attributes(attributes).except(:nickname))
16
+ end
17
+
16
18
  def valid_attributes(attributes={})
17
19
  {
18
20
  nickname: 'Marissa',
@@ -27,33 +29,6 @@ module AuthenticatedModelHelper
27
29
  @@email_count += 1
28
30
  "user#{@@email_count}@example.com"
29
31
  end
30
-
31
- def create_table_for_nonencrypted_user
32
- ActiveRecord::Migration.suppress_messages do
33
- ActiveRecord::Schema.define(version: 1) do
34
- create_table 'users', force: :cascade do |t|
35
- t.string 'email', default: '', null: false
36
- t.string 'encrypted_password', default: '', null: false
37
- t.string 'reset_password_token'
38
- t.datetime 'reset_password_sent_at'
39
- t.datetime 'remember_created_at'
40
- t.integer 'sign_in_count', default: 0, null: false
41
- t.datetime 'current_sign_in_at'
42
- t.datetime 'last_sign_in_at'
43
- t.string 'current_sign_in_ip'
44
- t.string 'last_sign_in_ip'
45
- t.datetime 'created_at', null: false
46
- t.datetime 'updated_at', null: false
47
- t.integer 'second_factor_attempts_count', default: 0
48
- t.string 'nickname', limit: 64
49
- t.string 'otp_secret_key'
50
- t.string 'direct_otp'
51
- t.datetime 'direct_otp_sent_at'
52
- t.timestamp 'totp_timestamp'
53
- end
54
- end
55
- end
56
- end
57
32
  end
58
33
 
59
34
  RSpec.configuration.send(:include, AuthenticatedModelHelper)
@@ -1,8 +1,9 @@
1
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
2
+ def sign_in(user = create_user, scope: :user)
3
+ allow(warden).to receive(:authenticated?).and_call_original
4
+ allow(warden).to receive(:authenticated?).with(scope).and_return(true)
5
+ allow(controller).to receive(:"current_#{scope}").and_return(user)
6
+ warden.session(scope)[TwoFactorAuthentication::NEED_AUTHENTICATION] = true
6
7
  end
7
8
  end
8
9
 
@@ -30,6 +30,7 @@ end
30
30
 
31
31
  RSpec.configure do |config|
32
32
  config.include Warden::Test::Helpers, type: :feature
33
+ config.include Warden::Test::Helpers, type: :request
33
34
  config.include FeaturesSpecHelper, type: :feature
34
35
 
35
36
  config.before(:each) do
@@ -9,6 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.email = ["dmitrii.golub@gmail.com"]
10
10
  s.homepage = "https://github.com/Houdini/two_factor_authentication"
11
11
  s.summary = %q{Two factor authentication plugin for devise}
12
+ s.license = "MIT"
12
13
  s.description = <<-EOF
13
14
  ### Features ###
14
15
  * control sms code pattern
@@ -17,23 +18,21 @@ Gem::Specification.new do |s|
17
18
  * your own sms logic
18
19
  EOF
19
20
 
20
- s.rubyforge_project = "two_factor_authentication"
21
-
22
21
  s.files = `git ls-files`.split("\n")
23
22
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
23
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
24
  s.require_paths = ["lib"]
26
25
 
27
- s.add_runtime_dependency 'rails', '>= 3.1.1'
26
+ s.add_runtime_dependency 'rails', '>= 5.0'
28
27
  s.add_runtime_dependency 'devise'
29
28
  s.add_runtime_dependency 'randexp'
30
29
  s.add_runtime_dependency 'rotp', '>= 4.0.0'
31
30
  s.add_runtime_dependency 'encryptor'
32
31
 
33
- s.add_development_dependency 'bundler'
34
32
  s.add_development_dependency 'rake'
35
33
  s.add_development_dependency 'rspec-rails', '>= 3.0.1'
36
- s.add_development_dependency 'capybara', '~> 2.5'
34
+ s.add_development_dependency 'capybara', '>= 2.5', '< 4'
37
35
  s.add_development_dependency 'pry'
36
+ s.add_development_dependency 'byebug'
38
37
  s.add_development_dependency 'timecop'
39
38
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: two_factor_authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitrii Golub
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2019-01-29 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 3.1.1
18
+ version: '5.0'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: 3.1.1
25
+ version: '5.0'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: devise
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +80,7 @@ dependencies:
81
80
  - !ruby/object:Gem::Version
82
81
  version: '0'
83
82
  - !ruby/object:Gem::Dependency
84
- name: bundler
83
+ name: rake
85
84
  requirement: !ruby/object:Gem::Requirement
86
85
  requirements:
87
86
  - - ">="
@@ -95,49 +94,55 @@ dependencies:
95
94
  - !ruby/object:Gem::Version
96
95
  version: '0'
97
96
  - !ruby/object:Gem::Dependency
98
- name: rake
97
+ name: rspec-rails
99
98
  requirement: !ruby/object:Gem::Requirement
100
99
  requirements:
101
100
  - - ">="
102
101
  - !ruby/object:Gem::Version
103
- version: '0'
102
+ version: 3.0.1
104
103
  type: :development
105
104
  prerelease: false
106
105
  version_requirements: !ruby/object:Gem::Requirement
107
106
  requirements:
108
107
  - - ">="
109
108
  - !ruby/object:Gem::Version
110
- version: '0'
109
+ version: 3.0.1
111
110
  - !ruby/object:Gem::Dependency
112
- name: rspec-rails
111
+ name: capybara
113
112
  requirement: !ruby/object:Gem::Requirement
114
113
  requirements:
115
114
  - - ">="
116
115
  - !ruby/object:Gem::Version
117
- version: 3.0.1
116
+ version: '2.5'
117
+ - - "<"
118
+ - !ruby/object:Gem::Version
119
+ version: '4'
118
120
  type: :development
119
121
  prerelease: false
120
122
  version_requirements: !ruby/object:Gem::Requirement
121
123
  requirements:
122
124
  - - ">="
123
125
  - !ruby/object:Gem::Version
124
- version: 3.0.1
126
+ version: '2.5'
127
+ - - "<"
128
+ - !ruby/object:Gem::Version
129
+ version: '4'
125
130
  - !ruby/object:Gem::Dependency
126
- name: capybara
131
+ name: pry
127
132
  requirement: !ruby/object:Gem::Requirement
128
133
  requirements:
129
- - - "~>"
134
+ - - ">="
130
135
  - !ruby/object:Gem::Version
131
- version: '2.5'
136
+ version: '0'
132
137
  type: :development
133
138
  prerelease: false
134
139
  version_requirements: !ruby/object:Gem::Requirement
135
140
  requirements:
136
- - - "~>"
141
+ - - ">="
137
142
  - !ruby/object:Gem::Version
138
- version: '2.5'
143
+ version: '0'
139
144
  - !ruby/object:Gem::Dependency
140
- name: pry
145
+ name: byebug
141
146
  requirement: !ruby/object:Gem::Requirement
142
147
  requirements:
143
148
  - - ">="
@@ -177,17 +182,19 @@ extensions: []
177
182
  extra_rdoc_files: []
178
183
  files:
179
184
  - ".codeclimate.yml"
185
+ - ".github/workflows/ci.yml"
180
186
  - ".gitignore"
181
187
  - ".rubocop.yml"
182
- - ".travis.yml"
183
188
  - CHANGELOG.md
184
189
  - Gemfile
185
190
  - LICENSE
191
+ - MIGRATION_GUIDE.md
186
192
  - README.md
187
193
  - Rakefile
188
194
  - app/controllers/devise/two_factor_authentication_controller.rb
189
195
  - app/views/devise/two_factor_authentication/max_login_attempts_reached.html.erb
190
196
  - app/views/devise/two_factor_authentication/show.html.erb
197
+ - config/locales/de.yml
191
198
  - config/locales/en.yml
192
199
  - config/locales/es.yml
193
200
  - config/locales/fr.yml
@@ -207,10 +214,13 @@ files:
207
214
  - spec/controllers/two_factor_authentication_controller_spec.rb
208
215
  - spec/features/two_factor_authenticatable_spec.rb
209
216
  - spec/generators/active_record/two_factor_authentication_generator_spec.rb
217
+ - spec/generators/two_factor_authentication/two_factor_authentication_generator_spec.rb
210
218
  - spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb
219
+ - spec/lib/two_factor_authentication/schema_spec.rb
211
220
  - spec/rails_app/.gitignore
212
221
  - spec/rails_app/README.md
213
222
  - spec/rails_app/Rakefile
223
+ - spec/rails_app/app/assets/config/manifest.js
214
224
  - spec/rails_app/app/assets/javascripts/application.js
215
225
  - spec/rails_app/app/assets/stylesheets/application.css
216
226
  - spec/rails_app/app/controllers/application_controller.rb
@@ -221,6 +231,7 @@ files:
221
231
  - spec/rails_app/app/models/admin.rb
222
232
  - spec/rails_app/app/models/encrypted_user.rb
223
233
  - spec/rails_app/app/models/guest_user.rb
234
+ - spec/rails_app/app/models/secure_user.rb
224
235
  - spec/rails_app/app/models/user.rb
225
236
  - spec/rails_app/app/views/home/dashboard.html.erb
226
237
  - spec/rails_app/app/views/home/index.html.erb
@@ -238,7 +249,6 @@ files:
238
249
  - spec/rails_app/config/initializers/devise.rb
239
250
  - spec/rails_app/config/initializers/inflections.rb
240
251
  - spec/rails_app/config/initializers/mime_types.rb
241
- - spec/rails_app/config/initializers/secret_token.rb
242
252
  - spec/rails_app/config/initializers/session_store.rb
243
253
  - spec/rails_app/config/initializers/wrap_parameters.rb
244
254
  - spec/rails_app/config/locales/devise.en.yml
@@ -251,6 +261,8 @@ files:
251
261
  - spec/rails_app/db/migrate/20151224180310_populate_otp_column.rb
252
262
  - spec/rails_app/db/migrate/20151228230340_remove_otp_secret_key_from_user.rb
253
263
  - spec/rails_app/db/migrate/20160209032439_devise_create_admins.rb
264
+ - spec/rails_app/db/migrate/20260929000000_add_otp_columns_to_users.rb
265
+ - spec/rails_app/db/migrate/20260929000001_devise_create_secure_users.rb
254
266
  - spec/rails_app/db/schema.rb
255
267
  - spec/rails_app/lib/assets/.gitkeep
256
268
  - spec/rails_app/lib/sms_provider.rb
@@ -259,6 +271,7 @@ files:
259
271
  - spec/rails_app/public/500.html
260
272
  - spec/rails_app/public/favicon.ico
261
273
  - spec/rails_app/script/rails
274
+ - spec/requests/two_factor_authentication_helpers_spec.rb
262
275
  - spec/spec_helper.rb
263
276
  - spec/support/authenticated_model_helper.rb
264
277
  - spec/support/capybara.rb
@@ -268,9 +281,9 @@ files:
268
281
  - spec/support/totp_helper.rb
269
282
  - two_factor_authentication.gemspec
270
283
  homepage: https://github.com/Houdini/two_factor_authentication
271
- licenses: []
284
+ licenses:
285
+ - MIT
272
286
  metadata: {}
273
- post_install_message:
274
287
  rdoc_options: []
275
288
  require_paths:
276
289
  - lib
@@ -285,19 +298,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
285
298
  - !ruby/object:Gem::Version
286
299
  version: '0'
287
300
  requirements: []
288
- rubyforge_project: two_factor_authentication
289
- rubygems_version: 2.6.14
290
- signing_key:
301
+ rubygems_version: 4.0.10
291
302
  specification_version: 4
292
303
  summary: Two factor authentication plugin for devise
293
304
  test_files:
294
305
  - spec/controllers/two_factor_authentication_controller_spec.rb
295
306
  - spec/features/two_factor_authenticatable_spec.rb
296
307
  - spec/generators/active_record/two_factor_authentication_generator_spec.rb
308
+ - spec/generators/two_factor_authentication/two_factor_authentication_generator_spec.rb
297
309
  - spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb
310
+ - spec/lib/two_factor_authentication/schema_spec.rb
298
311
  - spec/rails_app/.gitignore
299
312
  - spec/rails_app/README.md
300
313
  - spec/rails_app/Rakefile
314
+ - spec/rails_app/app/assets/config/manifest.js
301
315
  - spec/rails_app/app/assets/javascripts/application.js
302
316
  - spec/rails_app/app/assets/stylesheets/application.css
303
317
  - spec/rails_app/app/controllers/application_controller.rb
@@ -308,6 +322,7 @@ test_files:
308
322
  - spec/rails_app/app/models/admin.rb
309
323
  - spec/rails_app/app/models/encrypted_user.rb
310
324
  - spec/rails_app/app/models/guest_user.rb
325
+ - spec/rails_app/app/models/secure_user.rb
311
326
  - spec/rails_app/app/models/user.rb
312
327
  - spec/rails_app/app/views/home/dashboard.html.erb
313
328
  - spec/rails_app/app/views/home/index.html.erb
@@ -325,7 +340,6 @@ test_files:
325
340
  - spec/rails_app/config/initializers/devise.rb
326
341
  - spec/rails_app/config/initializers/inflections.rb
327
342
  - spec/rails_app/config/initializers/mime_types.rb
328
- - spec/rails_app/config/initializers/secret_token.rb
329
343
  - spec/rails_app/config/initializers/session_store.rb
330
344
  - spec/rails_app/config/initializers/wrap_parameters.rb
331
345
  - spec/rails_app/config/locales/devise.en.yml
@@ -338,6 +352,8 @@ test_files:
338
352
  - spec/rails_app/db/migrate/20151224180310_populate_otp_column.rb
339
353
  - spec/rails_app/db/migrate/20151228230340_remove_otp_secret_key_from_user.rb
340
354
  - spec/rails_app/db/migrate/20160209032439_devise_create_admins.rb
355
+ - spec/rails_app/db/migrate/20260929000000_add_otp_columns_to_users.rb
356
+ - spec/rails_app/db/migrate/20260929000001_devise_create_secure_users.rb
341
357
  - spec/rails_app/db/schema.rb
342
358
  - spec/rails_app/lib/assets/.gitkeep
343
359
  - spec/rails_app/lib/sms_provider.rb
@@ -346,6 +362,7 @@ test_files:
346
362
  - spec/rails_app/public/500.html
347
363
  - spec/rails_app/public/favicon.ico
348
364
  - spec/rails_app/script/rails
365
+ - spec/requests/two_factor_authentication_helpers_spec.rb
349
366
  - spec/spec_helper.rb
350
367
  - spec/support/authenticated_model_helper.rb
351
368
  - spec/support/capybara.rb
data/.travis.yml DELETED
@@ -1,28 +0,0 @@
1
- language: ruby
2
-
3
- env:
4
- - "RAILS_VERSION=4.2"
5
- - "RAILS_VERSION=5.2"
6
- - "RAILS_VERSION=master"
7
-
8
- rvm:
9
- - 2.3.8
10
- - 2.4.5
11
- - 2.5.3
12
-
13
- matrix:
14
- fast_finish: true
15
- allow_failures:
16
- - env: "RAILS_VERSION=master"
17
- include:
18
- - rvm: 2.2
19
- env: RAILS_VERSION=4.2
20
-
21
- before_install:
22
- - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
23
- - gem install bundler -v '< 2'
24
-
25
- before_script:
26
- - bundle exec rake app:db:setup
27
-
28
- script: bundle exec rake spec
@@ -1,7 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # Your secret key for verifying the integrity of signed cookies.
4
- # If you change this key, all old signed cookies will become invalid!
5
- # Make sure the secret is at least 30 characters and all random,
6
- # no regular words or you'll be exposed to dictionary attacks.
7
- Dummy::Application.config.secret_token = 'e75d8cdfc7c99757a5d4b427bde4b4b1072eb169c022cdbb038bdbcefb3901ef60ac912b6fb14260db099156520b9cc8838e4bf8e209b7246fad891950825032'