diff --git a/etc/emqx.conf b/etc/emqx.conf index 33db7abb6..ddc17eef9 100644 --- a/etc/emqx.conf +++ b/etc/emqx.conf @@ -1088,10 +1088,18 @@ listener.tcp.external.access.1 = allow all ## Enable the option for X.509 certificate based authentication. ## EMQX will use the common name of certificate as MQTT username. +## 'pem' encodes CRT in base64, and md5 is the md5 hash of CRT. ## -## Value: cn | dn | crt +## Value: cn | dn | crt | pem | md5 ## listener.tcp.external.peer_cert_as_username = cn +## Enable the option for X.509 certificate based authentication. +## EMQX will use the common name of certificate as MQTT clientid. +## 'pem' encodes CRT in base64, and md5 is the md5 hash of CRT. +## +## Value: cn | dn | crt | pem | md5 +## listener.tcp.external.peer_cert_as_clientid = cn + ## The TCP backlog defines the maximum length that the queue of pending ## connections can grow to. ## @@ -1443,10 +1451,18 @@ listener.ssl.external.ciphers = TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TL ## Use the CN, DN or CRT field from the client certificate as a username. ## Notice that 'verify' should be set as 'verify_peer'. +## 'pem' encodes CRT in base64, and md5 is the md5 hash of CRT. ## -## Value: cn | dn | crt +## Value: cn | dn | crt | pem | md5 ## listener.ssl.external.peer_cert_as_username = cn +## Use the CN, DN or CRT field from the client certificate as a username. +## Notice that 'verify' should be set as 'verify_peer'. +## 'pem' encodes CRT in base64, and md5 is the md5 hash of CRT. +## +## Value: cn | dn | crt | pem | md5 +## listener.ssl.external.peer_cert_as_clientid = cn + ## TCP backlog for the SSL connection. ## ## See listener.tcp.$name.backlog @@ -1890,9 +1906,14 @@ listener.wss.external.ciphers = TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TL ## See: listener.ssl.$name.peer_cert_as_username ## -## Value: cn | dn | crt +## Value: cn | dn | crt | pem | md5 ## listener.wss.external.peer_cert_as_username = cn +## See: listener.ssl.$name.peer_cert_as_clientid +## +## Value: cn | dn | crt | pem | md5 +## listener.wss.external.peer_cert_as_clientid = cn + ## TCP backlog for the WebSocket/SSL connection. ## ## See: listener.tcp.$name.backlog diff --git a/priv/emqx.schema b/priv/emqx.schema index 0ddc02dc9..302278f44 100644 --- a/priv/emqx.schema +++ b/priv/emqx.schema @@ -1212,7 +1212,11 @@ end}. ]}. {mapping, "listener.tcp.$name.peer_cert_as_username", "emqx.listeners", [ - {datatype, {enum, [cn, dn, crt]}} + {datatype, {enum, [cn, dn, crt, pem, md5]}} +]}. + +{mapping, "listener.tcp.$name.peer_cert_as_clientid", "emqx.listeners", [ + {datatype, {enum, [cn, dn, crt, pem, md5]}} ]}. {mapping, "listener.tcp.$name.backlog", "emqx.listeners", [ @@ -1426,7 +1430,11 @@ end}. ]}. {mapping, "listener.ssl.$name.peer_cert_as_username", "emqx.listeners", [ - {datatype, {enum, [cn, dn, crt]}} + {datatype, {enum, [cn, dn, crt, pem, md5]}} +]}. + +{mapping, "listener.ssl.$name.peer_cert_as_clientid", "emqx.listeners", [ + {datatype, {enum, [cn, dn, crt, pem, md5]}} ]}. %%-------------------------------------------------------------------- @@ -1766,7 +1774,11 @@ end}. ]}. {mapping, "listener.wss.$name.peer_cert_as_username", "emqx.listeners", [ - {datatype, {enum, [cn, dn, crt]}} + {datatype, {enum, [cn, dn, crt, pem, md5]}} +]}. + +{mapping, "listener.wss.$name.peer_cert_as_clientid", "emqx.listeners", [ + {datatype, {enum, [cn, dn, crt, pem, md5]}} ]}. {mapping, "listener.wss.$name.compress", "emqx.listeners", [ @@ -1906,6 +1918,7 @@ end}. {fail_if_no_subprotocol, cuttlefish:conf_get(Prefix ++ ".fail_if_no_subprotocol", Conf, undefined)}, {supported_subprotocols, string:tokens(cuttlefish:conf_get(Prefix ++ ".supported_subprotocols", Conf, ""), ", ")}, {peer_cert_as_username, cuttlefish:conf_get(Prefix ++ ".peer_cert_as_username", Conf, undefined)}, + {peer_cert_as_clientid, cuttlefish:conf_get(Prefix ++ ".peer_cert_as_clientid", Conf, undefined)}, {compress, cuttlefish:conf_get(Prefix ++ ".compress", Conf, undefined)}, {idle_timeout, cuttlefish:conf_get(Prefix ++ ".idle_timeout", Conf, undefined)}, {max_frame_size, cuttlefish:conf_get(Prefix ++ ".max_frame_size", Conf, undefined)}, diff --git a/src/emqx_channel.erl b/src/emqx_channel.erl index 1ca9f36ed..9def736cb 100644 --- a/src/emqx_channel.erl +++ b/src/emqx_channel.erl @@ -220,13 +220,19 @@ setting_peercert_infos(NoSSL, ClientInfo, _Options) setting_peercert_infos(Peercert, ClientInfo, Options) -> {DN, CN} = {esockd_peercert:subject(Peercert), esockd_peercert:common_name(Peercert)}, - Username = case proplists:get_value(peer_cert_as_username, Options) of - cn -> CN; - dn -> DN; - crt -> Peercert; - _ -> undefined - end, - ClientInfo#{username => Username, dn => DN, cn => CN}. + Username = peer_cert_as(peer_cert_as_username, Options, Peercert, DN, CN), + ClientId = peer_cert_as(peer_cert_as_clientid, Options, Peercert, DN, CN), + ClientInfo#{username => Username, clientid => ClientId, dn => DN, cn => CN}. + +peer_cert_as(Key, Options, Peercert, DN, CN) -> + case proplists:get_value(Key, Options) of + cn -> CN; + dn -> DN; + crt -> Peercert; + pem -> base64:encode(Peercert); + md5 -> emqx_passwd:hash(md5, Peercert); + _ -> undefined + end. take_ws_cookie(ClientInfo, ConnInfo) -> case maps:take(ws_cookie, ConnInfo) of