Clean up forward auth caching: remove duplication, fix rate limiting, and plug cache gaps

- Remove duplicated app_allows_user_cached?/headers_for_user_cached methods; call model methods directly
- Fix sliding-window rate limit bug by using increment instead of write (avoids TTL reset)
- Use cached app lookup in validate_redirect_url instead of hitting DB on every unauthorized request
- Add cache busting to ApplicationGroup so group assignment changes invalidate the cache
- Eager-load user groups (includes(user: :groups)) to eliminate N+1 queries
- Replace pluck(:name) with map(&:name) to use already-loaded associations
- Remove hardcoded fallback domain, dead methods, and unnecessary comments
- Fix test indentation and make group-order assertions deterministic

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dan Milne
2026-03-21 23:54:19 +11:00
parent 5505f99287
commit 6844c5fab3
5 changed files with 36 additions and 138 deletions

View File

@@ -9,7 +9,7 @@ module Api
@group = groups(:admin_group)
@rule = Application.create!(name: "Test App", slug: "test-app", app_type: "forward_auth", domain_pattern: "test.example.com", active: true)
@inactive_rule = Application.create!(name: "Inactive App", slug: "inactive-app", app_type: "forward_auth", domain_pattern: "inactive.example.com", active: false)
end
end
# Authentication Tests
test "should redirect to login when no session cookie" do

View File

@@ -130,7 +130,9 @@ class ForwardAuthIntegrationTest < ActionDispatch::IntegrationTest
# Rails normalizes header keys to lowercase
assert_equal @user.email_address, response.headers["x-remote-user"]
assert response.headers.key?("x-remote-groups")
assert_equal "Group Two,Group One", response.headers["x-remote-groups"]
groups_in_header = response.headers["x-remote-groups"].split(",").sort
expected_groups = @user.groups.reload.map(&:name).sort
assert_equal expected_groups, groups_in_header
# Test custom headers
get "/api/verify", headers: {"X-Forwarded-Host" => "custom.example.com"}
@@ -138,7 +140,7 @@ class ForwardAuthIntegrationTest < ActionDispatch::IntegrationTest
# Custom headers are also normalized to lowercase
assert_equal @user.email_address, response.headers["x-webauth-user"]
assert response.headers.key?("x-webauth-roles")
assert_equal "Group Two,Group One", response.headers["x-webauth-roles"]
assert_equal expected_groups, response.headers["x-webauth-roles"].split(",").sort
# Test no headers
get "/api/verify", headers: {"X-Forwarded-Host" => "noheaders.example.com"}