Mercurial > prosody-modules
view mod_auth_ldap/mod_auth_ldap.lua @ 5296:0f5657db1cfc
mod_isolate_host: handle server-generated stanzas
The hook for setting the no_host_isolation is only called for c2s
sessions. This does not work for stanzas generated by the server,
such as PEP notifications or presence probe answers.
To handle that, we do per-stanza checks for the case that the origin
is local.
author | Jonas Schäfer <jonas@wielicki.name> |
---|---|
date | Sat, 01 Apr 2023 12:03:08 +0200 |
parents | f2b29183ef08 |
children |
line wrap: on
line source
-- mod_auth_ldap local jid_split = require "util.jid".split; local new_sasl = require "util.sasl".new; local lualdap = require "lualdap"; local function ldap_filter_escape(s) return (s:gsub("[*()\\%z]", function(c) return ("\\%02x"):format(c:byte()) end)); end -- Config options local ldap_server = module:get_option_string("ldap_server", "localhost"); local ldap_rootdn = module:get_option_string("ldap_rootdn", ""); local ldap_password = module:get_option_string("ldap_password", ""); local ldap_tls = module:get_option_boolean("ldap_tls"); local ldap_scope = module:get_option_string("ldap_scope", "subtree"); local ldap_filter = module:get_option_string("ldap_filter", "(uid=$user)"):gsub("%%s", "$user", 1); local ldap_base = assert(module:get_option_string("ldap_base"), "ldap_base is a required option for ldap"); local ldap_mode = module:get_option_string("ldap_mode", "bind"); local ldap_admins = module:get_option_string("ldap_admin_filter", module:get_option_string("ldap_admins")); -- COMPAT with mistake in documentation local host = ldap_filter_escape(module:get_option_string("realm", module.host)); -- Initiate connection local ld = nil; module.unload = function() if ld then pcall(ld, ld.close); end end function ldap_do_once(method, ...) if ld == nil then local err; ld, err = lualdap.open_simple(ldap_server, ldap_rootdn, ldap_password, ldap_tls); if not ld then return nil, err, "reconnect"; end end -- luacheck: ignore 411/success local success, iterator, invariant, initial = pcall(ld[method], ld, ...); if not success then ld = nil; return nil, iterator, "search"; end local success, dn, attr = pcall(iterator, invariant, initial); if not success then ld = nil; return success, dn, "iter"; end return dn, attr, "return"; end function ldap_do(method, retry_count, ...) local dn, attr, where; for _=1,1+retry_count do dn, attr, where = ldap_do_once(method, ...); if dn or not(attr) then break; end -- nothing or something found module:log("warn", "LDAP: %s %s (in %s)", tostring(dn), tostring(attr), where); -- otherwise retry end if not dn and attr then module:log("error", "LDAP: %s", tostring(attr)); end return dn, attr; end function get_user(username) module:log("debug", "get_user(%q)", username); return ldap_do("search", 2, { base = ldap_base; scope = ldap_scope; sizelimit = 1; filter = ldap_filter:gsub("%$(%a+)", { user = ldap_filter_escape(username); host = host; }); }); end local provider = {}; function provider.create_user(username, password) -- luacheck: ignore 212 return nil, "Account creation not available with LDAP."; end function provider.user_exists(username) return not not get_user(username); end function provider.set_password(username, password) local dn, attr = get_user(username); if not dn then return nil, attr end if attr.userPassword == password then return true end return ldap_do("modify", 2, dn, { '=', userPassword = password }); end if ldap_mode == "getpasswd" then function provider.get_password(username) local dn, attr = get_user(username); if dn and attr then return attr.userPassword; end end function provider.test_password(username, password) return provider.get_password(username) == password; end function provider.get_sasl_handler() return new_sasl(module.host, { plain = function(sasl, username) -- luacheck: ignore 212/sasl local password = provider.get_password(username); if not password then return "", nil; end return password, true; end }); end elseif ldap_mode == "bind" then local function test_password(userdn, password) local ok, err = lualdap.open_simple(ldap_server, userdn, password, ldap_tls); if not ok then module:log("debug", "ldap open_simple error: %s", err); end return not not ok; end function provider.test_password(username, password) local dn = get_user(username); if not dn then return end return test_password(dn, password) end function provider.get_sasl_handler() return new_sasl(module.host, { plain_test = function(sasl, username, password) -- luacheck: ignore 212/sasl return provider.test_password(username, password), true; end }); end else module:log("error", "Unsupported ldap_mode %s", tostring(ldap_mode)); end if ldap_admins then function provider.is_admin(jid) local username, user_host = jid_split(jid); if user_host ~= module.host then return false; end return ldap_do("search", 2, { base = ldap_base; scope = ldap_scope; sizelimit = 1; filter = ldap_admins:gsub("%$(%a+)", { user = ldap_filter_escape(username); host = host; }); }); end end module:provides("auth", provider);