util/sasl.lua

branch
sasl
changeset 2182
1112871916eb
parent 2181
e92339c48ee6
child 2183
f0a85d11823e
--- a/util/sasl.lua	Fri Aug 28 22:03:11 2009 +0200
+++ b/util/sasl.lua	Thu Nov 12 21:57:37 2009 +0100
@@ -119,219 +119,9 @@
 	return self.mech_i(self, message);
 end
 
---=========================
---SASL PLAIN according to RFC 4616
-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
-end
-registerMechanism("PLAIN", {"plain", "plain_test"}, sasl_mechanism_plain);
-
---=========================
---SASL DIGEST-MD5 according to RFC 2831
-local function sasl_mechanism_digest_md5(self, message)
-	--TODO complete support for authzid
-
-	local function serialize(message)
-		local data = ""
-
-		if type(message) ~= "table" then error("serialize needs an argument of type table.") end
-
-		-- testing all possible values
-		if message["realm"] then data = data..[[realm="]]..message.realm..[[",]] end
-		if message["nonce"] then data = data..[[nonce="]]..message.nonce..[[",]] end
-		if message["qop"] then data = data..[[qop="]]..message.qop..[[",]] end
-		if message["charset"] then data = data..[[charset=]]..message.charset.."," end
-		if message["algorithm"] then data = data..[[algorithm=]]..message.algorithm.."," end
-		if message["rspauth"] then data = data..[[rspauth=]]..message.rspauth.."," end
-		data = data:gsub(",$", "")
-		return data
-	end
-
-	local function utf8tolatin1ifpossible(passwd)
-		local i = 1;
-		while i <= #passwd do
-			local passwd_i = to_byte(passwd:sub(i, i));
-			if passwd_i > 0x7F then
-				if passwd_i < 0xC0 or passwd_i > 0xC3 then
-					return passwd;
-				end
-				i = i + 1;
-				passwd_i = to_byte(passwd:sub(i, i));
-				if passwd_i < 0x80 or passwd_i > 0xBF then
-					return passwd;
-				end
-			end
-			i = i + 1;
-		end
-
-		local p = {};
-		local j = 0;
-		i = 1;
-		while (i <= #passwd) do
-			local passwd_i = to_byte(passwd:sub(i, i));
-			if passwd_i > 0x7F then
-				i = i + 1;
-				local passwd_i_1 = to_byte(passwd:sub(i, i));
-				t_insert(p, to_char(passwd_i%4*64 + passwd_i_1%64)); -- I'm so clever
-			else
-				t_insert(p, to_char(passwd_i));
-			end
-			i = i + 1;
-		end
-		return t_concat(p);
-	end
-	local function latin1toutf8(str)
-		local p = {};
-		for ch in gmatch(str, ".") do
-			ch = to_byte(ch);
-			if (ch < 0x80) then
-				t_insert(p, to_char(ch));
-			elseif (ch < 0xC0) then
-				t_insert(p, to_char(0xC2, ch));
-			else
-				t_insert(p, to_char(0xC3, ch - 64));
-			end
-		end
-		return t_concat(p);
-	end
-	local function parse(data)
-		local message = {}
-		for k, v in gmatch(data, [[([%w%-]+)="?([^",]*)"?,?]]) do -- FIXME The hacky regex makes me shudder
-			message[k] = v;
-		end
-		return message;
-	end
-
-	if not self.nonce then
-		self.nonce = generate_uuid();
-		self.step = 0;
-		self.nonce_count = {};
-	end
-
-	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 or response["realm"] == "" then
-			response["realm"] = "";
-		elseif response["realm"] ~= self.realm then
-			return "failure", "not-authorized", "Incorrect realm value";
-		end
-
-		local decoder;
-		if response["charset"] == nil then
-			decoder = utf8tolatin1ifpossible;
-		elseif response["charset"] ~= "utf-8" then
-			return "failure", "incorrect-encoding", "The client's response uses "..response["charset"].." for encoding with isn't supported by sasl.lua. Supported encodings are latin or utf-8.";
-		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."
-		end
-
-		--TODO maybe realm support
-		self.username = response["username"];
-		local password_encoding, Y = self.credentials_handler("DIGEST-MD5", response["username"], self.realm, response["realm"], decoder);
-		if Y == nil then return "failure", "not-authorized"
-		elseif Y == false then return "failure", "account-disabled" end
-		local A1 = "";
-		if response.authzid then
-			if response.authzid == self.username.."@"..self.realm then
-				-- COMPAT
-				log("warn", "Client is violating XMPP RFC. See section 6.1 of RFC 3920.");
-				A1 = Y..":"..response["nonce"]..":"..response["cnonce"]..":"..response.authzid;
-			else
-				A1 = "?";
-			end
-		else
-			A1 = Y..":"..response["nonce"]..":"..response["cnonce"];
-		end
-		local A2 = "AUTHENTICATE:"..protocol.."/"..domain;
-
-		local HA1 = md5(A1, true);
-		local HA2 = md5(A2, true);
-
-		local KD = HA1..":"..response["nonce"]..":"..response["nc"]..":"..response["cnonce"]..":"..response["qop"]..":"..HA2;
-		local response_value = md5(KD, true);
-
-		if response_value == response["response"] then
-			-- calculate rspauth
-			A2 = ":"..protocol.."/"..domain;
-
-			HA1 = md5(A1, true);
-			HA2 = md5(A2, true);
-
-			KD = HA1..":"..response["nonce"]..":"..response["nc"]..":"..response["cnonce"]..":"..response["qop"]..":"..HA2
-			local rspauth = md5(KD, true);
-			self.authenticated = true;
-			return "challenge", serialize({rspauth = rspauth});
-		else
-			return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."
-		end
-	elseif self.step == 3 then
-		if self.authenticated ~= nil then return "success"
-		else return "failure", "malformed-request" end
-	end
-end
+-- load the mechanisms
+require "sasl.plain"
+require "sasl.digest-md5"
+require "sasl.scram"
 
 return _M;

mercurial