nginx Portier Authentication.
Handles all the Portier Relying Party (aka client side) work inside nginx
and the result is an nginx variable set to the users email address that can be added to an HTTP header or FCGI variable to the application being served for use as an external authenticator. Once authenticated, the user receives a session cookie that expires after 18 hours of inactivity.
Project sponsored by NetworkRADIUS.
You will require:
- nginx with Lua support, and your application running on it
apt-get -yy install --no-install-recommends \
ca-certificates \
libnginx-mod-http-lua \
lua-json \
lua-luaossl \
lua-nginx-dns \
lua-nginx-string \
nginx-full
The install process is pretty awful, mostly as everyone's application environment is a bit bespoke, but these guidelines below should get you moving:
- create a directory
/opt/portier/nginx
- copy all the
*.lua
files andnginx-env
from this project into it - symlink/copy
nginx.mod
to/etc/nginx/modules-enabled/99-portier-nginx.conf
- patch
/lib/systemd/system/nginx.service
withnginx-env-service.patch
- copy
webroot
from this project into it - inspect the sample
ngnix
configuration in the project- the portier-nginx parts are top-and-tailed with
####
- extract the
http { ... }
andserver { ... }
sections and graft them into your own nginx configuration - in the example
location / { ... }
shows how to usea.lua
with HTTP (settingX-Portier-Nginx-Email
) and FCGI (settingREMOTE_USER
) backends
- the portier-nginx parts are top-and-tailed with
- follow the configuration instructions below, typically requires editing
/opt/portier/nginx/nginx-env
- restart nginx
Hopefully everything starts up okay, and depending on how you reconciled the sample nginx
configuration with your existing one, when you open your application you should be directed to a login screen.
Type in your email address, walk through the authentication flow and you then should be able to access your application.
To logout, send the user to /.portier/logout
which will delete the cookie and redirect the user to /
.
Where environment variables are described, to update them edit /opt/portier/nginx/nginx-env
and run:
systemctl restart nginx
Edit webroot/index.html
to suit your cosmetic needs.
On errors, the user will be redirected to the login page, but in the fragment will be a the following query string encoded key value pairs:
email
: address suppliederror
: human readable message
You may wish to use these values to indicate why the email address supplied failed.
By default, the broker used is https://broker.portier.io
but this is can be overridden by setting the environment variable PORTIER_BROKER
to another URL.
By default, the nameservers used to assist in email address validation are Google's resolvers, but this can be overridden by setting the environment variable PORTIER_NAMESERVERS
to a whitespace seperated list of nameservers to use.
N.B. if you change this, you should also change resolver
in the nginx
configuration too
When you start nginx
you will see a warning in your error log similar to:
2018/08/03 14:46:58 [warn] 8659#8659: [lua] i.lua:51: using runtime secret
This is harmless, but will mean every time you reload nginx any currently authenticated users will be logged out. To prevent this you can set the secret to a static value with:
dd if=/dev/urandom of=/opt/portier/nginx/secret bs=1 count=16
chmod 640 /opt/portier/nginx/secret
chown root:www-data /opt/portier/nginx/secret
You may wish to test externally the email address if it is authorized to connect.
To do set the environment variable PORTIER_AUTHORIZE
; on how to use this you can inspect the provided examples (authz*.lua
).
If your function returns true
, authorization is considered successful. If you return false
then the user is rejected, though instead you can return a string instead and the value will be returned to the user to communicate the reason for the authorization failed (eg. expired account, time of day, ...).
If your function explodes, then authorization is considered failed and the user is shown the same message as if you returned false
.
Almost the easiest thing here is to slum it with a Docker container (sorry, it is awful) where you can run:
docker build -t portier-nginx .
docker run -it --rm -p 1080:80 portier-nginx
Now from within the container run:
/etc/init.d/nginx start
php -S 127.0.0.1:8000 -t /opt/portier/nginx/webroot
On your workstation, point your browser at http://localhost:1080 and type in your email address to start off the authentication. If it is successful, you should see the phpinfo()
splash screen and if you scroll down you should find $_SERVER['HTTP_X_PORTIER_NGINX_EMAIL']
is set to your email address.
After a successful authentication, portier-nginx sets the session cookie portier-nginx-email
and then uses that going forward. The cookie is made up of the tuple:
[hmac type]:[hmac truncated to 80bits]:[created time]:[email]
Currently md5
is used as the HMAC hash function, the HMAC is truncated to 80bits, and these cookies expire after 18 hours of inactivity (renewing on each request during their validity).
Each lua file servers a particular purpose: