From 74b1cf1a9dc20634b033f3aeab83aa8788b4b21a Mon Sep 17 00:00:00 2001 From: "hardy.mansen@unibet.com" Date: Thu, 26 Nov 2015 20:09:41 +0100 Subject: [PATCH 1/4] rfc6750 compability --- nginx-jwt.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/nginx-jwt.lua b/nginx-jwt.lua index 482765a..30388c7 100644 --- a/nginx-jwt.lua +++ b/nginx-jwt.lua @@ -28,6 +28,7 @@ function M.auth(claim_specs) if auth_header == nil then ngx.log(ngx.WARN, "No Authorization header") + ngx.header["WWW-Authenticate"] = 'Bearer' ngx.exit(ngx.HTTP_UNAUTHORIZED) end @@ -38,6 +39,7 @@ function M.auth(claim_specs) if token == nil then ngx.log(ngx.WARN, "Missing token") + ngx.header["WWW-Authenticate"] = 'Bearer' ngx.exit(ngx.HTTP_UNAUTHORIZED) end @@ -47,6 +49,7 @@ function M.auth(claim_specs) local jwt_obj = jwt:verify(secret, token, 0) if jwt_obj.verified == false then ngx.log(ngx.WARN, "Invalid token: ".. jwt_obj.reason) + ngx.header["WWW-Authenticate"] = 'Bearer error="invalid_token"' ngx.exit(ngx.HTTP_UNAUTHORIZED) end @@ -63,6 +66,7 @@ function M.auth(claim_specs) -- process each claim local blocking_claim = "" + local blocking_spec = "" for claim, spec in pairs(claim_specs) do -- make sure token actually contains the claim local claim_value = jwt_obj.payload[claim] @@ -100,12 +104,20 @@ function M.auth(claim_specs) -- make sure token claim value satisfies the claim spec if not spec_action(spec, claim_value) then blocking_claim = claim + blocking_spec = spec break end end if blocking_claim ~= "" then ngx.log(ngx.WARN, "User did not satisfy claim: ".. blocking_claim) + + -- https://tools.ietf.org/html/rfc6750#section-3.1 + if blocking_claim == "scope" then + ngx.header["WWW-Authenticate"] = 'Bearer error="insufficient_scope",' .. blocking_claim .. '=' .. blocking_spec + ngx.exit(ngx.HTTP_FORBIDDEN) + end + ngx.header["WWW-Authenticate"] = 'Bearer' ngx.exit(ngx.HTTP_UNAUTHORIZED) end end From a0c329f6f399fde3dea46516be0b02cf7eec2a47 Mon Sep 17 00:00:00 2001 From: "hardy.mansen@unibet.com" Date: Tue, 1 Dec 2015 09:55:31 +0100 Subject: [PATCH 2/4] tests cases for rfc6750 --- hosts/proxy/default/nginx/conf/nginx.conf | 1 + test/test_integration.js | 25 ++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/hosts/proxy/default/nginx/conf/nginx.conf b/hosts/proxy/default/nginx/conf/nginx.conf index f3714d0..c0edc50 100644 --- a/hosts/proxy/default/nginx/conf/nginx.conf +++ b/hosts/proxy/default/nginx/conf/nginx.conf @@ -29,6 +29,7 @@ http { local jwt = require("nginx-jwt") jwt.auth({ aud="^foo:", + scope="admin", roles=function (val) return jwt.table_contains(val, "marketing") end }) '; diff --git a/test/test_integration.js b/test/test_integration.js index c30081c..0a6a278 100644 --- a/test/test_integration.js +++ b/test/test_integration.js @@ -78,6 +78,7 @@ describe('proxy', function () { return request(url) .get('/secure') .expect(401) + .expect('WWW-Authenticate', 'Bearer') .end(); }); @@ -86,6 +87,7 @@ describe('proxy', function () { .get('/secure') .headers({'Authorization': 'Bearer not-a-valid-jwt'}) .expect(401) + .expect('WWW-Authenticate', 'Bearer error="invalid_token"') .end(); }); @@ -110,39 +112,56 @@ describe('proxy', function () { it("should return 401 when an authenticated user is missing a required claim", function () { var token = jwt.sign( // roles claim missing - { sub: 'foo-user', aud: 'foo1:bar' }, + { sub: 'foo-user', aud: 'foo1:bar', scope: 'admin' }, secret); return request(url) .get('/secure/admin') .headers({'Authorization': 'Bearer ' + token}) .expect(401) + .expect('WWW-Authenticate', 'Bearer') .end(); }); it("should return 401 when a claim of an authenticated user doesn't pass a 'pattern' claim spec", function () { var token = jwt.sign( // aud claim has incorrect value - { sub: 'foo-user', aud: 'foo1:bar', roles: ["sales", "marketing"] }, + { sub: 'foo-user', aud: 'foo1:bar', roles: ["sales", "marketing"], scope: 'admin' }, secret); return request(url) .get('/secure/admin') .headers({'Authorization': 'Bearer ' + token}) .expect(401) + .expect('WWW-Authenticate', 'Bearer') + .end(); + }); + + it("should return 403 when a scope claim has incorrect value", function () { + var token = jwt.sign( + // scope claim has incorrect value + { sub: 'foo-user', aud: 'foo:bar', roles: ["sales", "marketing"], scope: 'user' }, + secret); + + return request(url) + .get('/secure/admin') + .headers({'Authorization': 'Bearer ' + token}) + .expect(401) + .expect('WWW-Authenticate', 'Bearer error="insufficient_scope",scope=admin') .end(); }); it("should return 401 when a claim of an authenticated user doesn't pass a 'function' claim spec", function () { var token = jwt.sign( // roles claim is missing 'marketing' role - { sub: 'foo-user', aud: 'foo:bar', roles: ["sales"] }, + { sub: 'foo-user', aud: 'foo:bar', roles: ["sales"], scope: 'admin' }, secret); return request(url) .get('/secure/admin') .headers({'Authorization': 'Bearer ' + token}) .expect(401) + .expect('WWW-Authenticate', 'Bearer') .end(); }); From 03e035daccf7d734c33f605a7e43b33affab8f1f Mon Sep 17 00:00:00 2001 From: "hardy.mansen@unibet.com" Date: Tue, 1 Dec 2015 09:58:47 +0100 Subject: [PATCH 3/4] typos --- hosts/proxy/default/nginx/conf/nginx.conf | 2 +- test/test_integration.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hosts/proxy/default/nginx/conf/nginx.conf b/hosts/proxy/default/nginx/conf/nginx.conf index c0edc50..398fdf3 100644 --- a/hosts/proxy/default/nginx/conf/nginx.conf +++ b/hosts/proxy/default/nginx/conf/nginx.conf @@ -29,7 +29,7 @@ http { local jwt = require("nginx-jwt") jwt.auth({ aud="^foo:", - scope="admin", + scope="admin", roles=function (val) return jwt.table_contains(val, "marketing") end }) '; diff --git a/test/test_integration.js b/test/test_integration.js index 0a6a278..c4f3fda 100644 --- a/test/test_integration.js +++ b/test/test_integration.js @@ -146,7 +146,7 @@ describe('proxy', function () { return request(url) .get('/secure/admin') .headers({'Authorization': 'Bearer ' + token}) - .expect(401) + .expect(403) .expect('WWW-Authenticate', 'Bearer error="insufficient_scope",scope=admin') .end(); }); From 472292a08bcb9065ff6ee1aa5882e3ea4286e708 Mon Sep 17 00:00:00 2001 From: "hardy.mansen@unibet.com" Date: Tue, 1 Dec 2015 18:07:55 +0100 Subject: [PATCH 4/4] fix 200 test --- test/test_integration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_integration.js b/test/test_integration.js index c4f3fda..59376b0 100644 --- a/test/test_integration.js +++ b/test/test_integration.js @@ -168,7 +168,7 @@ describe('proxy', function () { it("should return 200 when an authenticated user is also authorized by all claims", function () { var token = jwt.sign( // everything is good - { sub: 'foo-user', aud: 'foo:bar', roles: ["sales", "marketing"] }, + { sub: 'foo-user', aud: 'foo:bar', roles: ["sales", "marketing"], scope: 'admin' }, secret); return request(url)