416 lines
16 KiB
Erlang
416 lines
16 KiB
Erlang
%% 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.
|
|
%%
|
|
-module(scope_SUITE).
|
|
|
|
-compile(export_all).
|
|
|
|
-include_lib("rabbit_common/include/rabbit.hrl").
|
|
-include_lib("common_test/include/ct.hrl").
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
all() ->
|
|
[
|
|
variable_expansion,
|
|
permission_all,
|
|
permission_vhost,
|
|
permission_resource,
|
|
permission_topic
|
|
].
|
|
|
|
variable_expansion(_Config) ->
|
|
Scenarios = [
|
|
{ "Emtpy Scopes",
|
|
#{
|
|
<<"client_id">> => <<"some_client">>,
|
|
<<"scope">> => []
|
|
}, <<"default">>, []
|
|
},
|
|
{ "No Scopes",
|
|
#{
|
|
<<"client_id">> => <<"some_client">>
|
|
}, <<"default">>, []
|
|
},
|
|
{ "Expand token's var and vhost",
|
|
#{
|
|
<<"client_id">> => <<"some_client">>,
|
|
<<"scope">> => [<<"read:{vhost}/{client_id}-*">>]
|
|
}, <<"default">>, [<<"read:default/some_client-*">>]
|
|
},
|
|
{ "Expand token's var and vhost on several scopes",
|
|
#{
|
|
<<"client_id">> => <<"some_client">>,
|
|
<<"username">> => <<"some_user">>,
|
|
<<"scope">> => [<<"read:{vhost}/{client_id}-*">>, <<"write:{vhost}/{client_id}/{username}">>]
|
|
}, <<"default">>, [<<"read:default/some_client-*">>, <<"write:default/some_client/some_user">>]
|
|
},
|
|
{ "Expand token's var",
|
|
#{
|
|
<<"client_id">> => <<"some_client">>,
|
|
<<"username">> => <<"some_user">>,
|
|
<<"scope">> => [<<"read:{client_id}/*/{username}">>]
|
|
}, <<"other">>, [<<"read:some_client/*/some_user">>]
|
|
},
|
|
{ "No Expansion required",
|
|
#{
|
|
<<"client_id">> => <<"some_client">>,
|
|
<<"scope">> => [<<"read:client_id/vhost-*">>]
|
|
}, <<"default">>, [<<"read:client_id/vhost-*">>]
|
|
},
|
|
{ "Missing var",
|
|
#{
|
|
<<"scope">> => [<<"read:{client_id}/*">>]
|
|
}, <<"default">>, [<<"read:client_id/*">>]
|
|
},
|
|
{ "Var with other than single binary value",
|
|
#{
|
|
<<"foo">> => [<<"bar">>],
|
|
<<"scope">> => [<<"read:{foo}/*">>]
|
|
}, <<"default">>, [<<"read:foo/*">>]
|
|
},
|
|
{ "Empty var",
|
|
#{
|
|
<<"scope">> => [<<"read:{}/*">>]
|
|
}, <<"default">>, [<<"read:/*">>]
|
|
},
|
|
{ "Missing closing variable character",
|
|
#{
|
|
<<"scope">> => [<<"read:{/*">>]
|
|
}, <<"default">>, [<<"">>]
|
|
},
|
|
{ "Unexpected closing variable character",
|
|
#{
|
|
<<"scope">> => [<<"read:var}/*">>]
|
|
}, <<"default">>, [<<"read:var}/*">>]
|
|
}
|
|
|
|
],
|
|
lists:foreach(fun({ Comment, Token, Vhost, ExpectedScopes}) ->
|
|
?assertEqual(ExpectedScopes,
|
|
rabbit_auth_backend_oauth2:get_expanded_scopes(Token, #resource{virtual_host = Vhost}), Comment)
|
|
end
|
|
, Scenarios).
|
|
|
|
permission_all(_Config) ->
|
|
WildcardScopeWrite = <<"write:*/*">>,
|
|
WildcardScopeWriteTopic = <<"write:*/*/*">>,
|
|
WildcardScopeRead = <<"read:*/*">>,
|
|
WildcardScopeReadTopic = <<"read:*/*/*">>,
|
|
WildcardScopeConfigure = <<"configure:*/*">>,
|
|
WildcardScopeConfigureTopic = <<"configure:*/*/*">>,
|
|
|
|
ReadScopes = [WildcardScopeRead, WildcardScopeReadTopic],
|
|
WriteScopes = [WildcardScopeWrite, WildcardScopeWriteTopic],
|
|
ConfigureScopes = [WildcardScopeConfigure, WildcardScopeConfigureTopic],
|
|
|
|
ExampleVhosts = [<<"/">>, <<"foo">>, <<"*">>, <<"foo/bar">>, <<"юникод"/utf8>>],
|
|
ExampleResources = [<<"foo">>, <<"foo/bar">>, <<"*">>, <<"*/*">>, <<"юникод"/utf8>>],
|
|
|
|
|
|
[ vhost_allowed(<<"/">>, Scope) ||
|
|
Scope <- ReadScopes ++ WriteScopes ++ ConfigureScopes ],
|
|
[ vhost_allowed(<<"foo">>, Scope) ||
|
|
Scope <- ReadScopes ++ WriteScopes ++ ConfigureScopes ],
|
|
[ vhost_allowed(<<"*">>, Scope) ||
|
|
Scope <- ReadScopes ++ WriteScopes ++ ConfigureScopes ],
|
|
[ vhost_allowed(<<"foo/bar">>, Scope) ||
|
|
Scope <- ReadScopes ++ WriteScopes ++ ConfigureScopes ],
|
|
[ vhost_allowed(<<"юникод"/utf8>>, Scope) ||
|
|
Scope <- ReadScopes ++ WriteScopes ++ ConfigureScopes ],
|
|
|
|
[ read_allowed(Vhost, Resource, Scope) ||
|
|
Scope <- ReadScopes,
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ write_allowed(Vhost, Resource, Scope) ||
|
|
Scope <- WriteScopes,
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ configure_allowed(Vhost, Resource, Scope) ||
|
|
Scope <- ConfigureScopes,
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ read_refused(Vhost, Resource, Scope) ||
|
|
Scope <- WriteScopes ++ ConfigureScopes,
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ write_refused(Vhost, Resource, Scope) ||
|
|
Scope <- ReadScopes ++ ConfigureScopes,
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ configure_refused(Vhost, Resource, Scope) ||
|
|
Scope <- WriteScopes ++ ReadScopes,
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ].
|
|
|
|
permission_vhost(_Config) ->
|
|
FooScopeWrite = <<"write:foo/*">>,
|
|
FooScopeWriteTopic = <<"write:foo/*/*">>,
|
|
FooScopeRead = <<"read:foo/*">>,
|
|
FooScopeReadTopic = <<"read:foo/*/*">>,
|
|
FooScopeConfigure = <<"configure:foo/*">>,
|
|
FooScopeConfigureTopic = <<"configure:foo/*/*">>,
|
|
|
|
ComplexVHost = <<"foo/bar/*/">>,
|
|
EncodedVhost = cow_qs:urlencode(ComplexVHost),
|
|
|
|
EncodedScopeWrite = <<"write:", EncodedVhost/binary, "/*">>,
|
|
EncodedScopeWriteTopic = <<"write:", EncodedVhost/binary, "/*/*">>,
|
|
EncodedScopeRead = <<"read:", EncodedVhost/binary, "/*">>,
|
|
EncodedScopeReadTopic = <<"read:", EncodedVhost/binary, "/*/*">>,
|
|
EncodedScopeConfigure = <<"configure:", EncodedVhost/binary, "/*">>,
|
|
EncodedScopeConfigureTopic = <<"configure:", EncodedVhost/binary, "/*/*">>,
|
|
|
|
FooReadScopes = [FooScopeRead, FooScopeReadTopic],
|
|
EncodedReadScopes = [EncodedScopeRead, EncodedScopeReadTopic],
|
|
|
|
FooWriteScopes = [FooScopeWrite, FooScopeWriteTopic],
|
|
EncodedWriteScopes = [EncodedScopeWrite, EncodedScopeWriteTopic],
|
|
|
|
FooConfigureScopes = [FooScopeConfigure, FooScopeConfigureTopic],
|
|
EncodedConfigureScopes = [EncodedScopeConfigure, EncodedScopeConfigureTopic],
|
|
|
|
ExampleResources = [<<"foo">>, <<"foo/bar">>, <<"*">>, <<"*/*">>, <<"юникод"/utf8>>],
|
|
|
|
Tags = [<<"tag:management">>, <<"tag:policymaker">>],
|
|
|
|
[ vhost_allowed(<<"foo">>, Scope) ||
|
|
Scope <- FooReadScopes ++ FooWriteScopes ++ FooConfigureScopes ],
|
|
[ vhost_allowed(ComplexVHost, [Scope] ++ Tags) ||
|
|
Scope <- EncodedReadScopes ++ EncodedWriteScopes ++ EncodedConfigureScopes ],
|
|
|
|
[ read_allowed(<<"foo">>, Resource, [Scope] ++ Tags) ||
|
|
Scope <- FooReadScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ write_allowed(<<"foo">>, Resource, [Scope] ++ Tags) ||
|
|
Scope <- FooWriteScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ configure_allowed(<<"foo">>, Resource, [Scope] ++ Tags) ||
|
|
Scope <- FooConfigureScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ read_refused(<<"foo">>, Resource, [Scope] ++ Tags) ||
|
|
Scope <- FooWriteScopes ++ FooConfigureScopes ++
|
|
EncodedWriteScopes ++ EncodedConfigureScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ write_refused(<<"foo">>, Resource, [Scope] ++ Tags) ||
|
|
Scope <- FooReadScopes ++ FooConfigureScopes ++
|
|
EncodedReadScopes ++ EncodedConfigureScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ configure_refused(<<"foo">>, Resource, [Scope] ++ Tags) ||
|
|
Scope <- FooWriteScopes ++ FooReadScopes ++
|
|
EncodedWriteScopes ++ EncodedReadScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ read_allowed(ComplexVHost, Resource, Scope) ||
|
|
Scope <- EncodedReadScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ write_allowed(ComplexVHost, Resource, Scope) ||
|
|
Scope <- EncodedWriteScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ configure_allowed(ComplexVHost, Resource, Scope) ||
|
|
Scope <- EncodedConfigureScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ read_refused(ComplexVHost, Resource, Scope) ||
|
|
Scope <- EncodedWriteScopes ++ EncodedConfigureScopes ++
|
|
FooWriteScopes ++ FooConfigureScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ write_refused(ComplexVHost, Resource, Scope) ||
|
|
Scope <- EncodedReadScopes ++ EncodedConfigureScopes ++
|
|
FooReadScopes ++ FooConfigureScopes,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ configure_refused(ComplexVHost, Resource, Scope) ||
|
|
Scope <- EncodedWriteScopes ++ EncodedReadScopes ++
|
|
FooWriteScopes ++ FooReadScopes,
|
|
Resource <- ExampleResources ].
|
|
|
|
permission_resource(_Config) ->
|
|
ComplexResource = <<"bar*/baz">>,
|
|
EncodedResource = cow_qs:urlencode(ComplexResource),
|
|
|
|
ScopeWrite = <<"write:*/", EncodedResource/binary>>,
|
|
ScopeWriteTopic = <<"write:*/", EncodedResource/binary, "/*">>,
|
|
ScopeRead = <<"read:*/", EncodedResource/binary>>,
|
|
ScopeReadTopic = <<"read:*/", EncodedResource/binary, "/*">>,
|
|
ScopeConfigure = <<"configure:*/", EncodedResource/binary>>,
|
|
ScopeConfigureTopic = <<"configure:*/", EncodedResource/binary, "/*">>,
|
|
|
|
ExampleVhosts = [<<"/">>, <<"foo">>, <<"*">>, <<"foo/bar">>, <<"юникод"/utf8>>],
|
|
ExampleResources = [<<"foo">>, <<"foo/bar">>, <<"*">>, <<"*/*">>, <<"юникод"/utf8>>],
|
|
|
|
%% Resource access is allowed for complex resource with any vhost
|
|
[ read_allowed(Vhost, ComplexResource, Scope) ||
|
|
Scope <- [ScopeRead, ScopeReadTopic],
|
|
Vhost <- ExampleVhosts ],
|
|
[ write_allowed(Vhost, ComplexResource, Scope) ||
|
|
Scope <- [ScopeWrite, ScopeWriteTopic],
|
|
Vhost <- ExampleVhosts ],
|
|
[ configure_allowed(Vhost, ComplexResource, Scope) ||
|
|
Scope <- [ScopeConfigure, ScopeConfigureTopic],
|
|
Vhost <- ExampleVhosts ],
|
|
|
|
%% Resource access is refused for any other resource
|
|
[ read_refused(Vhost, Resource, Scope) ||
|
|
Scope <- [ScopeWrite, ScopeWriteTopic,
|
|
ScopeRead, ScopeReadTopic,
|
|
ScopeConfigure, ScopeConfigureTopic],
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ write_refused(Vhost, Resource, Scope) ||
|
|
Scope <- [ScopeWrite, ScopeWriteTopic,
|
|
ScopeRead, ScopeReadTopic,
|
|
ScopeConfigure, ScopeConfigureTopic],
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ],
|
|
|
|
[ configure_refused(Vhost, Resource, Scope) ||
|
|
Scope <- [ScopeWrite, ScopeWriteTopic,
|
|
ScopeRead, ScopeReadTopic,
|
|
ScopeConfigure, ScopeConfigureTopic],
|
|
Vhost <- ExampleVhosts,
|
|
Resource <- ExampleResources ].
|
|
|
|
permission_topic(_Config) ->
|
|
TopicWildcardRead = <<"read:*/*/*">>,
|
|
TopicVhostRead = <<"read:vhost/*/*">>,
|
|
TopicResourceRead = <<"read:*/exchange/*">>,
|
|
TopicRoutingKeyRead = <<"read:*/*/rout">>,
|
|
TopicRoutingSuffixKeyRead = <<"read:*/*/*rout">>,
|
|
|
|
ExampleVhosts = [<<"/">>, <<"foo">>, <<"*">>, <<"foo/bar">>, <<"юникод"/utf8>>],
|
|
ExampleResources = [<<"foo">>, <<"foo/bar">>, <<"*">>, <<"*/*">>, <<"юникод"/utf8>>],
|
|
ExampleRoutingKeys = [<<"rout">>, <<"norout">>, <<"some_other">>],
|
|
|
|
[ topic_read_allowed(VHost, Resource, RoutingKey, TopicWildcardRead) ||
|
|
VHost <- ExampleVhosts,
|
|
Resource <- ExampleResources,
|
|
RoutingKey <- ExampleRoutingKeys],
|
|
|
|
[ topic_read_allowed(<<"vhost">>, Resource, RoutingKey, TopicVhostRead) ||
|
|
Resource <- ExampleResources,
|
|
RoutingKey <- ExampleRoutingKeys],
|
|
|
|
[ topic_read_allowed(VHost, <<"exchange">>, RoutingKey, TopicResourceRead) ||
|
|
VHost <- ExampleVhosts,
|
|
RoutingKey <- ExampleRoutingKeys],
|
|
|
|
[ topic_read_allowed(VHost, Resource, <<"rout">>, TopicRoutingKeyRead) ||
|
|
VHost <- ExampleVhosts,
|
|
Resource <- ExampleResources],
|
|
|
|
[ topic_read_allowed(VHost, Resource, RoutingKey, TopicRoutingSuffixKeyRead) ||
|
|
VHost <- ExampleVhosts,
|
|
Resource <- ExampleResources,
|
|
RoutingKey <- [<<"rout">>, <<"norout">>, <<"sprout">>]],
|
|
|
|
[ topic_read_refused(VHost, Resource, RoutingKey, TopicVhostRead) ||
|
|
VHost <- ExampleVhosts,
|
|
Resource <- ExampleResources,
|
|
RoutingKey <- ExampleRoutingKeys],
|
|
|
|
[ topic_read_refused(VHost, Resource, RoutingKey, TopicResourceRead) ||
|
|
VHost <- ExampleVhosts,
|
|
Resource <- ExampleResources,
|
|
RoutingKey <- ExampleRoutingKeys],
|
|
|
|
[ topic_read_refused(VHost, Resource, RoutingKey, TopicRoutingKeyRead) ||
|
|
VHost <- ExampleVhosts,
|
|
Resource <- ExampleResources,
|
|
RoutingKey <- [<<"foo">>, <<"bar">>]].
|
|
|
|
vhost_allowed(Vhost, Scopes) when is_list(Scopes) ->
|
|
?assertEqual(true, rabbit_oauth2_scope:vhost_access(Vhost, Scopes));
|
|
|
|
vhost_allowed(Vhost, Scope) ->
|
|
vhost_allowed(Vhost, [Scope]).
|
|
|
|
read_allowed(Vhost, Resource, Scopes) when is_list(Scopes) ->
|
|
resource_perm(Vhost, Resource, Scopes, read, true);
|
|
|
|
read_allowed(Vhost, Resource, Scope) ->
|
|
resource_perm(Vhost, Resource, Scope, read, true).
|
|
|
|
read_refused(Vhost, Resource, Scopes) when is_list(Scopes) ->
|
|
resource_perm(Vhost, Resource, Scopes, read, false);
|
|
|
|
read_refused(Vhost, Resource, Scope) ->
|
|
resource_perm(Vhost, Resource, Scope, read, false).
|
|
|
|
write_allowed(Vhost, Resource, Scopes) when is_list(Scopes) ->
|
|
resource_perm(Vhost, Resource, Scopes, write, true);
|
|
|
|
write_allowed(Vhost, Resource, Scope) ->
|
|
resource_perm(Vhost, Resource, Scope, write, true).
|
|
|
|
write_refused(Vhost, Resource, Scopes) when is_list(Scopes) ->
|
|
resource_perm(Vhost, Resource, Scopes, write, false);
|
|
|
|
write_refused(Vhost, Resource, Scope) ->
|
|
resource_perm(Vhost, Resource, Scope, write, false).
|
|
|
|
configure_allowed(Vhost, Resource, Scopes) when is_list(Scopes) ->
|
|
resource_perm(Vhost, Resource, Scopes, configure, true);
|
|
|
|
configure_allowed(Vhost, Resource, Scope) ->
|
|
resource_perm(Vhost, Resource, Scope, configure, true).
|
|
|
|
configure_refused(Vhost, Resource, Scopes) when is_list(Scopes) ->
|
|
resource_perm(Vhost, Resource, Scopes, configure, false);
|
|
|
|
configure_refused(Vhost, Resource, Scope) ->
|
|
resource_perm(Vhost, Resource, Scope, configure, false).
|
|
|
|
|
|
resource_perm(Vhost, Resource, Scopes, Permission, Result) when is_list(Scopes) ->
|
|
[ ?assertEqual(Result, rabbit_oauth2_scope:resource_access(
|
|
#resource{virtual_host = Vhost,
|
|
kind = Kind,
|
|
name = Resource},
|
|
Permission,
|
|
Scopes)) || Kind <- [queue, exchange] ];
|
|
|
|
resource_perm(Vhost, Resource, Scope, Permission, Result) ->
|
|
resource_perm(Vhost, Resource, [Scope], Permission, Result).
|
|
|
|
topic_read_allowed(Vhost, Resource, RoutingKey, Scopes) when is_list(Scopes) ->
|
|
topic_perm(Vhost, Resource, RoutingKey, Scopes, read, true);
|
|
|
|
topic_read_allowed(Vhost, Resource, RoutingKey, Scope) ->
|
|
topic_perm(Vhost, Resource, RoutingKey, Scope, read, true).
|
|
|
|
topic_read_refused(Vhost, Resource, RoutingKey, Scopes) when is_list(Scopes) ->
|
|
topic_perm(Vhost, Resource, RoutingKey, Scopes, read, false);
|
|
|
|
topic_read_refused(Vhost, Resource, RoutingKey, Scope) ->
|
|
topic_perm(Vhost, Resource, RoutingKey, Scope, read, false).
|
|
|
|
topic_perm(Vhost, Resource, RoutingKey, Scopes, Permission, Result) when is_list(Scopes) ->
|
|
?assertEqual(Result, rabbit_oauth2_scope:topic_access(
|
|
#resource{virtual_host = Vhost,
|
|
kind = topic,
|
|
name = Resource},
|
|
Permission,
|
|
#{routing_key => RoutingKey},
|
|
Scopes));
|
|
|
|
topic_perm(Vhost, Resource, RoutingKey, Scope, Permission, Result) ->
|
|
topic_perm(Vhost, Resource, RoutingKey, [Scope], Permission, Result).
|