From f3008c74d8b39d8b7e1d8b01e38e43df15715d09 Mon Sep 17 00:00:00 2001 From: firest Date: Thu, 8 Aug 2024 23:33:36 +0800 Subject: [PATCH] tmp --- apps/emqx/rebar.config | 4 +- apps/emqx/src/emqx_channel.erl | 10 +- .../include/emqx_auth_kerberos.hrl | 2 + .../src/emqx_authn_kerberos.erl | 8 +- .../src/emqx_authn_kerberos_schema.erl | 4 +- .../test/emqx_authn_kerberos_SUITE.erl | 282 ++++++++++++++++++ apps/emqx_retainer/rebar.config | 2 +- mix.exs | 2 +- rebar.config | 2 +- 9 files changed, 296 insertions(+), 20 deletions(-) create mode 100644 apps/emqx_auth_kerberos/test/emqx_authn_kerberos_SUITE.erl diff --git a/apps/emqx/rebar.config b/apps/emqx/rebar.config index 7a6ec9810..307c22b98 100644 --- a/apps/emqx/rebar.config +++ b/apps/emqx/rebar.config @@ -47,7 +47,7 @@ {meck, "0.9.2"}, {proper, "1.4.0"}, {bbmustache, "1.10.0"}, - {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.10.0"}}} + {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.12.0"}}} ]}, {extra_src_dirs, [ {"test", [recursive]}, @@ -59,7 +59,7 @@ {meck, "0.9.2"}, {proper, "1.4.0"}, {bbmustache, "1.10.0"}, - {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.9.7"}}} + {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.12.0"}}} ]}, {extra_src_dirs, [{"test", [recursive]}]} ]} diff --git a/apps/emqx/src/emqx_channel.erl b/apps/emqx/src/emqx_channel.erl index b2bdf530d..0d045f840 100644 --- a/apps/emqx/src/emqx_channel.erl +++ b/apps/emqx/src/emqx_channel.erl @@ -395,15 +395,7 @@ handle_in( connecting -> process_connect(NProperties, NChannel); reauthenticating -> - {ok, Auth, NChannel1} = - handle_out( - auth, - {?RC_SUCCESS, NProperties}, - NChannel#channel{conn_state = connected} - ), - {ok, Replies, NChannel2} = - process_connect(NProperties, NChannel1), - {ok, [?REPLY_OUTGOING(Auth) | Replies], NChannel2}; + process_connect(NProperties, NChannel); _ -> handle_out( auth, diff --git a/apps/emqx_auth_kerberos/include/emqx_auth_kerberos.hrl b/apps/emqx_auth_kerberos/include/emqx_auth_kerberos.hrl index f0f490b53..886fb0a2a 100644 --- a/apps/emqx_auth_kerberos/include/emqx_auth_kerberos.hrl +++ b/apps/emqx_auth_kerberos/include/emqx_auth_kerberos.hrl @@ -13,4 +13,6 @@ -define(AUTHN_TYPE_KERBEROS, {?AUTHN_MECHANISM_GSSAPI, ?AUTHN_BACKEND}). +-define(AUTHN_METHOD, <<"GSSAPI-KERBEROS">>). + -endif. diff --git a/apps/emqx_auth_kerberos/src/emqx_authn_kerberos.erl b/apps/emqx_auth_kerberos/src/emqx_authn_kerberos.erl index a0a2d81f8..7daec0e92 100644 --- a/apps/emqx_auth_kerberos/src/emqx_authn_kerberos.erl +++ b/apps/emqx_auth_kerberos/src/emqx_authn_kerberos.erl @@ -44,7 +44,7 @@ destroy(_) -> authenticate( #{ - auth_method := <<"GSSAPI-KERBEROS">>, + auth_method := ?AUTHN_METHOD, auth_data := AuthData, auth_cache := AuthCache }, @@ -55,8 +55,10 @@ authenticate( auth_continue(SaslConn, AuthData); _ -> case auth_new(Principal) of - {ok, SaslConn} -> auth_begin(SaslConn, AuthData); - Error -> Error + {ok, SaslConn} -> + auth_begin(SaslConn, AuthData); + Error -> + Error end end; authenticate(_Credential, _State) -> diff --git a/apps/emqx_auth_kerberos/src/emqx_authn_kerberos_schema.erl b/apps/emqx_auth_kerberos/src/emqx_authn_kerberos_schema.erl index 444340401..c189b2d9e 100644 --- a/apps/emqx_auth_kerberos/src/emqx_authn_kerberos_schema.erl +++ b/apps/emqx_auth_kerberos/src/emqx_authn_kerberos_schema.erl @@ -47,9 +47,7 @@ fields(kerberos) -> })}, {keytab_file, ?HOCON(binary(), #{ - required => false, - %% This is hidden for now because it has to be /etc/krb5.keytab - importance => ?IMPORTANCE_HIDDEN, + default => <<"/etc/krb5.keytab">>, desc => ?DESC(keytab_file) })} ]. diff --git a/apps/emqx_auth_kerberos/test/emqx_authn_kerberos_SUITE.erl b/apps/emqx_auth_kerberos/test/emqx_authn_kerberos_SUITE.erl new file mode 100644 index 000000000..cfdb70e8f --- /dev/null +++ b/apps/emqx_auth_kerberos/test/emqx_authn_kerberos_SUITE.erl @@ -0,0 +1,282 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved. +%%-------------------------------------------------------------------- + +-module(emqx_authn_kerberos_SUITE). + +-compile(export_all). +-compile(nowarn_export_all). + +-include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). +-include("emqx_auth_kerberos.hrl"). + +-include_lib("emqx/include/emqx_mqtt.hrl"). +-include_lib("emqx_auth/include/emqx_authn.hrl"). + +-define(PATH, [authentication]). + +-define(INVALID_SVR_PRINCIPAL, <<"not-exists/emqx-full.test@KDC.EMQX.NET">>). + +-define(SVR_HOST, "emqx.emqx.net"). +-define(SVR_PRINCIPAL, <<"emqx/emqx.emqx.net@KDC.EMQX.NET">>). +-define(SVR_KEYTAB_FILE, <<"/home/firest/server.keytab">>). + +-define(CLI_NAME, "client"). +-define(CLI_PRINCIPAL, <<"client@KDC.EMQX.NET">>). +-define(CLI_KEYTAB_FILE, <<"/home/firest/client.keytab">>). + +-define(HOST, "127.0.0.1"). +-define(PORT, 1883). + +-define(SERVER, "emqx"). + +all() -> + emqx_common_test_helpers:all(?MODULE). + +init_per_suite(Config) -> + Apps = emqx_cth_suite:start([emqx, emqx_conf, emqx_auth, emqx_auth_kerberos], #{ + work_dir => ?config(priv_dir, Config) + }), + IdleTimeout = emqx_config:get([mqtt, idle_timeout]), + [{apps, Apps}, {idle_timeout, IdleTimeout} | Config]. + +end_per_suite(Config) -> + ok = emqx_config:put([mqtt, idle_timeout], ?config(idle_timeout, Config)), + ok = emqx_cth_suite:stop(?config(apps, Config)), + ok. + +init_per_testcase(_Case, Config) -> + emqx_authn_test_lib:delete_authenticators( + [authentication], + ?GLOBAL + ), + Config. + +end_per_testcase(_Case, Config) -> + Config. + +%%------------------------------------------------------------------------------ +%% Tests +%%------------------------------------------------------------------------------ + +t_create(_Config) -> + ValidConfig = raw_config(), + + {ok, _} = emqx:update_config( + ?PATH, + {create_authenticator, ?GLOBAL, ValidConfig} + ), + + {ok, [#{provider := emqx_authn_kerberos}]} = + emqx_authn_chains:list_authenticators(?GLOBAL). + +t_create_invalid(_Config) -> + InvalidConfig0 = raw_config(), + InvalidConfig = InvalidConfig0#{<<"principal">> := ?INVALID_SVR_PRINCIPAL}, + + {error, _} = emqx:update_config( + ?PATH, + {create_authenticator, ?GLOBAL, InvalidConfig} + ), + + ?assertEqual( + {error, {not_found, {chain, ?GLOBAL}}}, + emqx_authn_chains:list_authenticators(?GLOBAL) + ). + +t_authenticate(_Config) -> + init_auth(), + + {ok, Handler, CT1} = setup_cli(), + {ok, C} = emqtt:start_link( + #{ + host => ?HOST, + port => ?PORT, + proto_ver => v5, + properties => + #{ + 'Authentication-Method' => ?AUTHN_METHOD, + 'Authentication-Data' => CT1 + }, + custom_auth_callbacks => + #{ + init => auth_init(Handler), + handle_auth => fun auth_handle/3 + } + } + ), + ?assertMatch({ok, _}, emqtt:connect(C)), + stop_cli(Handler), + ok. + +t_authenticate_bad_props(_Config) -> + erlang:process_flag(trap_exit, true), + init_auth(), + + {ok, Handler, CT1} = setup_cli(), + {ok, C} = emqtt:start_link( + #{ + host => ?HOST, + port => ?PORT, + proto_ver => v5, + properties => + #{ + 'Authentication-Method' => <<"SCRAM-SHA-512">>, + 'Authentication-Data' => CT1 + }, + custom_auth_callbacks => + #{ + init => auth_init(Handler), + handle_auth => fun auth_handle/3 + } + } + ), + + ?assertMatch({error, {not_authorized, _}}, emqtt:connect(C)), + stop_cli(Handler), + ok. + +t_authenticate_bad_token(_Config) -> + erlang:process_flag(trap_exit, true), + init_auth(), + + {ok, Handler, CT1} = setup_cli(), + {ok, C} = emqtt:start_link( + #{ + host => ?HOST, + port => ?PORT, + proto_ver => v5, + properties => + #{ + 'Authentication-Method' => <<"SCRAM-SHA-512">>, + 'Authentication-Data' => <> + }, + custom_auth_callbacks => + #{ + init => auth_init(Handler), + handle_auth => fun auth_handle/3 + } + } + ), + + ?assertMatch({error, {not_authorized, _}}, emqtt:connect(C)), + stop_cli(Handler), + ok. + +t_destroy(_) -> + State = init_auth(), + + emqx_authn_test_lib:delete_authenticators( + [authentication], + ?GLOBAL + ), + + {ok, Handler, CT1} = setup_cli(), + + ?assertMatch( + ignore, + emqx_authn_mongodb:authenticate( + #{ + auth_method => ?AUTHN_METHOD, + auth_data => CT1, + auth_cache => undefined + }, + State + ) + ), + + stop_cli(Handler), + ok. + +%%------------------------------------------------------------------------------ +%% Helpers +%%------------------------------------------------------------------------------ + +raw_config() -> + #{ + <<"mechanism">> => <<"gssapi">>, + <<"backend">> => <<"kerberos">>, + <<"principal">> => ?SVR_PRINCIPAL, + <<"keytab_file">> => ?SVR_KEYTAB_FILE + }. + +init_auth() -> + Config = raw_config(), + + {ok, _} = emqx:update_config( + ?PATH, + {create_authenticator, ?GLOBAL, Config} + ), + + {ok, [#{state := State}]} = emqx_authn_chains:list_authenticators(?GLOBAL), + + State. + +%%------------------------------------------------------------------------------ +%% Custom auth + +auth_init(Handler) -> + fun() -> #{handler => Handler, step => 1} end. + +auth_handle(AuthState, Reason, Props) -> + ct:pal(">>> auth packet received:\n rc: ~p\n props:\n ~p", [Reason, Props]), + do_auth_handle(AuthState, Reason, Props). + +do_auth_handle( + #{handler := Handler, step := Step} = AuthState0, + continue_authentication, + #{ + 'Authentication-Method' := ?AUTHN_METHOD, + 'Authentication-Data' := ST + } +) when Step =< 3 -> + {ok, CT} = call_cli_agent(Handler, {step, ST}), + AuthState = AuthState0#{step := Step + 1}, + OutProps = #{ + 'Authentication-Method' => ?AUTHN_METHOD, + 'Authentication-Data' => CT + }, + {continue, {?RC_CONTINUE_AUTHENTICATION, OutProps}, AuthState}; +do_auth_handle(_AuthState, _Reason, _Props) -> + {stop, protocol_error}. + +%%------------------------------------------------------------------------------ +%% Client Agent + +setup_cli() -> + Pid = erlang:spawn(fun() -> cli_agent_loop(#{}) end), + {ok, CT1} = call_cli_agent(Pid, setup), + {ok, Pid, CT1}. + +call_cli_agent(Pid, Msg) -> + Ref = erlang:make_ref(), + erlang:send(Pid, {call, self(), Ref, Msg}), + receive + {Ref, Data} -> + {ok, Data} + after 3000 -> + error("client agent timeout") + end. + +stop_cli(Pid) -> + erlang:send(Pid, stop). + +cli_agent_loop(State) -> + receive + stop -> + ok; + {call, From, Ref, Msg} -> + {ok, Reply, State2} = cli_agent_handler(Msg, State), + erlang:send(From, {Ref, Reply}), + cli_agent_loop(State2) + end. + +cli_agent_handler(setup, State) -> + ok = sasl_auth:kinit(?CLI_KEYTAB_FILE, ?CLI_PRINCIPAL), + {ok, Client} = sasl_auth:client_new(?SERVER, ?SVR_HOST, ?CLI_PRINCIPAL, ?CLI_NAME), + {ok, {sasl_continue, CT1}} = sasl_auth:client_start(Client), + {ok, CT1, State#{client => Client}}; +cli_agent_handler({step, ST}, #{client := Client} = State) -> + {ok, {_, CT}} = sasl_auth:client_step(Client, ST), + {ok, CT, State}. diff --git a/apps/emqx_retainer/rebar.config b/apps/emqx_retainer/rebar.config index 33dd50a4d..ddab8c160 100644 --- a/apps/emqx_retainer/rebar.config +++ b/apps/emqx_retainer/rebar.config @@ -30,7 +30,7 @@ {profiles, [ {test, [ {deps, [ - {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.10.0"}}} + {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.2.3.4"}}} ]} ]} ]}. diff --git a/mix.exs b/mix.exs index e45907d5a..fa8025e6d 100644 --- a/mix.exs +++ b/mix.exs @@ -246,7 +246,7 @@ defmodule EMQXUmbrella.MixProject do def common_dep(:emqtt), do: {:emqtt, - github: "emqx/emqtt", tag: "1.10.1", override: true, system_env: maybe_no_quic_env()} + github: "emqx/emqtt", tag: "1.12.0", override: true, system_env: maybe_no_quic_env()} def common_dep(:typerefl), do: {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true} diff --git a/rebar.config b/rebar.config index b260561cb..4147d084e 100644 --- a/rebar.config +++ b/rebar.config @@ -91,7 +91,7 @@ {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.7"}}}, {replayq, {git, "https://github.com/emqx/replayq.git", {tag, "0.3.8"}}}, {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}, - {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.10.1"}}}, + {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.12.0"}}}, {rulesql, {git, "https://github.com/emqx/rulesql", {tag, "0.2.1"}}}, % NOTE: depends on recon 2.5.x {observer_cli, "1.7.1"},