Authorization in nginx on the basis of google one-time passwords.
For various reasons, I had to refuse to authorize auth_basic and the password file, non-secret and that's it.
It is a lot of users with a different level of knowledge, therefore authorization on certificates does not approach.
They suggested a solution based on Nginx (http_auth_request_module) + Apache (google-authenticator-apache-module).
')
Having picked up a few days he raised, but could not understand some of the points how to work. Having picked it up and figured it out.

The idea is as follows. Verification of authorization does not occur at the nginx itself but on the apache server. Nginx sends the auth_request subquery to the 'Authorization server' apache, if the authorization is passed, apache responds HTTP 200, and nginx happily thinks that the user is authorized.
How it works. On the 'Authorization Server', you create a file (file name - login) for each user that contains a certain secure key.
Without going into details, we assume that based on this secure key and the current time, on the server side and on the client side, one-time passwords are generated independently of each other every minute.
As an application generating passwords is used:
Google Authenticator for Android .
Google Authenticator for iOS .
If you do not have a phone, then there is an application under Windows:
Google Authenticator for Windows .
There is also under java ...
How to synchronize the application with the server a little later, and now what needs to be configured on the server.
Unfortunately, there is no module for Nginx and cannot be due to the peculiarities of the implementation of Nginx. Why can’t I say for sure, but I was told the words about state mashine and so on ... :)
But under the Apache module there !!! Called
google-authenticator-apache-moduleThere are also binary assemblies under centsOS 6 - it works checked. There are source codes and there is more fresh in repo. I played with the binary build and then assembled the module from the sources.
This means that on apache + google-authenticator-apache-module we make an “authorization server” (you can even have 2 servers for reliability) and connect Nginx_s to it on all servers where we need to.
So we take apache2, we collect or we take the google-authenticator-apache-module binary module.
and write this config:
Loadmodule authn_google_module modules/mod_authn_google.so Listen *:8888 <Location ~ "/(|_auth/)" > # Nginx_. :) Order deny,allow Deny from all Allow from 10.0.0.0/8 Allow from 192.168.0.0/24 AuthType Basic AuthName "My Closed Zone Gauth" AuthBasicProvider "google_authenticator" Require valid-user GoogleAuthUserPath /etc/httpd/ga_auth GoogleAuthCookieLife 600 GoogleAuthEntryWindow 3 # GoogleAuthLogLevel - . GoogleAuthLogLevel 1 </Location>
Restart apache, try opening it in the browser - is there an authorization request? Perfectly!!!
Farther…
/ etc / httpd / ga_auth - directory where the files with secret keys are located.
How and what to create them:
google-authenticatorWe download ,
libpam-google-authenticator , we collect we receive google-authenticator. Here it can generate what we need.
I made a script so that the file went right where necessary.
The script passes the user login parameter.
After working the script will create a file and output to the console:
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/zzzz@mydomain.auth%3Fsecret%3DQYYY34XXXX534A4QA Your new secret key is: DQYYY34XXXX534A4QA Your verification code is 123456 Your emergency scratch codes are: 99942105 28654999 45999608 33300650 99907825
There are a lot of different things in the / etc / httpd / ga_auth / _user_login_ file, but nothing affects the google-authenticator-apache-module operation except “Your new secret key is:”, at least I experimented - nothing ... so you can leave only the first line with QUCFKE6AK3PBA4QA or you can not touch the file.
Further we open the link
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/zzzz@mydomain.auth%3Fsecret%3DQYYY34XXXX534A4QA(link is intentionally curve)
and see

Install on your phone (if you have not yet installed)
Google Authenticator . We scan the QR code and the phone starts generating a one-time password every minute.
You can try to log in to apache, it should work, but it can give 404 - because after authorization, apache wants to show some kind of index.html and you may not have it.
By the way, the google-authenticator-apache-module module honestly writes in / var / log / httpd / error_log.
And so, we have an “authorization server” and a telephone — both generate the same sequence of one-time passwords.
Let's proceed to the nginx setup.
we take Nginx fresher, I took the last stable
1.5.7 , we collect the key moment with - with
-http_auth_request_module (http_auth_request_module).
auth_request_set $auth_cookie $upstream_http_set_cookie; add_header Set-Cookie $auth_cookie; location = /_auth/ { internal; proxy_pass http://gauth_pool/; proxy_pass_request_body off; proxy_buffering off; proxy_cache off; proxy_set_header Content-Length ""; proxy_set_header Host mydomain.com; }
I selected this piece of config in a separate file and will include it where needed.
in /etc/nginx/nginx.conf at the end we add a pool of apache + servers at least 2 for reliability:
upstream gauth_pool { server ga1.mydomain.com:8888 weight=1; server ga2.mydomain.com:8888 weight=5; }
now everywhere where necessary for Nginx add:
server { listen 443 ssl spdy;
Checking :)
/etc/nginx/allow_nets.txt - list of IPs that do not need to log in. I think no need to torment everyone with authorization.
Now the most interesting thing is the subtleties:
It all works as follows.
Logged in While you are working on the site is constantly checking your authorization by cookie
set-cookie: google_authn=user:1390714695:FRxZCSDzox/a5KEGXXXXXXX5TYGIYZrRf=
It is constantly updated, 1390714695 - the time when the cookie expires. It is constantly updated with the current time {{GoogleAuthCookieLife 600} from the apache config. You can say this is the time of inactivity on the page. gone for 10 minutes - log in again.
And the second moment. The one-time password you entered does not last forever. In general, the term is 1 minute and that's it. But using the parameter
GoogleAuthEntryWindow 3, you can push the "time window" of the password.
The point is that the google-authenticator-apache-module can generate, in addition to the current password, passwords before and after GoogleAuthEntryWindow, this is done so that if the clock on your mobile and the clock on the server do not match, you could still log in.
The same can be done so that your one-time password is longer passed the authorization, it will allow longer to keep the authorization "passed";
And finally, a piece of the log from apache:
[Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] **** COOKIE AUTH at T=1390714549, referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] Cookie auth is DECLINED, referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] **** PW AUTH at T=1390714549 user "my_user", referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] getUserSecret with username "my_user", referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] OPENING FILENAME /etc/httpd/ga_auth/my_user, referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] Comparing Authentication @ T=46017151 Code=475002 "332994" vs. "475002", referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] Comparing Authentication @ T=46017151 Code=87841 "332994" vs. "087841", referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] Comparing Authentication @ T=46017151 Code=627132 "332994" vs. "627132", referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] Comparing Authentication @ T=46017151 Code=332994 "332994" vs. "332994", referer: https://www.mydomain.com/ [Sun Jan 20 09:01:49 2014] [error] [client 1.2.3.4] Created cookie expires 1390715149 hash is sEFQLm92bSI= Cookie: google_authn=my_user:1390715149:sEFQLm92bSI=, referer: https://www.mydomain.com/
Gradually, or rather once a minute, type lines
Comparing Authentication @ T=46017151 Code=87841 "332994" vs.
will be reduced until there is only a line with your password, and a minute later - authorization by a new one.