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.
- 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
|