diff --git a/rebar.config b/rebar.config index 063bace..be6d22c 100644 --- a/rebar.config +++ b/rebar.config @@ -60,6 +60,11 @@ {branch, "master"} } }, + {org_management_proto, + {git, "git@github.com:rbkmoney/org-management-proto.git", + {branch, "master"} + } + }, {scoper, {git, "https://github.com/rbkmoney/scoper.git", {branch, "master"} diff --git a/rebar.lock b/rebar.lock index e89d788..17b2c00 100644 --- a/rebar.lock +++ b/rebar.lock @@ -43,6 +43,10 @@ 0}, {<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2}, {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},2}, + {<<"org_management_proto">>, + {git,"git@github.com:rbkmoney/org-management-proto.git", + {ref,"06c5c8430e445cb7874e54358e457cbb5697fc32"}}, + 0}, {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.0">>},3}, {<<"ranch">>,{pkg,<<"ranch">>,<<"1.7.1">>},1}, {<<"recon">>,{pkg,<<"recon">>,<<"2.5.1">>},0}, diff --git a/src/bouncer.erl b/src/bouncer.erl index 46770c9..aa35f15 100644 --- a/src/bouncer.erl +++ b/src/bouncer.erl @@ -54,7 +54,8 @@ init([]) -> transport_opts => get_transport_opts(), shutdown_timeout => get_shutdown_timeout(), event_handler => EventHandlers, - handlers => get_handler_specs(ServiceOpts, AuditPulse), + handlers => + get_handler_specs(ServiceOpts, AuditPulse) ++ get_stub_handler_specs(ServiceOpts), additional_routes => [erl_health_handle:get_route(Healthcheck)] } ), @@ -108,6 +109,17 @@ get_handler_specs(ServiceOpts, AuditPulse) -> } ]. +%% TODO delete after org_management is done +get_stub_handler_specs(ServiceOpts) -> + OrgManagementStub = maps:get(org_management, ServiceOpts, #{}), + [ + { + maps:get(path, OrgManagementStub, <<"/v1/org_management_stub">>), + {{orgmgmt_auth_context_provider_thrift, 'AuthContextProvider'}, + bouncer_org_management_stub} + } + ]. + %% -spec enable_health_logging(erl_health:check()) -> diff --git a/src/bouncer_org_management_stub.erl b/src/bouncer_org_management_stub.erl new file mode 100644 index 0000000..8987379 --- /dev/null +++ b/src/bouncer_org_management_stub.erl @@ -0,0 +1,36 @@ +%% TODO delete after org_management is done +-module(bouncer_org_management_stub). + +-include_lib("org_management_proto/include/orgmgmt_context_thrift.hrl"). +-include_lib("bouncer_proto/include/bouncer_context_v1_thrift.hrl"). + +-behaviour(woody_server_thrift_handler). + +-export([handle_function/4]). + +-define(THRIFT_TYPE, + {struct, struct, {bouncer_context_v1_thrift, 'ContextFragment'}}). + +-spec handle_function(woody:func(), woody:args(), woody_context:ctx(), woody_state:st()) -> + {ok, woody:result()}. +handle_function('GetUserContext', {UserID}, _WoodyCtx, _Opts) -> + ContextFragmentV1 = #bctx_v1_ContextFragment{ + user = #bctx_v1_User{ + id = UserID, + orgs = [#bctx_v1_Organization{ + id = UserID, + owner = #bctx_v1_Entity{id = UserID} + }] + } + }, + {ok, #bctx_ContextFragment{ + type = v1_thrift_binary, + content = encode_context_fragment(ContextFragmentV1) + }}. + +encode_context_fragment(ContextFragment) -> + Codec = thrift_strict_binary_codec:new(), + case thrift_strict_binary_codec:write(Codec, ?THRIFT_TYPE, ContextFragment) of + {ok, Codec1} -> + thrift_strict_binary_codec:close(Codec1) + end. diff --git a/test/bouncer_stub_tests_SUITE.erl b/test/bouncer_stub_tests_SUITE.erl new file mode 100644 index 0000000..1a27e34 --- /dev/null +++ b/test/bouncer_stub_tests_SUITE.erl @@ -0,0 +1,151 @@ +%% TODO delete after org_management is done +-module(bouncer_stub_tests_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). +-include_lib("org_management_proto/include/orgmgmt_context_thrift.hrl"). + +-export([all/0]). +-export([groups/0]). +-export([init_per_suite/1]). +-export([end_per_suite/1]). +-export([init_per_group/2]). +-export([end_per_group/2]). +-export([init_per_testcase/2]). +-export([end_per_testcase/2]). + +-export([orgmgmt_get_user_context_ok/1]). + +-type config() :: ct_helper:config(). +-type group_name() :: atom(). +-type test_case_name() :: atom(). + +-define(CONFIG(Key, C), (element(2, lists:keyfind(Key, 1, C)))). + +%% + +-define(OPA_HOST, "opa"). +-define(OPA_ENDPOINT, {?OPA_HOST, 8181}). +-define(API_RULESET_ID, "authz/api"). + +-spec all() -> + [atom()]. + +all() -> + [ + {group, general} + ]. + +-spec groups() -> + [{group_name(), list(), [test_case_name()]}]. +groups() -> + [ + {general, [parallel], [ + orgmgmt_get_user_context_ok + ]} + ]. + +-spec init_per_suite(config()) -> + config(). + +init_per_suite(C) -> + Apps = + genlib_app:start_application(woody) ++ + genlib_app:start_application_with(scoper, [ + {storage, scoper_storage_logger} + ]), + [{suite_apps, Apps} | C]. + +-spec end_per_suite(config()) -> + ok. +end_per_suite(C) -> + genlib_app:stop_unload_applications(?CONFIG(suite_apps, C)). + +-spec init_per_group(group_name(), config()) -> + config(). +init_per_group(Name, C) when + Name == general +-> + start_bouncer([], C); +init_per_group(_Name, C) -> + C. + +start_bouncer(Env, C) -> + IP = "127.0.0.1", + Port = 8022, + OrgmgmtPath = <<"/v1/org_management_stub">>, + Apps = genlib_app:start_application_with(bouncer, [ + {ip, IP}, + {port, Port}, + {services, #{ + org_management => #{ + path => OrgmgmtPath + } + }} + ] ++ Env), + Services = #{ + org_management => mk_url(IP, Port, OrgmgmtPath) + }, + [{group_apps, Apps}, {service_urls, Services} | C]. + +mk_url(IP, Port, Path) -> + iolist_to_binary(["http://", IP, ":", genlib:to_binary(Port), Path]). + +-spec end_per_group(group_name(), config()) -> + _. +end_per_group(_Name, C) -> + stop_bouncer(C). + +stop_bouncer(C) -> + ct_helper:with_config(group_apps, C, + fun (Apps) -> genlib_app:stop_unload_applications(Apps) end). + +-spec init_per_testcase(atom(), config()) -> + config(). + +init_per_testcase(Name, C) -> + [{testcase, Name} | C]. + +-spec end_per_testcase(atom(), config()) -> + config(). + +end_per_testcase(_Name, _C) -> + ok. + +%% + +-spec orgmgmt_get_user_context_ok(config()) -> _. +orgmgmt_get_user_context_ok(C) -> + Client = mk_client(C), + UserID = <<"UserID">>, + ?assertMatch( + #bctx_ContextFragment{ + type = v1_thrift_binary, + content = _Content + }, + call_orgmgmt(UserID, Client) + ). + +mk_client(C) -> + WoodyCtx = woody_context:new(genlib:to_binary(?CONFIG(testcase, C))), + ServiceURLs = ?CONFIG(service_urls, C), + {WoodyCtx, ServiceURLs}. + +call_orgmgmt(UserID, Client) -> + call(org_management, 'GetUserContext', {UserID}, Client). + +call(ServiceName, Fn, Args, {WoodyCtx, ServiceURLs}) -> + Service = get_service_spec(ServiceName), + Opts = #{ + url => maps:get(ServiceName, ServiceURLs), + event_handler => scoper_woody_event_handler + }, + case woody_client:call({Service, Fn, Args}, Opts, WoodyCtx) of + {ok, Response} -> + Response; + {exception, Exception} -> + throw(Exception) + end. + +get_service_spec(org_management) -> + {orgmgmt_auth_context_provider_thrift, 'AuthContextProvider'}.