How to return a cookie to a client when auth_request is used?

Hi,

Question 1:

I would like to have an FastCGI authentication app assign a cookie to a
client, and the Fast Auth app is called using auth_request. The steps
are as
follows:

  1. Client sends a request
  2. NGINX auth_request forwards the request to a FastCGI app to
    authenticate.
  3. The authentication FastCGI app creates a cookie, using “Set-Cookie:
    name=value”. I would like this value to be returned to the client.
  4. Assuming the authentication was successful, NGINX then forwards the
    request to an upstream FastCGI app which sends a response to the client.
    The
    HTTP header should contain Set-Cookie: name=value

How do I get NGINX to include the cookie in the header that gets
forwarded
to the upstream module so the final response to the client contains the
cookie? I tried using auth_request_set but got

location / {

    auth_request /auth;
    include fastcgi_params;
    fastcgi_param  HTTP_COOKIE $http_cookie;
    #auth_request_set $http_cookie "test";  <======= I tried this 

just
to see how auth_request_set works. NGINX j

   fastcgi_pass   127.0.0.1:9000;
}

# new fastcgi to set the cookie
location /auth {
    include fastcgi_params;
    fastcgi_pass   127.0.0.1:9010;
}

Question 2. I also tried
auth_request_set $http_cookie “test”;
to see how auth_request_set works. NGINX gave me this error at
start
time

nginx: [emerg] the duplicate “http_cookie” variable in
/usr/local/nginx-1.7.9/conf/nginxWat.conf:25

Why did get such error?

Question 3. Can someone give me a pointer to a list of NGINX FastCGI
supported env variables such as $http_cookie / HTTP_COOKIE?

Thank you!

Posted at Nginx Forum:

Hello!

On Thu, Jan 15, 2015 at 03:11:23AM -0500, nginxuser100 wrote:

authenticate.
3. The authentication FastCGI app creates a cookie, using “Set-Cookie:
name=value”. I would like this value to be returned to the client.
4. Assuming the authentication was successful, NGINX then forwards the
request to an upstream FastCGI app which sends a response to the client. The
HTTP header should contain Set-Cookie: name=value

How do I get NGINX to include the cookie in the header that gets forwarded
to the upstream module so the final response to the client contains the
cookie? I tried using auth_request_set but got

You have to save the header value returned by the subrequest to a
variable with auth_request_set, and then add the header to a
response generated using the “add_header” directive. Something
like this should work:

location / {
    auth_request /auth;
    auth_request_set $saved_set_cookie $upstream_http_set_cookie;
    add_header Set-Cookie $saved_set_cookie;
    ...
}

[…]

Question 2. I also tried
auth_request_set $http_cookie “test”;
to see how auth_request_set works. NGINX gave me this error at start
time

nginx: [emerg] the duplicate “http_cookie” variable in
/usr/local/nginx-1.7.9/conf/nginxWat.conf:25

Why did get such error?

The $http_* variables are headers of a request, and you can’t
redefine them. Hence the error.

Question 3. Can someone give me a pointer to a list of NGINX FastCGI
supported env variables such as $http_cookie / HTTP_COOKIE?

All HTTP request headers are passed to FastCGI application as
HTTP_* params, and will be available to an application as
coresponding environment variables. Additional params are passed
as configured in your fastcgi_params file.


Maxim D.
http://nginx.org/

In case it will help someone else, the problem turned out to be in the
FastCGI auth server’s printf, the last “statement” of the HTTP header
should
end with \n\n instead of \r\n.

The following was wrong:
printf(“Content-type: text/html\n\n”
“Set-Cookie: name=AuthCookie\r\n”
“FastCGI 9010: Hello!\n”
…);

This did the trick:
printf(“Content-type: text/html\r\n”
“Set-Cookie: name=AuthCookie\n\n”
“FastCGI 9010: Hello!\n”
…);

Thank you!

Posted at Nginx Forum:

Thank you Maxim, it is much better in the sense that I am not getting an
error at NGINX start time, but the FastCGI back-end server listening at
port
9000 does not seem to get the cookie set by the FastCGI auth server, nor
any
data from a POST request body or data generated by FastCGI auth app.

On a separate note, GET request would get a response, but a POST request
would get an Internal error. Also, after a few successful GET requests,
I
sometimes would get an incomplete response, as if it was waiting for
some
input.
Any idea what I might be missing?

Note that I verified the auth fastcgi app on its own, and it printed the
cookie. I verified the fastcgi back-end server on its own, and it
returns a
complete POST response.

Below is the code and curl requests/responses. Thanks much!

http {
server {
listen 80;
server_name localhost;

location / {
    auth_request /auth;
    fastcgi_param  HTTP_COOKIE $http_cookie;
    include fastcgi_params;
    auth_request_set $saved_set_cookie $upstream_http_set_cookie;
    add_header Set-Cookie $saved_set_cookie;
    fastcgi_pass   127.0.0.1:9000;
}

location = /auth {
    include fastcgi_params;
    fastcgi_param  HTTP_COOKIE $http_cookie;
    fastcgi_pass   127.0.0.1:9010;
}

}
}

The FCGI auth server’s code sets the cookie as follows:

