diff options
-rw-r--r-- | lib/gitano.lua | 2 | ||||
-rw-r--r-- | lib/gitano/auth.lua | 140 |
2 files changed, 142 insertions, 0 deletions
diff --git a/lib/gitano.lua b/lib/gitano.lua index ad3cd7c..b57bd71 100644 --- a/lib/gitano.lua +++ b/lib/gitano.lua @@ -14,6 +14,7 @@ local actions = require 'gitano.actions' local lace = require 'gitano.lace' local markdown = require 'gitano.markdown' local supple = require 'gitano.supple' +local auth = require 'gitano.auth' return { util = util, @@ -25,4 +26,5 @@ return { lace = lace, markdown = markdown, supple = supple, + auth = auth } diff --git a/lib/gitano/auth.lua b/lib/gitano/auth.lua new file mode 100644 index 0000000..8cdd8ec --- /dev/null +++ b/lib/gitano/auth.lua @@ -0,0 +1,140 @@ +local config = require 'gitano.config' +local command = require 'gitano.command' +local log = require 'gitano.log' +local repository = require 'gitano.repository' +local util = require 'gitano.util' +local gall = require 'gall' + +local function load_admin_conf(repo_root) + local admin_repo = gall.repository.new((repo_root or "") .. + "/gitano-admin.git") + + if not admin_repo then + log.critical("Unable to locate administration repository.") + return nil + end + + local admin_head = admin_repo:get(admin_repo.HEAD) + + if not admin_head then + log.critical("Unable to find the HEAD of the administration repository.") + return nil + end + + local admin_conf, msg = config.parse(admin_head) + + if not admin_conf then + log.critical("Unable to parse administration repository.") + log.critical(" * " .. (msg or "No error?")) + return nil + end + + return admin_conf +end + +local function set_environment(repo_root, repo, context, transactionid) + local env = { + ["GITANO_ROOT"] = repo_root, + ["GITANO_USER"] = context.user, + ["GITANO_KEYTAG"] = context.keytag, + ["GITANO_PROJECT"] = (repo or {}).name or "", + ["GITANO_SOURCE"] = context.source, + ["GITANO_TRANSACTION_ID"] = transactionid, + } + + for k, v in pairs(env) do + luxio.setenv(k, v) + end + + return env +end + +local function is_authorized(user, source, cmdline) + local repo_root = os.getenv("GITANO_ROOT") + local keytag = "" + local authorized = false + + local start_log_level = log.get_level() + log.cap_level(log.level.INFO) + local transactionid = log.syslog.open() + + config.repo_path(repo_root) + + if not user or not cmdline then + return nil + end + + local parsed_cmdline, warnings = util.parse_cmdline(cmdline) + + if (#warnings > 0) then + log.error("Error parsing command"); + return nil + end + + local admin_conf = load_admin_conf(repo_root) + if admin_conf == nil then + log.fatal("Couldn't load a config from the admin repository") + end + + if admin_conf.groups["gitano-admin"].filtered_members[user] then + log.set_level(start_log_level) + end + + if not admin_conf.global.silent then + log.bump_level(log.level.CHAT) + end + + ip = os.getenv("REMOTE_ADDR") or "unknown ip" + log.syslog.info("Client connected from", ip, "as", user, + "(" .. keytag .. ")", "Executing command:", cmdline) + + local cmd = command.get(parsed_cmdline[1]) + + if not cmd then + log.critical("Unknown command: " .. parsed_cmdline[1]) + return nil + end + + local repo + if cmd.takes_repo and #parsed_cmdline > 1 then + -- Acquire the repository object for the target repo + local msg + repo, msg = repository.find(admin_conf, parsed_cmdline[2]) + + if not repo then + log.critical("Unable to locate repository.") + log.critical(" * " .. (tostring(msg) or "No error")) + return nil + end + end + + if not cmd.validate(admin_conf, repo, parsed_cmdline) then + log.critical("Validation of command line failed") + return nil + end + + local context = {source = source, user = user, keytag = keytag} + local action, reason = cmd.prep(admin_conf, repo, parsed_cmdline, context) + + if not action then + log.critical(reason) + log.critical("Ruleset did not complete cleanly") + return nil + end + + local env + if action == "allow" then + log.info(reason or "Ruleset permitted action") + authorized = true + env = set_environment(repo_root, repo, context, transactionid) + else + log.critical(reason) + log.critical("Ruleset denied action. Sorry.") + end + + return authorized, cmd, parsed_cmdline, admin_conf, env +end + +return { + is_authorized = is_authorized +} |