Merge 0.7->trunk
authorMatthew Wild <mwild1@gmail.com>
Sun, 23 May 2010 22:11:00 +0000 (23:11 +0100)
committerMatthew Wild <mwild1@gmail.com>
Sun, 23 May 2010 22:11:00 +0000 (23:11 +0100)
1  2 
core/usermanager.lua

diff --combined core/usermanager.lua
index 4fef936ee9de5de04c28d49931de8d20de458b2b,698d2f10413676bc28f3779e94b0f5242fe73e78..07097dc1b97a81d11eaee2bc1e1405b234b5a9b0
@@@ -18,132 -18,83 +18,133 @@@ local hosts = hosts
  
  local require_provisioning = config.get("*", "core", "cyrus_require_provisioning") or false;
  
 +local prosody = _G.prosody;
 +
  module "usermanager"
  
 -local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end
 +local new_default_provider;
  
 -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 {};
 +local function host_handler(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
 +prosody.events.add_handler("host-activated", host_handler);
 +prosody.events.add_handler("component-activated", host_handler);
 +
 +local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end
  
 -      if method == nil then method = "PLAIN"; end
 -      if method == "PLAIN" and credentials.password then -- PLAIN, do directly
 +function new_default_provider(host)
 +      local provider = { name = "default" };
 +      
 +      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
 -      -- compare
 -      if password == pwd then
 -              return true;
 -      else
 -              return nil, "Auth failed. Invalid username or password.";
 +
 +      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 not(require_provisioning) and is_cyrus(host) then return true; end
-               return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
++              local account, err = datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
++              return (account or err) ~= nil; -- FIXME also check for empty credentials
 +      end
 +
 +      function provider:create_user(username, password)
 +              if not(require_provisioning) and is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
 +              return datamanager.store(username, host, "accounts", {password = password});
 +      end
 +
 +      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)
 +              local admins = config.get(host, "core", "admins");
 +              if admins ~= config.get("*", "core", "admins") then
 +                      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("error", "Option 'admins' for host '%s' is not a table", host);
 +                      end
 +              end
 +              return is_admin(jid); -- Test whether it's a global admin instead
 +      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 not(require_provisioning) and is_cyrus(host) then return true; end
 -      local account, err = datamanager.load(username, host, "accounts");
 -      return (account or err) ~= nil; -- FIXME also check for empty credentials
 +      return hosts[host].users:user_exists(username);
  end
  
  function create_user(username, password, host)
 -      if not(require_provisioning) and 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
 +      if host and host ~= "*" then
 +              return hosts[host].users:is_admin(jid);
 +      else -- Test only whether this JID is a global admin
 +              local admins = config.get("*", "core", "admins");
 +              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("error", "Option 'admins' for host '%s' is not a table", host);
 +              end
                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
  
 +_M.new_default_provider = new_default_provider;
 +
  return _M;