Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 34 additions & 37 deletions deps/rabbitmq_mqtt/src/rabbit_mqtt_processor.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1178,65 +1178,56 @@ get_vhost(UserBin, SslLogin, Port) ->
get_vhost_ssl(UserBin, SslLogin, Port).

get_vhost_no_ssl(UserBin, Port) ->
case vhost_in_username(UserBin) of
true ->
{vhost_in_username_or_default, get_vhost_username(UserBin)};
false ->
PortVirtualHostMapping = rabbit_runtime_parameters:value_global(
mqtt_port_to_vhost_mapping
),
case get_vhost_from_port_mapping(Port, PortVirtualHostMapping) of
case get_vhost_username(UserBin) of
undefined ->
case get_vhost_from_port_mapping(Port) of
undefined ->
{plugin_configuration_or_default_vhost, {rabbit_mqtt_util:env(vhost), UserBin}};
VHost ->
{port_to_vhost_mapping, {VHost, UserBin}}
end
VhostFromConfig = rabbit_mqtt_util:env(vhost),
{plugin_configuration_or_default_vhost, {VhostFromConfig, UserBin}};
VHostFromPortMapping ->
{port_to_vhost_mapping, {VHostFromPortMapping, UserBin}}
end;
VHostUser ->
{vhost_in_username, VHostUser}
end.

get_vhost_ssl(UserBin, SslLoginName, Port) ->
UserVirtualHostMapping = rabbit_runtime_parameters:value_global(
mqtt_default_vhosts
),
case get_vhost_from_user_mapping(SslLoginName, UserVirtualHostMapping) of
case get_vhost_from_user_mapping(SslLoginName) of
undefined ->
PortVirtualHostMapping = rabbit_runtime_parameters:value_global(
mqtt_port_to_vhost_mapping
),
case get_vhost_from_port_mapping(Port, PortVirtualHostMapping) of
case get_vhost_from_port_mapping(Port) of
undefined ->
{vhost_in_username_or_default, get_vhost_username(UserBin)};
case get_vhost_username(UserBin) of
undefined ->
VhostFromConfig = rabbit_mqtt_util:env(vhost),
{plugin_configuration_or_default_vhost, {VhostFromConfig, UserBin}};
VHostUser ->
{vhost_in_username, VHostUser}
end;
VHostFromPortMapping ->
{port_to_vhost_mapping, {VHostFromPortMapping, UserBin}}
end;
VHostFromCertMapping ->
{client_cert_to_vhost_mapping, {VHostFromCertMapping, UserBin}}
end.

vhost_in_username(UserBin) ->
case application:get_env(?APP_NAME, ignore_colons_in_username) of
{ok, true} -> false;
_ ->
%% split at the last colon, disallowing colons in username
case re:split(UserBin, ":(?!.*?:)") of
[_, _] -> true;
[UserBin] -> false;
[] -> false
end
end.

get_vhost_username(UserBin) ->
Default = {rabbit_mqtt_util:env(vhost), UserBin},
case application:get_env(?APP_NAME, ignore_colons_in_username) of
{ok, true} -> Default;
{ok, true} -> undefined;
_ ->
%% split at the last colon, disallowing colons in username
case re:split(UserBin, ":(?!.*?:)") of
[Vhost, UserName] -> {Vhost, UserName};
[UserBin] -> Default;
[] -> Default
[UserBin] -> undefined;
[] -> undefined
end
end.

get_vhost_from_user_mapping(User) ->
UserVirtualHostMapping = rabbit_runtime_parameters:value_global(
mqtt_default_vhosts
),
get_vhost_from_user_mapping(User, UserVirtualHostMapping).

get_vhost_from_user_mapping(_User, not_found) ->
undefined;
get_vhost_from_user_mapping(User, Mapping) ->
Expand All @@ -1248,6 +1239,12 @@ get_vhost_from_user_mapping(User, Mapping) ->
VHost
end.

get_vhost_from_port_mapping(Port) ->
PortVirtualHostMapping = rabbit_runtime_parameters:value_global(
mqtt_port_to_vhost_mapping
),
get_vhost_from_port_mapping(Port, PortVirtualHostMapping).

get_vhost_from_port_mapping(_Port, not_found) ->
undefined;
get_vhost_from_port_mapping(Port, Mapping) ->
Expand Down
101 changes: 49 additions & 52 deletions deps/rabbitmq_mqtt/test/processor_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,27 @@ suite() ->

init_per_suite(Config) ->
ok = application:load(rabbitmq_mqtt),
meck:new(rabbit_runtime_parameters, [passthrough, no_link]),
Config.
end_per_suite(Config) ->
ok = application:unload(rabbitmq_mqtt),
meck:unload(rabbit_runtime_parameters),
Config.
init_per_group(_, Config) -> Config.
end_per_group(_, Config) -> Config.
init_per_testcase(get_vhost, Config) ->
mnesia:start(),
mnesia:create_table(rabbit_runtime_parameters, [
{attributes, record_info(fields, runtime_parameters)},
{record_name, runtime_parameters}]),
meck:new(rabbit_feature_flags, [passthrough, no_link]),
meck:expect(
rabbit_feature_flags, is_enabled,
fun
(khepri_db, _) -> false;
(FeatureNames, _) -> meck:passthrough([FeatureNames])
end),
Config;
init_per_testcase(_, Config) -> Config.
end_per_testcase(get_vhost, Config) ->
meck:unload(rabbit_feature_flags),
mnesia:stop(),
Config;
end_per_testcase(_, Config) -> Config.

