Merge pull request #14640 from rabbitmq/mergify/bp/v4.2.x/pr-14414
Test (make) / Build and Xref (1.18, 26) (push) Waiting to run
Details
Test (make) / Build and Xref (1.18, 27) (push) Waiting to run
Details
Test (make) / Build and Xref (1.18, 28) (push) Waiting to run
Details
Test (make) / Test (1.18, 28, khepri) (push) Waiting to run
Details
Test (make) / Test (1.18, 28, mnesia) (push) Waiting to run
Details
Test (make) / Test mixed clusters (1.18, 28, khepri) (push) Waiting to run
Details
Test (make) / Test mixed clusters (1.18, 28, mnesia) (push) Waiting to run
Details
Test (make) / Type check (1.18, 28) (push) Waiting to run
Details
Test Management UI with Selenium / selenium (chrome, 1.17.3, 27.3) (push) Waiting to run
Details
Test (make) / Build and Xref (1.18, 26) (push) Waiting to run
Details
Test (make) / Build and Xref (1.18, 27) (push) Waiting to run
Details
Test (make) / Build and Xref (1.18, 28) (push) Waiting to run
Details
Test (make) / Test (1.18, 28, khepri) (push) Waiting to run
Details
Test (make) / Test (1.18, 28, mnesia) (push) Waiting to run
Details
Test (make) / Test mixed clusters (1.18, 28, khepri) (push) Waiting to run
Details
Test (make) / Test mixed clusters (1.18, 28, mnesia) (push) Waiting to run
Details
Test (make) / Type check (1.18, 28) (push) Waiting to run
Details
Test Management UI with Selenium / selenium (chrome, 1.17.3, 27.3) (push) Waiting to run
Details
Implement LDAP credentials validation via HTTP API (backport #14414)
This commit is contained in:
commit
0249e07ca8
|
@ -35,7 +35,7 @@ define PROJECT_APP_EXTRA_KEYS
|
||||||
endef
|
endef
|
||||||
|
|
||||||
LOCAL_DEPS = eldap public_key
|
LOCAL_DEPS = eldap public_key
|
||||||
DEPS = rabbit_common rabbit
|
DEPS = rabbit_common rabbit rabbitmq_management
|
||||||
TEST_DEPS = ct_helper rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client
|
TEST_DEPS = ct_helper rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client
|
||||||
dep_ct_helper = git https://github.com/extend/ct_helper.git master
|
dep_ct_helper = git https://github.com/extend/ct_helper.git master
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,267 @@
|
||||||
|
%% This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
%% License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
%%
|
||||||
|
%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
|
||||||
|
%%
|
||||||
|
|
||||||
|
-module(rabbit_auth_backend_ldap_mgmt).
|
||||||
|
|
||||||
|
-behaviour(rabbit_mgmt_extension).
|
||||||
|
|
||||||
|
-export([dispatcher/0, web_ui/0]).
|
||||||
|
|
||||||
|
-export([init/2,
|
||||||
|
content_types_accepted/2,
|
||||||
|
allowed_methods/2,
|
||||||
|
resource_exists/2,
|
||||||
|
is_authorized/2,
|
||||||
|
accept_content/2]).
|
||||||
|
|
||||||
|
|
||||||
|
-include_lib("kernel/include/logger.hrl").
|
||||||
|
-include_lib("rabbitmq_web_dispatch/include/rabbitmq_web_dispatch_records.hrl").
|
||||||
|
|
||||||
|
dispatcher() -> [{"/ldap/validate/simple-bind", ?MODULE, []}].
|
||||||
|
|
||||||
|
web_ui() -> [].
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
init(Req, _Opts) ->
|
||||||
|
{cowboy_rest, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}.
|
||||||
|
|
||||||
|
content_types_accepted(ReqData, Context) ->
|
||||||
|
{[{'*', accept_content}], ReqData, Context}.
|
||||||
|
|
||||||
|
allowed_methods(ReqData, Context) ->
|
||||||
|
{[<<"PUT">>, <<"OPTIONS">>], ReqData, Context}.
|
||||||
|
|
||||||
|
resource_exists(ReqData, Context) ->
|
||||||
|
{true, ReqData, Context}.
|
||||||
|
|
||||||
|
is_authorized(ReqData, Context) ->
|
||||||
|
rabbit_mgmt_util:is_authorized(ReqData, Context).
|
||||||
|
|
||||||
|
accept_content(ReqData0, Context) ->
|
||||||
|
F = fun (_Values, BodyMap, ReqData1) ->
|
||||||
|
try
|
||||||
|
Port = safe_parse_int(maps:get(port, BodyMap, 389), "port"),
|
||||||
|
UseSsl = safe_parse_bool(maps:get(use_ssl, BodyMap, false), "use_ssl"),
|
||||||
|
UseStartTls = safe_parse_bool(maps:get(use_starttls, BodyMap, false), "use_starttls"),
|
||||||
|
Servers = maps:get(servers, BodyMap, []),
|
||||||
|
UserDN = maps:get(user_dn, BodyMap, <<"">>),
|
||||||
|
Password = maps:get(password, BodyMap, <<"">>),
|
||||||
|
Options0 = [
|
||||||
|
{port, Port},
|
||||||
|
{timeout, 5000}
|
||||||
|
],
|
||||||
|
{ok, Options1} = maybe_add_ssl_options(Options0, UseSsl, BodyMap),
|
||||||
|
case eldap:open(Servers, Options1) of
|
||||||
|
{ok, LDAP} ->
|
||||||
|
Result = case maybe_starttls(LDAP, UseStartTls, BodyMap) of
|
||||||
|
ok ->
|
||||||
|
case eldap:simple_bind(LDAP, UserDN, Password) of
|
||||||
|
ok ->
|
||||||
|
{true, ReqData1, Context};
|
||||||
|
{error, invalidCredentials} ->
|
||||||
|
rabbit_mgmt_util:unprocessable_entity("invalid LDAP credentials: "
|
||||||
|
"authentication failure",
|
||||||
|
ReqData1, Context);
|
||||||
|
{error, unwillingToPerform} ->
|
||||||
|
rabbit_mgmt_util:unprocessable_entity("invalid LDAP credentials: "
|
||||||
|
"authentication failure",
|
||||||
|
ReqData1, Context);
|
||||||
|
{error, invalidDNSyntax} ->
|
||||||
|
rabbit_mgmt_util:unprocessable_entity("invalid LDAP credentials: "
|
||||||
|
"DN syntax invalid / too long",
|
||||||
|
ReqData1, Context);
|
||||||
|
{error, E} ->
|
||||||
|
Reason = unicode_format(E),
|
||||||
|
rabbit_mgmt_util:unprocessable_entity(Reason, ReqData1, Context)
|
||||||
|
end;
|
||||||
|
{error, tls_already_started} ->
|
||||||
|
rabbit_mgmt_util:unprocessable_entity("TLS configuration error: "
|
||||||
|
"cannot use StartTLS on an SSL connection "
|
||||||
|
"(use_ssl and use_starttls cannot both be true)",
|
||||||
|
ReqData1, Context);
|
||||||
|
Error ->
|
||||||
|
Reason = unicode_format(Error),
|
||||||
|
rabbit_mgmt_util:unprocessable_entity(Reason, ReqData1, Context)
|
||||||
|
end,
|
||||||
|
eldap:close(LDAP),
|
||||||
|
Result;
|
||||||
|
{error, E} ->
|
||||||
|
Reason = unicode_format("LDAP connection failed: ~tp "
|
||||||
|
"(servers: ~tp, user_dn: ~ts, password: ~s)",
|
||||||
|
[E, Servers, UserDN, format_password_for_logging(Password)]),
|
||||||
|
rabbit_mgmt_util:bad_request(Reason, ReqData1, Context)
|
||||||
|
end
|
||||||
|
catch throw:{bad_request, ErrMsg} ->
|
||||||
|
rabbit_mgmt_util:bad_request(ErrMsg, ReqData1, Context)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
rabbit_mgmt_util:with_decode([], ReqData0, Context, F).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
maybe_starttls(_LDAP, false, _BodyMap) ->
|
||||||
|
ok;
|
||||||
|
maybe_starttls(LDAP, true, BodyMap) ->
|
||||||
|
{ok, TlsOptions} = tls_options(BodyMap),
|
||||||
|
eldap:start_tls(LDAP, TlsOptions, 5000).
|
||||||
|
|
||||||
|
maybe_add_ssl_options(Options0, false, _BodyMap) ->
|
||||||
|
{ok, Options0};
|
||||||
|
maybe_add_ssl_options(Options0, true, BodyMap) ->
|
||||||
|
case maps:is_key(ssl_options, BodyMap) of
|
||||||
|
false ->
|
||||||
|
{ok, Options0};
|
||||||
|
true ->
|
||||||
|
Options1 = [{ssl, true} | Options0],
|
||||||
|
{ok, TlsOptions} = tls_options(BodyMap),
|
||||||
|
Options2 = [{sslopts, TlsOptions} | Options1],
|
||||||
|
{ok, Options2}
|
||||||
|
end.
|
||||||
|
|
||||||
|
tls_options(BodyMap) when is_map_key(ssl_options, BodyMap) ->
|
||||||
|
SslOptionsMap = maps:get(ssl_options, BodyMap),
|
||||||
|
case is_map(SslOptionsMap) of
|
||||||
|
false ->
|
||||||
|
throw({bad_request, "ssl_options must be a map/object"});
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
CaCertfile = maps:get(<<"cacertfile">>, SslOptionsMap, undefined),
|
||||||
|
CaCertPemData = maps:get(<<"cacert_pem_data">>, SslOptionsMap, undefined),
|
||||||
|
TlsOpts0 = case {CaCertfile, CaCertPemData} of
|
||||||
|
{undefined, undefined} ->
|
||||||
|
[{cacerts, public_key:cacerts_get()}];
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
%% NB: for some reason the "cacertfile" key isn't turned into an atom
|
||||||
|
TlsOpts1 = case CaCertfile of
|
||||||
|
undefined ->
|
||||||
|
TlsOpts0;
|
||||||
|
CaCertfile ->
|
||||||
|
[{cacertfile, CaCertfile} | TlsOpts0]
|
||||||
|
end,
|
||||||
|
TlsOpts2 = case CaCertPemData of
|
||||||
|
undefined ->
|
||||||
|
TlsOpts1;
|
||||||
|
CaCertPems when is_list(CaCertPems) ->
|
||||||
|
F0 = fun (P) ->
|
||||||
|
try
|
||||||
|
case public_key:pem_decode(P) of
|
||||||
|
[{'Certificate', CaCertDerEncoded, not_encrypted}] ->
|
||||||
|
{true, CaCertDerEncoded};
|
||||||
|
[] ->
|
||||||
|
throw({bad_request, "invalid PEM data in cacert_pem_data: "
|
||||||
|
"no valid certificates found"});
|
||||||
|
_Unexpected ->
|
||||||
|
throw({bad_request, "unexpected cacert_pem_data passed to "
|
||||||
|
"/ldap/validate/simple-bind ssl_options.cacerts"})
|
||||||
|
end
|
||||||
|
catch
|
||||||
|
error:Reason ->
|
||||||
|
throw({bad_request, unicode_format("invalid PEM data in cacert_pem_data: ~tp", [Reason])})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
CaCertsDerEncoded = lists:filtermap(F0, CaCertPems),
|
||||||
|
[{cacerts, CaCertsDerEncoded} | TlsOpts1];
|
||||||
|
_ ->
|
||||||
|
TlsOpts1
|
||||||
|
end,
|
||||||
|
TlsOpts3 = case maps:get(<<"verify">>, SslOptionsMap, undefined) of
|
||||||
|
undefined ->
|
||||||
|
TlsOpts2;
|
||||||
|
Verify ->
|
||||||
|
try
|
||||||
|
VerifyStr = unicode:characters_to_list(Verify),
|
||||||
|
[{verify, list_to_existing_atom(VerifyStr)} | TlsOpts2]
|
||||||
|
catch
|
||||||
|
error:badarg ->
|
||||||
|
throw({bad_request, "invalid verify option passed to "
|
||||||
|
"/ldap/validate/simple-bind ssl_options.verify"})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
TlsOpts4 = case maps:get(<<"server_name_indication">>, SslOptionsMap, disable) of
|
||||||
|
disable ->
|
||||||
|
TlsOpts3;
|
||||||
|
SniValue ->
|
||||||
|
try
|
||||||
|
SniStr = unicode:characters_to_list(SniValue),
|
||||||
|
[{server_name_indication, SniStr} | TlsOpts3]
|
||||||
|
catch
|
||||||
|
error:badarg ->
|
||||||
|
throw({bad_request, "invalid server_name_indication: expected string"});
|
||||||
|
error:_ ->
|
||||||
|
throw({bad_request, "invalid server_name_indication: expected string"})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
TlsOpts5 = case maps:get(<<"depth">>, SslOptionsMap, undefined) of
|
||||||
|
undefined ->
|
||||||
|
TlsOpts4;
|
||||||
|
DepthValue ->
|
||||||
|
Depth = safe_parse_int(DepthValue, "ssl_options.depth"),
|
||||||
|
[{depth, Depth} | TlsOpts4]
|
||||||
|
end,
|
||||||
|
TlsOpts6 = case maps:get(<<"versions">>, SslOptionsMap, undefined) of
|
||||||
|
undefined ->
|
||||||
|
TlsOpts5;
|
||||||
|
VersionStrs when is_list(VersionStrs) ->
|
||||||
|
F1 = fun (VStr) ->
|
||||||
|
try
|
||||||
|
{true, list_to_existing_atom(VStr)}
|
||||||
|
catch error:badarg ->
|
||||||
|
throw({bad_request, "invalid TLS version passed to "
|
||||||
|
"/ldap/validate/simple-bind ssl_options.versions"})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
Versions = lists:filtermap(F1, VersionStrs),
|
||||||
|
[{versions, Versions} | TlsOpts5]
|
||||||
|
end,
|
||||||
|
TlsOpts7 = case maps:get(<<"ssl_hostname_verification">>, SslOptionsMap, undefined) of
|
||||||
|
undefined ->
|
||||||
|
TlsOpts6;
|
||||||
|
"wildcard" ->
|
||||||
|
[{customize_hostname_check, [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}]} | TlsOpts6];
|
||||||
|
_ ->
|
||||||
|
throw({bad_request, "invalid value passed to "
|
||||||
|
"/ldap/validate/simple-bind ssl_options.ssl_hostname_verification"})
|
||||||
|
end,
|
||||||
|
{ok, TlsOpts7};
|
||||||
|
tls_options(_BodyMap) ->
|
||||||
|
{ok, []}.
|
||||||
|
|
||||||
|
unicode_format(Arg) ->
|
||||||
|
rabbit_data_coercion:to_utf8_binary(io_lib:format("~tp", [Arg])).
|
||||||
|
|
||||||
|
unicode_format(Format, Args) ->
|
||||||
|
rabbit_data_coercion:to_utf8_binary(io_lib:format(Format, Args)).
|
||||||
|
|
||||||
|
format_password_for_logging(<<>>) ->
|
||||||
|
"[empty]";
|
||||||
|
format_password_for_logging(Password) ->
|
||||||
|
io_lib:format("[~p characters]", [string:length(Password)]).
|
||||||
|
|
||||||
|
safe_parse_int(Value, FieldName) ->
|
||||||
|
try
|
||||||
|
rabbit_mgmt_util:parse_int(Value)
|
||||||
|
catch
|
||||||
|
throw:{error, {not_integer, BadValue}} ->
|
||||||
|
Msg = unicode_format("invalid value for ~s: expected integer, got ~tp",
|
||||||
|
[FieldName, BadValue]),
|
||||||
|
throw({bad_request, Msg})
|
||||||
|
end.
|
||||||
|
|
||||||
|
safe_parse_bool(Value, FieldName) ->
|
||||||
|
try
|
||||||
|
rabbit_mgmt_util:parse_bool(Value)
|
||||||
|
catch
|
||||||
|
throw:{error, {not_boolean, BadValue}} ->
|
||||||
|
Msg = unicode_format("invalid value for ~s: expected boolean, got ~tp",
|
||||||
|
[FieldName, BadValue]),
|
||||||
|
throw({bad_request, Msg})
|
||||||
|
end.
|
|
@ -11,6 +11,9 @@
|
||||||
-include_lib("common_test/include/ct.hrl").
|
-include_lib("common_test/include/ct.hrl").
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
-include_lib("amqp_client/include/amqp_client.hrl").
|
-include_lib("amqp_client/include/amqp_client.hrl").
|
||||||
|
-include_lib("rabbitmq_ct_helpers/include/rabbit_mgmt_test.hrl").
|
||||||
|
|
||||||
|
-import(rabbit_mgmt_test_util, [http_put/4]).
|
||||||
|
|
||||||
-define(ALICE_NAME, "Alice").
|
-define(ALICE_NAME, "Alice").
|
||||||
-define(BOB_NAME, "Bob").
|
-define(BOB_NAME, "Bob").
|
||||||
|
@ -97,6 +100,7 @@ all() ->
|
||||||
|
|
||||||
groups() ->
|
groups() ->
|
||||||
Tests = [
|
Tests = [
|
||||||
|
validate_ldap_configuration_via_api,
|
||||||
purge_connection,
|
purge_connection,
|
||||||
ldap_only,
|
ldap_only,
|
||||||
ldap_and_internal,
|
ldap_and_internal,
|
||||||
|
@ -158,10 +162,23 @@ end_per_group(_, Config) ->
|
||||||
init_slapd(Config) ->
|
init_slapd(Config) ->
|
||||||
DataDir = ?config(data_dir, Config),
|
DataDir = ?config(data_dir, Config),
|
||||||
PrivDir = ?config(priv_dir, Config),
|
PrivDir = ?config(priv_dir, Config),
|
||||||
|
CertsDir = ?config(rmq_certsdir, Config),
|
||||||
|
CaCertfile = filename:join([CertsDir, "testca", "cacert.pem"]),
|
||||||
|
ServerCertfile = filename:join([CertsDir, "server", "cert.pem"]),
|
||||||
|
ServerKeyfile = filename:join([CertsDir, "server", "key.pem"]),
|
||||||
TcpPort = 25389,
|
TcpPort = 25389,
|
||||||
|
TlsPort = 25689,
|
||||||
SlapdDir = filename:join([PrivDir, "openldap"]),
|
SlapdDir = filename:join([PrivDir, "openldap"]),
|
||||||
InitSlapd = filename:join([DataDir, "init-slapd.sh"]),
|
InitSlapd = filename:join([DataDir, "init-slapd.sh"]),
|
||||||
Cmd = [InitSlapd, SlapdDir, {"~b", [TcpPort]}],
|
Cmd = [
|
||||||
|
InitSlapd,
|
||||||
|
SlapdDir,
|
||||||
|
{"~b", [TcpPort]},
|
||||||
|
{"~b", [TlsPort]},
|
||||||
|
CaCertfile,
|
||||||
|
ServerCertfile,
|
||||||
|
ServerKeyfile
|
||||||
|
],
|
||||||
case rabbit_ct_helpers:exec(Cmd) of
|
case rabbit_ct_helpers:exec(Cmd) of
|
||||||
{ok, Stdout} ->
|
{ok, Stdout} ->
|
||||||
{match, [SlapdPid]} = re:run(
|
{match, [SlapdPid]} = re:run(
|
||||||
|
@ -174,7 +191,8 @@ init_slapd(Config) ->
|
||||||
[SlapdPid, TcpPort]),
|
[SlapdPid, TcpPort]),
|
||||||
rabbit_ct_helpers:set_config(Config,
|
rabbit_ct_helpers:set_config(Config,
|
||||||
[{slapd_pid, SlapdPid},
|
[{slapd_pid, SlapdPid},
|
||||||
{ldap_port, TcpPort}]);
|
{ldap_port, TcpPort},
|
||||||
|
{ldap_tls_port, TlsPort}]);
|
||||||
_ ->
|
_ ->
|
||||||
_ = rabbit_ct_helpers:exec(["pkill", "-INT", "slapd"]),
|
_ = rabbit_ct_helpers:exec(["pkill", "-INT", "slapd"]),
|
||||||
{skip, "Failed to initialize slapd(8)"}
|
{skip, "Failed to initialize slapd(8)"}
|
||||||
|
@ -206,6 +224,10 @@ end_internal(Config) ->
|
||||||
ok = control_action(Config, delete_user, [?BOB_NAME]),
|
ok = control_action(Config, delete_user, [?BOB_NAME]),
|
||||||
ok = control_action(Config, delete_user, [?PETER_NAME]).
|
ok = control_action(Config, delete_user, [?PETER_NAME]).
|
||||||
|
|
||||||
|
|
||||||
|
init_per_testcase(validate_ldap_configuration_via_api = Testcase, Config) ->
|
||||||
|
_ = application:start(inets),
|
||||||
|
rabbit_ct_helpers:testcase_started(Config, Testcase);
|
||||||
init_per_testcase(Testcase, Config)
|
init_per_testcase(Testcase, Config)
|
||||||
when Testcase == ldap_and_internal;
|
when Testcase == ldap_and_internal;
|
||||||
Testcase == internal_followed_ldap_and_internal ->
|
Testcase == internal_followed_ldap_and_internal ->
|
||||||
|
@ -229,6 +251,9 @@ init_per_testcase(Testcase, Config)
|
||||||
init_per_testcase(Testcase, Config) ->
|
init_per_testcase(Testcase, Config) ->
|
||||||
rabbit_ct_helpers:testcase_started(Config, Testcase).
|
rabbit_ct_helpers:testcase_started(Config, Testcase).
|
||||||
|
|
||||||
|
end_per_testcase(validate_ldap_configuration_via_api = Testcase, Config) ->
|
||||||
|
_ = application:stop(inets),
|
||||||
|
rabbit_ct_helpers:testcase_finished(Config, Testcase);
|
||||||
end_per_testcase(Testcase, Config)
|
end_per_testcase(Testcase, Config)
|
||||||
when Testcase == ldap_and_internal;
|
when Testcase == ldap_and_internal;
|
||||||
Testcase == internal_followed_ldap_and_internal ->
|
Testcase == internal_followed_ldap_and_internal ->
|
||||||
|
@ -270,6 +295,434 @@ end_per_testcase(Testcase, Config) ->
|
||||||
%% Testsuite cases
|
%% Testsuite cases
|
||||||
%% -------------------------------------------------------------------
|
%% -------------------------------------------------------------------
|
||||||
|
|
||||||
|
validate_ldap_configuration_via_api(Config) ->
|
||||||
|
CertsDir = ?config(rmq_certsdir, Config),
|
||||||
|
CaCertfile = filename:join([CertsDir, "testca", "cacert.pem"]),
|
||||||
|
|
||||||
|
%% {user_dn_pattern, "cn=${username},ou=People,dc=rabbitmq,dc=com"},
|
||||||
|
UserDNFmt = "cn=~ts,ou=People,dc=rabbitmq,dc=com",
|
||||||
|
AliceUserDN = rabbit_data_coercion:to_utf8_binary(io_lib:format(UserDNFmt, [?ALICE_NAME])),
|
||||||
|
InvalidUserDN = rabbit_data_coercion:to_utf8_binary(io_lib:format(UserDNFmt, ["NOBODY"])),
|
||||||
|
Password = rabbit_data_coercion:to_utf8_binary("password"),
|
||||||
|
|
||||||
|
LdapPort = ?config(ldap_port, Config),
|
||||||
|
LdapTlsPort = ?config(ldap_tls_port, Config),
|
||||||
|
|
||||||
|
%% NB: bad resource name
|
||||||
|
http_put(Config, "/ldap/validate/bad-bind-name",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?METHOD_NOT_ALLOWED),
|
||||||
|
%% Invalid JSON should return 400 Bad Request
|
||||||
|
rabbit_mgmt_test_util:http_put_raw(Config, "/ldap/validate/simple-bind",
|
||||||
|
"{invalid json", ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% HTTP Method coverage tests
|
||||||
|
%% GET method - should return 405 Method Not Allowed
|
||||||
|
?assertMatch({ok, {{_, ?METHOD_NOT_ALLOWED, _}, _Headers, _ResBody}},
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, get, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")])),
|
||||||
|
|
||||||
|
%% HEAD method - should return 405 Method Not Allowed (same as GET)
|
||||||
|
?assertMatch({ok, {{_, ?METHOD_NOT_ALLOWED, _}, _Headers, _ResBody}},
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, head, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")])),
|
||||||
|
|
||||||
|
%% POST method - should return 405 Method Not Allowed
|
||||||
|
?assertMatch({ok, {{_, ?METHOD_NOT_ALLOWED, _}, _Headers, _ResBody}},
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, post, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")], "{}")),
|
||||||
|
|
||||||
|
%% DELETE method - should return 405 Method Not Allowed
|
||||||
|
?assertMatch({ok, {{_, ?METHOD_NOT_ALLOWED, _}, _Headers, _ResBody}},
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, delete, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")])),
|
||||||
|
|
||||||
|
%% OPTIONS method - should return 200 with Allow header showing only PUT, OPTIONS
|
||||||
|
{ok, {{_, OptionsCode, _}, OptionsHeaders, _OptionsResBody}} =
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, options, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")]),
|
||||||
|
?assertEqual(?OK, OptionsCode),
|
||||||
|
AllowHeader = proplists:get_value("allow", OptionsHeaders),
|
||||||
|
?assert(string:str(string:to_upper(AllowHeader), "PUT") > 0),
|
||||||
|
?assert(string:str(string:to_upper(AllowHeader), "OPTIONS") > 0),
|
||||||
|
%% Should NOT contain GET or HEAD
|
||||||
|
?assertEqual(0, string:str(string:to_upper(AllowHeader), "GET")),
|
||||||
|
?assertEqual(0, string:str(string:to_upper(AllowHeader), "HEAD")),
|
||||||
|
|
||||||
|
%% Missing required fields tests
|
||||||
|
%% Empty servers array - connection failure (400)
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => [],
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Missing servers field entirely - defaults to [], same as above (400)
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Missing user_dn field entirely - empty DN fails credential validation (422)
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?UNPROCESSABLE_ENTITY),
|
||||||
|
|
||||||
|
%% Missing password field entirely - empty password fails credential validation (422)
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?UNPROCESSABLE_ENTITY),
|
||||||
|
|
||||||
|
%% Invalid field values tests
|
||||||
|
%% Invalid port - string instead of number
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => "not_a_number"
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid port - negative number
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => -1
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid boolean - string instead of boolean
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort,
|
||||||
|
'use_ssl' => "maybe"
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid servers - non-list value
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => "not_a_list",
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Network/Infrastructure scenarios
|
||||||
|
%% Non-existent server
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["nonexistent.example.com"],
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid hostname format
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["not..a..valid..hostname"],
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Edge case credentials tests
|
||||||
|
%% Empty password - should be 422 (credential validation failure)
|
||||||
|
{ok, {{_, 422, _}, _Headers1, EmptyPasswordBody}} =
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, put, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")],
|
||||||
|
rabbit_mgmt_test_util:format_for_upload(#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => "",
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
})),
|
||||||
|
EmptyPasswordJson = rabbit_json:decode(EmptyPasswordBody),
|
||||||
|
?assertEqual(<<"unprocessable_entity">>, maps:get(<<"error">>, EmptyPasswordJson)),
|
||||||
|
?assertEqual(<<"anonymous_auth">>, maps:get(<<"reason">>, EmptyPasswordJson)),
|
||||||
|
|
||||||
|
%% Empty user DN - should be 422 (credential validation failure)
|
||||||
|
{ok, {{_, 422, _}, _Headers2, EmptyUserDnBody}} =
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, put, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")],
|
||||||
|
rabbit_mgmt_test_util:format_for_upload(#{
|
||||||
|
'user_dn' => "",
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
})),
|
||||||
|
EmptyUserDnJson = rabbit_json:decode(EmptyUserDnBody),
|
||||||
|
?assertEqual(<<"unprocessable_entity">>, maps:get(<<"error">>, EmptyUserDnJson)),
|
||||||
|
?assertEqual(<<"anonymous_auth">>, maps:get(<<"reason">>, EmptyUserDnJson)),
|
||||||
|
|
||||||
|
%% Very long user DN (test size limits)
|
||||||
|
{ok, {{_, 422, _}, _Headers3, LongUserDnBody}} =
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, put, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")],
|
||||||
|
rabbit_mgmt_test_util:format_for_upload(#{
|
||||||
|
'user_dn' => binary:copy(<<"x">>, 10000),
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
})),
|
||||||
|
LongUserDnJson = rabbit_json:decode(LongUserDnBody),
|
||||||
|
?assertEqual(<<"unprocessable_entity">>, maps:get(<<"error">>, LongUserDnJson)),
|
||||||
|
?assertEqual(<<"invalid LDAP credentials: DN syntax invalid / too long">>,
|
||||||
|
maps:get(<<"reason">>, LongUserDnJson)),
|
||||||
|
|
||||||
|
%% Very long password (test size limits)
|
||||||
|
{ok, {{_, 422, _}, _Headers4, LongPasswordBody}} =
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, put, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")],
|
||||||
|
rabbit_mgmt_test_util:format_for_upload(#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => binary:copy(<<"x">>, 10000),
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
})),
|
||||||
|
LongPasswordJson = rabbit_json:decode(LongPasswordBody),
|
||||||
|
?assertEqual(<<"unprocessable_entity">>, maps:get(<<"error">>, LongPasswordJson)),
|
||||||
|
?assertEqual(<<"invalid LDAP credentials: authentication failure">>,
|
||||||
|
maps:get(<<"reason">>, LongPasswordJson)),
|
||||||
|
|
||||||
|
%% SSL/TLS Edge Cases
|
||||||
|
%% Both use_ssl and use_starttls set to true - TLS configuration error
|
||||||
|
{ok, {{_, 422, _}, _Headers5, BothTlsBody}} =
|
||||||
|
rabbit_mgmt_test_util:req(Config, 0, put, "/ldap/validate/simple-bind",
|
||||||
|
[rabbit_mgmt_test_util:auth_header("guest", "guest")],
|
||||||
|
rabbit_mgmt_test_util:format_for_upload(#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'use_starttls' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
BothTlsJson = rabbit_json:decode(BothTlsBody),
|
||||||
|
?assertEqual(<<"unprocessable_entity">>, maps:get(<<"error">>, BothTlsJson)),
|
||||||
|
?assertEqual(<<"TLS configuration error: cannot use StartTLS on an SSL connection (use_ssl and use_starttls cannot both be true)">>,
|
||||||
|
maps:get(<<"reason">>, BothTlsJson)),
|
||||||
|
|
||||||
|
%% Invalid certificate file path
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'cacertfile' => "/nonexistent/path/cert.pem"
|
||||||
|
}
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid PEM data - should now return 400 Bad Request
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'cacert_pem_data' => ["not-valid-pem-data"]
|
||||||
|
}
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid SSL options structure - not a map
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => "not_a_map"
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid TLS versions
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'versions' => ["invalid_version", "tlsv1.2"],
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid verify option
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'verify' => "invalid_verify_option",
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid depth value - string instead of integer
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'depth' => "not_a_number",
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid server_name_indication - integer instead of string
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'server_name_indication' => 123,
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
|
||||||
|
%% Invalid server_name_indication - boolean instead of string
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'server_name_indication' => true,
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?NO_CONTENT),
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => InvalidUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort
|
||||||
|
}, ?UNPROCESSABLE_ENTITY),
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
}, ?NO_CONTENT),
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'server_name_indication' => "localhost",
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
}, ?NO_CONTENT),
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapPort,
|
||||||
|
'use_ssl' => false,
|
||||||
|
'use_starttls' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'server_name_indication' => "localhost",
|
||||||
|
'cacertfile' => CaCertfile
|
||||||
|
}
|
||||||
|
}, ?NO_CONTENT),
|
||||||
|
{ok, CaCertfileContent} = file:read_file(CaCertfile),
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'versions' => ["tlsv1.2", "tlsv1.3"],
|
||||||
|
'depth' => 8,
|
||||||
|
'verify' => "verify_peer",
|
||||||
|
'cacert_pem_data' => [CaCertfileContent]
|
||||||
|
}
|
||||||
|
}, ?NO_CONTENT),
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'versions' => ["tlsfoobar", "tlsv1.3"],
|
||||||
|
'depth' => 8,
|
||||||
|
'verify' => "verify_peer",
|
||||||
|
'cacert_pem_data' => [CaCertfileContent, CaCertfileContent]
|
||||||
|
}
|
||||||
|
}, ?BAD_REQUEST),
|
||||||
|
http_put(Config, "/ldap/validate/simple-bind",
|
||||||
|
#{
|
||||||
|
'user_dn' => AliceUserDN,
|
||||||
|
'password' => Password,
|
||||||
|
'servers' => ["localhost"],
|
||||||
|
'port' => LdapTlsPort,
|
||||||
|
'use_ssl' => true,
|
||||||
|
'ssl_options' => #{
|
||||||
|
'verify' => "verify_peer",
|
||||||
|
'cacertfile' => CaCertfile,
|
||||||
|
'ssl_hostname_verification' => "wildcard"
|
||||||
|
}
|
||||||
|
}, ?NO_CONTENT).
|
||||||
|
|
||||||
purge_connection(Config) ->
|
purge_connection(Config) ->
|
||||||
{ok, _} = rabbit_ct_broker_helpers:rpc(Config, 0,
|
{ok, _} = rabbit_ct_broker_helpers:rpc(Config, 0,
|
||||||
rabbit_auth_backend_ldap,
|
rabbit_auth_backend_ldap,
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# vim:sw=4:et:
|
# vim:sw=4:et:
|
||||||
|
|
||||||
set -ex
|
set -eux
|
||||||
|
|
||||||
readonly slapd_data_dir="$1"
|
readonly slapd_data_dir="$1"
|
||||||
readonly tcp_port="$2"
|
readonly tcp_port="$2"
|
||||||
|
readonly tls_port="$3"
|
||||||
|
readonly cacertfile="$4"
|
||||||
|
readonly server_certfile="$5"
|
||||||
|
readonly server_keyfile="$6"
|
||||||
|
|
||||||
readonly pidfile="$slapd_data_dir/slapd.pid"
|
readonly pidfile="$slapd_data_dir/slapd.pid"
|
||||||
readonly uri="ldap://localhost:$tcp_port"
|
readonly tcp_uri="ldap://localhost:$tcp_port"
|
||||||
|
readonly tls_uri="ldaps://localhost:$tls_port"
|
||||||
|
|
||||||
readonly binddn="cn=config"
|
readonly binddn="cn=config"
|
||||||
readonly passwd=secret
|
readonly passwd=secret
|
||||||
|
@ -68,6 +73,10 @@ loglevel 7
|
||||||
database config
|
database config
|
||||||
rootdn "$binddn"
|
rootdn "$binddn"
|
||||||
rootpw $passwd
|
rootpw $passwd
|
||||||
|
|
||||||
|
TLSCACertificateFile $cacertfile
|
||||||
|
TLSCertificateFile $server_certfile
|
||||||
|
TLSCertificateKeyFile $server_keyfile
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat "$conf_file"
|
cat "$conf_file"
|
||||||
|
@ -79,7 +88,7 @@ mkdir -p "$conf_dir"
|
||||||
"$slapd" \
|
"$slapd" \
|
||||||
-f "$conf_file" \
|
-f "$conf_file" \
|
||||||
-F "$conf_dir" \
|
-F "$conf_dir" \
|
||||||
-h "$uri"
|
-h "$tcp_uri $tls_uri"
|
||||||
|
|
||||||
readonly auth="-x -D $binddn -w $passwd"
|
readonly auth="-x -D $binddn -w $passwd"
|
||||||
|
|
||||||
|
@ -87,7 +96,7 @@ readonly auth="-x -D $binddn -w $passwd"
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
for seconds in 1 2 3 4 5 6 7 8 9 10; do
|
for seconds in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
ldapsearch $auth -H "$uri" -LLL -b cn=config dn && break;
|
ldapsearch $auth -H "$tcp_uri" -LLL -b cn=config dn && break;
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -106,22 +115,22 @@ mkdir -p "$example_data_dir"
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
sed -E -e "s,^olcDbDirectory:.*,olcDbDirectory: $example_data_dir," \
|
sed -E -e "s,^olcDbDirectory:.*,olcDbDirectory: $example_data_dir," \
|
||||||
< "$example_ldif_dir/global.ldif" | \
|
< "$example_ldif_dir/global.ldif" | \
|
||||||
ldapadd $auth -H "$uri"
|
ldapadd $auth -H "$tcp_uri"
|
||||||
|
|
||||||
# We remove the module path from the example LDIF as it was already
|
# We remove the module path from the example LDIF as it was already
|
||||||
# configured.
|
# configured.
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
sed -E -e "s,^olcModulePath:.*,olcModulePath: $modulepath," \
|
sed -E -e "s,^olcModulePath:.*,olcModulePath: $modulepath," \
|
||||||
< "$example_ldif_dir/memberof_init.ldif" | \
|
< "$example_ldif_dir/memberof_init.ldif" | \
|
||||||
ldapadd $auth -H "$uri"
|
ldapadd $auth -H "$tcp_uri"
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
ldapmodify $auth -H "$uri" -f "$example_ldif_dir/refint_1.ldif"
|
ldapmodify $auth -H "$tcp_uri" -f "$example_ldif_dir/refint_1.ldif"
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
ldapadd $auth -H "$uri" -f "$example_ldif_dir/refint_2.ldif"
|
ldapadd $auth -H "$tcp_uri" -f "$example_ldif_dir/refint_2.ldif"
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
ldapsearch $auth -H "$uri" -LLL -b cn=config dn
|
ldapsearch $auth -H "$tcp_uri" -LLL -b cn=config dn
|
||||||
|
|
||||||
echo SLAPD_PID="$(cat "$pidfile")"
|
echo SLAPD_PID="$(cat "$pidfile")"
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
-define(BAD_REQUEST, 400).
|
-define(BAD_REQUEST, 400).
|
||||||
-define(NOT_AUTHORISED, 401).
|
-define(NOT_AUTHORISED, 401).
|
||||||
-define(METHOD_NOT_ALLOWED, 405).
|
-define(METHOD_NOT_ALLOWED, 405).
|
||||||
|
-define(UNPROCESSABLE_ENTITY, 422).
|
||||||
%%-define(NOT_FOUND, 404). Defined for AMQP by amqp_client.hrl (as 404)
|
%%-define(NOT_FOUND, 404). Defined for AMQP by amqp_client.hrl (as 404)
|
||||||
%% httpc seems to get racy when using HTTP 1.1
|
%% httpc seems to get racy when using HTTP 1.1
|
||||||
-define(HTTPC_OPTS, [{version, "HTTP/1.0"}, {autoredirect, false}]).
|
-define(HTTPC_OPTS, [{version, "HTTP/1.0"}, {autoredirect, false}]).
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
is_authorized_vhost_visible_for_monitoring/2,
|
is_authorized_vhost_visible_for_monitoring/2,
|
||||||
is_authorized_global_parameters/2]).
|
is_authorized_global_parameters/2]).
|
||||||
-export([user/1]).
|
-export([user/1]).
|
||||||
-export([bad_request/3, service_unavailable/3, bad_request_exception/4,
|
-export([bad_request/3, service_unavailable/3, not_authorised/3, bad_request_exception/4,
|
||||||
internal_server_error/3, internal_server_error/4, precondition_failed/3,
|
internal_server_error/3, internal_server_error/4, precondition_failed/3,
|
||||||
|
unprocessable_entity/3,
|
||||||
id/2, parse_bool/1, parse_int/1, redirect_to_home/3]).
|
id/2, parse_bool/1, parse_int/1, redirect_to_home/3]).
|
||||||
-export([with_decode/4, not_found/3]).
|
-export([with_decode/4, not_found/3]).
|
||||||
-export([with_channel/4, with_channel/5]).
|
-export([with_channel/4, with_channel/5]).
|
||||||
|
@ -675,10 +676,12 @@ a2b(B) -> B.
|
||||||
bad_request(Reason, ReqData, Context) ->
|
bad_request(Reason, ReqData, Context) ->
|
||||||
halt_response(400, bad_request, Reason, ReqData, Context).
|
halt_response(400, bad_request, Reason, ReqData, Context).
|
||||||
|
|
||||||
|
unprocessable_entity(Reason, ReqData, Context) ->
|
||||||
|
halt_response(422, unprocessable_entity, Reason, ReqData, Context).
|
||||||
|
|
||||||
service_unavailable(Reason, ReqData, Context) ->
|
service_unavailable(Reason, ReqData, Context) ->
|
||||||
halt_response(503, service_unavailable, Reason, ReqData, Context).
|
halt_response(503, service_unavailable, Reason, ReqData, Context).
|
||||||
|
|
||||||
|
|
||||||
not_authorised(Reason, ReqData, Context) ->
|
not_authorised(Reason, ReqData, Context) ->
|
||||||
rabbit_web_dispatch_access_control:not_authorised(Reason, ReqData, Context).
|
rabbit_web_dispatch_access_control:not_authorised(Reason, ReqData, Context).
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue