diff --git a/CHANGES-5.0.md b/CHANGES-5.0.md index b942d5a0f..ae1184f81 100644 --- a/CHANGES-5.0.md +++ b/CHANGES-5.0.md @@ -17,6 +17,7 @@ * Fix `chars_limit` is not working when `formatter` is `json`. [#8518](http://github.com/emqx/emqx/pull/8518) * Ensuring that exhook dispatches the client events are sequential. [#8530](https://github.com/emqx/emqx/pull/8530) * Avoid using RocksDB backend for persistent sessions when such backend is unavailable. [#8528](https://github.com/emqx/emqx/pull/8528) +* Fix AuthN `cert_subject` and `cert_common_name` placeholder rendering failure. [#8531](https://github.com/emqx/emqx/pull/8531) * Support listen on an IPv6 address, e.g: [::1]:1883 or ::1:1883. [#8547](https://github.com/emqx/emqx/pull/8547) * GET '/rules' support for pagination and fuzzy search. [#8472](https://github.com/emqx/emqx/pull/8472) **‼️ Note** : The previous API only returns array: `[RuleObj1,RuleObj2]`, after updating, it will become diff --git a/apps/emqx_authn/src/emqx_authn_utils.erl b/apps/emqx_authn/src/emqx_authn_utils.erl index 17ad8a28b..994f2f275 100644 --- a/apps/emqx_authn/src/emqx_authn_utils.erl +++ b/apps/emqx_authn/src/emqx_authn_utils.erl @@ -118,21 +118,21 @@ parse_sql(Template, ReplaceWith) -> render_deep(Template, Credential) -> emqx_placeholder:proc_tmpl_deep( Template, - Credential, + mapping_credential(Credential), #{return => full_binary, var_trans => fun handle_var/2} ). render_str(Template, Credential) -> emqx_placeholder:proc_tmpl( Template, - Credential, + mapping_credential(Credential), #{return => full_binary, var_trans => fun handle_var/2} ). render_sql_params(ParamList, Credential) -> emqx_placeholder:proc_tmpl( ParamList, - Credential, + mapping_credential(Credential), #{return => rawlist, var_trans => fun handle_sql_var/2} ). @@ -230,3 +230,8 @@ handle_sql_var({var, <<"peerhost">>}, PeerHost) -> emqx_placeholder:bin(inet:ntoa(PeerHost)); handle_sql_var(_, Value) -> emqx_placeholder:sql_data(Value). + +mapping_credential(C = #{cn := CN, dn := DN}) -> + C#{cert_common_name => CN, cert_subject => DN}; +mapping_credential(C) -> + C. diff --git a/apps/emqx_authn/test/emqx_authn_http_SUITE.erl b/apps/emqx_authn/test/emqx_authn_http_SUITE.erl index 5384bcf6e..44ef43903 100644 --- a/apps/emqx_authn/test/emqx_authn_http_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_http_SUITE.erl @@ -34,7 +34,9 @@ password => <<"plain">>, peerhost => {127, 0, 0, 1}, listener => 'tcp:default', - protocol => mqtt + protocol => mqtt, + cert_subject => <<"cert_subject_data">>, + cert_common_name => <<"cert_common_name_data">> }). -define(SERVER_RESPONSE_JSON(Result), ?SERVER_RESPONSE_JSON(Result, false)). @@ -517,7 +519,9 @@ samples() -> <<"username">> := <<"plain">>, <<"password">> := <<"plain">>, <<"clientid">> := <<"clienta">>, - <<"peerhost">> := <<"127.0.0.1">> + <<"peerhost">> := <<"127.0.0.1">>, + <<"cert_subject">> := <<"cert_subject_data">>, + <<"cert_common_name">> := <<"cert_common_name_data">> } = jiffy:decode(RawBody, [return_maps]), Req = cowboy_req:reply( 200, @@ -534,7 +538,9 @@ samples() -> <<"clientid">> => ?PH_CLIENTID, <<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD, - <<"peerhost">> => ?PH_PEERHOST + <<"peerhost">> => ?PH_PEERHOST, + <<"cert_subject">> => ?PH_CERT_SUBJECT, + <<"cert_common_name">> => ?PH_CERT_CN_NAME } }, result => {ok, #{is_superuser => false, user_property => #{}}} diff --git a/apps/emqx_authn/test/emqx_authn_mongo_SUITE.erl b/apps/emqx_authn/test/emqx_authn_mongo_SUITE.erl index f68f9a528..2f7dd2391 100644 --- a/apps/emqx_authn/test/emqx_authn_mongo_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_mongo_SUITE.erl @@ -345,6 +345,33 @@ user_seeds() -> result => {ok, #{is_superuser => true}} }, + #{ + data => #{ + cert_subject => <<"cert_subject_data">>, + cert_common_name => <<"cert_common_name_data">>, + password_hash => + <<"ac63a624e7074776d677dd61a003b8c803eb11db004d0ec6ae032a5d7c9c5caf">>, + salt => <<"salt">>, + is_superuser => 1 + }, + credentials => #{ + cert_subject => <<"cert_subject_data">>, + cert_common_name => <<"cert_common_name_data">>, + password => <<"sha256">> + }, + config_params => #{ + <<"filter">> => #{ + <<"cert_subject">> => <<"${cert_subject}">>, + <<"cert_common_name">> => <<"${cert_common_name}">> + }, + <<"password_hash_algorithm">> => #{ + <<"name">> => <<"sha256">>, + <<"salt_position">> => <<"prefix">> + } + }, + result => {ok, #{is_superuser => true}} + }, + #{ data => #{ username => <<"bcrypt">>, diff --git a/apps/emqx_authn/test/emqx_authn_mysql_SUITE.erl b/apps/emqx_authn/test/emqx_authn_mysql_SUITE.erl index abf36c167..0fdba0b31 100644 --- a/apps/emqx_authn/test/emqx_authn_mysql_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_mysql_SUITE.erl @@ -318,6 +318,36 @@ user_seeds() -> result => {ok, #{is_superuser => true}} }, + #{ + data => #{ + username => "sha256", + password_hash => "ac63a624e7074776d677dd61a003b8c803eb11db004d0ec6ae032a5d7c9c5caf", + cert_subject => <<"cert_subject_data">>, + cert_common_name => <<"cert_common_name_data">>, + salt => "salt", + is_superuser_int => 1 + }, + credentials => #{ + clientid => <<"sha256">>, + password => <<"sha256">>, + cert_subject => <<"cert_subject_data">>, + cert_common_name => <<"cert_common_name_data">> + }, + config_params => #{ + <<"query">> => + << + "SELECT password_hash, salt, is_superuser_int as is_superuser\n" + " FROM users where cert_subject = ${cert_subject} AND \n" + " cert_common_name = ${cert_common_name} LIMIT 1" + >>, + <<"password_hash_algorithm">> => #{ + <<"name">> => <<"sha256">>, + <<"salt_position">> => <<"prefix">> + } + }, + result => {ok, #{is_superuser => true}} + }, + #{ data => #{ username => <<"bcrypt">>, @@ -433,14 +463,24 @@ init_seeds() -> " username VARCHAR(255),\n" " password_hash VARCHAR(255),\n" " salt VARCHAR(255),\n" + " cert_subject VARCHAR(255),\n" + " cert_common_name VARCHAR(255),\n" " is_superuser_str VARCHAR(255),\n" " is_superuser_int TINYINT)" ), - Fields = [username, password_hash, salt, is_superuser_str, is_superuser_int], + Fields = [ + username, + password_hash, + salt, + cert_subject, + cert_common_name, + is_superuser_str, + is_superuser_int + ], InsertQuery = - "INSERT INTO users(username, password_hash, salt, " - " is_superuser_str, is_superuser_int) VALUES(?, ?, ?, ?, ?)", + "INSERT INTO users(username, password_hash, salt, cert_subject, cert_common_name," + " is_superuser_str, is_superuser_int) VALUES(?, ?, ?, ?, ?, ?, ?)", lists:foreach( fun(#{data := Values}) -> diff --git a/apps/emqx_authn/test/emqx_authn_pgsql_SUITE.erl b/apps/emqx_authn/test/emqx_authn_pgsql_SUITE.erl index 2d9607c41..ff017a79e 100644 --- a/apps/emqx_authn/test/emqx_authn_pgsql_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_pgsql_SUITE.erl @@ -380,6 +380,36 @@ user_seeds() -> result => {ok, #{is_superuser => true}} }, + #{ + data => #{ + username => "sha256", + password_hash => "ac63a624e7074776d677dd61a003b8c803eb11db004d0ec6ae032a5d7c9c5caf", + cert_subject => <<"cert_subject_data">>, + cert_common_name => <<"cert_common_name_data">>, + salt => "salt", + is_superuser_int => 1 + }, + credentials => #{ + clientid => <<"sha256">>, + password => <<"sha256">>, + cert_subject => <<"cert_subject_data">>, + cert_common_name => <<"cert_common_name_data">> + }, + config_params => #{ + <<"query">> => + << + "SELECT password_hash, salt, is_superuser_int as is_superuser\n" + " FROM users where cert_subject = ${cert_subject} AND \n" + " cert_common_name = ${cert_common_name} LIMIT 1" + >>, + <<"password_hash_algorithm">> => #{ + <<"name">> => <<"sha256">>, + <<"salt_position">> => <<"prefix">> + } + }, + result => {ok, #{is_superuser => true}} + }, + #{ data => #{ username => <<"bcrypt">>, @@ -474,6 +504,8 @@ init_seeds() -> " username varchar(255),\n" " password_hash varchar(255),\n" " salt varchar(255),\n" + " cert_subject varchar(255),\n" + " cert_common_name varchar(255),\n" " is_superuser_str varchar(255),\n" " is_superuser_int smallint,\n" " is_superuser_bool boolean)" @@ -487,12 +519,21 @@ init_seeds() -> ). create_user(Values) -> - Fields = [username, password_hash, salt, is_superuser_str, is_superuser_int, is_superuser_bool], + Fields = [ + username, + password_hash, + salt, + cert_subject, + cert_common_name, + is_superuser_str, + is_superuser_int, + is_superuser_bool + ], InsertQuery = - "INSERT INTO users(username, password_hash, salt," + "INSERT INTO users(username, password_hash, salt, cert_subject, cert_common_name, " "is_superuser_str, is_superuser_int, is_superuser_bool) " - "VALUES($1, $2, $3, $4, $5, $6)", + "VALUES($1, $2, $3, $4, $5, $6, $7, $8)", Params = [maps:get(F, Values, null) || F <- Fields], {ok, 1} = q(InsertQuery, Params), diff --git a/apps/emqx_authn/test/emqx_authn_redis_SUITE.erl b/apps/emqx_authn/test/emqx_authn_redis_SUITE.erl index 3423879f6..dde5f8188 100644 --- a/apps/emqx_authn/test/emqx_authn_redis_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_redis_SUITE.erl @@ -475,6 +475,52 @@ user_seeds() -> } }, result => {ok, #{is_superuser => true}} + }, + + #{ + data => #{ + password_hash => + <<"a3c7f6b085c3e5897ffb9b86f18a9d905063f8550a74444b5892e193c1b50428">>, + is_superuser => <<"1">> + }, + credentials => #{ + clientid => <<"sha256_no_salt">>, + cn => <<"cert_common_name">>, + dn => <<"cert_subject_name">>, + password => <<"sha256_no_salt">> + }, + key => <<"mqtt_user:cert_common_name">>, + config_params => #{ + <<"cmd">> => <<"HMGET mqtt_user:${cert_common_name} password_hash is_superuser">>, + <<"password_hash_algorithm">> => #{ + <<"name">> => <<"sha256">>, + <<"salt_position">> => <<"disable">> + } + }, + result => {ok, #{is_superuser => true}} + }, + + #{ + data => #{ + password_hash => + <<"a3c7f6b085c3e5897ffb9b86f18a9d905063f8550a74444b5892e193c1b50428">>, + is_superuser => <<"1">> + }, + credentials => #{ + clientid => <<"sha256_no_salt">>, + cn => <<"cert_common_name">>, + dn => <<"cert_subject_name">>, + password => <<"sha256_no_salt">> + }, + key => <<"mqtt_user:cert_subject_name">>, + config_params => #{ + <<"cmd">> => <<"HMGET mqtt_user:${cert_subject} password_hash is_superuser">>, + <<"password_hash_algorithm">> => #{ + <<"name">> => <<"sha256">>, + <<"salt_position">> => <<"disable">> + } + }, + result => {ok, #{is_superuser => true}} } ].