17 local base64 = require "util.encodings".base64; |
17 local base64 = require "util.encodings".base64; |
18 local xor = require "bit".bxor |
18 local xor = require "bit".bxor |
19 local hmac_sha1 = require "util.hmac".sha1; |
19 local hmac_sha1 = require "util.hmac".sha1; |
20 local sha1 = require "util.hashes".sha1; |
20 local sha1 = require "util.hashes".sha1; |
21 local generate_uuid = require "util.uuid".generate; |
21 local generate_uuid = require "util.uuid".generate; |
|
22 local saslprep = require "util.encodings".stringprep.saslprep; |
|
23 local log = require "util.logger".init("sasl"); |
22 |
24 |
23 module "plain" |
25 module "plain" |
24 |
26 |
25 --========================= |
27 --========================= |
26 --SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10 |
28 --SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10 |
81 local client_first_message = message; |
84 local client_first_message = message; |
82 self.state["client_first_message"] = client_first_message; |
85 self.state["client_first_message"] = client_first_message; |
83 self.state["name"] = client_first_message:match("n=(.+),r=") |
86 self.state["name"] = client_first_message:match("n=(.+),r=") |
84 self.state["clientnonce"] = client_first_message:match("r=([^,]+)") |
87 self.state["clientnonce"] = client_first_message:match("r=([^,]+)") |
85 |
88 |
86 self.state.name = validate_username(self.state.name); |
|
87 if not self.state.name or not self.state.clientnonce then |
89 if not self.state.name or not self.state.clientnonce then |
88 return "failure", "malformed-request"; |
90 return "failure", "malformed-request"; |
89 end |
91 end |
|
92 |
|
93 self.state.name = validate_username(self.state.name); |
|
94 if not self.state.name then |
|
95 log("debug", "Username violates either SASLprep or contains forbidden character sequences.") |
|
96 return "failure", "malformed-request"; |
|
97 end |
|
98 |
90 self.state["servernonce"] = generate_uuid(); |
99 self.state["servernonce"] = generate_uuid(); |
91 self.state["salt"] = generate_uuid(); |
100 self.state["salt"] = generate_uuid(); |
92 |
101 |
93 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..default_i; |
102 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..default_i; |
94 self.state["server_first_message"] = server_first_message; |
103 self.state["server_first_message"] = server_first_message; |
108 local password; |
117 local password; |
109 if self.profile.plain then |
118 if self.profile.plain then |
110 password, state = self.profile.plain(self.state.name, self.realm) |
119 password, state = self.profile.plain(self.state.name, self.realm) |
111 if state == nil then return "failure", "not-authorized" |
120 if state == nil then return "failure", "not-authorized" |
112 elseif state == false then return "failure", "account-disabled" end |
121 elseif state == false then return "failure", "account-disabled" end |
|
122 password = saslprep(password); |
|
123 if not password then |
|
124 log("debug", "Password violates SASLprep."); |
|
125 return "failure", "not-authorized" |
|
126 end |
113 end |
127 end |
114 |
128 |
115 local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i) |
129 local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i) |
116 local ClientKey = hmac_sha1(SaltedPassword, "Client Key") |
130 local ClientKey = hmac_sha1(SaltedPassword, "Client Key") |
117 local ServerKey = hmac_sha1(SaltedPassword, "Server Key") |
131 local ServerKey = hmac_sha1(SaltedPassword, "Server Key") |