Skip to content

Commit eebe67c

Browse files
Extract scopes using path expression
1 parent 3a17473 commit eebe67c

File tree

2 files changed

+153
-1
lines changed

2 files changed

+153
-1
lines changed

deps/rabbitmq_auth_backend_oauth2/src/rabbit_auth_backend_oauth2.erl

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,85 @@ has_additional_scopes_key(ResourceServer, Payload) when is_map(Payload) ->
296296
ScopeKey -> maps:is_key(ScopeKey, Payload)
297297
end.
298298

299+
%% Path is a binary expression which is a plain word like <<"roles">>
300+
%% or +1 word separated by . like <<"authorization.permissions.scopes">>
301+
%% The Payload is a map.
302+
%% Using the path <<"authorization.permissions.scopes">> as an example
303+
%% 1. lookup the key <<"authorization">> in the Payload
304+
%% 2. if it is found, the next map to use as payload is the value found from the key <<"authorization">>
305+
%% 3. lookup the key <<"permissions">> in the previous map
306+
%% 4. if it is found, it may be a map or a list of maps.
307+
%% 5. if it is a list of maps, iterate each element in the list
308+
%% 6. for each element in the list, which should be a map, find the key <<"scopes">>
309+
%% 7. because there are no more words/keys, return a list of all the values found
310+
%% associated to the word <<"scopes">>
311+
extract_token_value(R, Payload, Path, ValueMapperFun)
312+
when is_map(Payload), is_binary(Path), is_function(ValueMapperFun) ->
313+
extract_token_value_from_map(R, Payload, [], split_path(Path), ValueMapperFun);
314+
extract_token_value(_, _, _, _) ->
315+
[].
316+
317+
extract_scope_list_from_token_value(_R, List) when is_list(List) -> List;
318+
extract_scope_list_from_token_value(_R, Binary) when is_binary(Binary) ->
319+
binary:split(Binary, <<" ">>, [global, trim_all]);
320+
extract_scope_list_from_token_value(#resource_server{id = ResourceServerId}, Map) when is_map(Map) ->
321+
case maps:get(ResourceServerId, Map, undefined) of
322+
undefined -> [];
323+
Ks when is_list(Ks) ->
324+
[erlang:iolist_to_binary([ResourceServerId, <<".">>, K]) || K <- Ks];
325+
ClaimBin when is_binary(ClaimBin) ->
326+
UnprefixedClaims = binary:split(ClaimBin, <<" ">>, [global, trim_all]),
327+
[erlang:iolist_to_binary([ResourceServerId, <<".">>, K]) || K <- UnprefixedClaims];
328+
_ -> []
329+
end;
330+
extract_scope_list_from_token_value(_, _) -> [].
331+
332+
extract_token_value_from_map(_, _Map, Acc, [], _Mapper) ->
333+
Acc;
334+
extract_token_value_from_map(R, Map, Acc, [KeyStr], Mapper) when is_map(Map) ->
335+
case maps:find(KeyStr, Map) of
336+
{ok, Value} -> Acc ++ Mapper(R, Value);
337+
error -> Acc
338+
end;
339+
extract_token_value_from_map(R, Map, Acc, [KeyStr | Rest], Mapper) when is_map(Map) ->
340+
case maps:find(KeyStr, Map) of
341+
{ok, M} when is_map(M) -> extract_token_value_from_map(R, M, Acc, Rest, Mapper);
342+
{ok, L} when is_list(L) -> extract_token_value_from_list(R, L, Acc, Rest, Mapper);
343+
{ok, Value} when Rest =:= [] -> Acc ++ Mapper(R, Value);
344+
_ -> Acc
345+
end;
346+
extract_token_value_from_map(_, _, Acc, _, _Mapper) ->
347+
Acc.
348+
349+
extract_token_value_from_list(_, [], Acc, [], _Mapper) ->
350+
Acc;
351+
extract_token_value_from_list(_, [], Acc, [_KeyStr | _Rest], _Mapper) ->
352+
Acc;
353+
extract_token_value_from_list(R, [H | T], Acc, [KeyStr | Rest] = KeyList, Mapper) when is_map(H) ->
354+
NewAcc = case maps:find(KeyStr, H) of
355+
{ok, Map} when is_map(Map) -> extract_token_value_from_map(R, Map, Acc, Rest, Mapper);
356+
{ok, List} when is_list(List) -> extract_token_value_from_list(R, List, Acc, Rest, Mapper);
357+
{ok, Value} -> Acc++Mapper(R, Value);
358+
_ -> Acc
359+
end,
360+
extract_token_value_from_list(R, T, NewAcc, KeyList, Mapper);
361+
362+
extract_token_value_from_list(R, [E | T], Acc, [], Mapper) ->
363+
extract_token_value_from_list(R, T, Acc++Mapper(R, E), [], Mapper);
364+
extract_token_value_from_list(R, [E | _T] = L, Acc, KeyList, Mapper) when is_map(E) ->
365+
extract_token_value_from_list(R, L, Acc, KeyList, Mapper);
366+
extract_token_value_from_list(R, [_ | T], Acc, KeyList, Mapper) ->
367+
extract_token_value_from_list(R, T, Acc, KeyList, Mapper).
368+
369+
370+
%split_path(Path) when is_list(Path) ->
371+
% string:tokens(Path, ".");
372+
split_path(Path) when is_binary(Path) ->
373+
binary:split(Path, <<".">>, [global, trim_all]).
374+
375+
376+
377+
299378
-spec extract_scopes_from_additional_scopes_key(
300379
ResourceServer :: resource_server(), Payload :: map()) -> map().
301380
extract_scopes_from_additional_scopes_key(ResourceServer, Payload) ->

deps/rabbitmq_auth_backend_oauth2/test/unit_SUITE.erl

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
user_login_authentication/2,
1818
user_login_authorization/2,
1919
normalize_token_scope/2,
20-
check_vhost_access/3]).
20+
check_vhost_access/3,
21+
extract_token_value/4,
22+
extract_scope_list_from_token_value/2]).
2123
-import(rabbit_oauth2_resource_server, [
2224
new_resource_server/1
2325
]).
2426

