emqttd_auth_clientid.erl 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqttd_auth_clientid).
  17. -include("emqttd.hrl").
  18. -export([add_clientid/1, add_clientid/2, lookup_clientid/1, remove_clientid/1,
  19. all_clientids/0]).
  20. -behaviour(emqttd_auth_mod).
  21. %% emqttd_auth_mod callbacks
  22. -export([init/1, check/3, description/0]).
  23. -define(AUTH_CLIENTID_TAB, mqtt_auth_clientid).
  24. -record(?AUTH_CLIENTID_TAB, {client_id, ipaddr, password}).
  25. %%--------------------------------------------------------------------
  26. %% API
  27. %%--------------------------------------------------------------------
  28. %% @doc Add clientid
  29. -spec(add_clientid(binary()) -> {atomic, ok} | {aborted, any()}).
  30. add_clientid(ClientId) when is_binary(ClientId) ->
  31. R = #mqtt_auth_clientid{client_id = ClientId},
  32. mnesia:transaction(fun mnesia:write/1, [R]).
  33. %% @doc Add clientid with password
  34. -spec(add_clientid(binary(), binary()) -> {atomic, ok} | {aborted, any()}).
  35. add_clientid(ClientId, Password) ->
  36. R = #mqtt_auth_clientid{client_id = ClientId, password = Password},
  37. mnesia:transaction(fun mnesia:write/1, [R]).
  38. %% @doc Lookup clientid
  39. -spec(lookup_clientid(binary()) -> list(#mqtt_auth_clientid{})).
  40. lookup_clientid(ClientId) ->
  41. mnesia:dirty_read(?AUTH_CLIENTID_TAB, ClientId).
  42. %% @doc Lookup all clientids
  43. -spec(all_clientids() -> list(binary())).
  44. all_clientids() -> mnesia:dirty_all_keys(?AUTH_CLIENTID_TAB).
  45. %% @doc Remove clientid
  46. -spec(remove_clientid(binary()) -> {atomic, ok} | {aborted, any()}).
  47. remove_clientid(ClientId) ->
  48. mnesia:transaction(fun mnesia:delete/1, [{?AUTH_CLIENTID_TAB, ClientId}]).
  49. %%--------------------------------------------------------------------
  50. %% emqttd_auth_mod callbacks
  51. %%--------------------------------------------------------------------
  52. init(Opts) ->
  53. mnesia:create_table(?AUTH_CLIENTID_TAB, [
  54. {ram_copies, [node()]},
  55. {attributes, record_info(fields, ?AUTH_CLIENTID_TAB)}]),
  56. mnesia:add_table_copy(?AUTH_CLIENTID_TAB, node(), ram_copies),
  57. Clients = load_client_from(proplists:get_value(config, Opts)),
  58. mnesia:transaction(fun() -> [mnesia:write(C) || C<- Clients] end),
  59. {ok, Opts}.
  60. check(#mqtt_client{client_id = undefined}, _Password, _Opts) ->
  61. {error, clientid_undefined};
  62. check(#mqtt_client{client_id = ClientId, peername = {IpAddress, _}}, _Password, []) ->
  63. check_clientid_only(ClientId, IpAddress);
  64. check(#mqtt_client{client_id = ClientId, peername = {IpAddress, _}}, _Password, [{password, no}|_]) ->
  65. check_clientid_only(ClientId, IpAddress);
  66. check(_Client, undefined, [{password, yes}|_]) ->
  67. {error, password_undefined};
  68. check(#mqtt_client{client_id = ClientId}, Password, [{password, yes}|_]) ->
  69. case mnesia:dirty_read(?AUTH_CLIENTID_TAB, ClientId) of
  70. [] -> {error, clientid_not_found};
  71. [#?AUTH_CLIENTID_TAB{password = Password}] -> ok; %% TODO: plaintext??
  72. _ -> {error, password_error}
  73. end.
  74. description() -> "ClientId authentication module".
  75. %%--------------------------------------------------------------------
  76. %% Internal functions
  77. %%--------------------------------------------------------------------
  78. load_client_from(undefined) ->
  79. ok;
  80. load_client_from(File) ->
  81. {ok, Clients} = file:consult(File),
  82. [client(Client) || Client <- Clients].
  83. client(ClientId) when is_list(ClientId) ->
  84. #mqtt_auth_clientid{client_id = list_to_binary(ClientId)};
  85. client({ClientId, IpAddr}) when is_list(ClientId) ->
  86. #mqtt_auth_clientid{client_id = iolist_to_binary(ClientId),
  87. ipaddr = esockd_cidr:parse(IpAddr, true)}.
  88. check_clientid_only(ClientId, IpAddr) ->
  89. case mnesia:dirty_read(?AUTH_CLIENTID_TAB, ClientId) of
  90. [] ->
  91. {error, clientid_not_found};
  92. [#?AUTH_CLIENTID_TAB{ipaddr = undefined}] ->
  93. ok;
  94. [#?AUTH_CLIENTID_TAB{ipaddr = CIDR}] ->
  95. case esockd_cidr:match(IpAddr, CIDR) of
  96. true -> ok;
  97. false -> {error, wrong_ipaddr}
  98. end
  99. end.