30 --SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10 |
30 --SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10 |
31 |
31 |
32 --[[ |
32 --[[ |
33 Supported Authentication Backends |
33 Supported Authentication Backends |
34 |
34 |
35 scram-{MECH}: |
35 scram_{MECH}: |
|
36 -- MECH being a standard hash name (like those at IANA's hash registry) with '-' replaced with '_' |
36 function(username, realm) |
37 function(username, realm) |
37 return salted_password, iteration_count, salt, state; |
38 return salted_password, iteration_count, salt, state; |
38 end |
39 end |
39 ]] |
40 ]] |
40 |
41 |
88 username = username:gsub("=3D", "="); |
89 username = username:gsub("=3D", "="); |
89 |
90 |
90 -- apply SASLprep |
91 -- apply SASLprep |
91 username = saslprep(username); |
92 username = saslprep(username); |
92 return username; |
93 return username; |
|
94 end |
|
95 |
|
96 local function hashprep( hashname ) |
|
97 local hash = hashname:lower() |
|
98 hash = hash:gsub("-", "_") |
|
99 return hash |
93 end |
100 end |
94 |
101 |
95 function saltedPasswordSHA1(password, salt, iteration_count) |
102 function saltedPasswordSHA1(password, salt, iteration_count) |
96 local salted_password |
103 local salted_password |
97 if type(password) ~= "string" or type(salt) ~= "string" or type(iteration_count) ~= "number" then |
104 if type(password) ~= "string" or type(salt) ~= "string" or type(iteration_count) ~= "number" then |
154 succ, self.state.salted_password = saltedPasswordSHA1(password, self.state.salt, default_i, self.state.iteration_count); |
161 succ, self.state.salted_password = saltedPasswordSHA1(password, self.state.salt, default_i, self.state.iteration_count); |
155 if not succ then |
162 if not succ then |
156 log("error", "Generating salted password failed. Reason: %s", self.state.salted_password); |
163 log("error", "Generating salted password failed. Reason: %s", self.state.salted_password); |
157 return "failure", "temporary-auth-failure"; |
164 return "failure", "temporary-auth-failure"; |
158 end |
165 end |
159 elseif self.profile["scram_"..hash_name] then |
166 elseif self.profile["scram_"..hashprep(hash_name)] then |
160 local salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm); |
167 local salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm); |
161 if state == nil then return "failure", "not-authorized" |
168 if state == nil then return "failure", "not-authorized" |
162 elseif state == false then return "failure", "account-disabled" end |
169 elseif state == false then return "failure", "account-disabled" end |
163 |
170 |
164 self.state.salted_password = salted_password; |
171 self.state.salted_password = salted_password; |
204 return scram_hash; |
211 return scram_hash; |
205 end |
212 end |
206 |
213 |
207 function init(registerMechanism) |
214 function init(registerMechanism) |
208 local function registerSCRAMMechanism(hash_name, hash, hmac_hash) |
215 local function registerSCRAMMechanism(hash_name, hash, hmac_hash) |
209 registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hash_name:lower())}, scram_gen(hash_name:lower(), hash, hmac_hash)); |
216 registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash)); |
210 end |
217 end |
211 |
218 |
212 registerSCRAMMechanism("SHA-1", sha1, hmac_sha1); |
219 registerSCRAMMechanism("SHA-1", sha1, hmac_sha1); |
213 end |
220 end |
214 |
221 |