Merge branch 'stable'

This commit is contained in:
Daniil Fedotov 2017-02-08 13:36:43 +00:00
commit fe2a3c3b3c
6 changed files with 56 additions and 53 deletions

View File

@ -22,6 +22,10 @@ The list is node-local.
This plugin requires RabbitMQ `3.6.1` or later.
## Erlang Version Requirements
This plugin requires Erlang version 17.3 or later.
## Installation and Binary Builds
This plugin is now available from the [RabbitMQ community plugins page](http://www.rabbitmq.com/community-plugins.html).

View File

@ -28,12 +28,12 @@ list_certs(_Config) ->
%% so they should be unique (there is no need to add change time)
{ok,
[{CertName,
#{name => CertName,
[{name, CertName},
%% Url can be formed from CertName, so there is no
%% need for this attribute.
%% But we use it as an example for providers where CertName and
%% url are different.
url => <<"https://certs.opera.com/02/roots/", CertName/binary>>}}
{url, <<"https://certs.opera.com/02/roots/", CertName/binary>>}]}
|| CertName <- CertNames],
nostate};
Other -> {error, {http_error, Other}}
@ -46,7 +46,8 @@ list_certs(Config, _) -> list_certs(Config).
%% This function loads a certificate data using certifocate ID and attributes.
%% We use the url parameter in attributes.
%% Some providers can ignore attributes and use CertId instead
load_cert(_CertId, #{url := Url}, _Config) ->
load_cert(_CertId, Attributes, _Config) ->
Url = proplists:get_value(url, Attributes),
case httpc:request(get, {rabbit_data_coercion:to_list(Url), []},
[], [{body_format, binary}]) of
{ok, {{_,Code,_}, _Headers, Body}} when Code div 100 == 2 ->

View File

@ -244,7 +244,7 @@ update_certs(CertsList, Provider, Config) ->
lists:foreach(
fun(CertId) ->
Attributes = proplists:get_value(CertId, CertsList),
Name = maps:get(name, Attributes, undefined),
Name = proplists:get_value(name, Attributes, undefined),
case load_and_decode_cert(Provider, CertId, Attributes, Config) of
{ok, Cert, IssuerId} ->
save_cert(CertId, Provider, IssuerId, Cert, Name);
@ -295,7 +295,7 @@ get_old_cert_ids(Provider) ->
when P == Provider ->
CId
end),
lists:append(ets:select(table_name(), MS)).
ets:select(table_name(), MS).
providers(Config) ->
Providers = proplists:get_value(providers, Config, []),

View File

@ -6,18 +6,18 @@
-> no_change | {ok, [{CertId, Attributes}]}
when Config :: list(),
CertId :: term(),
Attributes :: map().
Attributes :: list().
-callback list_certs(Config, ProviderState)
-> no_change | {ok, [{CertId, Attributes}]}
when Config :: list(),
ProviderState :: term(),
CertId :: term(),
Attributes :: map().
Attributes :: list().
-callback load_cert(CertId, Attributes, Config)
-> {ok, Cert} | {error, term()}
when CertId :: term(),
Attributes :: map(),
Attributes :: list(),
Config :: list(),
Cert :: public_key:der_encoded().

View File

@ -15,7 +15,7 @@
-type cert_id() :: {FileName :: string(), ChangeTime :: integer()}.
-spec list_certs(Config :: list())
-> no_change | {ok, [{cert_id(), map()}], State}
-> no_change | {ok, [{cert_id(), list()}], State}
when State :: #directory_state{}.
list_certs(Config) ->
Path = directory_path(Config),
@ -25,7 +25,7 @@ list_certs(Config) ->
directory_change_time = NewChangeTime}}.
-spec list_certs(Config :: list(), State)
-> no_change | {ok, [{cert_id(), map()}], State}
-> no_change | {ok, [{cert_id(), list()}], State}
when State :: #directory_state{}.
list_certs(Config, #directory_state{directory_path = DirPath,
directory_change_time = ChangeTime}) ->
@ -40,9 +40,9 @@ list_certs(Config, #directory_state{directory_path = DirPath,
directory_change_time = NewChangeTime}}
end.
-spec load_cert(cert_id(), map(), Config :: list())
-spec load_cert(cert_id(), list(), Config :: list())
-> {ok, Cert :: public_key:der_encoded()}.
load_cert({FileName, _}, #{}, Config) ->
load_cert({FileName, _}, _, Config) ->
Path = directory_path(Config),
Cert = extract_cert(Path, FileName),
rabbit_log:info(
@ -64,7 +64,7 @@ list_certs_0(Path) ->
fun(FileName) ->
AbsName = filename:absname(FileName, Path),
CertId = {FileName, modification_time(AbsName)},
{CertId, #{name => FileName}}
{CertId, [{name, FileName}]}
end,
FileNames).
@ -92,9 +92,8 @@ default_directory() ->
%% directory, then the Mesia database directory, finally the node
%% directory where we will place the default whitelist in `Full`.
Table = filename:split(rabbit_mnesia:dir()),
Mnesia = lists:droplast(Table),
Node = lists:droplast(Mnesia),
Full = Node ++ ["trust_store", "whitelist"],
Node = lists:sublist(Table, length(Table) - 2),
Full = Node ++ ["trust_store", "whitelist"],
filename:join(Full).
ensure_directory(Path) ->

View File

@ -8,12 +8,12 @@
-define(SERVER_REJECT_CLIENT, {tls_alert, "unknown ca"}).
all() ->
[
{group, non_parallel_tests}
{group, file_provider_tests}
].
groups() ->
[
{non_parallel_tests, [], [
{file_provider_tests, [], [
library,
invasive_SSL_option_change,
validation_success_for_AMQP_client,
@ -57,19 +57,31 @@ end_per_suite(Config) ->
rabbit_ct_client_helpers:teardown_steps() ++
rabbit_ct_broker_helpers:teardown_steps()).
init_per_group(_, Config) ->
Config.
init_per_group(file_provider_tests, Config) ->
WhitelistDir = filename:join([?config(rmq_certsdir, Config),
"trust_store",
"file_provider_tests"]),
ok = filelib:ensure_dir(WhitelistDir),
ok = file:make_dir(WhitelistDir),
Config1 = rabbit_ct_helpers:set_config(Config, {whitelist_dir, WhitelistDir}),
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
?MODULE, change_configuration,
[rabbitmq_trust_store, [{directory, WhitelistDir},
{refresh_interval, interval()},
{providers, [rabbit_trust_store_file_provider]}]]),
Config1.
end_per_group(_, Config) ->
Config.
init_per_testcase(Testcase, Config) ->
TestCaseDir = rabbit_ct_helpers:config_to_testcase_name(Config, Testcase),
WhitelistDir = filename:join([?config(rmq_certsdir, Config), "trust_store", TestCaseDir]),
ok = filelib:ensure_dir(WhitelistDir),
WhitelistDir = ?config(whitelist_dir, Config),
ok = rabbit_file:recursive_delete([WhitelistDir]),
ok = file:make_dir(WhitelistDir),
Config1 = rabbit_ct_helpers:set_config(Config, {whitelist_dir, WhitelistDir}),
rabbit_ct_helpers:testcase_started(Config1, Testcase).
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
?MODULE, change_configuration,
[rabbitmq_trust_store, [{directory, WhitelistDir}]]),
rabbit_ct_helpers:testcase_started(Config, Testcase).
end_per_testcase(Testcase, Config) ->
rabbit_ct_helpers:testcase_finished(Config, Testcase).
@ -178,7 +190,7 @@ validate_chain1(Config) ->
Host = rabbit_ct_helpers:get_config(Config, rmq_hostname),
ok = whitelist(Config, "alice", CertTrusted, KeyTrusted),
ok = change_configuration(rabbitmq_trust_store, [{directory, whitelist_dir(Config)}]),
rabbit_trust_store:refresh(),
catch rabbit_networking:stop_tcp_listener(Port),
ok = rabbit_networking:start_ssl_listener(Port, [{cacerts, [Root]},
@ -221,7 +233,7 @@ validate_longer_chain1(Config) ->
Host = rabbit_ct_helpers:get_config(Config, rmq_hostname),
ok = whitelist(Config, "alice", CertTrusted, KeyTrusted),
ok = change_configuration(rabbitmq_trust_store, [{directory, whitelist_dir(Config)}]),
rabbit_trust_store:refresh(),
catch rabbit_networking:stop_tcp_listener(Port),
ok = rabbit_networking:start_ssl_listener(Port, [{cacerts, [Root]},
@ -287,8 +299,7 @@ validate_chain_without_whitelisted1(Config) ->
Port = port(Config),
Host = rabbit_ct_helpers:get_config(Config, rmq_hostname),
ok = change_configuration(rabbitmq_trust_store, [{directory, whitelist_dir(Config)}]),
rabbit_trust_store:refresh(),
catch rabbit_networking:stop_tcp_listener(Port),
ok = rabbit_networking:start_ssl_listener(Port, [{cacerts, [Root]},
@ -320,7 +331,7 @@ whitelisted_certificate_accepted_from_AMQP_client_regardless_of_validation_to_ro
Host = rabbit_ct_helpers:get_config(Config, rmq_hostname),
ok = whitelist(Config, "alice", CertTrusted, KeyTrusted),
ok = change_configuration(rabbitmq_trust_store, [{directory, whitelist_dir(Config)}]),
rabbit_trust_store:refresh(),
%% When: Rabbit validates paths with a different root `R` than
%% that of the certificate `CertTrusted`.
@ -353,9 +364,7 @@ removed_certificate_denied_from_AMQP_client1(Config) ->
Port = port(Config),
Host = rabbit_ct_helpers:get_config(Config, rmq_hostname),
ok = whitelist(Config, "bob", CertOther, KeyOther),
ok = change_configuration(rabbitmq_trust_store, [{directory, whitelist_dir(Config)},
{refresh_interval,
{seconds, interval()}}]),
rabbit_trust_store:refresh(),
%% When: we wait for at least one second (the accuracy of the
%% file system's time), remove the whitelisted certificate,
@ -392,10 +401,7 @@ installed_certificate_accepted_from_AMQP_client1(Config) ->
Port = port(Config),
Host = rabbit_ct_helpers:get_config(Config, rmq_hostname),
ok = change_configuration(rabbitmq_trust_store, [{directory, whitelist_dir(Config)},
{refresh_interval,
{seconds, interval()}}]),
rabbit_trust_store:refresh(),
%% When: we wait for at least one second (the accuracy of the
%% file system's time), add a certificate to the directory,
@ -440,9 +446,7 @@ whitelist_directory_DELTA1(Config) ->
ok = whitelist(Config, "foo", CertListed1, KeyListed1),
ok = whitelist(Config, "bar", CertRevoked, KeyRevoked),
ok = change_configuration(rabbitmq_trust_store, [{directory, whitelist_dir(Config)},
{refresh_interval,
{seconds, interval()}}]),
rabbit_trust_store:refresh(),
%% When: we wait for at least one second (the accuracy
%% of the file system's time), delete a certificate and
@ -500,8 +504,7 @@ replaced_whitelisted_certificate_should_be_accepted1(Config) ->
{key, Key} | cfg()], 1),
%% And: the first certificate has been whitelisted
ok = whitelist(Config, "bart", CertFirst, KeyFirst),
ok = change_configuration(rabbitmq_trust_store, [{directory, whitelist_dir(Config)},
{refresh_interval, {seconds, interval()}}]),
rabbit_trust_store:refresh(),
wait_for_trust_store_refresh(),
@ -570,13 +573,12 @@ ignore_corrupt_cert1(Config) ->
{Root, Cert, Key} = ct_helper:make_certs(),
{_, CertTrusted, KeyTrusted} = ct_helper:make_certs(),
WhitelistDir = whitelist_dir(Config),
ok = change_configuration(rabbitmq_trust_store, [{directory, WhitelistDir}]),
rabbit_trust_store:refresh(),
ok = whitelist(Config, "alice", CertTrusted, KeyTrusted),
%% When: Rabbit tries to whitelist the corrupt certificate.
ok = whitelist(Config, "corrupt", <<48>>, KeyTrusted),
ok = change_configuration(rabbitmq_trust_store, [{directory, WhitelistDir}]),
rabbit_trust_store:refresh(),
catch rabbit_networking:stop_tcp_listener(Port),
ok = rabbit_networking:start_ssl_listener(Port, [{cacerts, [Root]},
@ -608,13 +610,11 @@ ignore_same_cert_with_different_name1(Config) ->
{Root, Cert, Key} = ct_helper:make_certs(),
{_, CertTrusted, KeyTrusted} = ct_helper:make_certs(),
WhitelistDir = whitelist_dir(Config),
ok = change_configuration(rabbitmq_trust_store, [{directory, WhitelistDir}]),
rabbit_trust_store:refresh(),
ok = whitelist(Config, "alice", CertTrusted, KeyTrusted),
%% When: Rabbit tries to insert the duplicate certificate
ok = whitelist(Config, "malice", CertTrusted, KeyTrusted),
ok = change_configuration(rabbitmq_trust_store, [{directory, WhitelistDir}]),
rabbit_trust_store:refresh(),
catch rabbit_networking:stop_tcp_listener(Port),
ok = rabbit_networking:start_ssl_listener(Port, [{cacerts, [Root]},
@ -636,8 +636,8 @@ ignore_same_cert_with_different_name1(Config) ->
list(Config) ->
{_Root, Cert, Key} = ct_helper:make_certs(),
ok = whitelist(Config, "alice", Cert, Key),
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
?MODULE, change_configuration, [rabbitmq_trust_store, [{directory, whitelist_dir(Config)}]]),
% wait_for_trust_store_refresh(),
ok = rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_trust_store, refresh, []),
Certs = rabbit_ct_broker_helpers:rpc(Config, 0,
rabbit_trust_store, list, []),
% only really tests it isn't totally broken.
@ -646,8 +646,7 @@ list(Config) ->
disabled_provider_removes_certificates(Config) ->
{_Root, Cert, Key} = ct_helper:make_certs(),
ok = whitelist(Config, "alice", Cert, Key),
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
?MODULE, change_configuration, [rabbitmq_trust_store, [{directory, whitelist_dir(Config)}]]),
ok = rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_trust_store, refresh, []),
%% Certificate is there
Certs = rabbit_ct_broker_helpers:rpc(Config, 0,