devise-two-factor 1.0.2 → 1.1.0

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: 3861bb33d902cf04f7a2d8b87364758bc1815895
4
- data.tar.gz: 8cb9baa150b510bd49663ae3c9a7be207f19d201
3
+ metadata.gz: f606d2579650285b6cc4377b1da513596d979e3c
4
+ data.tar.gz: 36d5f5df579e84d85db796eacdb07376abdfec47
5
5
  SHA512:
6
- metadata.gz: 92cedbaed7b992027e851a52af6a086703255037ca9f6538a55e87a722cedef0be09d619cfd64faadaca198be45383acec0332d3ffb2b52ad1558407e5cfaa55
7
- data.tar.gz: fd1efa087db868c6b4ec4731db434c4304677ef05d47385c64c008f144450627586d135903584d5093e55a928af76be8e07a4bf22889816be490c8d7851e8ca1
6
+ metadata.gz: 5539b146deb18560ac1be676606a8165d860acef7661b80d73ce000d006d9a530c06121393707a0d9d91951c415703e7ece16cdda6698bf71f081267322d149f
7
+ data.tar.gz: d0c422b2f12ffdae6d507732d71fe06684fe69c2501c1a24c920b50ddfcfb037d5f69229869fbd62f54f345a43ea2788e90fb4e8942dfb20faf564d95069fed9
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/.travis.yml CHANGED
@@ -3,4 +3,6 @@ cache: bundler
3
3
  rvm:
4
4
  - "1.9.3"
5
5
  - "2.0.0"
6
+ - "2.1"
7
+ - "2.2"
6
8
  - jruby-19mode # JRuby in 1.9 mode
data/README.md CHANGED
@@ -20,7 +20,7 @@ Devise-two-factor doesn't require much to get started, but there are a few prere
20
20
 
21
21
  First, you'll need a Rails application setup with Devise. Visit the Devise [homepage](https://github.com/plataformatec/devise) for instructions.
22
22
 
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:
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
24
 
25
25
  ```
26
26
  devise :two_factor_authenticatable,
@@ -47,6 +47,20 @@ It also adds the :two_factor_authenticatable directive to your model, and sets u
47
47
 
48
48
  If you're running Rails 3, or do not have strong parameters enabled, the generator will also setup the required mass-assignment security options in your model.
49
49
 
50
+ If you're running Rails 4, you'll also need to whitelist `:otp_attempt` as a permitted parameter in Devise `:sign_in` controller. You can do this by adding the following to your `application_controller.rb`
51
+
52
+ ```ruby
53
+ before_action :configure_permitted_parameters, if: :devise_controller?
54
+
55
+ ...
56
+
57
+ protected
58
+
59
+ def configure_permitted_parameters
60
+ devise_parameter_sanitizer.for(:sign_in) << :otp_attempt
61
+ end
62
+ ```
63
+
50
64
  **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.**
51
65
 
52
66
  ## Designing Your Workflow
@@ -72,49 +86,7 @@ These parameters can be submitted to the standard Devise login route, and the st
72
86
  ### Disabling Automatic Login After Password Resets
73
87
  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
88
 
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
- ```
89
+ Because of this, you need to set `sign_in_after_reset_password` to false (either globally in your Devise initializer or via `devise_for`)
118
90
 
119
91
  ### Enabling Two-Factor Authentication
120
92
  Enabling two-factor authentication for a user is easy. For example, if my user model were named User, I could do the following:
@@ -26,11 +26,11 @@ Gem::Specification.new do |s|
26
26
 
27
27
  s.add_runtime_dependency 'railties'
28
28
  s.add_runtime_dependency 'activesupport'
29
- s.add_runtime_dependency 'activemodel'
30
29
  s.add_runtime_dependency 'attr_encrypted', '~> 1.3.2'
31
- s.add_runtime_dependency 'devise', '>= 3.2.4', '< 3.5'
32
- s.add_runtime_dependency 'rotp', '< 2'
30
+ s.add_runtime_dependency 'devise', '~> 3.5.0'
31
+ s.add_runtime_dependency 'rotp', '~> 2'
33
32
 
