Merge pull request #1913 from emqx/cert_as_username
Support use certificate as username
This commit is contained in:
commit
71b198f543
|
@ -1159,10 +1159,10 @@ listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-G
|
|||
## Value: on | off
|
||||
## listener.ssl.external.honor_cipher_order = on
|
||||
|
||||
## Use the CN field from the client certificate as a username.
|
||||
## Use the CN, EN or CRT field from the client certificate as a username.
|
||||
## Notice that 'verify' should be set as 'verify_peer'.
|
||||
##
|
||||
## Value: cn | en
|
||||
## Value: cn | en | crt
|
||||
## listener.ssl.external.peer_cert_as_username = cn
|
||||
|
||||
## TCP backlog for the SSL connection.
|
||||
|
@ -1522,7 +1522,7 @@ listener.wss.external.certfile = {{ platform_etc_dir }}/certs/cert.pem
|
|||
|
||||
## See: listener.ssl.$name.peer_cert_as_username
|
||||
##
|
||||
## Value: cn | dn
|
||||
## Value: cn | dn | crt
|
||||
## listener.wss.external.peer_cert_as_username = cn
|
||||
|
||||
## TCP backlog for the WebSocket/SSL connection.
|
||||
|
|
|
@ -949,7 +949,7 @@ end}.
|
|||
]}.
|
||||
|
||||
{mapping, "listener.tcp.$name.peer_cert_as_username", "emqx.listeners", [
|
||||
{datatype, {enum, [cn, dn]}}
|
||||
{datatype, {enum, [cn, dn, crt]}}
|
||||
]}.
|
||||
|
||||
{mapping, "listener.tcp.$name.backlog", "emqx.listeners", [
|
||||
|
@ -1139,7 +1139,7 @@ end}.
|
|||
]}.
|
||||
|
||||
{mapping, "listener.ssl.$name.peer_cert_as_username", "emqx.listeners", [
|
||||
{datatype, {enum, [cn, dn]}}
|
||||
{datatype, {enum, [cn, dn, crt]}}
|
||||
]}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
@ -1400,7 +1400,7 @@ end}.
|
|||
]}.
|
||||
|
||||
{mapping, "listener.wss.$name.peer_cert_as_username", "emqx.listeners", [
|
||||
{datatype, {enum, [cn, dn]}}
|
||||
{datatype, {enum, [cn, dn, crt]}}
|
||||
]}.
|
||||
|
||||
{translation, "emqx.listeners", fun(Conf) ->
|
||||
|
|
|
@ -33,35 +33,34 @@
|
|||
-export([shutdown/2]).
|
||||
|
||||
-record(pstate, {
|
||||
zone,
|
||||
sendfun,
|
||||
peername,
|
||||
peercert,
|
||||
proto_ver,
|
||||
proto_name,
|
||||
ackprops,
|
||||
client_id,
|
||||
is_assigned,
|
||||
conn_pid,
|
||||
conn_props,
|
||||
ack_props,
|
||||
username,
|
||||
session,
|
||||
clean_start,
|
||||
topic_aliases,
|
||||
packet_size,
|
||||
will_topic,
|
||||
will_msg,
|
||||
keepalive,
|
||||
mountpoint,
|
||||
is_super,
|
||||
is_bridge,
|
||||
enable_ban,
|
||||
enable_acl,
|
||||
recv_stats,
|
||||
send_stats,
|
||||
connected,
|
||||
connected_at
|
||||
zone,
|
||||
sendfun,
|
||||
peername,
|
||||
peercert,
|
||||
proto_ver,
|
||||
proto_name,
|
||||
client_id,
|
||||
is_assigned,
|
||||
conn_pid,
|
||||
conn_props,
|
||||
ack_props,
|
||||
username,
|
||||
session,
|
||||
clean_start,
|
||||
topic_aliases,
|
||||
packet_size,
|
||||
will_topic,
|
||||
will_msg,
|
||||
keepalive,
|
||||
mountpoint,
|
||||
is_super,
|
||||
is_bridge,
|
||||
enable_ban,
|
||||
enable_acl,
|
||||
recv_stats,
|
||||
send_stats,
|
||||
connected,
|
||||
connected_at
|
||||
}).
|
||||
|
||||
-type(state() :: #pstate{}).
|
||||
|
@ -71,6 +70,8 @@
|
|||
-compile(export_all).
|
||||
-endif.
|
||||
|
||||
-define(NO_PROPS, undefined).
|
||||
|
||||
-define(LOG(Level, Format, Args, PState),
|
||||
emqx_logger:Level([{client, PState#pstate.client_id}], "MQTT(~s@~s): " ++ Format,
|
||||
[PState#pstate.client_id, esockd_net:format(PState#pstate.peername) | Args])).
|
||||
|
@ -106,9 +107,10 @@ init(#{peername := Peername, peercert := Peercert, sendfun := SendFun}, Options)
|
|||
|
||||
init_username(Peercert, Options) ->
|
||||
case proplists:get_value(peer_cert_as_username, Options) of
|
||||
cn -> esockd_peercert:common_name(Peercert);
|
||||
dn -> esockd_peercert:subject(Peercert);
|
||||
_ -> undefined
|
||||
cn -> esockd_peercert:common_name(Peercert);
|
||||
dn -> esockd_peercert:subject(Peercert);
|
||||
crt -> Peercert;
|
||||
_ -> undefined
|
||||
end.
|
||||
|
||||
set_username(Username, PState = #pstate{username = undefined}) ->
|
||||
|
@ -603,10 +605,10 @@ send(Packet = ?PACKET(Type), PState = #pstate{proto_ver = Ver, sendfun = SendFun
|
|||
%%------------------------------------------------------------------------------
|
||||
%% Assign a clientid
|
||||
|
||||
maybe_assign_client_id(PState = #pstate{client_id = <<>>, ackprops = AckProps}) ->
|
||||
maybe_assign_client_id(PState = #pstate{client_id = <<>>, ack_props = AckProps}) ->
|
||||
ClientId = emqx_guid:to_base62(emqx_guid:gen()),
|
||||
AckProps1 = set_property('Assigned-Client-Identifier', ClientId, AckProps),
|
||||
PState#pstate{client_id = ClientId, is_assigned = true, ackprops = AckProps1};
|
||||
PState#pstate{client_id = ClientId, is_assigned = true, ack_props = AckProps1};
|
||||
maybe_assign_client_id(PState) ->
|
||||
PState.
|
||||
|
||||
|
@ -671,7 +673,7 @@ authenticate(Credentials, Password) ->
|
|||
{error, Error}
|
||||
end.
|
||||
|
||||
set_property(Name, Value, undefined) ->
|
||||
set_property(Name, Value, ?NO_PROPS) ->
|
||||
#{Name => Value};
|
||||
set_property(Name, Value, Props) ->
|
||||
Props#{Name => Value}.
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
|
||||
-module(emqx_protocol_tests).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
set_property_test() ->
|
||||
?assertEqual(#{test => test_property}, emqx_protocol:set_property(test, test_property, undefined)),
|
||||
TestMap = #{test => test_property},
|
||||
?assertEqual(#{test => test_property, test1 => test_property2},
|
||||
emqx_protocol:set_property(test1, test_property2, TestMap)),
|
||||
ok.
|
||||
|
||||
init_username_test() ->
|
||||
?assertEqual(<<"Peercert">>,
|
||||
emqx_protocol:init_username(<<"Peercert">>, [{peer_cert_as_username, crt}])),
|
||||
?assertEqual(undefined,
|
||||
emqx_protocol:init_username(undefined, [{peer_cert_as_username, undefined}])).
|
Loading…
Reference in New Issue