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
|
## Value: on | off
|
||||||
## listener.ssl.external.honor_cipher_order = on
|
## 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'.
|
## Notice that 'verify' should be set as 'verify_peer'.
|
||||||
##
|
##
|
||||||
## Value: cn | en
|
## Value: cn | en | crt
|
||||||
## listener.ssl.external.peer_cert_as_username = cn
|
## listener.ssl.external.peer_cert_as_username = cn
|
||||||
|
|
||||||
## TCP backlog for the SSL connection.
|
## 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
|
## See: listener.ssl.$name.peer_cert_as_username
|
||||||
##
|
##
|
||||||
## Value: cn | dn
|
## Value: cn | dn | crt
|
||||||
## listener.wss.external.peer_cert_as_username = cn
|
## listener.wss.external.peer_cert_as_username = cn
|
||||||
|
|
||||||
## TCP backlog for the WebSocket/SSL connection.
|
## TCP backlog for the WebSocket/SSL connection.
|
||||||
|
|
|
@ -949,7 +949,7 @@ end}.
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{mapping, "listener.tcp.$name.peer_cert_as_username", "emqx.listeners", [
|
{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", [
|
{mapping, "listener.tcp.$name.backlog", "emqx.listeners", [
|
||||||
|
@ -1139,7 +1139,7 @@ end}.
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{mapping, "listener.ssl.$name.peer_cert_as_username", "emqx.listeners", [
|
{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", [
|
{mapping, "listener.wss.$name.peer_cert_as_username", "emqx.listeners", [
|
||||||
{datatype, {enum, [cn, dn]}}
|
{datatype, {enum, [cn, dn, crt]}}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{translation, "emqx.listeners", fun(Conf) ->
|
{translation, "emqx.listeners", fun(Conf) ->
|
||||||
|
|
|
@ -33,35 +33,34 @@
|
||||||
-export([shutdown/2]).
|
-export([shutdown/2]).
|
||||||
|
|
||||||
-record(pstate, {
|
-record(pstate, {
|
||||||
zone,
|
zone,
|
||||||
sendfun,
|
sendfun,
|
||||||
peername,
|
peername,
|
||||||
peercert,
|
peercert,
|
||||||
proto_ver,
|
proto_ver,
|
||||||
proto_name,
|
proto_name,
|
||||||
ackprops,
|
client_id,
|
||||||
client_id,
|
is_assigned,
|
||||||
is_assigned,
|
conn_pid,
|
||||||
conn_pid,
|
conn_props,
|
||||||
conn_props,
|
ack_props,
|
||||||
ack_props,
|
username,
|
||||||
username,
|
session,
|
||||||
session,
|
clean_start,
|
||||||
clean_start,
|
topic_aliases,
|
||||||
topic_aliases,
|
packet_size,
|
||||||
packet_size,
|
will_topic,
|
||||||
will_topic,
|
will_msg,
|
||||||
will_msg,
|
keepalive,
|
||||||
keepalive,
|
mountpoint,
|
||||||
mountpoint,
|
is_super,
|
||||||
is_super,
|
is_bridge,
|
||||||
is_bridge,
|
enable_ban,
|
||||||
enable_ban,
|
enable_acl,
|
||||||
enable_acl,
|
recv_stats,
|
||||||
recv_stats,
|
send_stats,
|
||||||
send_stats,
|
connected,
|
||||||
connected,
|
connected_at
|
||||||
connected_at
|
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-type(state() :: #pstate{}).
|
-type(state() :: #pstate{}).
|
||||||
|
@ -71,6 +70,8 @@
|
||||||
-compile(export_all).
|
-compile(export_all).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
|
-define(NO_PROPS, undefined).
|
||||||
|
|
||||||
-define(LOG(Level, Format, Args, PState),
|
-define(LOG(Level, Format, Args, PState),
|
||||||
emqx_logger:Level([{client, PState#pstate.client_id}], "MQTT(~s@~s): " ++ Format,
|
emqx_logger:Level([{client, PState#pstate.client_id}], "MQTT(~s@~s): " ++ Format,
|
||||||
[PState#pstate.client_id, esockd_net:format(PState#pstate.peername) | Args])).
|
[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) ->
|
init_username(Peercert, Options) ->
|
||||||
case proplists:get_value(peer_cert_as_username, Options) of
|
case proplists:get_value(peer_cert_as_username, Options) of
|
||||||
cn -> esockd_peercert:common_name(Peercert);
|
cn -> esockd_peercert:common_name(Peercert);
|
||||||
dn -> esockd_peercert:subject(Peercert);
|
dn -> esockd_peercert:subject(Peercert);
|
||||||
_ -> undefined
|
crt -> Peercert;
|
||||||
|
_ -> undefined
|
||||||
end.
|
end.
|
||||||
|
|
||||||
set_username(Username, PState = #pstate{username = undefined}) ->
|
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
|
%% 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()),
|
ClientId = emqx_guid:to_base62(emqx_guid:gen()),
|
||||||
AckProps1 = set_property('Assigned-Client-Identifier', ClientId, AckProps),
|
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) ->
|
maybe_assign_client_id(PState) ->
|
||||||
PState.
|
PState.
|
||||||
|
|
||||||
|
@ -671,7 +673,7 @@ authenticate(Credentials, Password) ->
|
||||||
{error, Error}
|
{error, Error}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
set_property(Name, Value, undefined) ->
|
set_property(Name, Value, ?NO_PROPS) ->
|
||||||
#{Name => Value};
|
#{Name => Value};
|
||||||
set_property(Name, Value, Props) ->
|
set_property(Name, Value, Props) ->
|
||||||
Props#{Name => Value}.
|
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