2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 -- Copyright (C) 2010 Jeff Mitchell
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
12 local getAuthenticationDatabaseSHA1
= require
"util.sasl.scram".getAuthenticationDatabaseSHA1
;
13 local usermanager
= require
"core.usermanager";
14 local generate_uuid
= require
"util.uuid".generate
;
15 local new_sasl
= require
"util.sasl".new
;
16 local hex
= require
"util.hex";
17 local to_hex
, from_hex
= hex
.to
, hex
.from
;
19 local log = module
._log
;
20 local host
= module
.host
;
22 local accounts
= module
:open_store("accounts");
26 -- Default; can be set per-user
27 local default_iteration_count
= 4096;
29 -- define auth provider
32 function provider
.test_password(username
, password
)
33 log("debug", "test password for user '%s'", username
);
34 local credentials
= accounts
:get(username
) or {};
36 if credentials
.password
~= nil and string.len(credentials
.password
) ~= 0 then
37 if credentials
.password
~= password
then
38 return nil, "Auth failed. Provided password is incorrect.";
41 if provider
.set_password(username
, credentials
.password
) == nil then
42 return nil, "Auth failed. Could not set hashed password from plaintext.";
48 if credentials
.iteration_count
== nil or credentials
.salt
== nil or string.len(credentials
.salt
) == 0 then
49 return nil, "Auth failed. Stored salt and iteration count information is not complete.";
52 local valid
, stored_key
, server_key
= getAuthenticationDatabaseSHA1(password
, credentials
.salt
, credentials
.iteration_count
);
54 local stored_key_hex
= to_hex(stored_key
);
55 local server_key_hex
= to_hex(server_key
);
57 if valid
and stored_key_hex
== credentials
.stored_key
and server_key_hex
== credentials
.server_key
then
60 return nil, "Auth failed. Invalid username, password, or password hash information.";
64 function provider
.set_password(username
, password
)
65 log("debug", "set_password for username '%s'", username
);
66 local account
= accounts
:get(username
);
68 account
.salt
= generate_uuid();
69 account
.iteration_count
= max(account
.iteration_count
or 0, default_iteration_count
);
70 local valid
, stored_key
, server_key
= getAuthenticationDatabaseSHA1(password
, account
.salt
, account
.iteration_count
);
71 local stored_key_hex
= to_hex(stored_key
);
72 local server_key_hex
= to_hex(server_key
);
74 account
.stored_key
= stored_key_hex
75 account
.server_key
= server_key_hex
77 account
.password
= nil;
78 return accounts
:set(username
, account
);
80 return nil, "Account not available.";
83 function provider
.user_exists(username
)
84 local account
= accounts
:get(username
);
86 log("debug", "account not found for username '%s'", username
);
87 return nil, "Auth failed. Invalid username";
92 function provider
.users()
93 return accounts
:users();
96 function provider
.create_user(username
, password
)
97 if password
== nil then
98 return accounts
:set(username
, {});
100 local salt
= generate_uuid();
101 local valid
, stored_key
, server_key
= getAuthenticationDatabaseSHA1(password
, salt
, default_iteration_count
);
102 local stored_key_hex
= to_hex(stored_key
);
103 local server_key_hex
= to_hex(server_key
);
104 return accounts
:set(username
, {
105 stored_key
= stored_key_hex
, server_key
= server_key_hex
,
106 salt
= salt
, iteration_count
= default_iteration_count
110 function provider
.delete_user(username
)
111 return accounts
:set(username
, nil);
114 function provider
.get_sasl_handler()
115 local testpass_authentication_profile
= {
116 plain_test
= function(_
, username
, password
, realm
)
117 return usermanager
.test_password(username
, realm
, password
), true;
119 scram_sha_1
= function(_
, username
)
120 local credentials
= accounts
:get(username
);
121 if not credentials
then return; end
122 if credentials
.password
then
123 if provider
.set_password(username
, credentials
.password
) == nil then
124 return nil, "Auth failed. Could not set hashed password from plaintext.";
126 credentials
= accounts
:get(username
);
127 if not credentials
then return; end
130 local stored_key
, server_key
= credentials
.stored_key
, credentials
.server_key
;
131 local iteration_count
, salt
= credentials
.iteration_count
, credentials
.salt
;
132 stored_key
= stored_key
and from_hex(stored_key
);
133 server_key
= server_key
and from_hex(server_key
);
134 return stored_key
, server_key
, iteration_count
, salt
, true;
137 return new_sasl(host
, testpass_authentication_profile
);
140 module
:provides("auth", provider
);