Fix tests

This commit is contained in:
Dan Milne
2026-01-01 14:52:24 +11:00
parent 9b81aee490
commit d597ca8810
3 changed files with 59 additions and 35 deletions

View File

@@ -1,8 +1,7 @@
require "test_helper" require "test_helper"
# Note: This file tests API endpoints directly (post/get/assert_response) # Advanced integration tests for Forward Auth API
# so it should use IntegrationTest, not SystemTestCase class ForwardAuthAdvancedTest < ActionDispatch::IntegrationTest
class ForwardAuthSystemTest < ActionDispatch::IntegrationTest
setup do setup do
@user = users(:one) @user = users(:one)
@admin_user = users(:two) @admin_user = users(:two)

View File

@@ -54,45 +54,39 @@ class WebauthnSecurityTest < ActionDispatch::IntegrationTest
end end
# ==================== # ====================
# USER HANDLE BINDING TESTS # USER HANDLE SECURITY TESTS
# ==================== # ====================
test "user handle is properly bound to WebAuthn credential" do test "WebAuthn challenge includes authenticated user's handle (not another user's)" do
user = User.create!(email_address: "webauthn_handle_test@example.com", password: "password123") # Create two users
user_a = User.create!(email_address: "usera@example.com", password: "password123")
user_b = User.create!(email_address: "userb@example.com", password: "password123")
# Create a WebAuthn credential with user handle # Generate handles for both users
user_handle = SecureRandom.uuid handle_a = user_a.webauthn_user_handle
credential = user.webauthn_credentials.create!( handle_b = user_b.webauthn_user_handle
external_id: Base64.urlsafe_encode64("fake_credential_id"),
public_key: Base64.urlsafe_encode64("fake_public_key"),
sign_count: 0,
nickname: "Test Key",
user_handle: user_handle
)
# Verify user handle is associated with the credential # Sign in as User A
assert_equal user_handle, credential.user_handle post signin_path, params: {email_address: user_a.email_address, password: "password123"}
assert_response :redirect
user.destroy # Request WebAuthn challenge (for registration)
end post webauthn_challenge_path, params: {email: user_a.email_address}
assert_response :success
test "WebAuthn authentication validates user handle" do # Parse the JSON response
user = User.create!(email_address: "webauthn_handle_auth_test@example.com", password: "password123") challenge_data = JSON.parse(response.body)
user_handle = SecureRandom.uuid # SECURITY: Verify challenge includes User A's handle
user.webauthn_credentials.create!( assert challenge_data.key?("user")
external_id: Base64.urlsafe_encode64("fake_credential_id"), assert_equal handle_a, challenge_data["user"]["id"], "Challenge should include authenticated user's handle"
public_key: Base64.urlsafe_encode64("fake_public_key"), assert_equal user_a.email_address, challenge_data["user"]["name"]
sign_count: 0,
nickname: "Test Key",
user_handle: user_handle
)
# Sign in with WebAuthn # SECURITY: Verify challenge does NOT include User B's handle
# The implementation should verify the user handle matches assert_not_equal handle_b, challenge_data["user"]["id"], "Challenge should NOT include another user's handle"
# This test documents the expected behavior
user.destroy user_a.destroy
user_b.destroy
end end
# ==================== # ====================
@@ -316,7 +310,7 @@ class WebauthnSecurityTest < ActionDispatch::IntegrationTest
test "WebAuthn can be required for authentication" do test "WebAuthn can be required for authentication" do
user = User.create!(email_address: "webauthn_required_test@example.com", password: "password123") user = User.create!(email_address: "webauthn_required_test@example.com", password: "password123")
user.update!(webauthn_enabled: true) user.update!(webauthn_required: true)
# Sign in with password should still work # Sign in with password should still work
post signin_path, params: {email_address: "webauthn_required_test@example.com", password: "password123"} post signin_path, params: {email_address: "webauthn_required_test@example.com", password: "password123"}
@@ -329,7 +323,7 @@ class WebauthnSecurityTest < ActionDispatch::IntegrationTest
test "WebAuthn can be used for passwordless authentication" do test "WebAuthn can be used for passwordless authentication" do
user = User.create!(email_address: "webauthn_passwordless_test@example.com", password: "password123") user = User.create!(email_address: "webauthn_passwordless_test@example.com", password: "password123")
user.update!(webauthn_enabled: true) user.update!(webauthn_required: true)
user.webauthn_credentials.create!( user.webauthn_credentials.create!(
external_id: Base64.urlsafe_encode64("passwordless_credential"), external_id: Base64.urlsafe_encode64("passwordless_credential"),

View File

@@ -319,4 +319,35 @@ class UserTest < ActiveSupport::TestCase
# Note: parsed_backup_codes method and legacy tests removed # Note: parsed_backup_codes method and legacy tests removed
# All users now use BCrypt hashes stored in JSON column # All users now use BCrypt hashes stored in JSON column
# WebAuthn user handle tests
test "generates and persists unique webauthn user handle" do
user = User.create!(email_address: "webauthn_test@example.com", password: "password123")
# User should not have a webauthn_id initially
assert_nil user.webauthn_id
# Getting the user handle should generate and persist it
handle = user.webauthn_user_handle
assert_not_nil handle
assert_equal 86, handle.length # Base64-urlsafe-encoded 64 bytes (no padding)
# Reload and verify it was persisted
user.reload
assert_equal handle, user.webauthn_id
# Subsequent calls should return the same handle (stable)
assert_equal handle, user.webauthn_user_handle
end
test "webauthn user handles are unique across users" do
user1 = User.create!(email_address: "user1@example.com", password: "password123")
user2 = User.create!(email_address: "user2@example.com", password: "password123")
handle1 = user1.webauthn_user_handle
handle2 = user2.webauthn_user_handle
# Each user should get a unique handle
assert_not_equal handle1, handle2
end
end end