2527
all() ->
2628
[
29+
test_extract_scope_from_path_expression,
2730
filter_matching_scope_prefix_and_drop_it,
2831
normalize_token_scopes_with_scope_prefix,
2932
normalize_token_scope_from_space_separated_list_in_scope_claim,
@@ -1286,6 +1289,76 @@ normalize_token_scope_without_scope_claim(_) ->
12861289
Token0 = #{ },
12871290
?assertEqual([], uaa_jwt:get_scope(normalize_token_scope(ResourceServer, Token0))).
12881291

1292+
1293+
test_extract_scope_from_path_expression(_) ->
1294+
M = fun rabbit_auth_backend_oauth2:extract_scope_list_from_token_value/2,
1295+
R = #resource_server{id = <<"rabbitmq">>},
1296+
1297+
[<<"role1">>] = extract_token_value(R,
1298+
#{ <<"auth">> => #{ <<"permission">> => <<"role1">> }},
1299+
<<"auth.permission">>, M),
1300+
[<<"role1">>,<<"role2">>] = extract_token_value(R,
1301+
#{ <<"auth">> => #{ <<"permission">> => [<<"role1">>,<<"role2">>] }},
1302+
<<"auth.permission">>, M),
1303+
[<<"role1">>,<<"role2">>] = extract_token_value(R,
1304+
#{ <<"auth">> => #{ <<"permission">> => <<"role1 role2">> }},
1305+
<<"auth.permission">>, M),
1306+
[<<"rabbitmq.role1">>,<<"rabbitmq.role2">>] = extract_token_value(R,
1307+
#{ <<"auth">> => #{
1308+
<<"rabbitmq">> => [<<"role1">>,<<"role2">>]
1309+
}},
1310+
<<"auth">>, M),
1311+
[<<"rabbitmq.role1">>,<<"rabbitmq.role2">>] = extract_token_value(R,
1312+
#{ <<"auth">> => #{
1313+
<<"rabbitmq">> => <<"role1 role2">>
1314+
}},
1315+
<<"auth">>, M),
1316+
[<<"role1">>,<<"role2">>] = extract_token_value(R,
1317+
#{ <<"auth">> => #{
1318+
<<"permission">> => [
1319+
#{ <<"scopes">> => <<"role1">>},
1320+
#{ <<"scopes">> => <<"role2">>}
1321+
]
1322+
}},
1323+
<<"auth.permission.scopes">>, M),
1324+
1325+
[<<"role1">>,<<"role2">>] = extract_token_value(R,
1326+
#{ <<"auth">> => #{
1327+
<<"permission">> => [
1328+
#{ <<"scopes">> => [<<"role1">>]},
1329+
#{ <<"scopes">> => [<<"role2">>]}
1330+
]
1331+
}},
1332+
<<"auth.permission.scopes">>, M),
1333+
1334+
[<<"role1">>,<<"role2">>] = extract_token_value(R,
1335+
#{ <<"auth">> => [
1336+
#{ <<"permission">> => [
1337+
#{ <<"scopes">> => [<<"role1">>]}
1338+
]},
1339+
#{ <<"permission">> => [
1340+
#{ <<"scopes">> => [<<"role2">>]}
1341+
]}
1342+
]},
1343+
<<"auth.permission.scopes">>, M),
1344+
1345+
[<<"role1">>] = extract_token_value(R,
1346+
#{ <<"auth">> => #{ <<"permission">> => [<<"role1">>] }},
1347+
<<"auth.permission">>, M),
1348+
1349+
[] = extract_token_value(R,
1350+
#{ <<"auth">> => #{ <<"permission">> => [<<"role1">>] }},
1351+
<<"auth.permission2">>, M),
1352+
1353+
[] = extract_token_value(R,
1354+
#{ <<"auth">> => #{ <<"permission">> => [<<"role1">>] }},
1355+
<<"auth2.permission">>, M),
1356+
1357+
[] = extract_token_value(R,
1358+
#{ <<"auth">> => #{ <<"permission">> => [<<"role1">>] }},
1359+
<<"auth.permission2">>, M).
1360+
1361+
12891362
%%
12901363
%% Helpers
12911364
%%

0 commit comments

Comments
 (0)