fix(authn api): add method for removing listener-specific chains

This commit is contained in:
Ilya Averyanov 2022-05-30 15:31:51 +03:00
parent 2738eadd3a
commit 4cae80c8d2
4 changed files with 133 additions and 0 deletions

View File

@ -52,6 +52,7 @@
-type update_request() :: -type update_request() ::
{create_authenticator, chain_name(), map()} {create_authenticator, chain_name(), map()}
| {delete_authenticator, chain_name(), authenticator_id()} | {delete_authenticator, chain_name(), authenticator_id()}
| {delete_authenticators, chain_name()}
| {update_authenticator, chain_name(), authenticator_id(), map()} | {update_authenticator, chain_name(), authenticator_id(), map()}
| {move_authenticator, chain_name(), authenticator_id(), position()}. | {move_authenticator, chain_name(), authenticator_id(), position()}.
@ -88,6 +89,8 @@ do_pre_config_update({delete_authenticator, _ChainName, AuthenticatorID}, OldCon
OldConfig OldConfig
), ),
{ok, NewConfig}; {ok, NewConfig};
do_pre_config_update({delete_authenticators, _ChainName}, _OldConfig) ->
{ok, []};
do_pre_config_update({update_authenticator, ChainName, AuthenticatorID, Config}, OldConfig) -> do_pre_config_update({update_authenticator, ChainName, AuthenticatorID, Config}, OldConfig) ->
CertsDir = certs_dir(ChainName, AuthenticatorID), CertsDir = certs_dir(ChainName, AuthenticatorID),
NewConfig = lists:map( NewConfig = lists:map(
@ -156,6 +159,25 @@ do_post_config_update(
{error, Reason} -> {error, Reason} ->
{error, Reason} {error, Reason}
end; end;
do_post_config_update(
{delete_authenticators, ChainName},
_NewConfig,
OldConfig,
_AppEnvs
) ->
case emqx_authentication:delete_chain(ChainName) of
ok ->
lists:foreach(
fun(Config) ->
AuthenticatorID = authenticator_id(Config),
CertsDir = certs_dir(ChainName, AuthenticatorID),
ok = clear_certs(CertsDir, Config)
end,
to_list(OldConfig)
);
{error, Reason} ->
{error, Reason}
end;
do_post_config_update( do_post_config_update(
{update_authenticator, ChainName, AuthenticatorID, Config}, {update_authenticator, ChainName, AuthenticatorID, Config},
NewConfig, NewConfig,

View File

@ -49,6 +49,13 @@ emqx_authn_api {
} }
} }
listeners_listener_id_authentication_delete {
desc {
en: """Delete listener-specific authentication."""
zh: """删除特定于侦听器的身份验证。"""
}
}
listeners_listener_id_authentication_post { listeners_listener_id_authentication_post {
desc { desc {
en: """Create authenticator for listener authentication.""" en: """Create authenticator for listener authentication."""

View File

@ -253,6 +253,15 @@ schema("/listeners/:listener_id/authentication") ->
) )
} }
}, },
delete => #{
tags => ?API_TAGS_SINGLE,
description => ?DESC(listeners_listener_id_authentication_delete),
parameters => [param_listener_id()],
responses => #{
204 => <<"Authentication chain deleted">>,
404 => error_codes([?NOT_FOUND], <<"Not Found">>)
}
},
post => #{ post => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => ?DESC(listeners_listener_id_authentication_post), description => ?DESC(listeners_listener_id_authentication_post),
@ -642,6 +651,13 @@ listener_authenticators(get, #{bindings := #{listener_id := ListenerID}}) ->
fun(Type, Name, _) -> fun(Type, Name, _) ->
list_authenticators([listeners, Type, Name, authentication]) list_authenticators([listeners, Type, Name, authentication])
end end
);
listener_authenticators(delete, #{bindings := #{listener_id := ListenerID}}) ->
with_listener(
ListenerID,
fun(Type, Name, ChainName) ->
delete_authenticators([listeners, Type, Name, authentication], ChainName)
end
). ).
listener_authenticator(get, #{bindings := #{listener_id := ListenerID, id := AuthenticatorID}}) -> listener_authenticator(get, #{bindings := #{listener_id := ListenerID, id := AuthenticatorID}}) ->
@ -1094,6 +1110,16 @@ delete_authenticator(ConfKeyPath, ChainName, AuthenticatorID) ->
serialize_error(Reason) serialize_error(Reason)
end. end.
delete_authenticators(ConfKeyPath, ChainName) ->
case update_config(ConfKeyPath, {delete_authenticators, ChainName}) of
{ok, _} ->
{204};
{error, {_PrePostConfigUpdate, emqx_authentication, Reason}} ->
serialize_error(Reason);
{error, Reason} ->
serialize_error(Reason)
end.
move_authenticator(ConfKeyPath, ChainName, AuthenticatorID, Position) -> move_authenticator(ConfKeyPath, ChainName, AuthenticatorID, Position) ->
case parse_position(Position) of case parse_position(Position) of
{ok, NPosition} -> {ok, NPosition} ->

View File

@ -657,6 +657,84 @@ test_authenticator_import_users(PathPrefix) ->
{ok, 204, _} = request(post, ImportUri, #{filename => CSVFileName}). {ok, 204, _} = request(post, ImportUri, #{filename => CSVFileName}).
t_switch_to_global_chain(_) ->
{ok, 200, _} = request(
post,
uri([?CONF_NS]),
emqx_authn_test_lib:built_in_database_example()
),
{ok, 200, _} = request(
post,
uri([listeners, "tcp:default", ?CONF_NS]),
emqx_authn_test_lib:built_in_database_example()
),
GlobalUser = #{user_id => <<"global_user">>, password => <<"p1">>},
{ok, 201, _} = request(
post,
uri([?CONF_NS, "password_based:built_in_database", "users"]),
GlobalUser
),
ListenerUser = #{user_id => <<"listener_user">>, password => <<"p1">>},
{ok, 201, _} = request(
post,
uri([listeners, "tcp:default", ?CONF_NS, "password_based:built_in_database", "users"]),
ListenerUser
),
process_flag(trap_exit, true),
%% Listener user should be OK
{ok, Client0} = emqtt:start_link([
{username, <<"listener_user">>},
{password, <<"p1">>}
]),
?assertMatch(
{ok, _},
emqtt:connect(Client0)
),
ok = emqtt:disconnect(Client0),
%% Global user should not be OK
{ok, Client1} = emqtt:start_link([
{username, <<"global_user">>},
{password, <<"p1">>}
]),
?assertMatch(
{error, {unauthorized_client, _}},
emqtt:connect(Client1)
),
{ok, 204, _} = request(
delete,
uri([listeners, "tcp:default", ?CONF_NS])
),
%% Listener user should not be OK local chain removed
{ok, Client2} = emqtt:start_link([
{username, <<"listener_user">>},
{password, <<"p1">>}
]),
?assertMatch(
{error, {unauthorized_client, _}},
emqtt:connect(Client2)
),
%% Global user should be now OK, switched back to the global chain
{ok, Client3} = emqtt:start_link([
{username, <<"global_user">>},
{password, <<"p1">>}
]),
?assertMatch(
{ok, _},
emqtt:connect(Client3)
),
ok = emqtt:disconnect(Client3).
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% Helpers %% Helpers
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------