devise-otp 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b5936698b6e66c85c09d06f13df85acec3ef012b
4
- data.tar.gz: 88768f71081fa8385d38aa5c035453003f7253b4
3
+ metadata.gz: a79f472f1aa5f902585f4e0d9fba2be6acd49c4d
4
+ data.tar.gz: ae454d13216e89de407336b54572276958d1c7b6
5
5
  SHA512:
6
- metadata.gz: b7f176ffae7d15974ce50a6e60c9a169c6e03c5e0f9933b7642e893592d4691c3e7d561a7755ea011a246d7a02a6711aa9c3e0b0cd0a75de1c5312126d94b2ea
7
- data.tar.gz: d1c47a4ce461d627709639a76963130b3566dda2951a2685d40551dccdad204d68ab15f0606ba31da9ba40259ceccfb21fe68bd2a3b32158292d092591a73ff7
6
+ metadata.gz: 850c7c8ce55daf8a956f5d281f3e3be67030c543f7d91872e1009216c57f5dc8e56a381f287b862c1b994117a06fe5fc836829b3dc759c9ce12564c2743bb711
7
+ data.tar.gz: 425351d1ac147a529daf7a45d07456f8bc49697134ecaf6495bb42100f2b5cc451720620d461291fbdcde4c3b8e70cb61eb4b31d192cbabdd28f637883e7df5d
@@ -1,5 +1,5 @@
1
1
  module Devise
2
2
  module Otp
3
- VERSION = "0.2.2"
3
+ VERSION = "0.2.3"
4
4
  end
5
5
  end
@@ -74,8 +74,7 @@ module DeviseOtpAuthenticatable
74
74
  return false unless resource.class.otp_trust_persistence
75
75
  if cookies[otp_scoped_persistence_cookie].present?
76
76
  cookies.signed[otp_scoped_persistence_cookie] ==
77
- [resource.class.serialize_into_cookie(resource), resource.otp_persistence_seed].tap do
78
- end
77
+ [resource.to_key, resource.authenticatable_salt, resource.otp_persistence_seed]
79
78
  else
80
79
  false
81
80
  end
@@ -89,7 +88,7 @@ module DeviseOtpAuthenticatable
89
88
  cookies.signed[otp_scoped_persistence_cookie] = {
90
89
  :httponly => true,
91
90
  :expires => Time.now + resource.class.otp_trust_persistence,
92
- :value => [resource.class.serialize_into_cookie(resource), resource.otp_persistence_seed]
91
+ :value => [resource.to_key, resource.authenticatable_salt, resource.otp_persistence_seed]
93
92
  }
94
93
  end
95
94
 
@@ -41,7 +41,7 @@ module Devise::Models
41
41
  @recovery_otp = nil
42
42
  generate_otp_auth_secret
43
43
  reset_otp_persistence
