• Stars
    star
    141
  • Rank 259,971 (Top 6 %)
  • Language
    Lua
  • License
    MIT License
  • Created over 10 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Lua module to add Google OAuth to nginx

nginx-google-oauth

Lua module to add Google OAuth to nginx.

Installation

You can copy access.lua to your nginx configurations, or clone the repository. Your installation of nginx must already be built with Lua support, and you will need the json and luasec modules as well.

Ubuntu

You will need to install the following packages.

lua5.1
liblua5.1-0
liblua5.1-0-dev
liblua5.1-sec-dev
liblua5.1-json

You will also need to download and build the following and link them with nginx

ngx_devel_kit
lua-nginx-module

See /chef/source-lua.rb for a Chef recipe to install nginx and Lua with all of the requirements.

Configuration

Add the access controls in your configuration. Because oauth tickets will be included in cookies (and you are presumably protecting something very important), it is strongly recommended that you use SSL.

server {
  server_name supersecret.net;
  listen 443;

  ssl on;
  ssl_certificate /etc/nginx/certs/supersecret.net.pem;
  ssl_certificate_key /etc/nginx/certs/supersecret.net.key;

  set $ngo_client_id "abc-def.apps.googleusercontent.com";
  set $ngo_client_secret "abcdefg-123-xyz";
  set $ngo_token_secret "a very long randomish string";
  set $ngo_secure_cookies "true";
  access_by_lua_file "/etc/nginx/nginx-google-oauth/access.lua";
}

The access controls can be configured using nginx variables. The supported variables are:

  • $ngo_client_id This is the client id key
  • $ngo_client_secret This is the client secret
  • $ngo_token_secret The key used to encrypt the session token stored in the user cookie. Should be long & unguessable.
  • $ngo_domain The domain to use for validating users when not using white- or blacklists
  • $ngo_whitelist Optional list of authorized email addresses
  • $ngo_blacklist Optional list of unauthorized email addresses
  • $ngo_callback_scheme The scheme for the callback URL, defaults to that of the request (e.g. https)
  • $ngo_callback_host The host for the callback, defaults to first entry in the server_name list (e.g supersecret.net)
  • $ngo_callback_uri The URI for the callback, defaults to "/_oauth"
  • $ngo_debug If defined, will enable debug logging through nginx error logger
  • $ngo_secure_cookies If defined, will ensure that cookies can only be transfered over a secure connection
  • $ngo_css An optional stylesheet to replace the default stylesheet when using the body_filter
  • $ngo_user If set, will be populated with the OAuth username returned from Google (portion left of '@' in email)
  • $ngo_email_as_user If set and $ngo_user is defined, username returned will be full email address

Configuring OAuth Access

Visit https://console.developers.google.com. If you're signed in to multiple Google accounts, be sure to switch to the one which you want to host the OAuth credentials (usually your company's Apps domain). This should match $ngo_domain (e.g. "yourcompany.com").

From the dashboard, create a new project. After selecting that project, you should see an "APIs & Auth" section in the left-hand navigation. Within that section, select "Credentials". This will present a page in which you can generate a Client ID and configure access. Choose "Web application" for the application type, and enter all origins and redirect URIs you plan to use.

