Module: Configuring upstream params (eg fastcgi_param) per request

I’m working on an authentication module for nginx, namely the Shibboleth
auth module (GitHub - nginx-shib/nginx-http-shibboleth: Shibboleth auth request module for nginx). This
module is based off the core nginx auth_request module
(https://github.com/nginx/nginx/blob/master/src/http/modules/ngx_http_auth_request_module.c).
The original module allows a sub-request to determine whether to grant
or
deny access to a nginx location; the Shibboleth module works in the same
way, but copies specific headers (in the format “Variable-[Field-name]”)
from the auth sub-response into the original parent request so that they
are
sent to the upstream application.

As it stands, the Shibboleth module can copy these variables
automatically
as headers, by iterating across all headers_out in the auth
sub-response,
testing for the Variable- string prefix, and then copying the values
into
the parent request’s headers_in (see
https://github.com/nginx-shib/nginx-http-shibboleth/blob/development/ngx_http_shibboleth_module.c#L299).
This works well but care needs to be exercised to avoid spoofing.

What I’d like to do is allow the same automated copying of
Variable-[Field-name] headers from the sub-response’s headers_out
into
relevant environment parameters (eg fastcgi_param, uwsgi_param etc) for
upstreams that support this.

I can achieve the desired result with manual use of shib_request_set
(identical to auth_request_set, which sets nginx variables from the auth
request response), like so:

location / {
shib_request_set $shib_auth_type $upstream_http_variable_auth_type;
fastcgi_param Auth-Type $shib_auth_type;
fastcgi_pass localhost:8000;
}

which sets $shib_auth_type to the value of header
Variable-Auth-Type,
and then sets the FastCGI param Auth-Type to the given value. The
drawback is that this requires manual configuration for all potential
Variable- prefixed headers (dozens or more are possible at times), and
also different directives for each type of upstream (fastcgi_param,
uwsgi_param, scgi_param etc).

So, is it possible to set an upstream’s parameters dynamically from my
module’s request handler (eg in the ngx_http_auth_request_handler
function)
or another part of the module (eg a filter)?

Looking at the fastcgi, scgi and uwsgi modules in nginx, they have
different
(but similar) implementations and upstreams such as proxy_pass don’t
support
environment parameters. So if this is possible, I’d envisage that my
module
would need to be aware of how the different upstreams’ params are
configured. My manual config solution might already be best, but I
wanted
to ask the question all the same.

Thanks!

Posted at Nginx Forum:

Anyone have any thoughts? Even if it’s just to say “this isn’t
possible”.

Cheers,
David

Posted at Nginx Forum:

Hello!

On Thu, Jun 02, 2016 at 12:05:17AM -0400, davidjb wrote:

Anyone have any thoughts? Even if it’s just to say “this isn’t possible”.

When working with multiple servers within a single upstream{}
block, nginx creates a request only once. If a server fails,
nginx will re-try the same request to a different server. So it’s
not possible to supply different parameters for different servers -
because the request is already created.

If you want to send different requests, you have to use other
mechanisms available in nginx, such as error_page fallback. Then
it will be possible to create another request with different
headers / FastCGI parameters.


Maxim D.
http://nginx.org/