ED-332: Update token keeper client (#584)

This commit is contained in:
Alexey S 2021-12-21 14:33:32 +03:00 committed by GitHub
parent 8381da653a
commit 35edff0a8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 126 additions and 61 deletions

View File

@ -18,7 +18,7 @@
-type token_type() :: bearer.
-type preauth_context() :: {unauthorized, {token_type(), token_keeper_client:token()}}.
-type auth_context() :: {authorized, token_keeper_auth_data:auth_data()}.
-type auth_context() :: {authorized, token_keeper_client:auth_data()}.
-type resolution() :: allowed | forbidden.
-type consumer() :: client | merchant | provider.
-type token_spec() :: #{
@ -26,7 +26,7 @@
scope := {invoice | invoice_template | customer, binary()},
shop => binary(),
lifetime => pos_integer() | unlimited,
metadata => token_keeper_auth_data:metadata()
metadata => token_keeper_client:metadata()
}.
-export_type([preauth_context/0]).
@ -54,20 +54,20 @@ get_subject_id(AuthContext) ->
end.
-spec get_party_id(auth_context()) -> binary() | undefined.
get_party_id(?authorized(AuthData)) ->
get_metadata(get_metadata_mapped_key(party_id), token_keeper_auth_data:get_metadata(AuthData)).
get_party_id(?authorized(#{metadata := Metadata})) ->
get_metadata(get_metadata_mapped_key(party_id), Metadata).
-spec get_user_id(auth_context()) -> binary() | undefined.
get_user_id(?authorized(AuthData)) ->
get_metadata(get_metadata_mapped_key(user_id), token_keeper_auth_data:get_metadata(AuthData)).
get_user_id(?authorized(#{metadata := Metadata})) ->
get_metadata(get_metadata_mapped_key(user_id), Metadata).
-spec get_user_email(auth_context()) -> binary() | undefined.
get_user_email(?authorized(AuthData)) ->
get_metadata(get_metadata_mapped_key(user_email), token_keeper_auth_data:get_metadata(AuthData)).
get_user_email(?authorized(#{metadata := Metadata})) ->
get_metadata(get_metadata_mapped_key(user_email), Metadata).
-spec get_consumer(auth_context()) -> consumer().
get_consumer(?authorized(AuthData)) ->
case get_metadata(get_metadata_mapped_key(token_consumer), token_keeper_auth_data:get_metadata(AuthData)) of
get_consumer(?authorized(#{metadata := Metadata})) ->
case get_metadata(get_metadata_mapped_key(token_consumer), Metadata) of
<<"merchant">> -> merchant;
<<"client">> -> client;
<<"provider">> -> provider;
@ -85,7 +85,7 @@ preauthorize_api_key(ApiKey) ->
{error, Error}
end.
-spec authorize_api_key(preauth_context(), token_keeper_client:source_context(), woody_context:ctx()) ->
-spec authorize_api_key(preauth_context(), token_keeper_client:token_context(), woody_context:ctx()) ->
{ok, auth_context()} | {error, _Reason}.
authorize_api_key(?unauthorized({TokenType, Token}), TokenContext, WoodyContext) ->
authorize_token_by_type(TokenType, Token, TokenContext, WoodyContext).
@ -113,9 +113,12 @@ authorize_operation(Prototypes, ProcessingContext) ->
issue_access_token(TokenSpec, WoodyContext) ->
ContextFragment = create_context_fragment(TokenSpec),
Metadata = create_metadata(TokenSpec),
%%TODO InvoiceTemplateAccessTokens are technically not ephemeral and should become so in the future
AuthData = token_keeper_client:create_ephemeral(ContextFragment, Metadata, WoodyContext),
token_keeper_auth_data:get_token(AuthData).
AuthorityID = get_authority_id(TokenSpec),
%% @TODO for now access tokens are only ephemeral, fix this for compact stuff
% %%TODO InvoiceTemplateAccessTokens are technically not ephemeral and should become so in the future
AuthClient = token_keeper_client:ephemeral_authority(AuthorityID, WoodyContext),
{ok, #{token := Token}} = token_keeper_authority_ephemeral:create(ContextFragment, Metadata, AuthClient),
Token.
%%
%% Internal functions
@ -194,14 +197,22 @@ create_metadata(TokenSpec) ->
Metadata1 = put_metadata(get_metadata_mapped_key(party_id), PartyID, Metadata0),
put_metadata(get_metadata_mapped_key(token_consumer), <<"client">>, Metadata1).
get_authority_id(#{scope := {invoice, _}}) ->
access_invoice;
get_authority_id(#{scope := {invoice_template, _}}) ->
access_invoice_template;
get_authority_id(#{scope := {customer, _}}) ->
access_customer.
extract_auth_context(#{swagger_context := #{auth_context := AuthContext}}) ->
AuthContext.
get_token_keeper_fragment(?authorized(AuthData)) ->
token_keeper_auth_data:get_context_fragment(AuthData).
get_token_keeper_fragment(?authorized(#{context := Context})) ->
Context.
authorize_token_by_type(bearer, Token, TokenContext, WoodyContext) ->
case token_keeper_client:get_by_token(Token, TokenContext, WoodyContext) of
Authenticator = token_keeper_client:authenticator(WoodyContext),
case token_keeper_authenticator:authenticate(Token, TokenContext, Authenticator) of
{ok, AuthData} ->
{ok, ?authorized(AuthData)};
{error, TokenKeeperError} ->

View File

@ -8,7 +8,7 @@
%%
-spec gather_context_fragments(
TokenContextFragment :: token_keeper_auth_data:context_fragment(),
TokenContextFragment :: token_keeper_client:context_fragment(),
UserID :: binary() | undefined,
RequestContext :: swag_server:request_context(),
WoodyContext :: woody_context:ctx()

View File

@ -225,7 +225,7 @@ make_token_context(#{cowboy_req := CowboyReq}) ->
Origin when is_binary(Origin) ->
#{request_origin => Origin};
undefined ->
undefined
#{}
end.
create_processing_context(OperationID, SwaggerContext, WoodyContext, HandlerOpts) ->

View File

@ -12,7 +12,7 @@
-type sup_or_config() :: capi_ct_helper:sup_or_config().
-type app_name() :: capi_ct_helper:app_name().
-type token_handler() :: fun(('GetByToken', tuple()) -> term() | no_return()).
-type token_handler() :: fun(('Authenticate' | 'Create', tuple()) -> term() | no_return()).
-export([mock_token/2]).
-export([mock_not_found/1]).
@ -21,7 +21,6 @@
-export([mock_invoice_access_token/3]).
-export([mock_invoice_template_access_token/3]).
-export([mock_customer_access_token/3]).
-export([make_token_handler/1]).
-spec mock_token(token_handler(), sup_or_config()) -> list(app_name()).
mock_token(HandlerFun, SupOrConfig) ->
@ -29,9 +28,14 @@ mock_token(HandlerFun, SupOrConfig) ->
capi_ct_helper:mock_services_(
[
{
token_keeper,
{tk_token_keeper_thrift, 'TokenKeeper'},
token_authenticator,
{tk_token_keeper_thrift, 'TokenAuthenticator'},
HandlerFun
},
{
ephememeral_token_authority,
{tk_token_keeper_thrift, 'EphemeralTokenAuthority'},
make_authority_handler()
}
],
SupOrConfig
@ -40,8 +44,24 @@ mock_token(HandlerFun, SupOrConfig) ->
start_client(ServiceURLs) ->
capi_ct_helper:start_app(token_keeper_client, [
{service_client, #{
url => maps:get(token_keeper, ServiceURLs)
{service_clients, #{
authenticator => #{
url => maps:get(token_authenticator, ServiceURLs)
},
authorities => #{
ephemeral => #{
access_customer => #{
url => maps:get(ephememeral_token_authority, ServiceURLs)
},
access_invoice => #{
url => maps:get(ephememeral_token_authority, ServiceURLs)
},
access_invoice_template => #{
url => maps:get(ephememeral_token_authority, ServiceURLs)
}
},
offline => #{}
}
}}
]).
@ -49,11 +69,11 @@ start_client(ServiceURLs) ->
-spec mock_not_found(sup_or_config()) -> list(app_name()).
mock_not_found(SupOrConfig) ->
mock_token(fun('GetByToken', {_, _}) -> {throwing, #token_keeper_AuthDataNotFound{}} end, SupOrConfig).
mock_token(fun('Authenticate', {_, _}) -> {throwing, #token_keeper_AuthDataNotFound{}} end, SupOrConfig).
-spec mock_user_session_token(sup_or_config()) -> list(app_name()).
mock_user_session_token(SupOrConfig) ->
Handler = make_token_handler(fun() ->
Handler = make_authenticator_handler(fun() ->
UserParams = #{
id => ?USER_ID,
realm => #{id => <<"external">>},
@ -70,7 +90,7 @@ mock_user_session_token(SupOrConfig) ->
-spec mock_api_key_token(binary(), sup_or_config()) -> list(app_name()).
mock_api_key_token(PartyID, SupOrConfig) ->
Handler = make_token_handler(fun() ->
Handler = make_authenticator_handler(fun() ->
AuthParams = #{
method => <<"ApiKeyToken">>,
token => #{id => ?STRING},
@ -82,7 +102,7 @@ mock_api_key_token(PartyID, SupOrConfig) ->
-spec mock_invoice_access_token(binary(), binary(), sup_or_config()) -> list(app_name()).
mock_invoice_access_token(PartyID, InvoiceID, SupOrConfig) ->
Handler = make_token_handler(fun() ->
Handler = make_authenticator_handler(fun() ->
AuthParams = #{
method => <<"InvoiceAccessToken">>,
expiration => posix_to_rfc3339(lifetime_to_expiration(?TOKEN_LIFETIME)),
@ -97,7 +117,7 @@ mock_invoice_access_token(PartyID, InvoiceID, SupOrConfig) ->
-spec mock_invoice_template_access_token(binary(), binary(), sup_or_config()) -> list(app_name()).
mock_invoice_template_access_token(PartyID, InvoiceTemplateID, SupOrConfig) ->
Handler = make_token_handler(fun() ->
Handler = make_authenticator_handler(fun() ->
AuthParams = #{
method => <<"InvoiceAccessToken">>,
expiration => posix_to_rfc3339(unlimited),
@ -110,7 +130,7 @@ mock_invoice_template_access_token(PartyID, InvoiceTemplateID, SupOrConfig) ->
-spec mock_customer_access_token(binary(), binary(), sup_or_config()) -> list(app_name()).
mock_customer_access_token(PartyID, CustomerID, SupOrConfig) ->
Handler = make_token_handler(fun() ->
Handler = make_authenticator_handler(fun() ->
AuthParams = #{
method => <<"CustomerAccessToken">>,
expiration => posix_to_rfc3339(lifetime_to_expiration(?TOKEN_LIFETIME)),
@ -123,28 +143,31 @@ mock_customer_access_token(PartyID, CustomerID, SupOrConfig) ->
%%
-spec make_token_handler(function()) -> token_handler().
make_token_handler(Handler) ->
fun
('GetByToken', {Token, _}) ->
{Authority, ContextFragment, Metadata} = Handler(),
AuthData = #token_keeper_AuthData{
token = Token,
status = active,
context = ContextFragment,
authority = Authority,
metadata = combine_metadata(Metadata)
},
{ok, AuthData};
('CreateEphemeral', {ContextFragment, Metadata}) ->
AuthData = #token_keeper_AuthData{
token = ?API_TOKEN,
status = active,
context = ContextFragment,
authority = ?TK_AUTHORITY_APIKEYMGMT,
metadata = Metadata
},
{ok, AuthData}
-spec make_authenticator_handler(function()) -> token_handler().
make_authenticator_handler(Handler) ->
fun('Authenticate', {Token, _}) ->
{Authority, ContextFragment, Metadata} = Handler(),
AuthData = #token_keeper_AuthData{
token = Token,
status = active,
context = ContextFragment,
authority = Authority,
metadata = combine_metadata(Metadata)
},
{ok, AuthData}
end.
-spec make_authority_handler() -> token_handler().
make_authority_handler() ->
fun('Create', {ContextFragment, Metadata}) ->
AuthData = #token_keeper_AuthData{
token = ?API_TOKEN,
status = active,
context = ContextFragment,
authority = ?TK_AUTHORITY_APIKEYMGMT,
metadata = Metadata
},
{ok, AuthData}
end.
%%

View File

@ -185,12 +185,43 @@
]},
{token_keeper_client, [
{service_client, #{
url => <<"http://token-keeper:8022/">>,
timeout => 1000,
retries => #{
'GetByToken' => {linear, 3, 100},
'_' => finish
{service_clients, #{
authenticator => #{
url => <<"http://token-keeper:8022/v2/authenticator">>,
timeout => 1000,
retries => #{
'Authenticate' => {linear, 3, 100},
'_' => finish
}
},
authorities => #{
ephemeral => #{
access_customer => #{
url => <<"http://token-keeper:8022/v2/authority/com.rbkmoney.capi.access.customer">>,
timeout => 1000,
retries => #{
'Create' => {linear, 3, 100},
'_' => finish
}
},
access_invoice => #{
url => <<"http://token-keeper:8022/v2/authority/com.rbkmoney.capi.access.invoice">>,
timeout => 1000,
retries => #{
'Create' => {linear, 3, 100},
'_' => finish
}
},
access_invoice_template => #{
url => <<"http://token-keeper:8022/v2/authority/com.rbkmoney.capi.access.invoicetpl">>,
timeout => 1000,
retries => #{
'Create' => {linear, 3, 100},
'_' => finish
}
}
},
offline => #{}
}
}}
]},

View File

@ -134,11 +134,11 @@
1},
{<<"token_keeper_client">>,
{git,"https://github.com/rbkmoney/token-keeper-client.git",
{ref,"27158ea5d3e3c74f0090f8d2ac3f2ca52ab39584"}},
{ref,"d3673e72c4c3480b4b8ddff85f1450a6ffd5dd34"}},
0},
{<<"token_keeper_proto">>,
{git,"https://github.com/rbkmoney/token-keeper-proto.git",
{ref,"15781716691a72de8c8f065c11c5b08173fc8434"}},
{ref,"8f7016f68692fc8e3141ba0fce2d47b6c8b6102a"}},
1},
{<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1},
{<<"woody">>,