33
+ s.add_development_dependency 'activemodel'
34
34
  s.add_development_dependency 'bundler', '> 1.0'
35
35
  s.add_development_dependency 'rspec', '> 2', '< 3'
36
36
  s.add_development_dependency 'simplecov'
@@ -1,4 +1,3 @@
1
- require 'active_model'
2
1
  require 'attr_encrypted'
3
2
  require 'rotp'
4
3
 
@@ -1,5 +1,3 @@
1
- require 'active_model'
2
-
3
1
  module Devise
4
2
  module Models
5
3
  # TwoFactorBackupable allows a user to generate backup codes which
@@ -25,7 +23,7 @@ module Devise
25
23
  codes << SecureRandom.hex(code_length / 2) # Hexstring has length 2*n
26
24
  end
27
25
 
28
- hashed_codes = codes.map { |code| Devise.bcrypt self.class, code }
26
+ hashed_codes = codes.map { |code| Devise::Encryptor.digest(self.class, code) }
29
27
  self.otp_backup_codes = hashed_codes
30
28
 
31
29
  codes
@@ -37,14 +35,7 @@ module Devise
37
35
  codes = self.otp_backup_codes || []
38
36
 
39
37
  codes.each do |backup_code|
40
- # We hashed the code with Devise.bcrypt, so if Devise changes that
41
- # method, we'll have to adjust our comparison here to match it
42
- # TODO Fork Devise and encapsulate this logic in a helper
43
- bcrypt = ::BCrypt::Password.new(backup_code)
44
- hashed_code = ::BCrypt::Engine.hash_secret("#{code}#{self.class.pepper}",
45
- bcrypt.salt)
46
-
47
- next unless Devise.secure_compare(hashed_code, backup_code)
38
+ next unless Devise::Encryptor.compare(self.class, backup_code, code)
48
39
 
49
40
  codes.delete(backup_code)
50
41
  self.otp_backup_codes = codes
@@ -70,7 +70,7 @@ shared_examples 'two_factor_authenticatable' do
70
70
  end
71
71
 
72
72
  it 'should return uri with issuer option' do
