summaryrefslogtreecommitdiff
path: root/test/controllers/otp_challenges_controller_test.rb
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-24 13:53:13 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-24 13:53:13 +0200
commitdcb576618b868b888a5b1b31e35491f300ce4050 (patch)
tree3a970eae416fba2939cd366b1ba2b5d294154f2c /test/controllers/otp_challenges_controller_test.rb
parentfefec929c59c72dc93e4be30e8f23cd8c5258b0a (diff)
Complete the login only after the second factor
Enrolled users get a pending marker instead of a session after the password step; a valid code through the challenge writes the real session via reset_session. otp_required without enrollment funnels into setup everywhere except the enrollment, user, and login machinery.
Diffstat (limited to 'test/controllers/otp_challenges_controller_test.rb')
-rw-r--r--test/controllers/otp_challenges_controller_test.rb39
1 files changed, 39 insertions, 0 deletions
diff --git a/test/controllers/otp_challenges_controller_test.rb b/test/controllers/otp_challenges_controller_test.rb
new file mode 100644
index 00000000..470e84a2
--- /dev/null
+++ b/test/controllers/otp_challenges_controller_test.rb
@@ -0,0 +1,39 @@
1require "test_helper"
2
3class OtpChallengesControllerTest < ActionController::TestCase
4 fixtures :users
5
6 def setup
7 @user = users(:quentin)
8 @user.update!(:otp_secret => ROTP::Base32.random)
9 @request.session[:pending_otp_user_id] = @user.id
10 @request.session[:otp_deadline] = 2.minutes.from_now.to_i
11 @request.session[:otp_attempts] = 0
12 end
13
14 test "a valid code completes the login" do
15 post :create, params: { :code => ROTP::TOTP.new(@user.otp_secret).now }
16 assert_equal @user.id, session[:user_id]
17 assert_nil session[:pending_otp_user_id]
18 end
19
20 test "a wrong code does not log in" do
21 post :create, params: { :code => "000000" }
22 assert_nil session[:user_id]
23 assert_response :success
24 end
25
26 test "the pending window expires" do
27 @request.session[:otp_deadline] = 1.minute.ago.to_i
28 post :create, params: { :code => ROTP::TOTP.new(@user.otp_secret).now }
29 assert_nil session[:user_id]
30 assert_redirected_to login_path
31 end
32
33 test "attempts are limited" do
34 5.times { post :create, params: { :code => "000000" } }
35 post :create, params: { :code => ROTP::TOTP.new(@user.otp_secret).now }
36 assert_nil session[:user_id]
37 assert_redirected_to login_path
38 end
39end