mirror of
https://github.com/valitydev/token-keeper.git
synced 2024-11-06 02:15:21 +00:00
ED-222: Simplify metadata format (#14)
This commit is contained in:
parent
11f8f23670
commit
8dca9ed3c8
@ -71,20 +71,23 @@
|
||||
%% Which jwt key to use for signing for this authority
|
||||
%% You can only use keys that have the same authority configured for them
|
||||
signer => test,
|
||||
%% Storage configuration (NOT IMPLEMENTED)
|
||||
storage => {machinegun, #{}},
|
||||
%% Where to fetch authdata for tokens issued by this authority
|
||||
authdata_sources => [
|
||||
%% Fetch from storage
|
||||
{storage,
|
||||
%% Use token claims as storage
|
||||
{claim, #{
|
||||
%% Enable compatability with legacy issued tokens when getting from storage
|
||||
compatability => {true, <<"test.rbkmoney.apikeymgmt">>}
|
||||
%% Fetch from claim
|
||||
{claim, #{
|
||||
%% Enable compatibility with legacy issued tokens when getting from storage
|
||||
compatibility => {true, #{
|
||||
%% Where to put metadata
|
||||
metadata_mappings => #{
|
||||
party_id => <<"test.rbkmoney.party.id">>,
|
||||
consumer => <<"test.rbkmoney.capi.consumer">>
|
||||
}
|
||||
}}
|
||||
},
|
||||
{storage,
|
||||
%% Use machinegun as storage (NOT IMPLEMENTED)
|
||||
machinegun
|
||||
},
|
||||
}},
|
||||
%% Fetch from storage (configured for authority) (NOT IMPLEMENTED)
|
||||
storage,
|
||||
%% Create a new bouncer context using token data
|
||||
{extract, #{
|
||||
%% Configuration for how to extract said context
|
||||
@ -102,15 +105,21 @@
|
||||
{detect_token, #{
|
||||
%% phony_api_key options to use (can be used standalone)
|
||||
phony_api_key_opts => #{
|
||||
%% What to use as metadata namespace
|
||||
metadata_ns => <<"test.rbkmoney.apikeymgmt">>
|
||||
%% Where to put metadata
|
||||
metadata_mappings => #{
|
||||
party_id => <<"test.rbkmoney.party.id">>
|
||||
}
|
||||
},
|
||||
%% user_session_token options to use (can be used standalone)
|
||||
user_session_token_opts => #{
|
||||
%% Realm of the user
|
||||
user_realm => <<"external">>,
|
||||
%% What to use as metadata namespace
|
||||
metadata_ns => <<"test.rbkmoney.keycloak">>
|
||||
%% Where to put metadata
|
||||
metadata_mappings => #{
|
||||
user_id => <<"test.rbkmoney.user.id">>,
|
||||
user_email => <<"test.rbkmoney.user.email">>,
|
||||
user_realm => <<"test.rbkmoney.user.realm">>
|
||||
}
|
||||
},
|
||||
%% List of origins using which we perform token classification
|
||||
user_session_token_origins => [<<"http://localhost">>]
|
||||
|
@ -57,15 +57,15 @@
|
||||
{<<"snowflake">>,
|
||||
{git,"https://github.com/rbkmoney/snowflake.git",
|
||||
{ref,"de159486ef40cec67074afe71882bdc7f7deab72"}},
|
||||
1},
|
||||
0},
|
||||
{<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.6">>},2},
|
||||
{<<"thrift">>,
|
||||
{git,"https://github.com/rbkmoney/thrift_erlang.git",
|
||||
{ref,"846a0819d9b6d09d0c31f160e33a78dbad2067b4"}},
|
||||
0},
|
||||
{<<"token_keeper_proto">>,
|
||||
{git,"git@github.com:rbkmoney/token-keeper-proto.git",
|
||||
{ref,"48a18d87ea2443540272c80213f7612beea6af9c"}},
|
||||
{git,"https://github.com/rbkmoney/token-keeper-proto.git",
|
||||
{ref,"15781716691a72de8c8f065c11c5b08173fc8434"}},
|
||||
0},
|
||||
{<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},2},
|
||||
{<<"woody">>,
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
%% API Types
|
||||
|
||||
-type authdata_source() :: storage_source() | extractor_source().
|
||||
-type authdata_source() :: storage_source() | claim_source() | extractor_source().
|
||||
-type sourced_authdata() :: #{
|
||||
id => tk_authority:authdata_id(),
|
||||
status := tk_authority:status(),
|
||||
@ -25,12 +25,14 @@
|
||||
%% Internal types
|
||||
|
||||
-type storage_source() :: {storage, tk_authdata_source_storage:source_opts()}.
|
||||
-type claim_source() :: {claim, tk_authdata_source_claim:source_opts()}.
|
||||
-type extractor_source() :: maybe_opts(extractor, tk_authdata_source_extractor:source_opts()).
|
||||
|
||||
-type maybe_opts(Source, Opts) :: Source | {Source, Opts}.
|
||||
|
||||
-type source_opts() ::
|
||||
tk_authdata_source_extractor:source_opts()
|
||||
| tk_authdata_source_claim:source_opts()
|
||||
| tk_authdata_source_storage:source_opts().
|
||||
|
||||
%% API functions
|
||||
@ -50,5 +52,7 @@ get_source_opts(Source) when is_atom(Source) ->
|
||||
|
||||
get_source_handler(storage) ->
|
||||
tk_authdata_source_storage;
|
||||
get_source_handler(claim) ->
|
||||
tk_authdata_source_claim;
|
||||
get_source_handler(extract) ->
|
||||
tk_authdata_source_extractor.
|
||||
|
27
src/tk_authdata_source_claim.erl
Normal file
27
src/tk_authdata_source_claim.erl
Normal file
@ -0,0 +1,27 @@
|
||||
-module(tk_authdata_source_claim).
|
||||
-behaviour(tk_authdata_source).
|
||||
|
||||
%% Behaviour
|
||||
|
||||
-export([get_authdata/2]).
|
||||
|
||||
%%
|
||||
|
||||
-type stored_authdata() :: tk_storage:storable_authdata().
|
||||
-type source_opts() :: tk_token_claim_utils:decode_opts().
|
||||
|
||||
-export_type([stored_authdata/0]).
|
||||
-export_type([source_opts/0]).
|
||||
|
||||
%% Behaviour functions
|
||||
|
||||
-spec get_authdata(tk_token_jwt:t(), source_opts()) -> stored_authdata() | undefined.
|
||||
get_authdata(Token, Opts) ->
|
||||
Claims = tk_token_jwt:get_claims(Token),
|
||||
case tk_token_claim_utils:decode_authdata(Claims, Opts) of
|
||||
{ok, AuthData} ->
|
||||
AuthData;
|
||||
{error, Reason} ->
|
||||
_ = logger:warning("Failed claim get: ~p", [Reason]),
|
||||
undefined
|
||||
end.
|
@ -8,25 +8,28 @@
|
||||
%%
|
||||
|
||||
-type stored_authdata() :: tk_storage:storable_authdata().
|
||||
-type source_opts() :: claim_storage().
|
||||
-type source_opts() :: tk_storage:storage_opts().
|
||||
|
||||
-export_type([stored_authdata/0]).
|
||||
-export_type([source_opts/0]).
|
||||
|
||||
%%
|
||||
|
||||
-type claim_storage() :: maybe_opts(claim, tk_storage_claim:storage_opts()).
|
||||
-type maybe_opts(Source, Opts) :: Source | {Source, Opts}.
|
||||
|
||||
%% Behaviour functions
|
||||
|
||||
-spec get_authdata(tk_token_jwt:t(), source_opts()) -> stored_authdata() | undefined.
|
||||
get_authdata(Token, StorageOpts) ->
|
||||
Claims = tk_token_jwt:get_claims(Token),
|
||||
case tk_storage:get_by_claims(Claims, StorageOpts) of
|
||||
{ok, AuthData} ->
|
||||
AuthData;
|
||||
AuthDataID = get_authdata_id(Claims),
|
||||
case tk_storage:get(AuthDataID, StorageOpts) of
|
||||
%% Not implemented
|
||||
%% {ok, AuthData} ->
|
||||
%% AuthData;
|
||||
{error, Reason} ->
|
||||
_ = logger:warning("Failed storage get: ~p", [Reason]),
|
||||
undefined
|
||||
end.
|
||||
|
||||
%%
|
||||
|
||||
get_authdata_id(_Claims) ->
|
||||
%% Not implemented
|
||||
<<>>.
|
||||
|
@ -31,8 +31,7 @@
|
||||
-type authdata_id() :: binary().
|
||||
-type status() :: active | revoked.
|
||||
-type encoded_context_fragment() :: tk_context_thrift:'ContextFragment'().
|
||||
-type metadata() :: #{metadata_ns() => #{binary() => binary()}}.
|
||||
-type metadata_ns() :: binary().
|
||||
-type metadata() :: #{binary() => binary()}.
|
||||
|
||||
-export_type([authority/0]).
|
||||
|
||||
@ -41,7 +40,6 @@
|
||||
-export_type([status/0]).
|
||||
-export_type([encoded_context_fragment/0]).
|
||||
-export_type([metadata/0]).
|
||||
-export_type([metadata_ns/0]).
|
||||
-export_type([autority_id/0]).
|
||||
|
||||
%% API Functions
|
||||
|
@ -13,7 +13,9 @@
|
||||
|
||||
-type extractor_opts() :: #{
|
||||
domain := binary(),
|
||||
metadata_ns := binary()
|
||||
metadata_mappings := #{
|
||||
party_id := binary()
|
||||
}
|
||||
}.
|
||||
|
||||
-export_type([extractor_opts/0]).
|
||||
@ -26,7 +28,16 @@ get_context(Token, ExtractorOpts) ->
|
||||
case extract_invoice_template_rights(Token, ExtractorOpts) of
|
||||
{ok, InvoiceTemplateID} ->
|
||||
BCtx = create_bouncer_ctx(tk_token_jwt:get_token_id(Token), UserID, InvoiceTemplateID),
|
||||
{BCtx, wrap_metadata(get_metadata(Token), ExtractorOpts)};
|
||||
{BCtx,
|
||||
make_metadata(
|
||||
#{
|
||||
%% @TEMP: This is a temporary hack.
|
||||
%% When some external services will stop requiring woody user
|
||||
%% identity to be present it must be removed too
|
||||
party_id => tk_token_jwt:get_subject_id(Token)
|
||||
},
|
||||
ExtractorOpts
|
||||
)};
|
||||
{error, Reason} ->
|
||||
_ = logger:warning("Failed to extract invoice template rights: ~p", [Reason]),
|
||||
undefined
|
||||
@ -34,16 +45,6 @@ get_context(Token, ExtractorOpts) ->
|
||||
|
||||
%%
|
||||
|
||||
get_metadata(Token) ->
|
||||
%% @TEMP: This is a temporary hack.
|
||||
%% When some external services will stop requiring woody user identity to be present it must be removed too
|
||||
case tk_token_jwt:get_subject_id(Token) of
|
||||
UserID when UserID =/= undefined ->
|
||||
#{<<"party_id">> => UserID};
|
||||
undefined ->
|
||||
undefined
|
||||
end.
|
||||
|
||||
extract_invoice_template_rights(TokenContext, ExtractorOpts) ->
|
||||
Domain = maps:get(domain, ExtractorOpts),
|
||||
case get_acl(Domain, get_resource_hierarchy(), TokenContext) of
|
||||
@ -106,9 +107,9 @@ create_bouncer_ctx(TokenID, UserID, InvoiceTemplateID) ->
|
||||
bouncer_context_helpers:empty()
|
||||
).
|
||||
|
||||
wrap_metadata(Metadata, ExtractorOpts) ->
|
||||
MetadataNS = maps:get(metadata_ns, ExtractorOpts),
|
||||
#{MetadataNS => Metadata}.
|
||||
make_metadata(Metadata, ExtractorOpts) ->
|
||||
Mappings = maps:get(metadata_mappings, ExtractorOpts),
|
||||
tk_utils:remap(genlib_map:compact(Metadata), Mappings).
|
||||
|
||||
get_resource_hierarchy() ->
|
||||
#{
|
||||
|
@ -6,7 +6,9 @@
|
||||
%%
|
||||
|
||||
-type extractor_opts() :: #{
|
||||
metadata_ns := binary()
|
||||
metadata_mappings := #{
|
||||
party_id := binary()
|
||||
}
|
||||
}.
|
||||
|
||||
-export_type([extractor_opts/0]).
|
||||
@ -15,20 +17,26 @@
|
||||
|
||||
-spec get_context(tk_token_jwt:t(), extractor_opts()) -> tk_extractor:extracted_context().
|
||||
get_context(Token, ExtractorOpts) ->
|
||||
UserID = tk_token_jwt:get_subject_id(Token),
|
||||
PartyID = tk_token_jwt:get_subject_id(Token),
|
||||
Acc0 = bouncer_context_helpers:empty(),
|
||||
Acc1 = bouncer_context_helpers:add_auth(
|
||||
#{
|
||||
method => <<"ApiKeyToken">>,
|
||||
token => #{id => tk_token_jwt:get_token_id(Token)},
|
||||
scope => [#{party => #{id => UserID}}]
|
||||
scope => [#{party => #{id => PartyID}}]
|
||||
},
|
||||
Acc0
|
||||
),
|
||||
{Acc1, wrap_metadata(#{<<"party_id">> => UserID}, ExtractorOpts)}.
|
||||
{Acc1,
|
||||
make_metadata(
|
||||
#{
|
||||
party_id => PartyID
|
||||
},
|
||||
ExtractorOpts
|
||||
)}.
|
||||
|
||||
%%
|
||||
|
||||
wrap_metadata(Metadata, ExtractorOpts) ->
|
||||
MetadataNS = maps:get(metadata_ns, ExtractorOpts),
|
||||
#{MetadataNS => Metadata}.
|
||||
make_metadata(Metadata, ExtractorOpts) ->
|
||||
Mappings = maps:get(metadata_mappings, ExtractorOpts),
|
||||
tk_utils:remap(genlib_map:compact(Metadata), Mappings).
|
||||
|
@ -6,7 +6,11 @@
|
||||
%%
|
||||
|
||||
-type extractor_opts() :: #{
|
||||
metadata_ns := binary(),
|
||||
metadata_mappings := #{
|
||||
user_id := binary(),
|
||||
user_email := binary(),
|
||||
user_realm := binary()
|
||||
},
|
||||
user_realm := binary()
|
||||
}.
|
||||
|
||||
@ -38,12 +42,12 @@ get_context(Token, ExtractorOpts) ->
|
||||
Acc1
|
||||
),
|
||||
{Acc2,
|
||||
wrap_metadata(
|
||||
genlib_map:compact(#{
|
||||
<<"user_id">> => UserID,
|
||||
<<"user_email">> => Email,
|
||||
<<"user_realm">> => UserRealm
|
||||
}),
|
||||
make_metadata(
|
||||
#{
|
||||
user_id => UserID,
|
||||
user_email => Email,
|
||||
user_realm => UserRealm
|
||||
},
|
||||
ExtractorOpts
|
||||
)}.
|
||||
|
||||
@ -54,6 +58,6 @@ make_auth_expiration(Timestamp) when is_integer(Timestamp) ->
|
||||
make_auth_expiration(Expiration) when Expiration =:= unlimited; Expiration =:= undefined ->
|
||||
undefined.
|
||||
|
||||
wrap_metadata(Metadata, ExtractorOpts) ->
|
||||
MetadataNS = maps:get(metadata_ns, ExtractorOpts),
|
||||
#{MetadataNS => Metadata}.
|
||||
make_metadata(Metadata, ExtractorOpts) ->
|
||||
Mappings = maps:get(metadata_mappings, ExtractorOpts),
|
||||
tk_utils:remap(genlib_map:compact(Metadata), Mappings).
|
||||
|
@ -1,19 +1,19 @@
|
||||
-module(tk_storage).
|
||||
|
||||
-export([get/2]).
|
||||
-export([get_by_claims/2]).
|
||||
-export([store/2]).
|
||||
-export([revoke/2]).
|
||||
|
||||
%%
|
||||
|
||||
-callback get(authdata_id(), opts()) -> {ok, tk_storage:storable_authdata()} | {error, _Reason}.
|
||||
-callback get_by_claims(claims(), opts()) -> {ok, tk_storage:storable_authdata()} | {error, _Reason}.
|
||||
-callback store(tk_storage:storable_authdata(), opts()) -> {ok, claims()} | {error, _Reason}.
|
||||
-callback revoke(authdata_id(), opts()) -> ok | {error, _Reason}.
|
||||
|
||||
%%
|
||||
|
||||
-type storage_opts() :: {storage(), opts()} | storage().
|
||||
|
||||
-type storable_authdata() :: #{
|
||||
id => tk_authority:authdata_id(),
|
||||
status := tk_authority:status(),
|
||||
@ -23,15 +23,15 @@
|
||||
}.
|
||||
|
||||
-export_type([storable_authdata/0]).
|
||||
-export_type([storage_opts/0]).
|
||||
|
||||
%%
|
||||
|
||||
-type authdata_id() :: tk_authority:authdata_id().
|
||||
-type claims() :: tk_token_jwt:claims().
|
||||
|
||||
-type storage_opts() :: {storage(), opts()} | storage().
|
||||
-type storage() :: claim.
|
||||
-type opts() :: tk_storage_claim:storage_opts().
|
||||
-type storage() :: machinegun.
|
||||
-type opts() :: tk_storage_machinegun:storage_opts().
|
||||
|
||||
%%
|
||||
|
||||
@ -41,12 +41,6 @@ get(DataID, StorageOpts) ->
|
||||
Handler = get_storage_handler(Storage),
|
||||
Handler:get(DataID, Opts).
|
||||
|
||||
-spec get_by_claims(claims(), storage_opts()) -> {ok, storable_authdata()} | {error, _Reason}.
|
||||
get_by_claims(Claims, StorageOpts) ->
|
||||
{Storage, Opts} = get_storage_opts(StorageOpts),
|
||||
Handler = get_storage_handler(Storage),
|
||||
Handler:get_by_claims(Claims, Opts).
|
||||
|
||||
-spec store(storable_authdata(), storage_opts()) -> {ok, claims()} | {error, _Reason}.
|
||||
store(AuthData, StorageOpts) ->
|
||||
{Storage, Opts} = get_storage_opts(StorageOpts),
|
||||
@ -61,8 +55,8 @@ revoke(DataID, StorageOpts) ->
|
||||
|
||||
%%
|
||||
|
||||
get_storage_handler(claim) ->
|
||||
tk_storage_claim.
|
||||
get_storage_handler(machinegun) ->
|
||||
tk_storage_machinegun.
|
||||
|
||||
get_storage_opts({_Storage, _Opts} = StorageOpts) ->
|
||||
StorageOpts;
|
||||
|
@ -1,23 +1,27 @@
|
||||
-module(tk_storage_claim).
|
||||
-module(tk_token_claim_utils).
|
||||
|
||||
-include_lib("token_keeper_proto/include/tk_context_thrift.hrl").
|
||||
|
||||
-behaviour(tk_storage).
|
||||
-export([get/2]).
|
||||
-export([get_by_claims/2]).
|
||||
-export([store/2]).
|
||||
-export([revoke/2]).
|
||||
-export([decode_authdata/2]).
|
||||
-export([encode_authdata/1]).
|
||||
|
||||
-type storage_opts() :: #{
|
||||
compatability => {true, MetadataNS :: binary()} | false
|
||||
-type decode_opts() :: #{
|
||||
compatibility => {true, compatibility_opts()} | false
|
||||
}.
|
||||
|
||||
-export_type([storage_opts/0]).
|
||||
-type compatibility_opts() :: #{
|
||||
metadata_mappings := #{
|
||||
party_id := binary(),
|
||||
token_consumer := binary()
|
||||
}
|
||||
}.
|
||||
|
||||
-export_type([decode_opts/0]).
|
||||
-export_type([compatibility_opts/0]).
|
||||
|
||||
%%
|
||||
|
||||
-type storable_authdata() :: tk_storage:storable_authdata().
|
||||
-type authdata_id() :: tk_authority:authdata_id().
|
||||
-type claim() :: tk_token_jwt:claim().
|
||||
-type claims() :: tk_token_jwt:claims().
|
||||
|
||||
@ -30,14 +34,10 @@
|
||||
|
||||
%%
|
||||
|
||||
-spec get(authdata_id(), storage_opts()) -> {error, not_found}.
|
||||
get(_DataID, _Opts) ->
|
||||
{error, not_found}.
|
||||
|
||||
-spec get_by_claims(claims(), storage_opts()) ->
|
||||
-spec decode_authdata(claims(), decode_opts()) ->
|
||||
{ok, storable_authdata()}
|
||||
| {error, not_found | {claim_decode_error, {unsupported, claim()} | {malformed, binary()}}}.
|
||||
get_by_claims(#{?CLAIM_BOUNCER_CTX := BouncerClaim} = Claims, Opts) ->
|
||||
decode_authdata(#{?CLAIM_BOUNCER_CTX := BouncerClaim} = Claims, Opts) ->
|
||||
case decode_bouncer_claim(BouncerClaim) of
|
||||
{ok, ContextFragment} ->
|
||||
case get_metadata(Claims, Opts) of
|
||||
@ -49,21 +49,17 @@ get_by_claims(#{?CLAIM_BOUNCER_CTX := BouncerClaim} = Claims, Opts) ->
|
||||
{error, Reason} ->
|
||||
{error, {claim_decode_error, Reason}}
|
||||
end;
|
||||
get_by_claims(_Claims, _Opts) ->
|
||||
decode_authdata(_Claims, _Opts) ->
|
||||
{error, not_found}.
|
||||
|
||||
-spec store(storable_authdata(), storage_opts()) -> {ok, claims()}.
|
||||
store(#{context := ContextFragment} = AuthData, _Opts) ->
|
||||
{ok, #{
|
||||
-spec encode_authdata(storable_authdata()) -> claims().
|
||||
encode_authdata(#{context := ContextFragment} = AuthData) ->
|
||||
#{
|
||||
?CLAIM_BOUNCER_CTX => encode_bouncer_claim(ContextFragment),
|
||||
?CLAIM_TK_METADATA => encode_metadata(AuthData)
|
||||
}}.
|
||||
}.
|
||||
|
||||
-spec revoke(authdata_id(), storage_opts()) -> {error, storage_immutable}.
|
||||
revoke(_DataID, _Opts) ->
|
||||
{error, storage_immutable}.
|
||||
|
||||
%% Internal functions
|
||||
%%
|
||||
|
||||
decode_bouncer_claim(#{
|
||||
?CLAIM_CTX_TYPE := ?CLAIM_CTX_TYPE_V1_THRIFT_BINARY,
|
||||
@ -101,8 +97,8 @@ encode_metadata(#{}) ->
|
||||
|
||||
get_metadata(#{?CLAIM_TK_METADATA := Metadata}, _Opts) ->
|
||||
{ok, Metadata};
|
||||
get_metadata(Claims, #{compatability := {true, MetadataNS}}) ->
|
||||
{ok, wrap_metadata(create_metadata(Claims), MetadataNS)};
|
||||
get_metadata(Claims, #{compatibility := {true, CompatOpts}}) ->
|
||||
{ok, create_metadata(Claims, CompatOpts)};
|
||||
get_metadata(_Claims, _Opts) ->
|
||||
{error, no_metadata_claim}.
|
||||
|
||||
@ -113,21 +109,11 @@ create_authdata(ContextFragment, Metadata) ->
|
||||
metadata => Metadata
|
||||
}).
|
||||
|
||||
create_metadata(Claims) ->
|
||||
Metadata = maps:with(get_passthrough_claim_names(), Claims),
|
||||
%% TODO: This is a temporary hack.
|
||||
%% When some external services will stop requiring woody user identity to be present it must be removed too
|
||||
genlib_map:compact(Metadata#{
|
||||
<<"party_id">> => maps:get(<<"sub">>, Claims, undefined)
|
||||
}).
|
||||
|
||||
wrap_metadata(Metadata, _MetadataNS) when map_size(Metadata) =:= 0 ->
|
||||
undefined;
|
||||
wrap_metadata(Metadata, MetadataNS) ->
|
||||
#{MetadataNS => Metadata}.
|
||||
|
||||
get_passthrough_claim_names() ->
|
||||
[
|
||||
%% token consumer
|
||||
<<"cons">>
|
||||
].
|
||||
create_metadata(Claims, CompatOpts) ->
|
||||
Metadata = #{
|
||||
%% TODO: This is a temporary hack.
|
||||
%% When some external services will stop requiring woody user identity to be present it must be removed too
|
||||
party_id => maps:get(<<"sub">>, Claims, undefined),
|
||||
consumer => maps:get(<<"cons">>, Claims, undefined)
|
||||
},
|
||||
tk_utils:remap(genlib_map:compact(Metadata), maps:get(metadata_mappings, CompatOpts)).
|
64
src/tk_utils.erl
Normal file
64
src/tk_utils.erl
Normal file
@ -0,0 +1,64 @@
|
||||
-module(tk_utils).
|
||||
|
||||
-export([remap/2]).
|
||||
|
||||
-spec remap(Map :: map(), KeyMap :: map()) -> map().
|
||||
remap(Map, KeyMap) ->
|
||||
maps:fold(
|
||||
fun(Key, Value, Acc) ->
|
||||
case maps:get(Key, KeyMap, undefined) of
|
||||
NewKey when NewKey =/= undefined ->
|
||||
Acc#{NewKey => Value};
|
||||
undefined ->
|
||||
error({badarg, {no_mapping, Key}})
|
||||
end
|
||||
end,
|
||||
maps:new(),
|
||||
Map
|
||||
).
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec remap_test() -> _.
|
||||
remap_test() ->
|
||||
?assertEqual(
|
||||
#{
|
||||
<<"a">> => a,
|
||||
<<"b">> => b,
|
||||
<<"c">> => c
|
||||
},
|
||||
remap(
|
||||
#{
|
||||
a => a,
|
||||
b => b,
|
||||
c => c
|
||||
},
|
||||
#{
|
||||
a => <<"a">>,
|
||||
b => <<"b">>,
|
||||
c => <<"c">>
|
||||
}
|
||||
)
|
||||
).
|
||||
|
||||
-spec remap_no_mapping_test() -> _.
|
||||
remap_no_mapping_test() ->
|
||||
?assertError(
|
||||
{badarg, {no_mapping, c}},
|
||||
remap(
|
||||
#{
|
||||
a => a,
|
||||
b => b,
|
||||
c => c
|
||||
},
|
||||
#{
|
||||
a => <<"a">>,
|
||||
b => <<"b">>
|
||||
}
|
||||
)
|
||||
).
|
||||
|
||||
-endif.
|
@ -34,8 +34,8 @@ handle_function_('CreateEphemeral' = Op, {ContextFragment, Metadata}, State) ->
|
||||
_ = handle_beat(Op, started, State),
|
||||
Authority = get_autority_config(get_issuing_authority()),
|
||||
AuthData = issue_auth_data(ContextFragment, Metadata, Authority),
|
||||
{ok, StorageClaims} = tk_storage:store(AuthData, claim),
|
||||
{ok, Token} = tk_token_jwt:issue(unique_id(), StorageClaims, get_signer(Authority)),
|
||||
Claims = tk_token_claim_utils:encode_authdata(AuthData),
|
||||
{ok, Token} = tk_token_jwt:issue(unique_id(), Claims, get_signer(Authority)),
|
||||
EncodedAuthData = encode_auth_data(AuthData#{token => Token}),
|
||||
_ = handle_beat(Op, succeeded, State),
|
||||
{ok, EncodedAuthData};
|
||||
|
@ -37,20 +37,17 @@
|
||||
|
||||
-define(CONFIG(Key, C), (element(2, lists:keyfind(Key, 1, C)))).
|
||||
|
||||
-define(TK_META_NS_KEYCLOAK, <<"test.rbkmoney.token-keeper">>).
|
||||
-define(TK_META_NS_APIKEYMGMT, <<"test.rbkmoney.apikeymgmt">>).
|
||||
-define(META_PARTY_ID, <<"test.rbkmoney.party.id">>).
|
||||
-define(META_USER_ID, <<"test.rbkmoney.user.id">>).
|
||||
-define(META_USER_EMAIL, <<"test.rbkmoney.user.email">>).
|
||||
-define(META_USER_REALM, <<"test.rbkmoney.user.realm">>).
|
||||
-define(META_CAPI_CONSUMER, <<"test.rbkmoney.capi.consumer">>).
|
||||
|
||||
-define(TK_AUTHORITY_KEYCLOAK, <<"test.rbkmoney.keycloak">>).
|
||||
-define(TK_AUTHORITY_CAPI, <<"test.rbkmoney.capi">>).
|
||||
|
||||
-define(TK_RESOURCE_DOMAIN, <<"test-domain">>).
|
||||
|
||||
-define(METADATA(Authority, Metadata), #{Authority := Metadata}).
|
||||
-define(PARTY_METADATA(Authority, SubjectID), ?METADATA(Authority, #{<<"party_id">> := SubjectID})).
|
||||
-define(USER_METADATA(Authority, SubjectID, Email),
|
||||
?METADATA(Authority, #{<<"user_id">> := SubjectID, <<"user_email">> := Email})
|
||||
).
|
||||
|
||||
-define(TOKEN_SOURCE_CONTEXT(), ?TOKEN_SOURCE_CONTEXT(<<"http://spanish.inquisition">>)).
|
||||
-define(TOKEN_SOURCE_CONTEXT(SourceURL), #token_keeper_TokenSourceContext{request_origin = SourceURL}).
|
||||
|
||||
@ -131,11 +128,17 @@ init_per_group(detect_token_type = Name, C) ->
|
||||
methods => [
|
||||
{detect_token, #{
|
||||
phony_api_key_opts => #{
|
||||
metadata_ns => ?TK_META_NS_APIKEYMGMT
|
||||
metadata_mappings => #{
|
||||
party_id => ?META_PARTY_ID
|
||||
}
|
||||
},
|
||||
user_session_token_opts => #{
|
||||
user_realm => <<"external">>,
|
||||
metadata_ns => ?TK_META_NS_KEYCLOAK
|
||||
metadata_mappings => #{
|
||||
user_id => ?META_USER_ID,
|
||||
user_email => ?META_USER_EMAIL,
|
||||
user_realm => ?META_USER_REALM
|
||||
}
|
||||
},
|
||||
user_session_token_origins => [?USER_TOKEN_SOURCE]
|
||||
}}
|
||||
@ -160,10 +163,15 @@ init_per_group(claim_only = Name, C) ->
|
||||
claim_only => #{
|
||||
id => ?TK_AUTHORITY_CAPI,
|
||||
authdata_sources => [
|
||||
{storage,
|
||||
{claim, #{
|
||||
compatability => {true, ?TK_META_NS_APIKEYMGMT}
|
||||
}}}
|
||||
{claim, #{
|
||||
compatibility =>
|
||||
{true, #{
|
||||
metadata_mappings => #{
|
||||
party_id => ?META_PARTY_ID,
|
||||
consumer => ?META_CAPI_CONSUMER
|
||||
}
|
||||
}}
|
||||
}}
|
||||
]
|
||||
}
|
||||
}}
|
||||
@ -183,15 +191,22 @@ init_per_group(invoice_template_access_token = Name, C) ->
|
||||
invoice_tpl_authority => #{
|
||||
id => ?TK_AUTHORITY_CAPI,
|
||||
authdata_sources => [
|
||||
{storage,
|
||||
{claim, #{
|
||||
compatability => {true, ?TK_META_NS_APIKEYMGMT}
|
||||
}}},
|
||||
{claim, #{
|
||||
compatibility =>
|
||||
{true, #{
|
||||
metadata_mappings => #{
|
||||
party_id => ?META_PARTY_ID,
|
||||
token_consumer => ?META_CAPI_CONSUMER
|
||||
}
|
||||
}}
|
||||
}},
|
||||
{extract, #{
|
||||
methods => [
|
||||
{invoice_template_access_token, #{
|
||||
domain => ?TK_RESOURCE_DOMAIN,
|
||||
metadata_ns => ?TK_META_NS_APIKEYMGMT
|
||||
metadata_mappings => #{
|
||||
party_id => ?META_PARTY_ID
|
||||
}
|
||||
}}
|
||||
]
|
||||
}}
|
||||
@ -218,7 +233,7 @@ init_per_group(issuing = Name, C) ->
|
||||
id => ?TK_AUTHORITY_CAPI,
|
||||
signer => test,
|
||||
authdata_sources => [
|
||||
{storage, claim}
|
||||
claim
|
||||
]
|
||||
}
|
||||
}}
|
||||
@ -340,7 +355,7 @@ detect_api_key_test(C) ->
|
||||
token = Token,
|
||||
status = active,
|
||||
context = Context,
|
||||
metadata = ?PARTY_METADATA(?TK_META_NS_APIKEYMGMT, SubjectID),
|
||||
metadata = #{?META_PARTY_ID := SubjectID},
|
||||
authority = ?TK_AUTHORITY_KEYCLOAK
|
||||
} = call_get_by_token(Token, ?TOKEN_SOURCE_CONTEXT(), Client),
|
||||
_ = assert_context({api_key_token, JTI, SubjectID}, Context).
|
||||
@ -357,7 +372,11 @@ detect_user_session_token_test(C) ->
|
||||
token = Token,
|
||||
status = active,
|
||||
context = Context,
|
||||
metadata = ?USER_METADATA(?TK_META_NS_KEYCLOAK, SubjectID, SubjectEmail),
|
||||
metadata = #{
|
||||
?META_USER_ID := SubjectID,
|
||||
?META_USER_EMAIL := SubjectEmail,
|
||||
?META_USER_REALM := <<"external">>
|
||||
},
|
||||
authority = ?TK_AUTHORITY_KEYCLOAK
|
||||
} = call_get_by_token(Token, ?TOKEN_SOURCE_CONTEXT(?USER_TOKEN_SOURCE), Client),
|
||||
_ = assert_context({user_session_token, JTI, SubjectID, SubjectEmail, unlimited}, Context).
|
||||
@ -389,7 +408,7 @@ bouncer_context_from_claims_test(C) ->
|
||||
token = Token,
|
||||
status = active,
|
||||
context = Context,
|
||||
metadata = ?PARTY_METADATA(?TK_META_NS_APIKEYMGMT, SubjectID),
|
||||
metadata = #{?META_PARTY_ID := SubjectID},
|
||||
authority = ?TK_AUTHORITY_CAPI
|
||||
} = call_get_by_token(Token, ?TOKEN_SOURCE_CONTEXT(), Client),
|
||||
_ = assert_context({claim_token, JTI}, Context).
|
||||
@ -405,7 +424,7 @@ cons_claim_passthrough_test(C) ->
|
||||
token = Token,
|
||||
status = active,
|
||||
context = Context,
|
||||
metadata = ?METADATA(?TK_META_NS_APIKEYMGMT, #{<<"party_id">> := SubjectID, <<"cons">> := <<"client">>}),
|
||||
metadata = #{?META_PARTY_ID := SubjectID, ?META_CAPI_CONSUMER := <<"client">>},
|
||||
authority = ?TK_AUTHORITY_CAPI
|
||||
} = call_get_by_token(Token, ?TOKEN_SOURCE_CONTEXT(), Client),
|
||||
_ = assert_context({claim_token, JTI}, Context).
|
||||
@ -436,7 +455,7 @@ invoice_template_access_token_ok_test(C) ->
|
||||
token = Token,
|
||||
status = active,
|
||||
context = Context,
|
||||
metadata = ?PARTY_METADATA(?TK_META_NS_APIKEYMGMT, SubjectID),
|
||||
metadata = #{?META_PARTY_ID := SubjectID},
|
||||
authority = ?TK_AUTHORITY_CAPI
|
||||
} = call_get_by_token(Token, ?TOKEN_SOURCE_CONTEXT(), Client),
|
||||
_ = assert_context({invoice_template_access_token, JTI, SubjectID, InvoiceTemplateID}, Context).
|
||||
@ -482,7 +501,7 @@ basic_issuing_test(C) ->
|
||||
type = v1_thrift_binary,
|
||||
content = BinaryContextFragment
|
||||
},
|
||||
Metadata = #{<<"ns">> => #{<<"my">> => <<"metadata">>}},
|
||||
Metadata = #{<<"my">> => <<"metadata">>},
|
||||
#token_keeper_AuthData{
|
||||
id = undefined,
|
||||
token = Token,
|
||||
|
Loading…
Reference in New Issue
Block a user