44
- update(:otp_enabled => false, :otp_time_drift => 0,
44
+ update_attributes!(:otp_enabled => false, :otp_time_drift => 0,
45
45
  :otp_session_challenge => nil, :otp_challenge_expires => nil,
46
46
  :otp_recovery_counter => 0)
47
47
  end
@@ -61,15 +61,15 @@ module Devise::Models
61
61
  end
62
62
 
63
63
  def enable_otp!
64
- update!(:otp_enabled => true, :otp_enabled_on => Time.now)
64
+ update_attributes!(:otp_enabled => true, :otp_enabled_on => Time.now)
65
65
  end
66
66
 
67
67
  def disable_otp!
68
- update!(:otp_enabled => false, :otp_enabled_on => nil, :otp_time_drift => 0)
68
+ update_attributes!(:otp_enabled => false, :otp_enabled_on => nil, :otp_time_drift => 0)
69
69
  end
70
70
 
71
71
  def generate_otp_challenge!(expires = nil)
72
- update!(:otp_session_challenge => SecureRandom.hex,
72
+ update_attributes!(:otp_session_challenge => SecureRandom.hex,
73
73
  :otp_challenge_expires => DateTime.now + (expires || self.class.otp_authentication_timeout))
74
74
  otp_session_challenge
75
75
  end
@@ -89,12 +89,8 @@ module Devise::Models
89
89
  alias_method :valid_otp_token?, :validate_otp_token
90
90
 
91
91
  def validate_otp_time_token(token)
92
- if drift = validate_otp_token_with_drift(token)
93
- update_column(:otp_time_drift, drift)
94
- true
95
- else
96
- false
97
- end
92
+ return false if token.blank?
93
+ validate_otp_token_with_drift(token)
98
94
  end
99
95
  alias_method :valid_otp_time_token?, :validate_otp_time_token
100
96
 
@@ -12,7 +12,7 @@ class User < PARENT_MODEL_CLASS
12
12
  end
13
13
 
14
14
  devise :otp_authenticatable, :database_authenticatable, :registerable,
15
- :recoverable, :rememberable, :trackable, :validatable
15
+ :trackable, :validatable
16
16
 
17
17
  # Setup accessible (or protected) attributes for your model
18
18
  #attr_accessible :otp_enabled, :otp_mandatory, :as => :otp_privileged
@@ -0,0 +1,65 @@
1
+ require 'test_helper'
2
+ require 'integration_tests_helper'
3
+
4
+ class PersistenceTest < ActionDispatch::IntegrationTest
5
+
6
+ def setup
7
+ @old_persistence = User.otp_trust_persistence
8
+ User.otp_trust_persistence = 3.seconds
9
+ end
10
+
11
+ def teardown
12
+ User.otp_trust_persistence = @old_persistence
13
+ Capybara.reset_sessions!
14
+ end
15
+
16
+ test 'a user should be requested the otp challenge every log in' do
17
+ # log in 1fa
18
+ user = enable_otp_and_sign_in
19
+ otp_challenge_for user
20
+
21
+ visit user_otp_token_path
22
+ assert_equal user_otp_token_path, current_path
23
+
24
+ sign_out
25
+ sign_user_in
26
+
27
+ assert_equal user_otp_credential_path, current_path
28
+ end
29
+
30
+ test 'a user should be able to set their browser as trusted' do
31
+ # log in 1fa
32
+ user = enable_otp_and_sign_in
33
+ otp_challenge_for user
34
+
35
+ visit user_otp_token_path
36
+ assert_equal user_otp_token_path, current_path
37
+
38
+ click_link('Trust this browser')
39
+ assert_text 'Your browser is trusted.'
40
+ sign_out
41
+
42
+ sign_user_in
43
+
44
+ assert_equal root_path, current_path
45
+ end
46
+
47
+ test 'trusted status should expire' do
48
+ # log in 1fa
49
+ user = enable_otp_and_sign_in
50
+ otp_challenge_for user
51
+
52
+ visit user_otp_token_path
53
+ assert_equal user_otp_token_path, current_path
54
+
55
+ click_link('Trust this browser')
56
+ assert_text 'Your browser is trusted.'
57
+ sign_out
58
+
59
+ sleep User.otp_trust_persistence.to_i + 1
60
+ sign_user_in
61
+
62
+ assert_equal user_otp_credential_path, current_path
63
+ end
64
+
65
+ end
@@ -89,4 +89,18 @@ class RefreshTest < ActionDispatch::IntegrationTest
89
89
 
90
90
  assert_equal user_otp_token_path, current_path
91
91
  end
92
+
93
+ test 'and rejected when the token is blank or null' do
94
+ user = enable_otp_and_sign_in_with_otp
95
+
96
+ sleep(2)
97
+ visit user_otp_token_path
98
+ assert_equal refresh_user_otp_credential_path, current_path
99
+
100
+ fill_in 'user_refresh_password', :with => '12345678'
101
+ fill_in 'user_token', :with => ''
102
+ click_button 'Continue...'
103
+
104
+ assert_equal refresh_user_otp_credential_path, current_path
105
+ end
92
106
  end
@@ -50,6 +50,16 @@ class SignInTest < ActionDispatch::IntegrationTest
50
50
  assert_equal new_user_session_path, current_path
51
51
  end
52
52
 
53
+ test 'fail blank token authentication' do
54
+ enable_otp_and_sign_in
55
+ assert_equal user_otp_credential_path, current_path
56
+
57
+ fill_in 'user_token', :with => ''
58
+ click_button 'Submit Token'
59
+
60
+ assert_equal user_otp_credential_path, current_path
61
+ end
62
+
53
63
  test 'successful token authentication' do
54
64
  user = enable_otp_and_sign_in
55
65
 
@@ -1,4 +1,5 @@
1
1
  class ActionDispatch::IntegrationTest
2
+ include Warden::Test::Helpers
2
3
 
3
4
  def warden
4
5
  request.env['warden']
@@ -36,6 +37,11 @@ class ActionDispatch::IntegrationTest
36
37
  user
37
38
  end
38
39
 
40
+ def otp_challenge_for(user)
41
+ fill_in 'user_token', :with => ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
42
+ click_button 'Submit Token'
43
+ end
44
+
39
45
  def disable_otp
40
46
  visit user_otp_token_path
41
47
  uncheck 'user_otp_enabled'
@@ -43,7 +49,7 @@ class ActionDispatch::IntegrationTest
43
49
  end
44
50
 
45
51
  def sign_out
46
- Capybara.reset_sessions!
52
+ logout :user
47
53
  end
48
54
 
49
55
  def sign_user_in(user = nil)
@@ -57,5 +63,4 @@ class ActionDispatch::IntegrationTest
57
63
  user
58
64
  end
59
65
 
60
-
61
66
  end
@@ -80,6 +80,12 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
80
80
  assert_equal false, u.otp_challenge_valid?
81
81
  end
82
82
 
83
+ test 'null otp challenge' do
84
+ u = User.first
85
+ u.update_attribute(:otp_enabled, true)
86
+ assert_equal false, u.validate_otp_token('')
87
+ assert_equal false, u.validate_otp_token(nil)
88
+ end
83
89
 
84
90
  test 'generated otp token should be valid for the user' do
85
91
  u = User.first
metadata CHANGED
@@ -1,81 +1,81 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise-otp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lele Forzani
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-14 00:00:00.000000000 Z
11
+ date: 2014-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: 3.2.6
20
- - - "<"
20
+ - - <
21
21
  - !ruby/object:Gem::Version
22
22
  version: '5'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - ">="
27
+ - - '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: 3.2.6
30
- - - "<"
30
+ - - <
31
31
  - !ruby/object:Gem::Version
32
32
  version: '5'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: devise
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
37
+ - - '>='
38
38
  - !ruby/object:Gem::Version
39
39
  version: 3.1.0
40
- - - "<"
40
+ - - <
41
41
  - !ruby/object:Gem::Version
42
42
  version: 4.0.0
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - ">="
47
+ - - '>='
48
48
  - !ruby/object:Gem::Version
49
49
  version: 3.1.0
50
- - - "<"
50
+ - - <
51
51
  - !ruby/object:Gem::Version
52
52
  version: 4.0.0
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: rotp
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
- - - ">="
57
+ - - '>='
58
58
  - !ruby/object:Gem::Version
59
59
  version: 2.0.0
60
60
  type: :runtime
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
- - - ">="
64
+ - - '>='
65
65
  - !ruby/object:Gem::Version
66
66
  version: 2.0.0
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: sqlite3
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - ">="
71
+ - - '>='
72
72
  - !ruby/object:Gem::Version
73
73
  version: '0'
74
74
  type: :development
75
75
  prerelease: false
76
76
  version_requirements: !ruby/object:Gem::Requirement
77
77
  requirements:
78
- - - ">="
78
+ - - '>='
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
81
  description: Time Based OTP/rfc6238 compatible authentication for Devise
@@ -85,8 +85,8 @@ executables: []
85
85
  extensions: []
86
86
  extra_rdoc_files: []
87
87
  files:
88
- - ".gitignore"
89
- - ".travis.yml"
88
+ - .gitignore
89
+ - .travis.yml
90
90
  - Gemfile
91
91
  - LICENSE.txt
92
92
  - README.md
@@ -160,6 +160,7 @@ files:
160
160
  - test/dummy/public/500.html
161
161
  - test/dummy/public/favicon.ico
162
162
  - test/dummy/script/rails
163
+ - test/integration/persistence_test.rb
163
164
  - test/integration/refresh_test.rb
164
165
  - test/integration/sign_in_test.rb
165
166
  - test/integration/token_test.rb
@@ -177,12 +178,12 @@ require_paths:
177
178
  - lib
178
179
  required_ruby_version: !ruby/object:Gem::Requirement
179
180
  requirements:
180
- - - ">="
181
+ - - '>='
181
182
  - !ruby/object:Gem::Version
182
183
  version: '0'
183
184
  required_rubygems_version: !ruby/object:Gem::Requirement
184
185
  requirements:
185
- - - ">="
186
+ - - '>='
186
187
  - !ruby/object:Gem::Version
187
188
  version: '0'
188
189
  requirements: []
@@ -236,6 +237,7 @@ test_files:
236
237
  - test/dummy/public/500.html
237
238
  - test/dummy/public/favicon.ico
238
239
  - test/dummy/script/rails
240
+ - test/integration/persistence_test.rb
239
241
  - test/integration/refresh_test.rb
240
242
  - test/integration/sign_in_test.rb
241
243
  - test/integration/token_test.rb