Store stage in SASL object.
authorTobias Markmann <tm@ayena.de>
Fri, 28 Aug 2009 20:01:58 +0000 (22:01 +0200)
committerTobias Markmann <tm@ayena.de>
Fri, 28 Aug 2009 20:01:58 +0000 (22:01 +0200)
util/sasl.lua

index 6fd45ce1552786ee2185c94205498c1757d0b3d7..6b14c1b1b83e87082fc45986e2fe17a6577b3a79 100644 (file)
@@ -151,7 +151,7 @@ registerMechanism("PLAIN", {"plain", "plain_test"}, sasl_mechanism_plain);
 
 --=========================
 --SASL DIGEST-MD5 according to RFC 2831
-local function new_digest_md5(realm, credentials_handler)
+local function sasl_mechanism_digest_md5(self, message)
        --TODO complete support for authzid
 
        local function serialize(message)
@@ -225,112 +225,109 @@ local function new_digest_md5(realm, credentials_handler)
                return message;
        end
 
-       local object = { mechanism = "DIGEST-MD5", realm = realm, credentials_handler = credentials_handler};
-
-       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
+       if not self.nonce then
+               self.nonce = generate_uuid();
+               self.step = 0;
+               self.nonce_count = {};
+       end
 
-                       -- check for username, it's REQUIRED by RFC 2831
-                       if not response["username"] then
-                               return "failure", "malformed-request";
-                       end
-                       self["username"] = response["username"];
+       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 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
+               -- 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 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
+               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 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
+               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
+               --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 = Y..":"..response["nonce"]..":"..response["cnonce"];
+                               A1 = "?";
                        end
-                       local A2 = "AUTHENTICATE:"..protocol.."/"..domain;
+               else
+                       A1 = Y..":"..response["nonce"]..":"..response["cnonce"];
+               end
+               local A2 = "AUTHENTICATE:"..protocol.."/"..domain;
 
-                       local HA1 = md5(A1, true);
-                       local HA2 = md5(A2, true);
+               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);
+               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;
+               if response_value == response["response"] then
+                       -- calculate rspauth
+                       A2 = ":"..protocol.."/"..domain;
 
-                               HA1 = md5(A1, true);
-                               HA2 = md5(A2, true);
+                       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
+                       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
-       return object;
 end
 
 return _M;