Merge pull request #110 from rabbitmq/rabbitmq-mqtt-73
Introduce mqtt_default_vhosts global parameter
This commit is contained in:
commit
03f147d08a
|
|
@ -21,7 +21,7 @@
|
|||
close_connection/1]).
|
||||
|
||||
%% for testing purposes
|
||||
-export([get_vhost_username/1]).
|
||||
-export([get_vhost_username/1, get_vhost_from_mapping/2]).
|
||||
|
||||
-include_lib("amqp_client/include/amqp_client.hrl").
|
||||
-include("rabbit_mqtt_frame.hrl").
|
||||
|
|
@ -455,8 +455,9 @@ make_will_msg(#mqtt_frame_connect{ will_retain = Retain,
|
|||
process_login(UserBin, PassBin, ProtoVersion,
|
||||
#proc_state{ channels = {undefined, undefined},
|
||||
socket = Sock,
|
||||
adapter_info = AdapterInfo }) ->
|
||||
{VHost, UsernameBin} = get_vhost_username(UserBin),
|
||||
adapter_info = AdapterInfo,
|
||||
ssl_login_name = SslLoginName}) ->
|
||||
{VHost, UsernameBin} = get_vhost_username(UserBin, SslLoginName),
|
||||
case rabbit_vhost:exists(VHost) of
|
||||
true ->
|
||||
case amqp_connection:start(#amqp_params_direct{
|
||||
|
|
@ -486,6 +487,12 @@ process_login(UserBin, PassBin, ProtoVersion,
|
|||
[binary_to_list(UserBin), Explanation]),
|
||||
?CONNACK_CREDENTIALS;
|
||||
{error, access_refused} ->
|
||||
rabbit_log:warning("MQTT login failed for ~p access_refused "
|
||||
"(vhost access not allowed)~n",
|
||||
[binary_to_list(UserBin)]),
|
||||
?CONNACK_AUTH;
|
||||
{error, not_allowed} ->
|
||||
%% when vhost allowed for TLS connection
|
||||
rabbit_log:warning("MQTT login failed for ~p access_refused "
|
||||
"(vhost access not allowed)~n",
|
||||
[binary_to_list(UserBin)]),
|
||||
|
|
@ -497,6 +504,24 @@ process_login(UserBin, PassBin, ProtoVersion,
|
|||
?CONNACK_CREDENTIALS
|
||||
end.
|
||||
|
||||
get_vhost_username(UserBin, SslLoginName) ->
|
||||
case {UserBin, SslLoginName} of
|
||||
{UserBin, none} ->
|
||||
get_vhost_username(UserBin);
|
||||
{UserBin, undefined} ->
|
||||
get_vhost_username(UserBin);
|
||||
{UserBin, SslLoginName} ->
|
||||
UserVirtualHostMapping = rabbit_runtime_parameters:value_global(
|
||||
mqtt_default_vhosts
|
||||
),
|
||||
case get_vhost_from_mapping(SslLoginName, UserVirtualHostMapping) of
|
||||
undefined ->
|
||||
get_vhost_username(UserBin);
|
||||
VHost ->
|
||||
{VHost, UserBin}
|
||||
end
|
||||
end.
|
||||
|
||||
get_vhost_username(UserBin) ->
|
||||
Default = {rabbit_mqtt_util:env(vhost), UserBin},
|
||||
case application:get_env(?APP, ignore_colons_in_username) of
|
||||
|
|
@ -509,6 +534,20 @@ get_vhost_username(UserBin) ->
|
|||
end
|
||||
end.
|
||||
|
||||
get_vhost_from_mapping(User, Mapping) ->
|
||||
case Mapping of
|
||||
not_found ->
|
||||
undefined;
|
||||
Mapping ->
|
||||
case rabbit_misc:pget(User, Mapping) of
|
||||
VHost ->
|
||||
VHost;
|
||||
undefined ->
|
||||
undefined
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
creds(User, Pass, SSLLoginName) ->
|
||||
DefaultUser = rabbit_mqtt_util:env(default_user),
|
||||
DefaultPass = rabbit_mqtt_util:env(default_pass),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@ groups() ->
|
|||
[{anonymous_ssl_user, [],
|
||||
[anonymous_auth_success,
|
||||
user_credentials_auth,
|
||||
ssl_user_auth_success]},
|
||||
ssl_user_auth_success,
|
||||
ssl_user_vhost_not_allowed,
|
||||
ssl_user_vhost_parameter_mapping_success,
|
||||
ssl_user_vhost_parameter_mapping_not_allowed,
|
||||
ssl_user_vhost_parameter_mapping_vhost_does_not_exist]},
|
||||
{anonymous_no_ssl_user, [],
|
||||
[anonymous_auth_success,
|
||||
user_credentials_auth
|
||||
|
|
@ -24,7 +28,11 @@ groups() ->
|
|||
{ssl_user, [],
|
||||
[anonymous_auth_failure,
|
||||
user_credentials_auth,
|
||||
ssl_user_auth_success]},
|
||||
ssl_user_auth_success,
|
||||
ssl_user_vhost_not_allowed,
|
||||
ssl_user_vhost_parameter_mapping_success,
|
||||
ssl_user_vhost_parameter_mapping_not_allowed,
|
||||
ssl_user_vhost_parameter_mapping_vhost_does_not_exist]},
|
||||
{no_ssl_user, [],
|
||||
[anonymous_auth_failure,
|
||||
user_credentials_auth,
|
||||
|
|
@ -72,28 +80,74 @@ mqtt_config(no_ssl_user) ->
|
|||
|
||||
init_per_testcase(Testcase, Config) when Testcase == ssl_user_auth_success;
|
||||
Testcase == ssl_user_auth_failure ->
|
||||
Hostname = re:replace(os:cmd("hostname"), "\\s+", "", [global,{return,list}]),
|
||||
User = "O=client,CN=" ++ Hostname,
|
||||
{ok,_} = rabbit_ct_broker_helpers:rabbitmqctl(Config, 0, ["add_user", User, ""]),
|
||||
{ok, _} = rabbit_ct_broker_helpers:rabbitmqctl(Config, 0, ["set_permissions", "-p", "/", User, ".*", ".*", ".*"]),
|
||||
Config1 = rabbit_ct_helpers:set_config(Config, [{temp_ssl_user, User}]),
|
||||
Config1 = set_cert_user_on_default_vhost(Config),
|
||||
rabbit_ct_helpers:testcase_started(Config1, Testcase);
|
||||
init_per_testcase(ssl_user_vhost_parameter_mapping_success, Config) ->
|
||||
Config1 = set_cert_user_on_default_vhost(Config),
|
||||
User = ?config(temp_ssl_user, Config1),
|
||||
ok = rabbit_ct_broker_helpers:clear_permissions(Config1, User, <<"/">>),
|
||||
Config2 = set_vhost_for_cert_user(Config1, User),
|
||||
rabbit_ct_helpers:testcase_started(Config2, ssl_user_vhost_parameter_mapping_success);
|
||||
init_per_testcase(ssl_user_vhost_parameter_mapping_not_allowed, Config) ->
|
||||
Config1 = set_cert_user_on_default_vhost(Config),
|
||||
User = ?config(temp_ssl_user, Config1),
|
||||
Config2 = set_vhost_for_cert_user(Config1, User),
|
||||
VhostForCertUser = ?config(temp_vhost_for_ssl_user, Config2),
|
||||
ok = rabbit_ct_broker_helpers:clear_permissions(Config2, User, VhostForCertUser),
|
||||
rabbit_ct_helpers:testcase_started(Config2, ssl_user_vhost_parameter_mapping_not_allowed);
|
||||
init_per_testcase(user_credentials_auth, Config) ->
|
||||
User = <<"new-user">>,
|
||||
Pass = <<"new-user-pass">>,
|
||||
{ok,_} = rabbit_ct_broker_helpers:rabbitmqctl(Config, 0, ["add_user", User, Pass]),
|
||||
{ok, _} = rabbit_ct_broker_helpers:rabbitmqctl(Config, 0, ["set_permissions", "-p", "/", User, ".*", ".*", ".*"]),
|
||||
ok = rabbit_ct_broker_helpers:add_user(Config, 0, User, Pass),
|
||||
ok = rabbit_ct_broker_helpers:set_full_permissions(Config, User, <<"/">>),
|
||||
Config1 = rabbit_ct_helpers:set_config(Config, [{new_user, User},
|
||||
{new_user_pass, Pass}]),
|
||||
rabbit_ct_helpers:testcase_started(Config1, user_credentials_auth);
|
||||
init_per_testcase(ssl_user_vhost_not_allowed, Config) ->
|
||||
Config1 = set_cert_user_on_default_vhost(Config),
|
||||
User = ?config(temp_ssl_user, Config1),
|
||||
ok = rabbit_ct_broker_helpers:clear_permissions(Config1, User, <<"/">>),
|
||||
rabbit_ct_helpers:testcase_started(Config1, ssl_user_vhost_not_allowed);
|
||||
init_per_testcase(ssl_user_vhost_parameter_mapping_vhost_does_not_exist, Config) ->
|
||||
Config1 = set_cert_user_on_default_vhost(Config),
|
||||
User = ?config(temp_ssl_user, Config1),
|
||||
Config2 = set_vhost_for_cert_user(Config1, User),
|
||||
VhostForCertUser = ?config(temp_vhost_for_ssl_user, Config2),
|
||||
ok = rabbit_ct_broker_helpers:delete_vhost(Config, VhostForCertUser),
|
||||
rabbit_ct_helpers:testcase_started(Config1, ssl_user_vhost_parameter_mapping_vhost_does_not_exist);
|
||||
init_per_testcase(Testcase, Config) ->
|
||||
rabbit_ct_helpers:testcase_started(Config, Testcase).
|
||||
|
||||
set_cert_user_on_default_vhost(Config) ->
|
||||
Hostname = re:replace(os:cmd("hostname"), "\\s+", "", [global,{return,list}]),
|
||||
User = "O=client,CN=" ++ Hostname,
|
||||
ok = rabbit_ct_broker_helpers:add_user(Config, 0, User, ""),
|
||||
ok = rabbit_ct_broker_helpers:set_full_permissions(Config, User, <<"/">>),
|
||||
rabbit_ct_helpers:set_config(Config, [{temp_ssl_user, User}]).
|
||||
|
||||
set_vhost_for_cert_user(Config, User) ->
|
||||
VhostForCertUser = <<"vhost_for_cert_user">>,
|
||||
UserToVHostMappingParameter = [
|
||||
{rabbit_data_coercion:to_binary(User), VhostForCertUser},
|
||||
{<<"O=client,CN=unlikelytoexistuser">>, <<"vhost2">>}
|
||||
],
|
||||
ok = rabbit_ct_broker_helpers:add_vhost(Config, VhostForCertUser),
|
||||
ok = rabbit_ct_broker_helpers:set_full_permissions(Config, User, VhostForCertUser),
|
||||
ok = rabbit_ct_broker_helpers:set_global_parameter(Config, mqtt_default_vhosts, UserToVHostMappingParameter),
|
||||
rabbit_ct_helpers:set_config(Config, [{temp_vhost_for_ssl_user, VhostForCertUser}]).
|
||||
|
||||
end_per_testcase(Testcase, Config) when Testcase == ssl_user_auth_success;
|
||||
Testcase == ssl_user_auth_failure ->
|
||||
User = ?config(temp_ssl_user, Config),
|
||||
{ok,_} = rabbit_ct_broker_helpers:rabbitmqctl(Config, 0, ["delete_user", User]),
|
||||
Testcase == ssl_user_auth_failure;
|
||||
Testcase == ssl_user_vhost_not_allowed ->
|
||||
delete_cert_user(Config),
|
||||
rabbit_ct_helpers:testcase_finished(Config, Testcase);
|
||||
end_per_testcase(TestCase, Config) when TestCase == ssl_user_vhost_parameter_mapping_success;
|
||||
TestCase == ssl_user_vhost_parameter_mapping_not_allowed ->
|
||||
delete_cert_user(Config),
|
||||
VhostForCertUser = ?config(temp_vhost_for_ssl_user, Config),
|
||||
ok = rabbit_ct_broker_helpers:delete_vhost(Config, VhostForCertUser),
|
||||
ok = rabbit_ct_broker_helpers:clear_global_parameter(Config, mqtt_default_vhosts),
|
||||
rabbit_ct_helpers:testcase_finished(Config, TestCase);
|
||||
end_per_testcase(user_credentials_auth, Config) ->
|
||||
User = ?config(new_user, Config),
|
||||
{ok,_} = rabbit_ct_broker_helpers:rabbitmqctl(Config, 0, ["delete_user", User]),
|
||||
|
|
@ -101,6 +155,10 @@ end_per_testcase(user_credentials_auth, Config) ->
|
|||
end_per_testcase(Testcase, Config) ->
|
||||
rabbit_ct_helpers:testcase_finished(Config, Testcase).
|
||||
|
||||
delete_cert_user(Config) ->
|
||||
User = ?config(temp_ssl_user, Config),
|
||||
{ok,_} = rabbit_ct_broker_helpers:rabbitmqctl(Config, 0, ["delete_user", User]).
|
||||
|
||||
anonymous_auth_success(Config) ->
|
||||
expect_successful_connection(fun connect_anonymous/1, Config).
|
||||
|
||||
|
|
@ -146,6 +204,17 @@ user_credentials_auth(Config) ->
|
|||
fun(Conf) -> connect_user(<<"non-existing-vhost:guest">>, <<"guest">>, Conf) end,
|
||||
Config).
|
||||
|
||||
ssl_user_vhost_parameter_mapping_success(Config) ->
|
||||
expect_successful_connection(fun connect_ssl/1, Config).
|
||||
|
||||
ssl_user_vhost_parameter_mapping_not_allowed(Config) ->
|
||||
expect_authentication_failure(fun connect_ssl/1, Config).
|
||||
|
||||
ssl_user_vhost_not_allowed(Config) ->
|
||||
expect_authentication_failure(fun connect_ssl/1, Config).
|
||||
|
||||
ssl_user_vhost_parameter_mapping_vhost_does_not_exist(Config) ->
|
||||
expect_authentication_failure(fun connect_ssl/1, Config).
|
||||
|
||||
connect_anonymous(Config) ->
|
||||
P = rabbit_ct_broker_helpers:get_node_config(Config, 0, tcp_port_mqtt),
|
||||
|
|
@ -194,6 +263,7 @@ expect_authentication_failure(ConnectFun, Config) ->
|
|||
{ok, C} = ConnectFun(Config),
|
||||
Result = receive
|
||||
{mqttc, C, connected} -> {error, unexpected_anonymous_connection};
|
||||
{'EXIT', C, {shutdown,{connack_error,'CONNACK_AUTH'}}} -> ok;
|
||||
{'EXIT', C, {shutdown,{connack_error,'CONNACK_CREDENTIALS'}}} -> ok
|
||||
after
|
||||
?CONNECT_TIMEOUT -> {error, emqttc_connection_timeout}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ groups() ->
|
|||
[
|
||||
{non_parallel_tests, [], [
|
||||
ignores_colons_in_username_if_option_set,
|
||||
interprets_colons_in_username_if_option_not_set
|
||||
interprets_colons_in_username_if_option_not_set,
|
||||
get_vhosts_from_global_runtime_parameter
|
||||
]}
|
||||
].
|
||||
|
||||
|
|
@ -58,3 +59,13 @@ interprets_colons_in_username_if_option_not_set(_Config) ->
|
|||
ignore_colons(false),
|
||||
?assertEqual({<<"a:b">>, <<"c">>},
|
||||
rabbit_mqtt_processor:get_vhost_username(<<"a:b:c">>)).
|
||||
|
||||
get_vhosts_from_global_runtime_parameter(_Config) ->
|
||||
MappingParameter = [
|
||||
{<<"O=client,CN=dummy1">>, <<"vhost1">>},
|
||||
{<<"O=client,CN=dummy2">>, <<"vhost2">>}
|
||||
],
|
||||
<<"vhost1">> = rabbit_mqtt_processor:get_vhost_from_mapping(<<"O=client,CN=dummy1">>, MappingParameter),
|
||||
<<"vhost2">> = rabbit_mqtt_processor:get_vhost_from_mapping(<<"O=client,CN=dummy2">>, MappingParameter),
|
||||
undefined = rabbit_mqtt_processor:get_vhost_from_mapping(<<"O=client,CN=dummy3">>, MappingParameter),
|
||||
undefined = rabbit_mqtt_processor:get_vhost_from_mapping(<<"O=client,CN=dummy3">>, not_found).
|
||||
Loading…
Reference in New Issue