Mercurial > prosody-modules
view mod_auth_joomla/mod_auth_joomla.lua @ 4203:c4002aae4ad3
mod_s2s_keepalive: Use timestamp as iq @id
RFC 6120 implies that the id attribute must be unique within a stream.
This should fix problems with remote servers that enforce uniqueness and
don't answer duplicated ids.
If it doesn't do that, then at least you can get a guesstimate at
round-trip time from the difference between the result iq stanza and the
timestamp it was logged without having to go look for when it was sent,
or needing to keep state.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Wed, 14 Oct 2020 18:02:10 +0200 |
parents | 7dbde05b48a9 |
children |
line wrap: on
line source
-- Joomla authentication backend for Prosody -- -- Copyright (C) 2011 Waqas Hussain -- local new_sasl = require "util.sasl".new; local nodeprep = require "util.encodings".stringprep.nodeprep; local saslprep = require "util.encodings".stringprep.saslprep; local DBI = require "DBI" local md5 = require "util.hashes".md5; local uuid_gen = require "util.uuid".generate; local connection; local params = module:get_option("sql"); local prefix = params and params.prefix or "jos_"; local resolve_relative_path = require "core.configmanager".resolve_relative_path; local function test_connection() if not connection then return nil; end if connection:ping() then return true; else module:log("debug", "Database connection closed"); connection = nil; end end local function connect() if not test_connection() then prosody.unlock_globals(); local dbh, err = DBI.Connect( params.driver, params.database, params.username, params.password, params.host, params.port ); prosody.lock_globals(); if not dbh then module:log("debug", "Database connection failed: %s", tostring(err)); return nil, err; end module:log("debug", "Successfully connected to database"); dbh:autocommit(true); -- don't run in transaction connection = dbh; return connection; end end do -- process options to get a db connection params = params or { driver = "SQLite3" }; if params.driver == "SQLite3" then params.database = resolve_relative_path(prosody.paths.data or ".", params.database or "prosody.sqlite"); end assert(params.driver and params.database, "Both the SQL driver and the database need to be specified"); assert(connect()); end local function getsql(sql, ...) if params.driver == "PostgreSQL" then sql = sql:gsub("`", "\""); end if not test_connection() then connect(); end -- do prepared statement stuff local stmt, err = connection:prepare(sql); if not stmt and not test_connection() then error("connection failed"); end if not stmt then module:log("error", "QUERY FAILED: %s %s", err, debug.traceback()); return nil, err; end -- run query local ok, err = stmt:execute(...); if not ok and not test_connection() then error("connection failed"); end if not ok then return nil, err; end return stmt; end local function setsql(sql, ...) local stmt, err = getsql(sql, ...); if not stmt then return stmt, err; end return stmt:affected(); end local function get_password(username) local stmt, err = getsql("SELECT `password` FROM `"..prefix.."users` WHERE `username`=?", username); if stmt then for row in stmt:rows(true) do return row.password; end end end local function getCryptedPassword(plaintext, salt) local salted = plaintext..salt; return md5(salted, true); end local function joomlaCheckHash(password, hash) local crypt, salt = hash:match("^([^:]*):(.*)$"); return (crypt or hash) == getCryptedPassword(password, salt or ''); end local function joomlaCreateHash(password) local salt = uuid_gen():gsub("%-", ""); local crypt = getCryptedPassword(password, salt); return crypt..':'..salt; end provider = {}; function provider.test_password(username, password) local hash = get_password(username); return hash and joomlaCheckHash(password, hash); end function provider.user_exists(username) module:log("debug", "test user %s existence", username); return get_password(username) and true; end function provider.get_password(username) return nil, "Getting password is not supported."; end function provider.set_password(username, password) local hash = joomlaCreateHash(password); local stmt, err = setsql("UPDATE `"..prefix.."users` SET `password`=? WHERE `username`=?", hash, username); return stmt and true, err; end function provider.create_user(username, password) return nil, "Account creation/modification not supported."; end local escapes = { [" "] = "\\20"; ['"'] = "\\22"; ["&"] = "\\26"; ["'"] = "\\27"; ["/"] = "\\2f"; [":"] = "\\3a"; ["<"] = "\\3c"; [">"] = "\\3e"; ["@"] = "\\40"; ["\\"] = "\\5c"; }; local unescapes = {}; for k,v in pairs(escapes) do unescapes[v] = k; end local function jid_escape(s) return s and (s:gsub(".", escapes)); end local function jid_unescape(s) return s and (s:gsub("\\%x%x", unescapes)); end function provider.get_sasl_handler() local sasl = {}; function sasl:clean_clone() return provider.get_sasl_handler(); end function sasl:mechanisms() return { PLAIN = true; }; end function sasl:select(mechanism) if not self.selected and mechanism == "PLAIN" then self.selected = mechanism; return true; end end function sasl:process(message) if not message then return "failure", "malformed-request"; end local authorization, authentication, password = message:match("^([^%z]*)%z([^%z]+)%z([^%z]+)"); if not authorization then return "failure", "malformed-request"; end authentication = saslprep(authentication); password = saslprep(password); if (not password) or (password == "") or (not authentication) or (authentication == "") then return "failure", "malformed-request", "Invalid username or password."; end local function test(authentication) local prepped = nodeprep(authentication); local normalized = jid_unescape(prepped); return normalized and provider.test_password(normalized, password) and prepped; end local username = test(authentication) or test(jid_escape(authentication)); if username then self.username = username; return "success"; end return "failure", "not-authorized", "Unable to authorize you with the authentication credentials you've sent."; end return sasl; end module:provides("auth", provider);