From fed938679823018a3c08a6e38ccf4397dd7ee51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC?= Date: Tue, 30 Jun 2020 09:00:20 +0300 Subject: [PATCH] FF-195: Ticket expiration check (#243) * added ticket expiration check * minor --- apps/wapi/src/wapi_auth.erl | 5 +++-- apps/wapi/src/wapi_wallet_ff_backend.erl | 28 ++++++++++++++++++++---- apps/wapi/src/wapi_wallet_handler.erl | 8 +++---- apps/wapi/test/wapi_p2p_tests_SUITE.erl | 26 ++++++++++++++++++++++ 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/apps/wapi/src/wapi_auth.erl b/apps/wapi/src/wapi_auth.erl index 4e0ec0c..15c6157 100644 --- a/apps/wapi/src/wapi_auth.erl +++ b/apps/wapi/src/wapi_auth.erl @@ -43,7 +43,7 @@ authorize_operation(OperationID, Req, #{swagger_context := #{auth_context := Aut uac:authorize_operation(OperationACL, AuthContext). -type token_spec() :: - {p2p_templates, P2PTemplateID :: binary()} | + {p2p_templates, P2PTemplateID :: binary(), Data :: map()} | {p2p_template_transfers, P2PTemplateID :: binary(), Data :: map()} | {destinations, DestinationID :: binary()} | {wallets, WalletID :: binary(), Asset :: map()}. @@ -67,8 +67,9 @@ issue_access_token(PartyID, TokenSpec, Expiration) -> -spec resolve_token_spec(token_spec()) -> claims(). -resolve_token_spec({p2p_templates, P2PTemplateID}) -> +resolve_token_spec({p2p_templates, P2PTemplateID, #{<<"expiration">> := Expiration}}) -> #{ + <<"data">> => #{<<"expiration">> => Expiration}, <<"resource_access">> => #{?DOMAIN => uac_acl:from_list( [{[{p2p_templates, P2PTemplateID}, p2p_template_tickets], write}, {[{p2p_templates, P2PTemplateID}], read}] )} diff --git a/apps/wapi/src/wapi_wallet_ff_backend.erl b/apps/wapi/src/wapi_wallet_ff_backend.erl index 04b8689..e3650fe 100644 --- a/apps/wapi/src/wapi_wallet_ff_backend.erl +++ b/apps/wapi/src/wapi_wallet_ff_backend.erl @@ -842,22 +842,32 @@ block_p2p_template(ID, Context) -> issue_p2p_template_access_token(ID, Expiration, Context) -> do(fun () -> _ = check_resource(p2p_template, ID, Context), - unwrap(wapi_backend_utils:issue_grant_token({p2p_templates, ID}, Expiration, Context)) + Data = #{<<"expiration">> => Expiration}, + unwrap(wapi_backend_utils:issue_grant_token({p2p_templates, ID, Data}, Expiration, Context)) end). -spec issue_p2p_transfer_ticket(params(), binary(), ctx()) -> - {ok, binary()} | + {ok, {binary(), binary()}} | {error, expired | p2p_template_machine:unknown_p2p_template_error() }. -issue_p2p_transfer_ticket(ID, Expiration, Context = #{woody_context := WoodyCtx}) -> +issue_p2p_transfer_ticket(ID, Expiration0, Context = #{woody_context := WoodyCtx}) -> do(fun () -> + {_, _, Claims} = wapi_handler_utils:get_auth_context(Context), + AccessData = maps:get(<<"data">>, Claims), + AccessExpiration = maps:get(<<"expiration">>, AccessData), PartyID = wapi_handler_utils:get_owner(Context), Key = bender_client:get_idempotent_key(<<"issue_p2p_transfer_ticket">>, ticket, PartyID, undefined), {ok, TransferID} = bender_client:gen_by_snowflake(Key, 0, WoodyCtx), Data = #{<<"transferID">> => TransferID}, - unwrap(wapi_backend_utils:issue_grant_token({p2p_template_transfers, ID, Data}, Expiration, Context)) + Expiration1 = choose_token_expiration(Expiration0, AccessExpiration), + case wapi_backend_utils:issue_grant_token({p2p_template_transfers, ID, Data}, Expiration1, Context) of + {ok, Token} -> + {Token, Expiration1}; + {error, Error} -> + throw(Error) + end end). -spec create_p2p_transfer_with_template(id(), params(), ctx()) -> result(map(), @@ -958,6 +968,16 @@ get_w2w_transfer(ID, Context) -> %% Internal functions +choose_token_expiration(TicketExpiration, AccessExpiration) -> + TicketMs = woody_deadline:to_unixtime_ms(woody_deadline:from_binary(TicketExpiration)), + AccessMs = woody_deadline:to_unixtime_ms(woody_deadline:from_binary(AccessExpiration)), + case TicketMs > AccessMs of + true -> + AccessExpiration; + false -> + TicketExpiration + end. + construct_resource(#{<<"type">> := Type, <<"token">> := Token} = Resource) when Type =:= <<"BankCardDestinationResource">> -> case wapi_crypto:decrypt_bankcard_token(Token) of diff --git a/apps/wapi/src/wapi_wallet_handler.erl b/apps/wapi/src/wapi_wallet_handler.erl index 4ea940d..0bee21c 100644 --- a/apps/wapi/src/wapi_wallet_handler.erl +++ b/apps/wapi/src/wapi_wallet_handler.erl @@ -721,13 +721,13 @@ process_request('IssueP2PTransferTemplateAccessToken', #{ end; process_request('IssueP2PTransferTicket', #{ p2pTransferTemplateID := ID, - 'P2PTransferTemplateTokenRequest' := #{<<"validUntil">> := Expiration} + 'P2PTransferTemplateTokenRequest' := #{<<"validUntil">> := Expiration0} }, Context, _Opts) -> - case wapi_wallet_ff_backend:issue_p2p_transfer_ticket(ID, Expiration, Context) of - {ok, Token} -> + case wapi_wallet_ff_backend:issue_p2p_transfer_ticket(ID, Expiration0, Context) of + {ok, {Token, Expiration1}} -> wapi_handler_utils:reply_ok(201, #{ <<"token">> => Token, - <<"validUntil">> => Expiration + <<"validUntil">> => Expiration1 }); {error, expired} -> wapi_handler_utils:reply_ok(422, diff --git a/apps/wapi/test/wapi_p2p_tests_SUITE.erl b/apps/wapi/test/wapi_p2p_tests_SUITE.erl index acd9d9c..8b55b63 100644 --- a/apps/wapi/test/wapi_p2p_tests_SUITE.erl +++ b/apps/wapi/test/wapi_p2p_tests_SUITE.erl @@ -32,6 +32,7 @@ block_p2p_template_ok_test/1, issue_p2p_template_access_token_ok_test/1, issue_p2p_transfer_ticket_ok_test/1, + issue_p2p_transfer_ticket_with_access_expiration_ok_test/1, create_p2p_transfer_with_template_ok_test/1, create_p2p_transfer_with_template_conflict_test/1, create_p2p_transfer_with_template_and_quote_ok_test/1 @@ -83,6 +84,7 @@ groups() -> block_p2p_template_ok_test, issue_p2p_template_access_token_ok_test, issue_p2p_transfer_ticket_ok_test, + issue_p2p_transfer_ticket_with_access_expiration_ok_test, create_p2p_transfer_with_template_ok_test, create_p2p_transfer_with_template_conflict_test, create_p2p_transfer_with_template_and_quote_ok_test @@ -606,6 +608,27 @@ issue_p2p_transfer_ticket_ok_test(C) -> wapi_ct_helper:get_context(TemplateToken) ). +-spec issue_p2p_transfer_ticket_with_access_expiration_ok_test(config()) -> + _. +issue_p2p_transfer_ticket_with_access_expiration_ok_test(C) -> + IdentityID = create_identity(C), + TemplateID = create_p2p_template(IdentityID, C), + AccessValidUntil = woody_deadline:to_binary(woody_deadline:from_timeout(100000)), + TemplateToken = issue_p2p_template_access_token(TemplateID, AccessValidUntil, C), + ValidUntil = woody_deadline:to_binary(woody_deadline:from_timeout(200000)), + {ok, #{<<"token">> := _Token, <<"validUntil">> := AccessValidUntil}} = call_api( + fun swag_client_wallet_p2_p_templates_api:issue_p2_p_transfer_ticket/3, + #{ + binding => #{ + <<"p2pTransferTemplateID">> => TemplateID + }, + body => #{ + <<"validUntil">> => ValidUntil + } + }, + wapi_ct_helper:get_context(TemplateToken) + ). + -spec create_p2p_transfer_with_template_ok_test(config()) -> _. create_p2p_transfer_with_template_ok_test(C) -> @@ -954,6 +977,9 @@ create_p2p_template(IdentityID, C) -> issue_p2p_template_access_token(TemplateID, C) -> ValidUntil = woody_deadline:to_binary(woody_deadline:from_timeout(100000)), + issue_p2p_template_access_token(TemplateID, ValidUntil, C). + +issue_p2p_template_access_token(TemplateID, ValidUntil, C) -> {ok, #{<<"token">> := TemplateToken}} = call_api( fun swag_client_wallet_p2_p_templates_api:issue_p2_p_transfer_template_access_token/3, #{