Skip to content

Commit

Permalink
work in progress, added better log token, working on tests
Browse files Browse the repository at this point in the history
fixes auth0#45 bug fixes to build scripts, and vagrant provisioning
  • Loading branch information
Cody Lee committed Nov 11, 2015
1 parent 234cbe7 commit 72afb03
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 22 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,7 @@ npm-debug.log
*.lua.swp
lib/
nginx-jwt.tar.gz

# Intellij
.idea/
*.iml
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ Besides being able to install Docker and run Docker directly in the host OS, the
sudo ./build run
```

#### Ubuntu on MacOS (via Vagrant)
#### Vagrant

If your host OS is Mac OS but you'd like to test that the build scripts run on Ubuntu, you can use the provided Vagrant scripts to spin up an Ubuntu VM that has all the necessary tools installed.
If you'd like to test that the build scripts run on Ubuntu VM, you can use the provided Vagrant scripts to spin up an Ubuntu VM that has all the necessary tools installed.

First, if you haven't already, install **Vagrant** either by [installing the package](http://www.vagrantup.com/downloads.html) or using [Homebrew](http://sourabhbajaj.com/mac-setup/Vagrant/README.html).

Expand All @@ -229,7 +229,12 @@ And then SSH into it:
vagrant ssh
```

Once in, you'll need to use git to clone this repo and `cd` into the project:
If you're VM provider (ie Virtualbox) has guest additions installed, it will automatically mount the working directory to /vagrant.

Due to issues with security around synced folders and symlinks, most providers will explicitly prevent this so npm install will fail on tests. To get around this
if this folder was already mounted there should be a copy in ~/nginx-jwt already copied.

Otherwise you'll need to use git to clone this repo and `cd` into the project:

