feat(authn): support ${cert_pem} placeholder
This commit is contained in:
parent
2f0eb3560b
commit
751f7a24e9
|
@ -28,8 +28,10 @@
|
|||
%% cert
|
||||
-define(VAR_CERT_SUBJECT, "cert_subject").
|
||||
-define(VAR_CERT_CN_NAME, "cert_common_name").
|
||||
-define(VAR_CERT_PEM, "cert_pem").
|
||||
-define(PH_CERT_SUBJECT, ?PH(?VAR_CERT_SUBJECT)).
|
||||
-define(PH_CERT_CN_NAME, ?PH(?VAR_CERT_CN_NAME)).
|
||||
-define(PH_CERT_PEM, ?PH(?VAR_CERT_PEM)).
|
||||
|
||||
%% MQTT/Gateway
|
||||
-define(VAR_PASSWORD, "password").
|
||||
|
|
|
@ -1722,6 +1722,16 @@ count_flapping_event(_ConnPkt, #channel{clientinfo = ClientInfo}) ->
|
|||
%%--------------------------------------------------------------------
|
||||
%% Authenticate
|
||||
|
||||
%% If peercert exists, add it as `cert_pem` credential field.
|
||||
maybe_add_cert(Map, #channel{conninfo = ConnInfo}) ->
|
||||
maybe_add_cert(Map, ConnInfo);
|
||||
maybe_add_cert(Map, #{peercert := PeerCert}) when is_binary(PeerCert) ->
|
||||
%% NOTE: it's raw binary at this point,
|
||||
%% encoding to PEM (base64) is done lazy in emqx_authn_utils:render_var
|
||||
Map#{cert_pem => PeerCert};
|
||||
maybe_add_cert(Map, _) ->
|
||||
Map.
|
||||
|
||||
authenticate(
|
||||
?CONNECT_PACKET(
|
||||
#mqtt_packet_connect{
|
||||
|
@ -1734,20 +1744,23 @@ authenticate(
|
|||
auth_cache = AuthCache
|
||||
} = Channel
|
||||
) ->
|
||||
%% Auth with CONNECT packet for MQTT v5
|
||||
AuthData = emqx_mqtt_props:get('Authentication-Data', Properties, undefined),
|
||||
do_authenticate(
|
||||
Credential0 =
|
||||
ClientInfo#{
|
||||
auth_method => AuthMethod,
|
||||
auth_data => AuthData,
|
||||
auth_cache => AuthCache
|
||||
},
|
||||
Channel
|
||||
);
|
||||
Credential = maybe_add_cert(Credential0, Channel),
|
||||
do_authenticate(Credential, Channel);
|
||||
authenticate(
|
||||
?CONNECT_PACKET(#mqtt_packet_connect{password = Password}),
|
||||
#channel{clientinfo = ClientInfo} = Channel
|
||||
) ->
|
||||
do_authenticate(ClientInfo#{password => Password}, Channel);
|
||||
%% Auth with CONNECT packet for MQTT v3
|
||||
Credential = maybe_add_cert(ClientInfo#{password => Password}, Channel),
|
||||
do_authenticate(Credential, Channel);
|
||||
authenticate(
|
||||
?AUTH_PACKET(_, #{'Authentication-Method' := AuthMethod} = Properties),
|
||||
#channel{
|
||||
|
@ -1756,6 +1769,7 @@ authenticate(
|
|||
auth_cache = AuthCache
|
||||
} = Channel
|
||||
) ->
|
||||
%% Enhanced auth
|
||||
case emqx_mqtt_props:get('Authentication-Method', ConnProps, undefined) of
|
||||
AuthMethod ->
|
||||
AuthData = emqx_mqtt_props:get('Authentication-Data', Properties, undefined),
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
?VAR_PEERHOST,
|
||||
?VAR_CERT_SUBJECT,
|
||||
?VAR_CERT_CN_NAME,
|
||||
?VAR_CERT_PEM,
|
||||
?VAR_NS_CLIENT_ATTRS
|
||||
]).
|
||||
|
||||
|
@ -357,6 +358,8 @@ render_var(_, undefined) ->
|
|||
% Any allowed but undefined binding will be replaced with empty string, even when
|
||||
% rendering SQL values.
|
||||
<<>>;
|
||||
render_var(?VAR_CERT_PEM, Value) ->
|
||||
base64:encode(Value);
|
||||
render_var(?VAR_PEERHOST, Value) ->
|
||||
inet:ntoa(Value);
|
||||
render_var(_Name, Value) ->
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
protocol => mqtt,
|
||||
cert_subject => <<"cert_subject_data">>,
|
||||
cert_common_name => <<"cert_common_name_data">>,
|
||||
cert_pem => <<"fake_raw_cert_to_be_base64_encoded">>,
|
||||
client_attrs => #{<<"group">> => <<"g1">>}
|
||||
}).
|
||||
|
||||
|
@ -222,7 +223,8 @@ t_no_value_for_placeholder(_Config) ->
|
|||
{ok, RawBody, Req1} = cowboy_req:read_body(Req0),
|
||||
#{
|
||||
<<"cert_subject">> := <<"">>,
|
||||
<<"cert_common_name">> := <<"">>
|
||||
<<"cert_common_name">> := <<"">>,
|
||||
<<"cert_pem">> := <<"">>
|
||||
} = emqx_utils_json:decode(RawBody, [return_maps]),
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
|
@ -238,7 +240,8 @@ t_no_value_for_placeholder(_Config) ->
|
|||
<<"headers">> => #{<<"content-type">> => <<"application/json">>},
|
||||
<<"body">> => #{
|
||||
<<"cert_subject">> => ?PH_CERT_SUBJECT,
|
||||
<<"cert_common_name">> => ?PH_CERT_CN_NAME
|
||||
<<"cert_common_name">> => ?PH_CERT_CN_NAME,
|
||||
<<"cert_pem">> => ?PH_CERT_PEM
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -251,7 +254,7 @@ t_no_value_for_placeholder(_Config) ->
|
|||
|
||||
ok = emqx_authn_http_test_server:set_handler(Handler),
|
||||
|
||||
Credentials = maps:without([cert_subject, cert_common_name], ?CREDENTIALS),
|
||||
Credentials = maps:without([cert_subject, cert_common_name, cert_pem], ?CREDENTIALS),
|
||||
|
||||
?assertMatch({ok, _}, emqx_access_control:authenticate(Credentials)),
|
||||
|
||||
|
@ -656,8 +659,10 @@ samples() ->
|
|||
<<"peerhost">> := <<"127.0.0.1">>,
|
||||
<<"cert_subject">> := <<"cert_subject_data">>,
|
||||
<<"cert_common_name">> := <<"cert_common_name_data">>,
|
||||
<<"cert_pem">> := CertPem,
|
||||
<<"the_group">> := <<"g1">>
|
||||
} = emqx_utils_json:decode(RawBody, [return_maps]),
|
||||
<<"fake_raw_cert_to_be_base64_encoded">> = base64:decode(CertPem),
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
|
@ -676,6 +681,7 @@ samples() ->
|
|||
<<"peerhost">> => ?PH_PEERHOST,
|
||||
<<"cert_subject">> => ?PH_CERT_SUBJECT,
|
||||
<<"cert_common_name">> => ?PH_CERT_CN_NAME,
|
||||
<<"cert_pem">> => ?PH_CERT_PEM,
|
||||
<<"the_group">> => <<"${client_attrs.group}">>
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue