Skip to content

Latest commit

 

History

History
126 lines (78 loc) · 6.54 KB

README.md

File metadata and controls

126 lines (78 loc) · 6.54 KB

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.

Pre-flight

You will require:

Debian

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

Deploy

The install process is pretty awful, mostly as everyone's application environment is a bit bespoke, but these guidelines below should get you moving:

  1. create a directory /opt/portier/nginx
  2. copy all the *.lua files and nginx-env from this project into it
  3. symlink/copy nginx.mod to /etc/nginx/modules-enabled/99-portier-nginx.conf
  4. patch /lib/systemd/system/nginx.service with nginx-env-service.patch
  5. copy webroot from this project into it
  6. inspect the sample ngnix configuration in the project
    • the portier-nginx parts are top-and-tailed with ####
    • extract the http { ... } and server { ... } sections and graft them into your own nginx configuration
    • in the example location / { ... } shows how to use a.lua with HTTP (setting X-Portier-Nginx-Email) and FCGI (setting REMOTE_USER) backends
  7. follow the configuration instructions below, typically requires editing /opt/portier/nginx/nginx-env
  8. 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 /.

Configuration

Where environment variables are described, to update them edit /opt/portier/nginx/nginx-env and run:

systemctl restart nginx

Login Page

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 supplied
  • error: human readable message

You may wish to use these values to indicate why the email address supplied failed.

Broker

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.

Nameservers

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

Runtime Secret

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

Authorization

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.

Development

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.

Functional Description

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:

  • i.lua: sets the global variables that will be used by all the workers; including the secret
  • a.lua: tests if the user has a valid portier-nginx-email cookie, if not it redirects them to login
  • l.lua: handles the email login flow
  • v.lua: validates the post back from the portier broker