Page 1 of 1

Basic Authentication from FastCGI

Posted: Wed Feb 05, 2020 8:35 pm
by PeterH
So today I was doing a bit of custom code for a project and needed a way to authenticate less sensitive parts of a reverse proxy using only nginx and PB. I found the subrequest stuff quite interesting and got a bit curious if I could trigger the HTTP Basic Authentication features in the browser directly from my fastcgi-project.

A little Wikipedia later, and some (less than clever) googling on top of that, I found how easy this was:

Code: Select all

If Not InitCGI() Or Not ReadCGI()
  End
EndIf

If Not InitFastCGI(5600) ; Create the FastCGI program on port 5600
  End
EndIf

While WaitFastCGIRequest()
  If ReadCGI()
      WriteCGIHeader("Status", "401")
      WriteCGIHeader("WWW-Authenticate", "Basic realm=" + Chr(34) + "My Realm" + Chr(34), #PB_CGI_LastHeader)
  Endif
Wend
Then the nightmare started. I can't figure out how to read the input from the client/visitor. All documentation says that the "Client sends a request header containing 'Authorization: Basic XXXXXX', where XXXXXX is username:password in base64.", but I can't figure out how (or where) to read the "Authorization"-value from. Anyone? Feels like I'm halfway there, but still not.

And before anyone starts a discussion involving the method: Yes, I know that old classic basic authentication it not recommended nowadays. I still want to know how to do it.

Re: Basic Authentication from FastCGI

Posted: Thu Feb 06, 2020 12:44 am
by percy_b
Hi PeterH,

I am no expert on this subject, but I would imagine you might need a script on the server-side that reads a posted message. Assuming that the server is Apache and you are using PHP on the server-side, you might want to take a look at this:

https://www.php.net/apache_request_headers

Re: Basic Authentication from FastCGI

Posted: Thu Feb 06, 2020 4:03 pm
by PeterH
Just wanted to give an update on this.
The trick is simply to verify the auth from the same place that you send the 401. If an auth has been entered, the "Authorization"-header is passed on. There might be some conditions, and therefor I'm writing down my settings here.

In the server section inside my server configuration file in nginx, I have this line

Code: Select all

underscores_in_headers on;
Under each location that I want to be protected by my custom auth I have:

Code: Select all

auth_request /myownauth;
as well as

Code: Select all

proxy_set_header Authorization $http_authorization;
One of the location sections are:

Code: Select all

    location = /myownauth {
    internal;
    proxy_pass              https://127.0.0.1/anythingthatendswith.cgi; #this is for testing at the moment. Feel free to change the location ~\.cgi$
    proxy_pass_request_body off;
    proxy_set_header        Content-Length "";
    proxy_set_header        X-Original-URI $request_uri;
    proxy_set_header        Authorization $http_authorization;
    proxy_pass_header       Authorization;
    }
The actual fastcgi section:

Code: Select all

    location ~ \.cgi$ {
    include /etc/nginx/fastcgi_params;
      fastcgi_pass  127.0.0.1:5555;  #5555 is my fast cgi port, only accessible locally for the local machine
      fastcgi_pass_header Authorization; #one of the tests, unsure if necessary to be honest
    }
And finally in my fastcgi_params I have this line added at the end:

Code: Select all

fastcgi_param  AUTHORIZATION $http_authorization;
I don't have the time to test out what actually made it work, but currently I can access the Authorize-header using both of these lines:

Code: Select all

CGIVariable("HTTP_AUTHORIZATION")
CGIVariable("AUTHORIZATION")
Hope it helps someone. The resulting line for the username "test" and the password "test" (both without quotes) is:

Code: Select all

Basic dGVzdDp0ZXN0
"Basic" is the authentication type and the rest is "test:test" (without quotes) with base64-encoding. Hence you can't have a colon in your username, but as part of the password it works fine. This is not an implementation issue but according to the RFC.

An example FastCGI that shows "Authorization" header contents in the console output of the fastcgi-process:

Code: Select all

If Not InitCGI() Or Not ReadCGI()
  End
EndIf

If Not InitFastCGI(5555) ; Create the FastCGI program on port 5555
EndIf

While WaitFastCGIRequest()
  If ReadCGI()

    PrintN("Authorization1: " + CGIVariable("HTTP_AUTHORIZATION"))
    PrintN("Authorization2: " + CGIVariable("AUTHORIZATION"))
    ;Check the login etc here, custom session stuff if wanted, and if not valid run the following two lines:
    WriteCGIHeader("Status", "401")
    WriteCGIHeader("WWW-Authenticate", "Basic realm=" + Chr(34) + "My cool realm" + Chr(34), #PB_CGI_LastHeader)

  EndIf
Wend
The realm is not absolutely necessary.
Cheers!