Tests now pass with local authentication

This is the first step of a multi-step SaaS engine extraction.

Looking ahead to an open source release, we need to make sure that
local authentication is treated as an "official" option, and not just
a hack I added for Kevin to do load testing outside our DC. So this PR
gets to green, and adds a CI step in "local authentication" mode.

This all probably feels a little hacky to you, Reader, but the goal of
this change is to ease the next step, which will be extracting the
37id and Queenbee integrations into a proprietary "SaaS mode" engine.

In service of that goal, this commit simply wraps all of the dependent
code and tests with a conditional check on
`config.x.local_authentication`.
This commit is contained in:
Mike Dalessio
2025-09-11 19:25:05 -04:00
parent 424edb6291
commit 8f39c015ea
24 changed files with 447 additions and 419 deletions
@@ -1,36 +1,34 @@
require "test_helper"
class ControllerAuthenticationTest < ActionDispatch::IntegrationTest
test "access without an account slug redirects to launchpad" do
integration_session.default_url_options[:script_name] = "" # no tenant
if Rails.application.config.x.local_authentication
test "access without an account slug redirects to new session" do
integration_session.default_url_options[:script_name] = "" # no tenant
get cards_path
assert_redirected_to Launchpad.login_url(product: true)
end
test "access with an account slug but no session redirects to launchpad" do
get cards_path
assert_redirected_to Launchpad.login_url(product: true, account: Account.sole)
end
test "local auth, access without an account slug redirects to launchpad" do
integration_session.default_url_options[:script_name] = "" # no tenant
with_local_auth do
get cards_path
assert_redirected_to new_session_path
end
assert_redirected_to Launchpad.login_url(product: true)
end
test "local auth, access with an account slug but no session redirects to new session" do
with_local_auth do
test "access with an account slug but no session redirects to new session" do
get cards_path
assert_redirected_to new_session_path
end
else
test "access without an account slug redirects to launchpad" do
integration_session.default_url_options[:script_name] = "" # no tenant
get cards_path
assert_redirected_to Launchpad.login_url(product: true)
end
assert_redirected_to new_session_path
test "access with an account slug but no session redirects to launchpad" do
get cards_path
assert_redirected_to Launchpad.login_url(product: true, account: Account.sole)
end
end
test "access with an account slug and a session allows functional access" do
@@ -1,38 +1,40 @@
require "test_helper"
class Sessions::LaunchpadControllerTest < ActionDispatch::IntegrationTest
test "show renders when not signed in" do
get session_launchpad_path(params: { sig: "test-sig" })
unless Rails.application.config.x.local_authentication
test "show renders when not signed in" do
get session_launchpad_path(params: { sig: "test-sig" })
assert_response :success
assert_response :success
assert_select "form input#sig" do |node|
assert_equal node.length, 1
assert_equal node.first["value"], "test-sig"
assert_select "form input#sig" do |node|
assert_equal node.length, 1
assert_equal node.first["value"], "test-sig"
end
end
test "create establishes a session when the sig is valid" do
user = users(:david)
put session_launchpad_path(params: { sig: user.signal_user.perishable_signature })
assert_redirected_to root_url
assert parsed_cookies.signed[:session_token]
end
test "create checks user.active?" do
user = users(:david)
user.update! active: false
put session_launchpad_path(params: { sig: user.signal_user.perishable_signature })
assert_response :unauthorized
end
test "returns 401 when the sig is invalid" do
put session_launchpad_path(params: { sig: "invalid" })
assert_response :unauthorized
end
end
test "create establishes a session when the sig is valid" do
user = users(:david)
put session_launchpad_path(params: { sig: user.signal_user.perishable_signature })
assert_redirected_to root_url
assert parsed_cookies.signed[:session_token]
end
test "create checks user.active?" do
user = users(:david)
user.update! active: false
put session_launchpad_path(params: { sig: user.signal_user.perishable_signature })
assert_response :unauthorized
end
test "returns 401 when the sig is invalid" do
put session_launchpad_path(params: { sig: "invalid" })
assert_response :unauthorized
end
end
+37 -43
View File
@@ -1,61 +1,55 @@
require "test_helper"
class SessionsControllerTest < ActionDispatch::IntegrationTest
test "destroy" do
sign_in_as :kevin
unless Rails.application.config.x.local_authentication
test "destroy" do
sign_in_as :kevin
delete session_path
assert_redirected_to Launchpad.logout_url
assert_not cookies[:session_token].present?
end
test "local auth, destroy" do
sign_in_as :kevin
with_local_auth do
delete session_path
assert_redirected_to Launchpad.logout_url
assert_not cookies[:session_token].present?
end
assert_redirected_to new_session_path
assert_not cookies[:session_token].present?
end
test "new" do
get new_session_path
assert_response :forbidden
end
test "local auth, new" do
with_local_auth do
test "new" do
get new_session_path
assert_response :forbidden
end
assert_response :success
end
test "create" do
post session_path, params: { email_address: "david@37signals.com", password: "secret123456" }
assert_response :forbidden
end
test "local auth, create with valid credentials" do
with_local_auth do
test "create" do
post session_path, params: { email_address: "david@37signals.com", password: "secret123456" }
assert_response :forbidden
end
else
test "destroy" do
sign_in_as :kevin
delete session_path
assert_redirected_to new_session_path
assert_not cookies[:session_token].present?
end
assert_redirected_to root_path
assert cookies[:session_token].present?
end
test "new" do
get new_session_path
test "local auth, create with invalid credentials" do
with_local_auth do
assert_response :success
end
test "create with valid credentials" do
post session_path, params: { email_address: "david@37signals.com", password: "secret123456" }
assert_redirected_to root_path
assert cookies[:session_token].present?
end
test "create with invalid credentials" do
post session_path, params: { email_address: "david@37signals.com", password: "wrong" }
end
assert_redirected_to new_session_path
assert_not cookies[:session_token].present?
assert_redirected_to new_session_path
assert_not cookies[:session_token].present?
end
end
end
@@ -1,103 +1,105 @@
require "test_helper"
class Signup::AccountsControllerTest < ActionDispatch::IntegrationTest
test "new under a tenanted URL redirects to the root" do
get new_signup_account_url
unless Rails.application.config.x.local_authentication
test "new under a tenanted URL redirects to the root" do
get new_signup_account_url
assert_redirected_to root_url
end
assert_redirected_to root_url
end
test "new under an untenanted URL is OK" do
integration_session.default_url_options[:script_name] = "" # no tenant
test "new under an untenanted URL is OK" do
integration_session.default_url_options[:script_name] = "" # no tenant
get new_signup_account_url, headers: auth_headers
get new_signup_account_url, headers: auth_headers
assert_response :success
end
assert_response :success
end
test "create with invalid params" do
integration_session.default_url_options[:script_name] = "" # no tenant
test "create with invalid params" do
integration_session.default_url_options[:script_name] = "" # no tenant
post signup_accounts_url,
headers: auth_headers,
params: { signup: { full_name: "Jim", email_address: "jim@example.com", password: "", company_name: "" } }
post signup_accounts_url,
headers: auth_headers,
params: { signup: { full_name: "Jim", email_address: "jim@example.com", password: "", company_name: "" } }
assert_response :unprocessable_entity
assert_select "div.alert--error", text: /you need to choose a password/i
end
assert_response :unprocessable_entity
assert_select "div.alert--error", text: /you need to choose a password/i
end
test "create for a new " do
integration_session.default_url_options[:script_name] = "" # no tenant
test "create for a new " do
integration_session.default_url_options[:script_name] = "" # no tenant
assert_difference -> { SignalId::Identity.count }, +1 do
assert_difference -> { SignalId::Account.count }, +1 do
post signup_accounts_url, headers: auth_headers,
params: {
signup: {
full_name: "Jim",
email_address: "jim@example.com",
password: SecureRandom.hex(12),
company_name: "signup-accounts-controller-test-1"
assert_difference -> { SignalId::Identity.count }, +1 do
assert_difference -> { SignalId::Account.count }, +1 do
post signup_accounts_url, headers: auth_headers,
params: {
signup: {
full_name: "Jim",
email_address: "jim@example.com",
password: SecureRandom.hex(12),
company_name: "signup-accounts-controller-test-1"
}
}
}
end
end
signal_account = SignalId::Account.last
assert_redirected_to(/#{signal_account.login_url}/)
end
test "create for an existing identity" do
integration_session.default_url_options[:script_name] = "" # no tenant
identity = signal_identities(:david)
post signup_accounts_url, headers: auth_headers,
params: { signup: { email_address: identity.email_address, company_name: "signup-accounts-controller-test-2" } }
assert_authentication_requested_for identity
assert_no_difference -> { SignalId::Identity.count } do
assert_difference -> { SignalId::Account.count } do
authenticate_via_launchpad_as(identity)
assert_redirected_to_account
assert_nil session[:signup]
end
end
signal_account = SignalId::Account.last
ApplicationRecord.with_tenant(signal_account.queenbee_id) do
assert_equal Account.last, signal_account.peer
end
end
signal_account = SignalId::Account.last
assert_redirected_to(/#{signal_account.login_url}/)
end
test "actions require HTTP basic authentication while we're in internal-only mode" do
integration_session.default_url_options[:script_name] = "" # no tenant
test "create for an existing identity" do
integration_session.default_url_options[:script_name] = "" # no tenant
get new_signup_account_url
identity = signal_identities(:david)
assert_response :unauthorized
end
post signup_accounts_url, headers: auth_headers,
params: { signup: { email_address: identity.email_address, company_name: "signup-accounts-controller-test-2" } }
assert_authentication_requested_for identity
assert_no_difference -> { SignalId::Identity.count } do
assert_difference -> { SignalId::Account.count } do
authenticate_via_launchpad_as(identity)
assert_redirected_to_account
assert_nil session[:signup]
private
def auth_headers
{ "HTTP_AUTHORIZATION" => ActionController::HttpAuthentication::Basic.encode_credentials("testname", "testpassword") }
end
end
signal_account = SignalId::Account.last
ApplicationRecord.with_tenant(signal_account.queenbee_id) do
assert_equal Account.last, signal_account.peer
end
def assert_authentication_requested_for(identity)
assert_response :redirect
assert_match(/#{Regexp.escape(Launchpad.url("/authenticate", login_hint: identity.email_address))}.*&purpose=signup/, redirect_to_url)
end
def authenticate_via_launchpad_as(identity)
get signup_session_url, headers: auth_headers, params: { sig: identity.perishable_signature }
assert_equal identity.id, session[:signup]["identity_id"]
assert_redirected_to new_signup_completion_url
post signup_completions_url, headers: auth_headers
end
def assert_redirected_to_account(signal_account = SignalId::Account.last)
assert_response :redirect
assert_match(/#{Regexp.escape(signal_account.url("/session/launchpad"))}.*&sig=/, redirect_to_url)
end
end
test "actions require HTTP basic authentication while we're in internal-only mode" do
integration_session.default_url_options[:script_name] = "" # no tenant
get new_signup_account_url
assert_response :unauthorized
end
private
def auth_headers
{ "HTTP_AUTHORIZATION" => ActionController::HttpAuthentication::Basic.encode_credentials("testname", "testpassword") }
end
def assert_authentication_requested_for(identity)
assert_response :redirect
assert_match(/#{Regexp.escape(Launchpad.url("/authenticate", login_hint: identity.email_address))}.*&purpose=signup/, redirect_to_url)
end
def authenticate_via_launchpad_as(identity)
get signup_session_url, headers: auth_headers, params: { sig: identity.perishable_signature }
assert_equal identity.id, session[:signup]["identity_id"]
assert_redirected_to new_signup_completion_url
post signup_completions_url, headers: auth_headers
end
def assert_redirected_to_account(signal_account = SignalId::Account.last)
assert_response :redirect
assert_match(/#{Regexp.escape(signal_account.url("/session/launchpad"))}.*&sig=/, redirect_to_url)
end
end