Mercurial > prosody-modules
view mod_auth_external_insecure/mod_auth_external_insecure.lua @ 5418:f2c7bb3af600
mod_http_oauth2: Add role selector to consent page
List includes all roles available to the user, if more than one.
Defaults to either the first role in the scope string or the users
primary role.
Earlier draft listed all roles, but having options that can't be
selected is bad UX and the entire list of all roles on the server could
be long, and perhaps even sensitive.
Allows e.g. picking a role with fewer permissions than what might
otherwise have been selected.
UX wise, doing this with more checkboxes or possibly radio buttons would
have been confusion and/or looked messier.
Fixes the previous situation where unselecting a role would default to
the primary role, which could be more permissions than requested.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 05 May 2023 01:23:13 +0200 |
parents | f84ede3e9e3b |
children |
line wrap: on
line source
-- -- Prosody IM -- Copyright (C) 2010 Waqas Hussain -- Copyright (C) 2010 Jeff Mitchell -- Copyright (C) 2013 Mikael Nordfeldth -- Copyright (C) 2013 Matthew Wild, finally came to fix it all -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- local lpty = assert(require "lpty", "mod_auth_external requires lpty: https://modules.prosody.im/mod_auth_external.html#installation"); local usermanager = require "core.usermanager"; local new_sasl = require "util.sasl".new; local server = require "net.server"; local have_async, async = pcall(require, "util.async"); local log = module._log; local host = module.host; local script_type = module:get_option_string("external_auth_protocol", "generic"); local command = module:get_option_string("external_auth_command", ""); local read_timeout = module:get_option_number("external_auth_timeout", 5); local blocking = module:get_option_boolean("external_auth_blocking", true); -- non-blocking is very experimental local auth_processes = module:get_option_number("external_auth_processes", 1); assert(script_type == "ejabberd" or script_type == "generic", "Config error: external_auth_protocol must be 'ejabberd' or 'generic'"); assert(not host:find(":"), "Invalid hostname"); if not blocking then assert(server.event, "External auth non-blocking mode requires libevent installed and enabled"); log("debug", "External auth in non-blocking mode, yay!") waiter, guard = async.waiter, async.guarder(); elseif auth_processes > 1 then log("warn", "external_auth_processes is greater than 1, but we are in blocking mode - reducing to 1"); auth_processes = 1; end local ptys = {}; local pty_options = { throw_errors = false, no_local_echo = true, use_path = false }; for i = 1, auth_processes do ptys[i] = lpty.new(pty_options); end function module.unload() for i = 1, auth_processes do ptys[i]:endproc(); end end module:hook_global("server-cleanup", module.unload); local curr_process = 0; function send_query(text) curr_process = (curr_process%auth_processes)+1; local pty = ptys[curr_process]; local finished_with_pty if not blocking then finished_with_pty = guard(pty); -- Prevent others from crossing this line while we're busy end if not pty:hasproc() then local status, ret = pty:exitstatus(); if status and (status ~= "exit" or ret ~= 0) then log("warn", "Auth process exited unexpectedly with %s %d, restarting", status, ret or 0); return nil; end local ok, err = pty:startproc(command); if not ok then log("error", "Failed to start auth process '%s': %s", command, err); return nil; end log("debug", "Started auth process"); end pty:send(text); if blocking then return pty:read(read_timeout); else local response; local wait, done = waiter(); server.addevent(pty:getfd(), server.event.EV_READ, function () response = pty:read(); done(); return -1; end); wait(); finished_with_pty(); return response; end end function do_query(kind, username, password) if not username then return nil, "not-acceptable"; end local query = (password and "%s:%s:%s:%s" or "%s:%s:%s"):format(kind, username, host, password); local len = #query if len > 1000 then return nil, "policy-violation"; end if script_type == "ejabberd" then local lo = len % 256; local hi = (len - lo) / 256; query = string.char(hi, lo)..query; elseif script_type == "generic" then query = query..'\n'; end local response, err = send_query(query); if not response then log("warn", "Error while waiting for result from auth process: %s", err or "unknown error"); elseif (script_type == "ejabberd" and response == "\0\2\0\0") or (script_type == "generic" and response:gsub("\r?\n$", "") == "0") then return nil, "not-authorized"; elseif (script_type == "ejabberd" and response == "\0\2\0\1") or (script_type == "generic" and response:gsub("\r?\n$", "") == "1") then return true; else log("warn", "Unable to interpret data from auth process, %s", (response:match("^error:") and response) or ("["..#response.." bytes]")); return nil, "internal-server-error"; end end local provider = {}; function provider.test_password(username, password) return do_query("auth", username, password); end function provider.set_password(username, password) return do_query("setpass", username, password); end function provider.user_exists(username) return do_query("isuser", username); end function provider.create_user(username, password) -- luacheck: ignore 212 return nil, "Account creation/modification not available."; end function provider.get_sasl_handler() local testpass_authentication_profile = { plain_test = function(sasl, username, password, realm) return usermanager.test_password(username, realm, password), true; end, }; return new_sasl(host, testpass_authentication_profile); end module:provides("auth", provider);