Files
clinch/test/controllers/api/forward_auth_controller_test.rb
Dan Milne d98f777e7d Refactor email delivery and background jobs system
- Switch from SolidQueue to async job processor for simpler background job handling
- Remove SolidQueue gem and related configuration files
- Add letter_opener gem for development email preview
- Fix invitation email template issues (invitation_login_token method and route helper)
- Configure SMTP settings via environment variables in application.rb
- Add email delivery configuration banner on admin users page
- Improve admin users page with inline action buttons and SMTP configuration warnings
- Update development and production environments to use async processor
- Add helper methods to detect SMTP configuration and filter out localhost settings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-26 16:30:02 +11:00

275 lines
8.9 KiB
Ruby

require "test_helper"
module Api
class ForwardAuthControllerTest < ActionDispatch::IntegrationTest
setup do
@user = users(:one)
@admin_user = users(:two)
@inactive_user = users(:three)
@group = groups(:one)
@rule = ForwardAuthRule.create!(domain_pattern: "test.example.com", active: true)
@inactive_rule = ForwardAuthRule.create!(domain_pattern: "inactive.example.com", active: false)
end
# Authentication Tests
test "should redirect to login when no session cookie" do
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 302
assert_match %r{/signin}, response.location
assert_equal "No session cookie", response.headers["X-Auth-Reason"]
end
test "should redirect when session cookie is invalid" do
get "/api/verify", headers: {
"X-Forwarded-Host" => "test.example.com",
"Cookie" => "_clinch_session_id=invalid_session_id"
}
assert_response 302
assert_match %r{/signin}, response.location
assert_equal "Invalid session", response.headers["X-Auth-Reason"]
end
test "should redirect when session is expired" do
expired_session = @user.sessions.create!(created_at: 1.year.ago)
get "/api/verify", headers: {
"X-Forwarded-Host" => "test.example.com",
"Cookie" => "_clinch_session_id=#{expired_session.id}"
}
assert_response 302
assert_match %r{/signin}, response.location
assert_equal "Session expired", response.headers["X-Auth-Reason"]
end
test "should redirect when user is inactive" do
sign_in_as(@inactive_user)
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 302
assert_equal "User account is not active", response.headers["X-Auth-Reason"]
end
test "should return 200 when user is authenticated" do
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 200
end
# Rule Matching Tests
test "should return 200 when matching rule exists" do
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 200
end
test "should return 200 with default headers when no rule matches" do
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "unknown.example.com" }
assert_response 200
assert_equal "X-Remote-User", response.headers["X-Remote-User"]
assert_equal @user.email_address, response.headers["X-Remote-User"]
end
test "should return 403 when rule exists but is inactive" do
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "inactive.example.com" }
assert_response 403
assert_equal "No authentication rule configured for this domain", response.headers["X-Auth-Reason"]
end
test "should return 403 when rule exists but user not in allowed groups" do
@rule.allowed_groups << @group
sign_in_as(@user) # User not in group
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 403
assert_match %r{permission to access this domain}, response.headers["X-Auth-Reason"]
end
test "should return 200 when user is in allowed groups" do
@rule.allowed_groups << @group
@user.groups << @group
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 200
end
# Domain Pattern Tests
test "should match wildcard domains correctly" do
wildcard_rule = ForwardAuthRule.create!(domain_pattern: "*.example.com", active: true)
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "app.example.com" }
assert_response 200
get "/api/verify", headers: { "X-Forwarded-Host" => "api.example.com" }
assert_response 200
get "/api/verify", headers: { "X-Forwarded-Host" => "other.com" }
assert_response 200 # Falls back to default behavior
end
test "should match exact domains correctly" do
exact_rule = ForwardAuthRule.create!(domain_pattern: "api.example.com", active: true)
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "api.example.com" }
assert_response 200
get "/api/verify", headers: { "X-Forwarded-Host" => "app.api.example.com" }
assert_response 200 # Falls back to default behavior
end
# Header Configuration Tests
test "should return default headers when rule has no custom config" do
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 200
assert_equal "X-Remote-User", response.headers.keys.find { |k| k.include?("User") }
assert_equal "X-Remote-Email", response.headers.keys.find { |k| k.include?("Email") }
assert_equal "X-Remote-Name", response.headers.keys.find { |k| k.include?("Name") }
assert_equal @user.email_address, response.headers["X-Remote-User"]
end
test "should return custom headers when configured" do
custom_rule = ForwardAuthRule.create!(
domain_pattern: "custom.example.com",
active: true,
headers_config: {
user: "X-WEBAUTH-USER",
email: "X-WEBAUTH-EMAIL",
groups: "X-WEBAUTH-ROLES"
}
)
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "custom.example.com" }
assert_response 200
assert_equal "X-WEBAUTH-USER", response.headers.keys.find { |k| k.include?("USER") }
assert_equal "X-WEBAUTH-EMAIL", response.headers.keys.find { |k| k.include?("EMAIL") }
assert_equal @user.email_address, response.headers["X-WEBAUTH-USER"]
end
test "should return no headers when all headers disabled" do
no_headers_rule = ForwardAuthRule.create!(
domain_pattern: "noheaders.example.com",
active: true,
headers_config: { user: "", email: "", name: "", groups: "", admin: "" }
)
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "noheaders.example.com" }
assert_response 200
auth_headers = response.headers.select { |k, v| k.match?(/^(X-|Remote-)/i) }
assert_empty auth_headers
end
test "should include groups header when user has groups" do
@user.groups << @group
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 200
assert_equal @group.name, response.headers["X-Remote-Groups"]
end
test "should not include groups header when user has no groups" do
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 200
assert_nil response.headers["X-Remote-Groups"]
end
test "should include admin header correctly" do
sign_in_as(@admin_user) # Assuming users(:two) is admin
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 200
assert_equal "true", response.headers["X-Remote-Admin"]
end
test "should include multiple groups when user has multiple groups" do
group2 = groups(:two)
@user.groups << @group
@user.groups << group2
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "test.example.com" }
assert_response 200
groups_header = response.headers["X-Remote-Groups"]
assert_includes groups_header, @group.name
assert_includes groups_header, group2.name
end
# Header Fallback Tests
test "should fall back to Host header when X-Forwarded-Host is missing" do
sign_in_as(@user)
get "/api/verify", headers: { "Host" => "test.example.com" }
assert_response 200
end
test "should handle requests without any host headers" do
sign_in_as(@user)
get "/api/verify"
assert_response 200
assert_equal "User #{@user.email_address} authenticated (no domain specified)",
request.env["action_dispatch.instance"].instance_variable_get(:@logged_messages)&.last
end
# Security Tests
test "should handle malformed session IDs gracefully" do
get "/api/verify", headers: {
"X-Forwarded-Host" => "test.example.com",
"Cookie" => "_clinch_session_id=malformed_session_id_with_special_chars!@#$%"
}
assert_response 302
assert_equal "Invalid session", response.headers["X-Auth-Reason"]
end
test "should handle very long domain names" do
long_domain = "a" * 250 + ".example.com"
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => long_domain }
assert_response 200 # Should fall back to default behavior
end
test "should handle case insensitive domain matching" do
sign_in_as(@user)
get "/api/verify", headers: { "X-Forwarded-Host" => "TEST.Example.COM" }
assert_response 200
end
end
end