Merge pull request #13229 from zmstone/0611-auth-with-raw-cert
feat(authn): support `${cert_pem}` placeholder
This commit is contained in:
commit
51810c6919
|
@ -28,8 +28,10 @@
|
||||||
%% cert
|
%% cert
|
||||||
-define(VAR_CERT_SUBJECT, "cert_subject").
|
-define(VAR_CERT_SUBJECT, "cert_subject").
|
||||||
-define(VAR_CERT_CN_NAME, "cert_common_name").
|
-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_SUBJECT, ?PH(?VAR_CERT_SUBJECT)).
|
||||||
-define(PH_CERT_CN_NAME, ?PH(?VAR_CERT_CN_NAME)).
|
-define(PH_CERT_CN_NAME, ?PH(?VAR_CERT_CN_NAME)).
|
||||||
|
-define(PH_CERT_PEM, ?PH(?VAR_CERT_PEM)).
|
||||||
|
|
||||||
%% MQTT/Gateway
|
%% MQTT/Gateway
|
||||||
-define(VAR_PASSWORD, "password").
|
-define(VAR_PASSWORD, "password").
|
||||||
|
|
|
@ -1729,6 +1729,16 @@ count_flapping_event(_ConnPkt, #channel{clientinfo = ClientInfo}) ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Authenticate
|
%% 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(
|
authenticate(
|
||||||
?CONNECT_PACKET(
|
?CONNECT_PACKET(
|
||||||
#mqtt_packet_connect{
|
#mqtt_packet_connect{
|
||||||
|
@ -1741,20 +1751,23 @@ authenticate(
|
||||||
auth_cache = AuthCache
|
auth_cache = AuthCache
|
||||||
} = Channel
|
} = Channel
|
||||||
) ->
|
) ->
|
||||||
|
%% Auth with CONNECT packet for MQTT v5
|
||||||
AuthData = emqx_mqtt_props:get('Authentication-Data', Properties, undefined),
|
AuthData = emqx_mqtt_props:get('Authentication-Data', Properties, undefined),
|
||||||
do_authenticate(
|
Credential0 =
|
||||||
ClientInfo#{
|
ClientInfo#{
|
||||||
auth_method => AuthMethod,
|
auth_method => AuthMethod,
|
||||||
auth_data => AuthData,
|
auth_data => AuthData,
|
||||||
auth_cache => AuthCache
|
auth_cache => AuthCache
|
||||||
},
|
},
|
||||||
Channel
|
Credential = maybe_add_cert(Credential0, Channel),
|
||||||
);
|
do_authenticate(Credential, Channel);
|
||||||
authenticate(
|
authenticate(
|
||||||
?CONNECT_PACKET(#mqtt_packet_connect{password = Password}),
|
?CONNECT_PACKET(#mqtt_packet_connect{password = Password}),
|
||||||
#channel{clientinfo = ClientInfo} = Channel
|
#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(
|
authenticate(
|
||||||
?AUTH_PACKET(_, #{'Authentication-Method' := AuthMethod} = Properties),
|
?AUTH_PACKET(_, #{'Authentication-Method' := AuthMethod} = Properties),
|
||||||
#channel{
|
#channel{
|
||||||
|
@ -1763,6 +1776,7 @@ authenticate(
|
||||||
auth_cache = AuthCache
|
auth_cache = AuthCache
|
||||||
} = Channel
|
} = Channel
|
||||||
) ->
|
) ->
|
||||||
|
%% Enhanced auth
|
||||||
case emqx_mqtt_props:get('Authentication-Method', ConnProps, undefined) of
|
case emqx_mqtt_props:get('Authentication-Method', ConnProps, undefined) of
|
||||||
AuthMethod ->
|
AuthMethod ->
|
||||||
AuthData = emqx_mqtt_props:get('Authentication-Data', Properties, undefined),
|
AuthData = emqx_mqtt_props:get('Authentication-Data', Properties, undefined),
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
?VAR_PEERHOST,
|
?VAR_PEERHOST,
|
||||||
?VAR_CERT_SUBJECT,
|
?VAR_CERT_SUBJECT,
|
||||||
?VAR_CERT_CN_NAME,
|
?VAR_CERT_CN_NAME,
|
||||||
|
?VAR_CERT_PEM,
|
||||||
?VAR_NS_CLIENT_ATTRS
|
?VAR_NS_CLIENT_ATTRS
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -357,6 +358,8 @@ render_var(_, undefined) ->
|
||||||
% Any allowed but undefined binding will be replaced with empty string, even when
|
% Any allowed but undefined binding will be replaced with empty string, even when
|
||||||
% rendering SQL values.
|
% rendering SQL values.
|
||||||
<<>>;
|
<<>>;
|
||||||
|
render_var(?VAR_CERT_PEM, Value) ->
|
||||||
|
base64:encode(Value);
|
||||||
render_var(?VAR_PEERHOST, Value) ->
|
render_var(?VAR_PEERHOST, Value) ->
|
||||||
inet:ntoa(Value);
|
inet:ntoa(Value);
|
||||||
render_var(_Name, Value) ->
|
render_var(_Name, Value) ->
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
protocol => mqtt,
|
protocol => mqtt,
|
||||||
cert_subject => <<"cert_subject_data">>,
|
cert_subject => <<"cert_subject_data">>,
|
||||||
cert_common_name => <<"cert_common_name_data">>,
|
cert_common_name => <<"cert_common_name_data">>,
|
||||||
|
cert_pem => <<"fake_raw_cert_to_be_base64_encoded">>,
|
||||||
client_attrs => #{<<"group">> => <<"g1">>}
|
client_attrs => #{<<"group">> => <<"g1">>}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
@ -222,7 +223,8 @@ t_no_value_for_placeholder(_Config) ->
|
||||||
{ok, RawBody, Req1} = cowboy_req:read_body(Req0),
|
{ok, RawBody, Req1} = cowboy_req:read_body(Req0),
|
||||||
#{
|
#{
|
||||||
<<"cert_subject">> := <<"">>,
|
<<"cert_subject">> := <<"">>,
|
||||||
<<"cert_common_name">> := <<"">>
|
<<"cert_common_name">> := <<"">>,
|
||||||
|
<<"cert_pem">> := <<"">>
|
||||||
} = emqx_utils_json:decode(RawBody, [return_maps]),
|
} = emqx_utils_json:decode(RawBody, [return_maps]),
|
||||||
Req = cowboy_req:reply(
|
Req = cowboy_req:reply(
|
||||||
200,
|
200,
|
||||||
|
@ -238,7 +240,8 @@ t_no_value_for_placeholder(_Config) ->
|
||||||
<<"headers">> => #{<<"content-type">> => <<"application/json">>},
|
<<"headers">> => #{<<"content-type">> => <<"application/json">>},
|
||||||
<<"body">> => #{
|
<<"body">> => #{
|
||||||
<<"cert_subject">> => ?PH_CERT_SUBJECT,
|
<<"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),
|
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)),
|
?assertMatch({ok, _}, emqx_access_control:authenticate(Credentials)),
|
||||||
|
|
||||||
|
@ -656,8 +659,10 @@ samples() ->
|
||||||
<<"peerhost">> := <<"127.0.0.1">>,
|
<<"peerhost">> := <<"127.0.0.1">>,
|
||||||
<<"cert_subject">> := <<"cert_subject_data">>,
|
<<"cert_subject">> := <<"cert_subject_data">>,
|
||||||
<<"cert_common_name">> := <<"cert_common_name_data">>,
|
<<"cert_common_name">> := <<"cert_common_name_data">>,
|
||||||
|
<<"cert_pem">> := CertPem,
|
||||||
<<"the_group">> := <<"g1">>
|
<<"the_group">> := <<"g1">>
|
||||||
} = emqx_utils_json:decode(RawBody, [return_maps]),
|
} = emqx_utils_json:decode(RawBody, [return_maps]),
|
||||||
|
<<"fake_raw_cert_to_be_base64_encoded">> = base64:decode(CertPem),
|
||||||
Req = cowboy_req:reply(
|
Req = cowboy_req:reply(
|
||||||
200,
|
200,
|
||||||
#{<<"content-type">> => <<"application/json">>},
|
#{<<"content-type">> => <<"application/json">>},
|
||||||
|
@ -676,6 +681,7 @@ samples() ->
|
||||||
<<"peerhost">> => ?PH_PEERHOST,
|
<<"peerhost">> => ?PH_PEERHOST,
|
||||||
<<"cert_subject">> => ?PH_CERT_SUBJECT,
|
<<"cert_subject">> => ?PH_CERT_SUBJECT,
|
||||||
<<"cert_common_name">> => ?PH_CERT_CN_NAME,
|
<<"cert_common_name">> => ?PH_CERT_CN_NAME,
|
||||||
|
<<"cert_pem">> => ?PH_CERT_PEM,
|
||||||
<<"the_group">> => <<"${client_attrs.group}">>
|
<<"the_group">> => <<"${client_attrs.group}">>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue