move to emqtt/emq_auth_username plugin
This commit is contained in:
parent
f1d9f7cd49
commit
bf075a125b
|
@ -1,164 +0,0 @@
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
|
|
||||||
%%
|
|
||||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
%% you may not use this file except in compliance with the License.
|
|
||||||
%% You may obtain a copy of the License at
|
|
||||||
%%
|
|
||||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
%%
|
|
||||||
%% Unless required by applicable law or agreed to in writing, software
|
|
||||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
%% See the License for the specific language governing permissions and
|
|
||||||
%% limitations under the License.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
|
|
||||||
%% @doc Authentication with username and password
|
|
||||||
-module(emqttd_auth_username).
|
|
||||||
|
|
||||||
-include("emqttd.hrl").
|
|
||||||
|
|
||||||
-include("emqttd_cli.hrl").
|
|
||||||
|
|
||||||
%% CLI callbacks
|
|
||||||
-export([cli/1]).
|
|
||||||
|
|
||||||
-behaviour(emqttd_auth_mod).
|
|
||||||
|
|
||||||
-export([is_enabled/0]).
|
|
||||||
|
|
||||||
-export([add_user/2, remove_user/1, lookup_user/1, all_users/0]).
|
|
||||||
|
|
||||||
%% emqttd_auth callbacks
|
|
||||||
-export([init/1, check/3, description/0]).
|
|
||||||
|
|
||||||
-define(AUTH_USERNAME_TAB, mqtt_auth_username).
|
|
||||||
|
|
||||||
-record(?AUTH_USERNAME_TAB, {username, password}).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% CLI
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
cli(["list"]) ->
|
|
||||||
if_enabled(fun() ->
|
|
||||||
Usernames = mnesia:dirty_all_keys(?AUTH_USERNAME_TAB),
|
|
||||||
[?PRINT("~s~n", [Username]) || Username <- Usernames]
|
|
||||||
end);
|
|
||||||
|
|
||||||
cli(["add", Username, Password]) ->
|
|
||||||
if_enabled(fun() ->
|
|
||||||
?PRINT("~p~n", [add_user(iolist_to_binary(Username), iolist_to_binary(Password))])
|
|
||||||
end);
|
|
||||||
|
|
||||||
cli(["del", Username]) ->
|
|
||||||
if_enabled(fun() ->
|
|
||||||
?PRINT("~p~n", [remove_user(iolist_to_binary(Username))])
|
|
||||||
end);
|
|
||||||
|
|
||||||
cli(_) ->
|
|
||||||
?USAGE([{"users list", "List users"},
|
|
||||||
{"users add <Username> <Password>", "Add User"},
|
|
||||||
{"users del <Username>", "Delete User"}]).
|
|
||||||
|
|
||||||
if_enabled(Fun) ->
|
|
||||||
case is_enabled() of
|
|
||||||
true -> Fun();
|
|
||||||
false -> hint()
|
|
||||||
end.
|
|
||||||
|
|
||||||
hint() ->
|
|
||||||
?PRINT_MSG("Please enable '{auth, username, []}' in etc/emqttd.conf first.~n").
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% API
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
|
|
||||||
is_enabled() ->
|
|
||||||
lists:member(?AUTH_USERNAME_TAB, mnesia:system_info(tables)).
|
|
||||||
|
|
||||||
%% @doc Add User
|
|
||||||
-spec(add_user(binary(), binary()) -> ok | {error, any()}).
|
|
||||||
add_user(Username, Password) ->
|
|
||||||
User = #?AUTH_USERNAME_TAB{username = Username, password = hash(Password)},
|
|
||||||
ret(mnesia:transaction(fun insert_user/1, [User])).
|
|
||||||
|
|
||||||
insert_user(User = #?AUTH_USERNAME_TAB{username = Username}) ->
|
|
||||||
case mnesia:read(?AUTH_USERNAME_TAB, Username) of
|
|
||||||
[] -> mnesia:write(User);
|
|
||||||
[_|_] -> mnesia:abort(existed)
|
|
||||||
end.
|
|
||||||
|
|
||||||
add_default_user(Username, Password) when is_atom(Username) ->
|
|
||||||
add_default_user(atom_to_list(Username), Password);
|
|
||||||
|
|
||||||
add_default_user(Username, Password) ->
|
|
||||||
add_user(iolist_to_binary(Username), iolist_to_binary(Password)).
|
|
||||||
|
|
||||||
%% @doc Lookup user by username
|
|
||||||
-spec(lookup_user(binary()) -> list()).
|
|
||||||
lookup_user(Username) ->
|
|
||||||
mnesia:dirty_read(?AUTH_USERNAME_TAB, Username).
|
|
||||||
|
|
||||||
%% @doc Remove user
|
|
||||||
-spec(remove_user(binary()) -> ok | {error, any()}).
|
|
||||||
remove_user(Username) ->
|
|
||||||
ret(mnesia:transaction(fun mnesia:delete/1, [{?AUTH_USERNAME_TAB, Username}])).
|
|
||||||
|
|
||||||
ret({atomic, ok}) -> ok;
|
|
||||||
ret({aborted, Error}) -> {error, Error}.
|
|
||||||
|
|
||||||
%% @doc All usernames
|
|
||||||
-spec(all_users() -> list()).
|
|
||||||
all_users() -> mnesia:dirty_all_keys(?AUTH_USERNAME_TAB).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% emqttd_auth_mod callbacks
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
|
|
||||||
init(Opts) ->
|
|
||||||
mnesia:create_table(?AUTH_USERNAME_TAB, [
|
|
||||||
{disc_copies, [node()]},
|
|
||||||
{attributes, record_info(fields, ?AUTH_USERNAME_TAB)}]),
|
|
||||||
mnesia:add_table_copy(?AUTH_USERNAME_TAB, node(), disc_copies),
|
|
||||||
case proplists:get_value(passwd, Opts) of
|
|
||||||
undefined -> ok;
|
|
||||||
File -> {ok, DefaultUsers} = file:consult(File),
|
|
||||||
lists:foreach(fun({Username, Password}) ->
|
|
||||||
add_default_user(Username, Password)
|
|
||||||
end, DefaultUsers)
|
|
||||||
end,
|
|
||||||
emqttd_ctl:register_cmd(users, {?MODULE, cli}, []),
|
|
||||||
{ok, Opts}.
|
|
||||||
|
|
||||||
check(#mqtt_client{username = undefined}, _Password, _Opts) ->
|
|
||||||
{error, username_undefined};
|
|
||||||
check(_User, undefined, _Opts) ->
|
|
||||||
{error, password_undefined};
|
|
||||||
check(#mqtt_client{username = Username}, Password, _Opts) ->
|
|
||||||
case mnesia:dirty_read(?AUTH_USERNAME_TAB, Username) of
|
|
||||||
[] ->
|
|
||||||
{error, username_not_found};
|
|
||||||
[#?AUTH_USERNAME_TAB{password = <<Salt:4/binary, Hash/binary>>}] ->
|
|
||||||
case Hash =:= md5_hash(Salt, Password) of
|
|
||||||
true -> ok;
|
|
||||||
false -> {error, password_error}
|
|
||||||
end
|
|
||||||
end.
|
|
||||||
|
|
||||||
description() ->
|
|
||||||
"Username password authentication module".
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Internal functions
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
|
|
||||||
hash(Password) ->
|
|
||||||
SaltBin = salt(), <<SaltBin/binary, (md5_hash(SaltBin, Password))/binary>>.
|
|
||||||
|
|
||||||
md5_hash(SaltBin, Password) ->
|
|
||||||
erlang:md5(<<SaltBin/binary, Password/binary>>).
|
|
||||||
|
|
||||||
salt() ->
|
|
||||||
emqttd_time:seed(), Salt = rand:uniform(16#ffffffff), <<Salt:32>>.
|
|
||||||
|
|
Loading…
Reference in New Issue