feat: support check_config callback for authenticator provider
This commit is contained in:
parent
494bac419d
commit
6d9b3ed341
|
@ -116,7 +116,9 @@
|
|||
-type user_info() :: #{user_id := binary(),
|
||||
atom() => term()}.
|
||||
|
||||
-callback refs() -> [{ref, Module, Name}] when Module::module(), Name::atom().
|
||||
%% @doc check_config takes raw config from config file,
|
||||
%% parse and validate it, and reutrn parsed result.
|
||||
-callback check_config(config()) -> config().
|
||||
|
||||
-callback create(Config)
|
||||
-> {ok, State}
|
||||
|
@ -176,6 +178,7 @@
|
|||
, update_user/3
|
||||
, lookup_user/3
|
||||
, list_users/1
|
||||
, check_config/1
|
||||
]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
|
|
|
@ -27,6 +27,11 @@
|
|||
, authn_type/1
|
||||
]).
|
||||
|
||||
%% TODO: certs handling should be moved out of emqx app
|
||||
-ifdef(TEST).
|
||||
-export([convert_certs/2, convert_certs/3, diff_cert/2, clear_certs/2]).
|
||||
-endif.
|
||||
|
||||
-export_type([config/0]).
|
||||
|
||||
-include("logger.hrl").
|
||||
|
@ -151,17 +156,33 @@ do_check_conifg(Config, Providers) ->
|
|||
providers => Providers}),
|
||||
throw(unknown_authn_type);
|
||||
Module ->
|
||||
%% TODO: check if Module:check_config/1 is exported
|
||||
%% so we do not force all providers to implement hocon schema
|
||||
try hocon_schema:check_plain(Module, #{<<"config">> => Config},
|
||||
#{atom_key => true}) of
|
||||
#{config := Result} ->
|
||||
Result
|
||||
do_check_conifg(Type, Config, Module)
|
||||
end.
|
||||
|
||||
do_check_conifg(Type, Config, Module) ->
|
||||
F = case erlang:function_exported(Module, check_config, 1) of
|
||||
true ->
|
||||
fun Module:check_config/1;
|
||||
false ->
|
||||
fun(C) ->
|
||||
#{config := R} =
|
||||
hocon_schema:check_plain(Module, #{<<"config">> => C},
|
||||
#{atom_key => true}),
|
||||
R
|
||||
end
|
||||
end,
|
||||
try
|
||||
F(Config)
|
||||
catch
|
||||
C : E : S ->
|
||||
?SLOG(warning, #{msg => "failed_to_check_config", config => Config}),
|
||||
erlang:raise(C, E, S)
|
||||
end
|
||||
?SLOG(warning, #{msg => "failed_to_check_config",
|
||||
config => Config,
|
||||
type => Type,
|
||||
exception => C,
|
||||
reason => E,
|
||||
stacktrace => S
|
||||
}),
|
||||
throw(bad_authenticator_config)
|
||||
end.
|
||||
|
||||
return_map([L]) -> L;
|
||||
|
|
|
@ -26,13 +26,13 @@
|
|||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include_lib("typerefl/include/types.hrl").
|
||||
|
||||
-export([ fields/1 ]).
|
||||
-export([ roots/0, fields/1 ]).
|
||||
|
||||
-export([ refs/0
|
||||
, create/1
|
||||
-export([ create/1
|
||||
, update/2
|
||||
, authenticate/2
|
||||
, destroy/1
|
||||
, check_config/1
|
||||
]).
|
||||
|
||||
-define(AUTHN, emqx_authentication).
|
||||
|
@ -42,6 +42,8 @@
|
|||
%% Hocon Schema
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
roots() -> [{config, #{type => hoconsc:union([hoconsc:ref(type1), hoconsc:ref(type2)])}}].
|
||||
|
||||
fields(type1) ->
|
||||
[ {mechanism, {enum, ['password-based']}}
|
||||
, {backend, {enum, ['built-in-database']}}
|
||||
|
@ -62,10 +64,11 @@ enable(_) -> undefined.
|
|||
%% Callbacks
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
refs() ->
|
||||
[ hoconsc:ref(?MODULE, type1)
|
||||
, hoconsc:ref(?MODULE, type2)
|
||||
].
|
||||
check_config(C) ->
|
||||
#{config := R} =
|
||||
hocon_schema:check_plain(?MODULE, #{<<"config">> => C},
|
||||
#{atom_key => true}),
|
||||
R.
|
||||
|
||||
create(_Config) ->
|
||||
{ok, #{mark => 1}}.
|
||||
|
@ -268,14 +271,14 @@ t_convert_certs(Config) when is_list(Config) ->
|
|||
, {<<"cacertfile">>, "cacert.pem"}
|
||||
]),
|
||||
|
||||
CertsDir = ?AUTHN:certs_dir([Global, <<"password-based:built-in-database">>]),
|
||||
#{<<"ssl">> := NCerts} = ?AUTHN:convert_certs(CertsDir, #{<<"ssl">> => Certs}),
|
||||
CertsDir = certs_dir(Config, [Global, <<"password-based:built-in-database">>]),
|
||||
#{<<"ssl">> := NCerts} = convert_certs(CertsDir, #{<<"ssl">> => Certs}),
|
||||
?assertEqual(false, diff_cert(maps:get(<<"keyfile">>, NCerts), maps:get(<<"keyfile">>, Certs))),
|
||||
|
||||
Certs2 = certs([ {<<"keyfile">>, "key.pem"}
|
||||
, {<<"certfile">>, "cert.pem"}
|
||||
]),
|
||||
#{<<"ssl">> := NCerts2} = ?AUTHN:convert_certs(CertsDir, #{<<"ssl">> => Certs2}, #{<<"ssl">> => NCerts}),
|
||||
#{<<"ssl">> := NCerts2} = convert_certs(CertsDir, #{<<"ssl">> => Certs2}, #{<<"ssl">> => NCerts}),
|
||||
?assertEqual(false, diff_cert(maps:get(<<"keyfile">>, NCerts2), maps:get(<<"keyfile">>, Certs2))),
|
||||
?assertEqual(maps:get(<<"keyfile">>, NCerts), maps:get(<<"keyfile">>, NCerts2)),
|
||||
?assertEqual(maps:get(<<"certfile">>, NCerts), maps:get(<<"certfile">>, NCerts2)),
|
||||
|
@ -284,13 +287,13 @@ t_convert_certs(Config) when is_list(Config) ->
|
|||
, {<<"certfile">>, "client-cert.pem"}
|
||||
, {<<"cacertfile">>, "cacert.pem"}
|
||||
]),
|
||||
#{<<"ssl">> := NCerts3} = ?AUTHN:convert_certs(CertsDir, #{<<"ssl">> => Certs3}, #{<<"ssl">> => NCerts2}),
|
||||
#{<<"ssl">> := NCerts3} = convert_certs(CertsDir, #{<<"ssl">> => Certs3}, #{<<"ssl">> => NCerts2}),
|
||||
?assertEqual(false, diff_cert(maps:get(<<"keyfile">>, NCerts3), maps:get(<<"keyfile">>, Certs3))),
|
||||
?assertNotEqual(maps:get(<<"keyfile">>, NCerts2), maps:get(<<"keyfile">>, NCerts3)),
|
||||
?assertNotEqual(maps:get(<<"certfile">>, NCerts2), maps:get(<<"certfile">>, NCerts3)),
|
||||
|
||||
?assertEqual(true, filelib:is_regular(maps:get(<<"keyfile">>, NCerts3))),
|
||||
?AUTHN:clear_certs(CertsDir, #{<<"ssl">> => NCerts3}),
|
||||
clear_certs(CertsDir, #{<<"ssl">> => NCerts3}),
|
||||
?assertEqual(false, filelib:is_regular(maps:get(<<"keyfile">>, NCerts3))).
|
||||
|
||||
update_config(Path, ConfigRequest) ->
|
||||
|
@ -305,7 +308,22 @@ certs(Certs) ->
|
|||
|
||||
diff_cert(CertFile, CertPem2) ->
|
||||
{ok, CertPem1} = file:read_file(CertFile),
|
||||
?AUTHN:diff_cert(CertPem1, CertPem2).
|
||||
emqx_authentication_config:diff_cert(CertPem1, CertPem2).
|
||||
|
||||
register_provider(Type, Module) ->
|
||||
ok = ?AUTHN:register_providers([{Type, Module}]).
|
||||
|
||||
certs_dir(CtConfig, Path) ->
|
||||
DataDir = proplists:get_value(data_dir, CtConfig),
|
||||
Dir = filename:join([DataDir | Path]),
|
||||
filelib:ensure_dir(Dir),
|
||||
Dir.
|
||||
|
||||
convert_certs(CertsDir, SslConfig) ->
|
||||
emqx_authentication_config:convert_certs(CertsDir, SslConfig).
|
||||
|
||||
convert_certs(CertsDir, New, Old) ->
|
||||
emqx_authentication_config:convert_certs(CertsDir, New, Old).
|
||||
|
||||
clear_certs(CertsDir, SslConfig) ->
|
||||
emqx_authentication_config:clear_certs(CertsDir, SslConfig).
|
||||
|
|
Loading…
Reference in New Issue