two_factor_authentication 1.1.4 → 1.1.5
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.
- checksums.yaml +4 -4
- data/.travis.yml +13 -6
- data/CHANGELOG.md +109 -0
- data/Gemfile +8 -2
- data/README.md +182 -54
- data/app/controllers/devise/two_factor_authentication_controller.rb +1 -1
- data/config/locales/fr.yml +7 -0
- data/lib/generators/active_record/templates/migration.rb +6 -11
- data/lib/two_factor_authentication.rb +3 -0
- data/lib/two_factor_authentication/hooks/two_factor_authenticatable.rb +26 -2
- data/lib/two_factor_authentication/models/two_factor_authenticatable.rb +89 -23
- data/lib/two_factor_authentication/schema.rb +12 -4
- data/lib/two_factor_authentication/version.rb +1 -1
- data/spec/controllers/two_factor_authentication_controller_spec.rb +33 -0
- data/spec/features/two_factor_authenticatable_spec.rb +164 -28
- data/spec/generators/active_record/two_factor_authentication_generator_spec.rb +36 -0
- data/spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb +213 -117
- data/spec/rails_app/app/models/encrypted_user.rb +14 -0
- data/spec/rails_app/app/models/user.rb +1 -2
- data/spec/rails_app/config/environments/test.rb +3 -0
- data/spec/rails_app/config/initializers/devise.rb +3 -1
- data/spec/rails_app/db/migrate/20151224171231_add_encrypted_columns_to_user.rb +9 -0
- data/spec/rails_app/db/migrate/20151224180310_populate_otp_column.rb +19 -0
- data/spec/rails_app/db/migrate/20151228230340_remove_otp_secret_key_from_user.rb +5 -0
- data/spec/rails_app/db/schema.rb +16 -14
- data/spec/spec_helper.rb +1 -0
- data/spec/support/authenticated_model_helper.rb +26 -2
- data/spec/support/controller_helper.rb +16 -0
- data/spec/support/features_spec_helper.rb +24 -1
- data/two_factor_authentication.gemspec +1 -0
- metadata +25 -3
- 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
|
data/spec/rails_app/db/schema.rb
CHANGED
@@ -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
|
12
|
+
# It's strongly recommended that you check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(:
|
14
|
+
ActiveRecord::Schema.define(version: 20151228230340) do
|
15
15
|
|
16
|
-
create_table "users", :
|
17
|
-
t.string "email",
|
18
|
-
t.string "encrypted_password",
|
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",
|
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",
|
28
|
-
t.datetime "updated_at",
|
29
|
-
t.
|
30
|
-
t.
|
31
|
-
t.string "
|
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"], :
|
35
|
-
add_index "users", ["
|
36
|
-
add_index "users", ["reset_password_token"], :
|
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
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|
+
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-
|
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/
|
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
|