Skip to content

Commit 6a9f859

Browse files
committed
Integration test for 2fa auth (#1237).
Patch by Jens Krämer. git-svn-id: http://svn.redmine.org/redmine/trunk@19991 e93f8b46-1217-0410-a6f0-8f06a7374b81
1 parent 8900eb6 commit 6a9f859

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

test/integration/twofa_test.rb

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# frozen_string_literal: true
2+
3+
# Redmine - project management software
4+
# Copyright (C) 2006-2020 Jean-Philippe Lang
5+
#
6+
# This program is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU General Public License
8+
# as published by the Free Software Foundation; either version 2
9+
# of the License, or (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program; if not, write to the Free Software
18+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
20+
require File.expand_path('../../test_helper', __FILE__)
21+
22+
class TwofaTest < Redmine::IntegrationTest
23+
fixtures :projects, :users, :email_addresses
24+
25+
test "should require twofa setup when configured" do
26+
with_settings twofa: "2" do
27+
log_user('jsmith', 'jsmith')
28+
follow_redirect!
29+
assert_redirected_to "/my/twofa/totp/activate/confirm"
30+
end
31+
end
32+
33+
test "should generate and accept backup codes" do
34+
log_user('jsmith', 'jsmith')
35+
get "/my/account"
36+
assert_response :success
37+
post "/my/twofa/totp/activate/init"
38+
assert_redirected_to "/my/twofa/totp/activate/confirm"
39+
follow_redirect!
40+
assert_response :success
41+
42+
totp = ROTP::TOTP.new User.find_by_login('jsmith').twofa_totp_key
43+
post "/my/twofa/totp/activate", params: { twofa_code: totp.now }
44+
assert_redirected_to "/my/account"
45+
follow_redirect!
46+
assert_response :success
47+
assert_select '.flash', /Two-factor authentication successfully enabled/i
48+
49+
post "/my/twofa/backup_codes/init"
50+
assert_redirected_to "/my/twofa/backup_codes/confirm"
51+
follow_redirect!
52+
assert_response :success
53+
assert_select 'form', /Please enter your two-factor authentication code/i
54+
55+
post "/my/twofa/backup_codes/create", params: { twofa_code: "wrong" }
56+
assert_redirected_to "/my/twofa/backup_codes/confirm"
57+
follow_redirect!
58+
assert_response :success
59+
assert_select 'form', /Please enter your two-factor authentication code/i
60+
61+
# prevent replay attack prevention from kicking in
62+
User.find_by_login('jsmith').update_column :twofa_totp_last_used_at, 2.minutes.ago.to_i
63+
64+
post "/my/twofa/backup_codes/create", params: { twofa_code: totp.now }
65+
assert_redirected_to "/my/twofa/backup_codes"
66+
follow_redirect!
67+
assert_response :success
68+
assert_select ".flash", /your backup codes have been generated/i
69+
70+
assert code = response.body.scan(/<code>([a-z0-9]{4} [a-z0-9]{4} [a-z0-9]{4})<\/code>/).flatten.first
71+
72+
post "/logout"
73+
follow_redirect!
74+
# prevent replay attack prevention from kicking in
75+
User.find_by_login('jsmith').update_column :twofa_totp_last_used_at, 2.minutes.ago.to_i
76+
77+
# sign in with backup code
78+
get "/login"
79+
assert_nil session[:user_id]
80+
assert_response :success
81+
post "/login", params: {
82+
username: 'jsmith',
83+
password: 'jsmith'
84+
}
85+
assert_redirected_to "/account/twofa/confirm"
86+
follow_redirect!
87+
88+
assert_select "#login-form h3", /two-factor authentication/i
89+
post "/account/twofa", params: { twofa_code: code }
90+
assert_redirected_to "/my/page"
91+
follow_redirect!
92+
assert_response :success
93+
end
94+
95+
test "should configure totp and require code on login" do
96+
with_settings twofa: "2" do
97+
log_user('jsmith', 'jsmith')
98+
follow_redirect!
99+
assert_redirected_to "/my/twofa/totp/activate/confirm"
100+
follow_redirect!
101+
102+
assert key = User.find_by_login('jsmith').twofa_totp_key
103+
assert key.present?
104+
totp = ROTP::TOTP.new key
105+
106+
post "/my/twofa/totp/activate", params: { twofa_code: '123456789' }
107+
assert_redirected_to "/my/twofa/totp/activate/confirm"
108+
follow_redirect!
109+
110+
post "/my/twofa/totp/activate", params: { twofa_code: totp.now }
111+
assert_redirected_to "/my/account"
112+
113+
post "/logout"
114+
follow_redirect!
115+
116+
# prevent replay attack prevention from kicking in
117+
User.find_by_login('jsmith').update_column :twofa_totp_last_used_at, 2.minutes.ago.to_i
118+
119+
# sign in with totp
120+
get "/login"
121+
assert_nil session[:user_id]
122+
assert_response :success
123+
post "/login", params: {
124+
username: 'jsmith',
125+
password: 'jsmith'
126+
}
127+
128+
assert_redirected_to "/account/twofa/confirm"
129+
follow_redirect!
130+
131+
assert_select "#login-form h3", /two-factor authentication/i
132+
post "/account/twofa", params: { twofa_code: 'wrong code' }
133+
assert_redirected_to "/account/twofa/confirm"
134+
follow_redirect!
135+
assert_select "#login-form h3", /two-factor authentication/i
136+
assert_select ".flash", /code is invalid/i
137+
138+
post "/account/twofa", params: { twofa_code: totp.now }
139+
assert_redirected_to "/my/page"
140+
follow_redirect!
141+
assert_response :success
142+
end
143+
end
144+
end

0 commit comments

Comments
 (0)