--- a/mod_auth_jetbrains_hub.lua Sat Oct 19 02:04:03 2019 -0500
+++ b/mod_auth_jetbrains_hub.lua Mon Oct 21 20:38:02 2019 -0500
@@ -10,11 +10,13 @@
local new_sasl = require "util.sasl".new;
local base64 = require "util.encodings".base64.encode;
+local json_decode = require "util.json".decode local have_async, async = pcall(require, "util.async");
local host = module.host;
local hub_url = module:get_option_string("jetbrains_hub_url", ""):gsub("$host", host);
if hub_url == "" then error("jetbrains_hub_url required") end
@@ -27,6 +29,12 @@
local hub_client_secret = module:get_option_string("jetbrains_hub_client_secret", "");
if hub_client_secret == "" then error("jetbrains_hub_client_secret required") end
+local hub_groups = module:get_option_set("jetbrains_hub_groups", {}); +-- we only need to update the group part of the query once on load so do it +local group_query = get_group_query() -- globals required by socket.http
@@ -36,86 +44,140 @@
if rawget(_G, "base_parsed") == nil then
rawset(_G, "base_parsed", false)
-if not have_async then -- FINE! Set your globals then
+local http_request = nil + http_request = function(url, headers, body) + local http = require "net.http"; + local wait, done = async.waiter(); + body = http.formencode(body); + local function cb(content_, code_, request_, response_) + code, response = code_, response_.body; + http.request(url, ex, cb); + http_request = function(url, headers, body) + local http = require "socket.http"; + local https = require "ssl.https"; + if string.sub(url, 1, string.len('https')) == 'https' then + request = https.request; + request = http.request; + local _, code, _ = request{ + body = http.formencode(body), + sink = ltn12.sink.table(t), + content = table.concat(t), -local function async_http_auth(url, username, password)
- module:log("debug", "async_http_auth()");
- local http = require "net.http";
- local wait, done = async.waiter();
- local content, code, request, response;
+local function get_group_query() + -- if there's no groups, just return an empty string + if #hub_groups == 0 then + -- we have at least one group, so output the start of our query + for i, v in ipairs(hub_groups) do + -- add the group making sure to quote it as spaces are allowed and will + -- fail if they're not quoted. + query = query .. "in:\"" .. v .. "\"" + -- if we have additional groups add our "or" separator between the + if i < #hub_groups then + query = query .. " or " + -- finally add our closing paren and return the query +local function check_group(username, token) + local headers = { Authorization = "Bearer "..token; }; + { name = "$top", value = "1" }; + { name = "query", value = "login:"..username..group_query }; + { name = "fields", value = "type" }; + local resp = http_request(hub_url .. "/api/rest/users", headers, body) + if resp["code"] == 200 then + local json_payload = json_decode(response.body); + if json_payload["total"] ~= 1 then + return nil, "Permission denied"; + return nil, "Failed to check access permissions" +function provider.test_password(username, password) + local headers = { Authorization = "Basic "..base64(hub_client_id..":"..hub_client_secret); }; { name = "grant_type", value = "password" };
{ name = "username", value = username };
{ name = "password", value = password };
{ name = "scope", value = hub_scopes };
- headers = { Authorization = "Basic "..base64(hub_client_id..":"..hub_client_secret); };
- body = http.formencode(body);
- local function cb(content_, code_, request_, response_)
- content, code, request, response = content_, code_, request_, response_;
- http.request(url, ex, cb);
- if code >= 200 and code <= 299 then
+ local resp = http_request(hub_url.."/api/rest/oauth2/token", headers, body); + if resp["code"] >= 200 and resp["code"] <= 299 then module:log("debug", "HTTP auth provider confirmed valid password");
+ if #hub_groups > 0 then + local json_payload = json_decode(resp["content"]); + return async_group_check(username, json_payload["access_token"]) - module:log("debug", "HTTP auth provider returned status code %d", code);
- return nil, "Auth failed. Invalid username or password.";
-local function sync_http_auth(url,username, password)
- module:log("debug", "sync_http_auth()");
- local http = require "socket.http";
- local https = require "ssl.https";
- if string.sub(url, 1, string.len('https')) == 'https' then
- request = https.request;
- request = http.request;
+ module:log("debug", "HTTP auth provider returned status code %d", resp["code"]);
- { name = "grant_type", value = "password" };
- { name = "username", value = username };
- { name = "password", value = password };
- { name = "scope", value = hub_scopes };
- local _, code, headers, status = request{
- headers = { Authorization = "Basic "..base64(hub_client_id..":"..hub_client_secret); },
- body = http.formencode(body)
- if type(code) == "number" and code >= 200 and code <= 299 then
- module:log("debug", "HTTP auth provider confirmed valid password");
- module:log("debug", "HTTP auth provider returned status code: "..code);
return nil, "Auth failed. Invalid username or password.";
-function provider.test_password(username, password)
- local url = hub_url .. "/api/rest/oauth2/token"
- log("debug", "Testing password for user %s at host %s with URL %s", username, host, url);
- return async_http_auth(url, username, password);
- return sync_http_auth(url, username, password);
function provider.users()