73
- subject.otp_provisioning_uri(account, issuer: issuer).should match(%r{otpauth://totp/#{account}\?issuer=#{issuer}&secret=\w{#{otp_secret_length}}$})
73
+ subject.otp_provisioning_uri(account, issuer: issuer).should match(%r{otpauth://totp/#{account}\?secret=\w{#{otp_secret_length}}&issuer=#{issuer}$})
74
74
  end
75
75
  end
76
76
  end
@@ -36,7 +36,7 @@ shared_examples 'two_factor_backupable' do
36
36
 
37
37
  context 'with existing recovery codes' do
38
38
  let(:old_codes) { Faker::Lorem.words }
39
- let(:old_codes_hashed) { old_codes.map { |x| Devise.bcrypt subject.class, x } }
39
+ let(:old_codes_hashed) { old_codes.map { |x| Devise::Encryptor.digest(subject.class, x) } }
40
40
 
41
41
  before do
42
42
  subject.otp_backup_codes = old_codes_hashed
@@ -8,8 +8,7 @@ module Devise
8
8
  # 1. The password and the OTP are correct
9
9
  # 2. The password is correct, and OTP is not required for login
10
10
  # We check the OTP, then defer to DatabaseAuthenticatable
11
- if validate(resource) { !resource.otp_required_for_login ||
12
- resource.valid_otp?(params[scope]['otp_attempt']) }
11
+ if validate(resource) { validate_otp(resource) }
13
12
  super
14
13
  end
15
14
 
@@ -19,6 +18,12 @@ module Devise
19
18
  # but database authenticatable automatically halts on a bad password
20
19
  @halted = false if @result == :failure
21
20
  end
21
+
22
+ def validate_otp(resource)
23
+ return true unless resource.otp_required_for_login
24
+ return if params[scope]['otp_attempt'].nil?
25
+ resource.valid_otp?(params[scope]['otp_attempt'])
26
+ end
22
27
  end
23
28
  end
24
29
  end
@@ -1,3 +1,3 @@
1
1
  module DeviseTwoFactor
2
- VERSION = '1.0.2'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'active_model'
2
3
 
3
4
  class TwoFactorAuthenticatableDouble
4
5
  include ::ActiveModel::Validations::Callbacks
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.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Wilton
@@ -84,172 +84,166 @@ cert_chain:
84
84
  5C31v4YyRBnNCp0pN66nxYX2avEiQ8riTBP5mlkPPOhsIoYQHHe2Uj75aVpu0LZ3
85
85
  cdFzuO4GC1dV0Wv+dsDm+MyF7DT5E9pUPXpnMJuPvPrFpCb+wrFlszW9hGjXbQ==
86
86
  -----END CERTIFICATE-----
87
- date: 2015-05-27 00:00:00.000000000 Z
87
+ date: 2015-07-10 00:00:00.000000000 Z
88
88
  dependencies:
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: railties
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - '>='
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  type: :runtime
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - '>='
100
+ - - ">="
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: activesupport
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - '>='
107
+ - - ">="
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  type: :runtime
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
- - - '>='
114
+ - - ">="
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
117
  - !ruby/object:Gem::Dependency
118
- name: activemodel
118
+ name: attr_encrypted
119
119
  requirement: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - '>='
121
+ - - "~>"
122
122
  - !ruby/object:Gem::Version
123
- version: '0'
123
+ version: 1.3.2
124
124
  type: :runtime
125
125
  prerelease: false
126
126
  version_requirements: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - '>='
128
+ - - "~>"
129
129
  - !ruby/object:Gem::Version
130
- version: '0'
130
+ version: 1.3.2
131
131
  - !ruby/object:Gem::Dependency
132
- name: attr_encrypted
132
+ name: devise
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
- - - ~>
135
+ - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 1.3.2
137
+ version: 3.5.0
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: 1.3.2
144
+ version: 3.5.0
145
145
  - !ruby/object:Gem::Dependency
146
- name: devise
146
+ name: rotp
147
147
  requirement: !ruby/object:Gem::Requirement
148
148
  requirements:
149
- - - '>='
149
+ - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: 3.2.4
152
- - - <
153
- - !ruby/object:Gem::Version
154
- version: '3.5'
151
+ version: '2'
155
152
  type: :runtime
156
153
  prerelease: false
157
154
  version_requirements: !ruby/object:Gem::Requirement
158
155
  requirements:
159
- - - '>='
160
- - !ruby/object:Gem::Version
161
- version: 3.2.4
162
- - - <
156
+ - - "~>"
163
157
  - !ruby/object:Gem::Version
164
- version: '3.5'
158
+ version: '2'
165
159
  - !ruby/object:Gem::Dependency
166
- name: rotp
160
+ name: activemodel
167
161
  requirement: !ruby/object:Gem::Requirement
168
162
  requirements:
169
- - - <
163
+ - - ">="
170
164
  - !ruby/object:Gem::Version
171
- version: '2'
172
- type: :runtime
165
+ version: '0'
166
+ type: :development
173
167
  prerelease: false
174
168
  version_requirements: !ruby/object:Gem::Requirement
175
169
  requirements:
176
- - - <
170
+ - - ">="
177
171
  - !ruby/object:Gem::Version
178
- version: '2'
172
+ version: '0'
179
173
  - !ruby/object:Gem::Dependency
180
174
  name: bundler
181
175
  requirement: !ruby/object:Gem::Requirement
182
176
  requirements:
183
- - - '>'
177
+ - - ">"
184
178
  - !ruby/object:Gem::Version
185
179
  version: '1.0'
186
180
  type: :development
187
181
  prerelease: false
188
182
  version_requirements: !ruby/object:Gem::Requirement
189
183
  requirements:
190
- - - '>'
184
+ - - ">"
191
185
  - !ruby/object:Gem::Version
192
186
  version: '1.0'
193
187
  - !ruby/object:Gem::Dependency
194
188
  name: rspec
195
189
  requirement: !ruby/object:Gem::Requirement
196
190
  requirements:
197
- - - '>'
191
+ - - ">"
198
192
  - !ruby/object:Gem::Version
199
193
  version: '2'
200
- - - <
194
+ - - "<"
201
195
  - !ruby/object:Gem::Version
202
196
  version: '3'
203
197
  type: :development
204
198
  prerelease: false
205
199
  version_requirements: !ruby/object:Gem::Requirement
206
200
  requirements:
207
- - - '>'
201
+ - - ">"
208
202
  - !ruby/object:Gem::Version
209
203
  version: '2'
210
- - - <
204
+ - - "<"
211
205
  - !ruby/object:Gem::Version
212
206
  version: '3'
213
207
  - !ruby/object:Gem::Dependency
214
208
  name: simplecov
215
209
  requirement: !ruby/object:Gem::Requirement
216
210
  requirements:
217
- - - '>='
211
+ - - ">="
218
212
  - !ruby/object:Gem::Version
219
213
  version: '0'
220
214
  type: :development
221
215
  prerelease: false
222
216
  version_requirements: !ruby/object:Gem::Requirement
223
217
  requirements:
224
- - - '>='
218
+ - - ">="
225
219
  - !ruby/object:Gem::Version
226
220
  version: '0'
227
221
  - !ruby/object:Gem::Dependency
228
222
  name: faker
229
223
  requirement: !ruby/object:Gem::Requirement
230
224
  requirements:
231
- - - '>='
225
+ - - ">="
232
226
  - !ruby/object:Gem::Version
233
227
  version: '0'
234
228
  type: :development
235
229
  prerelease: false
236
230
  version_requirements: !ruby/object:Gem::Requirement
237
231
  requirements:
238
- - - '>='
232
+ - - ">="
239
233
  - !ruby/object:Gem::Version
240
234
  version: '0'
241
235
  - !ruby/object:Gem::Dependency
242
236
  name: timecop
243
237
  requirement: !ruby/object:Gem::Requirement
244
238
  requirements:
245
- - - '>='
239
+ - - ">="
246
240
  - !ruby/object:Gem::Version
247
241
  version: '0'
248
242
  type: :development
249
243
  prerelease: false
250
244
  version_requirements: !ruby/object:Gem::Requirement
251
245
  requirements:
252
- - - '>='
246
+ - - ">="
253
247
  - !ruby/object:Gem::Version
254
248
  version: '0'
255
249
  description: Barebones two-factor authentication with Devise
@@ -258,9 +252,9 @@ executables: []
258
252
  extensions: []
259
253
  extra_rdoc_files: []
260
254
  files:
261
- - .gitignore
262
- - .rspec
263
- - .travis.yml
255
+ - ".gitignore"
256
+ - ".rspec"
257
+ - ".travis.yml"
264
258
  - CONTRIBUTING.md
265
259
  - Gemfile
266
260
  - LICENSE
@@ -294,12 +288,12 @@ require_paths:
294
288
  - lib
295
289
  required_ruby_version: !ruby/object:Gem::Requirement
296
290
  requirements:
297
- - - '>='
291
+ - - ">="
298
292
  - !ruby/object:Gem::Version
299
293
  version: '0'
300
294
  required_rubygems_version: !ruby/object:Gem::Requirement
301
295
  requirements:
302
- - - '>='
296
+ - - ">="
303
297
  - !ruby/object:Gem::Version
304
298
  version: '0'
305
299
  requirements: []
@@ -312,4 +306,3 @@ test_files:
312
306
  - spec/devise/models/two_factor_authenticatable_spec.rb
313
307
  - spec/devise/models/two_factor_backupable_spec.rb
314
308
  - spec/spec_helper.rb
315
- has_rdoc:
metadata.gz.sig CHANGED
Binary file