feat(ldap): accept wrapped secrets as passwords
This commit is contained in:
parent
fda395014c
commit
06861e377f
|
@ -204,7 +204,7 @@ backend(get, #{bindings := #{backend := Type}}) ->
|
||||||
undefined ->
|
undefined ->
|
||||||
{404, #{code => ?BACKEND_NOT_FOUND, message => <<"Backend not found">>}};
|
{404, #{code => ?BACKEND_NOT_FOUND, message => <<"Backend not found">>}};
|
||||||
Backend ->
|
Backend ->
|
||||||
{200, to_json(Backend)}
|
{200, to_redacted_json(Backend)}
|
||||||
end;
|
end;
|
||||||
backend(put, #{bindings := #{backend := Backend}, body := Config}) ->
|
backend(put, #{bindings := #{backend := Backend}, body := Config}) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
|
@ -264,9 +264,9 @@ valid_config(_, _, _) ->
|
||||||
{error, invalid_config}.
|
{error, invalid_config}.
|
||||||
|
|
||||||
handle_backend_update_result({ok, #{backend := saml} = State}, _Config) ->
|
handle_backend_update_result({ok, #{backend := saml} = State}, _Config) ->
|
||||||
{200, to_json(maps:without([idp_meta, sp], State))};
|
{200, to_redacted_json(maps:without([idp_meta, sp], State))};
|
||||||
handle_backend_update_result({ok, _State}, Config) ->
|
handle_backend_update_result({ok, _State}, Config) ->
|
||||||
{200, to_json(Config)};
|
{200, to_redacted_json(Config)};
|
||||||
handle_backend_update_result(ok, _) ->
|
handle_backend_update_result(ok, _) ->
|
||||||
204;
|
204;
|
||||||
handle_backend_update_result({error, not_exists}, _) ->
|
handle_backend_update_result({error, not_exists}, _) ->
|
||||||
|
@ -278,9 +278,9 @@ handle_backend_update_result({error, Reason}, _) when is_binary(Reason) ->
|
||||||
handle_backend_update_result({error, Reason}, _) ->
|
handle_backend_update_result({error, Reason}, _) ->
|
||||||
{400, #{code => ?BAD_REQUEST, message => emqx_dashboard_sso:format(["Reason: ", Reason])}}.
|
{400, #{code => ?BAD_REQUEST, message => emqx_dashboard_sso:format(["Reason: ", Reason])}}.
|
||||||
|
|
||||||
to_json(Data) ->
|
to_redacted_json(Data) ->
|
||||||
emqx_utils_maps:jsonable_map(
|
emqx_utils_maps:jsonable_map(
|
||||||
Data,
|
emqx_utils:redact(Data),
|
||||||
fun(K, V) ->
|
fun(K, V) ->
|
||||||
{K, emqx_utils_maps:binary_string(V)}
|
{K, emqx_utils_maps:binary_string(V)}
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,9 +10,11 @@
|
||||||
-include_lib("emqx_dashboard/include/emqx_dashboard.hrl").
|
-include_lib("emqx_dashboard/include/emqx_dashboard.hrl").
|
||||||
-include_lib("snabbkaffe/include/snabbkaffe.hrl").
|
-include_lib("snabbkaffe/include/snabbkaffe.hrl").
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
-include_lib("common_test/include/ct.hrl").
|
||||||
|
|
||||||
-define(LDAP_HOST, "ldap").
|
-define(LDAP_HOST, "ldap").
|
||||||
-define(LDAP_DEFAULT_PORT, 389).
|
-define(LDAP_DEFAULT_PORT, 389).
|
||||||
|
-define(LDAP_PASSWORD, <<"public">>).
|
||||||
-define(LDAP_USER, <<"viewer1">>).
|
-define(LDAP_USER, <<"viewer1">>).
|
||||||
-define(LDAP_USER_PASSWORD, <<"viewer1">>).
|
-define(LDAP_USER_PASSWORD, <<"viewer1">>).
|
||||||
-define(LDAP_BASE_DN, <<"ou=dashboard,dc=emqx,dc=io">>).
|
-define(LDAP_BASE_DN, <<"ou=dashboard,dc=emqx,dc=io">>).
|
||||||
|
@ -128,9 +130,19 @@ t_update({init, Config}) ->
|
||||||
Config;
|
Config;
|
||||||
t_update({'end', _Config}) ->
|
t_update({'end', _Config}) ->
|
||||||
ok;
|
ok;
|
||||||
t_update(_) ->
|
t_update(Config) ->
|
||||||
Path = uri(["sso", "ldap"]),
|
Path = uri(["sso", "ldap"]),
|
||||||
{ok, 200, Result} = request(put, Path, ldap_config(#{<<"enable">> => <<"true">>})),
|
%% NOTE: this time verify that supplying password through file-based secret works.
|
||||||
|
PasswordFilename = filename:join([?config(priv_dir, Config), "passfile"]),
|
||||||
|
ok = file:write_file(PasswordFilename, ?LDAP_PASSWORD),
|
||||||
|
{ok, 200, Result} = request(
|
||||||
|
put,
|
||||||
|
Path,
|
||||||
|
ldap_config(#{
|
||||||
|
<<"enable">> => <<"true">>,
|
||||||
|
<<"password">> => iolist_to_binary(["file://", PasswordFilename])
|
||||||
|
})
|
||||||
|
),
|
||||||
check_running([<<"ldap">>]),
|
check_running([<<"ldap">>]),
|
||||||
?assertMatch(#{backend := <<"ldap">>, enable := true}, decode_json(Result)),
|
?assertMatch(#{backend := <<"ldap">>, enable := true}, decode_json(Result)),
|
||||||
?assertMatch([#{backend := <<"ldap">>, enable := true}], get_sso()),
|
?assertMatch([#{backend := <<"ldap">>, enable := true}], get_sso()),
|
||||||
|
@ -287,7 +299,7 @@ ldap_config(Override) ->
|
||||||
<<"base_dn">> => ?LDAP_BASE_DN,
|
<<"base_dn">> => ?LDAP_BASE_DN,
|
||||||
<<"filter">> => ?LDAP_FILTER_WITH_UID,
|
<<"filter">> => ?LDAP_FILTER_WITH_UID,
|
||||||
<<"username">> => <<"cn=root,dc=emqx,dc=io">>,
|
<<"username">> => <<"cn=root,dc=emqx,dc=io">>,
|
||||||
<<"password">> => <<"public">>,
|
<<"password">> => ?LDAP_PASSWORD,
|
||||||
<<"pool_size">> => 8
|
<<"pool_size">> => 8
|
||||||
},
|
},
|
||||||
Override
|
Override
|
||||||
|
|
|
@ -53,8 +53,6 @@
|
||||||
filter_tokens := params_tokens()
|
filter_tokens := params_tokens()
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-define(ECS, emqx_connector_schema_lib).
|
|
||||||
|
|
||||||
%%=====================================================================
|
%%=====================================================================
|
||||||
%% Hocon schema
|
%% Hocon schema
|
||||||
roots() ->
|
roots() ->
|
||||||
|
@ -63,9 +61,9 @@ roots() ->
|
||||||
fields(config) ->
|
fields(config) ->
|
||||||
[
|
[
|
||||||
{server, server()},
|
{server, server()},
|
||||||
{pool_size, fun ?ECS:pool_size/1},
|
{pool_size, fun emqx_connector_schema_lib:pool_size/1},
|
||||||
{username, fun ensure_username/1},
|
{username, fun ensure_username/1},
|
||||||
{password, fun ?ECS:password/1},
|
{password, emqx_connector_schema_lib:password_field()},
|
||||||
{base_dn,
|
{base_dn,
|
||||||
?HOCON(binary(), #{
|
?HOCON(binary(), #{
|
||||||
desc => ?DESC(base_dn),
|
desc => ?DESC(base_dn),
|
||||||
|
@ -124,7 +122,7 @@ server() ->
|
||||||
ensure_username(required) ->
|
ensure_username(required) ->
|
||||||
true;
|
true;
|
||||||
ensure_username(Field) ->
|
ensure_username(Field) ->
|
||||||
?ECS:username(Field).
|
emqx_connector_schema_lib:username(Field).
|
||||||
|
|
||||||
%% ===================================================================
|
%% ===================================================================
|
||||||
callback_mode() -> always_sync.
|
callback_mode() -> always_sync.
|
||||||
|
@ -223,7 +221,8 @@ connect(Options) ->
|
||||||
OpenOpts = maps:to_list(maps:with([port, sslopts], Conf)),
|
OpenOpts = maps:to_list(maps:with([port, sslopts], Conf)),
|
||||||
case eldap:open([Host], [{log, fun log/3}, {timeout, RequestTimeout} | OpenOpts]) of
|
case eldap:open([Host], [{log, fun log/3}, {timeout, RequestTimeout} | OpenOpts]) of
|
||||||
{ok, Handle} = Ret ->
|
{ok, Handle} = Ret ->
|
||||||
case eldap:simple_bind(Handle, Username, Password) of
|
%% TODO: teach `eldap` to accept 0-arity closures as passwords.
|
||||||
|
case eldap:simple_bind(Handle, Username, emqx_secret:unwrap(Password)) of
|
||||||
ok -> Ret;
|
ok -> Ret;
|
||||||
Error -> Error
|
Error -> Error
|
||||||
end;
|
end;
|
||||||
|
@ -320,13 +319,13 @@ log(Level, Format, Args) ->
|
||||||
).
|
).
|
||||||
|
|
||||||
prepare_template(Config, State) ->
|
prepare_template(Config, State) ->
|
||||||
do_prepare_template(maps:to_list(maps:with([base_dn, filter], Config)), State).
|
maps:fold(fun prepare_template/3, State, Config).
|
||||||
|
|
||||||
do_prepare_template([{base_dn, V} | T], State) ->
|
prepare_template(base_dn, V, State) ->
|
||||||
do_prepare_template(T, State#{base_tokens => emqx_placeholder:preproc_tmpl(V)});
|
State#{base_tokens => emqx_placeholder:preproc_tmpl(V)};
|
||||||
do_prepare_template([{filter, V} | T], State) ->
|
prepare_template(filter, V, State) ->
|
||||||
do_prepare_template(T, State#{filter_tokens => emqx_placeholder:preproc_tmpl(V)});
|
State#{filter_tokens => emqx_placeholder:preproc_tmpl(V)};
|
||||||
do_prepare_template([], State) ->
|
prepare_template(_Entry, _, State) ->
|
||||||
State.
|
State.
|
||||||
|
|
||||||
filter_escape(Binary) when is_binary(Binary) ->
|
filter_escape(Binary) when is_binary(Binary) ->
|
||||||
|
|
Loading…
Reference in New Issue