ignore_colons(B) -> application:set_env(rabbitmq_mqtt, ignore_colons_in_username, B).

ignores_colons_in_username_if_option_set(_Config) ->
ignore_colons(true),
?assertEqual({rabbit_mqtt_util:env(vhost), <<"a:b:c">>},
rabbit_mqtt_processor:get_vhost_username(<<"a:b:c">>)).
clear_vhost_global_parameters(),
ignore_colons(true),
?assertEqual(undefined,
rabbit_mqtt_processor:get_vhost_username(<<"a:b:c">>)),
?assertEqual({plugin_configuration_or_default_vhost,
{rabbit_mqtt_util:env(vhost), <<"a:b:c">>}},
rabbit_mqtt_processor:get_vhost(<<"a:b:c">>, none, 1883)).

interprets_colons_in_username_if_option_not_set(_Config) ->
ignore_colons(false),
Expand Down Expand Up @@ -150,26 +139,32 @@ get_vhost(_Config) ->

%% certificate user, port/vhost parameter but no mapping, cert/vhost mapping
%% should use cert/vhost mapping
set_global_parameter(mqtt_default_vhosts, [
{<<"O=client,CN=dummy">>, <<"somevhost">>},
{<<"O=client,CN=otheruser">>, <<"othervhost">>}
]),
set_global_parameter(mqtt_port_to_vhost_mapping, [
{<<"1884">>, <<"othervhost">>}
]),
set_global_parameters(
[{mqtt_default_vhosts,
[
{<<"O=client,CN=dummy">>, <<"somevhost">>},
{<<"O=client,CN=otheruser">>, <<"othervhost">>}
]},
{mqtt_port_to_vhost_mapping,
[
{<<"1884">>, <<"othervhost">>}
]}]),
{_, {<<"somevhost">>, <<"guest">>}} = rabbit_mqtt_processor:get_vhost(<<"guest">>, <<"O=client,CN=dummy">>, 1883),
clear_vhost_global_parameters(),

%% certificate user, port/vhost parameter, cert/vhost parameter
%% cert/vhost parameter takes precedence
set_global_parameter(mqtt_default_vhosts, [
{<<"O=client,CN=dummy">>, <<"cert-somevhost">>},
{<<"O=client,CN=otheruser">>, <<"othervhost">>}
]),
set_global_parameter(mqtt_port_to_vhost_mapping, [
{<<"1883">>, <<"port-vhost">>},
{<<"1884">>, <<"othervhost">>}
]),
set_global_parameters(
[{mqtt_default_vhosts,
[
{<<"O=client,CN=dummy">>, <<"cert-somevhost">>},
{<<"O=client,CN=otheruser">>, <<"othervhost">>}
]},
{mqtt_port_to_vhost_mapping,
[
{<<"1883">>, <<"port-vhost">>},
{<<"1884">>, <<"othervhost">>}
]}]),
{_, {<<"cert-somevhost">>, <<"guest">>}} = rabbit_mqtt_processor:get_vhost(<<"guest">>, <<"O=client,CN=dummy">>, 1883),
clear_vhost_global_parameters(),

Expand All @@ -179,28 +174,30 @@ get_vhost(_Config) ->

%% not a certificate user, port/vhost parameter, cert/vhost parameter
%% port/vhost mapping is used, as cert/vhost should not be used
set_global_parameter(mqtt_default_vhosts, [
{<<"O=cert">>, <<"cert-somevhost">>},
{<<"O=client,CN=otheruser">>, <<"othervhost">>}
]),
set_global_parameter(mqtt_port_to_vhost_mapping, [
{<<"1883">>, <<"port-vhost">>},
{<<"1884">>, <<"othervhost">>}
]),
set_global_parameters(
[{mqtt_default_vhosts,
[
{<<"O=cert">>, <<"cert-somevhost">>},
{<<"O=client,CN=otheruser">>, <<"othervhost">>}
]},
{mqtt_port_to_vhost_mapping,
[
{<<"1883">>, <<"port-vhost">>},
{<<"1884">>, <<"othervhost">>}
]}]),
{_, {<<"port-vhost">>, <<"guest">>}} = rabbit_mqtt_processor:get_vhost(<<"guest">>, none, 1883),
clear_vhost_global_parameters(),
ok.

set_global_parameter(Key, Term) ->
InsertParameterFun = fun () ->
mnesia:write(rabbit_runtime_parameters, #runtime_parameters{key = Key, value = Term}, write)
end,
set_global_parameters([{Key, Term}]).

{atomic, ok} = mnesia:transaction(InsertParameterFun).
set_global_parameters(KVList) ->
meck:expect(
rabbit_runtime_parameters, value_global,
fun(Key) -> proplists:get_value(Key, KVList, not_found) end).

clear_vhost_global_parameters() ->
DeleteParameterFun = fun () ->
ok = mnesia:delete(rabbit_runtime_parameters, mqtt_default_vhosts, write),
ok = mnesia:delete(rabbit_runtime_parameters, mqtt_port_to_vhost_mapping, write)
end,
{atomic, ok} = mnesia:transaction(DeleteParameterFun).
meck:expect(
rabbit_runtime_parameters, value_global,
fun(_) -> not_found end).
Loading