293 lines
9.6 KiB
Erlang
293 lines
9.6 KiB
Erlang
%%-*- mode: erlang -*-
|
|
%% emqx_auth_mongo config mapping
|
|
|
|
{mapping, "auth.mongo.type", "emqx_auth_mongo.server", [
|
|
{default, single},
|
|
{datatype, {enum, [single, unknown, sharded, rs]}}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.rs_set_name", "emqx_auth_mongo.server", [
|
|
{default, "mqtt"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.server", "emqx_auth_mongo.server", [
|
|
{default, "127.0.0.1:27017"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.pool", "emqx_auth_mongo.server", [
|
|
{default, 8},
|
|
{datatype, integer}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.login", "emqx_auth_mongo.server", [
|
|
{default, ""},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.password", "emqx_auth_mongo.server", [
|
|
{default, ""},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.database", "emqx_auth_mongo.server", [
|
|
{default, "mqtt"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.auth_source", "emqx_auth_mongo.server", [
|
|
{default, "mqtt"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.ssl", "emqx_auth_mongo.server", [
|
|
{default, false},
|
|
{datatype, {enum, [true, false]}}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.ssl_opts.keyfile", "emqx_auth_mongo.server", [
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.ssl_opts.certfile", "emqx_auth_mongo.server", [
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.ssl_opts.cacertfile", "emqx_auth_mongo.server", [
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.w_mode", "emqx_auth_mongo.server", [
|
|
{default, undef},
|
|
{datatype, {enum, [safe, unsafe, undef]}}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.r_mode", "emqx_auth_mongo.server", [
|
|
{default, undef},
|
|
{datatype, {enum, [master, slave_ok, undef]}}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.topology.$name", "emqx_auth_mongo.server", [
|
|
{datatype, integer}
|
|
]}.
|
|
|
|
{translation, "emqx_auth_mongo.server", fun(Conf) ->
|
|
H = cuttlefish:conf_get("auth.mongo.server", Conf),
|
|
Hosts = string:tokens(H, ","),
|
|
Type0 = cuttlefish:conf_get("auth.mongo.type", Conf),
|
|
Pool = cuttlefish:conf_get("auth.mongo.pool", Conf),
|
|
Login = cuttlefish:conf_get("auth.mongo.login", Conf),
|
|
Passwd = cuttlefish:conf_get("auth.mongo.password", Conf),
|
|
DB = cuttlefish:conf_get("auth.mongo.database", Conf),
|
|
AuthSrc = cuttlefish:conf_get("auth.mongo.auth_source", Conf),
|
|
R = cuttlefish:conf_get("auth.mongo.w_mode", Conf),
|
|
W = cuttlefish:conf_get("auth.mongo.r_mode", Conf),
|
|
Login0 = case Login =:= [] of
|
|
true -> [];
|
|
false -> [{login, list_to_binary(Login)}]
|
|
end,
|
|
Passwd0 = case Passwd =:= [] of
|
|
true -> [];
|
|
false -> [{password, list_to_binary(Passwd)}]
|
|
end,
|
|
W0 = case W =:= undef of
|
|
true -> [];
|
|
false -> [{w_mode, W}]
|
|
end,
|
|
R0 = case R =:= undef of
|
|
true -> [];
|
|
false -> [{r_mode, R}]
|
|
end,
|
|
Ssl = case cuttlefish:conf_get("auth.mongo.ssl", Conf) of
|
|
true ->
|
|
Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
|
|
SslOpts = fun(Prefix) ->
|
|
Filter([{keyfile, cuttlefish:conf_get(Prefix ++ ".keyfile", Conf, undefined)},
|
|
{certfile, cuttlefish:conf_get(Prefix ++ ".certfile", Conf, undefined)},
|
|
{cacertfile, cuttlefish:conf_get(Prefix ++ ".cacertfile", Conf, undefined)}])
|
|
end,
|
|
[{ssl, true}, {ssl_opts, SslOpts("auth.mongo.ssl_opts")}];
|
|
false ->
|
|
[]
|
|
end,
|
|
WorkerOptions = [{database, list_to_binary(DB)}, {auth_source, list_to_binary(AuthSrc)}]
|
|
++ Login0 ++ Passwd0 ++ W0 ++ R0 ++ Ssl,
|
|
|
|
Vars = cuttlefish_variable:fuzzy_matches(["auth", "mongo", "topology", "$name"], Conf),
|
|
Options = lists:map(fun({_, Name}) ->
|
|
Name2 = case Name of
|
|
"local_threshold_ms" -> "localThresholdMS";
|
|
"connect_timeout_ms" -> "connectTimeoutMS";
|
|
"socket_timeout_ms" -> "socketTimeoutMS";
|
|
"server_selection_timeout_ms" -> "serverSelectionTimeoutMS";
|
|
"wait_queue_timeout_ms" -> "waitQueueTimeoutMS";
|
|
"heartbeat_frequency_ms" -> "heartbeatFrequencyMS";
|
|
"min_heartbeat_frequency_ms" -> "minHeartbeatFrequencyMS";
|
|
_ -> Name
|
|
end,
|
|
{list_to_atom(Name2), cuttlefish:conf_get("auth.mongo.topology."++Name, Conf)}
|
|
end, Vars),
|
|
|
|
Type = case Type0 =:= rs of
|
|
true -> {Type0, list_to_binary(cuttlefish:conf_get("auth.mongo.rs_set_name", Conf))};
|
|
false -> Type0
|
|
end,
|
|
[{type, Type},
|
|
{hosts, Hosts},
|
|
{options, Options},
|
|
{worker_options, WorkerOptions},
|
|
{auto_reconnect, 1},
|
|
{pool_size, Pool}]
|
|
end}.
|
|
|
|
%% The mongodb operation timeout is specified by the value of `cursor_timeout` from application config,
|
|
%% or `infinity` if `cursor_timeout` not specified
|
|
{mapping, "auth.mongo.query_timeout", "mongodb.cursor_timeout", [
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{translation, "mongodb.cursor_timeout", fun(Conf) ->
|
|
case cuttlefish:conf_get("auth.mongo.query_timeout", Conf, undefined) of
|
|
undefined -> infinity;
|
|
Duration ->
|
|
case cuttlefish_duration:parse(Duration, ms) of
|
|
{error, Reason} -> error(Reason);
|
|
Ms when is_integer(Ms) -> Ms
|
|
end
|
|
end
|
|
end}.
|
|
|
|
{mapping, "auth.mongo.auth_query.collection", "emqx_auth_mongo.auth_query", [
|
|
{default, "mqtt_user"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.auth_query.password_field", "emqx_auth_mongo.auth_query", [
|
|
{default, "password"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.auth_query.password_hash", "emqx_auth_mongo.auth_query", [
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.auth_query.selector", "emqx_auth_mongo.auth_query", [
|
|
{default, ""},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{translation, "emqx_auth_mongo.auth_query", fun(Conf) ->
|
|
case cuttlefish:conf_get("auth.mongo.auth_query.collection", Conf) of
|
|
undefined -> cuttlefish:unset();
|
|
Collection ->
|
|
PasswordField = cuttlefish:conf_get("auth.mongo.auth_query.password_field", Conf),
|
|
PasswordHash = cuttlefish:conf_get("auth.mongo.auth_query.password_hash", Conf),
|
|
SelectorStr = cuttlefish:conf_get("auth.mongo.auth_query.selector", Conf),
|
|
SelectorList =
|
|
lists:map(fun(Selector) ->
|
|
case string:tokens(Selector, "=") of
|
|
[Field, Val] -> {list_to_binary(Field), list_to_binary(Val)};
|
|
_ -> {<<"username">>, <<"%u">>}
|
|
end
|
|
end, string:tokens(SelectorStr, ", ")),
|
|
|
|
PasswordFields = [list_to_binary(Field) || Field <- string:tokens(PasswordField, ",")],
|
|
HashValue =
|
|
case string:tokens(PasswordHash, ",") of
|
|
[Hash] -> list_to_atom(Hash);
|
|
[Prefix, Suffix] -> {list_to_atom(Prefix), list_to_atom(Suffix)};
|
|
[Hash, MacFun, Iterations, Dklen] -> {list_to_atom(Hash), list_to_atom(MacFun), list_to_integer(Iterations), list_to_integer(Dklen)};
|
|
_ -> plain
|
|
end,
|
|
[{collection, Collection},
|
|
{password_field, PasswordFields},
|
|
{password_hash, HashValue},
|
|
{selector, SelectorList}]
|
|
end
|
|
end}.
|
|
|
|
{mapping, "auth.mongo.super_query", "emqx_auth_mongo.super_query", [
|
|
{default, off},
|
|
{datatype, flag}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.super_query.collection", "emqx_auth_mongo.super_query", [
|
|
{default, "mqtt_user"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.super_query.super_field", "emqx_auth_mongo.super_query", [
|
|
{default, "is_superuser"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.super_query.selector", "emqx_auth_mongo.super_query", [
|
|
{default, ""},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{translation, "emqx_auth_mongo.super_query", fun(Conf) ->
|
|
case cuttlefish:conf_get("auth.mongo.super_query.collection", Conf) of
|
|
undefined -> cuttlefish:unset();
|
|
Collection ->
|
|
SuperField = cuttlefish:conf_get("auth.mongo.super_query.super_field", Conf),
|
|
SelectorStr = cuttlefish:conf_get("auth.mongo.super_query.selector", Conf),
|
|
SelectorList =
|
|
lists:map(fun(Selector) ->
|
|
case string:tokens(Selector, "=") of
|
|
[Field, Val] -> {list_to_binary(Field), list_to_binary(Val)};
|
|
_ -> {<<"username">>, <<"%u">>}
|
|
end
|
|
end, string:tokens(SelectorStr, ", ")),
|
|
[{collection, Collection}, {super_field, SuperField}, {selector, SelectorList}]
|
|
end
|
|
end}.
|
|
|
|
{mapping, "auth.mongo.acl_query", "emqx_auth_mongo.acl_query", [
|
|
{default, off},
|
|
{datatype, flag}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.acl_query.collection", "emqx_auth_mongo.acl_query", [
|
|
{default, "mqtt_user"},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{mapping, "auth.mongo.acl_query.selector", "emqx_auth_mongo.acl_query", [
|
|
{default, ""},
|
|
{datatype, string}
|
|
]}.
|
|
{mapping, "auth.mongo.acl_query.selector.$id", "emqx_auth_mongo.acl_query", [
|
|
{default, ""},
|
|
{datatype, string}
|
|
]}.
|
|
|
|
{translation, "emqx_auth_mongo.acl_query", fun(Conf) ->
|
|
case cuttlefish:conf_get("auth.mongo.acl_query.collection", Conf) of
|
|
undefined -> cuttlefish:unset();
|
|
Collection ->
|
|
SelectorStrList =
|
|
lists:map(
|
|
fun
|
|
({["auth","mongo","acl_query","selector"], ConfEntry}) ->
|
|
ConfEntry;
|
|
({["auth","mongo","acl_query","selector", _], ConfEntry}) ->
|
|
ConfEntry
|
|
end,
|
|
cuttlefish_variable:filter_by_prefix("auth.mongo.acl_query.selector", Conf)),
|
|
SelectorListList =
|
|
lists:map(
|
|
fun(SelectorStr) ->
|
|
lists:map(fun(Selector) ->
|
|
case string:tokens(Selector, "=") of
|
|
[Field, Val] -> {list_to_binary(Field), list_to_binary(Val)};
|
|
_ -> {<<"username">>, <<"%u">>}
|
|
end
|
|
end, string:tokens(SelectorStr, ", "))
|
|
end,
|
|
SelectorStrList),
|
|
[{collection, Collection}, {selector, SelectorListList}]
|
|
end
|
|
end}.
|