Compare commits
9 Commits
master
...
0731-authn
Author | SHA1 | Date |
---|---|---|
![]() |
579c28e9ab | |
![]() |
f3008c74d8 | |
![]() |
9ba0c33256 | |
![]() |
af28b52152 | |
![]() |
6364bab0a6 | |
![]() |
30420f0481 | |
![]() |
319530ddf2 | |
![]() |
7a2d9c6d25 | |
![]() |
1270e6a64d |
|
@ -16,24 +16,6 @@ services:
|
||||||
user: "${DOCKER_USER:-root}"
|
user: "${DOCKER_USER:-root}"
|
||||||
volumes:
|
volumes:
|
||||||
- /tmp/emqx-ci/emqx-shared-secret:/var/lib/secret
|
- /tmp/emqx-ci/emqx-shared-secret:/var/lib/secret
|
||||||
kdc:
|
|
||||||
hostname: kdc.emqx.net
|
|
||||||
image: ghcr.io/emqx/emqx-builder/5.3-9:1.15.7-26.2.5-3-ubuntu22.04
|
|
||||||
container_name: kdc.emqx.net
|
|
||||||
expose:
|
|
||||||
- 88 # kdc
|
|
||||||
- 749 # admin server
|
|
||||||
# ports:
|
|
||||||
# - 88:88
|
|
||||||
# - 749:749
|
|
||||||
networks:
|
|
||||||
emqx_bridge:
|
|
||||||
volumes:
|
|
||||||
- /tmp/emqx-ci/emqx-shared-secret:/var/lib/secret
|
|
||||||
- ./kerberos/krb5.conf:/etc/kdc/krb5.conf
|
|
||||||
- ./kerberos/krb5.conf:/etc/krb5.conf
|
|
||||||
- ./kerberos/run.sh:/usr/bin/run.sh
|
|
||||||
command: run.sh
|
|
||||||
kafka_1:
|
kafka_1:
|
||||||
image: wurstmeister/kafka:2.13-2.8.1
|
image: wurstmeister/kafka:2.13-2.8.1
|
||||||
# ports:
|
# ports:
|
||||||
|
@ -76,4 +58,3 @@ services:
|
||||||
- ./kerberos/krb5.conf:/etc/kdc/krb5.conf
|
- ./kerberos/krb5.conf:/etc/kdc/krb5.conf
|
||||||
- ./kerberos/krb5.conf:/etc/krb5.conf
|
- ./kerberos/krb5.conf:/etc/krb5.conf
|
||||||
command: kafka-entrypoint.sh
|
command: kafka-entrypoint.sh
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
version: '3.9'
|
||||||
|
|
||||||
|
services:
|
||||||
|
kdc:
|
||||||
|
hostname: kdc.emqx.net
|
||||||
|
image: ghcr.io/emqx/emqx-builder/5.3-9:1.15.7-26.2.5-3-ubuntu22.04
|
||||||
|
container_name: kdc.emqx.net
|
||||||
|
expose:
|
||||||
|
- 88 # kdc
|
||||||
|
- 749 # admin server
|
||||||
|
# ports:
|
||||||
|
# - 88:88
|
||||||
|
# - 749:749
|
||||||
|
networks:
|
||||||
|
emqx_bridge:
|
||||||
|
volumes:
|
||||||
|
- /tmp/emqx-ci/emqx-shared-secret:/var/lib/secret
|
||||||
|
- ./kerberos/krb5.conf:/etc/kdc/krb5.conf
|
||||||
|
- ./kerberos/krb5.conf:/etc/krb5.conf
|
||||||
|
- ./kerberos/run.sh:/usr/bin/run.sh
|
||||||
|
command: run.sh
|
|
@ -2,6 +2,7 @@ version: '3.9'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
erlang:
|
erlang:
|
||||||
|
hostname: erlang.emqx.net
|
||||||
container_name: erlang
|
container_name: erlang
|
||||||
image: ${DOCKER_CT_RUNNER_IMAGE:-ghcr.io/emqx/emqx-builder/5.3-9:1.15.7-26.2.5-3-ubuntu22.04}
|
image: ${DOCKER_CT_RUNNER_IMAGE:-ghcr.io/emqx/emqx-builder/5.3-9:1.15.7-26.2.5-3-ubuntu22.04}
|
||||||
env_file:
|
env_file:
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
rdns = false
|
rdns = false
|
||||||
dns_lookup_kdc = no
|
dns_lookup_kdc = no
|
||||||
dns_lookup_realm = no
|
dns_lookup_realm = no
|
||||||
|
default_keytab_name = /var/lib/secret/erlang.keytab
|
||||||
|
|
||||||
[realms]
|
[realms]
|
||||||
KDC.EMQX.NET = {
|
KDC.EMQX.NET = {
|
||||||
|
|
|
@ -6,20 +6,31 @@ echo "Remove old keytabs"
|
||||||
rm -f /var/lib/secret/kafka.keytab > /dev/null 2>&1
|
rm -f /var/lib/secret/kafka.keytab > /dev/null 2>&1
|
||||||
rm -f /var/lib/secret/rig.keytab > /dev/null 2>&1
|
rm -f /var/lib/secret/rig.keytab > /dev/null 2>&1
|
||||||
|
|
||||||
|
rm -f /var/lib/secret/erlang.keytab > /dev/null 2>&1
|
||||||
|
rm -f /var/lib/secret/krb_authn_cli.keytab > /dev/null 2>&1
|
||||||
|
|
||||||
echo "Create realm"
|
echo "Create realm"
|
||||||
|
|
||||||
kdb5_util -P emqx -r KDC.EMQX.NET create -s
|
kdb5_util -P emqx -r KDC.EMQX.NET create -s
|
||||||
|
|
||||||
echo "Add principals"
|
echo "Add principals"
|
||||||
|
|
||||||
kadmin.local -w password -q "add_principal -randkey kafka/kafka-1.emqx.net@KDC.EMQX.NET"
|
kadmin.local -w password -q "add_principal -randkey kafka/kafka-1.emqx.net@KDC.EMQX.NET" > /dev/null
|
||||||
kadmin.local -w password -q "add_principal -randkey rig@KDC.EMQX.NET" > /dev/null
|
kadmin.local -w password -q "add_principal -randkey rig@KDC.EMQX.NET" > /dev/null
|
||||||
|
|
||||||
|
# For Kerberos Authn
|
||||||
|
kadmin.local -w password -q "add_principal -randkey emqx/erlang.emqx.net@KDC.EMQX.NET" > /dev/null
|
||||||
|
kadmin.local -w password -q "add_principal -randkey krb_authn_cli@KDC.EMQX.NET" > /dev/null
|
||||||
|
|
||||||
|
|
||||||
echo "Create keytabs"
|
echo "Create keytabs"
|
||||||
|
|
||||||
kadmin.local -w password -q "ktadd -k /var/lib/secret/kafka.keytab -norandkey kafka/kafka-1.emqx.net@KDC.EMQX.NET " > /dev/null
|
kadmin.local -w password -q "ktadd -k /var/lib/secret/kafka.keytab -norandkey kafka/kafka-1.emqx.net@KDC.EMQX.NET " > /dev/null
|
||||||
kadmin.local -w password -q "ktadd -k /var/lib/secret/rig.keytab -norandkey rig@KDC.EMQX.NET " > /dev/null
|
kadmin.local -w password -q "ktadd -k /var/lib/secret/rig.keytab -norandkey rig@KDC.EMQX.NET " > /dev/null
|
||||||
|
|
||||||
|
# For Kerberos Authn
|
||||||
|
kadmin.local -w password -q "ktadd -k /var/lib/secret/erlang.keytab -norandkey emqx/erlang.emqx.net@KDC.EMQX.NET " > /dev/null
|
||||||
|
kadmin.local -w password -q "ktadd -k /var/lib/secret/krb_authn_cli.keytab -norandkey krb_authn_cli@KDC.EMQX.NET " > /dev/null
|
||||||
|
|
||||||
echo STARTING KDC
|
echo STARTING KDC
|
||||||
/usr/sbin/krb5kdc -n
|
/usr/sbin/krb5kdc -n
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
{meck, "0.9.2"},
|
{meck, "0.9.2"},
|
||||||
{proper, "1.4.0"},
|
{proper, "1.4.0"},
|
||||||
{bbmustache, "1.10.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, [
|
{extra_src_dirs, [
|
||||||
{"test", [recursive]},
|
{"test", [recursive]},
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
{meck, "0.9.2"},
|
{meck, "0.9.2"},
|
||||||
{proper, "1.4.0"},
|
{proper, "1.4.0"},
|
||||||
{bbmustache, "1.10.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]}]}
|
{extra_src_dirs, [{"test", [recursive]}]}
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -394,6 +394,8 @@ handle_in(
|
||||||
case ConnState of
|
case ConnState of
|
||||||
connecting ->
|
connecting ->
|
||||||
process_connect(NProperties, NChannel);
|
process_connect(NProperties, NChannel);
|
||||||
|
reauthenticating ->
|
||||||
|
process_connect(NProperties, NChannel);
|
||||||
_ ->
|
_ ->
|
||||||
handle_out(
|
handle_out(
|
||||||
auth,
|
auth,
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
Business Source License 1.1
|
||||||
|
|
||||||
|
Licensor: Hangzhou EMQ Technologies Co., Ltd.
|
||||||
|
Licensed Work: EMQX Enterprise Edition
|
||||||
|
The Licensed Work is (c) 2023
|
||||||
|
Hangzhou EMQ Technologies Co., Ltd.
|
||||||
|
Additional Use Grant: Students and educators are granted right to copy,
|
||||||
|
modify, and create derivative work for research
|
||||||
|
or education.
|
||||||
|
Change Date: 2028-01-26
|
||||||
|
Change License: Apache License, Version 2.0
|
||||||
|
|
||||||
|
For information about alternative licensing arrangements for the Software,
|
||||||
|
please contact Licensor: https://www.emqx.com/en/contact
|
||||||
|
|
||||||
|
Notice
|
||||||
|
|
||||||
|
The Business Source License (this document, or the “License”) is not an Open
|
||||||
|
Source license. However, the Licensed Work will eventually be made available
|
||||||
|
under an Open Source License, as stated in this License.
|
||||||
|
|
||||||
|
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
||||||
|
“Business Source License” is a trademark of MariaDB Corporation Ab.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Business Source License 1.1
|
||||||
|
|
||||||
|
Terms
|
||||||
|
|
||||||
|
The Licensor hereby grants you the right to copy, modify, create derivative
|
||||||
|
works, redistribute, and make non-production use of the Licensed Work. The
|
||||||
|
Licensor may make an Additional Use Grant, above, permitting limited
|
||||||
|
production use.
|
||||||
|
|
||||||
|
Effective on the Change Date, or the fourth anniversary of the first publicly
|
||||||
|
available distribution of a specific version of the Licensed Work under this
|
||||||
|
License, whichever comes first, the Licensor hereby grants you rights under
|
||||||
|
the terms of the Change License, and the rights granted in the paragraph
|
||||||
|
above terminate.
|
||||||
|
|
||||||
|
If your use of the Licensed Work does not comply with the requirements
|
||||||
|
currently in effect as described in this License, you must purchase a
|
||||||
|
commercial license from the Licensor, its affiliated entities, or authorized
|
||||||
|
resellers, or you must refrain from using the Licensed Work.
|
||||||
|
|
||||||
|
All copies of the original and modified Licensed Work, and derivative works
|
||||||
|
of the Licensed Work, are subject to this License. This License applies
|
||||||
|
separately for each version of the Licensed Work and the Change Date may vary
|
||||||
|
for each version of the Licensed Work released by Licensor.
|
||||||
|
|
||||||
|
You must conspicuously display this License on each original or modified copy
|
||||||
|
of the Licensed Work. If you receive the Licensed Work in original or
|
||||||
|
modified form from a third party, the terms and conditions set forth in this
|
||||||
|
License apply to your use of that work.
|
||||||
|
|
||||||
|
Any use of the Licensed Work in violation of this License will automatically
|
||||||
|
terminate your rights under this License for the current and all other
|
||||||
|
versions of the Licensed Work.
|
||||||
|
|
||||||
|
This License does not grant you any right in any trademark or logo of
|
||||||
|
Licensor or its affiliates (provided that you may use a trademark or logo of
|
||||||
|
Licensor as expressly required by this License).
|
||||||
|
|
||||||
|
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
||||||
|
AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
||||||
|
TITLE.
|
||||||
|
|
||||||
|
MariaDB hereby grants you permission to use this License’s text to license
|
||||||
|
your works, and to refer to it using the trademark “Business Source License”,
|
||||||
|
as long as you comply with the Covenants of Licensor below.
|
||||||
|
|
||||||
|
Covenants of Licensor
|
||||||
|
|
||||||
|
In consideration of the right to use this License’s text and the “Business
|
||||||
|
Source License” name and trademark, Licensor covenants to MariaDB, and to all
|
||||||
|
other recipients of the licensed work to be provided by Licensor:
|
||||||
|
|
||||||
|
1. To specify as the Change License the GPL Version 2.0 or any later version,
|
||||||
|
or a license that is compatible with GPL Version 2.0 or a later version,
|
||||||
|
where “compatible” means that software provided under the Change License can
|
||||||
|
be included in a program with software provided under GPL Version 2.0 or a
|
||||||
|
later version. Licensor may specify additional Change Licenses without
|
||||||
|
limitation.
|
||||||
|
|
||||||
|
2. To either: (a) specify an additional grant of rights to use that does not
|
||||||
|
impose any additional restriction on the right granted in this License, as
|
||||||
|
the Additional Use Grant; or (b) insert the text “None”.
|
||||||
|
|
||||||
|
3. To specify a Change Date.
|
||||||
|
|
||||||
|
4. Not to modify this License in any other way.
|
|
@ -0,0 +1 @@
|
||||||
|
kdc
|
|
@ -0,0 +1,18 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-ifndef(EMQX_AUTH_KERBEROS_HRL).
|
||||||
|
-define(EMQX_AUTH_KERBEROS_HRL, true).
|
||||||
|
|
||||||
|
-define(AUTHN_MECHANISM_GSSAPI, gssapi).
|
||||||
|
-define(AUTHN_MECHANISM_GSSAPI_BIN, <<"gssapi">>).
|
||||||
|
|
||||||
|
-define(AUTHN_BACKEND, kerberos).
|
||||||
|
-define(AUTHN_BACKEND_BIN, <<"kerberos">>).
|
||||||
|
|
||||||
|
-define(AUTHN_TYPE_KERBEROS, {?AUTHN_MECHANISM_GSSAPI, ?AUTHN_BACKEND}).
|
||||||
|
|
||||||
|
-define(AUTHN_METHOD, <<"GSSAPI-KERBEROS">>).
|
||||||
|
|
||||||
|
-endif.
|
|
@ -0,0 +1,7 @@
|
||||||
|
%% -*- mode: erlang -*-
|
||||||
|
|
||||||
|
{deps, [
|
||||||
|
{emqx, {path, "../emqx"}},
|
||||||
|
{emqx_utils, {path, "../emqx_utils"}},
|
||||||
|
{sasl_auth, {git, "https://github.com/kafka4beam/sasl_auth.git", {tag, "v2.1.1"}}}
|
||||||
|
]}.
|
|
@ -0,0 +1,18 @@
|
||||||
|
%% -*- mode: erlang -*-
|
||||||
|
{application, emqx_auth_kerberos, [
|
||||||
|
{description, "EMQX Kerberos Authentication"},
|
||||||
|
{vsn, "0.1.0"},
|
||||||
|
{registered, []},
|
||||||
|
{mod, {emqx_auth_kerberos_app, []}},
|
||||||
|
{applications, [
|
||||||
|
kernel,
|
||||||
|
stdlib,
|
||||||
|
emqx_auth,
|
||||||
|
sasl_auth
|
||||||
|
]},
|
||||||
|
{env, []},
|
||||||
|
{modules, []},
|
||||||
|
|
||||||
|
{licenses, ["Apache 2.0"]},
|
||||||
|
{links, []}
|
||||||
|
]}.
|
|
@ -0,0 +1,20 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_auth_kerberos_app).
|
||||||
|
|
||||||
|
-include("emqx_auth_kerberos.hrl").
|
||||||
|
|
||||||
|
-behaviour(application).
|
||||||
|
|
||||||
|
-export([start/2, stop/1]).
|
||||||
|
|
||||||
|
start(_StartType, _StartArgs) ->
|
||||||
|
ok = emqx_authn:register_provider(?AUTHN_TYPE_KERBEROS, emqx_authn_kerberos),
|
||||||
|
{ok, Sup} = emqx_auth_kerberos_sup:start_link(),
|
||||||
|
{ok, Sup}.
|
||||||
|
|
||||||
|
stop(_State) ->
|
||||||
|
ok = emqx_authn:deregister_provider(?AUTHN_TYPE_KERBEROS),
|
||||||
|
ok.
|
|
@ -0,0 +1,25 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_auth_kerberos_sup).
|
||||||
|
|
||||||
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
-export([start_link/0]).
|
||||||
|
|
||||||
|
-export([init/1]).
|
||||||
|
|
||||||
|
-define(SERVER, ?MODULE).
|
||||||
|
|
||||||
|
start_link() ->
|
||||||
|
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
SupFlags = #{
|
||||||
|
strategy => one_for_all,
|
||||||
|
intensity => 0,
|
||||||
|
period => 1
|
||||||
|
},
|
||||||
|
ChildSpecs = [],
|
||||||
|
{ok, {SupFlags, ChildSpecs}}.
|
|
@ -0,0 +1,121 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_authn_kerberos).
|
||||||
|
|
||||||
|
-include("emqx_auth_kerberos.hrl").
|
||||||
|
-include_lib("emqx_auth/include/emqx_authn.hrl").
|
||||||
|
-include_lib("typerefl/include/types.hrl").
|
||||||
|
|
||||||
|
-behaviour(emqx_authn_provider).
|
||||||
|
|
||||||
|
-export([
|
||||||
|
create/2,
|
||||||
|
update/2,
|
||||||
|
destroy/1,
|
||||||
|
authenticate/2
|
||||||
|
]).
|
||||||
|
|
||||||
|
create(
|
||||||
|
AuthenticatorID,
|
||||||
|
#{
|
||||||
|
principal := Principal,
|
||||||
|
keytab_file := KeyTabFile
|
||||||
|
}
|
||||||
|
) ->
|
||||||
|
KeyTabPath = emqx_schema:naive_env_interpolation(KeyTabFile),
|
||||||
|
case sasl_auth:kinit(KeyTabPath, Principal) of
|
||||||
|
ok ->
|
||||||
|
{ok, #{
|
||||||
|
id => AuthenticatorID,
|
||||||
|
principal => Principal,
|
||||||
|
keytab_file => KeyTabFile
|
||||||
|
}};
|
||||||
|
Error ->
|
||||||
|
Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
update(Config, #{id := ID}) ->
|
||||||
|
create(ID, Config).
|
||||||
|
|
||||||
|
destroy(_) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
#{
|
||||||
|
auth_method := ?AUTHN_METHOD,
|
||||||
|
auth_data := AuthData,
|
||||||
|
auth_cache := AuthCache
|
||||||
|
},
|
||||||
|
#{principal := Principal}
|
||||||
|
) when AuthData =/= undefined ->
|
||||||
|
case AuthCache of
|
||||||
|
#{sasl_conn := SaslConn} ->
|
||||||
|
auth_continue(SaslConn, AuthData);
|
||||||
|
_ ->
|
||||||
|
case auth_new(Principal) of
|
||||||
|
{ok, SaslConn} ->
|
||||||
|
auth_begin(SaslConn, AuthData);
|
||||||
|
Error ->
|
||||||
|
Error
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
authenticate(_Credential, _State) ->
|
||||||
|
ignore.
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% Internal functions
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
%% @private Parse server principal to get server FQDN.
|
||||||
|
%% The principal format is validated by config schema, so it can be assertive here.
|
||||||
|
get_server_fqdn(Principal) ->
|
||||||
|
Pattern = "^([a-zA-Z0-9._-]+)/([a-zA-Z0-9.-]+)@",
|
||||||
|
{match, [_, FQDN]} = re:run(Principal, Pattern, [{capture, all_but_first, binary}]),
|
||||||
|
FQDN.
|
||||||
|
|
||||||
|
auth_new(Principal) ->
|
||||||
|
ServerFQDN = get_server_fqdn(Principal),
|
||||||
|
case sasl_auth:server_new(<<"emqx">>, Principal, ServerFQDN) of
|
||||||
|
{ok, SaslConn} ->
|
||||||
|
{ok, SaslConn};
|
||||||
|
Error ->
|
||||||
|
?TRACE_AUTHN_PROVIDER("sasl_kerberos_new_failed", #{
|
||||||
|
reason => Error,
|
||||||
|
sasl_function => "server_server_new"
|
||||||
|
}),
|
||||||
|
{error, not_authorized}
|
||||||
|
end.
|
||||||
|
|
||||||
|
auth_begin(SaslConn, ClientToken) ->
|
||||||
|
case sasl_auth:server_start(SaslConn, ClientToken) of
|
||||||
|
{ok, {sasl_continue, ServerToken}} ->
|
||||||
|
{continue, ServerToken, #{sasl_conn => SaslConn}};
|
||||||
|
{ok, {sasl_ok, ServerToken}} ->
|
||||||
|
sasl_auth:server_done(SaslConn),
|
||||||
|
{ok, #{}, ServerToken};
|
||||||
|
Reason ->
|
||||||
|
?TRACE_AUTHN_PROVIDER("sasl_kerberos_start_failed", #{
|
||||||
|
reason => Reason,
|
||||||
|
sasl_function => "server_server_start"
|
||||||
|
}),
|
||||||
|
sasl_auth:server_done(SaslConn),
|
||||||
|
{error, not_authorized}
|
||||||
|
end.
|
||||||
|
|
||||||
|
auth_continue(SaslConn, ClientToken) ->
|
||||||
|
case sasl_auth:server_step(SaslConn, ClientToken) of
|
||||||
|
{ok, {sasl_continue, ServerToken}} ->
|
||||||
|
{continue, ServerToken, #{sasl_conn => SaslConn}};
|
||||||
|
{ok, {sasl_ok, ServerToken}} ->
|
||||||
|
sasl_auth:server_done(SaslConn),
|
||||||
|
{ok, #{}, ServerToken};
|
||||||
|
Reason ->
|
||||||
|
?TRACE_AUTHN_PROVIDER("sasl_kerberos_step_failed", #{
|
||||||
|
reason => Reason,
|
||||||
|
sasl_function => "server_server_step"
|
||||||
|
}),
|
||||||
|
sasl_auth:server_done(SaslConn),
|
||||||
|
{error, not_authorized}
|
||||||
|
end.
|
|
@ -0,0 +1,65 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_authn_kerberos_schema).
|
||||||
|
|
||||||
|
-include("emqx_auth_kerberos.hrl").
|
||||||
|
-include_lib("hocon/include/hoconsc.hrl").
|
||||||
|
|
||||||
|
-behaviour(emqx_authn_schema).
|
||||||
|
|
||||||
|
-export([
|
||||||
|
namespace/0,
|
||||||
|
fields/1,
|
||||||
|
desc/1,
|
||||||
|
refs/0,
|
||||||
|
select_union_member/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
namespace() -> "authn".
|
||||||
|
|
||||||
|
refs() ->
|
||||||
|
[?R_REF(kerberos)].
|
||||||
|
|
||||||
|
select_union_member(#{
|
||||||
|
<<"mechanism">> := ?AUTHN_MECHANISM_GSSAPI_BIN, <<"backend">> := ?AUTHN_BACKEND_BIN
|
||||||
|
}) ->
|
||||||
|
refs();
|
||||||
|
select_union_member(#{<<"mechanism">> := ?AUTHN_MECHANISM_GSSAPI_BIN}) ->
|
||||||
|
throw(#{
|
||||||
|
reason => "unknown_backend",
|
||||||
|
expected => ?AUTHN_BACKEND
|
||||||
|
});
|
||||||
|
select_union_member(_) ->
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
fields(kerberos) ->
|
||||||
|
emqx_authn_schema:common_fields() ++
|
||||||
|
[
|
||||||
|
{mechanism, emqx_authn_schema:mechanism(?AUTHN_MECHANISM_GSSAPI)},
|
||||||
|
{backend, emqx_authn_schema:backend(?AUTHN_BACKEND)},
|
||||||
|
{principal,
|
||||||
|
?HOCON(binary(), #{
|
||||||
|
required => true,
|
||||||
|
desc => ?DESC(principal),
|
||||||
|
validator => fun validate_principal/1
|
||||||
|
})},
|
||||||
|
{keytab_file,
|
||||||
|
?HOCON(binary(), #{
|
||||||
|
default => <<"/etc/krb5.keytab">>,
|
||||||
|
desc => ?DESC(keytab_file)
|
||||||
|
})}
|
||||||
|
].
|
||||||
|
|
||||||
|
desc(kerberos) ->
|
||||||
|
"Settings for Kerberos authentication.";
|
||||||
|
desc(_) ->
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
validate_principal(S) ->
|
||||||
|
P = <<"^([a-zA-Z0-9\\._-]+)/([a-zA-Z0-9\\.-]+)(?:@([A-Z0-9\\.-]+))?$">>,
|
||||||
|
case re:run(S, P) of
|
||||||
|
nomatch -> {error, invalid_server_principal_string};
|
||||||
|
{match, _} -> ok
|
||||||
|
end.
|
|
@ -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/erlang.emqx.nett@KDC.EMQX.NET">>).
|
||||||
|
|
||||||
|
-define(SVR_HOST, "erlang.emqx.net").
|
||||||
|
-define(SVR_PRINCIPAL, <<"emqx/erlang.emqx.net@KDC.EMQX.NET">>).
|
||||||
|
-define(SVR_KEYTAB_FILE, <<"/var/lib/secret/erlang.keytab">>).
|
||||||
|
|
||||||
|
-define(CLI_NAME, "krb_authn_cli").
|
||||||
|
-define(CLI_PRINCIPAL, <<"krb_authn_cli@KDC.EMQX.NET">>).
|
||||||
|
-define(CLI_KEYTAB_FILE, <<"/var/lib/secret/krb_authn_cli.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' => <<CT1/binary, "invalid">>
|
||||||
|
},
|
||||||
|
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}.
|
|
@ -1,2 +1,3 @@
|
||||||
toxiproxy
|
toxiproxy
|
||||||
|
kdc
|
||||||
kafka
|
kafka
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
{snappyer, "1.2.9"},
|
{snappyer, "1.2.9"},
|
||||||
{emqx_connector, {path, "../../apps/emqx_connector"}},
|
{emqx_connector, {path, "../../apps/emqx_connector"}},
|
||||||
{emqx_resource, {path, "../../apps/emqx_resource"}},
|
{emqx_resource, {path, "../../apps/emqx_resource"}},
|
||||||
{emqx_bridge, {path, "../../apps/emqx_bridge"}}
|
{emqx_bridge, {path, "../../apps/emqx_bridge"}},
|
||||||
|
{sasl_auth, {git, "https://github.com/kafka4beam/sasl_auth.git", {tag, "v2.1.1"}}}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{shell, [
|
{shell, [
|
||||||
|
|
|
@ -55,7 +55,10 @@ authn_mods(ce) ->
|
||||||
];
|
];
|
||||||
authn_mods(ee) ->
|
authn_mods(ee) ->
|
||||||
authn_mods(ce) ++
|
authn_mods(ce) ++
|
||||||
[emqx_gcp_device_authn_schema].
|
[
|
||||||
|
emqx_gcp_device_authn_schema,
|
||||||
|
emqx_authn_kerberos_schema
|
||||||
|
].
|
||||||
|
|
||||||
authz() ->
|
authz() ->
|
||||||
[{emqx_authz_schema, authz_mods()}].
|
[{emqx_authz_schema, authz_mods()}].
|
||||||
|
|
|
@ -20,7 +20,7 @@ Backends = case Profile of
|
||||||
[emqx_ds_builtin_local, emqx_ds_builtin_raft, emqx_fdb_ds]
|
[emqx_ds_builtin_local, emqx_ds_builtin_raft, emqx_fdb_ds]
|
||||||
end,
|
end,
|
||||||
|
|
||||||
io:format(user, "DS backends available for this release (~p): ~p~n", [Profile, Backends]),
|
io:format(user, "DS backends available for this release (~0p): ~0p~n", [Profile, Backends]),
|
||||||
|
|
||||||
{application, emqx_ds_backends, [
|
{application, emqx_ds_backends, [
|
||||||
{description, "A placeholder application that depends on all available DS backends"},
|
{description, "A placeholder application that depends on all available DS backends"},
|
||||||
|
|
|
@ -136,6 +136,7 @@
|
||||||
emqx_bridge_syskeeper,
|
emqx_bridge_syskeeper,
|
||||||
emqx_bridge_confluent,
|
emqx_bridge_confluent,
|
||||||
emqx_ds_shared_sub,
|
emqx_ds_shared_sub,
|
||||||
|
emqx_auth_gssapi,
|
||||||
emqx_auth_ext,
|
emqx_auth_ext,
|
||||||
emqx_cluster_link,
|
emqx_cluster_link,
|
||||||
emqx_ds_builtin_raft
|
emqx_ds_builtin_raft
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
{profiles, [
|
{profiles, [
|
||||||
{test, [
|
{test, [
|
||||||
{deps, [
|
{deps, [
|
||||||
{emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.10.0"}}}
|
{emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.2.3.4"}}}
|
||||||
]}
|
]}
|
||||||
]}
|
]}
|
||||||
]}.
|
]}.
|
||||||
|
|
3
mix.exs
3
mix.exs
|
@ -246,7 +246,7 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
def common_dep(:emqtt),
|
def common_dep(:emqtt),
|
||||||
do:
|
do:
|
||||||
{:emqtt,
|
{: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),
|
def common_dep(:typerefl),
|
||||||
do: {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true}
|
do: {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true}
|
||||||
|
@ -376,6 +376,7 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
:emqx_gateway_jt808,
|
:emqx_gateway_jt808,
|
||||||
:emqx_bridge_syskeeper,
|
:emqx_bridge_syskeeper,
|
||||||
:emqx_ds_shared_sub,
|
:emqx_ds_shared_sub,
|
||||||
|
:emqx_auth_gssapi,
|
||||||
:emqx_auth_ext,
|
:emqx_auth_ext,
|
||||||
:emqx_cluster_link,
|
:emqx_cluster_link,
|
||||||
:emqx_ds_builtin_raft
|
:emqx_ds_builtin_raft
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
{ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.7"}}},
|
{ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.7"}}},
|
||||||
{replayq, {git, "https://github.com/emqx/replayq.git", {tag, "0.3.8"}}},
|
{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"}}},
|
{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"}}},
|
{rulesql, {git, "https://github.com/emqx/rulesql", {tag, "0.2.1"}}},
|
||||||
% NOTE: depends on recon 2.5.x
|
% NOTE: depends on recon 2.5.x
|
||||||
{observer_cli, "1.7.1"},
|
{observer_cli, "1.7.1"},
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
emqx_authn_kerberos_schema {
|
||||||
|
|
||||||
|
principal {
|
||||||
|
label: "Kerberos Principal"
|
||||||
|
desc: """~
|
||||||
|
Server Kerberos principal.
|
||||||
|
For example <code>mqtt/emqx-cluster-1.example.com@MY_REALM.EXAMPLE.COM</code>.
|
||||||
|
NOTE: The realm in use has to be configured in /etc/krb5.conf in EMQX nodes.~"""
|
||||||
|
}
|
||||||
|
|
||||||
|
keytab_file {
|
||||||
|
label: "Keytab File"
|
||||||
|
desc: """~
|
||||||
|
Kerberos keytab file path.
|
||||||
|
NOTE: This file has to be placed in EMQX nodes.~"""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -147,7 +147,7 @@ consumer_mqtt_opts.label:
|
||||||
"""MQTT publish"""
|
"""MQTT publish"""
|
||||||
|
|
||||||
auth_kerberos_principal.desc:
|
auth_kerberos_principal.desc:
|
||||||
"""SASL GSSAPI authentication Kerberos principal. For example <code>client_name@MY.KERBEROS.REALM.MYDOMAIN.COM</code>, NOTE: The realm in use has to be configured in /etc/krb5.conf in EMQX nodes."""
|
"""SASL GSSAPI authentication Kerberos principal. For example <code>kafka/node1.example.com@EXAMPLE.COM</code>, NOTE: The realm in use has to be configured in /etc/krb5.conf in EMQX nodes."""
|
||||||
|
|
||||||
auth_kerberos_principal.label:
|
auth_kerberos_principal.label:
|
||||||
"""Kerberos Principal"""
|
"""Kerberos Principal"""
|
||||||
|
|
|
@ -256,6 +256,9 @@ for dep in ${CT_DEPS}; do
|
||||||
couchbase)
|
couchbase)
|
||||||
FILES+=( '.ci/docker-compose-file/docker-compose-couchbase.yaml' )
|
FILES+=( '.ci/docker-compose-file/docker-compose-couchbase.yaml' )
|
||||||
;;
|
;;
|
||||||
|
kdc)
|
||||||
|
FILES+=( '.ci/docker-compose-file/docker-compose-kdc.yaml' )
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "unknown_ct_dependency $dep"
|
echo "unknown_ct_dependency $dep"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
Loading…
Reference in New Issue