In the "Authorized Javascript Origins" field, enter all the protocols and domains from which you plan to perform authorization (e.g. https://supersecret.net), separated by a newline.

In the "Authorized Redirect URI", enter all of the URLs which the Lua module will send to Google to redirect after the OAuth workflow has been completed. By default, this will be the protocol, server_name and /_oauth (e.g. https://supersecret.net/_oauth. You can override these defaults using the $ngo_callback_* settings.

After completing the form you will be presented with the Client ID and Client Secret which you can use to configure $ngo_client_id and $ngo_client_secret respectively.

If you need to further limit access within your organization, you can use $ngo_whitelist and/or $ngo_blacklist. Both should be formatted as a space-separated list of allowed (whitelist) or rejected (blacklist) email addresses. If either of these values are defined, the $ngo_domain will not be used for validating that the user is authorized to access the protected resource.

Body filter

If you want visual confirmation of successful authentication, you can use the body_filter.lua script to inject a header into your web application. Your nginx configuration should look something like this:

server {
  server_name supersecret.net;
  listen 443;

  set $ngo_client_id 'abc-def.apps.googleusercontent.com';
  set $ngo_client_secret 'abcdefg-123-xyz';
  set $ngo_token_secret 'a very long randomish string';
  access_by_lua_file "/etc/nginx/nginx-google-oauth/access.lua";

  location / {
    header_filter_by_lua "ngx.header.content_length = nil";
    body_filter_by_lua_file "/etc/nginx/nginx-google-oauth/body_filter.lua";

    proxy_set_header Accept-Encoding "";
    proxy_pass http://supersecret-backend;
  }
}

The header_filter_by_lua directive is required so that the content_length header returned by the backend is stripped and re-calculated after the body filter has been applied.

The Accept-Encoding directive is recommended in cases where the backend may be returning a gzipped document, in which case nginx will not decompress the document before sending it to the body filter.

The body_filter_by_lua_file directive causes all responses from the backend to be routed through a lua script that will inject a div just after the opening <body> element. The div will take the form of:

<div class="ngo_auth">
  <img src="google-oauth-profile-pic" />
  <span class="ngo_user">google-oauth-user-name</span>
  <span class="ngo_email">google-oauth-email</span>
  <a href="signout_uri">Signout</a>
</div>

If $ngo_css is defined, the default stylesheet will be overridden, otherwise the stylesheet will be:

<style>
  div.ngo_auth { width: 100%; background-color: #6199DF; color: white; padding: 0.5em 0em 0. 5em 2em; vertical-align: middle; margin: 0; }
  div.ngo_auth > img { width: auto; height: 2em; margin: 0 1em 0 0; padding: 0; }
  div.ngo_auth > span { color: white; }
  div.ngo_auth > span.ngo_user { font-weight: bold; margin-right: 1em; }
  div.ngo_auth > a { color: white; margin-left: 3em; }
</style>

The filter operates by performing a regular expression match on <body>, and so should act as a no-op for non-HTML content types. It may be necessary to use the body filter only on a subset of routes depending on your application.

Username variable

If you wish to pass the username returned from Google to an external FastCGI/UWSGI script, consider using the $ngo_user variable:

server {
  server_name supersecret.net;
  listen 443;

  ssl on;
  ssl_certificate /etc/nginx/certs/supersecret.net.pem;
  ssl_certificate_key /etc/nginx/certs/supersecret.net.key;

  set $ngo_client_id "abc-def.apps.googleusercontent.com";
  set $ngo_client_secret "abcdefg-123-xyz";
  set $ngo_token_secret "a very long randomish string";
  set $ngo_secure_cookies "true";
  access_by_lua_file "/etc/nginx/nginx-google-oauth/access.lua";

  set $ngo_user "[email protected]";

  include uwsgi_params;
  uwsgi_param REMOTE_USER $ngo_user;
  uwsgi_param AUTH_TYPE Basic;
  uwsgi_pass 127.0.0.1:3031;
}

If you wish the full email address returned from Google to be set as the username, set the $ngo_email_as_user variable to any non-empty value.

Development

See test/README.md.

Bug reports and pull requests are welcome.

It can be useful to turn off lua_code_cache while you're iterating.

Roadmap

  • Add support for non-blocking sockets in obtaining an auth token
  • Support auth token refresh and timeouts
  • Continue support for Ubuntu but make imports work on other platforms as well
  • 401 page that allows signing out and back in with a different account
  • whitelist and blacklist is checked on every request

Copyright

Copyright 2014 Aaron Westendorf

License

MIT

Thanks

This project wouldn't have gone beyond the idea stage without the excellent example provided by SeatGeek.

Thank you to @eschwim for some much-needed usability and security fixes.

More Repositories

1

leaderboard

Leaderboards backed by Redis in Ruby
Ruby
478
star
2

kairos

Python module for time series data in Redis and Mongo
Python
207
star
3

stache

mustache and handlebars template handling in Rails 3.x and Rails 4.x
Ruby
166
star
4

haigha

AMQP Python client
Python
161
star
5

leaderboard-python

Leaderboards backed by Redis in Python
Python
156
star
6

activity_feed

Activity feeds backed by Redis
Ruby
135
star
7

amico

Relationships (e.g. friendships) backed by Redis
Ruby
112
star
8

confirm-with-reveal

Replacement for window.confirm() using the Reveal modal popup plugin from ZURB Foundation.
CoffeeScript
50
star
9

bracket_tree

Tree-based Bracketing System
Ruby
49
star
10

tassadar

A Starcraft 2 replay parser written in pure Ruby
Ruby
44
star
11

torus

A service implementing the Carbon protocol and storing time series data using kairos
Python
42
star
12

chai

Mocking framework for Python
Python
40
star
13

oembedr

Lightweight, Flexible OEmbed Consumer Library
Ruby
37
star
14

php-leaderboard

Leaderboards backed by Redis in PHP
PHP
25
star
15

leaderboard-coffeescript

Leaderboards backed by Redis in CoffeeScript
CoffeeScript
24
star
16

java-leaderboard

Leaderboards backed by Redis in Java
Java
24
star
17

factory-worker

Factories for NodeJS
JavaScript
23
star
18

bnet_scraper

A Nokogiri-based scraper of Battle.net profiles. Currently this only includes Starcraft2.
Ruby
22
star
19

python-leaderboard

Leaderboards backed by Redis in Python
Python
21
star
20

halo-reach-api

Ruby gem for interacting with the Halo:Reach API
Ruby
15
star
21

soonatra

Sinatra application to show a “Coming Soon” page and collect emails.
Ruby
14
star
22

GWFSelect-for-jQuery-UI

Google WebFont selection drop-down widget for jQuery UI.
JavaScript
13
star
23

amico-python

Relationships (e.g. friendships) backed by Redis
Python
11
star
24

php-bracket_tree

Tree-based Bracketing System
PHP
10
star
25

strumbar

Strumbar is a wrapper around ActiveSupport::Notifications with preconfigurations for basic instrumentation to be sent to statsd.
Ruby
9
star
26

scala-leaderboard

Leaderboards backed by Redis in Scala
Scala
7
star
27

vindicia-api

A wrapper for creating queries to the Vindicia CashBox API
Ruby
7
star
28

windbag

Notification System for Rails 3.1+
Ruby
6
star
29

pyevent

Python extension module for Niels Provos' libevent
Python
6
star
30

node-amico

NodeJS port of amico (Relationships (e.g. friendships) backed by Redis) using CoffeeScript.
CoffeeScript
6
star
31

ventilation

Ruby
6
star
32

improved_logging

Adds improved logging capabilities to the ActiveSupport::BufferedLogger class
Ruby
5
star
33

bracketeer

BracketTree Visual Template Creator
Ruby
4
star
34

seed_list

Seed management for tournament brackets
Ruby
3
star
35

tassadar-server

A web service interface to the tassadar Starcraft 2 replay parser
Ruby
3
star
36

leaderboard_factory

Nice little package to help you with leaderboards when you need a lot of them.
Ruby
3
star
37

py-eventsocket

Python
3
star
38

notify-campfire-multi

Notify multiple campfire rooms from a post-commit svn hook
Ruby
2
star
39

silver_spoon

Entitlements in Redis
Ruby
2
star
40

mm_sortable_item

A tiny MongoMapper plugin to provide some basic list functionality.
Ruby
2
star
41

javascripto

Client-side Javascript Application Framework
Ruby
2
star
42

saltstack-sandbox

A Vagrant-based sandbox environment for experimenting with SaltStack
2
star
43

hydra-async-demo

This is a user facing tutorial that will help guide users through the usage of Hydra Studio to support an asynchronous multiplayer game.
C#
2
star
44

read-and-write-if-nil

Pass through the value of a block to a cache key if the value is nil when it's requested
Ruby
1
star
45

ruby-openid-oauth-hybrid

ruby-openid-2.1.2 with added support for the openid-oauth hybrid extention
Ruby
1
star
46

bcms_xml_data_feed

JavaScript
1
star
47

website-middleman

Company public site and blog, rendered to static files by Middleman.
SCSS
1
star
48

gondola

Ruby
1
star
49

seedlings

Simple seed data management
Ruby
1
star
50

bcms_twitter

Twitter integration for BrowserCMS
JavaScript
1
star
51

beta

Beta access restriction library
Ruby
1
star
52

test-runner-benchmark

Benchmarking your tests
Ruby
1
star
53

action-mailer-with-temporary-delivery-method

Send email using ActionMailer but without using the templates or changing your smtp_settings
Ruby
1
star