Repository: caddyserver/caddy (language: go)

Issue:
forward_auth copy_headers must be case sensitive
Related docs: https://caddyserver.com/docs/caddyfile/directives/forward_auth#syntax

When using `forward_auth`, I noticed the `copy_headers` key accepts space-separated case-sensitive values. Should this config be case-insensitive? If so, I can help contribute to the docs.


Discussion / hints:
Hm, the implementation should probably be changed to be case-insensitive. I'll wait for @francislavoie to get back from his trip and see what his thoughts are!
We should probably reject any config that isn't canonical header names during Caddyfile adapt I think. But if someone uses the long-form, since it uses placeholders, we have no way to check that, really. The response headers are added to the replacer with Set() so there's no opportunity to transparently fix this (unless we change it to use replacer map, but then we'd need to make a copy of the response headers to avoid manipulations to the headers causing the placeholders to return the wrong thing)
I have to admit, "canonical form" is confusing with Http/2 and 3 where header names are serialized in lowercase. RFC 9110 doesn't really talk about canonicalization, it just says it's lowercase now: https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names

If we prefer to make them case-insensitive, can we make that work you think?
Well it doesn't need to be lowercase to be insensitive, you can just pass it through https://pkg.go.dev/net/textproto#CanonicalMIMEHeaderKey

What I'm trying to get at though is that doing that isn't completely trivial due to how the replacer works right now.

Fix patch:
diff --git a/modules/caddyhttp/reverseproxy/forwardauth/caddyfile.go b/modules/caddyhttp/reverseproxy/forwardauth/caddyfile.go
index a0b1f4213f2..cecc0001330 100644
--- a/modules/caddyhttp/reverseproxy/forwardauth/caddyfile.go
+++ b/modules/caddyhttp/reverseproxy/forwardauth/caddyfile.go
@@ -38,29 +38,28 @@ func init() {
 // configured for most™️ auth gateways that support forward auth. The typical
 // config which looks something like this:
 //
-//     forward_auth auth-gateway:9091 {
-//         uri /authenticate?redirect=https://auth.example.com
-//         copy_headers Remote-User Remote-Email
-//     }
+//	forward_auth auth-gateway:9091 {
+//	    uri /authenticate?redirect=https://auth.example.com
+//	    copy_headers Remote-User Remote-Email
+//	}
 //
 // is equivalent to a reverse_proxy directive like this:
 //
-//     reverse_proxy auth-gateway:9091 {
-//         method GET
-//         rewrite /authenticate?redirect=https://auth.example.com
+//	reverse_proxy auth-gateway:9091 {
+//	    method GET
+//	    rewrite /authenticate?redirect=https://auth.example.com
 //
-//         header_up X-Forwarded-Method {method}
-//         header_up X-Forwarded-Uri {uri}
-//
-//         @good status 2xx
-//         handle_response @good {
-//             request_header {
-//                 Remote-User {http.reverse_proxy.header.Remote-User}
-//                 Remote-Email {http.reverse_proxy.header.Remote-Email}
-//             }
-//         }
-//     }
+//	    header_up X-Forwarded-Method {method}
+//	    header_up X-Forwarded-Uri {uri}
 //
+//	    @good status 2xx
+//	    handle_response @good {
+//	        request_header {
+//	            Remote-User {http.reverse_proxy.header.Remote-User}
+//	            Remote-Email {http.reverse_proxy.header.Remote-Email}
+//	        }
+//	    }
+//	}
 func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
 	if !h.Next() {
 		return nil, h.ArgErr()
@@ -196,9 +195,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
 	// need at least one handler in the routes for the response handling
 	// logic in reverse_proxy to not skip this entry as empty.
 	for from, to := range headersToCopy {
-		handler.Request.Set[to] = []string{
-			"{http.reverse_proxy.header." + from + "}",
-		}
+		handler.Request.Set.Set(to, "{http.reverse_proxy.header."+http.CanonicalHeaderKey(from)+"}")
 	}
 
 	goodResponseHandler.Routes = append(


Test patch: