- local object = { mechanism = "DIGEST-MD5", realm = realm, password_handler = password_handler}
-
- --TODO: something better than math.random would be nice, maybe OpenSSL's random number generator
- object.nonce = generate_uuid()
- object.step = 0
- object.nonce_count = {}
-
- function object.feed(self, message)
- self.step = self.step + 1
- if (self.step == 1) then
- local challenge = serialize({ nonce = object.nonce,
- qop = "auth",
- charset = "utf-8",
- algorithm = "md5-sess",
- realm = self.realm});
- return "challenge", challenge
- elseif (self.step == 2) then
- local response = parse(message)
- -- check for replay attack
- if response["nc"] then
- if self.nonce_count[response["nc"]] then return "failure", "not-authorized" end
- end
-
- -- check for username, it's REQUIRED by RFC 2831
- if not response["username"] then
- return "failure", "malformed-request"
- end
- self["username"] = response["username"]
-
- -- check for nonce, ...
- if not response["nonce"] then
- return "failure", "malformed-request"
- else
- -- check if it's the right nonce
- if response["nonce"] ~= tostring(self.nonce) then return "failure", "malformed-request" end
- end
-
- if not response["cnonce"] then return "failure", "malformed-request", "Missing entry for cnonce in SASL message." end
- if not response["qop"] then response["qop"] = "auth" end
-
- if response["realm"] == nil then response["realm"] = "" end
-
- local domain = ""
- local protocol = ""
- if response["digest-uri"] then
- protocol, domain = response["digest-uri"]:match("(%w+)/(.*)$")
- if protocol == nil or domain == nil then return "failure", "malformed-request" end
- else
- return "failure", "malformed-request", "Missing entry for digest-uri in SASL message."
+digest-md5-test:
+ function(username, realm, encoding, digesthash)
+ return true or false, state;
+ end
+]]
+
+local method = {};
+method.__index = method;
+local mechanisms = {};
+local backend_mechanism = {};
+
+-- register a new SASL mechanims
+local function registerMechanism(name, backends, f)
+ 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.");
+ mechanisms[name] = f
+ 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);
+ end
+end
+
+-- create a new SASL object which can be used to authenticate clients
+function new(realm, profile)
+ sasl_i = {profile = profile};
+ sasl_i.realm = realm;
+ return setmetatable(sasl_i, method);
+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;