rodauth 1.13.0 → 1.14.0
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 +5 -5
- data/CHANGELOG +8 -0
- data/README.rdoc +1 -0
- data/doc/change_password_notify.rdoc +24 -0
- data/doc/release_notes/1.14.0.txt +19 -0
- data/lib/rodauth/features/account_expiration.rb +20 -0
- data/lib/rodauth/features/change_password_notify.rb +37 -0
- data/lib/rodauth/version.rb +1 -1
- data/spec/account_expiration_spec.rb +136 -1
- data/spec/change_password_notify_spec.rb +33 -0
- data/templates/password-changed-email.str +2 -0
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 62724514e9c4c31b8af9992d86ed3f1de98a38860ee7890f2da54e28fa4f2394
|
4
|
+
data.tar.gz: 58ba690b1c2e193728c6341d60df851e043fd3706ed1769c5ae6ecc0eed24592
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b187d024978cf9a7c22cc8f21e892dab50075c7eb2a605c45c7423cec186169e160d944e051d1e9c369222e373ee0e5ebd9effe217ca13f0d3edc7ec0e2875e
|
7
|
+
data.tar.gz: b990669e7aecbc09dcd90d89001ca35dd12fea964bbe1e8c29629b95f9a9bfe4fbb19cbcd683ab5b28575a7e00940aff087604e80f18c3d6c9a65b7bc658976b
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 1.14.0 (2017-12-19)
|
2
|
+
|
3
|
+
* Don't allow unlocking expired accounts when using account_expiration and lockout features (jeremyevans)
|
4
|
+
|
5
|
+
* Don't allow resetting passwords for expired accounts when using account_expiration and reset_password features (jeremyevans)
|
6
|
+
|
7
|
+
* Add change_password_notify feature for emailing when user uses change password feature (jeremyevans)
|
8
|
+
|
1
9
|
=== 1.13.0 (2017-11-21)
|
2
10
|
|
3
11
|
* Add json_response_body(hash) configuration method to jwt feature (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
= Documentation for Change Password Notify Feature
|
2
|
+
|
3
|
+
The change password notify feature emails the user when their password
|
4
|
+
is changed using the change password feature.
|
5
|
+
auth_value_method :password_changed_email_subject, 'Password Changed'
|
6
|
+
|
7
|
+
auth_value_methods(
|
8
|
+
:password_changed_email_body
|
9
|
+
)
|
10
|
+
auth_methods(
|
11
|
+
:create_password_changed_email,
|
12
|
+
:send_password_changed_email
|
13
|
+
)
|
14
|
+
|
15
|
+
|
16
|
+
== Auth Value Methods
|
17
|
+
|
18
|
+
password_changed_email_subject :: Subject to use for the password changed emails
|
19
|
+
password_changed_email_body :: Body to use for the password changed emails
|
20
|
+
|
21
|
+
== Auth Methods
|
22
|
+
|
23
|
+
create_password_changed_email :: A Mail::Message for the password changed email to send.
|
24
|
+
send_password_changed_email :: Send the account unlock email.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A change_password_notify feature has been added, which emails the
|
4
|
+
user when the change_password feature is used to change their
|
5
|
+
password. This can alert the user when their password may have
|
6
|
+
been changed without their knowledge.
|
7
|
+
|
8
|
+
= Other Improvements
|
9
|
+
|
10
|
+
* When using the account_expiration feature with the reset_password
|
11
|
+
feature, resetting the passwords for expired accounts is no longer
|
12
|
+
allowed. Note that the previous behavior isn't considered a
|
13
|
+
security issue, because even after resetting their password,
|
14
|
+
expired accounts could not login.
|
15
|
+
|
16
|
+
* When using the account_expiration feature with the lockout feature,
|
17
|
+
unlocking expired accounts is no longer allowed. Note that the
|
18
|
+
previous behavior isn't considered a security issue, because even
|
19
|
+
after unlocking the account, expired accounts could not login.
|
@@ -71,6 +71,26 @@ module Rodauth
|
|
71
71
|
|
72
72
|
private
|
73
73
|
|
74
|
+
def before_reset_password
|
75
|
+
check_account_expiration
|
76
|
+
super if defined?(super)
|
77
|
+
end
|
78
|
+
|
79
|
+
def before_reset_password_request
|
80
|
+
check_account_expiration
|
81
|
+
super if defined?(super)
|
82
|
+
end
|
83
|
+
|
84
|
+
def before_unlock_account
|
85
|
+
check_account_expiration
|
86
|
+
super if defined?(super)
|
87
|
+
end
|
88
|
+
|
89
|
+
def before_unlock_account_request
|
90
|
+
check_account_expiration
|
91
|
+
super if defined?(super)
|
92
|
+
end
|
93
|
+
|
74
94
|
def after_close_account
|
75
95
|
super if defined?(super)
|
76
96
|
account_activity_ds(account_id).delete
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
Feature.define(:change_password_notify, :ChangePasswordNotify) do
|
5
|
+
depends :change_password, :email_base
|
6
|
+
|
7
|
+
auth_value_method :password_changed_email_subject, 'Password Changed'
|
8
|
+
|
9
|
+
auth_value_methods(
|
10
|
+
:password_changed_email_body
|
11
|
+
)
|
12
|
+
auth_methods(
|
13
|
+
:create_password_changed_email,
|
14
|
+
:send_password_changed_email
|
15
|
+
)
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def send_password_changed_email
|
20
|
+
create_password_changed_email.deliver!
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_password_changed_email
|
24
|
+
create_email(password_changed_email_subject, password_changed_email_body)
|
25
|
+
end
|
26
|
+
|
27
|
+
def password_changed_email_body
|
28
|
+
render('password-changed-email')
|
29
|
+
end
|
30
|
+
|
31
|
+
def after_change_password
|
32
|
+
super
|
33
|
+
send_password_changed_email
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
data/lib/rodauth/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
2
|
|
3
3
|
describe 'Rodauth account expiration feature' do
|
4
|
-
it "should force account expiration after x number of days" do
|
4
|
+
it "should force account expiration after x number of days since last login" do
|
5
5
|
rodauth do
|
6
6
|
enable :login, :logout, :account_expiration
|
7
7
|
end
|
@@ -27,6 +27,141 @@ describe 'Rodauth account expiration feature' do
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
it "should not allow resetting of passwords for expired accounts" do
|
31
|
+
rodauth do
|
32
|
+
enable :login, :logout, :account_expiration, :reset_password
|
33
|
+
end
|
34
|
+
roda do |r|
|
35
|
+
r.rodauth
|
36
|
+
r.root{view :content=>rodauth.logged_in? ? "Logged In#{rodauth.last_account_login_at.strftime('%m%d%y')}" : "Not Logged"}
|
37
|
+
end
|
38
|
+
|
39
|
+
now = Time.now
|
40
|
+
login
|
41
|
+
page.body.must_include "Logged In#{now.strftime('%m%d%y')}"
|
42
|
+
logout
|
43
|
+
|
44
|
+
visit '/login'
|
45
|
+
click_link 'Forgot Password?'
|
46
|
+
fill_in 'Login', :with=>'foo@example.com'
|
47
|
+
click_button 'Request Password Reset'
|
48
|
+
link = email_link(/(\/reset-password\?key=.+)$/)
|
49
|
+
|
50
|
+
visit link
|
51
|
+
fill_in 'Password', :with=>'0123456'
|
52
|
+
fill_in 'Confirm Password', :with=>'0123456'
|
53
|
+
click_button 'Reset Password'
|
54
|
+
page.find('#notice_flash').text.must_equal "Your password has been reset"
|
55
|
+
page.current_path.must_equal '/'
|
56
|
+
|
57
|
+
visit '/login'
|
58
|
+
click_link 'Forgot Password?'
|
59
|
+
fill_in 'Login', :with=>'foo@example.com'
|
60
|
+
click_button 'Request Password Reset'
|
61
|
+
link = email_link(/(\/reset-password\?key=.+)$/)
|
62
|
+
|
63
|
+
DB[:account_activity_times].update(:last_login_at => Time.now - 181*86400)
|
64
|
+
|
65
|
+
visit link
|
66
|
+
page.title.must_equal 'Reset Password'
|
67
|
+
fill_in 'Password', :with=>'01234567'
|
68
|
+
fill_in 'Confirm Password', :with=>'01234567'
|
69
|
+
click_button 'Reset Password'
|
70
|
+
page.find('#error_flash').text.must_equal "You cannot log into this account as it has expired"
|
71
|
+
page.body.must_include 'Not Logged'
|
72
|
+
page.current_path.must_equal '/'
|
73
|
+
|
74
|
+
visit '/login'
|
75
|
+
click_link 'Forgot Password?'
|
76
|
+
fill_in 'Login', :with=>'foo@example.com'
|
77
|
+
click_button 'Request Password Reset'
|
78
|
+
page.find('#error_flash').text.must_equal "You cannot log into this account as it has expired"
|
79
|
+
page.body.must_include 'Not Logged'
|
80
|
+
page.current_path.must_equal '/'
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should not allow account unlocks for expired accounts" do
|
84
|
+
rodauth do
|
85
|
+
enable :lockout, :account_expiration, :logout
|
86
|
+
max_invalid_logins 2
|
87
|
+
unlock_account_autologin? false
|
88
|
+
end
|
89
|
+
roda do |r|
|
90
|
+
r.rodauth
|
91
|
+
r.root{view :content=>(rodauth.logged_in? ? "Logged In" : "Not Logged")}
|
92
|
+
end
|
93
|
+
|
94
|
+
login
|
95
|
+
logout
|
96
|
+
|
97
|
+
visit '/login'
|
98
|
+
fill_in 'Login', :with=>'foo@example.com'
|
99
|
+
3.times do
|
100
|
+
fill_in 'Password', :with=>'012345678910'
|
101
|
+
click_button 'Login'
|
102
|
+
end
|
103
|
+
|
104
|
+
page.body.must_include("This account is currently locked out")
|
105
|
+
click_button 'Request Account Unlock'
|
106
|
+
page.find('#notice_flash').text.must_equal 'An email has been sent to you with a link to unlock your account'
|
107
|
+
link = email_link(/(\/unlock-account\?key=.+)$/)
|
108
|
+
|
109
|
+
visit link
|
110
|
+
click_button 'Unlock Account'
|
111
|
+
page.find('#notice_flash').text.must_equal 'Your account has been unlocked'
|
112
|
+
page.body.must_include('Not Logged')
|
113
|
+
|
114
|
+
visit '/login'
|
115
|
+
fill_in 'Login', :with=>'foo@example.com'
|
116
|
+
3.times do
|
117
|
+
fill_in 'Password', :with=>'012345678910'
|
118
|
+
click_button 'Login'
|
119
|
+
end
|
120
|
+
|
121
|
+
page.body.must_include("This account is currently locked out")
|
122
|
+
click_button 'Request Account Unlock'
|
123
|
+
page.find('#notice_flash').text.must_equal 'An email has been sent to you with a link to unlock your account'
|
124
|
+
link = email_link(/(\/unlock-account\?key=.+)$/)
|
125
|
+
|
126
|
+
DB[:account_activity_times].update(:last_login_at => Time.now - 181*86400)
|
127
|
+
|
128
|
+
visit link
|
129
|
+
click_button 'Unlock Account'
|
130
|
+
page.find('#error_flash').text.must_equal "You cannot log into this account as it has expired"
|
131
|
+
page.body.must_include 'Not Logged'
|
132
|
+
page.current_path.must_equal '/'
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should not allow account unlock requests for expired accounts" do
|
136
|
+
rodauth do
|
137
|
+
enable :lockout, :account_expiration, :logout
|
138
|
+
max_invalid_logins 2
|
139
|
+
unlock_account_autologin? false
|
140
|
+
end
|
141
|
+
roda do |r|
|
142
|
+
r.rodauth
|
143
|
+
r.root{view :content=>(rodauth.logged_in? ? "Logged In" : "Not Logged")}
|
144
|
+
end
|
145
|
+
|
146
|
+
login
|
147
|
+
logout
|
148
|
+
|
149
|
+
visit '/login'
|
150
|
+
fill_in 'Login', :with=>'foo@example.com'
|
151
|
+
3.times do
|
152
|
+
fill_in 'Password', :with=>'012345678910'
|
153
|
+
click_button 'Login'
|
154
|
+
end
|
155
|
+
|
156
|
+
DB[:account_activity_times].update(:last_login_at => Time.now - 181*86400)
|
157
|
+
|
158
|
+
page.body.must_include("This account is currently locked out")
|
159
|
+
click_button 'Request Account Unlock'
|
160
|
+
page.find('#error_flash').text.must_equal "You cannot log into this account as it has expired"
|
161
|
+
page.body.must_include 'Not Logged'
|
162
|
+
page.current_path.must_equal '/'
|
163
|
+
end
|
164
|
+
|
30
165
|
it "should use last activity time if configured" do
|
31
166
|
rodauth do
|
32
167
|
enable :login, :logout, :account_expiration
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'Rodauth change_password_notify feature' do
|
4
|
+
it "should email when using change password" do
|
5
|
+
rodauth do
|
6
|
+
enable :login, :logout, :change_password_notify
|
7
|
+
change_password_requires_password? false
|
8
|
+
end
|
9
|
+
roda do |r|
|
10
|
+
r.rodauth
|
11
|
+
r.root{view :content=>""}
|
12
|
+
end
|
13
|
+
|
14
|
+
login
|
15
|
+
page.current_path.must_equal '/'
|
16
|
+
|
17
|
+
visit '/change-password'
|
18
|
+
fill_in 'New Password', :with=>'0123456'
|
19
|
+
fill_in 'Confirm Password', :with=>'0123456'
|
20
|
+
click_button 'Change Password'
|
21
|
+
page.find('#notice_flash').text.must_equal "Your password has been changed"
|
22
|
+
|
23
|
+
page.current_path.must_equal '/'
|
24
|
+
msgs = Mail::TestMailer.deliveries
|
25
|
+
msgs.length.must_equal 1
|
26
|
+
msgs.first.to.first.must_equal 'foo@example.com'
|
27
|
+
msgs.first.body.to_s.must_equal <<EMAIL
|
28
|
+
Someone (hopefully you) has changed the password for the account
|
29
|
+
associated to this email address.
|
30
|
+
EMAIL
|
31
|
+
msgs.clear
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rodauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -228,6 +228,7 @@ extra_rdoc_files:
|
|
228
228
|
- doc/http_basic_auth.rdoc
|
229
229
|
- doc/verify_login_change.rdoc
|
230
230
|
- doc/internals.rdoc
|
231
|
+
- doc/change_password_notify.rdoc
|
231
232
|
- doc/release_notes/1.0.0.txt
|
232
233
|
- doc/release_notes/1.1.0.txt
|
233
234
|
- doc/release_notes/1.2.0.txt
|
@@ -242,6 +243,7 @@ extra_rdoc_files:
|
|
242
243
|
- doc/release_notes/1.11.0.txt
|
243
244
|
- doc/release_notes/1.12.0.txt
|
244
245
|
- doc/release_notes/1.13.0.txt
|
246
|
+
- doc/release_notes/1.14.0.txt
|
245
247
|
files:
|
246
248
|
- CHANGELOG
|
247
249
|
- MIT-LICENSE
|
@@ -251,6 +253,7 @@ files:
|
|
251
253
|
- doc/base.rdoc
|
252
254
|
- doc/change_login.rdoc
|
253
255
|
- doc/change_password.rdoc
|
256
|
+
- doc/change_password_notify.rdoc
|
254
257
|
- doc/close_account.rdoc
|
255
258
|
- doc/confirm_password.rdoc
|
256
259
|
- doc/create_account.rdoc
|
@@ -274,6 +277,7 @@ files:
|
|
274
277
|
- doc/release_notes/1.11.0.txt
|
275
278
|
- doc/release_notes/1.12.0.txt
|
276
279
|
- doc/release_notes/1.13.0.txt
|
280
|
+
- doc/release_notes/1.14.0.txt
|
277
281
|
- doc/release_notes/1.2.0.txt
|
278
282
|
- doc/release_notes/1.3.0.txt
|
279
283
|
- doc/release_notes/1.4.0.txt
|
@@ -299,6 +303,7 @@ files:
|
|
299
303
|
- lib/rodauth/features/base.rb
|
300
304
|
- lib/rodauth/features/change_login.rb
|
301
305
|
- lib/rodauth/features/change_password.rb
|
306
|
+
- lib/rodauth/features/change_password_notify.rb
|
302
307
|
- lib/rodauth/features/close_account.rb
|
303
308
|
- lib/rodauth/features/confirm_password.rb
|
304
309
|
- lib/rodauth/features/create_account.rb
|
@@ -331,6 +336,7 @@ files:
|
|
331
336
|
- spec/account_expiration_spec.rb
|
332
337
|
- spec/all.rb
|
333
338
|
- spec/change_login_spec.rb
|
339
|
+
- spec/change_password_notify_spec.rb
|
334
340
|
- spec/change_password_spec.rb
|
335
341
|
- spec/close_account_spec.rb
|
336
342
|
- spec/confirm_password_spec.rb
|
@@ -377,6 +383,7 @@ files:
|
|
377
383
|
- templates/otp-auth.str
|
378
384
|
- templates/otp-disable.str
|
379
385
|
- templates/otp-setup.str
|
386
|
+
- templates/password-changed-email.str
|
380
387
|
- templates/password-confirm-field.str
|
381
388
|
- templates/password-field.str
|
382
389
|
- templates/recovery-auth.str
|
@@ -426,7 +433,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
426
433
|
version: '0'
|
427
434
|
requirements: []
|
428
435
|
rubyforge_project:
|
429
|
-
rubygems_version: 2.
|
436
|
+
rubygems_version: 2.7.3
|
430
437
|
signing_key:
|
431
438
|
specification_version: 4
|
432
439
|
summary: Authentication and Account Management Framework for Rack Applications
|