Support 'is_superuser/2 callback
This commit is contained in:
parent
d0218deb88
commit
8d48e8d2e2
|
@ -24,16 +24,16 @@
|
||||||
|
|
||||||
-ifdef(use_specs).
|
-ifdef(use_specs).
|
||||||
|
|
||||||
-callback init(AclOpts :: list()) -> {ok, State :: any()}.
|
-callback(init(AclOpts :: list()) -> {ok, State :: any()}).
|
||||||
|
|
||||||
-callback check_acl({Client, PubSub, Topic}, State :: any()) -> allow | deny | ignore when
|
-callback(check_acl({Client, PubSub, Topic}, State :: any()) -> allow | deny | ignore when
|
||||||
Client :: mqtt_client(),
|
Client :: mqtt_client(),
|
||||||
PubSub :: pubsub(),
|
PubSub :: pubsub(),
|
||||||
Topic :: binary().
|
Topic :: binary()).
|
||||||
|
|
||||||
-callback reload_acl(State :: any()) -> ok | {error, any()}.
|
-callback(reload_acl(State :: any()) -> ok | {error, any()}).
|
||||||
|
|
||||||
-callback description() -> string().
|
-callback(description() -> string()).
|
||||||
|
|
||||||
-else.
|
-else.
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
|
|
||||||
-behaviour(emqttd_auth_mod).
|
-behaviour(emqttd_auth_mod).
|
||||||
|
|
||||||
-export([init/1, check/3, description/0]).
|
-export([init/1, check/3, is_superuser/2, description/0]).
|
||||||
|
|
||||||
init(Opts) -> {ok, Opts}.
|
init(Opts) -> {ok, Opts}.
|
||||||
|
|
||||||
check(_Client, _Password, _Opts) -> ok.
|
check(_Client, _Password, _Opts) -> ok.
|
||||||
|
|
||||||
|
is_superuser(_Client, _Opts) -> false.
|
||||||
|
|
||||||
description() -> "Anonymous Authentication Module".
|
description() -> "Anonymous Authentication Module".
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
-behaviour(emqttd_auth_mod).
|
-behaviour(emqttd_auth_mod).
|
||||||
|
|
||||||
%% emqttd_auth_mod callbacks
|
%% emqttd_auth_mod callbacks
|
||||||
-export([init/1, check/3, description/0]).
|
-export([init/1, check/3, is_superuser/2, description/0]).
|
||||||
|
|
||||||
-define(AUTH_CLIENTID_TAB, mqtt_auth_clientid).
|
-define(AUTH_CLIENTID_TAB, mqtt_auth_clientid).
|
||||||
|
|
||||||
|
@ -88,6 +88,8 @@ check(#mqtt_client{client_id = ClientId}, Password, [{password, yes}|_]) ->
|
||||||
_ -> {error, password_error}
|
_ -> {error, password_error}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
is_superuser(_Client, _Opts) -> false.
|
||||||
|
|
||||||
description() -> "ClientId authentication module".
|
description() -> "ClientId authentication module".
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -14,14 +14,13 @@
|
||||||
%% limitations under the License.
|
%% limitations under the License.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc Authentication Behaviour.
|
|
||||||
-module(emqttd_auth_mod).
|
-module(emqttd_auth_mod).
|
||||||
|
|
||||||
-include("emqttd.hrl").
|
-include("emqttd.hrl").
|
||||||
|
|
||||||
-export([passwd_hash/2]).
|
-export([passwd_hash/2]).
|
||||||
|
|
||||||
-type hash_type() :: plain | md5 | sha | sha256.
|
-type(hash_type() :: plain | md5 | sha | sha256).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Authentication behavihour
|
%% Authentication behavihour
|
||||||
|
@ -29,21 +28,23 @@
|
||||||
|
|
||||||
-ifdef(use_specs).
|
-ifdef(use_specs).
|
||||||
|
|
||||||
-callback init(AuthOpts :: list()) -> {ok, State :: any()}.
|
-callback(init(AuthOpts :: list()) -> {ok, State :: any()}).
|
||||||
|
|
||||||
-callback check(Client, Password, State) -> ok | ignore | {error, string()} when
|
-callback(check(Client, Password, State) -> ok | ignore | {error, string()} when
|
||||||
Client :: mqtt_client(),
|
Client :: mqtt_client(),
|
||||||
Password :: binary(),
|
Password :: binary(),
|
||||||
State :: any().
|
State :: any()).
|
||||||
|
|
||||||
-callback description() -> string().
|
-callback(is_superuser(Client :: mqtt_client(), State :: any()) -> boolean()).
|
||||||
|
|
||||||
|
-callback(description() -> string()).
|
||||||
|
|
||||||
-else.
|
-else.
|
||||||
|
|
||||||
-export([behaviour_info/1]).
|
-export([behaviour_info/1]).
|
||||||
|
|
||||||
behaviour_info(callbacks) ->
|
behaviour_info(callbacks) ->
|
||||||
[{init, 1}, {check, 3}, {description, 0}];
|
[{init, 1}, {check, 3}, {is_superuser, 2}, {description, 0}];
|
||||||
behaviour_info(_Other) ->
|
behaviour_info(_Other) ->
|
||||||
undefined.
|
undefined.
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
-export([add_user/2, remove_user/1, lookup_user/1, all_users/0]).
|
-export([add_user/2, remove_user/1, lookup_user/1, all_users/0]).
|
||||||
|
|
||||||
%% emqttd_auth callbacks
|
%% emqttd_auth callbacks
|
||||||
-export([init/1, check/3, description/0]).
|
-export([init/1, check/3, is_superuser/2, description/0]).
|
||||||
|
|
||||||
-define(AUTH_USERNAME_TAB, mqtt_auth_username).
|
-define(AUTH_USERNAME_TAB, mqtt_auth_username).
|
||||||
|
|
||||||
|
@ -146,6 +146,8 @@ check(#mqtt_client{username = Username}, Password, _Opts) ->
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
is_superuser(_Client, _Opts) -> false.
|
||||||
|
|
||||||
description() ->
|
description() ->
|
||||||
"Username password authentication module".
|
"Username password authentication module".
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
%% Protocol State
|
%% Protocol State
|
||||||
-record(proto_state, {peername, sendfun, connected = false,
|
-record(proto_state, {peername, sendfun, connected = false,
|
||||||
client_id, client_pid, clean_sess,
|
client_id, client_pid, clean_sess,
|
||||||
proto_ver, proto_name, username,
|
proto_ver, proto_name, username, is_superuser = false,
|
||||||
will_msg, keepalive, max_clientid_len = ?MAX_CLIENTID_LEN,
|
will_msg, keepalive, max_clientid_len = ?MAX_CLIENTID_LEN,
|
||||||
session, ws_initial_headers, %% Headers from first HTTP request for websocket client
|
session, ws_initial_headers, %% Headers from first HTTP request for websocket client
|
||||||
connected_at}).
|
connected_at}).
|
||||||
|
@ -159,8 +159,12 @@ process(Packet = ?CONNECT_PACKET(Var), State0) ->
|
||||||
{ReturnCode1, SessPresent, State3} =
|
{ReturnCode1, SessPresent, State3} =
|
||||||
case validate_connect(Var, State1) of
|
case validate_connect(Var, State1) of
|
||||||
?CONNACK_ACCEPT ->
|
?CONNACK_ACCEPT ->
|
||||||
case emqttd_access_control:auth(client(State1), Password) of
|
Client = client(State1),
|
||||||
|
case emqttd_access_control:auth(Client, Password) of
|
||||||
ok ->
|
ok ->
|
||||||
|
%% Is Superuser?
|
||||||
|
IsSuperuser = emqttd_access_control:is_superuser(Client),
|
||||||
|
|
||||||
%% Generate clientId if null
|
%% Generate clientId if null
|
||||||
State2 = maybe_set_clientid(State1),
|
State2 = maybe_set_clientid(State1),
|
||||||
|
|
||||||
|
@ -172,7 +176,7 @@ process(Packet = ?CONNECT_PACKET(Var), State0) ->
|
||||||
%% Start keepalive
|
%% Start keepalive
|
||||||
start_keepalive(KeepAlive),
|
start_keepalive(KeepAlive),
|
||||||
%% ACCEPT
|
%% ACCEPT
|
||||||
{?CONNACK_ACCEPT, SP, State2#proto_state{session = Session}};
|
{?CONNACK_ACCEPT, SP, State2#proto_state{session = Session, is_superuser = IsSuperuser}};
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
exit({shutdown, Error})
|
exit({shutdown, Error})
|
||||||
end;
|
end;
|
||||||
|
@ -188,12 +192,10 @@ process(Packet = ?CONNECT_PACKET(Var), State0) ->
|
||||||
%% Send connack
|
%% Send connack
|
||||||
send(?CONNACK_PACKET(ReturnCode1, sp(SessPresent)), State3);
|
send(?CONNACK_PACKET(ReturnCode1, sp(SessPresent)), State3);
|
||||||
|
|
||||||
process(Packet = ?PUBLISH_PACKET(_Qos, Topic, _PacketId, _Payload), State) ->
|
process(Packet = ?PUBLISH_PACKET(_Qos, Topic, _PacketId, _Payload), State = #proto_state{is_superuser = IsSuper}) ->
|
||||||
case check_acl(publish, Topic, client(State)) of
|
case IsSuper orelse allow == check_acl(publish, Topic, client(State)) of
|
||||||
allow ->
|
true -> publish(Packet, State);
|
||||||
publish(Packet, State);
|
false -> ?LOG(error, "Cannot publish to ~s for ACL Deny", [Topic], State)
|
||||||
deny ->
|
|
||||||
?LOG(error, "Cannot publish to ~s for ACL Deny", [Topic], State)
|
|
||||||
end,
|
end,
|
||||||
{ok, State};
|
{ok, State};
|
||||||
|
|
||||||
|
@ -216,11 +218,14 @@ process(?PUBACK_PACKET(?PUBCOMP, PacketId), State = #proto_state{session = Sessi
|
||||||
process(?SUBSCRIBE_PACKET(PacketId, []), State) ->
|
process(?SUBSCRIBE_PACKET(PacketId, []), State) ->
|
||||||
send(?SUBACK_PACKET(PacketId, []), State);
|
send(?SUBACK_PACKET(PacketId, []), State);
|
||||||
|
|
||||||
process(?SUBSCRIBE_PACKET(PacketId, RawTopicTable), State = #proto_state{
|
%% TODO: refactor later...
|
||||||
client_id = ClientId, username = Username, session = Session}) ->
|
process(?SUBSCRIBE_PACKET(PacketId, RawTopicTable), State = #proto_state{session = Session,
|
||||||
Client = client(State),
|
client_id = ClientId, username = Username, is_superuser = IsSuperuser}) ->
|
||||||
TopicTable = parse_topic_table(RawTopicTable),
|
Client = client(State), TopicTable = parse_topic_table(RawTopicTable),
|
||||||
AllowDenies = [check_acl(subscribe, Topic, Client) || {Topic, _Opts} <- TopicTable],
|
AllowDenies = if
|
||||||
|
IsSuperuser -> [];
|
||||||
|
true -> [check_acl(subscribe, Topic, Client) || {Topic, _Opts} <- TopicTable]
|
||||||
|
end,
|
||||||
case lists:member(deny, AllowDenies) of
|
case lists:member(deny, AllowDenies) of
|
||||||
true ->
|
true ->
|
||||||
?LOG(error, "Cannot SUBSCRIBE ~p for ACL Deny", [TopicTable], State),
|
?LOG(error, "Cannot SUBSCRIBE ~p for ACL Deny", [TopicTable], State),
|
||||||
|
|
Loading…
Reference in New Issue