diff --git a/src/emqttd_access_control.erl b/src/emqttd_access_control.erl index c2c8fb9b3..fb36892c7 100644 --- a/src/emqttd_access_control.erl +++ b/src/emqttd_access_control.erl @@ -60,6 +60,7 @@ auth(_Client, _Password, []) -> auth(Client, Password, [{Mod, State, _Seq} | Mods]) -> case catch Mod:check(Client, Password, State) of ok -> ok; + {ok, IsSuper} -> {ok, IsSuper}; ignore -> auth(Client, Password, Mods); {error, Reason} -> {error, Reason}; {'EXIT', Error} -> {error, Error} diff --git a/src/emqttd_auth_anonymous.erl b/src/emqttd_auth_anonymous.erl index ed81492d1..8acdb7bf0 100644 --- a/src/emqttd_auth_anonymous.erl +++ b/src/emqttd_auth_anonymous.erl @@ -19,13 +19,11 @@ -behaviour(emqttd_auth_mod). --export([init/1, check/3, is_superuser/2, description/0]). +-export([init/1, check/3, description/0]). init(Opts) -> {ok, Opts}. check(_Client, _Password, _Opts) -> ok. -is_superuser(_Client, _Opts) -> false. - description() -> "Anonymous Authentication Module". diff --git a/src/emqttd_auth_clientid.erl b/src/emqttd_auth_clientid.erl index 168fca2e5..15a751ea8 100644 --- a/src/emqttd_auth_clientid.erl +++ b/src/emqttd_auth_clientid.erl @@ -24,7 +24,7 @@ -behaviour(emqttd_auth_mod). %% emqttd_auth_mod callbacks --export([init/1, check/3, is_superuser/2, description/0]). +-export([init/1, check/3, description/0]). -define(AUTH_CLIENTID_TAB, mqtt_auth_clientid). @@ -88,8 +88,6 @@ check(#mqtt_client{client_id = ClientId}, Password, [{password, yes}|_]) -> _ -> {error, password_error} end. -is_superuser(_Client, _Opts) -> false. - description() -> "ClientId authentication module". %%-------------------------------------------------------------------- diff --git a/src/emqttd_auth_mod.erl b/src/emqttd_auth_mod.erl index f05db3a35..845d5a0fb 100644 --- a/src/emqttd_auth_mod.erl +++ b/src/emqttd_auth_mod.erl @@ -30,13 +30,11 @@ -callback(init(AuthOpts :: list()) -> {ok, State :: any()}). --callback(check(Client, Password, State) -> ok | ignore | {error, string()} when +-callback(check(Client, Password, State) -> ok | | {ok, boolean()} | ignore | {error, string()} when Client :: mqtt_client(), Password :: binary(), State :: any()). --callback(is_superuser(Client :: mqtt_client(), State :: any()) -> boolean()). - -callback(description() -> string()). -else. @@ -44,7 +42,7 @@ -export([behaviour_info/1]). behaviour_info(callbacks) -> - [{init, 1}, {check, 3}, {is_superuser, 2}, {description, 0}]; + [{init, 1}, {check, 3}, {description, 0}]; behaviour_info(_Other) -> undefined. diff --git a/src/emqttd_auth_username.erl b/src/emqttd_auth_username.erl index d30f39e31..545bce7c3 100644 --- a/src/emqttd_auth_username.erl +++ b/src/emqttd_auth_username.erl @@ -31,7 +31,7 @@ -export([add_user/2, remove_user/1, lookup_user/1, all_users/0]). %% emqttd_auth callbacks --export([init/1, check/3, is_superuser/2, description/0]). +-export([init/1, check/3, description/0]). -define(AUTH_USERNAME_TAB, mqtt_auth_username). @@ -146,8 +146,6 @@ check(#mqtt_client{username = Username}, Password, _Opts) -> end end. -is_superuser(_Client, _Opts) -> false. - description() -> "Username password authentication module". @@ -162,5 +160,5 @@ md5_hash(SaltBin, Password) -> erlang:md5(<>). salt() -> - emqttd_time:seed(), Salt = random:uniform(16#ffffffff), <>. + emqttd_time:seed(), Salt = rand:uniform(16#ffffffff), <>. diff --git a/src/emqttd_protocol.erl b/src/emqttd_protocol.erl index 007e570a1..f3579d46b 100644 --- a/src/emqttd_protocol.erl +++ b/src/emqttd_protocol.erl @@ -159,12 +159,8 @@ process(Packet = ?CONNECT_PACKET(Var), State0) -> {ReturnCode1, SessPresent, State3} = case validate_connect(Var, State1) of ?CONNACK_ACCEPT -> - Client = client(State1), - case emqttd_access_control:auth(Client, Password) of - ok -> - %% Is Superuser? - IsSuperuser = emqttd_access_control:is_superuser(Client), - + case authenticate(client(State1), Password) of + {ok, IsSuperuser} -> %% Generate clientId if null State2 = maybe_set_clientid(State1), @@ -190,7 +186,9 @@ process(Packet = ?CONNECT_PACKET(Var), State0) -> %% Run hooks emqttd:run_hooks('client.connected', [ReturnCode1], client(State3)), %% Send connack - send(?CONNACK_PACKET(ReturnCode1, sp(SessPresent)), State3); + send(?CONNACK_PACKET(ReturnCode1, sp(SessPresent)), State3), + %% stop if authentication failure + stop_if_auth_failure(ReturnCode1, State3); process(Packet = ?PUBLISH_PACKET(_Qos, Topic, _PacketId, _Payload), State = #proto_state{is_superuser = IsSuper}) -> case IsSuper orelse allow == check_acl(publish, Topic, client(State)) of @@ -302,6 +300,12 @@ trace(send, Packet, ProtoState) -> redeliver({?PUBREL, PacketId}, State) -> send(?PUBREL_PACKET(PacketId), State). +stop_if_auth_failure(RC, State) when RC == ?CONNACK_CREDENTIALS; RC == ?CONNACK_AUTH -> + {stop, {shutdown, auth_failure}, State}; + +stop_if_auth_failure(_RC, State) -> + {ok, State}. + shutdown(_Error, #proto_state{client_id = undefined}) -> ignore; @@ -435,6 +439,13 @@ parse_topic_table(TopicTable) -> parse_topics(Topics) -> [emqttd_topic:parse(Topic) || Topic <- Topics]. +authenticate(Client, Password) -> + case emqttd_access_control:auth(Client, Password) of + ok -> {ok, false}; + {ok, IsSuper} -> {ok, IsSuper}; + {error, Error} -> {error, Error} + end. + %% PUBLISH ACL is cached in process dictionary. check_acl(publish, Topic, Client) -> IfCache = emqttd:conf(cache_acl, true),