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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75e8b63e29715336ec78a4a06db141ec2fdddf68
|
4
|
+
data.tar.gz: c2b09dd1294a966ce75425efc97b6e2089e33689
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d38f91cbb77148bd9c401f129d977f5fa22281ddb20ec12e4a12f02b1e35acabd04048bc88bad4d7e4cc80311e43f8720f45b0eeea116323c96fdee78cfb733
|
7
|
+
data.tar.gz: e7a2a0026e4558a8e0e8efbb3257b0fec162f7d45390a7521f249332e273c53568b309044000fae9ecdfcd55c3cfe13a951d2895f5327bb54b692a4fe2723fcf
|
data/.travis.yml
CHANGED
@@ -1,21 +1,28 @@
|
|
1
1
|
language: ruby
|
2
2
|
|
3
3
|
env:
|
4
|
-
- "RAILS_VERSION=3.2
|
5
|
-
- "RAILS_VERSION=4.0
|
6
|
-
- "RAILS_VERSION=4.1
|
7
|
-
- "RAILS_VERSION=4.2
|
4
|
+
- "RAILS_VERSION=3.2"
|
5
|
+
- "RAILS_VERSION=4.0"
|
6
|
+
- "RAILS_VERSION=4.1"
|
7
|
+
- "RAILS_VERSION=4.2"
|
8
8
|
- "RAILS_VERSION=master"
|
9
9
|
|
10
10
|
rvm:
|
11
|
-
- 1.9.3
|
12
11
|
- 2.0
|
13
12
|
- 2.1
|
14
|
-
- 2.2
|
13
|
+
- 2.2.2
|
15
14
|
|
16
15
|
matrix:
|
17
16
|
allow_failures:
|
18
17
|
- env: "RAILS_VERSION=master"
|
18
|
+
exclude:
|
19
|
+
- rvm: 2.0
|
20
|
+
env: RAILS_VERSION=master
|
21
|
+
- rvm: 2.1
|
22
|
+
env: RAILS_VERSION=master
|
23
|
+
|
24
|
+
before_install:
|
25
|
+
- gem update bundler
|
19
26
|
|
20
27
|
before_script:
|
21
28
|
- bundle exec rake app:db:migrate
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
## [Unreleased](https://github.com/houdini/two_factor_authentication/tree/HEAD)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/houdini/two_factor_authentication/compare/v1.1.4...HEAD)
|
6
|
+
|
7
|
+
**Closed issues:**
|
8
|
+
|
9
|
+
- How should I integrate Devise two factor authentication with custom sessions controller? [\#60](https://github.com/Houdini/two_factor_authentication/issues/60)
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- Update bundler on Travis before installing gems [\#63](https://github.com/Houdini/two_factor_authentication/pull/63) ([monfresh](https://github.com/monfresh))
|
14
|
+
- Add support for OTP secret key encryption [\#62](https://github.com/Houdini/two_factor_authentication/pull/62) ([monfresh](https://github.com/monfresh))
|
15
|
+
- Allow executing code after sign in and before sign out [\#61](https://github.com/Houdini/two_factor_authentication/pull/61) ([monfresh](https://github.com/monfresh))
|
16
|
+
|
17
|
+
## [v1.1.4](https://github.com/houdini/two_factor_authentication/tree/v1.1.4) (2016-01-01)
|
18
|
+
[Full Changelog](https://github.com/houdini/two_factor_authentication/compare/v1.1.3...v1.1.4)
|
19
|
+
|
20
|
+
**Closed issues:**
|
21
|
+
|
22
|
+
- Old OTP can be used after a new one has been generated [\#59](https://github.com/Houdini/two_factor_authentication/issues/59)
|
23
|
+
- Do we have any two\_factor\_method like authenticate\_user! [\#58](https://github.com/Houdini/two_factor_authentication/issues/58)
|
24
|
+
- Configuration [\#57](https://github.com/Houdini/two_factor_authentication/issues/57)
|
25
|
+
|
26
|
+
**Merged pull requests:**
|
27
|
+
|
28
|
+
- Abstract logic for two factor success and fail into separate methods.… [\#56](https://github.com/Houdini/two_factor_authentication/pull/56) ([kpheasey](https://github.com/kpheasey))
|
29
|
+
- Move require rotp library to the file where it is used [\#55](https://github.com/Houdini/two_factor_authentication/pull/55) ([gkopylov](https://github.com/gkopylov))
|
30
|
+
- Add support for remembering a user's 2FA session in a cookie [\#54](https://github.com/Houdini/two_factor_authentication/pull/54) ([boffbowsh](https://github.com/boffbowsh))
|
31
|
+
- Test against Ruby 2.2 and Rails 4.2 [\#53](https://github.com/Houdini/two_factor_authentication/pull/53) ([boffbowsh](https://github.com/boffbowsh))
|
32
|
+
- Eliminates appended '?' to redirects that have no query string [\#46](https://github.com/Houdini/two_factor_authentication/pull/46) ([daveriess](https://github.com/daveriess))
|
33
|
+
|
34
|
+
## [v1.1.3](https://github.com/houdini/two_factor_authentication/tree/v1.1.3) (2014-12-14)
|
35
|
+
[Full Changelog](https://github.com/houdini/two_factor_authentication/compare/list...v1.1.3)
|
36
|
+
|
37
|
+
**Closed issues:**
|
38
|
+
|
39
|
+
- rails g two\_factor\_authentication MODEL does not append .rb to end of migration [\#40](https://github.com/Houdini/two_factor_authentication/issues/40)
|
40
|
+
|
41
|
+
**Merged pull requests:**
|
42
|
+
|
43
|
+
- Allows length of OTP to be configured [\#44](https://github.com/Houdini/two_factor_authentication/pull/44) ([amoose](https://github.com/amoose))
|
44
|
+
- Missing translation. [\#43](https://github.com/Houdini/two_factor_authentication/pull/43) ([sadfuzzy](https://github.com/sadfuzzy))
|
45
|
+
- Preserve query parameters in \_return\_to for redirect. [\#42](https://github.com/Houdini/two_factor_authentication/pull/42) ([omb-awong](https://github.com/omb-awong))
|
46
|
+
- Add file extension to ActiveRecord generator [\#41](https://github.com/Houdini/two_factor_authentication/pull/41) ([jackturnbull](https://github.com/jackturnbull))
|
47
|
+
|
48
|
+
## [list](https://github.com/houdini/two_factor_authentication/tree/list) (2014-07-14)
|
49
|
+
[Full Changelog](https://github.com/houdini/two_factor_authentication/compare/v1.1.2...list)
|
50
|
+
|
51
|
+
## [v1.1.2](https://github.com/houdini/two_factor_authentication/tree/v1.1.2) (2014-07-14)
|
52
|
+
[Full Changelog](https://github.com/houdini/two_factor_authentication/compare/v1.1.1...v1.1.2)
|
53
|
+
|
54
|
+
**Closed issues:**
|
55
|
+
|
56
|
+
- NoMethodError \(undefined method `scan' for nil:NilClass\) [\#37](https://github.com/Houdini/two_factor_authentication/issues/37)
|
57
|
+
|
58
|
+
**Merged pull requests:**
|
59
|
+
|
60
|
+
- Updated readme with rake task to update existing users with OTP secret k... [\#39](https://github.com/Houdini/two_factor_authentication/pull/39) ([Znow](https://github.com/Znow))
|
61
|
+
- Updated readme with view overriding [\#38](https://github.com/Houdini/two_factor_authentication/pull/38) ([Znow](https://github.com/Znow))
|
62
|
+
|
63
|
+
## [v1.1.1](https://github.com/houdini/two_factor_authentication/tree/v1.1.1) (2014-05-31)
|
64
|
+
[Full Changelog](https://github.com/houdini/two_factor_authentication/compare/v1.1...v1.1.1)
|
65
|
+
|
66
|
+
**Closed issues:**
|
67
|
+
|
68
|
+
- Override views [\#36](https://github.com/Houdini/two_factor_authentication/issues/36)
|
69
|
+
- NoMethodError in Devise::TwoFactorAuthenticationController\#update [\#30](https://github.com/Houdini/two_factor_authentication/issues/30)
|
70
|
+
|
71
|
+
**Merged pull requests:**
|
72
|
+
|
73
|
+
- Use Strings and not Symbols for keys when storing variable in warden session [\#35](https://github.com/Houdini/two_factor_authentication/pull/35) ([karolsarnacki](https://github.com/karolsarnacki))
|
74
|
+
- Chore/extract reused hash key [\#34](https://github.com/Houdini/two_factor_authentication/pull/34) ([rud](https://github.com/rud))
|
75
|
+
- Pad OTP codes with less than 6 digits [\#31](https://github.com/Houdini/two_factor_authentication/pull/31) ([brissmyr](https://github.com/brissmyr))
|
76
|
+
|
77
|
+
## [v1.1](https://github.com/houdini/two_factor_authentication/tree/v1.1) (2014-04-16)
|
78
|
+
**Closed issues:**
|
79
|
+
|
80
|
+
- Update [\#15](https://github.com/Houdini/two_factor_authentication/issues/15)
|
81
|
+
- Data in formats other than HTML left unprotected [\#6](https://github.com/Houdini/two_factor_authentication/issues/6)
|
82
|
+
- Wordlists [\#5](https://github.com/Houdini/two_factor_authentication/issues/5)
|
83
|
+
- devise - wrong number of arguments \(1 for 0\) [\#3](https://github.com/Houdini/two_factor_authentication/issues/3)
|
84
|
+
- gem? [\#1](https://github.com/Houdini/two_factor_authentication/issues/1)
|
85
|
+
|
86
|
+
**Merged pull requests:**
|
87
|
+
|
88
|
+
- added is\_fully\_authenticated helper for current version [\#28](https://github.com/Houdini/two_factor_authentication/pull/28) ([edg3r](https://github.com/edg3r))
|
89
|
+
- Adds integration spec to ensure authentication code is sent on sign in [\#27](https://github.com/Houdini/two_factor_authentication/pull/27) ([rossta](https://github.com/rossta))
|
90
|
+
- ensure return\_to location is properly stored [\#26](https://github.com/Houdini/two_factor_authentication/pull/26) ([rossta](https://github.com/rossta))
|
91
|
+
- travis badge in README [\#25](https://github.com/Houdini/two_factor_authentication/pull/25) ([rossta](https://github.com/rossta))
|
92
|
+
- Integration specs [\#24](https://github.com/Houdini/two_factor_authentication/pull/24) ([rossta](https://github.com/rossta))
|
93
|
+
- README updates [\#23](https://github.com/Houdini/two_factor_authentication/pull/23) ([rossta](https://github.com/rossta))
|
94
|
+
- extract method \#max\_login\_attempts [\#22](https://github.com/Houdini/two_factor_authentication/pull/22) ([rossta](https://github.com/rossta))
|
95
|
+
- extract method \#populate\_otp\_column [\#21](https://github.com/Houdini/two_factor_authentication/pull/21) ([rossta](https://github.com/rossta))
|
96
|
+
- specs for Model\#provisioning\_uri [\#20](https://github.com/Houdini/two_factor_authentication/pull/20) ([rossta](https://github.com/rossta))
|
97
|
+
- Provide options for \#provisioning\_uri [\#19](https://github.com/Houdini/two_factor_authentication/pull/19) ([rossta](https://github.com/rossta))
|
98
|
+
- Use time-based authentication codes [\#16](https://github.com/Houdini/two_factor_authentication/pull/16) ([mattmueller](https://github.com/mattmueller))
|
99
|
+
- Add ru locales and locales for max\_limit\_reached view [\#13](https://github.com/Houdini/two_factor_authentication/pull/13) ([edg3r](https://github.com/edg3r))
|
100
|
+
- Update README.md [\#11](https://github.com/Houdini/two_factor_authentication/pull/11) ([edg3r](https://github.com/edg3r))
|
101
|
+
- Changed route from user to admin\_user [\#10](https://github.com/Houdini/two_factor_authentication/pull/10) ([ilanstern](https://github.com/ilanstern))
|
102
|
+
- Changed :notice to :error when setting flash message on attempt failure. [\#9](https://github.com/Houdini/two_factor_authentication/pull/9) ([johnmichaelbradley](https://github.com/johnmichaelbradley))
|
103
|
+
- Typo and punctuation corrections. [\#8](https://github.com/Houdini/two_factor_authentication/pull/8) ([johnmichaelbradley](https://github.com/johnmichaelbradley))
|
104
|
+
- Respond with 401 for request non-HTML requests [\#7](https://github.com/Houdini/two_factor_authentication/pull/7) ([WojtekKruszewski](https://github.com/WojtekKruszewski))
|
105
|
+
- need\_two\_factor\_authentication? method should accept request param. [\#4](https://github.com/Houdini/two_factor_authentication/pull/4) ([VladimirMikhailov](https://github.com/VladimirMikhailov))
|
106
|
+
- Add generators to make it easier to install and fix deprecation warnings [\#2](https://github.com/Houdini/two_factor_authentication/pull/2) ([carvil](https://github.com/carvil))
|
107
|
+
|
108
|
+
|
109
|
+
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in devise_ip_filter.gemspec
|
4
4
|
gemspec
|
@@ -20,6 +20,12 @@ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.2.0')
|
|
20
20
|
gem "test-unit", "~> 3.0"
|
21
21
|
end
|
22
22
|
|
23
|
+
group :test, :development do
|
24
|
+
gem 'sqlite3'
|
25
|
+
end
|
26
|
+
|
23
27
|
group :test do
|
24
|
-
gem
|
28
|
+
gem 'rack_session_access'
|
29
|
+
gem 'ammeter'
|
30
|
+
gem 'pry'
|
25
31
|
end
|
data/README.md
CHANGED
@@ -5,11 +5,12 @@
|
|
5
5
|
|
6
6
|
## Features
|
7
7
|
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
*
|
8
|
+
* configurable OTP code digit length
|
9
|
+
* configurable max login attempts
|
10
|
+
* customizable logic to determine if a user needs two factor authentication
|
11
|
+
* customizable logic for sending the OTP code to the user
|
12
12
|
* configurable period where users won't be asked for 2FA again
|
13
|
+
* option to encrypt the OTP secret key in the database, with iv and salt
|
13
14
|
|
14
15
|
## Configuration
|
15
16
|
|
@@ -23,62 +24,73 @@ Once that's done, run:
|
|
23
24
|
|
24
25
|
bundle install
|
25
26
|
|
26
|
-
|
27
|
+
Note that Ruby 2.0 or greater is required.
|
27
28
|
|
28
|
-
|
29
|
+
### Installation
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
and create a migration in `db/migrate/`, which will add `:otp_secret_key` and `:second_factor_attempts_count` to your table.
|
34
|
-
Finally, run the migration with:
|
31
|
+
#### Automatic initial setup
|
32
|
+
To set up the model and database migration file automatically, run the
|
33
|
+
following command:
|
35
34
|
|
36
|
-
bundle exec
|
35
|
+
bundle exec rails g two_factor_authentication MODEL
|
37
36
|
|
38
|
-
|
37
|
+
Where MODEL is your model name (e.g. User or Admin). This generator will add
|
38
|
+
`:two_factor_authenticatable` to your model's Devise options and create a
|
39
|
+
migration in `db/migrate/`, which will add the following columns to your table:
|
39
40
|
|
40
|
-
|
41
|
+
- `:second_factor_attempts_count`
|
42
|
+
- `:encrypted_otp_secret_key`
|
43
|
+
- `:encrypted_otp_secret_key_iv`
|
44
|
+
- `:encrypted_otp_secret_key_salt`
|
41
45
|
|
42
|
-
|
46
|
+
#### Manual initial setup
|
47
|
+
If you prefer to set up the model and migration manually, add the
|
48
|
+
`:two_factor_authentication` option to your existing devise options, such as:
|
43
49
|
|
44
50
|
```ruby
|
45
|
-
|
46
|
-
|
47
|
-
config.otp_length = 6 # OTP code length
|
48
|
-
config.remember_otp_session_for_seconds = 30.days # Time before browser has to enter OTP code again
|
51
|
+
devise :database_authenticatable, :registerable, :recoverable, :rememberable,
|
52
|
+
:trackable, :validatable, :two_factor_authenticatable
|
49
53
|
```
|
50
54
|
|
51
|
-
|
55
|
+
Then create your migration file using the Rails generator, such as:
|
52
56
|
|
53
|
-
```
|
54
|
-
|
55
|
-
# use Model#otp_code and send via SMS, etc.
|
56
|
-
end
|
57
|
+
```
|
58
|
+
rails g migration AddTwoFactorFieldsToUsers second_factor_attempts_count:integer encrypted_otp_secret_key:string:index encrypted_otp_secret_key_iv:string encrypted_otp_secret_key_salt:string
|
57
59
|
```
|
58
60
|
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
Open your migration file (it will be in the `db/migrate` directory and will be
|
62
|
+
named something like `20151230163930_add_two_factor_fields_to_users.rb`), and
|
63
|
+
add `unique: true` to the `add_index` line so that it looks like this:
|
62
64
|
|
63
65
|
```ruby
|
64
|
-
|
65
|
-
:recoverable, :rememberable, :trackable, :validatable, :two_factor_authenticatable
|
66
|
+
add_index :users, :encrypted_otp_secret_key, unique: true
|
66
67
|
```
|
68
|
+
Save the file.
|
69
|
+
|
70
|
+
#### Complete the setup
|
71
|
+
Run the migration with:
|
72
|
+
|
73
|
+
bundle exec rake db:migrate
|
67
74
|
|
68
75
|
Add the following line to your model to fully enable two-factor auth:
|
69
76
|
|
70
|
-
has_one_time_password
|
77
|
+
has_one_time_password(encrypted: true)
|
71
78
|
|
72
|
-
Set config values
|
79
|
+
Set config values in `config/initializers/devise.rb`:
|
73
80
|
|
74
81
|
```ruby
|
75
|
-
config.max_login_attempts = 3 # Maximum second factor attempts count
|
76
|
-
config.allowed_otp_drift_seconds = 30 # Allowed time drift
|
82
|
+
config.max_login_attempts = 3 # Maximum second factor attempts count.
|
83
|
+
config.allowed_otp_drift_seconds = 30 # Allowed time drift between client and server.
|
77
84
|
config.otp_length = 6 # OTP code length
|
78
|
-
config.remember_otp_session_for_seconds = 30.days # Time before browser has to enter OTP code again
|
85
|
+
config.remember_otp_session_for_seconds = 30.days # Time before browser has to enter OTP code again. Default is 0.
|
86
|
+
config.otp_secret_encryption_key = ENV['OTP_SECRET_ENCRYPTION_KEY']
|
79
87
|
```
|
88
|
+
The `otp_secret_encryption_key` must be a random key that is not stored in the
|
89
|
+
DB, and is not checked in to your repo. It is recommended to store it in an
|
90
|
+
environment variable, and you can generate it with `bundle exec rake secret`.
|
80
91
|
|
81
|
-
Override the method to send one-time passwords in your model
|
92
|
+
Override the method to send one-time passwords in your model. This is
|
93
|
+
automatically called when a user logs in:
|
82
94
|
|
83
95
|
```ruby
|
84
96
|
def send_two_factor_authentication_code
|
@@ -86,10 +98,10 @@ def send_two_factor_authentication_code
|
|
86
98
|
end
|
87
99
|
```
|
88
100
|
|
89
|
-
|
90
101
|
### Customisation and Usage
|
91
102
|
|
92
|
-
By default second factor authentication
|
103
|
+
By default, second factor authentication is required for each user. You can
|
104
|
+
change that by overriding the following method in your model:
|
93
105
|
|
94
106
|
```ruby
|
95
107
|
def need_two_factor_authentication?(request)
|
@@ -97,19 +109,29 @@ def need_two_factor_authentication?(request)
|
|
97
109
|
end
|
98
110
|
```
|
99
111
|
|
100
|
-
|
112
|
+
In the example above, two factor authentication will not be required for local
|
113
|
+
users.
|
101
114
|
|
102
|
-
This gem is compatible with Google Authenticator
|
115
|
+
This gem is compatible with [Google Authenticator](https://support.google.com/accounts/answer/1066447?hl=en).
|
116
|
+
You can generate provisioning uris by invoking the following method on your model:
|
103
117
|
|
104
|
-
|
118
|
+
```ruby
|
119
|
+
user.provisioning_uri # This assumes a user model with an email attribute
|
120
|
+
```
|
105
121
|
|
106
|
-
This provisioning uri can then be turned in to a QR code if desired so that
|
122
|
+
This provisioning uri can then be turned in to a QR code if desired so that
|
123
|
+
users may add the app to Google Authenticator easily. Once this is done, they
|
124
|
+
may retrieve a one-time password directly from the Google Authenticator app as
|
125
|
+
well as through whatever method you define in
|
126
|
+
`send_two_factor_authentication_code`.
|
107
127
|
|
108
128
|
#### Overriding the view
|
109
129
|
|
110
|
-
The default view that shows the form can be overridden by
|
130
|
+
The default view that shows the form can be overridden by adding a
|
131
|
+
file named `show.html.erb` (or `show.html.haml` if you prefer HAML)
|
132
|
+
inside `app/views/devise/two_factor_authentication/` and customizing it.
|
133
|
+
Below is an example using ERB:
|
111
134
|
|
112
|
-
The full path should be "app/views/devise/two_factor_authentication/show.html.erb"
|
113
135
|
|
114
136
|
```html
|
115
137
|
<h2>Hi, you received a code by email, please enter it below, thanks!</h2>
|
@@ -125,22 +147,128 @@ The full path should be "app/views/devise/two_factor_authentication/show.html.er
|
|
125
147
|
|
126
148
|
#### Updating existing users with OTP secret key
|
127
149
|
|
128
|
-
If you have existing users that
|
150
|
+
If you have existing users that need to be provided with a OTP secret key, so
|
151
|
+
they can use two factor authentication, create a rake task. It could look like this one below:
|
129
152
|
|
130
153
|
```ruby
|
131
|
-
desc
|
154
|
+
desc 'rake task to update users with otp secret key'
|
132
155
|
task :update_users_with_otp_secret_key => :environment do
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
156
|
+
User.find_each do |user|
|
157
|
+
user.otp_secret_key = ROTP::Base32.random_base32
|
158
|
+
user.save!
|
159
|
+
puts "Rake[:update_users_with_otp_secret_key] => OTP secret key set to '#{key}' for User '#{user.email}'"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
```
|
163
|
+
Then run the task with `bundle exec rake update_users_with_otp_secret_key`
|
164
|
+
|
165
|
+
#### Adding the OTP encryption option to an existing app
|
166
|
+
|
167
|
+
If you've already been using this gem, and want to start encrypting the OTP
|
168
|
+
secret key in the database (recommended), you'll need to perform the following
|
169
|
+
steps:
|
170
|
+
|
171
|
+
1. Generate a migration to add the necessary columns to your model's table:
|
172
|
+
|
173
|
+
```
|
174
|
+
rails g migration AddEncryptionFieldsToUsers encrypted_otp_secret_key:string:index encrypted_otp_secret_key_iv:string encrypted_otp_secret_key_salt:string
|
175
|
+
```
|
176
|
+
|
177
|
+
Open your migration file (it will be in the `db/migrate` directory and will be
|
178
|
+
named something like `20151230163930_add_encryption_fields_to_users.rb`), and
|
179
|
+
add `unique: true` to the `add_index` line so that it looks like this:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
add_index :users, :encrypted_otp_secret_key, unique: true
|
183
|
+
```
|
184
|
+
Save the file.
|
185
|
+
|
186
|
+
2. Run the migration: `bundle exec rake db:migrate`
|
187
|
+
|
188
|
+
2. Update the gem: `bundle update two_factor_authentication`
|
189
|
+
|
190
|
+
3. Add `encrypted: true` to `has_one_time_password` in your model.
|
191
|
+
For example: `has_one_time_password(encrypted: true)`
|
192
|
+
|
193
|
+
4. Generate a migration to populate the new encryption fields:
|
194
|
+
```
|
195
|
+
rails g migration PopulateEncryptedOtpFields
|
196
|
+
```
|
197
|
+
|
198
|
+
Open the generated file, and replace its contents with the following:
|
199
|
+
```ruby
|
200
|
+
class PopulateEncryptedOtpFields < ActiveRecord::Migration
|
201
|
+
def up
|
202
|
+
User.reset_column_information
|
203
|
+
|
204
|
+
User.find_each do |user|
|
205
|
+
user.otp_secret_key = user.read_attribute('otp_secret_key')
|
206
|
+
user.save!
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def down
|
211
|
+
User.reset_column_information
|
212
|
+
|
213
|
+
User.find_each do |user|
|
214
|
+
user.otp_secret_key = ROTP::Base32.random_base32
|
215
|
+
user.save!
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
5. Generate a migration to remove the `:otp_secret_key` column:
|
222
|
+
```
|
223
|
+
rails g migration RemoveOtpSecretKeyFromUsers otp_secret_key:string
|
224
|
+
```
|
225
|
+
|
226
|
+
6. Run the migrations: `bundle exec rake db:migrate`
|
227
|
+
|
228
|
+
If, for some reason, you want to switch back to the old non-encrypted version,
|
229
|
+
use these steps:
|
230
|
+
|
231
|
+
1. Remove `(encrypted: true)` from `has_one_time_password`
|
232
|
+
|
233
|
+
2. Roll back the last 3 migrations (assuming you haven't added any new ones
|
234
|
+
after them):
|
235
|
+
```
|
236
|
+
bundle exec rake db:rollback STEP=3
|
237
|
+
```
|
238
|
+
|
239
|
+
#### Executing some code after the user signs in and before they sign out
|
240
|
+
|
241
|
+
In some cases, you might want to perform some action right after the user signs
|
242
|
+
in, but before the OTP is sent, and also right before the user signs out. One
|
243
|
+
scenario where you would need this is if you are requiring users to confirm
|
244
|
+
their phone number first before they can receive an OTP. If they enter a wrong
|
245
|
+
number, then sign out or close the browser before they confirm, they won't be
|
246
|
+
able to confirm their real number. To solve this problem, we need to be able to
|
247
|
+
reset their unconfirmed number before they sign out or sign in, and before the
|
248
|
+
OTP code is sent.
|
249
|
+
|
250
|
+
To define this action, create a `#{user.class}OtpSender` class that takes the
|
251
|
+
current user as its parameter, and defines a `#reset_otp_state` instance method.
|
252
|
+
For example, if your user's class is `User`, you would create a `UserOtpSender`
|
253
|
+
class, like this:
|
254
|
+
```ruby
|
255
|
+
class UserOtpSender
|
256
|
+
def initialize(user)
|
257
|
+
@user = user
|
258
|
+
end
|
259
|
+
|
260
|
+
def reset_otp_state
|
261
|
+
if @user.unconfirmed_mobile.present?
|
262
|
+
@user.update(unconfirmed_mobile: nil)
|
263
|
+
end
|
264
|
+
end
|
141
265
|
end
|
142
266
|
```
|
267
|
+
If you have different types of users in your app (for example, User and Admin),
|
268
|
+
and you need different logic for each type of user, create a second class for
|
269
|
+
your admin user, such as `AdminOtpSender`, with its own logic for
|
270
|
+
`#reset_otp_state`.
|
143
271
|
|
144
|
-
### Example
|
272
|
+
### Example App
|
145
273
|
|
146
274
|
[TwoFactorAuthenticationExample](https://github.com/Houdini/TwoFactorAuthenticationExample)
|