12 local type = type; |
12 local type = type; |
13 local error = error; |
13 local error = error; |
14 local ipairs = ipairs; |
14 local ipairs = ipairs; |
15 local hashes = require "util.hashes"; |
15 local hashes = require "util.hashes"; |
16 local jid_bare = require "util.jid".bare; |
16 local jid_bare = require "util.jid".bare; |
17 local saltedPasswordSHA1 = require "util.sasl.scram".saltedPasswordSHA1; |
17 local getAuthenticationDatabaseSHA1 = require "util.sasl.scram".getAuthenticationDatabaseSHA1; |
18 local config = require "core.configmanager"; |
18 local config = require "core.configmanager"; |
19 local usermanager = require "core.usermanager"; |
19 local usermanager = require "core.usermanager"; |
20 local generate_uuid = require "util.uuid".generate; |
20 local generate_uuid = require "util.uuid".generate; |
21 local new_sasl = require "util.sasl".new; |
21 local new_sasl = require "util.sasl".new; |
22 local nodeprep = require "util.encodings".stringprep.nodeprep; |
22 local nodeprep = require "util.encodings".stringprep.nodeprep; |
23 local hosts = hosts; |
23 local hosts = hosts; |
|
24 |
|
25 -- TODO: remove these two lines in near future |
|
26 local hmac_sha1 = require "util.hmac".sha1; |
|
27 local sha1 = require "util.hashes".sha1; |
24 |
28 |
25 local prosody = _G.prosody; |
29 local prosody = _G.prosody; |
26 |
30 |
27 local is_cyrus = usermanager.is_cyrus; |
31 local is_cyrus = usermanager.is_cyrus; |
28 |
32 |
50 end |
54 end |
51 |
55 |
52 if credentials.iteration_count == nil or credentials.salt == nil or string.len(credentials.salt) == 0 then |
56 if credentials.iteration_count == nil or credentials.salt == nil or string.len(credentials.salt) == 0 then |
53 return nil, "Auth failed. Stored salt and iteration count information is not complete."; |
57 return nil, "Auth failed. Stored salt and iteration count information is not complete."; |
54 end |
58 end |
55 |
59 |
56 local valid, binpass = saltedPasswordSHA1(password, credentials.salt, credentials.iteration_count); |
60 local valid, stored_key, server_key |
57 local hexpass = binpass:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
61 |
58 |
62 -- convert hexpass to stored_key and server_key |
59 if valid and hexpass == credentials.hashpass then |
63 -- TODO: remove this in near future |
|
64 if credentials.hashpass then |
|
65 valid = true; |
|
66 local salted_password = credentials.hashpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); |
|
67 credentials.stored_key = sha1(hmac_sha1(salted_password, "Client Key")):gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
|
68 credentials.server_key = hmac_sha1(salted_password, "Server Key"):gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
|
69 credentials.hashpass = nil |
|
70 datamanager.store(username, host, "accounts", credentials); |
|
71 end |
|
72 |
|
73 local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); |
|
74 |
|
75 local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
|
76 local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
|
77 |
|
78 if valid and stored_key_hex == credentials.stored_key and server_key_hex == credentials.server_key then |
60 return true; |
79 return true; |
61 else |
80 else |
62 return nil, "Auth failed. Invalid username, password, or password hash information."; |
81 return nil, "Auth failed. Invalid username, password, or password hash information."; |
63 end |
82 end |
64 end |
83 end |
65 |
84 |
66 function provider.set_password(username, password) |
85 function provider.set_password(username, password) |
67 if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end |
86 if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end |
68 local account = datamanager.load(username, host, "accounts"); |
87 local account = datamanager.load(username, host, "accounts"); |
69 if account then |
88 if account then |
70 if account.iteration_count == nil then |
89 account.salt = account.salt or generate_uuid(); |
71 account.iteration_count = iteration_count; |
90 account.iteration_count = account.iteration_count or iteration_count; |
72 end |
91 local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, account.salt, account.iteration_count); |
73 |
92 local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
74 if account.salt == nil then |
93 local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
75 account.salt = generate_uuid(); |
94 |
76 end |
95 account.stored_key = stored_key_hex |
77 |
96 account.server_key = server_key_hex |
78 local valid, binpass = saltedPasswordSHA1(password, account.salt, account.iteration_count); |
|
79 local hexpass = binpass:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
|
80 account.hashpass = hexpass; |
|
81 |
97 |
82 account.password = nil; |
98 account.password = nil; |
83 return datamanager.store(username, host, "accounts", account); |
99 return datamanager.store(username, host, "accounts", account); |
84 end |
100 end |
85 return nil, "Account not available."; |
101 return nil, "Account not available."; |
100 end |
116 end |
101 |
117 |
102 function provider.create_user(username, password) |
118 function provider.create_user(username, password) |
103 if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end |
119 if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end |
104 local salt = generate_uuid(); |
120 local salt = generate_uuid(); |
105 local valid, binpass = saltedPasswordSHA1(password, salt, iteration_count); |
121 local valid, stored_key, server_key = saltedPasswordSHA1(password, salt, iteration_count); |
106 local hexpass = binpass:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
122 local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
107 return datamanager.store(username, host, "accounts", {hashpass = hexpass, salt = salt, iteration_count = iteration_count}); |
123 local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
|
124 return datamanager.store(username, host, "accounts", {stored_key = stored_key_hex, server_key = server_key_hex, salt = salt, iteration_count = iteration_count}); |
108 end |
125 end |
109 |
126 |
110 function provider.get_sasl_handler() |
127 function provider.get_sasl_handler() |
111 local realm = module:get_option("sasl_realm") or module.host; |
128 local realm = module:get_option("sasl_realm") or module.host; |
112 local testpass_authentication_profile = { |
129 local testpass_authentication_profile = { |
122 local credentials = datamanager.load(username, host, "accounts") or {}; |
139 local credentials = datamanager.load(username, host, "accounts") or {}; |
123 if credentials.password then |
140 if credentials.password then |
124 usermanager.set_password(username, credentials.password, host); |
141 usermanager.set_password(username, credentials.password, host); |
125 credentials = datamanager.load(username, host, "accounts") or {}; |
142 credentials = datamanager.load(username, host, "accounts") or {}; |
126 end |
143 end |
127 local salted_password, iteration_count, salt = credentials.hashpass, credentials.iteration_count, credentials.salt; |
144 |
128 salted_password = salted_password and salted_password:gsub("..", function(x) return string.char(tonumber(x, 16)); end); |
145 -- convert hexpass to stored_key and server_key |
129 return salted_password, iteration_count, salt, true; |
146 -- TODO: remove this in near future |
|
147 if credentials.hashpass then |
|
148 local salted_password = credentials.hashpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); |
|
149 credentials.stored_key = sha1(hmac_sha1(salted_password, "Client Key")):gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
|
150 credentials.server_key = hmac_sha1(salted_password, "Server Key"):gsub(".", function (c) return ("%02x"):format(c:byte()); end); |
|
151 credentials.hashpass = nil |
|
152 datamanager.store(username, host, "accounts", credentials); |
|
153 end |
|
154 |
|
155 local stored_key, server_key, iteration_count, salt = credentials.stored_key, credentials.server_key, credentials.iteration_count, credentials.salt; |
|
156 stored_key = stored_key and stored_key:gsub("..", function(x) return string.char(tonumber(x, 16)); end); |
|
157 server_key = server_key and server_key:gsub("..", function(x) return string.char(tonumber(x, 16)); end); |
|
158 return stored_key, server_key, iteration_count, salt, true; |
130 end |
159 end |
131 }; |
160 }; |
132 return new_sasl(realm, testpass_authentication_profile); |
161 return new_sasl(realm, testpass_authentication_profile); |
133 end |
162 end |
134 |
163 |