Rewriting the domain part of Set-Cookie in a proxy_pass

Hello

Does nginx (or a module) provide functionality equivalent to httpd’s
ProxyPassReverseCookieDomain?

Long explanation: I have a simple nginx reverse proxy

server {
server_name external.domain.com;
location / {
proxy_pass http://backend.int/;
}
}

The problem is that Set-Cookie response headers contain
“;Domain=backend.int”, because the backend does not know it is being
reverse proxied. Therefore the users’ browsers dutifully reject such bad
cookies.

How can I rewrite the content of the Set-Cookie response headers,
replacing “;Domain=backend.int” with “;Domain=external.domain.com”?

Unfortunately passing the Host header unchanged and reconfiguring the
virtual host table of the backend is not an option in this case.

Best,
Tobia

Posted at Nginx Forum:

On 8 Jun 2011 14h16 WEST, [email protected] wrote:

proxy_pass http://backend.int/;
}
}

The problem is that Set-Cookie response headers contain
“;Domain=backend.int”, because the backend does not know it is being
reverse proxied. Therefore the users’ browsers dutifully reject such
bad cookies.

How can I rewrite the content of the Set-Cookie response headers,
replacing “;Domain=backend.int” with “;Domain=external.domain.com”?

AFAIK you’ll need to use 3rd party modules. Either
Headers More | NGINX and/or
http://github.com/chaoslawful/lua-nginx-module

Probably the Embedded Perl module let’s you do that also. You’ll have to
try it out.

— appa

António P. P. Almeida Wrote:

How can I rewrite the content of the Set-Cookie
response headers, replacing “;Domain=backend.int”
with “;Domain=external.domain.com”?

AFAIK you’ll need to use 3rd party modules. Either
Headers More | NGINX and/or
http://github.com/chaoslawful/lua-nginx-module

Probably the Embedded Perl module let’s you do
that also. You’ll have to try it out.

Thanks for the pointers.

HttpHeadersMoreModule doesn’t seem to let me replace parts of headers.

Lua doesn’t seem to have it either:

Reading values from ngx.header.HEADER is not
implemented yet, and usually you shouldn’t need it.

That leaves me with the Perl module…

Tobia

Posted at Nginx Forum:

I wrote:

That leaves me with the Perl module…

…which apparently cannot do it either: you can only set response
headers from scratch.

$r->header_out(header, value) - set a response header.

Does anybody have any idea?

Tobia

Posted at Nginx Forum:

Hello!

On Wed, Jun 08, 2011 at 10:06:59AM -0400, tobia wrote:

I wrote:

That leaves me with the Perl module…

…which apparently cannot do it either: you can only set response
headers from scratch.

$r->header_out(header, value) - set a response header.

Does anybody have any idea?

You may get upstream response header via $upstream_http_*
variable, and set one (rewritten with perl_set) with add_header
directive.

The problem is still here though: you can’t iterate over multiple
Set-Cookie headers if there are more than one present in upstream
response.

Maxim D.

On Wed, Jun 8, 2011 at 3:02 PM, tobia [email protected] wrote:

that also. You’ll have to try it out.

Thanks for the pointers.

HttpHeadersMoreModule doesn’t seem to let me replace parts of headers.

Lua doesn’t seem to have it either:

Reading values from ngx.header.HEADER is not
implemented yet, and usually you shouldn’t need it.

I think you need to read the headers you get back from ngx.location.capture
in Lua (retrieve the backend response), then set the outbound headers
with
ngx.HEADER, so you should be able to do this in Lua.

So your content_by_lua block calls ngx.location.capture to get the
backend
response, reads the headers it gets from there, then sets the outbound
headers…

Justin

On Thu, Jun 9, 2011 at 3:30 AM, 杨镭 [email protected] wrote:

I am curious when there is an output_by_lua/output_by_luafle directive in
nginx-lua module.

We will probably have header_filter_by_lua and body_filter_by_lua
directives by this Christmas :wink:

For simplicity, I’ll just borrow the mechanism used by
set_by_lua(_file) and disable subrequest support like
ngx.location.capture() in lua output filters.

Currently, if one want to set/modify response header, the
only possible way is to do a subrequest using ngx.capture.
I think this is really cumbersome compared to declarative configuration such
as: output_by_lua_file.

Agreed :slight_smile:

Regards,
-agentzh

I am curious when there is an output_by_lua/output_by_luafle directive
in
nginx-lua module. Currently, if one want to set/modify response header,
the
only possible way is to do a subrequest using ngx.capture.

I think this is really cumbersome compared to declarative configuration
such
as: output_by_lua_file.

cc’ed agentzh

On Wed, Jun 8, 2011 at 10:17 PM, Justin Cormack <

agentzh wrote:

We will probably have header_filter_by_lua and
body_filter_by_lua directives by this Christmas :wink:

That will be great.

I still think Nginx should have plain C equivalents to Apache’s
ProxyPassReverseCookieDomain and ProxyPassReverseCookiePath. It’s a
problem that comes up fairly often when proxying legacy servers.

Nginx could even do it by default, when there is a proxy_pass with a
path component (which means: “process the request host and path”, as
opposed to a proxy_pass without trailing slash, which means “pass the
request unprocessed”)

What do you think?

Tobia

Posted at Nginx Forum:

On Wed, Jun 8, 2011 at 9:16 PM, tobia [email protected] wrote:

}

The problem is that Set-Cookie response headers contain
“;Domain=backend.int”, because the backend does not know it is being
reverse proxied. Therefore the users’ browsers dutifully reject such bad
cookies.

How can I rewrite the content of the Set-Cookie response headers,
replacing “;Domain=backend.int” with “;Domain=external.domain.com”?

Now with the latest ngx_lua v0.3.1rc3, we can implement this with a
little inlined Lua in nginx.conf:

server_name external.domain.com;

location / {
    proxy_pass http://backend.int/;

    header_filter_by_lua '
        local cookies = ngx.header.set_cookie
        if not cookies then return end
        local newcookies = {}
        for i, val in ipairs(cookies) do
            local newval = string.gsub(val, 

“([dD]omain)=[%w_-\\.]+”,
“%1=external.domain.com”)
table.insert(newcookies, newval)
end
ngx.header.set_cookie = newcookies
';
}

We can surely make this more portable by avoiding hard-coding the
external.domain.com” literal in our Lua code and reference
ngx.var.server_name (i.e., the nginx variable $server_name) instead :wink:

See the ngx_lua documentation for more details:

http://wiki.nginx.org/HttpLuaModule

The most relevant sections are

http://wiki.nginx.org/HttpLuaModule#header_filter_by_lua

and

http://wiki.nginx.org/HttpLuaModule#ngx.header.HEADER

Have fun!
-agentzh

On Wed, Sep 14, 2011 at 4:49 PM, agentzh [email protected] wrote:

server_name external.domain.com;

location / {
proxy_pass http://backend.int/;

header_filter_by_lua ’
local cookies = ngx.header.set_cookie
if not cookies then return end

Sorry, one line of Lua should be inserted right here for the case of a
single Set-Cookie response header:

        if type(cookies) ~= "table" then cookies = {cookies} end

that is, ngx.header.set_cookie will just return a single Lua string
instead of a Lua table if there’s only one Set-Cookie header.

Regards,
-agentzh