-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce a CLI command that grants permissions to all virtual hosts
Closes #1000
- Loading branch information
1 parent
3b5ec6a
commit ab99ccf
Showing
4 changed files
with
206 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/set_permissions_globally.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
## 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 VMware, Inc. or its affiliates. All rights reserved. | ||
|
||
defmodule RabbitMQ.CLI.Ctl.Commands.SetPermissionsGloballyCommand do | ||
alias RabbitMQ.CLI.Core.{DocGuide, ExitCodes, Helpers} | ||
|
||
@behaviour RabbitMQ.CLI.CommandBehaviour | ||
|
||
def merge_defaults(args, opts) do | ||
{args, Map.merge(%{vhost: "/"}, opts)} | ||
end | ||
|
||
def validate([], _) do | ||
{:validation_failure, :not_enough_args} | ||
end | ||
|
||
def validate([_ | _] = args, _) when length(args) < 4 do | ||
{:validation_failure, :not_enough_args} | ||
end | ||
|
||
def validate([_ | _] = args, _) when length(args) > 4 do | ||
{:validation_failure, :too_many_args} | ||
end | ||
|
||
def validate(_, _), do: :ok | ||
|
||
use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||
|
||
def run([user, conf, write, read], %{node: node_name}) do | ||
:rabbit_misc.rpc_call( | ||
node_name, | ||
:rabbit_auth_backend_internal, | ||
:set_permissions_globally, | ||
[user, conf, write, read, Helpers.cli_acting_user()] | ||
) | ||
end | ||
|
||
def output({:error, {:no_such_user, username}}, %{node: node_name, formatter: "json"}) do | ||
{:error, | ||
%{"result" => "error", "node" => node_name, "message" => "User #{username} does not exist"}} | ||
end | ||
|
||
def output({:error, {:no_such_user, username}}, _) do | ||
{:error, ExitCodes.exit_nouser(), "User #{username} does not exist"} | ||
end | ||
|
||
use RabbitMQ.CLI.DefaultOutput | ||
|
||
def usage, do: "set_permissions_globally <username> <conf> <write> <read>" | ||
|
||
def usage_additional() do | ||
[ | ||
["<username>", "Self-explanatory"], | ||
["<conf>", "Configuration permission pattern"], | ||
["<write>", "Write permission pattern"], | ||
["<read>", "Read permission pattern"] | ||
] | ||
end | ||
|
||
def usage_doc_guides() do | ||
[ | ||
DocGuide.access_control(), | ||
DocGuide.virtual_hosts() | ||
] | ||
end | ||
|
||
def help_section(), do: :access_control | ||
def description(), do: "Sets user permissions for all virtual hosts." | ||
|
||
def banner([user | _], _opts), | ||
do: "Setting permissions for user \"#{user}\" in all virtual hosts ..." | ||
end |
115 changes: 115 additions & 0 deletions
115
deps/rabbitmq_cli/test/ctl/set_permissions_globally_command_test.exs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
## 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-2020 VMware, Inc. or its affiliates. All rights reserved. | ||
|
||
defmodule SetPermissionsGloballyCommandTest do | ||
use ExUnit.Case, async: false | ||
import TestHelper | ||
|
||
@command RabbitMQ.CLI.Ctl.Commands.SetPermissionsGloballyCommand | ||
|
||
@vhost1 "test1" | ||
@vhost2 "test2" | ||
@vhost3 "test3" | ||
|
||
@user "guest" | ||
|
||
setup_all do | ||
RabbitMQ.CLI.Core.Distribution.start() | ||
|
||
for v <- [@vhost1, @vhost2, @vhost3], do: add_vhost(v) | ||
|
||
on_exit([], fn -> | ||
for v <- [@vhost1, @vhost2, @vhost3], do: delete_vhost(v) | ||
end) | ||
|
||
:ok | ||
end | ||
|
||
setup context do | ||
on_exit(context, fn -> | ||
set_permissions_globally(context[:user], [".*", ".*", ".*"]) | ||
end) | ||
|
||
{ | ||
:ok, | ||
opts: %{ | ||
node: get_rabbit_hostname() | ||
} | ||
} | ||
end | ||
|
||
test "merge_defaults: defaults can be overridden" do | ||
assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}} | ||
assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}} | ||
end | ||
|
||
test "validate: wrong number of arguments leads to an arg count error" do | ||
assert @command.validate([], %{}) == {:validation_failure, :not_enough_args} | ||
assert @command.validate(["insufficient"], %{}) == {:validation_failure, :not_enough_args} | ||
assert @command.validate(["not", "enough"], %{}) == {:validation_failure, :not_enough_args} | ||
|
||
assert @command.validate(["not", "quite", "enough"], %{}) == | ||
{:validation_failure, :not_enough_args} | ||
|
||
assert @command.validate(["this", "is", "way", "too", "many"], %{}) == | ||
{:validation_failure, :too_many_args} | ||
end | ||
|
||
@tag user: @user | ||
test "run: a well-formed, host-specific command returns okay", context do | ||
assert @command.run( | ||
[context[:user], "^#{context[:user]}-.*", ".*", ".*"], | ||
context[:opts] | ||
) == :ok | ||
|
||
p1 = Enum.find(list_permissions(@vhost1), fn x -> x[:user] == context[:user] end) | ||
p2 = Enum.find(list_permissions(@vhost2), fn x -> x[:user] == context[:user] end) | ||
p3 = Enum.find(list_permissions(@vhost3), fn x -> x[:user] == context[:user] end) | ||
|
||
assert p1[:configure] == "^#{context[:user]}-.*" | ||
assert p2[:configure] == "^#{context[:user]}-.*" | ||
assert p3[:configure] == "^#{context[:user]}-.*" | ||
end | ||
|
||
test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do | ||
opts = %{node: :jake@thedog, timeout: 200} | ||
|
||
assert match?({:badrpc, _}, @command.run([@user, ".*", ".*", ".*"], opts)) | ||
end | ||
|
||
@tag user: "interloper" | ||
test "run: an invalid user returns a no-such-user error", context do | ||
assert @command.run( | ||
[context[:user], "^#{context[:user]}-.*", ".*", ".*"], | ||
context[:opts] | ||
) == {:error, {:no_such_user, context[:user]}} | ||
end | ||
|
||
@tag user: @user | ||
test "run: invalid regex patterns returns an error", context do | ||
assert @command.run( | ||
[context[:user], "^#{context[:user]}-.*", ".*", "*"], | ||
context[:opts] | ||
) == {:error, {:invalid_regexp, '*', {'nothing to repeat', 0}}} | ||
|
||
# asserts that the failed command didn't change anything | ||
p1 = Enum.find(list_permissions(@vhost1), fn x -> x[:user] == context[:user] end) | ||
p2 = Enum.find(list_permissions(@vhost2), fn x -> x[:user] == context[:user] end) | ||
p3 = Enum.find(list_permissions(@vhost3), fn x -> x[:user] == context[:user] end) | ||
|
||
assert p1 == [user: context[:user], configure: ".*", write: ".*", read: ".*"] | ||
assert p2 == [user: context[:user], configure: ".*", write: ".*", read: ".*"] | ||
assert p3 == [user: context[:user], configure: ".*", write: ".*", read: ".*"] | ||
end | ||
|
||
@tag user: @user | ||
test "banner", context do | ||
vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]}) | ||
|
||
assert @command.banner([context[:user], "^#{context[:user]}-.*", ".*", ".*"], vhost_opts) =~ | ||
~r/Setting permissions for user \"#{context[:user]}\" in all virtual hosts \.\.\./ | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters