summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Klishin <mklishin@pivotal.io>2017-02-10 20:43:42 +0300
committerMichael Klishin <mklishin@pivotal.io>2017-02-10 20:43:42 +0300
commitbf8c3831744840240e63e9f2cc45594272d68e91 (patch)
tree62d50a8001e94fe0cf691d310c6ed246ae886c2e
parentff8a0fc45bc0302ccf50f154be4e6d6829a8ffaa (diff)
parentc987323355979fad895bf7f84538840148851af9 (diff)
downloadrabbitmq-server-git-bf8c3831744840240e63e9f2cc45594272d68e91.tar.gz
Merge branch 'stable' into rabbitmq-management-345
-rw-r--r--Makefile15
-rw-r--r--rabbitmq-components.mk6
-rw-r--r--src/rabbit_credential_validation.erl53
-rw-r--r--src/rabbit_credential_validator.erl28
-rw-r--r--src/rabbit_credential_validator_accept_everything.erl32
-rw-r--r--src/rabbit_credential_validator_min_password_length.erl56
-rw-r--r--src/rabbit_credential_validator_password_regexp.erl51
-rw-r--r--src/rabbit_plugins.erl2
-rw-r--r--src/rabbit_ssl.erl228
-rw-r--r--src/rabbit_table.erl9
-rw-r--r--src/rabbit_variable_queue.erl53
-rw-r--r--test/credential_validation_SUITE.erl275
-rw-r--r--test/dynamic_ha_SUITE.erl28
-rw-r--r--test/unit_inbroker_SUITE.erl36
-rw-r--r--test/worker_pool_SUITE.erl15
15 files changed, 598 insertions, 289 deletions
diff --git a/Makefile b/Makefile
index 176705010d..05305a4b89 100644
--- a/Makefile
+++ b/Makefile
@@ -90,11 +90,11 @@ define PROJECT_ENV
%% setting has no effect because credit_flow is not used when
%% writing to the queue index. See the setting
%% queue_index_embed_msgs_below above.
- {msg_store_credit_disc_bound, {2000, 500}},
+ {msg_store_credit_disc_bound, {3000, 800}},
{msg_store_io_batch_size, 2048},
- %% see rabbitmq-server#143
- %% and rabbitmq-server#949
- {credit_flow_default_credit, {200, 100}},
+ %% see rabbitmq-server#143,
+ %% rabbitmq-server#949, rabbitmq-server#1098
+ {credit_flow_default_credit, {400, 200}},
%% see rabbitmq-server#248
%% and rabbitmq-server#667
{channel_operation_timeout, 15000},
@@ -104,8 +104,9 @@ define PROJECT_ENV
{passphrase, undefined}
]},
%% rabbitmq-server-973
- {lazy_queue_explicit_gc_run_operation_threshold, 250},
- {background_gc_enabled, true},
+ {queue_explicit_gc_run_operation_threshold, 1000},
+ {lazy_queue_explicit_gc_run_operation_threshold, 1000},
+ {background_gc_enabled, false},
{background_gc_target_interval, 60000}
]
endef
@@ -130,8 +131,8 @@ EXTRA_SOURCES += $(USAGES_ERL)
$(PROJECT).d:: $(EXTRA_SOURCES)
DEP_PLUGINS = rabbit_common/mk/rabbitmq-build.mk \
- rabbit_common/mk/rabbitmq-run.mk \
rabbit_common/mk/rabbitmq-dist.mk \
+ rabbit_common/mk/rabbitmq-run.mk \
rabbit_common/mk/rabbitmq-tools.mk
# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be
diff --git a/rabbitmq-components.mk b/rabbitmq-components.mk
index c05a66fe13..f4db6812bc 100644
--- a/rabbitmq-components.mk
+++ b/rabbitmq-components.mk
@@ -42,6 +42,7 @@ dep_rabbit = git_rmq rabbitmq-server $(current_rmq_re
dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master
+dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master
@@ -59,6 +60,7 @@ dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rm
dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master
+dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master
@@ -102,7 +104,7 @@ dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(curre
dep_cowboy_commit = 1.0.4
dep_mochiweb = git git://github.com/basho/mochiweb.git v2.9.0p2
-dep_ranch_commit = 1.3.0
+dep_ranch_commit = 1.3.1
dep_webmachine_commit = 1.10.8p2
RABBITMQ_COMPONENTS = amqp_client \
@@ -110,6 +112,7 @@ RABBITMQ_COMPONENTS = amqp_client \
rabbit_common \
rabbitmq_amqp1_0 \
rabbitmq_auth_backend_amqp \
+ rabbitmq_auth_backend_cache \
rabbitmq_auth_backend_http \
rabbitmq_auth_backend_ldap \
rabbitmq_auth_mechanism_ssl \
@@ -127,6 +130,7 @@ RABBITMQ_COMPONENTS = amqp_client \
rabbitmq_federation_management \
rabbitmq_java_client \
rabbitmq_jms_client \
+ rabbitmq_jms_cts \
rabbitmq_jms_topic_exchange \
rabbitmq_lvc \
rabbitmq_management \
diff --git a/src/rabbit_credential_validation.erl b/src/rabbit_credential_validation.erl
new file mode 100644
index 0000000000..4a629da14f
--- /dev/null
+++ b/src/rabbit_credential_validation.erl
@@ -0,0 +1,53 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
+%%
+
+-module(rabbit_credential_validation).
+
+-include("rabbit.hrl").
+
+%% used for backwards compatibility
+-define(DEFAULT_BACKEND, rabbit_credential_validator_accept_everything).
+
+%%
+%% API
+%%
+
+-export([validate/2, backend/0]).
+
+-spec validate(rabbit_types:username(), rabbit_types:password()) -> 'ok' | {'error', string()}.
+
+%% Validates a username/password pair by delegating to the effective
+%% `rabbit_credential_validator`. Used by `rabbit_auth_backend_internal`.
+%% Note that some validators may choose to only validate passwords.
+%%
+%% Possible return values:
+%%
+%% * ok: provided credentials passed validation.
+%% * {error, Error, Args}: provided password password failed validation.
+
+validate(Username, Password) ->
+ Backend = backend(),
+ Backend:validate(Username, Password).
+
+-spec backend() -> atom().
+
+backend() ->
+ case application:get_env(rabbit, credential_validator) of
+ undefined ->
+ ?DEFAULT_BACKEND;
+ {ok, Proplist} ->
+ proplists:get_value(validation_backend, Proplist, ?DEFAULT_BACKEND)
+ end.
diff --git a/src/rabbit_credential_validator.erl b/src/rabbit_credential_validator.erl
new file mode 100644
index 0000000000..dd12f6d2d6
--- /dev/null
+++ b/src/rabbit_credential_validator.erl
@@ -0,0 +1,28 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
+%%
+
+-module(rabbit_credential_validator).
+
+-include("rabbit.hrl").
+
+%% Validates a password. Used by `rabbit_auth_backend_internal`.
+%%
+%% Possible return values:
+%%
+%% * ok: provided password passed validation.
+%% * {error, Error, Args}: provided password password failed validation.
+
+-callback validate(rabbit_types:username(), rabbit_types:password()) -> 'ok' | {'error', string()}.
diff --git a/src/rabbit_credential_validator_accept_everything.erl b/src/rabbit_credential_validator_accept_everything.erl
new file mode 100644
index 0000000000..f572d67e7f
--- /dev/null
+++ b/src/rabbit_credential_validator_accept_everything.erl
@@ -0,0 +1,32 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
+%%
+
+-module(rabbit_credential_validator_accept_everything).
+
+-include("rabbit.hrl").
+
+-behaviour(rabbit_credential_validator).
+
+%%
+%% API
+%%
+
+-export([validate/2]).
+
+-spec validate(rabbit_types:username(), rabbit_types:password()) -> 'ok' | {'error', string()}.
+
+validate(_Username, _Password) ->
+ ok.
diff --git a/src/rabbit_credential_validator_min_password_length.erl b/src/rabbit_credential_validator_min_password_length.erl
new file mode 100644
index 0000000000..78239fc71b
--- /dev/null
+++ b/src/rabbit_credential_validator_min_password_length.erl
@@ -0,0 +1,56 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
+%%
+
+-module(rabbit_credential_validator_min_password_length).
+
+-include("rabbit.hrl").
+
+-behaviour(rabbit_credential_validator).
+
+%% accommodates default (localhost-only) user credentials,
+%% guest/guest
+-define(DEFAULT_MIN_LENGTH, 5).
+
+%%
+%% API
+%%
+
+-export([validate/2]).
+%% for tests
+-export([validate/3]).
+
+-spec validate(rabbit_types:username(), rabbit_types:password()) -> 'ok' | {'error', string()}.
+
+validate(Username, Password) ->
+ MinLength = case application:get_env(rabbit, credential_validator) of
+ undefined ->
+ ?DEFAULT_MIN_LENGTH;
+ {ok, Proplist} ->
+ case proplists:get_value(min_length, Proplist) of
+ undefined -> ?DEFAULT_MIN_LENGTH;
+ Value -> rabbit_data_coercion:to_integer(Value)
+ end
+ end,
+ validate(Username, Password, MinLength).
+
+
+-spec validate(rabbit_types:username(), rabbit_types:password(), integer()) -> 'ok' | {'error', string(), [any()]}.
+
+validate(_Username, Password, MinLength) ->
+ case size(Password) >= MinLength of
+ true -> ok;
+ false -> {error, rabbit_misc:format("minimum required password length is ~B", [MinLength])}
+ end.
diff --git a/src/rabbit_credential_validator_password_regexp.erl b/src/rabbit_credential_validator_password_regexp.erl
new file mode 100644
index 0000000000..b516175126
--- /dev/null
+++ b/src/rabbit_credential_validator_password_regexp.erl
@@ -0,0 +1,51 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
+%%
+
+
+%% A `rabbit_credential_validator` implementation that matches
+%% password against a pre-configured regular expression.
+-module(rabbit_credential_validator_password_regexp).
+
+-include("rabbit.hrl").
+
+-behaviour(rabbit_credential_validator).
+
+%%
+%% API
+%%
+
+-export([validate/2]).
+%% for tests
+-export([validate/3]).
+
+-spec validate(rabbit_types:username(), rabbit_types:password()) -> 'ok' | {'error', string()}.
+
+validate(Username, Password) ->
+ {ok, Proplist} = application:get_env(rabbit, credential_validator),
+ Regexp = case proplists:get_value(regexp, Proplist) of
+ undefined -> {error, "rabbit.credential_validator.regexp config key is undefined"};
+ Value -> rabbit_data_coercion:to_list(Value)
+ end,
+ validate(Username, Password, Regexp).
+
+
+-spec validate(rabbit_types:username(), rabbit_types:password(), string()) -> 'ok' | {'error', string(), [any()]}.
+
+validate(_Username, Password, Pattern) ->
+ case re:run(rabbit_data_coercion:to_list(Password), Pattern) of
+ {match, _} -> ok;
+ nomatch -> {error, "provided password does not match the validator regular expression"}
+ end.
diff --git a/src/rabbit_plugins.erl b/src/rabbit_plugins.erl
index bde4ff5388..b408b7e613 100644
--- a/src/rabbit_plugins.erl
+++ b/src/rabbit_plugins.erl
@@ -15,7 +15,7 @@
%%
-module(rabbit_plugins).
--include("rabbit.hrl").
+-include_lib("rabbit_common/include/rabbit.hrl").
-export([setup/0, active/0, read_enabled/1, list/1, list/2, dependencies/3]).
-export([ensure/1]).
diff --git a/src/rabbit_ssl.erl b/src/rabbit_ssl.erl
index ac9fb204d0..6a87d93a29 100644
--- a/src/rabbit_ssl.erl
+++ b/src/rabbit_ssl.erl
@@ -11,13 +11,11 @@
%% The Original Code is RabbitMQ.
%%
%% The Initial Developer of the Original Code is GoPivotal, Inc.
-%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
+%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved.
%%
-module(rabbit_ssl).
--include("rabbit.hrl").
-
-include_lib("public_key/include/public_key.hrl").
-export([peer_cert_issuer/1, peer_cert_subject/1, peer_cert_validity/1]).
@@ -27,15 +25,7 @@
-export_type([certificate/0]).
--type certificate() :: binary().
-
--spec peer_cert_issuer(certificate()) -> string().
--spec peer_cert_subject(certificate()) -> string().
--spec peer_cert_validity(certificate()) -> string().
--spec peer_cert_subject_items
- (certificate(), tuple()) -> [string()] | 'not_found'.
--spec peer_cert_auth_name
- (certificate()) -> binary() | 'not_found' | 'unsafe'.
+-type certificate() :: rabbit_cert_info:certificate().
%%--------------------------------------------------------------------------
%% High-level functions used by reader
@@ -43,38 +33,24 @@
%% Return a string describing the certificate's issuer.
peer_cert_issuer(Cert) ->
- cert_info(fun(#'OTPCertificate' {
- tbsCertificate = #'OTPTBSCertificate' {
- issuer = Issuer }}) ->
- format_rdn_sequence(Issuer)
- end, Cert).
+ rabbit_cert_info:issuer(Cert).
%% Return a string describing the certificate's subject, as per RFC4514.
peer_cert_subject(Cert) ->
- cert_info(fun(#'OTPCertificate' {
- tbsCertificate = #'OTPTBSCertificate' {
- subject = Subject }}) ->
- format_rdn_sequence(Subject)
- end, Cert).
+ rabbit_cert_info:subject(Cert).
%% Return the parts of the certificate's subject.
peer_cert_subject_items(Cert, Type) ->
- cert_info(fun(#'OTPCertificate' {
- tbsCertificate = #'OTPTBSCertificate' {
- subject = Subject }}) ->
- find_by_type(Type, Subject)
- end, Cert).
+ rabbit_cert_info:subject_items(Cert, Type).
%% Return a string describing the certificate's validity.
peer_cert_validity(Cert) ->
- cert_info(fun(#'OTPCertificate' {
- tbsCertificate = #'OTPTBSCertificate' {
- validity = {'Validity', Start, End} }}) ->
- rabbit_misc:format("~s - ~s", [format_asn1_value(Start),
- format_asn1_value(End)])
- end, Cert).
+ rabbit_cert_info:validity(Cert).
%% Extract a username from the certificate
+-spec peer_cert_auth_name
+ (certificate()) -> binary() | 'not_found' | 'unsafe'.
+
peer_cert_auth_name(Cert) ->
{ok, Mode} = application:get_env(rabbit, ssl_cert_login_from),
peer_cert_auth_name(Mode, Cert).
@@ -106,189 +82,3 @@ auth_config_sane() ->
"disabled, verify=~p~n", [V]),
false
end.
-
-%%--------------------------------------------------------------------------
-
-cert_info(F, Cert) ->
- F(case public_key:pkix_decode_cert(Cert, otp) of
- {ok, DecCert} -> DecCert; %%pre R14B
- DecCert -> DecCert %%R14B onwards
- end).
-
-find_by_type(Type, {rdnSequence, RDNs}) ->
- case [V || #'AttributeTypeAndValue'{type = T, value = V}
- <- lists:flatten(RDNs),
- T == Type] of
- [] -> not_found;
- L -> [format_asn1_value(V) || V <- L]
- end.
-
-%%--------------------------------------------------------------------------
-%% Formatting functions
-%%--------------------------------------------------------------------------
-
-%% Format and rdnSequence as a RFC4514 subject string.
-format_rdn_sequence({rdnSequence, Seq}) ->
- string:join(lists:reverse([format_complex_rdn(RDN) || RDN <- Seq]), ",").
-
-%% Format an RDN set.
-format_complex_rdn(RDNs) ->
- string:join([format_rdn(RDN) || RDN <- RDNs], "+").
-
-%% Format an RDN. If the type name is unknown, use the dotted decimal
-%% representation. See RFC4514, section 2.3.
-format_rdn(#'AttributeTypeAndValue'{type = T, value = V}) ->
- FV = escape_rdn_value(format_asn1_value(V)),
- Fmts = [{?'id-at-surname' , "SN"},
- {?'id-at-givenName' , "GIVENNAME"},
- {?'id-at-initials' , "INITIALS"},
- {?'id-at-generationQualifier' , "GENERATIONQUALIFIER"},
- {?'id-at-commonName' , "CN"},
- {?'id-at-localityName' , "L"},
- {?'id-at-stateOrProvinceName' , "ST"},
- {?'id-at-organizationName' , "O"},
- {?'id-at-organizationalUnitName' , "OU"},
- {?'id-at-title' , "TITLE"},
- {?'id-at-countryName' , "C"},
- {?'id-at-serialNumber' , "SERIALNUMBER"},
- {?'id-at-pseudonym' , "PSEUDONYM"},
- {?'id-domainComponent' , "DC"},
- {?'id-emailAddress' , "EMAILADDRESS"},
- {?'street-address' , "STREET"},
- {{0,9,2342,19200300,100,1,1} , "UID"}], %% Not in public_key.hrl
- case proplists:lookup(T, Fmts) of
- {_, Fmt} ->
- rabbit_misc:format(Fmt ++ "=~s", [FV]);
- none when is_tuple(T) ->
- TypeL = [rabbit_misc:format("~w", [X]) || X <- tuple_to_list(T)],
- rabbit_misc:format("~s=~s", [string:join(TypeL, "."), FV]);
- none ->
- rabbit_misc:format("~p=~s", [T, FV])
- end.
-
-%% Escape a string as per RFC4514.
-escape_rdn_value(V) ->
- escape_rdn_value(V, start).
-
-escape_rdn_value([], _) ->
- [];
-escape_rdn_value([C | S], start) when C =:= $ ; C =:= $# ->
- [$\\, C | escape_rdn_value(S, middle)];
-escape_rdn_value(S, start) ->
- escape_rdn_value(S, middle);
-escape_rdn_value([$ ], middle) ->
- [$\\, $ ];
-escape_rdn_value([C | S], middle) when C =:= $"; C =:= $+; C =:= $,; C =:= $;;
- C =:= $<; C =:= $>; C =:= $\\ ->
- [$\\, C | escape_rdn_value(S, middle)];
-escape_rdn_value([C | S], middle) when C < 32 ; C >= 126 ->
- %% Of ASCII characters only U+0000 needs escaping, but for display
- %% purposes it's handy to escape all non-printable chars. All non-ASCII
- %% characters get converted to UTF-8 sequences and then escaped. We've
- %% already got a UTF-8 sequence here, so just escape it.
- rabbit_misc:format("\\~2.16.0B", [C]) ++ escape_rdn_value(S, middle);
-escape_rdn_value([C | S], middle) ->
- [C | escape_rdn_value(S, middle)].
-
-%% Get the string representation of an OTPCertificate field.
-format_asn1_value({ST, S}) when ST =:= teletexString; ST =:= printableString;
- ST =:= universalString; ST =:= utf8String;
- ST =:= bmpString ->
- format_directory_string(ST, S);
-format_asn1_value({utcTime, [Y1, Y2, M1, M2, D1, D2, H1, H2,
- Min1, Min2, S1, S2, $Z]}) ->
- rabbit_misc:format("20~c~c-~c~c-~c~cT~c~c:~c~c:~c~cZ",
- [Y1, Y2, M1, M2, D1, D2, H1, H2, Min1, Min2, S1, S2]);
-%% We appear to get an untagged value back for an ia5string
-%% (e.g. domainComponent).
-format_asn1_value(V) when is_list(V) ->
- V;
-format_asn1_value(V) when is_binary(V) ->
- %% OTP does not decode some values when combined with an unknown
- %% type. That's probably wrong, so as a last ditch effort let's
- %% try manually decoding. 'DirectoryString' is semi-arbitrary -
- %% but it is the type which covers the various string types we
- %% handle below.
- try
- {ST, S} = public_key:der_decode('DirectoryString', V),
- format_directory_string(ST, S)
- catch _:_ ->
- rabbit_misc:format("~p", [V])
- end;
-format_asn1_value(V) ->
- rabbit_misc:format("~p", [V]).
-
-%% DirectoryString { INTEGER : maxSize } ::= CHOICE {
-%% teletexString TeletexString (SIZE (1..maxSize)),
-%% printableString PrintableString (SIZE (1..maxSize)),
-%% bmpString BMPString (SIZE (1..maxSize)),
-%% universalString UniversalString (SIZE (1..maxSize)),
-%% uTF8String UTF8String (SIZE (1..maxSize)) }
-%%
-%% Precise definitions of printable / teletexString are hard to come
-%% by. This is what I reconstructed:
-%%
-%% printableString:
-%% "intended to represent the limited character sets available to
-%% mainframe input terminals"
-%% A-Z a-z 0-9 ' ( ) + , - . / : = ? [space]
-%% http://msdn.microsoft.com/en-us/library/bb540814(v=vs.85).aspx
-%%
-%% teletexString:
-%% "a sizable volume of software in the world treats TeletexString
-%% (T61String) as a simple 8-bit string with mostly Windows Latin 1
-%% (superset of iso-8859-1) encoding"
-%% http://www.mail-archive.com/asn1@asn1.org/msg00460.html
-%%
-%% (However according to that link X.680 actually defines
-%% TeletexString in some much more involved and crazy way. I suggest
-%% we treat it as ISO-8859-1 since Erlang does not support Windows
-%% Latin 1).
-%%
-%% bmpString:
-%% UCS-2 according to RFC 3641. Hence cannot represent Unicode
-%% characters above 65535 (outside the "Basic Multilingual Plane").
-%%
-%% universalString:
-%% UCS-4 according to RFC 3641.
-%%
-%% utf8String:
-%% UTF-8 according to RFC 3641.
-%%
-%% Within Rabbit we assume UTF-8 encoding. Since printableString is a
-%% subset of ASCII it is also a subset of UTF-8. The others need
-%% converting. Fortunately since the Erlang SSL library does the
-%% decoding for us (albeit into a weird format, see below), we just
-%% need to handle encoding into UTF-8. Note also that utf8Strings come
-%% back as binary.
-%%
-%% Note for testing: the default Ubuntu configuration for openssl will
-%% only create printableString or teletexString types no matter what
-%% you do. Edit string_mask in the [req] section of
-%% /etc/ssl/openssl.cnf to change this (see comments there). You
-%% probably also need to set utf8 = yes to get it to accept UTF-8 on
-%% the command line. Also note I could not get openssl to generate a
-%% universalString.
-
-format_directory_string(printableString, S) -> S;
-format_directory_string(teletexString, S) -> utf8_list_from(S);
-format_directory_string(bmpString, S) -> utf8_list_from(S);
-format_directory_string(universalString, S) -> utf8_list_from(S);
-format_directory_string(utf8String, S) -> binary_to_list(S).
-
-utf8_list_from(S) ->
- binary_to_list(
- unicode:characters_to_binary(flatten_ssl_list(S), utf32, utf8)).
-
-%% The Erlang SSL implementation invents its own representation for
-%% non-ascii strings - looking like [97,{0,0,3,187}] (that's LATIN
-%% SMALL LETTER A followed by GREEK SMALL LETTER LAMDA). We convert
-%% this into a list of unicode characters, which we can tell
-%% unicode:characters_to_binary is utf32.
-
-flatten_ssl_list(L) -> [flatten_ssl_list_item(I) || I <- L].
-
-flatten_ssl_list_item({A, B, C, D}) ->
- A * (1 bsl 24) + B * (1 bsl 16) + C * (1 bsl 8) + D;
-flatten_ssl_list_item(N) when is_number (N) ->
- N.
diff --git a/src/rabbit_table.erl b/src/rabbit_table.erl
index 43a744d315..4a9a02e492 100644
--- a/src/rabbit_table.erl
+++ b/src/rabbit_table.erl
@@ -18,7 +18,8 @@
-export([create/0, create_local_copy/1, wait_for_replicated/1, wait/1,
force_load/0, is_present/0, is_empty/0, needs_default_data/0,
- check_schema_integrity/1, clear_ram_only_tables/0, retry_timeout/0]).
+ check_schema_integrity/1, clear_ram_only_tables/0, retry_timeout/0,
+ wait_for_replicated/0]).
-include("rabbit.hrl").
@@ -28,6 +29,7 @@
-spec create() -> 'ok'.
-spec create_local_copy('disc' | 'ram') -> 'ok'.
-spec wait_for_replicated(retry()) -> 'ok'.
+-spec wait_for_replicated() -> 'ok'.
-spec wait([atom()]) -> 'ok'.
-spec retry_timeout() -> {non_neg_integer() | infinity, non_neg_integer()}.
-spec force_load() -> 'ok'.
@@ -64,6 +66,11 @@ create_local_copy(ram) ->
create_local_copies(ram),
create_local_copy(schema, ram_copies).
+%% This arity only exists for backwards compatibility with certain
+%% plugins. See https://github.com/rabbitmq/rabbitmq-clusterer/issues/19.
+wait_for_replicated() ->
+ wait_for_replicated(false).
+
wait_for_replicated(Retry) ->
wait([Tab || {Tab, TabDef} <- definitions(),
not lists:member({local_content, true}, TabDef)], Retry).
diff --git a/src/rabbit_variable_queue.erl b/src/rabbit_variable_queue.erl
index 58f0230420..f7582a622a 100644
--- a/src/rabbit_variable_queue.erl
+++ b/src/rabbit_variable_queue.erl
@@ -436,21 +436,28 @@
%% rabbit_amqqueue_process need fairly fresh rates.
-define(MSGS_PER_RATE_CALC, 100).
-
%% we define the garbage collector threshold
-%% it needs to tune the GC calls inside `reduce_memory_use`
-%% see: rabbitmq-server-973 and `maybe_execute_gc` function
--define(DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD, 250).
--define(EXPLICIT_GC_RUN_OP_THRESHOLD,
+%% it needs to tune the `reduce_memory_use` calls. Thus, the garbage collection.
+%% see: rabbitmq-server-973 and rabbitmq-server-964
+-define(DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD, 1000).
+-define(EXPLICIT_GC_RUN_OP_THRESHOLD(Mode),
case get(explicit_gc_run_operation_threshold) of
undefined ->
- Val = rabbit_misc:get_env(rabbit, lazy_queue_explicit_gc_run_operation_threshold,
- ?DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD),
+ Val = explicit_gc_run_operation_threshold_for_mode(Mode),
put(explicit_gc_run_operation_threshold, Val),
Val;
Val -> Val
end).
+explicit_gc_run_operation_threshold_for_mode(Mode) ->
+ {Key, Fallback} = case Mode of
+ lazy -> {lazy_queue_explicit_gc_run_operation_threshold,
+ ?DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD};
+ _ -> {queue_explicit_gc_run_operation_threshold,
+ ?DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD}
+ end,
+ rabbit_misc:get_env(rabbit, Key, Fallback).
+
%%----------------------------------------------------------------------------
%% Public API
%%----------------------------------------------------------------------------
@@ -590,27 +597,27 @@ publish(Msg, MsgProps, IsDelivered, ChPid, Flow, State) ->
publish1(Msg, MsgProps, IsDelivered, ChPid, Flow,
fun maybe_write_to_disk/4,
State),
- a(reduce_memory_use(maybe_update_rates(State1))).
+ a(maybe_reduce_memory_use(maybe_update_rates(State1))).
batch_publish(Publishes, ChPid, Flow, State) ->
{ChPid, Flow, State1} =
lists:foldl(fun batch_publish1/2, {ChPid, Flow, State}, Publishes),
State2 = ui(State1),
- a(reduce_memory_use(maybe_update_rates(State2))).
+ a(maybe_reduce_memory_use(maybe_update_rates(State2))).
publish_delivered(Msg, MsgProps, ChPid, Flow, State) ->
{SeqId, State1} =
publish_delivered1(Msg, MsgProps, ChPid, Flow,
fun maybe_write_to_disk/4,
State),
- {SeqId, a(reduce_memory_use(maybe_update_rates(State1)))}.
+ {SeqId, a(maybe_reduce_memory_use(maybe_update_rates(State1)))}.
batch_publish_delivered(Publishes, ChPid, Flow, State) ->
{ChPid, Flow, SeqIds, State1} =
lists:foldl(fun batch_publish_delivered1/2,
{ChPid, Flow, [], State}, Publishes),
State2 = ui(State1),
- {lists:reverse(SeqIds), a(reduce_memory_use(maybe_update_rates(State2)))}.
+ {lists:reverse(SeqIds), a(maybe_reduce_memory_use(maybe_update_rates(State2)))}.
discard(_MsgId, _ChPid, _Flow, State) -> State.
@@ -714,7 +721,7 @@ requeue(AckTags, #vqstate { mode = default,
{Delta1, MsgIds2, State3} = delta_merge(SeqIds1, Delta, MsgIds1,
State2),
MsgCount = length(MsgIds2),
- {MsgIds2, a(reduce_memory_use(
+ {MsgIds2, a(maybe_reduce_memory_use(
maybe_update_rates(ui(
State3 #vqstate { delta = Delta1,
q3 = Q3a,
@@ -732,7 +739,7 @@ requeue(AckTags, #vqstate { mode = lazy,
{Delta1, MsgIds1, State2} = delta_merge(SeqIds, Delta, MsgIds,
State1),
MsgCount = length(MsgIds1),
- {MsgIds1, a(reduce_memory_use(
+ {MsgIds1, a(maybe_reduce_memory_use(
maybe_update_rates(ui(
State2 #vqstate { delta = Delta1,
q3 = Q3a,
@@ -782,7 +789,7 @@ set_ram_duration_target(
(TargetRamCount =/= infinity andalso
TargetRamCount1 >= TargetRamCount) of
true -> State1;
- false -> reduce_memory_use(State1)
+ false -> maybe_reduce_memory_use(State1)
end).
maybe_update_rates(State = #vqstate{ in_counter = InCount,
@@ -864,7 +871,7 @@ timeout(State = #vqstate { index_state = IndexState }) ->
handle_pre_hibernate(State = #vqstate { index_state = IndexState }) ->
State #vqstate { index_state = rabbit_queue_index:flush(IndexState) }.
-resume(State) -> a(reduce_memory_use(State)).
+resume(State) -> a(maybe_reduce_memory_use(State)).
msg_rates(#vqstate { rates = #rates { in = AvgIngressRate,
out = AvgEgressRate } }) ->
@@ -2336,12 +2343,12 @@ ifold(Fun, Acc, Its, State) ->
%% Phase changes
%%----------------------------------------------------------------------------
-maybe_execute_gc(State = #vqstate {memory_reduction_run_count = MRedRunCount}) ->
- case MRedRunCount >= ?EXPLICIT_GC_RUN_OP_THRESHOLD of
- true -> garbage_collect(),
- State#vqstate{memory_reduction_run_count = 0};
- false -> State#vqstate{memory_reduction_run_count = MRedRunCount + 1}
-
+maybe_reduce_memory_use(State = #vqstate {memory_reduction_run_count = MRedRunCount,
+ mode = Mode}) ->
+ case MRedRunCount >= ?EXPLICIT_GC_RUN_OP_THRESHOLD(Mode) of
+ true -> State1 = reduce_memory_use(State),
+ State1#vqstate{memory_reduction_run_count = 0};
+ false -> State#vqstate{memory_reduction_run_count = MRedRunCount + 1}
end.
reduce_memory_use(State = #vqstate { target_ram_count = infinity }) ->
@@ -2356,7 +2363,6 @@ reduce_memory_use(State = #vqstate {
out = AvgEgress,
ack_in = AvgAckIngress,
ack_out = AvgAckEgress } }) ->
-
State1 = #vqstate { q2 = Q2, q3 = Q3 } =
case chunk_size(RamMsgCount + gb_trees:size(RPA), TargetRamCount) of
0 -> State;
@@ -2416,7 +2422,8 @@ reduce_memory_use(State = #vqstate {
S2 ->
push_betas_to_deltas(S2, State1)
end,
- maybe_execute_gc(State3).
+ garbage_collect(),
+ State3.
limit_ram_acks(0, State) ->
{0, ui(State)};
diff --git a/test/credential_validation_SUITE.erl b/test/credential_validation_SUITE.erl
new file mode 100644
index 0000000000..3ed2e832bd
--- /dev/null
+++ b/test/credential_validation_SUITE.erl
@@ -0,0 +1,275 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
+%%
+
+-module(credential_validation_SUITE).
+
+-compile(export_all).
+-include_lib("proper/include/proper.hrl").
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+
+all() ->
+ [
+ {group, unit},
+ {group, integration}
+ ].
+
+groups() ->
+ [
+ {integration, [], [
+ min_length_integration_fails
+ , regexp_integration_fails
+ , min_length_integration_succeeds
+ , regexp_integration_succeeds
+ , min_length_change_password_integration_fails
+ , regexp_change_password_integration_fails
+ , min_length_change_password_integration_succeeds
+ , regexp_change_password_integration_succeeds
+ ]},
+ {unit, [parallel], [
+ basic_unconditionally_accepting_succeeds,
+ min_length_fails,
+ min_length_succeeds,
+ min_length_proper_fails,
+ min_length_proper_succeeds,
+ regexp_fails,
+ regexp_succeeds,
+ regexp_proper_fails,
+ regexp_proper_succeeds
+ ]}
+].
+
+suite() ->
+ [
+ {timetrap, {minutes, 4}}
+ ].
+
+%%
+%% Setup/teardown
+%%
+
+init_per_suite(Config) ->
+ rabbit_ct_helpers:log_environment(),
+ rabbit_ct_helpers:run_setup_steps(Config).
+
+end_per_suite(Config) ->
+ rabbit_ct_helpers:run_teardown_steps(Config).
+
+init_per_group(integration, Config) ->
+ Suffix = rabbit_ct_helpers:testcase_absname(Config, "", "-"),
+ Config1 = rabbit_ct_helpers:set_config(Config, [
+ {rmq_nodes_count, 1},
+ {rmq_nodename_suffix, Suffix}
+ ]),
+ rabbit_ct_helpers:run_steps(Config1,
+ rabbit_ct_broker_helpers:setup_steps());
+
+init_per_group(unit, Config) ->
+ Config.
+
+end_per_group(integration, Config) ->
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, accept_everything),
+ rabbit_ct_helpers:run_steps(Config,
+ rabbit_ct_broker_helpers:teardown_steps());
+end_per_group(unit, Config) ->
+ Config.
+
+-define(USERNAME, <<"abc">>).
+
+init_per_testcase(Testcase, Config) ->
+ rabbit_ct_helpers:testcase_started(Config, Testcase).
+
+end_per_testcase(Testcase, Config) ->
+ rabbit_ct_helpers:testcase_finished(Config, Testcase).
+
+%%
+%% Test Cases
+%%
+
+basic_unconditionally_accepting_succeeds(_Config) ->
+ F = fun rabbit_credential_validator_accept_everything:validate/2,
+
+ Pwd1 = crypto:strong_rand_bytes(1),
+ ?assertEqual(ok, F(?USERNAME, Pwd1)),
+ Pwd2 = crypto:strong_rand_bytes(5),
+ ?assertEqual(ok, F(?USERNAME, Pwd2)),
+ Pwd3 = crypto:strong_rand_bytes(10),
+ ?assertEqual(ok, F(?USERNAME, Pwd3)),
+ Pwd4 = crypto:strong_rand_bytes(50),
+ ?assertEqual(ok, F(?USERNAME, Pwd4)),
+ Pwd5 = crypto:strong_rand_bytes(100),
+ ?assertEqual(ok, F(?USERNAME, Pwd5)),
+ Pwd6 = crypto:strong_rand_bytes(1000),
+ ?assertEqual(ok, F(?USERNAME, Pwd6)).
+
+min_length_fails(_Config) ->
+ F = fun rabbit_credential_validator_min_password_length:validate/3,
+
+ Pwd1 = crypto:strong_rand_bytes(1),
+ ?assertMatch({error, _}, F(?USERNAME, Pwd1, 5)),
+ Pwd2 = crypto:strong_rand_bytes(5),
+ ?assertMatch({error, _}, F(?USERNAME, Pwd2, 6)),
+ Pwd3 = crypto:strong_rand_bytes(10),
+ ?assertMatch({error, _}, F(?USERNAME, Pwd3, 15)),
+ Pwd4 = crypto:strong_rand_bytes(50),
+ ?assertMatch({error, _}, F(?USERNAME, Pwd4, 60)).
+
+min_length_succeeds(_Config) ->
+ F = fun rabbit_credential_validator_min_password_length:validate/3,
+
+ ?assertEqual(ok, F(?USERNAME, crypto:strong_rand_bytes(1), 1)),
+ ?assertEqual(ok, F(?USERNAME, crypto:strong_rand_bytes(6), 6)),
+ ?assertEqual(ok, F(?USERNAME, crypto:strong_rand_bytes(7), 6)),
+ ?assertEqual(ok, F(?USERNAME, crypto:strong_rand_bytes(20), 20)),
+ ?assertEqual(ok, F(?USERNAME, crypto:strong_rand_bytes(40), 30)),
+ ?assertEqual(ok, F(?USERNAME, crypto:strong_rand_bytes(50), 50)).
+
+min_length_proper_fails(_Config) ->
+ rabbit_ct_proper_helpers:run_proper(fun prop_min_length_fails_validation/0, [], 500).
+
+min_length_proper_succeeds(_Config) ->
+ rabbit_ct_proper_helpers:run_proper(fun prop_min_length_passes_validation/0, [], 500).
+
+regexp_fails(_Config) ->
+ F = fun rabbit_credential_validator_password_regexp:validate/3,
+
+ ?assertMatch({error, _}, F(?USERNAME, <<"abc">>, "^xyz")),
+ ?assertMatch({error, _}, F(?USERNAME, <<"abcdef">>, "^xyz")),
+ ?assertMatch({error, _}, F(?USERNAME, <<"abcxyz">>, "^abc\\d+")).
+
+regexp_succeeds(_Config) ->
+ F = fun rabbit_credential_validator_password_regexp:validate/3,
+
+ ?assertEqual(ok, F(?USERNAME, <<"abc">>, "^abc")),
+ ?assertEqual(ok, F(?USERNAME, <<"abcdef">>, "^abc")),
+ ?assertEqual(ok, F(?USERNAME, <<"abc123">>, "^abc\\d+")).
+
+regexp_proper_fails(_Config) ->
+ rabbit_ct_proper_helpers:run_proper(fun prop_regexp_fails_validation/0, [], 500).
+
+regexp_proper_succeeds(_Config) ->
+ rabbit_ct_proper_helpers:run_proper(fun prop_regexp_passes_validation/0, [], 500).
+
+min_length_integration_fails(Config) ->
+ rabbit_ct_broker_helpers:delete_user(Config, ?USERNAME),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, min_length, 50),
+ ?assertMatch(rabbit_credential_validator_min_password_length, validator_backend(Config)),
+ ?assertMatch({error, "minimum required password length is 50"},
+ rabbit_ct_broker_helpers:add_user(Config, ?USERNAME, <<"_">>)).
+
+regexp_integration_fails(Config) ->
+ rabbit_ct_broker_helpers:delete_user(Config, ?USERNAME),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, regexp),
+ ?assertMatch(rabbit_credential_validator_password_regexp, validator_backend(Config)),
+ ?assertMatch({error, _}, rabbit_ct_broker_helpers:add_user(Config, ?USERNAME, <<"_">>)).
+
+min_length_integration_succeeds(Config) ->
+ rabbit_ct_broker_helpers:delete_user(Config, ?USERNAME),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, min_length, 5),
+ ?assertMatch(rabbit_credential_validator_min_password_length, validator_backend(Config)),
+ ?assertMatch(ok, rabbit_ct_broker_helpers:add_user(Config, ?USERNAME, <<"abcdefghi">>)).
+
+regexp_integration_succeeds(Config) ->
+ rabbit_ct_broker_helpers:delete_user(Config, ?USERNAME),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, regexp),
+ ?assertMatch(rabbit_credential_validator_password_regexp, validator_backend(Config)),
+ ?assertMatch(ok, rabbit_ct_broker_helpers:add_user(Config, ?USERNAME, <<"xyz12345678901">>)).
+
+min_length_change_password_integration_fails(Config) ->
+ rabbit_ct_broker_helpers:delete_user(Config, ?USERNAME),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, accept_everything),
+ rabbit_ct_broker_helpers:add_user(Config, ?USERNAME, <<"abcdefghi">>),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, min_length, 50),
+ ?assertMatch(rabbit_credential_validator_min_password_length, validator_backend(Config)),
+ ?assertMatch({error, "minimum required password length is 50"},
+ rabbit_ct_broker_helpers:change_password(Config, ?USERNAME, <<"_">>)).
+
+regexp_change_password_integration_fails(Config) ->
+ rabbit_ct_broker_helpers:delete_user(Config, ?USERNAME),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, accept_everything),
+ rabbit_ct_broker_helpers:add_user(Config, ?USERNAME, <<"abcdefghi">>),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, regexp),
+ ?assertMatch(rabbit_credential_validator_password_regexp, validator_backend(Config)),
+ ?assertMatch({error, _}, rabbit_ct_broker_helpers:change_password(Config, ?USERNAME, <<"_">>)).
+
+min_length_change_password_integration_succeeds(Config) ->
+ rabbit_ct_broker_helpers:delete_user(Config, ?USERNAME),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, accept_everything),
+ rabbit_ct_broker_helpers:add_user(Config, ?USERNAME, <<"abcdefghi">>),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, min_length, 5),
+ ?assertMatch(rabbit_credential_validator_min_password_length, validator_backend(Config)),
+ ?assertMatch(ok, rabbit_ct_broker_helpers:change_password(Config, ?USERNAME, <<"abcdefghi">>)).
+
+regexp_change_password_integration_succeeds(Config) ->
+ rabbit_ct_broker_helpers:delete_user(Config, ?USERNAME),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, accept_everything),
+ rabbit_ct_broker_helpers:add_user(Config, ?USERNAME, <<"abcdefghi">>),
+ rabbit_ct_broker_helpers:switch_credential_validator(Config, regexp),
+ ?assertMatch(rabbit_credential_validator_password_regexp, validator_backend(Config)),
+ ?assertMatch(ok, rabbit_ct_broker_helpers:change_password(Config, ?USERNAME, <<"xyz12345678901">>)).
+
+%%
+%% PropEr
+%%
+
+prop_min_length_fails_validation() ->
+ N = 5,
+ F = fun rabbit_credential_validator_min_password_length:validate/3,
+ ?FORALL(Val, binary(N),
+ ?FORALL(Length, choose(N + 1, 100),
+ failed_validation(F(?USERNAME, Val, Length + 1)))).
+
+prop_min_length_passes_validation() ->
+ N = 20,
+ F = fun rabbit_credential_validator_min_password_length:validate/3,
+ ?FORALL(Val, binary(N),
+ ?FORALL(Length, choose(1, N - 1),
+ passed_validation(F(?USERNAME, Val, Length)))).
+
+prop_regexp_fails_validation() ->
+ N = 5,
+ F = fun rabbit_credential_validator_password_regexp:validate/3,
+ ?FORALL(Val, binary(N),
+ ?FORALL(Length, choose(N + 1, 100),
+ failed_validation(F(?USERNAME, Val, regexp_that_requires_length_of_at_least(Length + 1))))).
+
+prop_regexp_passes_validation() ->
+ N = 5,
+ F = fun rabbit_credential_validator_password_regexp:validate/3,
+ ?FORALL(Val, binary(N),
+ passed_validation(F(?USERNAME, Val, regexp_that_requires_length_of_at_most(size(Val) + 1)))).
+
+%%
+%% Helpers
+%%
+
+passed_validation(ok) ->
+ true;
+passed_validation({error, _}) ->
+ false.
+
+failed_validation(Result) ->
+ not passed_validation(Result).
+
+regexp_that_requires_length_of_at_least(N) when is_integer(N) ->
+ rabbit_misc:format("^[a-zA-Z0-9]{~p,~p}", [N, N + 10]).
+
+regexp_that_requires_length_of_at_most(N) when is_integer(N) ->
+ rabbit_misc:format("^[a-zA-Z0-9]{0,~p}", [N]).
+
+validator_backend(Config) ->
+ rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_credential_validation, backend, []).
+
diff --git a/test/dynamic_ha_SUITE.erl b/test/dynamic_ha_SUITE.erl
index 502e3a7e86..a7c7eec861 100644
--- a/test/dynamic_ha_SUITE.erl
+++ b/test/dynamic_ha_SUITE.erl
@@ -65,8 +65,8 @@ groups() ->
nodes_policy_should_pick_master_from_its_params
% FIXME: Re-enable those tests when the know issues are
% fixed.
- %failing_random_policies,
- %random_policy
+ % failing_random_policies,
+ % random_policy
]}
]}
].
@@ -124,17 +124,18 @@ change_policy(Config) ->
%% When we first declare a queue with no policy, it's not HA.
amqp_channel:call(ACh, #'queue.declare'{queue = ?QNAME}),
+ timer:sleep(100),
assert_slaves(A, ?QNAME, {A, ''}),
%% Give it policy "all", it becomes HA and gets all mirrors
rabbit_ct_broker_helpers:set_ha_policy(Config, A, ?POLICY, <<"all">>),
- assert_slaves(A, ?QNAME, {A, [B, C]}),
+ assert_slaves(A, ?QNAME, {A, [B, C]}, [{A, []}, {A, [B]}, {A, [C]}]),
%% Give it policy "nodes", it gets specific mirrors
rabbit_ct_broker_helpers:set_ha_policy(Config, A, ?POLICY,
{<<"nodes">>, [rabbit_misc:atom_to_binary(A),
rabbit_misc:atom_to_binary(B)]}),
- assert_slaves(A, ?QNAME, {A, [B]}),
+ assert_slaves(A, ?QNAME, {A, [B]}, [{A, [B, C]}]),
%% Now explicitly change the mirrors
rabbit_ct_broker_helpers:set_ha_policy(Config, A, ?POLICY,
@@ -150,7 +151,7 @@ change_policy(Config) ->
rabbit_ct_broker_helpers:set_ha_policy(Config, A, ?POLICY,
{<<"nodes">>, [rabbit_misc:atom_to_binary(B),
rabbit_misc:atom_to_binary(C)]}),
- assert_slaves(A, ?QNAME, {A, [B, C]}, [{A, [B]}, {A, [C]}]),
+ assert_slaves(A, ?QNAME, {B, [C]}, [{A, []}, {A, [B]}, {A, [C]}, {A, [B, C]}]),
ok.
@@ -166,15 +167,15 @@ change_cluster(Config) ->
%% Give it policy exactly 4, it should mirror to all 3 nodes
rabbit_ct_broker_helpers:set_ha_policy(Config, A, ?POLICY,
{<<"exactly">>, 4}),
- assert_slaves(A, ?QNAME, {A, [B, C]}),
+ assert_slaves(A, ?QNAME, {A, [B, C]}, [{A, []}, {A, [B]}, {A, [C]}]),
%% Add D and E, D joins in
rabbit_ct_broker_helpers:cluster_nodes(Config, [A, D, E]),
- assert_slaves(A, ?QNAME, {A, [B, C, D]}),
+ assert_slaves(A, ?QNAME, {A, [B, C, D]}, [{A, [B, C]}]),
%% Remove D, E joins in
rabbit_ct_broker_helpers:stop_node(Config, D),
- assert_slaves(A, ?QNAME, {A, [B, C, E]}),
+ assert_slaves(A, ?QNAME, {A, [B, C, E]}, [{A, [B, C]}]),
ok.
@@ -343,15 +344,18 @@ assert_slaves0(RPCNode, QName, {ExpMNode, ExpSNodes}, PermittedIntermediate) ->
%% just wait - of course this means if something does not
%% change when expected then we time out the test which is
%% a bit tedious
- case [found || {PermMNode, PermSNodes} <- PermittedIntermediate,
+ case [{PermMNode, PermSNodes} || {PermMNode, PermSNodes} <- PermittedIntermediate,
PermMNode =:= ActMNode,
equal_list(PermSNodes, ActSNodes)] of
[] -> ct:fail("Expected ~p / ~p, got ~p / ~p~nat ~p~n",
[ExpMNode, ExpSNodes, ActMNode, ActSNodes,
get_stacktrace()]);
- _ -> timer:sleep(100),
- assert_slaves0(RPCNode, QName, {ExpMNode, ExpSNodes},
- PermittedIntermediate)
+ State ->
+ ct:pal("Waiting to leave state ~p~n Waiting for ~p~n",
+ [State, {ExpMNode, ExpSNodes}]),
+ timer:sleep(100),
+ assert_slaves0(RPCNode, QName, {ExpMNode, ExpSNodes},
+ PermittedIntermediate)
end;
true ->
put(previous_exp_m_node, ExpMNode),
diff --git a/test/unit_inbroker_SUITE.erl b/test/unit_inbroker_SUITE.erl
index f80f83c391..9d0b84e733 100644
--- a/test/unit_inbroker_SUITE.erl
+++ b/test/unit_inbroker_SUITE.erl
@@ -250,9 +250,21 @@ orelse Group =:= backing_queue_embed_limit_1024 ->
end_per_group1(_, Config) ->
Config.
+init_per_testcase(Testcase, Config) when Testcase == variable_queue_requeue;
+ Testcase == variable_queue_fold ->
+ ok = rabbit_ct_broker_helpers:rpc(
+ Config, 0, application, set_env,
+ [rabbit, queue_explicit_gc_run_operation_threshold, 0]),
+ rabbit_ct_helpers:testcase_started(Config, Testcase);
init_per_testcase(Testcase, Config) ->
rabbit_ct_helpers:testcase_started(Config, Testcase).
+end_per_testcase(Testcase, Config) when Testcase == variable_queue_requeue;
+ Testcase == variable_queue_fold ->
+ ok = rabbit_ct_broker_helpers:rpc(
+ Config, 0, application, set_env,
+ [rabbit, queue_explicit_gc_run_operation_threshold, 1000]),
+ rabbit_ct_helpers:testcase_finished(Config, Testcase);
end_per_testcase(Testcase, Config) ->
rabbit_ct_helpers:testcase_finished(Config, Testcase).
@@ -1679,24 +1691,18 @@ check_variable_queue_status(VQ0, Props) ->
%% ---------------------------------------------------------------------------
credit_flow_settings(Config) ->
- passed = rabbit_ct_broker_helpers:rpc(Config, 0,
+ rabbit_ct_broker_helpers:rpc(Config, 0,
?MODULE, credit_flow_settings1, [Config]).
credit_flow_settings1(_Config) ->
- %% default values
- passed = test_proc(200, 100),
-
- application:set_env(rabbit, credit_flow_default_credit, {100, 300}),
- passed = test_proc(100, 300),
-
- application:unset_env(rabbit, credit_flow_default_credit),
-
- % back to defaults
- passed = test_proc(200, 100),
+ passed = test_proc(400, 200, {400, 200}),
+ passed = test_proc(600, 300),
passed.
test_proc(InitialCredit, MoreCreditAfter) ->
- Pid = spawn(fun dummy/0),
+ test_proc(InitialCredit, MoreCreditAfter, {InitialCredit, MoreCreditAfter}).
+test_proc(InitialCredit, MoreCreditAfter, Settings) ->
+ Pid = spawn(?MODULE, dummy, [Settings]),
Pid ! {credit, self()},
{InitialCredit, MoreCreditAfter} =
receive
@@ -1704,13 +1710,13 @@ test_proc(InitialCredit, MoreCreditAfter) ->
end,
passed.
-dummy() ->
+dummy(Settings) ->
credit_flow:send(self()),
receive
{credit, From} ->
- From ! {credit, get(credit_flow_default_credit)};
+ From ! {credit, Settings};
_ ->
- dummy()
+ dummy(Settings)
end.
%% -------------------------------------------------------------------
diff --git a/test/worker_pool_SUITE.erl b/test/worker_pool_SUITE.erl
index 7eb4d6fd04..9b6b0721a2 100644
--- a/test/worker_pool_SUITE.erl
+++ b/test/worker_pool_SUITE.erl
@@ -41,7 +41,7 @@ end_per_testcase(_, Config) ->
unlink(Pool),
exit(Pool, kill).
-run_code_synchronously(Config) ->
+run_code_synchronously(_) ->
Self = self(),
Test = make_ref(),
Sleep = 200,
@@ -63,7 +63,7 @@ run_code_synchronously(Config) ->
% Worker is a separate process
true = (Self /= Result).
-run_code_asynchronously(Config) ->
+run_code_asynchronously(_) ->
Self = self(),
Test = make_ref(),
Sleep = 200,
@@ -84,7 +84,7 @@ run_code_asynchronously(Config) ->
% Worker is a separate process
true = (Self /= Result).
-set_timeout(Config) ->
+set_timeout(_) ->
Self = self(),
Test = make_ref(),
Worker = worker_pool:submit(?POOL_NAME,
@@ -112,7 +112,7 @@ set_timeout(Config) ->
end.
-cancel_timeout(Config) ->
+cancel_timeout(_) ->
Self = self(),
Test = make_ref(),
Worker = worker_pool:submit(?POOL_NAME,
@@ -146,7 +146,7 @@ cancel_timeout(Config) ->
after 0 -> ok
end.
-cancel_timeout_by_setting(Config) ->
+cancel_timeout_by_setting(_) ->
Self = self(),
Test = make_ref(),
Worker = worker_pool:submit(?POOL_NAME,
@@ -186,8 +186,3 @@ cancel_timeout_by_setting(Config) ->
receive {hello_reset, Worker, Test} -> ok
after 1000 -> exit(timeout_is_late)
end.
-
-
-
-
-