From b8ee977d9d474c6cdf4ae0df3853e4e9e7091950 Mon Sep 17 00:00:00 2001 From: zhanghongtong Date: Thu, 2 Sep 2021 10:44:04 +0800 Subject: [PATCH] feat(authz api): support read cert file for api --- .../emqx_authz/src/emqx_authz_api_sources.erl | 48 +++++++++++++------ .../test/emqx_authz_api_sources_SUITE.erl | 13 ++++- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/apps/emqx_authz/src/emqx_authz_api_sources.erl b/apps/emqx_authz/src/emqx_authz_api_sources.erl index 0ebf5e511..06d5aa859 100644 --- a/apps/emqx_authz/src/emqx_authz_api_sources.erl +++ b/apps/emqx_authz/src/emqx_authz_api_sources.erl @@ -325,7 +325,7 @@ sources(get, _) -> _ -> NSource1#{annotations => #{status => unhealthy}} end, - lists:append(AccIn, [NSource2]); + lists:append(AccIn, [read_cert(NSource2)]); (Source, AccIn) -> lists:append(AccIn, [Source#{annotations => #{status => healthy}}]) end, [], emqx_authz:lookup()), @@ -340,7 +340,7 @@ sources(post, #{body := #{<<"type">> := <<"file">>, <<"rules">> := Rules, <<"ena messgae => atom_to_binary(Reason)}} end; sources(post, #{body := Body}) when is_map(Body) -> - case emqx_authz:update(head, [save_cert(Body)]) of + case emqx_authz:update(head, [write_cert(Body)]) of {ok, _} -> {204}; {error, Reason} -> {400, #{code => <<"BAD_REQUEST">>, @@ -353,7 +353,7 @@ sources(put, #{body := Body}) when is_list(Body) -> Filename = filename:join([emqx:get_config([node, data_dir]), "authorization_rules.conf"]), write_file(Filename, erlang:list_to_bitstring([<> || Rule <- Rules])), #{type => file, enable => Enable, path => Filename}; - _ -> save_cert(Source) + _ -> write_cert(Source) end end || Source <- Body], case emqx_authz:update(replace, NBody) of @@ -392,7 +392,7 @@ source(get, #{bindings := #{type := Type}}) -> _ -> NSource1#{annotations => #{status => unhealthy}} end, - {200, NSource2} + {200, read_cert(NSource2)} end; source(put, #{bindings := #{type := file}, body := #{<<"type">> := <<"file">>, <<"rules">> := Rules, <<"enable">> := Enable}}) -> #{path := Path} = emqx_authz:lookup(file), @@ -404,7 +404,7 @@ source(put, #{bindings := #{type := file}, body := #{<<"type">> := <<"file">>, < messgae => atom_to_binary(Reason)}} end; source(put, #{bindings := #{type := Type}, body := Body}) when is_map(Body) -> - case emqx_authz:update({replace_once, Type}, save_cert(Body)) of + case emqx_authz:update({replace_once, Type}, write_cert(Body)) of {ok, _} -> {204}; {error, not_found_source} -> {404, #{code => <<"NOT_FOUND">>, @@ -431,7 +431,27 @@ move_source(post, #{bindings := #{type := Type}, body := #{<<"position">> := Pos messgae => atom_to_binary(Reason)}} end. -save_cert(#{<<"config">> := #{<<"ssl">> := #{<<"enable">> := true} = SSL} = Config} = Body) -> +read_cert(#{config := #{ssl := #{enable := true} = SSL} = Config} = Source) -> + CaCert = case file:read_file(maps:get(cacertfile, SSL, "")) of + {ok, CaCert0} -> CaCert0; + _ -> "" + end, + Cert = case file:read_file(maps:get(certfile, SSL, "")) of + {ok, Cert0} -> Cert0; + _ -> "" + end, + Key = case file:read_file(maps:get(keyfile, SSL, "")) of + {ok, Key0} -> Key0; + _ -> "" + end, + Source#{config => Config#{ssl => SSL#{cacertfile => CaCert, + certfile => Cert, + keyfile => Key + }} + }; +read_cert(Source) -> Source. + +write_cert(#{<<"config">> := #{<<"ssl">> := #{<<"enable">> := true} = SSL} = Config} = Source) -> CertPath = filename:join([emqx:get_config([node, data_dir]), "certs"]), CaCert = case maps:is_key(<<"cacertfile">>, SSL) of true -> @@ -439,24 +459,24 @@ save_cert(#{<<"config">> := #{<<"ssl">> := #{<<"enable">> := true} = SSL} = Conf maps:get(<<"cacertfile">>, SSL)); false -> "" end, - Cert = case maps:is_key(<<"certfile">>, SSL) of + Cert = case maps:is_key(<<"certfile">>, SSL) of true -> write_file(filename:join([CertPath, "cert-" ++ emqx_rule_id:gen() ++".pem"]), maps:get(<<"certfile">>, SSL)); false -> "" end, - Key = case maps:is_key(<<"keyfile">>, SSL) of + Key = case maps:is_key(<<"keyfile">>, SSL) of true -> write_file(filename:join([CertPath, "key-" ++ emqx_rule_id:gen() ++".pem"]), maps:get(<<"keyfile">>, SSL)); false -> "" end, - Body#{<<"config">> := Config#{<<"ssl">> => SSL#{<<"cacertfile">> => CaCert, - <<"certfile">> => Cert, - <<"keyfile">> => Key} - } - }; -save_cert(Body) -> Body. + Source#{<<"config">> := Config#{<<"ssl">> => SSL#{<<"cacertfile">> => CaCert, + <<"certfile">> => Cert, + <<"keyfile">> => Key} + } + }; +write_cert(Source) -> Source. write_file(Filename, Bytes) -> ok = filelib:ensure_dir(Filename), diff --git a/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl index a7e747069..bb2bb27e4 100644 --- a/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl @@ -126,7 +126,7 @@ init_per_suite(Config) -> ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - ok = emqx_ct_helpers:start_apps([emqx_authz, emqx_dashboard], fun set_special_configs/1), + ok = emqx_ct_helpers:start_apps([emqx_authz, emqx_dashboard], fun set_special_configs/1), {ok, _} = emqx:update_config([authorization, cache, enable], false), {ok, _} = emqx:update_config([authorization, no_match], deny), @@ -208,6 +208,10 @@ t_api(_) -> ?assertMatch(#{<<"type">> := <<"http">>, <<"enable">> := false}, jsx:decode(Result4)), #{<<"config">> := Config} = ?SOURCE2, + + dbg:tracer(),dbg:p(all,c), + dbg:tpl(emqx_authz_api_sources, read_cert, cx), + dbg:tpl(emqx_authz_api_sources, write_cert, cx), {ok, 204, _} = request(put, uri(["authorization", "sources", "mongo"]), ?SOURCE2#{<<"config">> := Config#{<<"ssl">> := #{ <<"enable">> => true, @@ -218,7 +222,12 @@ t_api(_) -> }}}), {ok, 200, Result5} = request(get, uri(["authorization", "sources", "mongo"]), []), ?assertMatch(#{<<"type">> := <<"mongo">>, - <<"config">> := #{<<"ssl">> := #{<<"enable">> := true}} + <<"config">> := #{<<"ssl">> := #{<<"enable">> := true, + <<"cacertfile">> := <<"fake cacert file">>, + <<"certfile">> := <<"fake cert file">>, + <<"keyfile">> := <<"fake key file">>, + <<"verify">> := false + }} }, jsx:decode(Result5)), ?assert(filelib:is_file(filename:join([emqx:get_config([node, data_dir]), "certs", "cacert-fake.pem"]))), ?assert(filelib:is_file(filename:join([emqx:get_config([node, data_dir]), "certs", "cert-fake.pem"]))),