```bash
git clone THIS_REPO_URL
Expand Down
2 changes: 1 addition & 1 deletion hosts/proxy/base64-secret/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM proxy-base-image
FROM auth0/proxy-base-image

# secret is base-64 encoded and URL-safe
ENV JWT_SECRET="VGhpcyBzZWNyZXQgaXMgc3RvcmVkIGJhc2UtNjQgZW5jb2RlZCBvbiB0aGUgcHJveHkgaG9zdA"
Expand Down
2 changes: 1 addition & 1 deletion hosts/proxy/config-claim_specs-not-table/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM proxy-base-image
FROM auth0/proxy-base-image

ENV JWT_SECRET="JWTs are the best!"

Expand Down
2 changes: 1 addition & 1 deletion hosts/proxy/config-unsupported-claim-spec-type/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM proxy-base-image
FROM auth0/proxy-base-image

ENV JWT_SECRET="JWTs are the best!"

Expand Down
2 changes: 1 addition & 1 deletion hosts/proxy/default/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM proxy-base-image
FROM auth0/proxy-base-image

ENV JWT_SECRET="JWTs are the best!"

Expand Down
106 changes: 94 additions & 12 deletions nginx-jwt.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
local jwt = require "resty.jwt"
local cjson = require "cjson"
local basexx = require "basexx"

local logToken = os.getenv("LOG_TOKEN")
if logToken == nil then
logToken = false
else
logToken = string.lower(logToken)
if logToken == "true" or logToken == "1" then
logToken = true
else
logToken = false
end
end

local secret = os.getenv("JWT_SECRET")

local authHeader = os.getenv("AUTHORIZATION_HEADER")
if authHeader == "" or authHeader == nil then
authHeader = "Authorization"
end

local authTokenPrefix = os.getenv("AUTHORIZATION_PREFIX")

assert(secret ~= nil, "Environment variable JWT_SECRET not set")

if os.getenv("JWT_SECRET_IS_BASE64_ENCODED") == 'true' then
Expand All @@ -22,26 +42,37 @@ end

local M = {}

function M.auth(claim_specs)
function M.auth(claim_specs, header_specs)

-- require Authorization request header
local auth_header = ngx.var.http_Authorization
local auth_header = ngx.var[authHeader]

if auth_header == nil then
ngx.log(ngx.WARN, "No Authorization header")
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end

ngx.log(ngx.INFO, "Authorization: " .. auth_header)
if (log_token ~= false) then
ngx.log(ngx.INFO, "Authorization: " .. auth_header)
end

-- require Bearer token
local _, _, token = string.find(auth_header, "Bearer%s+(.+)")
local token;
if authTokenPrefix ~= nil then
local _
_, _, token = string.find(auth_header, authTokenPrefix .. "%s+(.+)")
else
token = auth_header
end

if token == nil then
ngx.log(ngx.WARN, "Missing token")
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end

ngx.log(ngx.INFO, "Token: " .. token)
if (logToken ~= false) then
ngx.log(ngx.INFO, "Token: " .. token)
end

-- require valid JWT
local jwt_obj = jwt:verify(secret, token, 0)
Expand All @@ -50,11 +81,12 @@ function M.auth(claim_specs)
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end

ngx.log(ngx.INFO, "JWT: " .. cjson.encode(jwt_obj))
if (logToken ~= false) then
ngx.log(ngx.INFO, "JWT: " .. cjson.encode(jwt_obj))
end

-- optionally require specific claims
if claim_specs ~= nil then
--TODO: test
-- make sure they passed a Table
if type(claim_specs) ~= 'table' then
ngx.log(ngx.STDERR, "Configuration error: claim_specs arg must be a table")
Expand All @@ -63,6 +95,7 @@ function M.auth(claim_specs)

-- process each claim
local blocking_claim = ""
local spec_actions
for claim, spec in pairs(claim_specs) do
-- make sure token actually contains the claim
local claim_value = jwt_obj.payload[claim]
Expand All @@ -71,7 +104,7 @@ function M.auth(claim_specs)
break
end

local spec_actions = {
spec_actions = spec_actions or {
-- claim spec is a string (pattern)
["string"] = function (pattern, val)
return string.match(val, pattern) ~= nil
Expand All @@ -91,9 +124,8 @@ function M.auth(claim_specs)
local spec_action = spec_actions[type(spec)]

-- make sure claim spec is a supported type
-- TODO: test
if spec_action == nil then
ngx.log(ngx.STDERR, "Configuration error: claim_specs arg claim '" .. claim .. "' must be a string or a table")
ngx.log(ngx.STDERR, "Configuration error: claim_specs arg claim '" .. claim .. "' must be a string or a function")
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end

Expand All @@ -110,8 +142,58 @@ function M.auth(claim_specs)
end
end

-- write the X-Auth-UserId header
ngx.header["X-Auth-UserId"] = jwt_obj.payload.sub
-- optionally add specific headers
if header_specs ~= nil then
-- make sure they passed a Table
if type(header_specs) ~= 'table' then
ngx.log(ngx.STDERR, "Configuration error: header_specs arg must be a table")
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end

local blocking_claim = ""
local spec_actions
for claim, spec in pairs(header_specs) do
-- make sure token actually contains the claim
local claim_value = jwt_obj.payload[claim]
if claim_value == nil then
blocking_claim = claim .. " (missing)"
break
end

spec_actions = spec_actions or {
-- claim spec is a string
["string"] = function (header, val)
return header;
end,

-- claim spec is a predicate function
["function"] = function (func, val)
return func(val)
end
}

local spec_action = spec_actions[type(spec)]

-- make sure claim spec is a supported type
if spec_action == nil then
ngx.log(ngx.STDERR, "Configuration error: header_specs arg header '" .. claim .. "' must be a string or a function")
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end

-- make sure token claim value satisfies the claim spec
local header = spec_action(spec, claim_value)
if not header then
blocking_claim = claim
break
end
ngx.header[header] = claim_value
end

if blocking_claim ~= "" then
ngx.log(ngx.WARN, "User did not satisfy claim: ".. blocking_claim)
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
end
end

function M.table_contains(table, item)
Expand Down
13 changes: 11 additions & 2 deletions provision-vagrant.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,22 @@ apt-get update
apt-get install -y make g++ curl git vim nfs-common portmap build-essential libssl-dev

# Install Node.js
curl --silent --location https://deb.nodesource.com/setup_0.12 | sudo bash -
#curl --silent --location https://deb.nodesource.com/setup_0.12 | sudo bash -
curl --silent --location https://deb.nodesource.com/setup_5.x | sudo bash -
apt-get install --yes nodejs

# Install Docker
curl -sSL https://get.docker.com/ubuntu | sh
curl -sSL https://get.docker.com/ | sh

usermod -aG docker vagrant

# Vim settings:
echo 'syntax on' > /home/vagrant/.vimrc

touch /etc/vagrant-provisioned

# If your VM provider auto-mounted the current directory under /vagrant, simply copy a copy to prevent npm symlink issues
if [ -e "/vagrant/build" ];
then
cp -R /vagrant nginx-jwt
fi
3 changes: 2 additions & 1 deletion scripts/build_proxy_base_image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ image_exists=$(docker images | grep "proxy-base-image\s*$dockerfile_sha1") || tr

if [ -z "$image_exists" ]; then
echo -e "${blue}Building image${no_color}"
docker build -t="proxy-base-image:$dockerfile_sha1" --force-rm $proxy_base_dir
docker build -t="auth0/proxy-base-image:$dockerfile_sha1" --force-rm $proxy_base_dir
docker tag "auth0/proxy-base-image:$dockerfile_sha1" "auth0/proxy-base-image:latest"
else
echo -e "${blue}Base image already exists${no_color}"
fi

0 comments on commit 72afb03

Please sign in to comment.