Merge 0.9->0.10
[prosody.git] / util / sasl / plain.lua
1 -- sasl.lua v0.4
2 -- Copyright (C) 2008-2010 Tobias Markmann
3 --
4 --    All rights reserved.
5 --
6 --    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7 --
8 --        * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9 --        * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10 --        * Neither the name of Tobias Markmann nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 --
12 --    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13
14 local s_match = string.match;
15 local saslprep = require "util.encodings".stringprep.saslprep;
16 local nodeprep = require "util.encodings".stringprep.nodeprep;
17 local log = require "util.logger".init("sasl");
18
19 local _ENV = nil;
20
21 -- ================================
22 -- SASL PLAIN according to RFC 4616
23
24 --[[
25 Supported Authentication Backends
26
27 plain:
28         function(username, realm)
29                 return password, state;
30         end
31
32 plain_test:
33         function(username, password, realm)
34                 return true or false, state;
35         end
36 ]]
37
38 local function plain(self, message)
39         if not message then
40                 return "failure", "malformed-request";
41         end
42
43         local authorization, authentication, password = s_match(message, "^([^%z]*)%z([^%z]+)%z([^%z]+)");
44
45         if not authorization then
46                 return "failure", "malformed-request";
47         end
48
49         -- SASLprep password and authentication
50         authentication = saslprep(authentication);
51         password = saslprep(password);
52
53         if (not password) or (password == "") or (not authentication) or (authentication == "") then
54                 log("debug", "Username or password violates SASLprep.");
55                 return "failure", "malformed-request", "Invalid username or password.";
56         end
57
58         local _nodeprep = self.profile.nodeprep;
59         if _nodeprep ~= false then
60                 authentication = (_nodeprep or nodeprep)(authentication);
61                 if not authentication or authentication == "" then
62                         return "failure", "malformed-request", "Invalid username or password."
63                 end
64         end
65
66         local correct, state = false, false;
67         if self.profile.plain then
68                 local correct_password;
69                 correct_password, state = self.profile.plain(self, authentication, self.realm);
70                 correct = (correct_password == password);
71         elseif self.profile.plain_test then
72                 correct, state = self.profile.plain_test(self, authentication, password, self.realm);
73         end
74
75         self.username = authentication
76         if state == false then
77                 return "failure", "account-disabled";
78         elseif state == nil or not correct then
79                 return "failure", "not-authorized", "Unable to authorize you with the authentication credentials you've sent.";
80         end
81
82         return "success";
83 end
84
85 local function init(registerMechanism)
86         registerMechanism("PLAIN", {"plain", "plain_test"}, plain);
87 end
88
89 return {
90         init = init;
91 }