Merge pull request #1913 from emqx/cert_as_username

Support use certificate as username
This commit is contained in:
turtleDeng 2018-10-26 19:37:20 +08:00 committed by GitHub
commit 71b198f543
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 41 deletions

View File

@ -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.

View File

@ -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) ->

View File

@ -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}.

View File

@ -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}])).