emqx_auth_mongo.schema 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. %%-*- mode: erlang -*-
  2. %% emqx_auth_mongo config mapping
  3. {mapping, "auth.mongo.type", "emqx_auth_mongo.server", [
  4. {default, single},
  5. {datatype, {enum, [single, unknown, sharded, rs]}}
  6. ]}.
  7. {mapping, "auth.mongo.rs_set_name", "emqx_auth_mongo.server", [
  8. {default, "mqtt"},
  9. {datatype, string}
  10. ]}.
  11. {mapping, "auth.mongo.server", "emqx_auth_mongo.server", [
  12. {default, "127.0.0.1:27017"},
  13. {datatype, string}
  14. ]}.
  15. {mapping, "auth.mongo.pool", "emqx_auth_mongo.server", [
  16. {default, 8},
  17. {datatype, integer}
  18. ]}.
  19. %% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
  20. {mapping, "auth.mongo.login", "emqx_auth_mongo.server", [
  21. {datatype, string}
  22. ]}.
  23. {mapping, "auth.mongo.username", "emqx_auth_mongo.server", [
  24. {datatype, string}
  25. ]}.
  26. {mapping, "auth.mongo.password", "emqx_auth_mongo.server", [
  27. {default, ""},
  28. {datatype, string}
  29. ]}.
  30. {mapping, "auth.mongo.database", "emqx_auth_mongo.server", [
  31. {default, "mqtt"},
  32. {datatype, string}
  33. ]}.
  34. {mapping, "auth.mongo.auth_source", "emqx_auth_mongo.server", [
  35. {default, "mqtt"},
  36. {datatype, string}
  37. ]}.
  38. {mapping, "auth.mongo.ssl.enable", "emqx_auth_mongo.server", [
  39. {default, off},
  40. {datatype, {enum, [on, off, true, false]}} %% FIXME: ture/false is compatible with 4.0-4.2 version format, plan to delete in 5.0
  41. ]}.
  42. {mapping, "auth.mongo.ssl.keyfile", "emqx_auth_mongo.server", [
  43. {datatype, string}
  44. ]}.
  45. {mapping, "auth.mongo.ssl.certfile", "emqx_auth_mongo.server", [
  46. {datatype, string}
  47. ]}.
  48. {mapping, "auth.mongo.ssl.cacertfile", "emqx_auth_mongo.server", [
  49. {datatype, string}
  50. ]}.
  51. {mapping, "auth.mongo.ssl.verify", "emqx_auth_mongo.server", [
  52. {default, false},
  53. {datatype, {enum, [true, false]}}
  54. ]}.
  55. {mapping, "auth.mongo.ssl.server_name_indication", "emqx_auth_mongo.server", [
  56. {datatype, string}
  57. ]}.
  58. %% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
  59. {mapping, "auth.mongo.ssl_opts.keyfile", "emqx_auth_mongo.server", [
  60. {datatype, string}
  61. ]}.
  62. %% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
  63. {mapping, "auth.mongo.ssl_opts.certfile", "emqx_auth_mongo.server", [
  64. {datatype, string}
  65. ]}.
  66. %% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
  67. {mapping, "auth.mongo.ssl_opts.cacertfile", "emqx_auth_mongo.server", [
  68. {datatype, string}
  69. ]}.
  70. {mapping, "auth.mongo.w_mode", "emqx_auth_mongo.server", [
  71. {default, undef},
  72. {datatype, {enum, [safe, unsafe, undef]}}
  73. ]}.
  74. {mapping, "auth.mongo.r_mode", "emqx_auth_mongo.server", [
  75. {default, undef},
  76. {datatype, {enum, [master, slave_ok, undef]}}
  77. ]}.
  78. {mapping, "auth.mongo.topology.$name", "emqx_auth_mongo.server", [
  79. {datatype, integer}
  80. ]}.
  81. {translation, "emqx_auth_mongo.server", fun(Conf) ->
  82. H = cuttlefish:conf_get("auth.mongo.server", Conf),
  83. Hosts = string:tokens(H, ","),
  84. Type0 = cuttlefish:conf_get("auth.mongo.type", Conf),
  85. Pool = cuttlefish:conf_get("auth.mongo.pool", Conf),
  86. %% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
  87. Login = cuttlefish:conf_get("auth.mongo.username", Conf,
  88. cuttlefish:conf_get("auth.mongo.login", Conf, "")
  89. ),
  90. Passwd = cuttlefish:conf_get("auth.mongo.password", Conf),
  91. DB = cuttlefish:conf_get("auth.mongo.database", Conf),
  92. AuthSrc = cuttlefish:conf_get("auth.mongo.auth_source", Conf),
  93. R = cuttlefish:conf_get("auth.mongo.w_mode", Conf),
  94. W = cuttlefish:conf_get("auth.mongo.r_mode", Conf),
  95. Login0 = case Login =:= [] of
  96. true -> [];
  97. false -> [{login, list_to_binary(Login)}]
  98. end,
  99. Passwd0 = case Passwd =:= [] of
  100. true -> [];
  101. false -> [{password, list_to_binary(Passwd)}]
  102. end,
  103. W0 = case W =:= undef of
  104. true -> [];
  105. false -> [{w_mode, W}]
  106. end,
  107. R0 = case R =:= undef of
  108. true -> [];
  109. false -> [{r_mode, R}]
  110. end,
  111. Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
  112. SslOpts = fun(Prefix) ->
  113. Verify = case cuttlefish:conf_get(Prefix ++ ".verify", Conf, false) of
  114. true -> verify_peer;
  115. false -> verify_none
  116. end,
  117. Filter([{verify, Verify},
  118. {server_name_indication, case cuttlefish:conf_get(Prefix ++ ".server_name_indication", Conf, undefined) of
  119. "disable" -> disable;
  120. SNI -> SNI
  121. end},
  122. {keyfile, cuttlefish:conf_get(Prefix ++ ".keyfile", Conf, undefined)},
  123. {certfile, cuttlefish:conf_get(Prefix ++ ".certfile", Conf, undefined)},
  124. {cacertfile, cuttlefish:conf_get(Prefix ++ ".cacertfile", Conf, undefined)}])
  125. end,
  126. %% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
  127. GenSsl = case cuttlefish:conf_get("auth.mongo.ssl.cacertfile", Conf, undefined) of
  128. undefined -> [{ssl, true}, {ssl_opts, SslOpts("auth.mongo.ssl_opts")}];
  129. _ -> [{ssl, true}, {ssl_opts, SslOpts("auth.mongo.ssl")}]
  130. end,
  131. %% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
  132. Ssl = case cuttlefish:conf_get("auth.mongo.ssl.enable", Conf) of
  133. on -> GenSsl;
  134. off -> [];
  135. true -> [{ssl, true}, {ssl_opts, SslOpts("auth.mongo.ssl_opts")}];
  136. false -> []
  137. end,
  138. WorkerOptions = [{database, list_to_binary(DB)}, {auth_source, list_to_binary(AuthSrc)}]
  139. ++ Login0 ++ Passwd0 ++ W0 ++ R0 ++ Ssl,
  140. Vars = cuttlefish_variable:fuzzy_matches(["auth", "mongo", "topology", "$name"], Conf),
  141. Options = lists:map(fun({_, Name}) ->
  142. Name2 = case Name of
  143. "local_threshold_ms" -> "localThresholdMS";
  144. "connect_timeout_ms" -> "connectTimeoutMS";
  145. "socket_timeout_ms" -> "socketTimeoutMS";
  146. "server_selection_timeout_ms" -> "serverSelectionTimeoutMS";
  147. "wait_queue_timeout_ms" -> "waitQueueTimeoutMS";
  148. "heartbeat_frequency_ms" -> "heartbeatFrequencyMS";
  149. "min_heartbeat_frequency_ms" -> "minHeartbeatFrequencyMS";
  150. _ -> Name
  151. end,
  152. {list_to_atom(Name2), cuttlefish:conf_get("auth.mongo.topology."++Name, Conf)}
  153. end, Vars),
  154. Type = case Type0 =:= rs of
  155. true -> {Type0, list_to_binary(cuttlefish:conf_get("auth.mongo.rs_set_name", Conf))};
  156. false -> Type0
  157. end,
  158. [{type, Type},
  159. {hosts, Hosts},
  160. {options, Options},
  161. {worker_options, WorkerOptions},
  162. {auto_reconnect, 1},
  163. {pool_size, Pool}]
  164. end}.
  165. %% The mongodb operation timeout is specified by the value of `cursor_timeout` from application config,
  166. %% or `infinity` if `cursor_timeout` not specified
  167. {mapping, "auth.mongo.query_timeout", "mongodb.cursor_timeout", [
  168. {datatype, string}
  169. ]}.
  170. {translation, "mongodb.cursor_timeout", fun(Conf) ->
  171. case cuttlefish:conf_get("auth.mongo.query_timeout", Conf, undefined) of
  172. undefined -> infinity;
  173. Duration ->
  174. case cuttlefish_duration:parse(Duration, ms) of
  175. {error, Reason} -> error(Reason);
  176. Ms when is_integer(Ms) -> Ms
  177. end
  178. end
  179. end}.
  180. {mapping, "auth.mongo.auth_query.collection", "emqx_auth_mongo.auth_query", [
  181. {default, "mqtt_user"},
  182. {datatype, string}
  183. ]}.
  184. {mapping, "auth.mongo.auth_query.password_field", "emqx_auth_mongo.auth_query", [
  185. {default, "password"},
  186. {datatype, string}
  187. ]}.
  188. {mapping, "auth.mongo.auth_query.password_hash", "emqx_auth_mongo.auth_query", [
  189. {datatype, string}
  190. ]}.
  191. {mapping, "auth.mongo.auth_query.selector", "emqx_auth_mongo.auth_query", [
  192. {default, ""},
  193. {datatype, string}
  194. ]}.
  195. {translation, "emqx_auth_mongo.auth_query", fun(Conf) ->
  196. case cuttlefish:conf_get("auth.mongo.auth_query.collection", Conf) of
  197. undefined -> cuttlefish:unset();
  198. Collection ->
  199. PasswordField = cuttlefish:conf_get("auth.mongo.auth_query.password_field", Conf),
  200. PasswordHash = cuttlefish:conf_get("auth.mongo.auth_query.password_hash", Conf),
  201. SelectorStr = cuttlefish:conf_get("auth.mongo.auth_query.selector", Conf),
  202. SelectorList =
  203. lists:map(fun(Selector) ->
  204. case string:tokens(Selector, "=") of
  205. [Field, Val] -> {list_to_binary(Field), list_to_binary(Val)};
  206. _ -> {<<"username">>, <<"%u">>}
  207. end
  208. end, string:tokens(SelectorStr, ", ")),
  209. PasswordFields = [list_to_binary(Field) || Field <- string:tokens(PasswordField, ",")],
  210. HashValue =
  211. case string:tokens(PasswordHash, ",") of
  212. [Hash] -> list_to_atom(Hash);
  213. [Prefix, Suffix] -> {list_to_atom(Prefix), list_to_atom(Suffix)};
  214. [Hash, MacFun, Iterations, Dklen] -> {list_to_atom(Hash), list_to_atom(MacFun), list_to_integer(Iterations), list_to_integer(Dklen)};
  215. _ -> plain
  216. end,
  217. [{collection, Collection},
  218. {password_field, PasswordFields},
  219. {password_hash, HashValue},
  220. {selector, SelectorList}]
  221. end
  222. end}.
  223. {mapping, "auth.mongo.super_query", "emqx_auth_mongo.super_query", [
  224. {default, off},
  225. {datatype, flag}
  226. ]}.
  227. {mapping, "auth.mongo.super_query.collection", "emqx_auth_mongo.super_query", [
  228. {default, "mqtt_user"},
  229. {datatype, string}
  230. ]}.
  231. {mapping, "auth.mongo.super_query.super_field", "emqx_auth_mongo.super_query", [
  232. {default, "is_superuser"},
  233. {datatype, string}
  234. ]}.
  235. {mapping, "auth.mongo.super_query.selector", "emqx_auth_mongo.super_query", [
  236. {default, ""},
  237. {datatype, string}
  238. ]}.
  239. {translation, "emqx_auth_mongo.super_query", fun(Conf) ->
  240. case cuttlefish:conf_get("auth.mongo.super_query.collection", Conf) of
  241. undefined -> cuttlefish:unset();
  242. Collection ->
  243. SuperField = cuttlefish:conf_get("auth.mongo.super_query.super_field", Conf),
  244. SelectorStr = cuttlefish:conf_get("auth.mongo.super_query.selector", Conf),
  245. SelectorList =
  246. lists:map(fun(Selector) ->
  247. case string:tokens(Selector, "=") of
  248. [Field, Val] -> {list_to_binary(Field), list_to_binary(Val)};
  249. _ -> {<<"username">>, <<"%u">>}
  250. end
  251. end, string:tokens(SelectorStr, ", ")),
  252. [{collection, Collection}, {super_field, SuperField}, {selector, SelectorList}]
  253. end
  254. end}.
  255. {mapping, "auth.mongo.acl_query", "emqx_auth_mongo.acl_query", [
  256. {default, off},
  257. {datatype, flag}
  258. ]}.
  259. {mapping, "auth.mongo.acl_query.collection", "emqx_auth_mongo.acl_query", [
  260. {default, "mqtt_user"},
  261. {datatype, string}
  262. ]}.
  263. {mapping, "auth.mongo.acl_query.selector", "emqx_auth_mongo.acl_query", [
  264. {default, ""},
  265. {datatype, string}
  266. ]}.
  267. {mapping, "auth.mongo.acl_query.selector.$id", "emqx_auth_mongo.acl_query", [
  268. {default, ""},
  269. {datatype, string}
  270. ]}.
  271. {translation, "emqx_auth_mongo.acl_query", fun(Conf) ->
  272. case cuttlefish:conf_get("auth.mongo.acl_query.collection", Conf) of
  273. undefined -> cuttlefish:unset();
  274. Collection ->
  275. SelectorStrList =
  276. lists:map(
  277. fun
  278. ({["auth","mongo","acl_query","selector"], ConfEntry}) ->
  279. ConfEntry;
  280. ({["auth","mongo","acl_query","selector", _], ConfEntry}) ->
  281. ConfEntry
  282. end,
  283. cuttlefish_variable:filter_by_prefix("auth.mongo.acl_query.selector", Conf)),
  284. SelectorListList =
  285. lists:map(
  286. fun(SelectorStr) ->
  287. lists:map(fun(Selector) ->
  288. case string:tokens(Selector, "=") of
  289. [Field, Val] -> {list_to_binary(Field), list_to_binary(Val)};
  290. _ -> {<<"username">>, <<"%u">>}
  291. end
  292. end, string:tokens(SelectorStr, ", "))
  293. end,
  294. SelectorStrList),
  295. [{collection, Collection}, {selector, SelectorListList}]
  296. end
  297. end}.