mod_pubsub, util.pubsub: Support for fetching items
[prosody.git] / util / sasl / digest-md5.lua
index df0a5b476af80028b689d24f5c3a25fd2dedad6a..2837148ec4723270b92d11b30ac551299e230184 100644 (file)
@@ -1,5 +1,5 @@
 -- sasl.lua v0.4
--- Copyright (C) 2008-2009 Tobias Markmann
+-- Copyright (C) 2008-2010 Tobias Markmann
 --
 --    All rights reserved.
 --
@@ -24,14 +24,25 @@ local md5 = require "util.hashes".md5;
 local log = require "util.logger".init("sasl");
 local generate_uuid = require "util.uuid".generate;
 
-module "plain"
+module "digest-md5"
 
 --=========================
 --SASL DIGEST-MD5 according to RFC 2831
-local function digest_response()
-       
-       return response, A1, A2
-end
+
+--[[
+Supported Authentication Backends
+
+digest_md5:
+       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, domain, realm, encoding, digesthash)
+               return true or false, state;
+       end
+]]
 
 local function digest(self, message)
        --TODO complete support for authzid
@@ -39,8 +50,6 @@ local function digest(self, message)
        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
@@ -101,7 +110,8 @@ local function digest(self, message)
        end
        local function parse(data)
                local message = {}
-               for k, v in s_gmatch(data, [[([%w%-]+)="?([^",]*)"?,?]]) do -- FIXME The hacky regex makes me shudder
+               -- COMPAT: %z in the pattern to work around jwchat bug (sends "charset=utf-8\0")
+               for k, v in s_gmatch(data, [[([%w%-]+)="?([^",%z]*)"?,?]]) do -- FIXME The hacky regex makes me shudder
                        message[k] = v;
                end
                return message;
@@ -169,13 +179,16 @@ local function digest(self, message)
 
                --TODO maybe realm support
                self.username = response["username"];
+               local Y, state;
                if self.profile.plain then
                        local password, state = self.profile.plain(response["username"], self.realm)
                        if state == nil then return "failure", "not-authorized"
                        elseif state == false then return "failure", "account-disabled" end
                        Y = md5(response["username"]..":"..response["realm"]..":"..password);
                elseif self.profile["digest-md5"] then
-                       --local Y, state = self.profile["digest-md5"](response["username"], self.realm, response["charset"])
+                       Y, state = self.profile["digest-md5"](response["username"], self.realm, response["realm"], response["charset"])
+                       if state == nil then return "failure", "not-authorized"
+                       elseif state == false then return "failure", "account-disabled" end
                elseif self.profile["digest-md5-test"] then
                        -- TODO
                end
@@ -184,12 +197,12 @@ local function digest(self, message)
                --elseif Y == false then return "failure", "account-disabled" end
                local A1 = "";
                if response.authzid then
-                       if response.authzid == self.username.."@"..self.realm then
+                       if response.authzid == self.username or response.authzid == self.username.."@"..self.realm then
                                -- COMPAT
-                               log("warn", "Client is violating XMPP RFC. See section 6.1 of RFC 3920.");
+                               log("warn", "Client is violating RFC 3920 (section 6.1, point 7).");
                                A1 = Y..":"..response["nonce"]..":"..response["cnonce"]..":"..response.authzid;
                        else
-                               A1 = "?";
+                               return "failure", "invalid-authzid";
                        end
                else
                        A1 = Y..":"..response["nonce"]..":"..response["cnonce"];
@@ -212,6 +225,7 @@ local function digest(self, message)
                        KD = HA1..":"..response["nonce"]..":"..response["nc"]..":"..response["cnonce"]..":"..response["qop"]..":"..HA2
                        local rspauth = md5(KD, true);
                        self.authenticated = true;
+                       --TODO: considering sending the rspauth in a success node for saving one roundtrip; allowed according to http://tools.ietf.org/html/draft-saintandre-rfc3920bis-09#section-7.3.6
                        return "challenge", serialize({rspauth = rspauth});
                else
                        return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."