mod_auth_internal_ng/mod_auth_internal_ng.lua
changeset 1593 3e4d15ae2133
equal deleted inserted replaced
1592:47fb4f36dacd 1593:3e4d15ae2133
       
     1 -- Prosody IM
       
     2 -- Copyright (C) 2008-2010 Matthew Wild
       
     3 -- Copyright (C) 2008-2010 Waqas Hussain
       
     4 -- Copyright (C) 2014 Kim Alvefur
       
     5 --
       
     6 -- This project is MIT/X11 licensed. Please see the
       
     7 -- COPYING file in the source package for more information.
       
     8 --
       
     9 
       
    10 local new_sasl = require "util.sasl".new;
       
    11 local random_bytes = require"util.random".bytes;
       
    12 local rfc5803 = require"util.rfc5803";
       
    13 local scram = require "util.sasl.scram";
       
    14 local hex = require"util.hex";
       
    15 
       
    16 local mode = module:get_option_string("store_credentials", "hashed");
       
    17 local default_i = module:get_option_number("default_iteration_count", 2^12);
       
    18 
       
    19 local accounts = module:open_store("accounts");
       
    20 
       
    21 local function hashify(account)
       
    22 	local i = default_i;
       
    23 	local password = account.password;
       
    24 
       
    25 	if account.hashedPassword then
       
    26 		if not password then return end -- Already hashed
       
    27 		local _, old_i = rfc5803.unpack(account.hashedPassword);
       
    28 		if old_i > i then i = old_i; end
       
    29 	end
       
    30 	local salt = random_bytes(16);
       
    31 	local ok, stored_key, server_key = scram.getAuthenticationDatabaseSHA1(password, salt, i);
       
    32 	if not ok then return nil, stored_key; end
       
    33 	account.hashedPassword = rfc5803.pack("SHA-1", i, salt, stored_key, server_key);
       
    34 	account.password = nil;
       
    35 	account.iteration_count, account.salt = nil, nil;
       
    36 	account.stored_key, account.server_key = nil, nil;
       
    37 	return account;
       
    38 end
       
    39 
       
    40 local function get_scram_hash(account)
       
    41 	if account.hashedPassword then
       
    42 		return rfc5803.unpack(account.hashedPassword);
       
    43 	elseif account.stored_key then
       
    44 		return "SHA-1", account.iteration_count, account.salt,
       
    45 			hex.from(account.stored_key), hex.from(account.server_key);
       
    46 	end
       
    47 end
       
    48 
       
    49 function user_exists(username)
       
    50 	local account, err = accounts:get(username);
       
    51 	if not account then return account, err; end
       
    52 	return next(account) ~= nil;
       
    53 end
       
    54 
       
    55 function create_user(username, password)
       
    56 	local account = { password = password };
       
    57 	if mode == "hashed" then
       
    58 		hashify(account);
       
    59 	end
       
    60 	return accounts:set(username, account);
       
    61 end
       
    62 
       
    63 function delete_user(username)
       
    64 	return accounts:set(username, nil);
       
    65 end
       
    66 
       
    67 function test_password(username, password)
       
    68 	local account, err = accounts:get(username);
       
    69 	if not account then return account, err; end
       
    70 	if account.password then
       
    71 		return password == account.password;
       
    72 	end
       
    73 	local hash, i, salt, our_stored_key, our_server_key = get_scram_hash(account);
       
    74 	local ok, stored_key, server_key = scram.getAuthenticationDatabaseSHA1(password, salt, i);
       
    75 	if not ok then return ok, stored_key; end
       
    76 	ok = hash == "SHA-1" and stored_key == our_stored_key and server_key == our_server_key;
       
    77 	if ok and mode == "unhash" then
       
    78 		account.password, account.hashedPassword = password;
       
    79 		accounts:set(username, account);
       
    80 	end
       
    81 	return ok;
       
    82 end
       
    83 
       
    84 local sasl_profile = {};
       
    85 
       
    86 function get_sasl_handler()
       
    87 	return new_sasl(module.host, sasl_profile);
       
    88 end
       
    89 
       
    90 function set_password(username, password)
       
    91 	local account, err = accounts:get(username);
       
    92 	if not account then account = {}; end
       
    93 	account.password = password;
       
    94 	if mode == "hashed" then
       
    95 		account, err = hashify(account);
       
    96 	end
       
    97 	if not account then return account, err; end
       
    98 	return accounts:set(username, account);
       
    99 end
       
   100 
       
   101 if mode == "plain" then
       
   102 	function get_password(username)
       
   103 		local account, err = accounts:get(username);
       
   104 		if not account then return nil, err; end
       
   105 		return account.password;
       
   106 	end
       
   107 
       
   108 	function sasl_profile:plain(username)
       
   109 		return get_password(username), true;
       
   110 	end
       
   111 elseif mode == "unhash" then
       
   112 	function sasl_profile:plain_test(username, password)
       
   113 		local ok = test_password(username, password);
       
   114 		if ok then
       
   115 			set_password(username, password);
       
   116 		end
       
   117 		return ok, true;
       
   118 	end
       
   119 elseif mode == "hashed" then
       
   120 	function sasl_profile:plain_test(username, password)
       
   121 		return test_password(username, password), true;
       
   122 	end
       
   123 
       
   124 	function sasl_profile:scram_sha_1(username)
       
   125 		local account, err = accounts:get(username);
       
   126 		if not account then return account, err; end
       
   127 		if not account.hashedPassword and hashify(account) then
       
   128 			accounts:set(username, account);
       
   129 		end
       
   130 		local hash, i, salt, stored_key, server_key = get_scram_hash(account);
       
   131 		if hash == "SHA-1" then
       
   132 			return stored_key, server_key, i, salt, true;
       
   133 		end
       
   134 	end
       
   135 else
       
   136 	module:log("error", "Unsupported store_credentials mode %q", mode);
       
   137 	return;
       
   138 end
       
   139 
       
   140 if accounts.users then
       
   141 	function users()
       
   142 		return accounts:users();
       
   143 	end
       
   144 end
       
   145 
       
   146 module:provides "auth";
       
   147