From 9bad2bf65b604c9e48009396addc2973de7c1619 Mon Sep 17 00:00:00 2001 From: Feng Date: Tue, 3 Nov 2015 12:52:27 +0800 Subject: [PATCH] support Seq --- src/emqttd_access_control.erl | 36 ++++++++++++++++------------ test/emqttd_access_control_tests.erl | 21 +++++++++------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/emqttd_access_control.erl b/src/emqttd_access_control.erl index 320b6f75f..7d15d5904 100644 --- a/src/emqttd_access_control.erl +++ b/src/emqttd_access_control.erl @@ -24,7 +24,6 @@ %%% %%% @end %%%----------------------------------------------------------------------------- - -module(emqttd_access_control). -author("Feng Lee "). @@ -36,14 +35,13 @@ -define(SERVER, ?MODULE). %% API Function Exports --export([start_link/0, - start_link/1, +-export([start_link/0, start_link/1, auth/2, % authentication check_acl/3, % acl check reload_acl/0, % reload acl - register_mod/3, - unregister_mod/2, lookup_mods/1, + register_mod/3, register_mod/4, + unregister_mod/2, stop/0]). %% 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, []) -> {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 ok -> ok; {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, []) -> lager:error("ACL: nomatch when ~s ~s ~s", [ClientId, PubSub, Topic]), 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 allow -> allow; deny -> deny; @@ -113,7 +111,7 @@ check_acl(Client, PubSub, Topic, [{M, State}|AclMods]) -> %%------------------------------------------------------------------------------ -spec reload_acl() -> list() | {error, any()}. 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 @@ -121,7 +119,11 @@ reload_acl() -> %%------------------------------------------------------------------------------ -spec register_mod(Type :: auth | acl, Mod :: atom(), Opts :: list()) -> ok | {error, any()}. 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 @@ -172,22 +174,26 @@ init_mods(acl, AclMods) -> init_mod(Fun, Name, Opts) -> Module = Fun(Name), {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), Reply = case lists:keyfind(Mod, 1, Mods) of - false -> + false -> case catch Mod:init(Opts) of - {ok, ModState} -> - ets:insert(?ACCESS_CONTROL_TAB, {tab_key(Type), [{Mod, ModState}|Mods]}), + {ok, ModState} -> + NewMods = + lists:sort(fun({_, _, Seq1}, {_, _, Seq2}) -> + Seq1 >= Seq2 + end, [{Mod, ModState, Seq} | Mods]), + ets:insert(?ACCESS_CONTROL_TAB, {tab_key(Type), NewMods}), ok; {'EXIT', Error} -> lager:error("Access Control: register ~s error - ~p", [Mod, Error]), {error, Error} end; - _ -> + _ -> {error, existed} end, {reply, Reply, State}; diff --git a/test/emqttd_access_control_tests.erl b/test/emqttd_access_control_tests.erl index 7db0490ef..5da45f4a8 100644 --- a/test/emqttd_access_control_tests.erl +++ b/test/emqttd_access_control_tests.erl @@ -42,30 +42,33 @@ register_mod_test() -> with_acl( fun() -> 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:register_mod(auth, emqttd_auth_anonymous_test_mod,[]), - ?assertMatch([{emqttd_auth_anonymous_test_mod, _}, {emqttd_auth_anonymous, _}], - emqttd_access_control:lookup_mods(auth)) + emqttd_access_control:register_mod(auth, emqttd_auth_dashboard, [], 99), + ?assertMatch([{emqttd_auth_dashboard, _, 99}, + {emqttd_auth_anonymous_test_mod, _, 0}, + {emqttd_auth_anonymous, _, 0}], + emqttd_access_control:lookup_mods(auth)) end). unregister_mod_test() -> with_acl( fun() -> - emqttd_access_control:register_mod(acl,emqttd_acl_test_mod, []), - ?assertMatch([{emqttd_acl_test_mod, _}, {emqttd_acl_internal, _}], + emqttd_access_control:register_mod(acl, emqttd_acl_test_mod, []), + ?assertMatch([{emqttd_acl_test_mod, _, 0}, {emqttd_acl_internal, _, 0}], emqttd_access_control:lookup_mods(acl)), emqttd_access_control:unregister_mod(acl, emqttd_acl_test_mod), 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,[]), - ?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:unregister_mod(auth, emqttd_auth_anonymous_test_mod), 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). check_acl_test() -> @@ -83,7 +86,7 @@ check_acl_test() -> with_acl(Fun) -> process_flag(trap_exit, true), - AclOpts = [ + AclOpts = [ {auth, [ %% Authentication with username, password %{username, []},