method.__index = method;
local mechanisms = {};
local backend_mechanism = {};
+local mechanism_channelbindings = {};
-- register a new SASL mechanims
-local function registerMechanism(name, backends, f)
+function registerMechanism(name, backends, f, cb_backends)
assert(type(name) == "string", "Parameter name MUST be a string.");
assert(type(backends) == "string" or type(backends) == "table", "Parameter backends MUST be either a string or a table.");
assert(type(f) == "function", "Parameter f MUST be a function.");
+ if cb_backends then assert(type(cb_backends) == "table"); end
mechanisms[name] = f
+ if cb_backends then
+ mechanism_channelbindings[name] = {};
+ for _, cb_name in ipairs(cb_backends) do
+ mechanism_channelbindings[name][cb_name] = true;
+ end
+ end
for _, backend_name in ipairs(backends) do
if backend_mechanism[backend_name] == nil then backend_mechanism[backend_name] = {}; end
t_insert(backend_mechanism[backend_name], name);
-- create a new SASL object which can be used to authenticate clients
function new(realm, profile)
- local mechanisms = {};
- for backend, f in pairs(profile) do
- if backend_mechanism[backend] then
- for _, mechanism in ipairs(backend_mechanism[backend]) do
- mechanisms[mechanism] = true;
+ local mechanisms = profile.mechanisms;
+ if not mechanisms then
+ mechanisms = {};
+ for backend, f in pairs(profile) do
+ if backend_mechanism[backend] then
+ for _, mechanism in ipairs(backend_mechanism[backend]) do
+ mechanisms[mechanism] = true;
+ end
end
end
+ profile.mechanisms = mechanisms;
end
return setmetatable({ profile = profile, realm = realm, mechs = mechanisms }, method);
end
+-- add a channel binding handler
+function method:add_cb_handler(name, f)
+ if type(self.profile.cb) ~= "table" then
+ self.profile.cb = {};
+ end
+ self.profile.cb[name] = f;
+ return self;
+end
+
-- get a fresh clone with the same realm and profile
function method:clean_clone()
return new(self.realm, self.profile)
-- get a list of possible SASL mechanims to use
function method:mechanisms()
- return self.mechs;
+ local current_mechs = {};
+ for mech, _ in pairs(self.mechs) do
+ if mechanism_channelbindings[mech] then
+ if self.profile.cb then
+ local ok = false;
+ for cb_name, _ in pairs(self.profile.cb) do
+ if mechanism_channelbindings[mech][cb_name] then
+ ok = true;
+ end
+ end
+ if ok == true then current_mechs[mech] = true; end
+ end
+ else
+ current_mechs[mech] = true;
+ end
+ end
+ return current_mechs;
end
-- select a mechanism to use
require "util.sasl.digest-md5".init(registerMechanism);
require "util.sasl.anonymous" .init(registerMechanism);
require "util.sasl.scram" .init(registerMechanism);
+require "util.sasl.external" .init(registerMechanism);
return _M;