usermanager: Support for pluggable authentication providers

Wed, 05 May 2010 01:05:58 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Wed, 05 May 2010 01:05:58 +0100
changeset 2987
0acfae4da199
parent 2986
fff153f7f4de
child 2989
87c378c77be3

usermanager: Support for pluggable authentication providers

core/usermanager.lua file | annotate | diff | comparison | revisions
--- a/core/usermanager.lua	Tue May 04 23:43:01 2010 +0100
+++ b/core/usermanager.lua	Wed May 05 01:05:58 2010 +0100
@@ -16,82 +16,117 @@
 local config = require "core.configmanager";
 local hosts = hosts;
 
+local prosody = _G.prosody;
+
 module "usermanager"
 
+local new_default_provider;
+
+prosody.events.add_handler("host-activated", function (host)
+	local host_session = hosts[host];
+	host_session.events.add_handler("item-added/auth-provider", function (provider)
+		if config.get(host, "core", "authentication") == provider.name then
+			host_session.users = provider;
+		end
+	end);
+	host_session.events.add_handler("item-removed/auth-provider", function (provider)
+		if host_session.users == provider then
+			host_session.users = new_default_provider(host);
+		end
+	end);
+	host_session.users = new_default_provider(host); -- Start with the default usermanager provider
+end);
+
 local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end
 
-function validate_credentials(host, username, password, method)
-	log("debug", "User '%s' is being validated", username);
-	if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end
-	local credentials = datamanager.load(username, host, "accounts") or {};
-
-	if method == nil then method = "PLAIN"; end
-	if method == "PLAIN" and credentials.password then -- PLAIN, do directly
+function new_default_provider(host)
+	local provider = {};
+	
+	function provider.test_password(username, password)
+		if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end
+		local credentials = datamanager.load(username, host, "accounts") or {};
+	
 		if password == credentials.password then
 			return true;
 		else
 			return nil, "Auth failed. Invalid username or password.";
 		end
-  end
-	-- must do md5
-	-- make credentials md5
-	local pwd = credentials.password;
-	if not pwd then pwd = credentials.md5; else pwd = hashes.md5(pwd, true); end
-	-- make password md5
-	if method == "PLAIN" then
-		password = hashes.md5(password or "", true);
-	elseif method ~= "DIGEST-MD5" then
-		return nil, "Unsupported auth method";
+	end
+
+	function provider.get_password(username)
+		if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
+		return (datamanager.load(username, host, "accounts") or {}).password;
+	end
+	
+	function provider.set_password(username, password)
+		if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
+		local account = datamanager.load(username, host, "accounts");
+		if account then
+			account.password = password;
+			return datamanager.store(username, host, "accounts", account);
+		end
+		return nil, "Account not available.";
+	end
+
+	function provider.user_exists(username)
+		if is_cyrus(host) then return true; end
+		return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
+	end
+
+	function provider.create_user(username, password)
+		if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
+		return datamanager.store(username, host, "accounts", {password = password});
 	end
-	-- compare
-	if password == pwd then
-		return true;
-	else
-		return nil, "Auth failed. Invalid username or password.";
+
+	function provider.get_supported_methods()
+		return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config
 	end
+
+	function provider.is_admin(jid)
+		host = host or "*";
+		local admins = config.get(host, "core", "admins");
+		if host ~= "*" and admins == config.get("*", "core", "admins") then
+			return nil;
+		end
+		if type(admins) == "table" then
+			jid = jid_bare(jid);
+			for _,admin in ipairs(admins) do
+				if admin == jid then return true; end
+			end
+		elseif admins then
+			log("warn", "Option 'admins' for host '%s' is not a table", host);
+		end
+		return nil;
+	end
+	return provider;
+end
+
+function validate_credentials(host, username, password, method)
+	return hosts[host].users.test_password(username, password);
 end
 
 function get_password(username, host)
-	if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
-	return (datamanager.load(username, host, "accounts") or {}).password
+	return hosts[host].users.get_password(username);
 end
+
 function set_password(username, host, password)
-	if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
-	local account = datamanager.load(username, host, "accounts");
-	if account then
-		account.password = password;
-		return datamanager.store(username, host, "accounts", account);
-	end
-	return nil, "Account not available.";
+	return hosts[host].users.set_password(username, password);
 end
 
 function user_exists(username, host)
-	if is_cyrus(host) then return true; end
-	return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
+	return hosts[host].users.user_exists(username);
 end
 
 function create_user(username, password, host)
-	if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
-	return datamanager.store(username, host, "accounts", {password = password});
+	return hosts[host].users.create_user(username, password);
 end
 
 function get_supported_methods(host)
-	return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config
+	return hosts[host].users.get_supported_methods();
 end
 
 function is_admin(jid, host)
-	host = host or "*";
-	local admins = config.get(host, "core", "admins");
-	if host ~= "*" and admins == config.get("*", "core", "admins") then
-		return nil;
-	end
-	if type(admins) == "table" then
-		jid = jid_bare(jid);
-		for _,admin in ipairs(admins) do
-			if admin == jid then return true; end
-		end
-	elseif admins then log("warn", "Option 'admins' for host '%s' is not a table", host); end
-	return nil;
+	return hosts[host].users.is_admin(jid);
 end
 
 return _M;

mercurial