devise-otp 0.2.2 → 0.2.3
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/lib/devise-otp/version.rb +1 -1
- data/lib/devise_otp_authenticatable/controllers/helpers.rb +2 -3
- data/lib/devise_otp_authenticatable/models/otp_authenticatable.rb +6 -10
- data/test/dummy/app/models/user.rb +1 -1
- data/test/integration/persistence_test.rb +65 -0
- data/test/integration/refresh_test.rb +14 -0
- data/test/integration/sign_in_test.rb +10 -0
- data/test/integration_tests_helper.rb +7 -2
- data/test/models/otp_authenticatable_test.rb +6 -0
- metadata +20 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a79f472f1aa5f902585f4e0d9fba2be6acd49c4d
|
4
|
+
data.tar.gz: ae454d13216e89de407336b54572276958d1c7b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 850c7c8ce55daf8a956f5d281f3e3be67030c543f7d91872e1009216c57f5dc8e56a381f287b862c1b994117a06fe5fc836829b3dc759c9ce12564c2743bb711
|
7
|
+
data.tar.gz: 425351d1ac147a529daf7a45d07456f8bc49697134ecaf6495bb42100f2b5cc451720620d461291fbdcde4c3b8e70cb61eb4b31d192cbabdd28f637883e7df5d
|
data/lib/devise-otp/version.rb
CHANGED
@@ -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.
|
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.
|
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
|
-
|
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
|
-
|
64
|
+
update_attributes!(:otp_enabled => true, :otp_enabled_on => Time.now)
|
65
65
|
end
|
66
66
|
|
67
67
|
def disable_otp!
|
68
|
-
|
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
|
-
|
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
|
-
|
93
|
-
|
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
|
-
:
|
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
|
-
|
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.
|
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
|
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
|
-
-
|
89
|
-
-
|
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
|