diff --git a/test/controllers/api_test.rb b/test/controllers/api_test.rb index a48511cf8..f6bf18ca6 100644 --- a/test/controllers/api_test.rb +++ b/test/controllers/api_test.rb @@ -6,6 +6,22 @@ class ApiTest < ActionDispatch::IntegrationTest @jasons_bearer_token = bearer_token_env(identity_access_tokens(:jasons_api_token).token) end + test "authenticate with user credentials" do + identity = identities(:david) + + untenanted do + post session_path(format: :json), params: { email_address: identity.email_address } + assert_response :created + pending_token = @response.parsed_body["pending_authentication_token"] + assert pending_token.present? + + magic_link = MagicLink.last + post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: pending_token } + assert_response :success + assert @response.parsed_body["session_token"].present? + end + end + test "authenticate with valid access token" do get boards_path(format: :json), env: @davids_bearer_token assert_response :success diff --git a/test/controllers/magic_link_api_test.rb b/test/controllers/magic_link_api_test.rb deleted file mode 100644 index 4b7f7f444..000000000 --- a/test/controllers/magic_link_api_test.rb +++ /dev/null @@ -1,118 +0,0 @@ -require "test_helper" - -class MagicLinkApiTest < ActionDispatch::IntegrationTest - test "request a magic link" do - untenanted do - post session_path(format: :json), params: { email_address: identities(:david).email_address } - assert_response :created - end - end - - test "magic link consumption" do - identity = identities(:david) - magic_link = identity.send_magic_link - pending_token = pending_authentication_token_for(identity.email_address) - - untenanted do - post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: pending_token } - assert_response :success - assert @response.parsed_body["session_token"].present? - end - end - - test "full JSON authentication flow with pending_authentication_token" do - identity = identities(:david) - - untenanted do - post session_path(format: :json), params: { email_address: identity.email_address } - assert_response :created - pending_token = @response.parsed_body["pending_authentication_token"] - assert pending_token.present? - - magic_link = MagicLink.last - post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: pending_token } - assert_response :success - assert @response.parsed_body["session_token"].present? - end - end - - test "magic link consumption without pending_authentication_token returns unauthorized" do - identity = identities(:david) - magic_link = identity.send_magic_link - - untenanted do - post session_magic_link_path(format: :json), params: { code: magic_link.code } - assert_response :unauthorized - assert_equal "Enter your email address to sign in.", @response.parsed_body["message"] - end - end - - test "magic link consumption with invalid code via JSON" do - identity = identities(:david) - pending_token = pending_authentication_token_for(identity.email_address) - - untenanted do - post session_magic_link_path(format: :json), params: { code: "INVALID", pending_authentication_token: pending_token } - assert_response :unauthorized - assert_equal "Try another code.", @response.parsed_body["message"] - end - end - - test "magic link consumption with cross-user code via JSON returns unauthorized" do - identity = identities(:david) - other_identity = identities(:jason) - magic_link = other_identity.send_magic_link - pending_token = pending_authentication_token_for(identity.email_address) - - untenanted do - post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: pending_token } - assert_response :unauthorized - assert_equal "Something went wrong. Please try again.", @response.parsed_body["message"] - end - end - - test "magic link consumption with expired pending_authentication_token" do - identity = identities(:david) - magic_link = identity.send_magic_link - - expired_token = nil - travel_to 15.minutes.ago do - expired_token = pending_authentication_token_for(identity.email_address) - end - - untenanted do - post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: expired_token } - assert_response :unauthorized - assert_equal "Enter your email address to sign in.", @response.parsed_body["message"] - end - end - - test "create session for new user via JSON" do - new_email = "new-user-#{SecureRandom.hex(6)}@example.com" - - untenanted do - assert_difference -> { Identity.count }, 1 do - assert_difference -> { MagicLink.count }, 1 do - post session_path(format: :json), params: { email_address: new_email } - end - end - assert_response :created - assert @response.parsed_body["pending_authentication_token"].present? - assert MagicLink.last.for_sign_up? - end - end - - test "create session with invalid email via JSON" do - untenanted do - assert_no_difference -> { Identity.count } do - post session_path(format: :json), params: { email_address: "not-a-valid-email" } - end - assert_response :unprocessable_entity - end - end - - private - def pending_authentication_token_for(email_address) - Rails.application.message_verifier(:pending_authentication).generate(email_address, expires_in: 10.minutes) - end -end diff --git a/test/controllers/sessions/magic_links_controller_test.rb b/test/controllers/sessions/magic_links_controller_test.rb index 5a4a48e51..6d07a9c4a 100644 --- a/test/controllers/sessions/magic_links_controller_test.rb +++ b/test/controllers/sessions/magic_links_controller_test.rb @@ -79,4 +79,72 @@ class Sessions::MagicLinksControllerTest < ActionDispatch::IntegrationTest assert_response :redirect, "Expired magic link should redirect" assert MagicLink.exists?(expired_link.id), "Expired magic link should not be consumed" end + + test "create via JSON" do + identity = identities(:david) + magic_link = identity.send_magic_link + pending_token = pending_authentication_token_for(identity.email_address) + + untenanted do + post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: pending_token } + assert_response :success + assert @response.parsed_body["session_token"].present? + end + end + + test "create via JSON without pending_authentication_token" do + identity = identities(:david) + magic_link = identity.send_magic_link + + untenanted do + post session_magic_link_path(format: :json), params: { code: magic_link.code } + assert_response :unauthorized + assert_equal "Enter your email address to sign in.", @response.parsed_body["message"] + end + end + + test "create via JSON with invalid code" do + identity = identities(:david) + pending_token = pending_authentication_token_for(identity.email_address) + + untenanted do + post session_magic_link_path(format: :json), params: { code: "INVALID", pending_authentication_token: pending_token } + assert_response :unauthorized + assert_equal "Try another code.", @response.parsed_body["message"] + end + end + + test "create via JSON with cross-user code" do + identity = identities(:david) + other_identity = identities(:jason) + magic_link = other_identity.send_magic_link + pending_token = pending_authentication_token_for(identity.email_address) + + untenanted do + post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: pending_token } + assert_response :unauthorized + assert_equal "Something went wrong. Please try again.", @response.parsed_body["message"] + end + end + + test "create via JSON with expired pending_authentication_token" do + identity = identities(:david) + magic_link = identity.send_magic_link + + expired_token = nil + travel_to 15.minutes.ago do + expired_token = pending_authentication_token_for(identity.email_address) + end + + untenanted do + post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: expired_token } + assert_response :unauthorized + assert_equal "Enter your email address to sign in.", @response.parsed_body["message"] + end + end + + private + def pending_authentication_token_for(email_address) + Sessions::MagicLinksController.new.send(:pending_authentication_token_verifier).generate(email_address, expires_in: 10.minutes) + end end diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index 07c58ed74..1a0ddb061 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -86,4 +86,35 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest assert_not cookies[:session_token].present? end end + + test "create via JSON" do + untenanted do + post session_path(format: :json), params: { email_address: identities(:david).email_address } + assert_response :created + end + end + + test "create for a new user via JSON" do + new_email = "new-user-#{SecureRandom.hex(6)}@example.com" + + untenanted do + assert_difference -> { Identity.count }, 1 do + assert_difference -> { MagicLink.count }, 1 do + post session_path(format: :json), params: { email_address: new_email } + end + end + assert_response :created + assert @response.parsed_body["pending_authentication_token"].present? + assert MagicLink.last.for_sign_up? + end + end + + test "create with invalid email address via JSON" do + untenanted do + assert_no_difference -> { Identity.count } do + post session_path(format: :json), params: { email_address: "not-a-valid-email" } + end + assert_response :unprocessable_entity + end + end end