X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=util%2Fsasl.lua;h=9c8fff7804a28edd6b7e4e430b846d3d23093696;hb=2949c6844187c10f634e60bf00166c899f90044a;hp=687878c498112995f893b87bc413622da46d2d6b;hpb=8f5798486ab1a7b1da3eff4223c6e4f78dfb41be;p=prosody.git diff --git a/util/sasl.lua b/util/sasl.lua index 687878c4..9c8fff78 100644 --- a/util/sasl.lua +++ b/util/sasl.lua @@ -14,22 +14,20 @@ local md5 = require "util.hashes".md5; local log = require "util.logger".init("sasl"); -local tostring = tostring; local st = require "util.stanza"; -local generate_uuid = require "util.uuid".generate; +local set = require "util.set"; +local array = require "util.array"; +local to_unicode = require "util.encodings".idna.to_unicode; + +local tostring = tostring; local pairs, ipairs = pairs, ipairs; local t_insert, t_concat = table.insert, table.concat; -local to_byte, to_char = string.byte, string.char; -local to_unicode = require "util.encodings".idna.to_unicode; local s_match = string.match; -local gmatch = string.gmatch -local string = string -local math = require "math" local type = type local error = error -local print = print local setmetatable = setmetatable; local assert = assert; +local require = require; require "util.iterators" local keys = keys @@ -40,6 +38,10 @@ module "sasl" --[[ Authentication Backend Prototypes: +state = false : disabled +state = true : enabled +state = nil : non-existant + plain: function(username, realm) return password, state; @@ -51,12 +53,13 @@ plain-test: end digest-md5: - function(username, realm, encoding) + function(username, domain, realm, encoding) -- domain and realm are usually the same; for some broken + -- implementations it's not return digesthash, state; end digest-md5-test: - function(username, realm, encoding, digesthash) + function(username, domain, realm, encoding, digesthash) return true or false, state; end ]] @@ -79,20 +82,40 @@ local function registerMechanism(name, backends, f) end -- create a new SASL object which can be used to authenticate clients -function new(realm, profile) - sasl_i = {profile = profile}; +function new(realm, profile, forbidden) + local sasl_i = {profile = profile}; sasl_i.realm = realm; - return setmetatable(sasl_i, method); + local s = setmetatable(sasl_i, method); + if forbidden == nil then forbidden = {} end + s:forbidden(forbidden) + return s; +end + +-- get a fresh clone with the same realm, profiles and forbidden mechanisms +function method:clean_clone() + return new(self.realm, self.profile, self:forbidden()) +end + +-- set the forbidden mechanisms +function method:forbidden( restrict ) + if restrict then + -- set forbidden + self.restrict = set.new(restrict); + else + -- get forbidden + return array.collect(self.restrict:items()); + end end -- get a list of possible SASL mechanims to use function method:mechanisms() local mechanisms = {} for backend, f in pairs(self.profile) do - print(backend) if backend_mechanism[backend] then for _, mechanism in ipairs(backend_mechanism[backend]) do - mechanisms[mechanism] = true; + if not self.restrict:contains(mechanism) then + mechanisms[mechanism] = true; + end end end end @@ -102,6 +125,10 @@ end -- select a mechanism to use function method:select(mechanism) + if self.mech_i then + return false; + end + self.mech_i = mechanisms[mechanism] if self.mech_i == nil then return false; @@ -111,42 +138,16 @@ end -- feed new messages to process into the library function method:process(message) - if message == "" or message == nil then return "failure", "malformed-request" end + --if message == "" or message == nil then return "failure", "malformed-request" end return self.mech_i(self, message); end ---========================= ---SASL PLAIN -local function sasl_mechanism_plain(self, message) - local response = message - local authorization = s_match(response, "([^&%z]+)") - local authentication = s_match(response, "%z([^&%z]+)%z") - local password = s_match(response, "%z[^&%z]+%z([^&%z]+)") - - if authentication == nil or password == nil then - return "failure", "malformed-request"; - end - - local correct, state = false, false; - if self.profile.plain then - local correct_password; - correct_password, state = self.profile.plain(authentication, self.realm); - if correct_password == password then correct = true; else correct = false; end - elseif self.profile.plain_test then - correct, state = self.profile.plain_test(authentication, self.realm, password); - end - - self.username = authentication - if not state then - return "failure", "account-disabled"; - end - - if correct then - return "success"; - else - return "failure", "not-authorized"; - end +-- load the mechanisms +load_mechs = {"plain", "digest-md5", "anonymous", "scram"} +for _, mech in ipairs(load_mechs) do + local name = "util.sasl."..mech; + local m = require(name); + m.init(registerMechanism) end -registerMechanism("PLAIN", {"plain", "plain_test"}, sasl_mechanism_plain); return _M;