int main(int argc, char **argv) {
int count = 0;
while(FCGI_Accept() >= 0) {

printf(“Content-type: text/html\n\n”
“Set-Cookie: name=AuthCookie\r\n”
“FastCGI 9010:
Hello!\n”

FastCGI 9010: Hello!

\n”
“Request number %d running on host %s\n”,
++count, getenv(“SERVER_NAME”));

    /* code to print the env variables */
    ....

    FCGI_Finish();
}
return 0;

}


The FCGI back-end server’s code is as follows:

#include “fcgi_stdio.h”
#include <stdlib.h>

extern char **environ;

int main(int argc, char **argv) {
int count = 0;

while(FCGI_Accept() >= 0){
    char *contentLength = getenv("CONTENT_LENGTH");
    int packetRead = 0;
    int done = 0;
    int len;
    int idx;

    if (contentLength != NULL) {
        len = strtol(contentLength, NULL, 10);
    }
    else {
        len = 0;
    }

    /* Create a file to put output */
    FCGI_FILE * fileOut = FCGI_fopen("/tmp/fcgi.out", "w");
    if (fileOut) {
        while(done < len) {
            char buffer[1024];
            int i;

            packetRead = FCGI_fread(buffer, 1, sizeof(buffer), 

stdin);
if (packetRead < 0) {
break;
}
if (packetRead > 0) {
FCGI_fwrite(buffer, 1, packetRead, fileOut);
done += packetRead;
}

        }
        FCGI_fclose(fileOut);
    }

    printf("Content-type: text/html\n\n"
           "<html><head><title>FastCGI 9000: 

Hello!\n"

FastCGI 9000: Hello!

\n”
“Request number=%d lenrx=%d pktRead=%d uri=%s
reqMethod=%s
cookie=%s host= %s\n”,
++count, len, packetRead, getenv(“REQUEST_URI”),
getenv(“REQUEST_METHOD”), getenv(“HTTP_COOKIE”),
getenv(“SERVER_NAME”));

    /* Print the received environment variables */
    if ( !environ || environ[0] == NULL ){
        printf ("Null environment </body></html>\n");
        return 0;
    }
    for (idx = 0; environ[idx] != NULL; idx++)
    {
        printf("<h1>%s</h1>\n", environ[idx]);
    }
    printf ("</body></html>\n");

    FCGI_Finish();
}
return 0;

}


GET request/response, but no cookie in the response from the FastCGI
back-end server:

curl -v ‘http://localhost:80/

  • About to connect() to localhost port 80 (#0)
  • Trying ::1… Connection refused
  • Trying 127.0.0.1… connected
  • Connected to localhost (127.0.0.1) port 80 (#0)

GET / HTTP/1.1
User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7
NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: /

< HTTP/1.1 200 OK
< Server: nginx/1.7.9
< Date: Sun, 18 Jan 2015 17:20:23 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
<

FastCGI 9000: Hello!

FastCGI 9000: Hello!

Request number=2 lenrx=0 pktRead=0 uri=/ reqMethod=GET cookie= host= localhost

FCGI_ROLE=RESPONDER

HTTP_COOKIE=

QUERY_STRING=

REQUEST_METHOD=GET

CONTENT_TYPE=

CONTENT_LENGTH=

SCRIPT_NAME=/

REQUEST_URI=/

DOCUMENT_URI=/

DOCUMENT_ROOT=/usr/local/nginx-1.7.9/html

SERVER_PROTOCOL=HTTP/1.1

GATEWAY_INTERFACE=CGI/1.1

SERVER_SOFTWARE=nginx/1.7.9

REMOTE_ADDR=127.0.0.1

REMOTE_PORT=41122

SERVER_ADDR=127.0.0.1

SERVER_PORT=80

SERVER_NAME=localhost

REDIRECT_STATUS=200

HTTP_USER_AGENT=curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2

HTTP_HOST=localhost

HTTP_ACCEPT=*/*

* Connection #0 to host localhost left intact * Closing connection #0

POST request failure:

curl -d “name=Rafael%20Sagula&phone=3320780” -v ‘http://localhost:80/

  • About to connect() to localhost port 80 (#0)
  • Trying ::1… Connection refused
  • Trying 127.0.0.1… connected
  • Connected to localhost (127.0.0.1) port 80 (#0)

POST / HTTP/1.1
User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7
NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: /
Content-Length: 34
Content-Type: application/x-www-form-urlencoded

< HTTP/1.1 500 Internal Server Error
< Server: nginx/1.7.9
< Date: Sun, 18 Jan 2015 16:56:35 GMT
< Content-Type: text/html
< Content-Length: 192
< Connection: close
<

500 Internal Server Error

500 Internal Server Error


nginx/1.7.9 * Closing connection #0

A curl response that seems to be waiting for input:

curl -d “name=Rafael%20Sagula&phone=3320780” -v ‘http://localhost:80/

  • About to connect() to localhost port 80 (#0)
  • Trying ::1… Connection refused
  • Trying 127.0.0.1… connected
  • Connected to localhost (127.0.0.1) port 80 (#0)

POST / HTTP/1.1
User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7
NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: /
Content-Length: 34
Content-Type: application/x-www-form-urlencoded

^C

Posted at Nginx Forum: