devise-two-factor 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of devise-two-factor might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 938b85d49e3435d3b68b2c9f2b1e6c9af8ca9757
4
- data.tar.gz: 0fbb5330958d58752c38291640b9dfad48ce7ee6
3
+ metadata.gz: b71e31499a33b73bf9091ea49d750379c9a65445
4
+ data.tar.gz: 2d5600d12491430e2ba1053d31f0757fb7159141
5
5
  SHA512:
6
- metadata.gz: 731403794ad7ae6ef5b1830c168696b7acd82236af741f82b9623e44696f2b29492b16a089735fdc44b384c28818366894c292f306798250813a067aad5b6cae
7
- data.tar.gz: 858170aa39d456777fa6fe7e1c80503a67a7d48e4c4b715d1668fcd7f132c20deea4c04a2f1700cc6f97050e247ddf21234145339a3206bc82d9d70a37001c12
6
+ metadata.gz: bbe11caae0da8ea8a6fcbcd8b36592066c9fa73e027c1b67f0294d431219592623d832614e1db08c25f5bb39805e0945ba831996850934b2e191761a4cc06a44
7
+ data.tar.gz: 32ac8864fb19ad19a0d13514e1afb3eabcb2c7ffcddb329c8a801cc35e1598e4f0161fff6599ac7b24b89803d83e8220bf684e05f82ea745a3e3eca1f389d8c9
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -3,7 +3,7 @@ By [Tinfoil Security](http://tinfoilsecurity.com/)
3
3
 
4
4
  [![Build Status](https://travis-ci.org/tinfoil/devise-two-factor.svg?branch=master)](https://travis-ci.org/tinfoil/devise-two-factor)
5
5
 
6
- Devise-two-factor is a minimalist extension to Devise which offers support for two-factor authentication. It:
6
+ Devise-two-factor is a minimalist extension to Devise which offers support for two-factor authentication, through the [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) scheme. It:
7
7
 
8
8
  * Allows you to incorporate two-factor authentication into your existing models
9
9
  * Is opinionated about security, so you don't have to be
@@ -11,17 +11,22 @@ Devise-two-factor is a minimalist extension to Devise which offers support for t
11
11
  * Is extensible, and includes two-factor backup codes as an example of how plugins can be structured
12
12
 
13
13
  ## Example App
14
- An example Rails 4 application is provided in demo/
15
-
16
- It showcases a minimal example of devise-two-factor in action, and can act as a reference for integrating the gem into your own application.
14
+ An example Rails 4 application is provided in demo/. It showcases a minimal example of devise-two-factor in action, and can act as a reference for integrating the gem into your own application.
17
15
 
16
+ For the demo app to work, create an encryption key and store it as an environment variable. One way to do this is to create a file named `local_env.yml` in the application root. Set the value of 'ENCRYPTION_KEY' in the YML file. That value will be loaded into the application environment by `application.rb`.
18
17
 
19
18
  ## Getting Started
20
19
  Devise-two-factor doesn't require much to get started, but there are a few prerequisites before you can start using it in your application.
21
20
 
22
21
  First, you'll need a Rails application setup with Devise. Visit the Devise [homepage](https://github.com/plataformatec/devise) for instructions.
23
22
 
24
- Next, since devise-two-factor encrypts its secrets before storing them in the database, you'll need to generate an encryption key, and store it in an environment variable of your choice.
23
+ Next, since devise-two-factor encrypts its secrets before storing them in the database, you'll need to generate an encryption key, and store it in an environment variable of your choice. Set the encryption key in the model that uses devise:
24
+
25
+ ```
26
+ devise :two_factor_authenticatable,
27
+ :otp_secret_encryption_key => ENV['YOUR_ENCRYPTION_KEY_HERE']
28
+
29
+ ```
25
30
 
26
31
  Finally, you can automate all of the required setup by simply running:
27
32
 
@@ -45,14 +50,14 @@ If you're running Rails 3, or do not have strong parameters enabled, the generat
45
50
  **After running the generator, verify that :database_authenticatable is not being loaded by your model. The generator will try to remove it, but if you have a non-standard Devise setup, this step may fail. Loading both :database_authenticatable and :two_factor_authenticatable in a model will allow users to bypass two-factor authenticatable due to the way Warden handles cascading strategies.**
46
51
 
47
52
  ## Designing Your Workflow
48
- Devise-two-factor only worries about the backend, leaving the details of the integration up to you. This means that you're responsible for building the UI that drives the gem. While there is an example Rails application included in the gem, it is importable to remember that this gem is intentionally very open-ended, and you should build a user experience which fits your individual application.
53
+ Devise-two-factor only worries about the backend, leaving the details of the integration up to you. This means that you're responsible for building the UI that drives the gem. While there is an example Rails application included in the gem, it is important to remember that this gem is intentionally very open-ended, and you should build a user experience which fits your individual application.
49
54
 
50
55
  There are two key workflows you'll have to think about:
51
56
 
52
57
  1. Logging in with two-factor authentication
53
58
  2. Enabling two-factor authentication for a given user
54
59
 
55
- We chose to keep things as simple as possible, and our implemention can be found by registering at [Tinfoil Security](https://tinfoilsecurity.com/), and enabling two-factor authentication from the [security settings page](https://www.tinfoilsecurity.com/account/security).
60
+ We chose to keep things as simple as possible, and our implementation can be found by registering at [Tinfoil Security](https://tinfoilsecurity.com/), and enabling two-factor authentication from the [security settings page](https://www.tinfoilsecurity.com/account/security).
56
61
 
57
62
 
58
63
  ### Logging In
@@ -64,6 +69,53 @@ Logging in with two-factor authentication works extremely similarly to regular d
64
69
 
65
70
  These parameters can be submitted to the standard Devise login route, and the strategy will handle the authentication of the user for you.
66
71
 
72
+ ### Disabling Automatic Login After Password Resets
73
+ If you use the Devise ```recoverable``` strategy, the default behavior after a password reset is to automatically authenticate the user and log them in. This is obviously a problem if a user has two-factor authentication enabled, as resetting the password would get around the 2FA requirement.
74
+
75
+ Because of this, you need to override the controller and disable the automatic login on your own. If you don't use the ```recoverable``` strategy and don't provide the option of password resets, you don't need to worry about this. An example is as follows:
76
+
77
+ ```ruby
78
+ # app/controllers/passwords_controller.rb
79
+ class PasswordsController < Devise::PasswordsController
80
+ # Overrides to require a user to log in after resetting the password
81
+
82
+ def update
83
+ self.resource = resource_class.reset_password_by_token(resource_params)
84
+ yield resource if block_given?
85
+
86
+ if resource.errors.empty?
87
+ resource.unlock_access! if unlockable?(resource)
88
+ flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
89
+ set_flash_message(:notice, flash_message) if is_flashing_format?
90
+
91
+ # Do not automatically login if two-factor is enabled for this user.
92
+ # Remove the following three lines entirely if you want to disable
93
+ # automatic login for all users regardless, after a password reset.
94
+ unless resource.try(:otp_required_for_login?)
95
+ sign_in(resource_name, resource)
96
+ end
97
+
98
+ respond_with resource, location: after_resetting_password_path_for(resource)
99
+ else
100
+ respond_with resource
101
+ end
102
+ end
103
+
104
+ protected
105
+
106
+ def after_resetting_password_path_for(resource)
107
+ new_session_path(resource)
108
+ end
109
+ end
110
+ ```
111
+
112
+ And then tell Devise to use your new controller instead of the default:
113
+
114
+ ```ruby
115
+ # app/config/routes.rb
116
+ devise_for :users, :controllers => {:passwords => "passwords"}
117
+ ```
118
+
67
119
  ### Enabling Two-Factor Authentication
68
120
  Enabling two-factor authentication for a user is easy. For example, if my user model were named User, I could do the following:
69
121
 
@@ -77,6 +129,14 @@ Before you can do this however, you need to decide how you're going to transmit
77
129
 
78
130
  At Tinfoil Security, we opted to use the excellent [rqrcode-rails3](https://github.com/samvincent/rqrcode-rails3) gem to generate a QR-code representing the user's secret key, which can then be scanned by any mobile two-factor authentication client.
79
131
 
132
+ If you instead to decide to send the one-time password to the user directly, such as via SMS, you'll need a mechanism for generating the one-time password on the server:
133
+
134
+ ```ruby
135
+ current_user.current_otp
136
+ ```
137
+
138
+ The generated code will be valid for the duration specified by otp_allowed_drift.
139
+
80
140
  However you decide to handle enrollment, there are a few important considerations to be made:
81
141
 
82
142
  * Whether you'll force the use of two-factor authentication, and if so, how you'll migrate existing users to system, and what your onboarding experience will look like
@@ -146,7 +206,7 @@ Now just continue with the setup in the previous section, skipping the generator
146
206
  Devise-two-factor includes shared-examples for both TwoFactorAuthenticatable and TwoFactorBackupable. Adding the following two lines to the specs for your two-factor enabled models will allow you to test your models for two-factor functionality:
147
207
 
148
208
  ```ruby
149
- require 'devise_two_factor/spec_helpers
209
+ require 'devise_two_factor/spec_helpers'
150
210
 
151
211
  it_behaves_like "two_factor_authenticatable"
152
212
  it_behaves_like "two_factor_backupable"
@@ -27,12 +27,12 @@ Gem::Specification.new do |s|
27
27
  s.add_runtime_dependency 'rails' # For generators
28
28
  s.add_runtime_dependency 'activesupport'
29
29
  s.add_runtime_dependency 'activemodel'
30
- s.add_runtime_dependency 'attr_encrypted'
31
- s.add_runtime_dependency 'devise'
32
- s.add_runtime_dependency 'rotp'
30
+ s.add_runtime_dependency 'attr_encrypted', '~> 1.3.2'
31
+ s.add_runtime_dependency 'devise', '~> 3.2.4'
32
+ s.add_runtime_dependency 'rotp', '~> 1.6.1'
33
33
 
34
- s.add_development_dependency 'bundler', '> 1.0'
35
- s.add_development_dependency 'rspec', '~> 2.8'
34
+ s.add_development_dependency 'bundler', '> 1.0'
35
+ s.add_development_dependency 'rspec', '~> 2.8'
36
36
  s.add_development_dependency 'simplecov'
37
37
  s.add_development_dependency 'faker'
38
38
  s.add_development_dependency 'timecop'
@@ -10,7 +10,7 @@ module Devise
10
10
 
11
11
  included do
12
12
  attr_encrypted :otp_secret, :key => self.otp_secret_encryption_key,
13
- :mode => :per_attribute_iv_and_salt
13
+ :mode => :per_attribute_iv_and_salt unless self.attr_encrypted?(:otp_secret)
14
14
 
15
15
  attr_accessor :otp_attempt
16
16
  end
@@ -41,22 +41,22 @@ shared_examples 'two_factor_authenticatable' do
41
41
 
42
42
  it 'validates a precisely correct OTP' do
43
43
  otp = ROTP::TOTP.new(otp_secret).at(Time.now)
44
- subject.valid_otp?(otp).should be_true
44
+ subject.valid_otp?(otp).should be true
45
45
  end
46
46
 
47
47
  it 'validates an OTP within the allowed drift' do
48
48
  otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift, true)
49
- subject.valid_otp?(otp).should be_true
49
+ subject.valid_otp?(otp).should be true
50
50
  end
51
51
 
52
52
  it 'does not validate an OTP above the allowed drift' do
53
53
  otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift * 2, true)
54
- subject.valid_otp?(otp).should be_false
54
+ subject.valid_otp?(otp).should be false
55
55
  end
56
56
 
57
57
  it 'does not validate an OTP below the allowed drift' do
58
58
  otp = ROTP::TOTP.new(otp_secret).at(Time.now - subject.class.otp_allowed_drift * 2, true)
59
- subject.valid_otp?(otp).should be_false
59
+ subject.valid_otp?(otp).should be false
60
60
  end
61
61
  end
62
62
 
@@ -56,14 +56,14 @@ shared_examples 'two_factor_backupable' do
56
56
 
57
57
  context 'given an invalid recovery code' do
58
58
  it 'returns false' do
59
- subject.invalidate_otp_backup_code!('password').should be_false
59
+ subject.invalidate_otp_backup_code!('password').should be false
60
60
  end
61
61
  end
62
62
 
63
63
  context 'given a valid recovery code' do
64
64
  it 'returns true' do
65
65
  @plaintext_codes.each do |code|
66
- subject.invalidate_otp_backup_code!(code).should be_true
66
+ subject.invalidate_otp_backup_code!(code).should be true
67
67
  end
68
68
  end
69
69
 
@@ -71,7 +71,7 @@ shared_examples 'two_factor_backupable' do
71
71
  code = @plaintext_codes.sample
72
72
 
73
73
  subject.invalidate_otp_backup_code!(code)
74
- subject.invalidate_otp_backup_code!(code).should be_false
74
+ subject.invalidate_otp_backup_code!(code).should be false
75
75
  end
76
76
 
77
77
  it 'does not invalidate the other recovery codes' do
@@ -81,7 +81,7 @@ shared_examples 'two_factor_backupable' do
81
81
  @plaintext_codes.delete(code)
82
82
 
83
83
  @plaintext_codes.each do |code|
84
- subject.invalidate_otp_backup_code!(code).should be_true
84
+ subject.invalidate_otp_backup_code!(code).should be true
85
85
  end
86
86
  end
87
87
  end
@@ -1,3 +1,3 @@
1
1
  module DeviseTwoFactor
2
- VERSION = '1.0.0'.freeze
2
+ VERSION = '1.0.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise-two-factor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Wilton
@@ -84,7 +84,7 @@ cert_chain:
84
84
  5C31v4YyRBnNCp0pN66nxYX2avEiQ8riTBP5mlkPPOhsIoYQHHe2Uj75aVpu0LZ3
85
85
  cdFzuO4GC1dV0Wv+dsDm+MyF7DT5E9pUPXpnMJuPvPrFpCb+wrFlszW9hGjXbQ==
86
86
  -----END CERTIFICATE-----
87
- date: 2014-05-20 00:00:00.000000000 Z
87
+ date: 2015-04-07 00:00:00.000000000 Z
88
88
  dependencies:
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: rails
@@ -132,44 +132,44 @@ dependencies:
132
132
  name: attr_encrypted
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
- - - '>='
135
+ - - ~>
136
136
  - !ruby/object:Gem::Version
137
- version: '0'
137
+ version: 1.3.2
138
138
  type: :runtime
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - '>='
142
+ - - ~>
143
143
  - !ruby/object:Gem::Version
144
- version: '0'
144
+ version: 1.3.2
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: devise
147
147
  requirement: !ruby/object:Gem::Requirement
148
148
  requirements:
149
- - - '>='
149
+ - - ~>
150
150
  - !ruby/object:Gem::Version
151
- version: '0'
151
+ version: 3.2.4
152
152
  type: :runtime
153
153
  prerelease: false
154
154
  version_requirements: !ruby/object:Gem::Requirement
155
155
  requirements:
156
- - - '>='
156
+ - - ~>
157
157
  - !ruby/object:Gem::Version
158
- version: '0'
158
+ version: 3.2.4
159
159
  - !ruby/object:Gem::Dependency
160
160
  name: rotp
161
161
  requirement: !ruby/object:Gem::Requirement
162
162
  requirements:
163
- - - '>='
163
+ - - ~>
164
164
  - !ruby/object:Gem::Version
165
- version: '0'
165
+ version: 1.6.1
166
166
  type: :runtime
167
167
  prerelease: false
168
168
  version_requirements: !ruby/object:Gem::Requirement
169
169
  requirements:
170
- - - '>='
170
+ - - ~>
171
171
  - !ruby/object:Gem::Version
172
- version: '0'
172
+ version: 1.6.1
173
173
  - !ruby/object:Gem::Dependency
174
174
  name: bundler
175
175
  requirement: !ruby/object:Gem::Requirement
@@ -300,3 +300,4 @@ test_files:
300
300
  - spec/devise/models/two_factor_authenticatable_spec.rb
301
301
  - spec/devise/models/two_factor_backupable_spec.rb
302
302
  - spec/spec_helper.rb
303
+ has_rdoc:
metadata.gz.sig CHANGED
Binary file