Software / code / prosody
Comparison
core/usermanager.lua @ 2987:0acfae4da199
usermanager: Support for pluggable authentication providers
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Wed, 05 May 2010 01:05:58 +0100 |
| parent | 2934:060bb8217fea |
| child | 2999:9a8f942433c4 |
comparison
equal
deleted
inserted
replaced
| 2986:fff153f7f4de | 2987:0acfae4da199 |
|---|---|
| 14 local hashes = require "util.hashes"; | 14 local hashes = require "util.hashes"; |
| 15 local jid_bare = require "util.jid".bare; | 15 local jid_bare = require "util.jid".bare; |
| 16 local config = require "core.configmanager"; | 16 local config = require "core.configmanager"; |
| 17 local hosts = hosts; | 17 local hosts = hosts; |
| 18 | 18 |
| 19 local prosody = _G.prosody; | |
| 20 | |
| 19 module "usermanager" | 21 module "usermanager" |
| 22 | |
| 23 local new_default_provider; | |
| 24 | |
| 25 prosody.events.add_handler("host-activated", function (host) | |
| 26 local host_session = hosts[host]; | |
| 27 host_session.events.add_handler("item-added/auth-provider", function (provider) | |
| 28 if config.get(host, "core", "authentication") == provider.name then | |
| 29 host_session.users = provider; | |
| 30 end | |
| 31 end); | |
| 32 host_session.events.add_handler("item-removed/auth-provider", function (provider) | |
| 33 if host_session.users == provider then | |
| 34 host_session.users = new_default_provider(host); | |
| 35 end | |
| 36 end); | |
| 37 host_session.users = new_default_provider(host); -- Start with the default usermanager provider | |
| 38 end); | |
| 20 | 39 |
| 21 local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end | 40 local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end |
| 22 | 41 |
| 23 function validate_credentials(host, username, password, method) | 42 function new_default_provider(host) |
| 24 log("debug", "User '%s' is being validated", username); | 43 local provider = {}; |
| 25 if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end | 44 |
| 26 local credentials = datamanager.load(username, host, "accounts") or {}; | 45 function provider.test_password(username, password) |
| 27 | 46 if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end |
| 28 if method == nil then method = "PLAIN"; end | 47 local credentials = datamanager.load(username, host, "accounts") or {}; |
| 29 if method == "PLAIN" and credentials.password then -- PLAIN, do directly | 48 |
| 30 if password == credentials.password then | 49 if password == credentials.password then |
| 31 return true; | 50 return true; |
| 32 else | 51 else |
| 33 return nil, "Auth failed. Invalid username or password."; | 52 return nil, "Auth failed. Invalid username or password."; |
| 34 end | 53 end |
| 35 end | |
| 36 -- must do md5 | |
| 37 -- make credentials md5 | |
| 38 local pwd = credentials.password; | |
| 39 if not pwd then pwd = credentials.md5; else pwd = hashes.md5(pwd, true); end | |
| 40 -- make password md5 | |
| 41 if method == "PLAIN" then | |
| 42 password = hashes.md5(password or "", true); | |
| 43 elseif method ~= "DIGEST-MD5" then | |
| 44 return nil, "Unsupported auth method"; | |
| 45 end | 54 end |
| 46 -- compare | 55 |
| 47 if password == pwd then | 56 function provider.get_password(username) |
| 48 return true; | 57 if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end |
| 49 else | 58 return (datamanager.load(username, host, "accounts") or {}).password; |
| 50 return nil, "Auth failed. Invalid username or password."; | |
| 51 end | 59 end |
| 60 | |
| 61 function provider.set_password(username, password) | |
| 62 if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end | |
| 63 local account = datamanager.load(username, host, "accounts"); | |
| 64 if account then | |
| 65 account.password = password; | |
| 66 return datamanager.store(username, host, "accounts", account); | |
| 67 end | |
| 68 return nil, "Account not available."; | |
| 69 end | |
| 70 | |
| 71 function provider.user_exists(username) | |
| 72 if is_cyrus(host) then return true; end | |
| 73 return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials | |
| 74 end | |
| 75 | |
| 76 function provider.create_user(username, password) | |
| 77 if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end | |
| 78 return datamanager.store(username, host, "accounts", {password = password}); | |
| 79 end | |
| 80 | |
| 81 function provider.get_supported_methods() | |
| 82 return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config | |
| 83 end | |
| 84 | |
| 85 function provider.is_admin(jid) | |
| 86 host = host or "*"; | |
| 87 local admins = config.get(host, "core", "admins"); | |
| 88 if host ~= "*" and admins == config.get("*", "core", "admins") then | |
| 89 return nil; | |
| 90 end | |
| 91 if type(admins) == "table" then | |
| 92 jid = jid_bare(jid); | |
| 93 for _,admin in ipairs(admins) do | |
| 94 if admin == jid then return true; end | |
| 95 end | |
| 96 elseif admins then | |
| 97 log("warn", "Option 'admins' for host '%s' is not a table", host); | |
| 98 end | |
| 99 return nil; | |
| 100 end | |
| 101 return provider; | |
| 102 end | |
| 103 | |
| 104 function validate_credentials(host, username, password, method) | |
| 105 return hosts[host].users.test_password(username, password); | |
| 52 end | 106 end |
| 53 | 107 |
| 54 function get_password(username, host) | 108 function get_password(username, host) |
| 55 if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end | 109 return hosts[host].users.get_password(username); |
| 56 return (datamanager.load(username, host, "accounts") or {}).password | |
| 57 end | 110 end |
| 111 | |
| 58 function set_password(username, host, password) | 112 function set_password(username, host, password) |
| 59 if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end | 113 return hosts[host].users.set_password(username, password); |
| 60 local account = datamanager.load(username, host, "accounts"); | |
| 61 if account then | |
| 62 account.password = password; | |
| 63 return datamanager.store(username, host, "accounts", account); | |
| 64 end | |
| 65 return nil, "Account not available."; | |
| 66 end | 114 end |
| 67 | 115 |
| 68 function user_exists(username, host) | 116 function user_exists(username, host) |
| 69 if is_cyrus(host) then return true; end | 117 return hosts[host].users.user_exists(username); |
| 70 return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials | |
| 71 end | 118 end |
| 72 | 119 |
| 73 function create_user(username, password, host) | 120 function create_user(username, password, host) |
| 74 if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end | 121 return hosts[host].users.create_user(username, password); |
| 75 return datamanager.store(username, host, "accounts", {password = password}); | |
| 76 end | 122 end |
| 77 | 123 |
| 78 function get_supported_methods(host) | 124 function get_supported_methods(host) |
| 79 return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config | 125 return hosts[host].users.get_supported_methods(); |
| 80 end | 126 end |
| 81 | 127 |
| 82 function is_admin(jid, host) | 128 function is_admin(jid, host) |
| 83 host = host or "*"; | 129 return hosts[host].users.is_admin(jid); |
| 84 local admins = config.get(host, "core", "admins"); | |
| 85 if host ~= "*" and admins == config.get("*", "core", "admins") then | |
| 86 return nil; | |
| 87 end | |
| 88 if type(admins) == "table" then | |
| 89 jid = jid_bare(jid); | |
| 90 for _,admin in ipairs(admins) do | |
| 91 if admin == jid then return true; end | |
| 92 end | |
| 93 elseif admins then log("warn", "Option 'admins' for host '%s' is not a table", host); end | |
| 94 return nil; | |
| 95 end | 130 end |
| 96 | 131 |
| 97 return _M; | 132 return _M; |