support Seq

This commit is contained in:
Feng 2015-11-03 12:52:27 +08:00
parent ea564ec8ef
commit 9bad2bf65b
2 changed files with 33 additions and 24 deletions

View File

@ -24,7 +24,6 @@
%%% %%%
%%% @end %%% @end
%%%----------------------------------------------------------------------------- %%%-----------------------------------------------------------------------------
-module(emqttd_access_control). -module(emqttd_access_control).
-author("Feng Lee <feng@emqtt.io>"). -author("Feng Lee <feng@emqtt.io>").
@ -36,14 +35,13 @@
-define(SERVER, ?MODULE). -define(SERVER, ?MODULE).
%% API Function Exports %% API Function Exports
-export([start_link/0, -export([start_link/0, start_link/1,
start_link/1,
auth/2, % authentication auth/2, % authentication
check_acl/3, % acl check check_acl/3, % acl check
reload_acl/0, % reload acl reload_acl/0, % reload acl
register_mod/3,
unregister_mod/2,
lookup_mods/1, lookup_mods/1,
register_mod/3, register_mod/4,
unregister_mod/2,
stop/0]). stop/0]).
%% gen_server callbacks %% gen_server callbacks
@ -77,7 +75,7 @@ auth(Client, Password) when is_record(Client, mqtt_client) ->
auth(Client, Password, lookup_mods(auth)). auth(Client, Password, lookup_mods(auth)).
auth(_Client, _Password, []) -> auth(_Client, _Password, []) ->
{error, "No auth module to check!"}; {error, "No auth module to check!"};
auth(Client, Password, [{Mod, State} | Mods]) -> auth(Client, Password, [{Mod, State, _Seq} | Mods]) ->
case Mod:check(Client, Password, State) of case Mod:check(Client, Password, State) of
ok -> ok; ok -> ok;
{error, Reason} -> {error, Reason}; {error, Reason} -> {error, Reason};
@ -100,7 +98,7 @@ check_acl(Client, PubSub, Topic) when ?IS_PUBSUB(PubSub) ->
check_acl(#mqtt_client{client_id = ClientId}, PubSub, Topic, []) -> check_acl(#mqtt_client{client_id = ClientId}, PubSub, Topic, []) ->
lager:error("ACL: nomatch when ~s ~s ~s", [ClientId, PubSub, Topic]), lager:error("ACL: nomatch when ~s ~s ~s", [ClientId, PubSub, Topic]),
allow; allow;
check_acl(Client, PubSub, Topic, [{M, State}|AclMods]) -> check_acl(Client, PubSub, Topic, [{M, State, _Seq}|AclMods]) ->
case M:check_acl({Client, PubSub, Topic}, State) of case M:check_acl({Client, PubSub, Topic}, State) of
allow -> allow; allow -> allow;
deny -> deny; deny -> deny;
@ -113,7 +111,7 @@ check_acl(Client, PubSub, Topic, [{M, State}|AclMods]) ->
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
-spec reload_acl() -> list() | {error, any()}. -spec reload_acl() -> list() | {error, any()}.
reload_acl() -> reload_acl() ->
[M:reload_acl(State) || {M, State} <- lookup_mods(acl)]. [M:reload_acl(State) || {M, State, _Seq} <- lookup_mods(acl)].
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% @doc Register authentication or ACL module %% @doc Register authentication or ACL module
@ -121,7 +119,11 @@ reload_acl() ->
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
-spec register_mod(Type :: auth | acl, Mod :: atom(), Opts :: list()) -> ok | {error, any()}. -spec register_mod(Type :: auth | acl, Mod :: atom(), Opts :: list()) -> ok | {error, any()}.
register_mod(Type, Mod, Opts) when Type =:= auth; Type =:= acl-> register_mod(Type, Mod, Opts) when Type =:= auth; Type =:= acl->
gen_server:call(?SERVER, {register_mod, Type, Mod, Opts}). register_mod(Type, Mod, Opts, 0).
-spec register_mod(auth | acl, atom(), list(), pos_integer()) -> ok | {error, any()}.
register_mod(Type, Mod, Opts, Seq) when Type =:= auth; Type =:= acl->
gen_server:call(?SERVER, {register_mod, Type, Mod, Opts, Seq}).
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% @doc Unregister authentication or ACL module %% @doc Unregister authentication or ACL module
@ -172,22 +174,26 @@ init_mods(acl, AclMods) ->
init_mod(Fun, Name, Opts) -> init_mod(Fun, Name, Opts) ->
Module = Fun(Name), Module = Fun(Name),
{ok, State} = Module:init(Opts), {ok, State} = Module:init(Opts),
{Module, State}. {Module, State, 0}.
handle_call({register_mod, Type, Mod, Opts}, _From, State) -> handle_call({register_mod, Type, Mod, Opts, Seq}, _From, State) ->
Mods = lookup_mods(Type), Mods = lookup_mods(Type),
Reply = Reply =
case lists:keyfind(Mod, 1, Mods) of case lists:keyfind(Mod, 1, Mods) of
false -> false ->
case catch Mod:init(Opts) of case catch Mod:init(Opts) of
{ok, ModState} -> {ok, ModState} ->
ets:insert(?ACCESS_CONTROL_TAB, {tab_key(Type), [{Mod, ModState}|Mods]}), NewMods =
lists:sort(fun({_, _, Seq1}, {_, _, Seq2}) ->
Seq1 >= Seq2
end, [{Mod, ModState, Seq} | Mods]),
ets:insert(?ACCESS_CONTROL_TAB, {tab_key(Type), NewMods}),
ok; ok;
{'EXIT', Error} -> {'EXIT', Error} ->
lager:error("Access Control: register ~s error - ~p", [Mod, Error]), lager:error("Access Control: register ~s error - ~p", [Mod, Error]),
{error, Error} {error, Error}
end; end;
_ -> _ ->
{error, existed} {error, existed}
end, end,
{reply, Reply, State}; {reply, Reply, State};

View File

@ -42,30 +42,33 @@ register_mod_test() ->
with_acl( with_acl(
fun() -> fun() ->
emqttd_access_control:register_mod(acl, emqttd_acl_test_mod, []), emqttd_access_control:register_mod(acl, emqttd_acl_test_mod, []),
?assertMatch([{emqttd_acl_test_mod, _}, {emqttd_acl_internal, _}], ?assertMatch([{emqttd_acl_test_mod, _, 0}, {emqttd_acl_internal, _, 0}],
emqttd_access_control:lookup_mods(acl)), emqttd_access_control:lookup_mods(acl)),
emqttd_access_control:register_mod(auth, emqttd_auth_anonymous_test_mod,[]), emqttd_access_control:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
?assertMatch([{emqttd_auth_anonymous_test_mod, _}, {emqttd_auth_anonymous, _}], emqttd_access_control:register_mod(auth, emqttd_auth_dashboard, [], 99),
emqttd_access_control:lookup_mods(auth)) ?assertMatch([{emqttd_auth_dashboard, _, 99},
{emqttd_auth_anonymous_test_mod, _, 0},
{emqttd_auth_anonymous, _, 0}],
emqttd_access_control:lookup_mods(auth))
end). end).
unregister_mod_test() -> unregister_mod_test() ->
with_acl( with_acl(
fun() -> fun() ->
emqttd_access_control:register_mod(acl,emqttd_acl_test_mod, []), emqttd_access_control:register_mod(acl, emqttd_acl_test_mod, []),
?assertMatch([{emqttd_acl_test_mod, _}, {emqttd_acl_internal, _}], ?assertMatch([{emqttd_acl_test_mod, _, 0}, {emqttd_acl_internal, _, 0}],
emqttd_access_control:lookup_mods(acl)), emqttd_access_control:lookup_mods(acl)),
emqttd_access_control:unregister_mod(acl, emqttd_acl_test_mod), emqttd_access_control:unregister_mod(acl, emqttd_acl_test_mod),
timer:sleep(5), timer:sleep(5),
?assertMatch([{emqttd_acl_internal, _}], emqttd_access_control:lookup_mods(acl)), ?assertMatch([{emqttd_acl_internal, _, 0}], emqttd_access_control:lookup_mods(acl)),
emqttd_access_control:register_mod(auth, emqttd_auth_anonymous_test_mod,[]), emqttd_access_control:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
?assertMatch([{emqttd_auth_anonymous_test_mod, _}, {emqttd_auth_anonymous, _}], ?assertMatch([{emqttd_auth_anonymous_test_mod, _, 0}, {emqttd_auth_anonymous, _, 0}],
emqttd_access_control:lookup_mods(auth)), emqttd_access_control:lookup_mods(auth)),
emqttd_access_control:unregister_mod(auth, emqttd_auth_anonymous_test_mod), emqttd_access_control:unregister_mod(auth, emqttd_auth_anonymous_test_mod),
timer:sleep(5), timer:sleep(5),
?assertMatch([{emqttd_auth_anonymous, _}], emqttd_access_control:lookup_mods(auth)) ?assertMatch([{emqttd_auth_anonymous, _, 0}], emqttd_access_control:lookup_mods(auth))
end). end).
check_acl_test() -> check_acl_test() ->
@ -83,7 +86,7 @@ check_acl_test() ->
with_acl(Fun) -> with_acl(Fun) ->
process_flag(trap_exit, true), process_flag(trap_exit, true),
AclOpts = [ AclOpts = [
{auth, [ {auth, [
%% Authentication with username, password %% Authentication with username, password
%{username, []}, %{username, []},