rodauth 1.22.0 → 1.23.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 +4 -4
- data/CHANGELOG +12 -0
- data/README.rdoc +5 -3
- data/doc/email_base.rdoc +1 -0
- data/doc/release_notes/1.23.0.txt +32 -0
- data/lib/rodauth.rb +5 -2
- data/lib/rodauth/features/base.rb +8 -0
- data/lib/rodauth/features/change_password_notify.rb +1 -1
- data/lib/rodauth/features/create_account.rb +1 -1
- data/lib/rodauth/features/email_auth.rb +3 -4
- data/lib/rodauth/features/email_base.rb +7 -2
- data/lib/rodauth/features/lockout.rb +1 -1
- data/lib/rodauth/features/login.rb +6 -2
- data/lib/rodauth/features/otp.rb +6 -3
- data/lib/rodauth/features/password_expiration.rb +1 -1
- data/lib/rodauth/features/recovery_codes.rb +3 -3
- data/lib/rodauth/features/reset_password.rb +2 -2
- data/lib/rodauth/features/sms_codes.rb +5 -5
- data/lib/rodauth/features/verify_account.rb +2 -2
- data/lib/rodauth/features/verify_login_change.rb +1 -1
- data/lib/rodauth/version.rb +1 -1
- data/templates/email-auth-request-form.str +2 -2
- data/templates/reset-password-request.str +3 -3
- data/templates/unlock-account-request.str +3 -3
- data/templates/verify-account-resend.str +3 -3
- metadata +5 -43
- data/Rakefile +0 -179
- data/spec/account_expiration_spec.rb +0 -225
- data/spec/all.rb +0 -1
- data/spec/change_login_spec.rb +0 -156
- data/spec/change_password_notify_spec.rb +0 -33
- data/spec/change_password_spec.rb +0 -202
- data/spec/close_account_spec.rb +0 -162
- data/spec/confirm_password_spec.rb +0 -70
- data/spec/create_account_spec.rb +0 -127
- data/spec/disallow_common_passwords_spec.rb +0 -93
- data/spec/disallow_password_reuse_spec.rb +0 -179
- data/spec/email_auth_spec.rb +0 -285
- data/spec/http_basic_auth_spec.rb +0 -143
- data/spec/jwt_cors_spec.rb +0 -57
- data/spec/jwt_refresh_spec.rb +0 -256
- data/spec/jwt_spec.rb +0 -235
- data/spec/lockout_spec.rb +0 -250
- data/spec/login_spec.rb +0 -328
- data/spec/migrate/001_tables.rb +0 -184
- data/spec/migrate/002_account_password_hash_column.rb +0 -11
- data/spec/migrate_password/001_tables.rb +0 -73
- data/spec/migrate_travis/001_tables.rb +0 -141
- data/spec/password_complexity_spec.rb +0 -109
- data/spec/password_expiration_spec.rb +0 -244
- data/spec/password_grace_period_spec.rb +0 -93
- data/spec/remember_spec.rb +0 -451
- data/spec/reset_password_spec.rb +0 -229
- data/spec/rodauth_spec.rb +0 -343
- data/spec/session_expiration_spec.rb +0 -58
- data/spec/single_session_spec.rb +0 -127
- data/spec/spec_helper.rb +0 -327
- data/spec/two_factor_spec.rb +0 -1462
- data/spec/update_password_hash_spec.rb +0 -40
- data/spec/verify_account_grace_period_spec.rb +0 -171
- data/spec/verify_account_spec.rb +0 -240
- data/spec/verify_change_login_spec.rb +0 -46
- data/spec/verify_login_change_spec.rb +0 -232
- data/spec/views/layout-other.str +0 -11
- data/spec/views/layout.str +0 -11
- data/spec/views/login.str +0 -21
data/spec/jwt_spec.rb
DELETED
@@ -1,235 +0,0 @@
|
|
1
|
-
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
describe 'Rodauth login feature' do
|
4
|
-
it "should not have jwt feature assume JWT token given during Basic/Digest authentication" do
|
5
|
-
rodauth do
|
6
|
-
enable :login, :logout
|
7
|
-
end
|
8
|
-
roda(:jwt) do |r|
|
9
|
-
rodauth.require_authentication
|
10
|
-
'1'
|
11
|
-
end
|
12
|
-
|
13
|
-
res = json_request("/", :headers=>{'HTTP_AUTHORIZATION'=>'Basic foo'})
|
14
|
-
res.must_equal [401, {'error'=>'Please login to continue'}]
|
15
|
-
|
16
|
-
res = json_request("/", :headers=>{'HTTP_AUTHORIZATION'=>'Digest foo'})
|
17
|
-
res.must_equal [401, {'error'=>'Please login to continue'}]
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should return error message if invalid JWT format used in request Authorization header" do
|
21
|
-
rodauth do
|
22
|
-
enable :login, :logout
|
23
|
-
end
|
24
|
-
roda(:jwt) do |r|
|
25
|
-
r.rodauth
|
26
|
-
rodauth.require_authentication
|
27
|
-
'1'
|
28
|
-
end
|
29
|
-
|
30
|
-
res = json_request('/login', :include_headers=>true, :login=>'foo@example.com', :password=>'0123456789')
|
31
|
-
|
32
|
-
res = json_request("/", :headers=>{'HTTP_AUTHORIZATION'=>res[1]['Authorization'][1..-1]})
|
33
|
-
res.must_equal [400, {'error'=>'invalid JWT format or claim in Authorization header'}]
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should use custom JSON error statuses even if the request isn't in JSON format if a JWT is in use" do
|
37
|
-
rodauth do
|
38
|
-
only_json? true
|
39
|
-
end
|
40
|
-
roda(:jwt) do |r|
|
41
|
-
r.rodauth
|
42
|
-
rodauth.require_authentication
|
43
|
-
'1'
|
44
|
-
end
|
45
|
-
|
46
|
-
status, headers, body = json_request("/", :headers=>{'CONTENT_TYPE'=>'text/html'}, :include_headers=>true)
|
47
|
-
status.must_equal 401
|
48
|
-
headers['Content-Type'].must_equal 'application/json'
|
49
|
-
JSON.parse(body.join).must_equal("error"=>"Please login to continue")
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should require json request content type in only json mode for rodauth endpoints only" do
|
53
|
-
oj = false
|
54
|
-
rodauth do
|
55
|
-
enable :login, :logout, :jwt
|
56
|
-
jwt_secret '1'
|
57
|
-
json_response_success_key 'success'
|
58
|
-
only_json?{oj}
|
59
|
-
end
|
60
|
-
roda(:csrf=>false, :json=>true) do |r|
|
61
|
-
r.rodauth
|
62
|
-
rodauth.require_authentication
|
63
|
-
'1'
|
64
|
-
end
|
65
|
-
|
66
|
-
res = json_request("/", :content_type=>'application/x-www-form-urlencoded', :include_headers=>true, :method=>'GET')
|
67
|
-
res[1].delete('Set-Cookie')
|
68
|
-
res.must_equal [302, {"Content-Type"=>'text/html', "Content-Length"=>'0', "Location"=>"/login",}, []]
|
69
|
-
|
70
|
-
res = json_request("/", :content_type=>'application/vnd.api+json', :method=>'GET')
|
71
|
-
res.must_equal [400, ['{"error":"Please login to continue"}']]
|
72
|
-
|
73
|
-
oj = true
|
74
|
-
|
75
|
-
res = json_request("/", :content_type=>'application/x-www-form-urlencoded', :method=>'GET')
|
76
|
-
res.must_equal [400, ['{"error":"Please login to continue"}']]
|
77
|
-
|
78
|
-
res = json_request("/", :method=>'GET')
|
79
|
-
res.must_equal [400, {'error'=>'Please login to continue'}]
|
80
|
-
|
81
|
-
res = json_request("/login", :content_type=>'application/x-www-form-urlencoded', :include_headers=>true, :method=>'GET')
|
82
|
-
msg = "Only JSON format requests are allowed"
|
83
|
-
res[1].delete('Set-Cookie')
|
84
|
-
res.must_equal [400, {"Content-Type"=>'text/html', "Content-Length"=>msg.length.to_s}, [msg]]
|
85
|
-
|
86
|
-
json_login
|
87
|
-
|
88
|
-
res = json_request("/", :content_type=>'application/x-www-form-urlencoded', :include_headers=>true, :method=>'GET')
|
89
|
-
res.must_equal [200, {"Content-Type"=>'text/html', "Content-Length"=>'1'}, ['1']]
|
90
|
-
end
|
91
|
-
|
92
|
-
it "should allow non-json requests if only_json? is false" do
|
93
|
-
rodauth do
|
94
|
-
enable :login, :logout, :jwt
|
95
|
-
jwt_secret '1'
|
96
|
-
only_json? false
|
97
|
-
end
|
98
|
-
roda(:jwt_html) do |r|
|
99
|
-
r.rodauth
|
100
|
-
rodauth.require_authentication
|
101
|
-
view(:content=>'1')
|
102
|
-
end
|
103
|
-
|
104
|
-
login
|
105
|
-
page.find('#notice_flash').text.must_equal 'You have been logged in'
|
106
|
-
end
|
107
|
-
|
108
|
-
it "should require POST for json requests" do
|
109
|
-
rodauth do
|
110
|
-
enable :login, :logout, :jwt
|
111
|
-
jwt_secret '1'
|
112
|
-
json_response_success_key 'success'
|
113
|
-
end
|
114
|
-
roda(:jwt) do |r|
|
115
|
-
r.rodauth
|
116
|
-
end
|
117
|
-
|
118
|
-
res = json_request("/login", :method=>'GET')
|
119
|
-
res.must_equal [405, {'error'=>'non-POST method used in JSON API'}]
|
120
|
-
end
|
121
|
-
|
122
|
-
it "should allow customizing JSON response bodies" do
|
123
|
-
rodauth do
|
124
|
-
enable :login, :logout, :jwt
|
125
|
-
json_response_body do |hash|
|
126
|
-
super('status'=>response.status, 'detail'=>hash)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
roda(:jwt) do |r|
|
130
|
-
r.rodauth
|
131
|
-
end
|
132
|
-
|
133
|
-
res = json_request("/login", :method=>'GET')
|
134
|
-
res.must_equal [405, {'status'=>405, 'detail'=>{'error'=>'non-POST method used in JSON API'}}]
|
135
|
-
end
|
136
|
-
|
137
|
-
it "should support valid_jwt? method for checking for valid JWT tokens" do
|
138
|
-
rodauth do
|
139
|
-
enable :login, :logout, :jwt
|
140
|
-
jwt_secret '1'
|
141
|
-
json_response_success_key 'success'
|
142
|
-
end
|
143
|
-
roda(:jwt) do |r|
|
144
|
-
r.rodauth
|
145
|
-
[rodauth.valid_jwt?.to_s]
|
146
|
-
end
|
147
|
-
|
148
|
-
res = json_request("/", :method=>'GET')
|
149
|
-
res.must_equal [200, ['false']]
|
150
|
-
|
151
|
-
res = json_request("/login", :method=>'GET')
|
152
|
-
res.must_equal [405, {'error'=>'non-POST method used in JSON API'}]
|
153
|
-
|
154
|
-
res = json_request("/", :method=>'GET')
|
155
|
-
res.must_equal [200, ['true']]
|
156
|
-
end
|
157
|
-
|
158
|
-
it "should require Accept contain application/json if jwt_check_accept? is true and Accept is present" do
|
159
|
-
rodauth do
|
160
|
-
enable :login, :logout, :jwt
|
161
|
-
jwt_secret '1'
|
162
|
-
json_response_success_key 'success'
|
163
|
-
jwt_check_accept? true
|
164
|
-
end
|
165
|
-
roda(:jwt) do |r|
|
166
|
-
r.rodauth
|
167
|
-
end
|
168
|
-
|
169
|
-
res = json_request("/login", :headers=>{'HTTP_ACCEPT'=>'text/html'})
|
170
|
-
res.must_equal [406, {'error'=>'Unsupported Accept header. Must accept "application/json" or compatible content type'}]
|
171
|
-
|
172
|
-
json_request("/login", :login=>'foo@example.com', :password=>'0123456789').must_equal [200, {"success"=>'You have been logged in'}]
|
173
|
-
json_request("/login", :headers=>{'HTTP_ACCEPT'=>'*/*'}, :login=>'foo@example.com', :password=>'0123456789').must_equal [200, {"success"=>'You have been logged in'}]
|
174
|
-
json_request("/login", :headers=>{'HTTP_ACCEPT'=>'application/*'}, :login=>'foo@example.com', :password=>'0123456789').must_equal [200, {"success"=>'You have been logged in'}]
|
175
|
-
json_request("/login", :headers=>{'HTTP_ACCEPT'=>'application/vnd.api+json'}, :login=>'foo@example.com', :password=>'0123456789').must_equal [200, {"success"=>'You have been logged in'}]
|
176
|
-
end
|
177
|
-
|
178
|
-
it "generates and verifies JWTs with claims" do
|
179
|
-
invalid_jti = false
|
180
|
-
|
181
|
-
rodauth do
|
182
|
-
enable :login, :logout, :jwt
|
183
|
-
jwt_secret '1'
|
184
|
-
json_response_success_key 'success'
|
185
|
-
jwt_session_key 'data'
|
186
|
-
jwt_symbolize_deeply? true
|
187
|
-
jwt_session_hash do
|
188
|
-
h = super()
|
189
|
-
h['data']['foo'] = {:bar=>[1]}
|
190
|
-
h.merge(
|
191
|
-
:aud => %w[Young Old],
|
192
|
-
:exp => Time.now.to_i + 120,
|
193
|
-
:iat => Time.now.to_i,
|
194
|
-
:iss => "Foobar, Inc.",
|
195
|
-
:jti => SecureRandom.hex(10),
|
196
|
-
:nbf => Time.now.to_i - 30,
|
197
|
-
:sub => session_value
|
198
|
-
)
|
199
|
-
end
|
200
|
-
jwt_decode_opts(
|
201
|
-
:aud => 'Old',
|
202
|
-
:iss => "Foobar, Inc.",
|
203
|
-
:leeway => 30,
|
204
|
-
:verify_aud => true,
|
205
|
-
:verify_expiration => true,
|
206
|
-
:verify_iat => true,
|
207
|
-
:verify_iss => true,
|
208
|
-
:verify_jti => proc{|jti| invalid_jti ? false : !!jti},
|
209
|
-
:verify_not_before => true
|
210
|
-
)
|
211
|
-
end
|
212
|
-
roda(:jwt) do |r|
|
213
|
-
r.rodauth
|
214
|
-
r.post{rodauth.session[:foo][:bar]}
|
215
|
-
end
|
216
|
-
|
217
|
-
json_login.must_equal [200, {"success"=>'You have been logged in'}]
|
218
|
-
|
219
|
-
payload = JWT.decode(@authorization, nil, false)[0]
|
220
|
-
payload['sub'].must_equal payload['data']['account_id']
|
221
|
-
payload['iat'].must_be_kind_of Integer
|
222
|
-
payload['exp'].must_be_kind_of Integer
|
223
|
-
payload['nbf'].must_be_kind_of Integer
|
224
|
-
payload['iss'].must_equal "Foobar, Inc."
|
225
|
-
payload['aud'].must_equal %w[Young Old]
|
226
|
-
payload['jti'].must_match(/^[0-9a-f]{20}$/)
|
227
|
-
|
228
|
-
json_request.must_equal [200, [1]]
|
229
|
-
|
230
|
-
invalid_jti = true
|
231
|
-
if RUBY_VERSION >= '1.9'
|
232
|
-
json_login(:no_check=>true).must_equal [400, {"error"=>'invalid JWT format or claim in Authorization header'}]
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
data/spec/lockout_spec.rb
DELETED
@@ -1,250 +0,0 @@
|
|
1
|
-
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
describe 'Rodauth lockout feature' do
|
4
|
-
it "should support account lockouts without autologin on unlock" do
|
5
|
-
lockouts = []
|
6
|
-
rodauth do
|
7
|
-
enable :lockout
|
8
|
-
max_invalid_logins 2
|
9
|
-
unlock_account_autologin? false
|
10
|
-
after_account_lockout{lockouts << true}
|
11
|
-
end
|
12
|
-
roda do |r|
|
13
|
-
r.rodauth
|
14
|
-
r.root{view :content=>(rodauth.logged_in? ? "Logged In" : "Not Logged")}
|
15
|
-
end
|
16
|
-
|
17
|
-
login(:pass=>'012345678910')
|
18
|
-
page.find('#error_flash').text.must_equal 'There was an error logging in'
|
19
|
-
|
20
|
-
login
|
21
|
-
page.find('#notice_flash').text.must_equal 'You have been logged in'
|
22
|
-
page.body.must_include("Logged In")
|
23
|
-
|
24
|
-
remove_cookie('rack.session')
|
25
|
-
|
26
|
-
visit '/login'
|
27
|
-
fill_in 'Login', :with=>'foo@example.com'
|
28
|
-
2.times do
|
29
|
-
fill_in 'Password', :with=>'012345678910'
|
30
|
-
click_button 'Login'
|
31
|
-
page.find('#error_flash').text.must_equal 'There was an error logging in'
|
32
|
-
end
|
33
|
-
lockouts.must_equal [true]
|
34
|
-
|
35
|
-
fill_in 'Password', :with=>'012345678910'
|
36
|
-
click_button 'Login'
|
37
|
-
page.find('#error_flash').text.must_equal "This account is currently locked out and cannot be logged in to."
|
38
|
-
page.body.must_include("This account is currently locked out")
|
39
|
-
click_button 'Request Account Unlock'
|
40
|
-
page.find('#notice_flash').text.must_equal 'An email has been sent to you with a link to unlock your account'
|
41
|
-
link = email_link(/(\/unlock-account\?key=.+)$/)
|
42
|
-
|
43
|
-
visit '/login'
|
44
|
-
fill_in 'Login', :with=>'foo@example.com'
|
45
|
-
fill_in 'Password', :with=>'012345678910'
|
46
|
-
click_button 'Login'
|
47
|
-
click_button 'Request Account Unlock'
|
48
|
-
email_link(/(\/unlock-account\?key=.+)$/).must_equal link
|
49
|
-
|
50
|
-
visit link[0...-1]
|
51
|
-
page.find('#error_flash').text.must_equal "There was an error unlocking your account: invalid or expired unlock account key"
|
52
|
-
|
53
|
-
visit link
|
54
|
-
click_button 'Unlock Account'
|
55
|
-
page.find('#notice_flash').text.must_equal 'Your account has been unlocked'
|
56
|
-
page.body.must_include('Not Logged')
|
57
|
-
|
58
|
-
login
|
59
|
-
page.find('#notice_flash').text.must_equal 'You have been logged in'
|
60
|
-
page.body.must_include("Logged In")
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should support account lockouts with autologin and password required on unlock" do
|
64
|
-
rodauth do
|
65
|
-
enable :lockout
|
66
|
-
unlock_account_requires_password? true
|
67
|
-
account_lockouts_email_last_sent_column :email_last_sent
|
68
|
-
end
|
69
|
-
roda do |r|
|
70
|
-
r.rodauth
|
71
|
-
r.root{view :content=>(rodauth.logged_in? ? "Logged In" : "Not Logged")}
|
72
|
-
end
|
73
|
-
|
74
|
-
visit '/login'
|
75
|
-
fill_in 'Login', :with=>'foo@example.com'
|
76
|
-
100.times do
|
77
|
-
fill_in 'Password', :with=>'012345678910'
|
78
|
-
click_button 'Login'
|
79
|
-
page.find('#error_flash').text.must_equal 'There was an error logging in'
|
80
|
-
end
|
81
|
-
|
82
|
-
fill_in 'Password', :with=>'012345678910'
|
83
|
-
click_button 'Login'
|
84
|
-
page.find('#error_flash').text.must_equal "This account is currently locked out and cannot be logged in to."
|
85
|
-
page.body.must_include("This account is currently locked out")
|
86
|
-
click_button 'Request Account Unlock'
|
87
|
-
page.find('#notice_flash').text.must_equal 'An email has been sent to you with a link to unlock your account'
|
88
|
-
link = email_link(/(\/unlock-account\?key=.+)$/)
|
89
|
-
|
90
|
-
visit '/login'
|
91
|
-
fill_in 'Login', :with=>'foo@example.com'
|
92
|
-
fill_in 'Password', :with=>'012345678910'
|
93
|
-
click_button 'Login'
|
94
|
-
click_button 'Request Account Unlock'
|
95
|
-
page.find('#error_flash').text.must_equal "An email has recently been sent to you with a link to unlock the account"
|
96
|
-
Mail::TestMailer.deliveries.must_equal []
|
97
|
-
|
98
|
-
visit link
|
99
|
-
click_button 'Unlock Account'
|
100
|
-
|
101
|
-
page.find('#error_flash').text.must_equal 'There was an error unlocking your account'
|
102
|
-
page.body.must_include('invalid password')
|
103
|
-
fill_in 'Password', :with=>'0123456789'
|
104
|
-
click_button 'Unlock Account'
|
105
|
-
|
106
|
-
page.find('#notice_flash').text.must_equal 'Your account has been unlocked'
|
107
|
-
page.body.must_include("Logged In")
|
108
|
-
end
|
109
|
-
|
110
|
-
it "should autounlock after enough time" do
|
111
|
-
rodauth do
|
112
|
-
enable :lockout
|
113
|
-
max_invalid_logins 2
|
114
|
-
end
|
115
|
-
roda do |r|
|
116
|
-
r.rodauth
|
117
|
-
r.root{view :content=>(rodauth.logged_in? ? "Logged In" : "Not Logged")}
|
118
|
-
end
|
119
|
-
|
120
|
-
visit '/login'
|
121
|
-
fill_in 'Login', :with=>'foo@example.com'
|
122
|
-
2.times do
|
123
|
-
fill_in 'Password', :with=>'012345678910'
|
124
|
-
click_button 'Login'
|
125
|
-
page.find('#error_flash').text.must_equal 'There was an error logging in'
|
126
|
-
end
|
127
|
-
fill_in 'Password', :with=>'012345678910'
|
128
|
-
click_button 'Login'
|
129
|
-
page.find('#error_flash').text.must_equal "This account is currently locked out and cannot be logged in to."
|
130
|
-
page.body.must_include("This account is currently locked out")
|
131
|
-
DB[:account_lockouts].update(:deadline=>Date.today - 3)
|
132
|
-
|
133
|
-
login
|
134
|
-
page.find('#notice_flash').text.must_equal 'You have been logged in'
|
135
|
-
page.body.must_include("Logged In")
|
136
|
-
end
|
137
|
-
|
138
|
-
it "should clear unlock token when closing account" do
|
139
|
-
rodauth do
|
140
|
-
enable :lockout, :close_account
|
141
|
-
max_invalid_logins 2
|
142
|
-
end
|
143
|
-
roda do |r|
|
144
|
-
r.get('b') do
|
145
|
-
session[:account_id] = DB[:accounts].get(:id)
|
146
|
-
'b'
|
147
|
-
end
|
148
|
-
r.rodauth
|
149
|
-
r.root{view :content=>(rodauth.logged_in? ? "Logged In" : "Not Logged")}
|
150
|
-
end
|
151
|
-
|
152
|
-
visit '/login'
|
153
|
-
fill_in 'Login', :with=>'foo@example.com'
|
154
|
-
3.times do
|
155
|
-
fill_in 'Password', :with=>'012345678910'
|
156
|
-
click_button 'Login'
|
157
|
-
end
|
158
|
-
DB[:account_lockouts].count.must_equal 1
|
159
|
-
|
160
|
-
visit 'b'
|
161
|
-
|
162
|
-
visit '/close-account'
|
163
|
-
fill_in 'Password', :with=>'0123456789'
|
164
|
-
click_button 'Close Account'
|
165
|
-
DB[:account_lockouts].count.must_equal 0
|
166
|
-
end
|
167
|
-
|
168
|
-
it "should handle uniqueness errors raised when inserting unlock account token" do
|
169
|
-
lockouts = []
|
170
|
-
rodauth do
|
171
|
-
enable :lockout
|
172
|
-
max_invalid_logins 2
|
173
|
-
after_account_lockout{lockouts << true}
|
174
|
-
end
|
175
|
-
roda do |r|
|
176
|
-
def rodauth.raised_uniqueness_violation(*) super; true; end
|
177
|
-
r.rodauth
|
178
|
-
r.root{view :content=>(rodauth.logged_in? ? "Logged In" : "Not Logged")}
|
179
|
-
end
|
180
|
-
|
181
|
-
visit '/login'
|
182
|
-
fill_in 'Login', :with=>'foo@example.com'
|
183
|
-
fill_in 'Password', :with=>'012345678910'
|
184
|
-
click_button 'Login'
|
185
|
-
page.find('#error_flash').text.must_equal 'There was an error logging in'
|
186
|
-
|
187
|
-
fill_in 'Password', :with=>'012345678910'
|
188
|
-
click_button 'Login'
|
189
|
-
lockouts.must_equal [true]
|
190
|
-
page.find('#error_flash').text.must_equal "This account is currently locked out and cannot be logged in to."
|
191
|
-
page.body.must_include("This account is currently locked out")
|
192
|
-
click_button 'Request Account Unlock'
|
193
|
-
page.find('#notice_flash').text.must_equal 'An email has been sent to you with a link to unlock your account'
|
194
|
-
|
195
|
-
link = email_link(/(\/unlock-account\?key=.+)$/)
|
196
|
-
visit link
|
197
|
-
click_button 'Unlock Account'
|
198
|
-
page.find('#notice_flash').text.must_equal 'Your account has been unlocked'
|
199
|
-
page.body.must_include("Logged In")
|
200
|
-
end
|
201
|
-
|
202
|
-
it "should support account lockouts via jwt" do
|
203
|
-
rodauth do
|
204
|
-
enable :logout, :lockout
|
205
|
-
max_invalid_logins 2
|
206
|
-
unlock_account_autologin? false
|
207
|
-
unlock_account_email_body{unlock_account_email_link}
|
208
|
-
end
|
209
|
-
roda(:jwt) do |r|
|
210
|
-
r.rodauth
|
211
|
-
[rodauth.logged_in? ? "Logged In" : "Not Logged"]
|
212
|
-
end
|
213
|
-
|
214
|
-
res = json_request('/unlock-account-request', :login=>'foo@example.com')
|
215
|
-
res.must_equal [401, {'error'=>"No matching login"}]
|
216
|
-
|
217
|
-
res = json_login(:pass=>'1', :no_check=>true)
|
218
|
-
res.must_equal [401, {'error'=>"There was an error logging in", "field-error"=>["password", "invalid password"]}]
|
219
|
-
|
220
|
-
json_login
|
221
|
-
json_logout
|
222
|
-
|
223
|
-
2.times do
|
224
|
-
res = json_login(:pass=>'1', :no_check=>true)
|
225
|
-
res.must_equal [401, {'error'=>"There was an error logging in", "field-error"=>["password", "invalid password"]}]
|
226
|
-
end
|
227
|
-
|
228
|
-
2.times do
|
229
|
-
res = json_login(:pass=>'1', :no_check=>true)
|
230
|
-
res.must_equal [403, {'error'=>"This account is currently locked out and cannot be logged in to."}]
|
231
|
-
end
|
232
|
-
|
233
|
-
res = json_request('/unlock-account')
|
234
|
-
res.must_equal [401, {'error'=>"There was an error unlocking your account: invalid or expired unlock account key"}]
|
235
|
-
|
236
|
-
res = json_request('/unlock-account-request', :login=>'foo@example.com')
|
237
|
-
res.must_equal [200, {'success'=>"An email has been sent to you with a link to unlock your account"}]
|
238
|
-
|
239
|
-
link = email_link(/key=.+$/)
|
240
|
-
res = json_request('/unlock-account', :key=>link[4...-1])
|
241
|
-
res.must_equal [401, {'error'=>"There was an error unlocking your account: invalid or expired unlock account key"}]
|
242
|
-
|
243
|
-
res = json_request('/unlock-account', :key=>link[4..-1])
|
244
|
-
res.must_equal [200, {'success'=>"Your account has been unlocked"}]
|
245
|
-
|
246
|
-
res = json_request.must_equal [200, ['Not Logged']]
|
247
|
-
|
248
|
-
json_login
|
249
|
-
end
|
250
|
-
end
|