diff --git a/apps/capi/src/capi_auth.erl b/apps/capi/src/capi_auth.erl index ee8bf73..9436693 100644 --- a/apps/capi/src/capi_auth.erl +++ b/apps/capi/src/capi_auth.erl @@ -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} -> diff --git a/apps/capi/src/capi_bouncer.erl b/apps/capi/src/capi_bouncer.erl index 5bd4a4d..1816ea7 100644 --- a/apps/capi/src/capi_bouncer.erl +++ b/apps/capi/src/capi_bouncer.erl @@ -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() diff --git a/apps/capi/src/capi_handler.erl b/apps/capi/src/capi_handler.erl index 75a5411..54c2514 100644 --- a/apps/capi/src/capi_handler.erl +++ b/apps/capi/src/capi_handler.erl @@ -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) -> diff --git a/apps/capi/test/capi_ct_helper_token_keeper.erl b/apps/capi/test/capi_ct_helper_token_keeper.erl index 9f88a02..c81e849 100644 --- a/apps/capi/test/capi_ct_helper_token_keeper.erl +++ b/apps/capi/test/capi_ct_helper_token_keeper.erl @@ -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. %% diff --git a/config/sys.config b/config/sys.config index c6b3ff9..9386ac5 100644 --- a/config/sys.config +++ b/config/sys.config @@ -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 => #{} } }} ]}, diff --git a/rebar.lock b/rebar.lock index c6e4125..eebbd6e 100644 --- a/rebar.lock +++ b/rebar.lock @@ -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">>,