emqx/apps/emqx_auth_ldap/priv/emqx_auth_ldap.schema

177 lines
5.8 KiB
Erlang

%%-*- mode: erlang -*-
%% emqx_auth_ldap config mapping
{mapping, "auth.ldap.servers", "emqx_auth_ldap.ldap", [
{default, "127.0.0.1"},
{datatype, string}
]}.
{mapping, "auth.ldap.port", "emqx_auth_ldap.ldap", [
{default, 389},
{datatype, integer}
]}.
{mapping, "auth.ldap.pool", "emqx_auth_ldap.ldap", [
{default, 8},
{datatype, integer}
]}.
{mapping, "auth.ldap.bind_dn", "emqx_auth_ldap.ldap", [
{datatype, string},
{default, "cn=root,dc=emqx,dc=io"}
]}.
{mapping, "auth.ldap.bind_password", "emqx_auth_ldap.ldap", [
{datatype, string},
{default, "public"}
]}.
{mapping, "auth.ldap.timeout", "emqx_auth_ldap.ldap", [
{default, "30s"},
{datatype, {duration, ms}}
]}.
{mapping, "auth.ldap.ssl", "emqx_auth_ldap.ldap", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.ldap.ssl.certfile", "emqx_auth_ldap.ldap", [
{datatype, string}
]}.
{mapping, "auth.ldap.ssl.keyfile", "emqx_auth_ldap.ldap", [
{datatype, string}
]}.
{mapping, "auth.ldap.ssl.cacertfile", "emqx_auth_ldap.ldap", [
{datatype, string}
]}.
{mapping, "auth.ldap.ssl.verify", "emqx_auth_ldap.ldap", [
{default, verify_none},
{datatype, {enum, [verify_none, verify_peer]}}
]}.
{mapping, "auth.ldap.ssl.fail_if_no_peer_cert", "emqx_auth_ldap.ldap", [
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.ldap.ssl.server_name_indication", "emqx_auth_ldap.ldap", [
{datatype, string}
]}.
{translation, "emqx_auth_ldap.ldap", fun(Conf) ->
A2N = fun(A) -> case inet:parse_address(A) of {ok, N} -> N; _ -> A end end,
Servers = [A2N(A) || A <- string:tokens(cuttlefish:conf_get("auth.ldap.servers", Conf), ",")],
Port = cuttlefish:conf_get("auth.ldap.port", Conf),
Pool = cuttlefish:conf_get("auth.ldap.pool", Conf),
BindDN = cuttlefish:conf_get("auth.ldap.bind_dn", Conf),
BindPassword = cuttlefish:conf_get("auth.ldap.bind_password", Conf),
Timeout = cuttlefish:conf_get("auth.ldap.timeout", Conf),
Filter = fun(Ls) -> [E || E = {_, V} <- Ls, V /= undefined]end,
SslOpts = fun() ->
[{certfile, cuttlefish:conf_get("auth.ldap.ssl.certfile", Conf)},
{keyfile, cuttlefish:conf_get("auth.ldap.ssl.keyfile", Conf)},
{cacertfile, cuttlefish:conf_get("auth.ldap.ssl.cacertfile", Conf, undefined)},
{verify, cuttlefish:conf_get("auth.ldap.ssl.verify", Conf, undefined)},
{server_name_indication, cuttlefish:conf_get("auth.ldap.ssl.server_name_indication", Conf, disable)},
{fail_if_no_peer_cert, cuttlefish:conf_get("auth.ldap.ssl.fail_if_no_peer_cert", Conf, undefined)}]
end,
Opts = [{servers, Servers},
{port, Port},
{timeout, Timeout},
{bind_dn, BindDN},
{bind_password, BindPassword},
{pool, Pool},
{auto_reconnect, 2}],
case cuttlefish:conf_get("auth.ldap.ssl", Conf) of
true -> [{ssl, true}, {sslopts, Filter(SslOpts())}|Opts];
false -> [{ssl, false}|Opts]
end
end}.
{mapping, "auth.ldap.device_dn", "emqx_auth_ldap.device_dn", [
{default, "ou=device,dc=emqx,dc=io"},
{datatype, string}
]}.
{mapping, "auth.ldap.match_objectclass", "emqx_auth_ldap.match_objectclass", [
{default, "mqttUser"},
{datatype, string}
]}.
{mapping, "auth.ldap.custom_base_dn", "emqx_auth_ldap.custom_base_dn", [
{default, "${username_attr}=${user},${device_dn}"},
{datatype, string}
]}.
%% auth.ldap.filters.1.key = "objectClass"
%% auth.ldap.filters.1.value = "mqttUser"
%% auth.ldap.filters.1.op = "and"
%% auth.ldap.filters.2.key = "uiAttr"
%% auth.ldap.filters.2.value "someAttr"
%% auth.ldap.filters.2.op = "or"
%% auth.ldap.filters.3.key = "someKey"
%% auth.ldap.filters.3.value = "someValue"
%% The configuratation structure sent to the application:
%% [{"objectClass","mqttUser"},"and",{"uiAttr","someAttr"},"or",{"someKey","someAttr"}]
%% The resulting LDAP filter would look like this:
%% ==> "|(&(objectClass=Class)(uiAttr=someAttr)(someKey=someValue))"
{translation, "emqx_auth_ldap.filters",
fun(Conf) ->
Settings = cuttlefish_variable:filter_by_prefix("auth.ldap.filters", Conf),
Keys = [{Num, {key, V}} || {["auth","ldap","filters", Num, "key"], V} <- Settings],
Values = [{Num, {value, V}} || {["auth","ldap","filters", Num, "value"], V} <- Settings],
Ops = [{Num, {op, V}} || {["auth","ldap","filters", Num, "op"], V} <- Settings],
RawFilters = Keys ++ Values ++ Ops,
Filters =
lists:foldl(
fun({Num,{T,V}}, Acc)->
maps:update_with(Num,
fun(F)->
maps:put(T,V,F)
end,
#{T=>V}, Acc)
end, #{}, RawFilters),
Order=lists:usort(maps:keys(Filters)),
lists:reverse(
lists:foldl(
fun(F,Acc)->
case F of
#{key:=K, op:=Op, value:=V} -> [Op,{K,V}|Acc];
#{key:=K, value:=V} -> [{K,V}|Acc]
end
end,
[],
lists:map(fun(K) -> maps:get(K, Filters) end, Order)))
end}.
{mapping, "auth.ldap.filters.$num.key", "emqx_auth_ldap.filters", [
{datatype, string}
]}.
{mapping, "auth.ldap.filters.$num.value", "emqx_auth_ldap.filters", [
{datatype, string}
]}.
{mapping, "auth.ldap.filters.$num.op", "emqx_auth_ldap.filters", [
{datatype, {enum, [ "or", "and" ] } }
]}.
{mapping, "auth.ldap.bind_as_user", "emqx_auth_ldap.bind_as_user", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.ldap.username.attributetype", "emqx_auth_ldap.username_attr", [
{default, "uid"},
{datatype, string}
]}.
{mapping, "auth.ldap.password.attributetype", "emqx_auth_ldap.password_attr", [
{default, "userPassword"},
{datatype, string}
]}.