Software /
code /
prosody
Comparison
util/sasl.lua @ 1160:7e48324f946e
Some beauty treatment.
author | Tobias Markmann <tm@ayena.de> |
---|---|
date | Fri, 15 May 2009 17:28:22 +0200 |
parent | 1159:f81c8cec0e71 |
child | 1161:5bc2b7b5b81d |
comparison
equal
deleted
inserted
replaced
1159:f81c8cec0e71 | 1160:7e48324f946e |
---|---|
129 return t_concat(p); | 129 return t_concat(p); |
130 end | 130 end |
131 local function parse(data) | 131 local function parse(data) |
132 message = {} | 132 message = {} |
133 for k, v in gmatch(data, [[([%w%-]+)="?([^",]*)"?,?]]) do -- FIXME The hacky regex makes me shudder | 133 for k, v in gmatch(data, [[([%w%-]+)="?([^",]*)"?,?]]) do -- FIXME The hacky regex makes me shudder |
134 message[k] = v | 134 message[k] = v; |
135 end | 135 end |
136 return message | 136 return message; |
137 end | 137 end |
138 | 138 |
139 local object = { mechanism = "DIGEST-MD5", realm = realm, password_handler = password_handler} | 139 local object = { mechanism = "DIGEST-MD5", realm = realm, password_handler = password_handler}; |
140 | 140 |
141 --TODO: something better than math.random would be nice, maybe OpenSSL's random number generator | 141 --TODO: something better than math.random would be nice, maybe OpenSSL's random number generator |
142 object.nonce = generate_uuid() | 142 object.nonce = generate_uuid(); |
143 object.step = 0 | 143 object.step = 0; |
144 object.nonce_count = {} | 144 object.nonce_count = {}; |
145 | 145 |
146 function object.feed(self, message) | 146 function object.feed(self, message) |
147 self.step = self.step + 1 | 147 self.step = self.step + 1; |
148 if (self.step == 1) then | 148 if (self.step == 1) then |
149 local challenge = serialize({ nonce = object.nonce, | 149 local challenge = serialize({ nonce = object.nonce, |
150 qop = "auth", | 150 qop = "auth", |
151 charset = "utf-8", | 151 charset = "utf-8", |
152 algorithm = "md5-sess", | 152 algorithm = "md5-sess", |
153 realm = self.realm}); | 153 realm = self.realm}); |
154 return "challenge", challenge | 154 return "challenge", challenge; |
155 elseif (self.step == 2) then | 155 elseif (self.step == 2) then |
156 local response = parse(message) | 156 local response = parse(message); |
157 -- check for replay attack | 157 -- check for replay attack |
158 if response["nc"] then | 158 if response["nc"] then |
159 if self.nonce_count[response["nc"]] then return "failure", "not-authorized" end | 159 if self.nonce_count[response["nc"]] then return "failure", "not-authorized" end |
160 end | 160 end |
161 | 161 |
162 -- check for username, it's REQUIRED by RFC 2831 | 162 -- check for username, it's REQUIRED by RFC 2831 |
163 if not response["username"] then | 163 if not response["username"] then |
164 return "failure", "malformed-request" | 164 return "failure", "malformed-request"; |
165 end | 165 end |
166 self["username"] = response["username"] | 166 self["username"] = response["username"]; |
167 | 167 |
168 -- check for nonce, ... | 168 -- check for nonce, ... |
169 if not response["nonce"] then | 169 if not response["nonce"] then |
170 return "failure", "malformed-request" | 170 return "failure", "malformed-request"; |
171 else | 171 else |
172 -- check if it's the right nonce | 172 -- check if it's the right nonce |
173 if response["nonce"] ~= tostring(self.nonce) then return "failure", "malformed-request" end | 173 if response["nonce"] ~= tostring(self.nonce) then return "failure", "malformed-request" end |
174 end | 174 end |
175 | 175 |
184 | 184 |
185 local decoder; | 185 local decoder; |
186 if response["charset"] == nil then | 186 if response["charset"] == nil then |
187 decoder = utf8tolatin1ifpossible; | 187 decoder = utf8tolatin1ifpossible; |
188 elseif response["charset"] ~= "utf-8" then | 188 elseif response["charset"] ~= "utf-8" then |
189 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." | 189 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."; |
190 end | 190 end |
191 | 191 |
192 local domain = "" | 192 local domain = ""; |
193 local protocol = "" | 193 local protocol = ""; |
194 if response["digest-uri"] then | 194 if response["digest-uri"] then |
195 protocol, domain = response["digest-uri"]:match("(%w+)/(.*)$") | 195 protocol, domain = response["digest-uri"]:match("(%w+)/(.*)$"); |
196 if protocol == nil or domain == nil then return "failure", "malformed-request" end | 196 if protocol == nil or domain == nil then return "failure", "malformed-request" end |
197 else | 197 else |
198 return "failure", "malformed-request", "Missing entry for digest-uri in SASL message." | 198 return "failure", "malformed-request", "Missing entry for digest-uri in SASL message." |
199 end | 199 end |
200 | 200 |
201 --TODO maybe realm support | 201 --TODO maybe realm support |
202 self.username = response["username"] | 202 self.username = response["username"]; |
203 local password_encoding, Y = self.password_handler(response["username"], response["realm"], "DIGEST-MD5", decoder) | 203 local password_encoding, Y = self.password_handler(response["username"], response["realm"], "DIGEST-MD5", decoder) |
204 if Y == nil then return "failure", "not-authorized" | 204 if Y == nil then return "failure", "not-authorized" |
205 elseif Y == false then return "failure", "account-disabled" end | 205 elseif Y == false then return "failure", "account-disabled" end |
206 local A1 = ""; | 206 local A1 = ""; |
207 if response.authzid then | 207 if response.authzid then |
214 else | 214 else |
215 A1 = Y..":"..response["nonce"]..":"..response["cnonce"]; | 215 A1 = Y..":"..response["nonce"]..":"..response["cnonce"]; |
216 end | 216 end |
217 local A2 = "AUTHENTICATE:"..protocol.."/"..domain; | 217 local A2 = "AUTHENTICATE:"..protocol.."/"..domain; |
218 | 218 |
219 local HA1 = md5(A1, true) | 219 local HA1 = md5(A1, true); |
220 local HA2 = md5(A2, true) | 220 local HA2 = md5(A2, true); |
221 | 221 |
222 local KD = HA1..":"..response["nonce"]..":"..response["nc"]..":"..response["cnonce"]..":"..response["qop"]..":"..HA2 | 222 local KD = HA1..":"..response["nonce"]..":"..response["nc"]..":"..response["cnonce"]..":"..response["qop"]..":"..HA2; |
223 local response_value = md5(KD, true) | 223 local response_value = md5(KD, true); |
224 | 224 |
225 if response_value == response["response"] then | 225 if response_value == response["response"] then |
226 -- calculate rspauth | 226 -- calculate rspauth |
227 A2 = ":"..protocol.."/"..domain; | 227 A2 = ":"..protocol.."/"..domain; |
228 | 228 |
229 HA1 = md5(A1, true) | 229 HA1 = md5(A1, true); |
230 HA2 = md5(A2, true) | 230 HA2 = md5(A2, true); |
231 | 231 |
232 KD = HA1..":"..response["nonce"]..":"..response["nc"]..":"..response["cnonce"]..":"..response["qop"]..":"..HA2 | 232 KD = HA1..":"..response["nonce"]..":"..response["nc"]..":"..response["cnonce"]..":"..response["qop"]..":"..HA2 |
233 local rspauth = md5(KD, true) | 233 local rspauth = md5(KD, true); |
234 self.authenticated = true | 234 self.authenticated = true; |
235 return "challenge", serialize({rspauth = rspauth}) | 235 return "challenge", serialize({rspauth = rspauth}); |
236 else | 236 else |
237 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated." | 237 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated." |
238 end | 238 end |
239 elseif self.step == 3 then | 239 elseif self.step == 3 then |
240 if self.authenticated ~= nil then return "success" | 240 if self.authenticated ~= nil then return "success" |
241 else return "failure", "malformed-request" end | 241 else return "failure", "malformed-request" end |
242 end | 242 end |
243 end | 243 end |
244 return object | 244 return object; |
245 end | 245 end |
246 | 246 |
247 local function new_anonymous(realm, password_handler) | 247 local function new_anonymous(realm, password_handler) |
248 local object = { mechanism = "ANONYMOUS", realm = realm, password_handler = password_handler} | 248 local object = { mechanism = "ANONYMOUS", realm = realm, password_handler = password_handler} |
249 function object.feed(self, message) | 249 function object.feed(self, message) |