diff --git a/deps/rabbit/priv/schema/rabbit.schema b/deps/rabbit/priv/schema/rabbit.schema index 07624a055f85..4d10cb206aad 100644 --- a/deps/rabbit/priv/schema/rabbit.schema +++ b/deps/rabbit/priv/schema/rabbit.schema @@ -229,7 +229,12 @@ end}. [{datatype, {enum, [true, false]}}]}. {mapping, "definitions.tls.password", "rabbit.definitions.ssl_options.password", - [{datatype, string}]}. + [{datatype, [tagged_binary, binary]}]}. + +{translation, "rabbit.definitions.ssl_options.password", +fun(Conf) -> + rabbit_cuttlefish:optionally_tagged_string("definitions.tls.password", Conf) +end}. {mapping, "definitions.tls.secure_renegotiate", "rabbit.definitions.ssl_options.secure_renegotiate", [{datatype, {enum, [true, false]}}]}. @@ -395,7 +400,12 @@ end}. [{datatype, {enum, [true, false]}}]}. {mapping, "ssl_options.password", "rabbit.ssl_options.password", - [{datatype, string}]}. + [{datatype, [tagged_binary, binary]}]}. + +{translation, "rabbit.ssl_options.password", +fun(Conf) -> + rabbit_cuttlefish:optionally_tagged_binary("ssl_options.password", Conf) +end}. {mapping, "ssl_options.psk_identity", "rabbit.ssl_options.psk_identity", [{datatype, string}]}. @@ -656,12 +666,12 @@ fun(Conf) -> end}. {mapping, "default_pass", "rabbit.default_pass", [ - {datatype, string} + {datatype, [tagged_binary, binary]} ]}. {translation, "rabbit.default_pass", fun(Conf) -> - list_to_binary(cuttlefish:conf_get("default_pass", Conf)) + rabbit_cuttlefish:optionally_tagged_binary("default_pass", Conf) end}. {mapping, "default_permissions.configure", "rabbit.default_permissions", [ @@ -696,7 +706,7 @@ end}. ]}. {mapping, "default_users.$name.password", "rabbit.default_users", [ - {datatype, string} + {datatype, [tagged_binary, binary]} ]}. {mapping, "default_users.$name.configure", "rabbit.default_users", [ diff --git a/deps/rabbit/src/rabbit_cuttlefish.erl b/deps/rabbit/src/rabbit_cuttlefish.erl index 18dbc282d46f..f43b4a1f4745 100644 --- a/deps/rabbit/src/rabbit_cuttlefish.erl +++ b/deps/rabbit/src/rabbit_cuttlefish.erl @@ -9,7 +9,10 @@ -export([ aggregate_props/2, - aggregate_props/3 + aggregate_props/3, + + optionally_tagged_binary/2, + optionally_tagged_string/2 ]). -type keyed_props() :: [{binary(), [{binary(), any()}]}]. @@ -41,3 +44,25 @@ aggregate_props(Conf, Prefix, KeyFun) -> FlatList ) ). + +optionally_tagged_binary(Key, Conf) -> + case cuttlefish:conf_get(Key, Conf) of + undefined -> cuttlefish:unset(); + {encrypted, Bin} when is_binary(Bin) -> {encrypted, Bin}; + {_, Bin} when is_binary(Bin) -> {encrypted, Bin}; + {encrypted, Str} when is_list(Str) -> {encrypted, list_to_binary(Str)}; + {_, Str} when is_list(Str) -> {encrypted, list_to_binary(Str)}; + Bin when is_binary(Bin) -> Bin; + Str when is_list(Str) -> list_to_binary(Str) + end. + +optionally_tagged_string(Key, Conf) -> + case cuttlefish:conf_get(Key, Conf) of + undefined -> cuttlefish:unset(); + {encrypted, Str} when is_list(Str) -> {encrypted, Str}; + {_, Str} when is_list(Str) -> {encrypted, Str}; + {encrypted, Bin} when is_binary(Bin) -> {encrypted, binary_to_list(Bin)}; + {_, Bin} when is_binary(Bin) -> {encrypted, binary_to_list(Bin)}; + Str when is_list(Str) -> Str; + Bin when is_binary(Bin) -> binary_to_list(Bin) + end. \ No newline at end of file diff --git a/deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets b/deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets index 247dd0f92f14..1a1b416e90e9 100644 --- a/deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets +++ b/deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets @@ -182,7 +182,7 @@ ssl_options.fail_if_no_peer_cert = true", [{rabbit, [{default_users, [ {<<"a">>, [{<<"vhost_pattern">>, "banana"}, {<<"tags">>, [administrator, operator]}, - {<<"password">>, "SECRET"}, + {<<"password">>, <<"SECRET">>}, {<<"read">>, ".*"}]}]}]}], []}, @@ -510,7 +510,7 @@ tcp_listen_options.exit_on_close = false", [{cacertfile,"test/config_schema_SUITE_data/certs/cacert.pem"}, {certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, {keyfile,"test/config_schema_SUITE_data/certs/key.pem"}, - {password,"t0p$3kRe7"}]}]}], + {password,<<"t0p$3kRe7">>}]}]}], []}, {ssl_options_tls_ver_old, "listeners.ssl.1 = 5671 diff --git a/deps/rabbitmq_auth_backend_http/priv/schema/rabbitmq_auth_backend_http.schema b/deps/rabbitmq_auth_backend_http/priv/schema/rabbitmq_auth_backend_http.schema index 150770ce2c18..b50013fb1651 100644 --- a/deps/rabbitmq_auth_backend_http/priv/schema/rabbitmq_auth_backend_http.schema +++ b/deps/rabbitmq_auth_backend_http/priv/schema/rabbitmq_auth_backend_http.schema @@ -116,7 +116,7 @@ end}. [{datatype, {enum, [true, false]}}]}. {mapping, "auth_http.ssl_options.password", "rabbitmq_auth_backend_http.ssl_options.password", - [{datatype, string}]}. + [{datatype, [tagged_binary, binary]}]}. {mapping, "auth_http.ssl_options.psk_identity", "rabbitmq_auth_backend_http.ssl_options.psk_identity", [{datatype, string}]}. diff --git a/deps/rabbitmq_auth_backend_http/test/config_schema_SUITE_data/rabbitmq_auth_backend_http.snippets b/deps/rabbitmq_auth_backend_http/test/config_schema_SUITE_data/rabbitmq_auth_backend_http.snippets index 9cd2ade9cb24..7d94d78bbc16 100644 --- a/deps/rabbitmq_auth_backend_http/test/config_schema_SUITE_data/rabbitmq_auth_backend_http.snippets +++ b/deps/rabbitmq_auth_backend_http/test/config_schema_SUITE_data/rabbitmq_auth_backend_http.snippets @@ -78,7 +78,7 @@ [{cacertfile,"test/config_schema_SUITE_data/certs/invalid_cacert.pem"}, {certfile,"test/config_schema_SUITE_data/certs/invalid_cert.pem"}, {keyfile,"test/config_schema_SUITE_data/certs/invalid_key.pem"}, - {password,"t0p$3kRe7"}]}]}], + {password,<<"t0p$3kRe7">>}]}]}], []}, {ssl_options_tls_versions, "auth_http.ssl_options.cacertfile = test/config_schema_SUITE_data/certs/invalid_cacert.pem diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decode_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decode_command.ex index 9f4211d89491..da124ae55564 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decode_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decode_command.ex @@ -86,6 +86,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do {:ok, result} catch _, _ -> + IO.inspect(__STACKTRACE__) {:error, "Failed to decrypt the value. Things to check: is the passphrase correct? Are the cipher and hash algorithms the same as those used for encryption?"} end @@ -109,6 +110,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do {:ok, result} catch _, _ -> + IO.inspect(__STACKTRACE__) {:error, "Failed to decrypt the value. Things to check: is the passphrase correct? Are the cipher and hash algorithms the same as those used for encryption?"} end @@ -117,7 +119,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do def formatter(), do: RabbitMQ.CLI.Formatters.Erlang def banner(_, _) do - "Decrypting value..." + "Decrypting an advanced.config (Erlang term) value..." end def usage, @@ -125,7 +127,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do def usage_additional() do [ - ["", "config value to decode"], + ["", "advanced.config (Erlang term) value to decode"], ["", "passphrase to use with the config value encryption key"], ["--cipher ", "cipher suite to use"], ["--hash ", "hashing function to use"], @@ -141,7 +143,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do def help_section(), do: :configuration - def description(), do: "Decrypts an encrypted configuration value" + def description(), do: "Decrypts an encrypted advanced.config value" # # Implementation diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decrypt_conf_value_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decrypt_conf_value_command.ex new file mode 100644 index 000000000000..6ac5958a96a1 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decrypt_conf_value_command.ex @@ -0,0 +1,172 @@ +## 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-2023 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +alias RabbitMQ.CLI.Core.Helpers + +defmodule RabbitMQ.CLI.Ctl.Commands.DecryptConfValueCommand do + alias RabbitMQ.CLI.Core.{DocGuide, Input} + + @behaviour RabbitMQ.CLI.CommandBehaviour + use RabbitMQ.CLI.DefaultOutput + + def switches() do + [ + cipher: :string, + hash: :string, + iterations: :integer + ] + end + + @atomized_keys [:cipher, :hash] + @prefix "encrypted:" + + def distribution(_), do: :none + + def merge_defaults(args, opts) do + with_defaults = + Map.merge( + %{ + cipher: :rabbit_pbe.default_cipher(), + hash: :rabbit_pbe.default_hash(), + iterations: :rabbit_pbe.default_iterations() + }, + opts + ) + + {args, Helpers.atomize_values(with_defaults, @atomized_keys)} + end + + def validate(args, _) when length(args) < 1 do + {:validation_failure, {:not_enough_args, "Please provide a value to decode and a passphrase"}} + end + + def validate(args, _) when length(args) > 2 do + {:validation_failure, :too_many_args} + end + + def validate(_args, opts) do + case {supports_cipher(opts.cipher), supports_hash(opts.hash), opts.iterations > 0} do + {false, _, _} -> + {:validation_failure, {:bad_argument, "The requested cipher is not supported"}} + + {_, false, _} -> + {:validation_failure, {:bad_argument, "The requested hash is not supported"}} + + {_, _, false} -> + {:validation_failure, + {:bad_argument, + "The requested number of iterations is incorrect (must be a positive integer)"}} + + {true, true, true} -> + :ok + end + end + + def run([value], %{cipher: cipher, hash: hash, iterations: iterations} = opts) do + case Input.consume_single_line_string_with_prompt("Passphrase: ", opts) do + :eof -> + {:error, :not_enough_args} + + passphrase -> + try do + term_value = Helpers.evaluate_input_as_term(value) + + term_to_decrypt = + case term_value do + prefixed_val when is_bitstring(prefixed_val) or is_list(prefixed_val) -> + tag_input_value_with_encrypted(prefixed_val) + + {:encrypted, _} = encrypted -> + encrypted + + _ -> + {:encrypted, term_value} + end + + result = :rabbit_pbe.decrypt_term(cipher, hash, iterations, passphrase, term_to_decrypt) + {:ok, result} + catch + _, _ -> + IO.inspect(__STACKTRACE__) + {:error, + "Failed to decrypt the value. Things to check: is the passphrase correct? Are the cipher and hash algorithms the same as those used for encryption?"} + end + end + end + + def run([value, passphrase], %{cipher: cipher, hash: hash, iterations: iterations}) do + try do + term_value = Helpers.evaluate_input_as_term(value) + + term_to_decrypt = + case term_value do + prefixed_val when is_bitstring(prefixed_val) or is_list(prefixed_val) -> + tag_input_value_with_encrypted(prefixed_val) + + {:encrypted, _} = encrypted -> + encrypted + + _ -> + {:encrypted, term_value} + end + + result = :rabbit_pbe.decrypt_term(cipher, hash, iterations, passphrase, term_to_decrypt) + {:ok, result} + catch + _, _ -> + IO.inspect(__STACKTRACE__) + {:error, + "Failed to decrypt the value. Things to check: is the passphrase correct? Are the cipher and hash algorithms the same as those used for encryption?"} + end + end + + def formatter(), do: RabbitMQ.CLI.Formatters.Erlang + + def banner(_, _) do + "Decrypting a rabbitmq.conf string value..." + end + + def usage, + do: "decrypt_conf_value value passphrase [--cipher ] [--hash ] [--iterations ]" + + def usage_additional() do + [ + ["", "a double-quoted rabbitmq.conf string value to decode"], + ["", "passphrase to use with the config value encryption key"], + ["--cipher ", "cipher suite to use"], + ["--hash ", "hashing function to use"], + ["--iterations ", "number of iteration to apply"] + ] + end + + def usage_doc_guides() do + [ + DocGuide.configuration() + ] + end + + def help_section(), do: :configuration + + def description(), do: "Decrypts an encrypted configuration value" + + # + # Implementation + # + + defp supports_cipher(cipher), do: Enum.member?(:rabbit_pbe.supported_ciphers(), cipher) + + defp supports_hash(hash), do: Enum.member?(:rabbit_pbe.supported_hashes(), hash) + + defp tag_input_value_with_encrypted(value) when is_bitstring(value) or is_list(value) do + bin_val = :rabbit_data_coercion.to_binary(value) + untagged_val = String.replace_prefix(bin_val, @prefix, "") + + {:encrypted, untagged_val} + end + defp tag_input_value_with_encrypted(value) do + {:encrypted, value} + end +end diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/encode_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/encode_command.ex index ae69e44b72d0..8eb43e688c91 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/encode_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/encode_command.ex @@ -77,6 +77,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do {:ok, result} catch _, _ -> + IO.inspect(__STACKTRACE__) {:error, "Error during cipher operation"} end end @@ -99,6 +100,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do {:ok, result} catch _, _ -> + IO.inspect(__STACKTRACE__) {:error, "Error during cipher operation"} end end @@ -115,6 +117,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do {:ok, result} catch _, _ -> + IO.inspect(__STACKTRACE__) {:error, "Error during cipher operation"} end end @@ -122,7 +125,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do def formatter(), do: RabbitMQ.CLI.Formatters.Erlang def banner(_, _) do - "Encrypting value ..." + "Encrypting value to be used in advanced.config..." end def usage, @@ -130,7 +133,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do def usage_additional() do [ - ["", "config value to encode"], + ["", "value to encode, to be used in advanced.config"], ["", "passphrase to use with the config value encryption key"], ["--cipher ", "cipher suite to use"], ["--hash ", "hashing function to use"], @@ -146,7 +149,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do def help_section(), do: :configuration - def description(), do: "Encrypts a sensitive configuration value" + def description(), do: "Encrypts a sensitive configuration value to be used in the advanced.config file" # # Implementation diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/encrypt_conf_value_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/encrypt_conf_value_command.ex new file mode 100644 index 000000000000..914ad7debeb2 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/encrypt_conf_value_command.ex @@ -0,0 +1,157 @@ +## 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-2024 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +defmodule RabbitMQ.CLI.Ctl.Commands.EncryptConfValueCommand do + alias RabbitMQ.CLI.Core.{DocGuide, Helpers, Input} + + @behaviour RabbitMQ.CLI.CommandBehaviour + use RabbitMQ.CLI.DefaultOutput + + def switches() do + [ + cipher: :string, + hash: :string, + iterations: :integer + ] + end + + @atomized_keys [:cipher, :hash] + + def distribution(_), do: :none + + def merge_defaults(args, opts) do + with_defaults = + Map.merge( + %{ + cipher: :rabbit_pbe.default_cipher(), + hash: :rabbit_pbe.default_hash(), + iterations: :rabbit_pbe.default_iterations() + }, + opts + ) + + {args, Helpers.atomize_values(with_defaults, @atomized_keys)} + end + + def validate(args, _) when length(args) > 2 do + {:validation_failure, :too_many_args} + end + + def validate(_args, opts) do + case {supports_cipher(opts.cipher), supports_hash(opts.hash), opts.iterations > 0} do + {false, _, _} -> + {:validation_failure, {:bad_argument, "The requested cipher is not supported."}} + + {_, false, _} -> + {:validation_failure, {:bad_argument, "The requested hash is not supported"}} + + {_, _, false} -> + {:validation_failure, {:bad_argument, "The requested number of iterations is incorrect"}} + + {true, true, true} -> + :ok + end + end + + def run([], %{cipher: cipher, hash: hash, iterations: iterations} = opts) do + case Input.consume_single_line_string_with_prompt("Value to encode: ", opts) do + :eof -> + {:error, :not_enough_args} + + value -> + case Input.consume_single_line_string_with_prompt("Passphrase: ", opts) do + :eof -> + {:error, :not_enough_args} + + passphrase -> + try do + term_value = Helpers.evaluate_input_as_term(value) + + {:encrypted, result} = + :rabbit_pbe.encrypt_term(cipher, hash, iterations, passphrase, term_value) + + {:ok, result} + catch + _, _ -> + {:error, "Error during cipher operation"} + end + end + end + end + + def run([value], %{cipher: cipher, hash: hash, iterations: iterations} = opts) do + case Input.consume_single_line_string_with_prompt("Passphrase: ", opts) do + :eof -> + {:error, :not_enough_args} + + passphrase -> + try do + term_value = Helpers.evaluate_input_as_term(value) + + {:encrypted, result} = + :rabbit_pbe.encrypt_term(cipher, hash, iterations, passphrase, term_value) + + {:ok, result} + catch + _, _ -> + IO.inspect(__STACKTRACE__) + {:error, "Error during cipher operation"} + end + end + end + + def run([value, passphrase], %{cipher: cipher, hash: hash, iterations: iterations}) do + try do + term_value = Helpers.evaluate_input_as_term(value) + + {:encrypted, result} = + :rabbit_pbe.encrypt_term(cipher, hash, iterations, passphrase, term_value) + + {:ok, result} + catch + _, _ -> + IO.inspect(__STACKTRACE__) + {:error, "Error during cipher operation"} + end + end + + def formatter(), do: RabbitMQ.CLI.Formatters.EncryptedConfValue + + def banner(_, _) do + "Encrypting value to be used in rabbitmq.conf..." + end + + def usage, + do: "encrypt_conf_value value passphrase [--cipher ] [--hash ] [--iterations ]" + + def usage_additional() do + [ + ["", "config value to encode"], + ["", "passphrase to use with the config value encryption key"], + ["--cipher ", "cipher suite to use"], + ["--hash ", "hashing function to use"], + ["--iterations ", "number of iteration to apply"] + ] + end + + def usage_doc_guides() do + [ + DocGuide.configuration() + ] + end + + def help_section(), do: :configuration + + def description(), do: "Encrypts a sensitive configuration value to be used in the advanced.config file" + + # + # Implementation + # + + defp supports_cipher(cipher), do: Enum.member?(:rabbit_pbe.supported_ciphers(), cipher) + + defp supports_hash(hash), do: Enum.member?(:rabbit_pbe.supported_hashes(), hash) +end diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/formatters/encrypted_conf_value.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/formatters/encrypted_conf_value.ex new file mode 100644 index 000000000000..7eabc77b3a7a --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/formatters/encrypted_conf_value.ex @@ -0,0 +1,26 @@ +## 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-2023 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +## Prints values from a command as strings(if possible) +defmodule RabbitMQ.CLI.Formatters.EncryptedConfValue do + alias RabbitMQ.CLI.Core.Helpers + alias RabbitMQ.CLI.Formatters.FormatterHelpers + + @behaviour RabbitMQ.CLI.FormatterBehaviour + + def format_output(output, _) do + Helpers.string_or_inspect("encrypted:#{output}") + end + + def format_stream(stream, options) do + Stream.map( + stream, + FormatterHelpers.without_errors_1(fn el -> + format_output(el, options) + end) + ) + end +end diff --git a/deps/rabbitmq_cli/test/ctl/decrypt_conf_value_command_test.exs b/deps/rabbitmq_cli/test/ctl/decrypt_conf_value_command_test.exs new file mode 100644 index 000000000000..e6dff24dbc21 --- /dev/null +++ b/deps/rabbitmq_cli/test/ctl/decrypt_conf_value_command_test.exs @@ -0,0 +1,83 @@ +## 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-2024 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +defmodule DecryptConfValueCommandTest do + use ExUnit.Case, async: false + @command RabbitMQ.CLI.Ctl.Commands.DecryptConfValueCommand + + setup _context do + {:ok, + opts: %{ + cipher: :rabbit_pbe.default_cipher(), + hash: :rabbit_pbe.default_hash(), + iterations: :rabbit_pbe.default_iterations() + }} + end + + test "validate: providing exactly 2 positional arguments passes", context do + assert :ok == @command.validate(["value", "secret"], context[:opts]) + end + + test "validate: providing no positional arguments fails", context do + assert match?( + {:validation_failure, {:not_enough_args, _}}, + @command.validate([], context[:opts]) + ) + end + + test "validate: providing one positional argument passes", context do + assert :ok == @command.validate(["value"], context[:opts]) + end + + test "validate: providing three or more positional argument fails", context do + assert match?( + {:validation_failure, :too_many_args}, + @command.validate(["value", "secret", "incorrect"], context[:opts]) + ) + end + + test "validate: hash and cipher must be supported", context do + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate( + ["value", "secret"], + Map.merge(context[:opts], %{cipher: :funny_cipher}) + ) + ) + + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate( + ["value", "secret"], + Map.merge(context[:opts], %{hash: :funny_hash}) + ) + ) + + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate( + ["value", "secret"], + Map.merge(context[:opts], %{cipher: :funny_cipher, hash: :funny_hash}) + ) + ) + + assert :ok == @command.validate(["value", "secret"], context[:opts]) + end + + test "validate: number of iterations must greater than 0", context do + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: 0})) + ) + + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: -1})) + ) + + assert :ok == @command.validate(["value", "secret"], context[:opts]) + end +end diff --git a/deps/rabbitmq_cli/test/ctl/encrypt_conf_value_command_test.exs b/deps/rabbitmq_cli/test/ctl/encrypt_conf_value_command_test.exs new file mode 100644 index 000000000000..e65f3b99a22a --- /dev/null +++ b/deps/rabbitmq_cli/test/ctl/encrypt_conf_value_command_test.exs @@ -0,0 +1,78 @@ +## 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-2024 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +defmodule EncryptConfValueCommandTest do + use ExUnit.Case, async: false + + @command RabbitMQ.CLI.Ctl.Commands.EncryptConfValueCommand + + setup _context do + {:ok, + opts: %{ + cipher: :rabbit_pbe.default_cipher(), + hash: :rabbit_pbe.default_hash(), + iterations: :rabbit_pbe.default_iterations() + }} + end + + test "validate: providing exactly 2 positional arguments passes", context do + assert :ok == @command.validate(["value", "secret"], context[:opts]) + end + + test "validate: providing zero or one positional argument passes", context do + assert :ok == @command.validate([], context[:opts]) + assert :ok == @command.validate(["value"], context[:opts]) + end + + test "validate: providing three or more positional argument fails", context do + assert match?( + {:validation_failure, :too_many_args}, + @command.validate(["value", "secret", "incorrect"], context[:opts]) + ) + end + + test "validate: hash and cipher must be supported", context do + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate( + ["value", "secret"], + Map.merge(context[:opts], %{cipher: :funny_cipher}) + ) + ) + + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate( + ["value", "secret"], + Map.merge(context[:opts], %{hash: :funny_hash}) + ) + ) + + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate( + ["value", "secret"], + Map.merge(context[:opts], %{cipher: :funny_cipher, hash: :funny_hash}) + ) + ) + + assert :ok == @command.validate(["value", "secret"], context[:opts]) + end + + test "validate: number of iterations must greater than 0", context do + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: 0})) + ) + + assert match?( + {:validation_failure, {:bad_argument, _}}, + @command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: -1})) + ) + + assert :ok == @command.validate(["value", "secret"], context[:opts]) + end +end diff --git a/deps/rabbitmq_management/priv/schema/rabbitmq_management.schema b/deps/rabbitmq_management/priv/schema/rabbitmq_management.schema index 1ee80516e200..83c32b3022ac 100644 --- a/deps/rabbitmq_management/priv/schema/rabbitmq_management.schema +++ b/deps/rabbitmq_management/priv/schema/rabbitmq_management.schema @@ -87,7 +87,7 @@ end}. {mapping, "management.ssl.cacertfile", "rabbitmq_management.ssl_config.cacertfile", [{datatype, string}, {validators, ["file_accessible"]}]}. {mapping, "management.ssl.password", "rabbitmq_management.ssl_config.password", - [{datatype, string}]}. + [{datatype, [tagged_binary, binary]}]}. {mapping, "management.ssl.verify", "rabbitmq_management.ssl_config.verify", [ {datatype, {enum, [verify_peer, verify_none]}}]}. @@ -295,7 +295,7 @@ end}. [{datatype, {enum, [true, false]}}]}. {mapping, "management.listener.ssl_opts.password", "rabbitmq_management.listener.ssl_opts.password", - [{datatype, string}]}. + [{datatype, [tagged_binary, binary]}]}. {mapping, "management.listener.ssl_opts.psk_identity", "rabbitmq_management.listener.ssl_opts.psk_identity", [{datatype, string}]}. diff --git a/deps/rabbitmq_trust_store/priv/schema/rabbitmq_trust_store.schema b/deps/rabbitmq_trust_store/priv/schema/rabbitmq_trust_store.schema index d3d33c251ccc..d9cc4a2afa51 100644 --- a/deps/rabbitmq_trust_store/priv/schema/rabbitmq_trust_store.schema +++ b/deps/rabbitmq_trust_store/priv/schema/rabbitmq_trust_store.schema @@ -124,7 +124,7 @@ end}. [{datatype, {enum, [true, false]}}]}. {mapping, "trust_store.ssl_options.password", "rabbitmq_trust_store.ssl_options.password", - [{datatype, string}]}. + [{datatype, [tagged_binary, binary]}]}. {mapping, "trust_store.ssl_options.psk_identity", "rabbitmq_trust_store.ssl_options.psk_identity", [{datatype, string}]}. diff --git a/deps/rabbitmq_trust_store/test/config_schema_SUITE_data/rabbitmq_trust_store.snippets b/deps/rabbitmq_trust_store/test/config_schema_SUITE_data/rabbitmq_trust_store.snippets index d45f48ecef45..b8d7f0457e3d 100644 --- a/deps/rabbitmq_trust_store/test/config_schema_SUITE_data/rabbitmq_trust_store.snippets +++ b/deps/rabbitmq_trust_store/test/config_schema_SUITE_data/rabbitmq_trust_store.snippets @@ -24,5 +24,5 @@ {url,"https://example.com"}, {ssl_options, [{certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, - {password,"i_am_password"}]}]}], + {password,<<"i_am_password">>}]}]}], [rabbitmq_trust_store]}]. diff --git a/deps/rabbitmq_web_mqtt/priv/schema/rabbitmq_web_mqtt.schema b/deps/rabbitmq_web_mqtt/priv/schema/rabbitmq_web_mqtt.schema index 91d6b1878239..e4afd579d4b7 100644 --- a/deps/rabbitmq_web_mqtt/priv/schema/rabbitmq_web_mqtt.schema +++ b/deps/rabbitmq_web_mqtt/priv/schema/rabbitmq_web_mqtt.schema @@ -56,7 +56,7 @@ {mapping, "web_mqtt.ssl.cacertfile", "rabbitmq_web_mqtt.ssl_config.cacertfile", [{datatype, string}, {validators, ["file_accessible"]}]}. {mapping, "web_mqtt.ssl.password", "rabbitmq_web_mqtt.ssl_config.password", - [{datatype, string}]}. + [{datatype, [tagged_binary, binary]}]}. {translation, "rabbitmq_web_mqtt.ssl_config", diff --git a/deps/rabbitmq_web_mqtt/test/config_schema_SUITE_data/rabbitmq_web_mqtt.snippets b/deps/rabbitmq_web_mqtt/test/config_schema_SUITE_data/rabbitmq_web_mqtt.snippets index f8ef2916f6ef..ab6735cbc830 100644 --- a/deps/rabbitmq_web_mqtt/test/config_schema_SUITE_data/rabbitmq_web_mqtt.snippets +++ b/deps/rabbitmq_web_mqtt/test/config_schema_SUITE_data/rabbitmq_web_mqtt.snippets @@ -85,7 +85,7 @@ {certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, {keyfile,"test/config_schema_SUITE_data/certs/key.pem"}, {cacertfile,"test/config_schema_SUITE_data/certs/cacert.pem"}, - {password,"changeme"}]}]}], + {password,<<"changeme">>}]}]}], [rabbitmq_web_mqtt]}, {ssl, @@ -108,7 +108,7 @@ {certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, {keyfile,"test/config_schema_SUITE_data/certs/key.pem"}, {cacertfile,"test/config_schema_SUITE_data/certs/cacert.pem"}, - {password,"changeme"}, + {password,<<"changeme">>}, {versions,['tlsv1.2','tlsv1.1']} ]}]}], @@ -145,7 +145,7 @@ {certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, {keyfile,"test/config_schema_SUITE_data/certs/key.pem"}, {cacertfile,"test/config_schema_SUITE_data/certs/cacert.pem"}, - {password,"changeme"}, + {password,<<"changeme">>}, {honor_cipher_order, true}, {honor_ecc_order, true}, diff --git a/deps/rabbitmq_web_stomp/priv/schema/rabbitmq_web_stomp.schema b/deps/rabbitmq_web_stomp/priv/schema/rabbitmq_web_stomp.schema index 273d30cb3a2b..c16e74837563 100644 --- a/deps/rabbitmq_web_stomp/priv/schema/rabbitmq_web_stomp.schema +++ b/deps/rabbitmq_web_stomp/priv/schema/rabbitmq_web_stomp.schema @@ -65,7 +65,7 @@ {mapping, "web_stomp.ssl.cacertfile", "rabbitmq_web_stomp.ssl_config.cacertfile", [{datatype, string}, {validators, ["file_accessible"]}]}. {mapping, "web_stomp.ssl.password", "rabbitmq_web_stomp.ssl_config.password", - [{datatype, string}]}. + [{datatype, [tagged_binary, binary]}]}. {translation, "rabbitmq_web_stomp.ssl_config", diff --git a/deps/rabbitmq_web_stomp/test/config_schema_SUITE_data/rabbitmq_web_stomp.snippets b/deps/rabbitmq_web_stomp/test/config_schema_SUITE_data/rabbitmq_web_stomp.snippets index 8a41ce031b90..fc901e2d05a4 100644 --- a/deps/rabbitmq_web_stomp/test/config_schema_SUITE_data/rabbitmq_web_stomp.snippets +++ b/deps/rabbitmq_web_stomp/test/config_schema_SUITE_data/rabbitmq_web_stomp.snippets @@ -79,7 +79,7 @@ {certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, {keyfile,"test/config_schema_SUITE_data/certs/key.pem"}, {cacertfile,"test/config_schema_SUITE_data/certs/cacert.pem"}, - {password,"changeme"}]}]}], + {password,<<"changeme">>}]}]}], [rabbitmq_web_stomp]}, {ssl, @@ -99,7 +99,7 @@ {certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, {keyfile,"test/config_schema_SUITE_data/certs/key.pem"}, {cacertfile,"test/config_schema_SUITE_data/certs/cacert.pem"}, - {password,"changeme"}, + {password,<<"changeme">>}, {versions,['tlsv1.2','tlsv1.1']} ]}]}], @@ -136,7 +136,7 @@ {certfile,"test/config_schema_SUITE_data/certs/cert.pem"}, {keyfile,"test/config_schema_SUITE_data/certs/key.pem"}, {cacertfile,"test/config_schema_SUITE_data/certs/cacert.pem"}, - {password,"changeme"}, + {password,<<"changeme">>}, {honor_cipher_order, true}, {honor_ecc_order, true},