Explorar el Código

fix: generate palce holder (#6250)

* fix: generate place holder

* style: whitespace cleanup

* refactor(authz): placeholder for athuz

* test: authz test suite for placeholder

* fix: lw place holder suite

* fix: auth n redis suite

Co-authored-by: JimMoen <LnJimMoen@outlook.com>
DDDHuang hace 4 años
padre
commit
21bd9bba55
Se han modificado 31 ficheros con 270 adiciones y 173 borrados
  1. 10 10
      apps/emqx/etc/emqx.conf
  2. 66 30
      apps/emqx/include/emqx_placeholder.hrl
  3. 7 6
      apps/emqx/src/emqx_mountpoint.erl
  4. 3 3
      apps/emqx/test/emqx_mountpoint_SUITE.erl
  5. 6 5
      apps/emqx_authn/src/emqx_authn_api.erl
  6. 8 6
      apps/emqx_authn/src/emqx_authn_utils.erl
  7. 4 4
      apps/emqx_authn/src/simple_authn/emqx_authn_jwks_connector.erl
  8. 2 2
      apps/emqx_authn/src/simple_authn/emqx_authn_jwt.erl
  9. 1 0
      apps/emqx_authn/test/data/user-credentials-malformed-1.json
  10. 4 0
      apps/emqx_authn/test/emqx_authn_api_SUITE.erl
  11. 6 4
      apps/emqx_authn/test/emqx_authn_mysql_SUITE.erl
  12. 12 6
      apps/emqx_authn/test/emqx_authn_pgsql_SUITE.erl
  13. 9 9
      apps/emqx_authn/test/emqx_authn_redis_SUITE.erl
  14. 9 0
      apps/emqx_authn/test/emqx_authn_test_lib.erl
  15. 19 9
      apps/emqx_authz/src/emqx_authz_http.erl
  16. 19 11
      apps/emqx_authz/src/emqx_authz_mongodb.erl
  17. 11 9
      apps/emqx_authz/src/emqx_authz_mysql.erl
  18. 11 9
      apps/emqx_authz/src/emqx_authz_postgresql.erl
  19. 8 5
      apps/emqx_authz/src/emqx_authz_redis.erl
  20. 21 17
      apps/emqx_authz/src/emqx_authz_rule.erl
  21. 2 1
      apps/emqx_authz/test/emqx_authz_SUITE.erl
  22. 2 1
      apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl
  23. 3 2
      apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl
  24. 3 3
      apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl
  25. 3 3
      apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl
  26. 3 3
      apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl
  27. 4 4
      apps/emqx_authz/test/emqx_authz_redis_SUITE.erl
  28. 5 4
      apps/emqx_authz/test/emqx_authz_rule_SUITE.erl
  29. 7 5
      apps/emqx_auto_subscribe/src/emqx_auto_subscribe_placeholder.erl
  30. 1 1
      apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl
  31. 1 1
      apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl

+ 10 - 10
apps/emqx/etc/emqx.conf

@@ -86,8 +86,8 @@ listeners.tcp.default {
   ## Set to "" to disable the feature.
   ##
   ## Variables in mountpoint string:
-  ##  - %c: clientid
-  ##  - %u: username
+  ##  - ${clientid}: clientid
+  ##  - ${username}: username
   ##
   ## @doc listeners.tcp.<name>.mountpoint
   ## ValueType: String
@@ -185,8 +185,8 @@ listeners.ssl.default {
   ## Set to "" to disable the feature.
   ##
   ## Variables in mountpoint string:
-  ##  - %c: clientid
-  ##  - %u: username
+  ##  - ${clientid}: clientid
+  ##  - ${username}: username
   ##
   ## @doc listeners.ssl.<name>.mountpoint
   ## ValueType: String
@@ -278,8 +278,8 @@ listeners.quic.default {
   ## Set to "" to disable the feature.
   ##
   ## Variables in mountpoint string:
-  ##  - %c: clientid
-  ##  - %u: username
+  ##  - ${clientid}: clientid
+  ##  - ${username}: username
   ##
   ## @doc listeners.quic.<name>.mountpoint
   ## ValueType: String
@@ -372,8 +372,8 @@ listeners.ws.default {
   ## Set to "" to disable the feature.
   ##
   ## Variables in mountpoint string:
-  ##  - %c: clientid
-  ##  - %u: username
+  ##  - ${clientid}: clientid
+  ##  - ${username}: username
   ##
   ## @doc listeners.ws.<name>.mountpoint
   ## ValueType: String
@@ -475,8 +475,8 @@ listeners.wss.default {
   ## Set to "" to disable the feature.
   ##
   ## Variables in mountpoint string:
-  ##  - %c: clientid
-  ##  - %u: username
+  ##  - ${clientid}: clientid
+  ##  - ${username}: username
   ##
   ## @doc listeners.wss.<name>.mountpoint
   ## ValueType: String

+ 66 - 30
apps/emqx/include/emqx_placeholder.hrl

@@ -17,60 +17,96 @@
 -ifndef(EMQ_X_PLACEHOLDER_HRL).
 -define(EMQ_X_PLACEHOLDER_HRL, true).
 
--define(PH(Type), <<"${", Type/binary, "}">>).
+-define(PH(Type),                   <<"${", Type/binary, "}">>  ).
 
 %% action: publish/subscribe/all
--define(PH_ACTION, ?PH(<<"action">>)).
+-define(PH_ACTION,                  <<"${action}">>             ).
 
 %% cert
--define(PH_CRET_SUBJECT, ?PH(<<"cert_subject">>)).
--define(PH_CRET_CN_NAME, ?PH(<<"cert_common_name">>)).
+-define(PH_CERT_SUBJECT,            <<"${cert_subject}">>       ).
+-define(PH_CERT_CN_NAME,            <<"${cert_common_name}">>   ).
 
 %% MQTT
--define(PH_PASSWORD, ?PH(<<"password">>)).
--define(PH_CLIENTID, ?PH(<<"clientid">>)).
--define(PH_FROM_CLIENTID, ?PH(<<"from_clienid">>)).
--define(PH_USERNAME, ?PH(<<"username">>)).
--define(PH_FROM_USERNAME, ?PH(<<"from_username">>)).
--define(PH_TOPIC, ?PH(<<"topic">>)).
+-define(PH_PASSWORD,                <<"${password}">>           ).
+-define(PH_CLIENTID,                <<"${clientid}">>           ).
+-define(PH_FROM_CLIENTID,           <<"${from_clientid}">>      ).
+-define(PH_USERNAME,                <<"${username}">>           ).
+-define(PH_FROM_USERNAME,           <<"${from_username}">>      ).
+-define(PH_TOPIC,                   <<"${topic}">>              ).
 %% MQTT payload
--define(PH_PAYLOAD, ?PH(<<"payload">>)).
+-define(PH_PAYLOAD,                 <<"${payload}">>            ).
 %% client IPAddress
--define(PH_PEERHOST, ?PH(<<"peerhost">>)).
+-define(PH_PEERHOST,                <<"${peerhost}">>           ).
+%% ip & port
+-define(PH_HOST,                    <<"${host}">>               ).
+-define(PH_PORT,                    <<"${port}">>               ).
 %% Enumeration of message QoS 0,1,2
--define(PH_QOS, ?PH(<<"qos">>)).
--define(PH_FLAGS, ?PH(<<"flags">>)).
+-define(PH_QOS,                     <<"${qos}">>                ).
+-define(PH_FLAGS,                   <<"${flags}">>              ).
 %% Additional data related to process within the MQTT message
--define(PH_HEADERS, ?PH(<<"hearders">>)).
+-define(PH_HEADERS,                 <<"${headers}">>            ).
 %% protocol name
--define(PH_PROTONAME, ?PH(<<"proto_name">>)).
+-define(PH_PROTONAME,               <<"${proto_name}">>         ).
 %% protocol version
--define(PH_PROTOVER, ?PH(<<"proto_ver">>)).
+-define(PH_PROTOVER,                <<"${proto_ver}">>          ).
 %% MQTT keepalive interval
--define(PH_KEEPALIVE, ?PH(<<"keepalive">>)).
+-define(PH_KEEPALIVE,               <<"${keepalive}">>          ).
 %% MQTT clean_start
--define(PH_CLEAR_START, ?PH(<<"clean_start">>)).
+-define(PH_CLEAR_START,             <<"${clean_start}">>        ).
 %% MQTT Session Expiration time
--define(PH_EXPIRY_INTERVAL, ?PH(<<"expiry_interval">>)).
+-define(PH_EXPIRY_INTERVAL,         <<"${expiry_interval}">>    ).
 
 %% Time when PUBLISH message reaches Broker (ms)
--define(PH_PUBLISH_RECEIVED_AT, ?PH(<<"publish_received_at">>)).
+-define(PH_PUBLISH_RECEIVED_AT,     <<"${publish_received_at}">>).
 %% Mountpoint for bridging messages
--define(PH_MOUNTPOINT, ?PH(<<"mountpoint">>)).
+-define(PH_MOUNTPOINT,              <<"${mountpoint}">>         ).
 %% IPAddress and Port of terminal
--define(PH_PEERNAME, ?PH(<<"peername">>)).
+-define(PH_PEERNAME,                <<"${peername}">>           ).
 %% IPAddress and Port listened by emqx
--define(PH_SOCKNAME, ?PH(<<"sockname">>)).
+-define(PH_SOCKNAME,                <<"${sockname}">>           ).
 %% whether it is MQTT bridge connection
--define(PH_IS_BRIDGE, ?PH(<<"is_bridge">>)).
+-define(PH_IS_BRIDGE,               <<"${is_bridge}">>          ).
 %% Terminal connection completion time (s)
--define(PH_CONNECTED_AT, ?PH(<<"connected_at">>)).
+-define(PH_CONNECTED_AT,            <<"${connected_at}">>       ).
 %% Event trigger time(millisecond)
--define(PH_TIMESTAMP, ?PH(<<"timestamp">>)).
+-define(PH_TIMESTAMP,               <<"${timestamp}">>          ).
 %% Terminal disconnection completion time (s)
--define(PH_DISCONNECTED_AT, ?PH(<<"disconnected_at">>)).
+-define(PH_DISCONNECTED_AT,         <<"${disconnected_at}">>    ).
 
--define(PH_NODE, ?PH(<<"node">>)).
--define(PH_REASON, ?PH(<<"reason">>)).
+-define(PH_NODE,                    <<"${node}">>               ).
+-define(PH_REASON,                  <<"${reason}">>             ).
+
+%% sync change these place holder with binary def.
+-define(PH_S_ACTION,                  "${action}"               ).
+-define(PH_S_CERT_SUBJECT,            "${cert_subject}"         ).
+-define(PH_S_CERT_CN_NAME,            "${cert_common_name}"     ).
+-define(PH_S_PASSWORD,                "${password}"             ).
+-define(PH_S_CLIENTID,                "${clientid}"             ).
+-define(PH_S_FROM_CLIENTID,           "${from_clientid}"        ).
+-define(PH_S_USERNAME,                "${username}"             ).
+-define(PH_S_FROM_USERNAME,           "${from_username}"        ).
+-define(PH_S_TOPIC,                   "${topic}"                ).
+-define(PH_S_PAYLOAD,                 "${payload}"              ).
+-define(PH_S_PEERHOST,                "${peerhost}"             ).
+-define(PH_S_HOST,                    "${host}"                 ).
+-define(PH_S_PORT,                    "${port}"                 ).
+-define(PH_S_QOS,                     "${qos}"                  ).
+-define(PH_S_FLAGS,                   "${flags}"                ).
+-define(PH_S_HEADERS,                 "${headers}"              ).
+-define(PH_S_PROTONAME,               "${proto_name}"           ).
+-define(PH_S_PROTOVER,                "${proto_ver}"            ).
+-define(PH_S_KEEPALIVE,               "${keepalive}"            ).
+-define(PH_S_CLEAR_START,             "${clean_start}"          ).
+-define(PH_S_EXPIRY_INTERVAL,         "${expiry_interval}"      ).
+-define(PH_S_PUBLISH_RECEIVED_AT,     "${publish_received_at}"  ).
+-define(PH_S_MOUNTPOINT,              "${mountpoint}"           ).
+-define(PH_S_PEERNAME,                "${peername}"             ).
+-define(PH_S_SOCKNAME,                "${sockname}"             ).
+-define(PH_S_IS_BRIDGE,               "${is_bridge}"            ).
+-define(PH_S_CONNECTED_AT,            "${connected_at}"         ).
+-define(PH_S_TIMESTAMP,               "${timestamp}"            ).
+-define(PH_S_DISCONNECTED_AT,         "${disconnected_at}"      ).
+-define(PH_S_NODE,                    "${node}"                 ).
+-define(PH_S_REASON,                  "${reason}"               ).
 
 -endif.

+ 7 - 6
apps/emqx/src/emqx_mountpoint.erl

@@ -17,6 +17,7 @@
 -module(emqx_mountpoint).
 
 -include("emqx.hrl").
+-include("emqx_placeholder.hrl").
 -include("types.hrl").
 
 -export([ mount/2
@@ -68,12 +69,12 @@ replvar(undefined, _Vars) ->
     undefined;
 replvar(MountPoint, #{clientid := ClientId, username := Username}) ->
     lists:foldl(fun feed_var/2, MountPoint,
-                [{<<"%c">>, ClientId}, {<<"%u">>, Username}]).
+                [{?PH_CLIENTID, ClientId}, {?PH_USERNAME, Username}]).
 
-feed_var({<<"%c">>, ClientId}, MountPoint) ->
-    emqx_topic:feed_var(<<"%c">>, ClientId, MountPoint);
-feed_var({<<"%u">>, undefined}, MountPoint) ->
+feed_var({?PH_CLIENTID, ClientId}, MountPoint) ->
+    emqx_topic:feed_var(?PH_CLIENTID, ClientId, MountPoint);
+feed_var({?PH_USERNAME, undefined}, MountPoint) ->
     MountPoint;
-feed_var({<<"%u">>, Username}, MountPoint) ->
-    emqx_topic:feed_var(<<"%u">>, Username, MountPoint).
+feed_var({?PH_USERNAME, Username}, MountPoint) ->
+    emqx_topic:feed_var(?PH_USERNAME, Username, MountPoint).
 

+ 3 - 3
apps/emqx/test/emqx_mountpoint_SUITE.erl

@@ -55,12 +55,12 @@ t_unmount(_) ->
 t_replvar(_) ->
     ?assertEqual(undefined, replvar(undefined, #{})),
     ?assertEqual(<<"mount/user/clientid/">>,
-                 replvar(<<"mount/%u/%c/">>,
+                 replvar(<<"mount/${username}/${clientid}/">>,
                          #{clientid => <<"clientid">>,
                            username => <<"user">>
                           })),
-    ?assertEqual(<<"mount/%u/clientid/">>,
-                 replvar(<<"mount/%u/%c/">>,
+    ?assertEqual(<<"mount/${username}/clientid/">>,
+                 replvar(<<"mount/${username}/${clientid}/">>,
                          #{clientid => <<"clientid">>,
                            username => undefined
                           })).

+ 6 - 5
apps/emqx_authn/src/emqx_authn_api.erl

@@ -20,6 +20,7 @@
 
 -include_lib("typerefl/include/types.hrl").
 -include("emqx_authn.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 -import(hoconsc, [mk/2, ref/1]).
 -import(emqx_dashboard_swagger, [error_codes/2]).
@@ -969,8 +970,8 @@ authenticator_examples() ->
                     <<"content-type">> => <<"application/json">>
                 },
                 body => #{
-                    <<"username">> => <<"${mqtt-username}">>,
-                    <<"password">> => <<"${mqtt-password}">>
+                    <<"username">> => ?PH_USERNAME,
+                    <<"password">> => ?PH_PASSWORD
                 },
                 pool_size => 8,
                 connect_timeout => 5000,
@@ -988,7 +989,7 @@ authenticator_examples() ->
                 secret => <<"mysecret">>,
                 secret_base64_encoded => false,
                 verify_claims => #{
-                    <<"username">> => <<"${mqtt-username}">>
+                    <<"username">> => ?PH_USERNAME
                 }
             }
         },
@@ -1001,7 +1002,7 @@ authenticator_examples() ->
                 database => example,
                 collection => users,
                 selector => #{
-                    username => <<"${mqtt-username}">>
+                    username => ?PH_USERNAME
                 },
                 password_hash_field => <<"password_hash">>,
                 salt_field => <<"salt">>,
@@ -1017,7 +1018,7 @@ authenticator_examples() ->
                 backend => <<"redis">>,
                 server => <<"127.0.0.1:6379">>,
                 database => 0,
-                query => <<"HMGET ${mqtt-username} password_hash salt">>,
+                query => <<"HMGET ${username} password_hash salt">>,
                 password_hash_algorithm => <<"sha256">>,
                 salt_position => <<"prefix">>
             }

+ 8 - 6
apps/emqx_authn/src/emqx_authn_utils.erl

@@ -16,6 +16,8 @@
 
 -module(emqx_authn_utils).
 
+-include_lib("emqx/include/emqx_placeholder.hrl").
+
 -export([ replace_placeholders/2
         , replace_placeholder/2
         , check_password/3
@@ -47,17 +49,17 @@ replace_placeholders([Placeholder | More], Credential, Acc) ->
             replace_placeholders(More, Credential, [convert_to_sql_param(V) | Acc])
     end.
 
-replace_placeholder(<<"${mqtt-username}">>, Credential) ->
+replace_placeholder(?PH_USERNAME, Credential) ->
     maps:get(username, Credential, undefined);
-replace_placeholder(<<"${mqtt-clientid}">>, Credential) ->
+replace_placeholder(?PH_CLIENTID, Credential) ->
     maps:get(clientid, Credential, undefined);
-replace_placeholder(<<"${mqtt-password}">>, Credential) ->
+replace_placeholder(?PH_PASSWORD, Credential) ->
     maps:get(password, Credential, undefined);
-replace_placeholder(<<"${ip-address}">>, Credential) ->
+replace_placeholder(?PH_PEERHOST, Credential) ->
     maps:get(peerhost, Credential, undefined);
-replace_placeholder(<<"${cert-subject}">>, Credential) ->
+replace_placeholder(?PH_CERT_SUBJECT, Credential) ->
     maps:get(dn, Credential, undefined);
-replace_placeholder(<<"${cert-common-name}">>, Credential) ->
+replace_placeholder(?PH_CERT_CN_NAME, Credential) ->
     maps:get(cn, Credential, undefined);
 replace_placeholder(Constant, _) ->
     Constant.

+ 4 - 4
apps/emqx_authn/src/simple_authn/emqx_authn_jwks_connector.erl

@@ -82,10 +82,10 @@ handle_info({refresh_jwks, _TRef, refresh}, #{request_id := RequestID} = State)
         _ ->
             ok = httpc:cancel_request(RequestID),
             receive
-				{http, _} -> ok
-			after 0 ->
-				ok
-			end
+                {http, _} -> ok
+            after 0 ->
+                    ok
+            end
     end,
     {noreply, refresh_jwks(State)};
 

+ 2 - 2
apps/emqx_authn/src/simple_authn/emqx_authn_jwt.erl

@@ -345,7 +345,7 @@ handle_placeholder(Placeholder0) ->
             Placeholder0
     end.
 
-validate_placeholder(<<"mqtt-clientid">>) ->
+validate_placeholder(<<"clientid">>) ->
     clientid;
-validate_placeholder(<<"mqtt-username">>) ->
+validate_placeholder(<<"username">>) ->
     username.

+ 1 - 0
apps/emqx_authn/test/data/user-credentials-malformed-1.json

@@ -4,6 +4,7 @@
         "password_hash":"c5e46903df45e5dc096dc74657610dbee8deaacae656df88a1788f1847390242",
         "salt": "e378187547bf2d6f0545a3f441aa4d8a",
         "is_superuser": true
+    
     ,
     {
         "user_id":"myuser2",

+ 4 - 0
apps/emqx_authn/test/emqx_authn_api_SUITE.erl

@@ -58,6 +58,10 @@ init_per_suite(Config) ->
     ok = emqx_common_test_helpers:start_apps(
            [emqx_authn, emqx_dashboard],
            fun set_special_configs/1),
+
+    ?AUTHN:delete_chain(?GLOBAL),
+    {ok, Chains} = ?AUTHN:list_chains(),
+    ?assertEqual(length(Chains), 0),
     Config.
 
 end_per_suite(_Config) ->

+ 6 - 4
apps/emqx_authn/test/emqx_authn_mysql_SUITE.erl

@@ -21,6 +21,7 @@
 -include("emqx_authn.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
@@ -62,7 +63,9 @@ t_authn(_) ->
                <<"backend">> => <<"mysql">>,
                <<"server">> => <<"127.0.0.1:3306">>,
                <<"database">> => <<"mqtt">>,
-               <<"query">> => <<"SELECT password_hash, salt FROM users where username = ${mqtt-username} LIMIT 1">>
+               <<"query">> =>
+                   <<"SELECT password_hash, salt FROM users where username = ",
+                        ?PH_USERNAME/binary, " LIMIT 1">>
                },
     {ok, _} = update_config([authentication], {create_authenticator, ?GLOBAL, Config}),
 
@@ -77,14 +80,13 @@ t_authn(_) ->
                    listener => 'tcp:default',
                    protocol => mqtt,
                    username => <<"good">>,
-			       password => Password},
+                   password => Password},
     ?assertEqual({ok, #{is_superuser => false}}, emqx_access_control:authenticate(ClientInfo)),
 
     ClientInfo2 = ClientInfo#{username => <<"bad">>},
     ?assertEqual({error, not_authorized}, emqx_access_control:authenticate(ClientInfo2)),
-
+    emqx_authn_test_lib:delete_config(<<"password-based:mysql">>),
     ?AUTHN:delete_chain(?GLOBAL).
 
 update_config(Path, ConfigRequest) ->
     emqx:update_config(Path, ConfigRequest, #{rawconf_with_defaults => true}).
-

+ 12 - 6
apps/emqx_authn/test/emqx_authn_pgsql_SUITE.erl

@@ -22,6 +22,7 @@
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
 -include_lib("epgsql/include/epgsql.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
@@ -55,11 +56,12 @@ end_per_testcase(_, _Config) ->
 %%------------------------------------------------------------------------------
 
 t_parse_query(_) ->
-    Query1 = <<"${mqtt-username}">>,
-    ?assertEqual({<<"$1">>, [<<"${mqtt-username}">>]}, emqx_authn_pgsql:parse_query(Query1)),
+    Query1 = ?PH_USERNAME,
+    ?assertEqual({<<"$1">>, [?PH_USERNAME]}, emqx_authn_pgsql:parse_query(Query1)),
 
-    Query2 = <<"${mqtt-username}, ${mqtt-clientid}">>,
-    ?assertEqual({<<"$1, $2">>, [<<"${mqtt-username}">>, <<"${mqtt-clientid}">>]}, emqx_authn_pgsql:parse_query(Query2)),
+    Query2 = <<?PH_USERNAME/binary, ", ", ?PH_CLIENTID/binary>>,
+    ?assertEqual({<<"$1, $2">>, [?PH_USERNAME, ?PH_CLIENTID]},
+        emqx_authn_pgsql:parse_query(Query2)),
 
     Query3 = <<"nomatch">>,
     ?assertEqual({<<"nomatch">>, []}, emqx_authn_pgsql:parse_query(Query3)).
@@ -73,13 +75,16 @@ t_authn(_) ->
                <<"backend">> => <<"postgresql">>,
                <<"server">> => <<"127.0.0.1:5432">>,
                <<"database">> => <<"mqtt">>,
-               <<"query">> => <<"SELECT password_hash, salt FROM users where username = ${mqtt-username} LIMIT 1">>
+               <<"query">> =>
+                   <<"SELECT password_hash, salt FROM users where username = ",
+                    ?PH_USERNAME/binary, " LIMIT 1">>
                },
     {ok, _} = update_config([authentication], {create_authenticator, ?GLOBAL, Config}),
 
     meck:expect(emqx_resource, query,
         fun(_, {sql, _, [<<"good">>]}) ->
-            {ok, [#column{name = <<"password_hash">>}, #column{name = <<"salt">>}], [{PasswordHash, Salt}]};
+            {ok, [#column{name = <<"password_hash">>}, #column{name = <<"salt">>}],
+                    [{PasswordHash, Salt}]};
            (_, {sql, _, _}) ->
             {error, this_is_a_fictitious_reason}
         end),
@@ -94,6 +99,7 @@ t_authn(_) ->
     ClientInfo2 = ClientInfo#{username => <<"bad">>},
     ?assertEqual({error, not_authorized}, emqx_access_control:authenticate(ClientInfo2)),
 
+    emqx_authn_test_lib:delete_config(<<"password-based:postgresql">>),
     ?AUTHN:delete_chain(?GLOBAL).
 
 update_config(Path, ConfigRequest) ->

+ 9 - 9
apps/emqx_authn/test/emqx_authn_redis_SUITE.erl

@@ -99,11 +99,11 @@ t_create_invalid(_Config) ->
          AuthConfig#{password => <<"wrongpass">>},
          AuthConfig#{database => <<"5678">>},
          AuthConfig#{
-           query => <<"MGET password_hash:${mqtt-username} salt:${mqtt-username}">>},
+           query => <<"MGET password_hash:${username} salt:${username}">>},
          AuthConfig#{
-           query => <<"HMGET mqtt_user:${mqtt-username} password_hash invalid_field">>},
+           query => <<"HMGET mqtt_user:${username} password_hash invalid_field">>},
          AuthConfig#{
-           query => <<"HMGET mqtt_user:${mqtt-username} salt is_superuser">>}
+           query => <<"HMGET mqtt_user:${username} salt is_superuser">>}
         ],
 
     lists:foreach(
@@ -178,7 +178,7 @@ t_update(_Config) ->
     CorrectConfig = raw_redis_auth_config(),
     IncorrectConfig =
         CorrectConfig#{
-             query => <<"HMGET invalid_key:${mqtt-username} password_hash salt is_superuser">>},
+             query => <<"HMGET invalid_key:${username} password_hash salt is_superuser">>},
 
     {ok, _} = emqx:update_config(
                 ?PATH,
@@ -215,7 +215,7 @@ raw_redis_auth_config() ->
         enable => <<"true">>,
 
         backend => <<"redis">>,
-        query => <<"HMGET mqtt_user:${mqtt-username} password_hash salt is_superuser">>,
+        query => <<"HMGET mqtt_user:${username} password_hash salt is_superuser">>,
         database => <<"1">>,
         password => <<"public">>,
         server => redis_server()
@@ -263,7 +263,7 @@ user_seeds() ->
                        },
        key => "mqtt_user:sha256",
        config_params => #{
-              query => <<"HMGET mqtt_user:${mqtt-clientid} password_hash salt is_superuser">>,
+              query => <<"HMGET mqtt_user:${clientid} password_hash salt is_superuser">>,
               password_hash_algorithm => <<"sha256">>,
               salt_position => <<"prefix">>
              },
@@ -299,7 +299,7 @@ user_seeds() ->
        key => "mqtt_user:bcrypt0",
        config_params => #{
               % clientid variable & username credentials
-              query => <<"HMGET mqtt_client:${mqtt-clientid} password_hash salt is_superuser">>,
+              query => <<"HMGET mqtt_client:${clientid} password_hash salt is_superuser">>,
               password_hash_algorithm => <<"bcrypt">>,
               salt_position => <<"suffix">>
              },
@@ -318,7 +318,7 @@ user_seeds() ->
        key => "mqtt_user:bcrypt1",
        config_params => #{
               % Bad key in query
-              query => <<"HMGET badkey:${mqtt-username} password_hash salt is_superuser">>,
+              query => <<"HMGET badkey:${username} password_hash salt is_superuser">>,
               password_hash_algorithm => <<"bcrypt">>,
               salt_position => <<"suffix">>
              },
@@ -337,7 +337,7 @@ user_seeds() ->
                        },
        key => "mqtt_user:bcrypt2",
        config_params => #{
-              query => <<"HMGET mqtt_user:${mqtt-username} password_hash salt is_superuser">>,
+              query => <<"HMGET mqtt_user:${username} password_hash salt is_superuser">>,
               password_hash_algorithm => <<"bcrypt">>,
               salt_position => <<"suffix">>
              },

+ 9 - 0
apps/emqx_authn/test/emqx_authn_test_lib.erl

@@ -16,6 +16,8 @@
 
 -module(emqx_authn_test_lib).
 
+-include("emqx_authn.hrl").
+
 -compile(nowarn_export_all).
 -compile(export_all).
 
@@ -45,3 +47,10 @@ delete_authenticators(Path, Chain) ->
                 end,
                 Authenticators)
     end.
+
+delete_config(ID) ->
+    {ok, _} =
+        emqx:update_config(
+            [authentication],
+            {delete_authenticator, ?GLOBAL, ID},
+            #{rawconf_with_defaults => false}).

+ 19 - 9
apps/emqx_authz/src/emqx_authz_http.erl

@@ -19,6 +19,7 @@
 -include("emqx_authz.hrl").
 -include_lib("emqx/include/emqx.hrl").
 -include_lib("emqx/include/logger.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 %% AuthZ Callbacks
 -export([ authorize/4
@@ -42,7 +43,7 @@ authorize(Client, PubSub, Topic,
               annotations := #{id := ResourceID}
              } = Source) ->
     Request = case Method of
-                  get  -> 
+                  get  ->
                       Query = maps:get(query, Url, ""),
                       Path1 = replvar(Path ++ "?" ++ Query, PubSub, Topic, Client),
                       {Path1, maps:to_list(Headers)};
@@ -68,7 +69,9 @@ query_string([], Acc) ->
     <<$&, Str/binary>> = iolist_to_binary(lists:reverse(Acc)),
     Str;
 query_string([{K, V} | More], Acc) ->
-    query_string(More, [["&", emqx_http_lib:uri_encode(K), "=", emqx_http_lib:uri_encode(V)] | Acc]).
+    query_string( More
+                , [ ["&", emqx_http_lib:uri_encode(K), "=", emqx_http_lib:uri_encode(V)]
+                  | Acc]).
 
 serialize_body(<<"application/json">>, Body) ->
     jsx:encode(Body);
@@ -84,13 +87,20 @@ replvar(Str0, PubSub, Topic,
          }) when is_list(Str0);
                  is_binary(Str0) ->
     NTopic = emqx_http_lib:uri_encode(Topic),
-    Str1 = re:replace(Str0, "%c", Clientid, [global, {return, binary}]),
-    Str2 = re:replace(Str1, "%u", bin(Username), [global, {return, binary}]),
-    Str3 = re:replace(Str2, "%a", inet_parse:ntoa(IpAddress), [global, {return, binary}]),
-    Str4 = re:replace(Str3, "%r", bin(Protocol), [global, {return, binary}]),
-    Str5 = re:replace(Str4, "%m", Mountpoint, [global, {return, binary}]),
-    Str6 = re:replace(Str5, "%t", NTopic, [global, {return, binary}]),
-    Str7 = re:replace(Str6, "%A", bin(PubSub), [global, {return, binary}]),
+    Str1 = re:replace( Str0, ?PH_S_CLIENTID
+                     , Clientid, [global, {return, binary}]),
+    Str2 = re:replace( Str1, ?PH_S_USERNAME
+                     , bin(Username), [global, {return, binary}]),
+    Str3 = re:replace( Str2, ?PH_S_HOST
+                     , inet_parse:ntoa(IpAddress), [global, {return, binary}]),
+    Str4 = re:replace( Str3, ?PH_S_PROTONAME
+                     , bin(Protocol), [global, {return, binary}]),
+    Str5 = re:replace( Str4, ?PH_S_MOUNTPOINT
+                     , Mountpoint, [global, {return, binary}]),
+    Str6 = re:replace( Str5, ?PH_S_TOPIC
+                     , NTopic, [global, {return, binary}]),
+    Str7 = re:replace( Str6, ?PH_S_ACTION
+                     , bin(PubSub), [global, {return, binary}]),
     Str7.
 
 bin(A) when is_atom(A) -> atom_to_binary(A, utf8);

+ 19 - 11
apps/emqx_authz/src/emqx_authz_mongodb.erl

@@ -19,6 +19,7 @@
 -include("emqx_authz.hrl").
 -include_lib("emqx/include/emqx.hrl").
 -include_lib("emqx/include/logger.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 %% AuthZ Callbacks
 -export([ authorize/4
@@ -40,12 +41,16 @@ authorize(Client, PubSub, Topic,
              }) ->
     case emqx_resource:query(ResourceID, {find, Collection, replvar(Selector, Client), #{}}) of
         {error, Reason} ->
-            ?SLOG(error, #{msg => "query_mongo_error", reason => Reason, resource_id => ResourceID}),
+            ?SLOG(error, #{msg => "query_mongo_error",
+                           reason => Reason,
+                           resource_id => ResourceID}),
             nomatch;
         [] -> nomatch;
         Rows ->
             Rules = [ emqx_authz_rule:compile({Permission, all, Action, Topics})
-                     || #{<<"topics">> := Topics, <<"permission">> := Permission, <<"action">> := Action} <- Rows],
+                     || #{<<"topics">> := Topics,
+                          <<"permission">> := Permission,
+                          <<"action">> := Action} <- Rows],
             do_authorize(Client, PubSub, Topic, Rules)
     end.
 
@@ -62,19 +67,23 @@ replvar(Selector, #{clientid := Clientid,
                     peerhost := IpAddress
                    }) ->
     Fun = fun
-              _Fun(K, V, AccIn) when is_map(V) -> maps:put(K, maps:fold(_Fun, AccIn, V), AccIn);
-              _Fun(K, V, AccIn) when is_list(V) ->
+              InFun(K, V, AccIn) when is_map(V) ->
+                  maps:put(K, maps:fold(InFun, AccIn, V), AccIn);
+              InFun(K, V, AccIn) when is_list(V) ->
                   maps:put(K, [ begin
                                     [{K1, V1}] = maps:to_list(M),
-                                    _Fun(K1, V1, AccIn)
+                                    InFun(K1, V1, AccIn)
                                 end || M <- V],
                            AccIn);
-              _Fun(K, V, AccIn) when is_binary(V) ->
-                  V1 = re:replace(V,  "%c", bin(Clientid), [global, {return, binary}]),
-                  V2 = re:replace(V1, "%u", bin(Username), [global, {return, binary}]),
-                  V3 = re:replace(V2, "%a", inet_parse:ntoa(IpAddress), [global, {return, binary}]),
+              InFun(K, V, AccIn) when is_binary(V) ->
+                  V1 = re:replace( V,  ?PH_S_CLIENTID
+                                 , bin(Clientid), [global, {return, binary}]),
+                  V2 = re:replace( V1, ?PH_S_USERNAME
+                                 , bin(Username), [global, {return, binary}]),
+                  V3 = re:replace( V2, ?PH_S_HOST
+                                 , inet_parse:ntoa(IpAddress), [global, {return, binary}]),
                   maps:put(K, V3, AccIn);
-              _Fun(K, V, AccIn) -> maps:put(K, V, AccIn)
+              InFun(K, V, AccIn) -> maps:put(K, V, AccIn)
           end,
     maps:fold(Fun, #{}, Selector).
 
@@ -82,4 +91,3 @@ bin(A) when is_atom(A) -> atom_to_binary(A, utf8);
 bin(B) when is_binary(B) -> B;
 bin(L) when is_list(L) -> list_to_binary(L);
 bin(X) -> X.
-

+ 11 - 9
apps/emqx_authz/src/emqx_authz_mysql.erl

@@ -19,6 +19,7 @@
 -include("emqx_authz.hrl").
 -include_lib("emqx/include/emqx.hrl").
 -include_lib("emqx/include/logger.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 %% AuthZ Callbacks
 -export([ description/0
@@ -55,7 +56,9 @@ authorize(Client, PubSub, Topic,
         {ok, Columns, Rows} ->
             do_authorize(Client, PubSub, Topic, Columns, Rows);
         {error, Reason} ->
-            ?SLOG(error, #{msg => "query_mysql_error", reason => Reason, resource_id => ResourceID}),
+            ?SLOG(error, #{ msg => "query_mysql_error"
+                          , reason => Reason
+                          , resource_id => ResourceID}),
             nomatch
     end.
 
@@ -87,16 +90,16 @@ replvar(Params, ClientInfo) ->
 replvar([], _ClientInfo, Acc) ->
     lists:reverse(Acc);
 
-replvar(["'%u'" | Params], ClientInfo, Acc) ->
+replvar([?PH_S_USERNAME | Params], ClientInfo, Acc) ->
     replvar(Params, ClientInfo, [safe_get(username, ClientInfo) | Acc]);
-replvar(["'%c'" | Params], ClientInfo = #{clientid := ClientId}, Acc) ->
+replvar([?PH_S_CLIENTID | Params], ClientInfo = #{clientid := ClientId}, Acc) ->
     replvar(Params, ClientInfo, [ClientId | Acc]);
-replvar(["'%a'" | Params], ClientInfo = #{peerhost := IpAddr}, Acc) ->
+replvar([?PH_S_PEERHOST | Params], ClientInfo = #{peerhost := IpAddr}, Acc) ->
     replvar(Params, ClientInfo, [inet_parse:ntoa(IpAddr) | Acc]);
-replvar(["'%C'" | Params], ClientInfo, Acc) ->
-    replvar(Params, ClientInfo, [safe_get(cn, ClientInfo)| Acc]);
-replvar(["'%d'" | Params], ClientInfo, Acc) ->
-    replvar(Params, ClientInfo, [safe_get(dn, ClientInfo)| Acc]);
+replvar([?PH_S_CERT_CN_NAME | Params], ClientInfo, Acc) ->
+    replvar(Params, ClientInfo, [safe_get(cn, ClientInfo) | Acc]);
+replvar([?PH_S_CERT_SUBJECT | Params], ClientInfo, Acc) ->
+    replvar(Params, ClientInfo, [safe_get(dn, ClientInfo) | Acc]);
 replvar([Param | Params], ClientInfo, Acc) ->
     replvar(Params, ClientInfo, [Param | Acc]).
 
@@ -107,4 +110,3 @@ bin(A) when is_atom(A) -> atom_to_binary(A, utf8);
 bin(B) when is_binary(B) -> B;
 bin(L) when is_list(L) -> list_to_binary(L);
 bin(X) -> X.
-

+ 11 - 9
apps/emqx_authz/src/emqx_authz_postgresql.erl

@@ -19,6 +19,7 @@
 -include("emqx_authz.hrl").
 -include_lib("emqx/include/emqx.hrl").
 -include_lib("emqx/include/logger.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 %% AuthZ Callbacks
 -export([ description/0
@@ -59,7 +60,9 @@ authorize(Client, PubSub, Topic,
         {ok, Columns, Rows} ->
             do_authorize(Client, PubSub, Topic, Columns, Rows);
         {error, Reason} ->
-            ?SLOG(error, #{msg => "query_postgresql_error", reason => Reason, resource_id => ResourceID}),
+            ?SLOG(error, #{ msg => "query_postgresql_error"
+                          , reason => Reason
+                          , resource_id => ResourceID}),
             nomatch
     end.
 
@@ -92,16 +95,16 @@ replvar(Params, ClientInfo) ->
 replvar([], _ClientInfo, Acc) ->
     lists:reverse(Acc);
 
-replvar(["'%u'" | Params], ClientInfo, Acc) ->
+replvar([?PH_S_USERNAME | Params], ClientInfo, Acc) ->
     replvar(Params, ClientInfo, [safe_get(username, ClientInfo) | Acc]);
-replvar(["'%c'" | Params], ClientInfo = #{clientid := ClientId}, Acc) ->
+replvar([?PH_S_CLIENTID | Params], ClientInfo = #{clientid := ClientId}, Acc) ->
     replvar(Params, ClientInfo, [ClientId | Acc]);
-replvar(["'%a'" | Params], ClientInfo = #{peerhost := IpAddr}, Acc) ->
+replvar([?PH_S_PEERHOST | Params], ClientInfo = #{peerhost := IpAddr}, Acc) ->
     replvar(Params, ClientInfo, [inet_parse:ntoa(IpAddr) | Acc]);
-replvar(["'%C'" | Params], ClientInfo, Acc) ->
-    replvar(Params, ClientInfo, [safe_get(cn, ClientInfo)| Acc]);
-replvar(["'%d'" | Params], ClientInfo, Acc) ->
-    replvar(Params, ClientInfo, [safe_get(dn, ClientInfo)| Acc]);
+replvar([?PH_S_CERT_CN_NAME | Params], ClientInfo, Acc) ->
+    replvar(Params, ClientInfo, [safe_get(cn, ClientInfo) | Acc]);
+replvar([?PH_S_CERT_SUBJECT | Params], ClientInfo, Acc) ->
+    replvar(Params, ClientInfo, [safe_get(dn, ClientInfo) | Acc]);
 replvar([Param | Params], ClientInfo, Acc) ->
     replvar(Params, ClientInfo, [Param | Acc]).
 
@@ -112,4 +115,3 @@ bin(A) when is_atom(A) -> atom_to_binary(A, utf8);
 bin(B) when is_binary(B) -> B;
 bin(L) when is_list(L) -> list_to_binary(L);
 bin(X) -> X.
-

+ 8 - 5
apps/emqx_authz/src/emqx_authz_redis.erl

@@ -19,6 +19,7 @@
 -include("emqx_authz.hrl").
 -include_lib("emqx/include/emqx.hrl").
 -include_lib("emqx/include/logger.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 %% AuthZ Callbacks
 -export([ authorize/4
@@ -43,7 +44,9 @@ authorize(Client, PubSub, Topic,
         {ok, Rows} ->
             do_authorize(Client, PubSub, Topic, Rows);
         {error, Reason} ->
-            ?SLOG(error, #{msg => "query_redis_error", reason => Reason, resource_id => ResourceID}),
+            ?SLOG(error, #{ msg => "query_redis_error"
+                          , reason => Reason
+                          , resource_id => ResourceID}),
             nomatch
     end.
 
@@ -58,13 +61,13 @@ do_authorize(Client, PubSub, Topic, [TopicFilter, Action | Tail]) ->
     end.
 
 replvar(Cmd, Client = #{cn := CN}) ->
-    replvar(repl(Cmd, "%C", CN), maps:remove(cn, Client));
+    replvar(repl(Cmd, ?PH_S_CERT_CN_NAME, CN), maps:remove(cn, Client));
 replvar(Cmd, Client = #{dn := DN}) ->
-    replvar(repl(Cmd, "%d", DN), maps:remove(dn, Client));
+    replvar(repl(Cmd, ?PH_S_CERT_SUBJECT, DN), maps:remove(dn, Client));
 replvar(Cmd, Client = #{clientid := ClientId}) ->
-    replvar(repl(Cmd, "%c", ClientId), maps:remove(clientid, Client));
+    replvar(repl(Cmd, ?PH_S_CLIENTID, ClientId), maps:remove(clientid, Client));
 replvar(Cmd, Client = #{username := Username}) ->
-    replvar(repl(Cmd, "%u", Username), maps:remove(username, Client));
+    replvar(repl(Cmd, ?PH_S_USERNAME, Username), maps:remove(username, Client));
 replvar(Cmd, _) ->
     Cmd.
 

+ 21 - 17
apps/emqx_authz/src/emqx_authz_rule.erl

@@ -18,6 +18,7 @@
 
 -include("emqx_authz.hrl").
 -include_lib("emqx/include/logger.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 -ifdef(TEST).
 -compile(export_all).
@@ -32,9 +33,12 @@
 
 -export_type([rule/0]).
 
-compile({Permission, all}) when ?ALLOW_DENY(Permission) -> {Permission, all, all, [compile_topic(<<"#">>)]};
-compile({Permission, Who, Action, TopicFilters}) when ?ALLOW_DENY(Permission), ?PUBSUB(Action), is_list(TopicFilters) ->
-    {atom(Permission), compile_who(Who), atom(Action), [compile_topic(Topic) || Topic <- TopicFilters]}.
+compile({Permission, all})
+  when ?ALLOW_DENY(Permission) -> {Permission, all, all, [compile_topic(<<"#">>)]};
+compile({Permission, Who, Action, TopicFilters})
+  when ?ALLOW_DENY(Permission), ?PUBSUB(Action), is_list(TopicFilters) ->
+    { atom(Permission), compile_who(Who), atom(Action)
+    , [compile_topic(Topic) || Topic <- TopicFilters]}.
 
 compile_who(all) -> all;
 compile_who({user, Username}) -> compile_who({username, Username});
@@ -68,12 +72,12 @@ compile_topic(Topic) ->
     end.
 
 pattern(Words) ->
-    lists:member(<<"%u">>, Words) orelse lists:member(<<"%c">>, Words).
+    lists:member(?PH_USERNAME, Words) orelse lists:member(?PH_CLIENTID, Words).
 
 atom(B) when is_binary(B) ->
     try binary_to_existing_atom(B, utf8)
     catch
-        _ -> binary_to_atom(B)
+        _E:_S -> binary_to_atom(B)
     end;
 atom(A) when is_atom(A) -> A.
 
@@ -143,11 +147,11 @@ match_who(_, _) -> false.
 
 match_topics(_ClientInfo, _Topic, []) ->
     false;
-match_topics(ClientInfo, Topic, [{pattern, PatternFilter}|Filters]) ->
+match_topics(ClientInfo, Topic, [{pattern, PatternFilter} | Filters]) ->
     TopicFilter = feed_var(ClientInfo, PatternFilter),
     match_topic(emqx_topic:words(Topic), TopicFilter)
         orelse match_topics(ClientInfo, Topic, Filters);
-match_topics(ClientInfo, Topic, [TopicFilter|Filters]) ->
+match_topics(ClientInfo, Topic, [TopicFilter | Filters]) ->
    match_topic(emqx_topic:words(Topic), TopicFilter)
        orelse match_topics(ClientInfo, Topic, Filters).
 
@@ -160,13 +164,13 @@ feed_var(ClientInfo, Pattern) ->
     feed_var(ClientInfo, Pattern, []).
 feed_var(_ClientInfo, [], Acc) ->
     lists:reverse(Acc);
-feed_var(ClientInfo = #{clientid := undefined}, [<<"%c">>|Words], Acc) ->
-    feed_var(ClientInfo, Words, [<<"%c">>|Acc]);
-feed_var(ClientInfo = #{clientid := ClientId}, [<<"%c">>|Words], Acc) ->
-    feed_var(ClientInfo, Words, [ClientId |Acc]);
-feed_var(ClientInfo = #{username := undefined}, [<<"%u">>|Words], Acc) ->
-    feed_var(ClientInfo, Words, [<<"%u">>|Acc]);
-feed_var(ClientInfo = #{username := Username}, [<<"%u">>|Words], Acc) ->
-    feed_var(ClientInfo, Words, [Username|Acc]);
-feed_var(ClientInfo, [W|Words], Acc) ->
-    feed_var(ClientInfo, Words, [W|Acc]).
+feed_var(ClientInfo = #{clientid := undefined}, [?PH_CLIENTID | Words], Acc) ->
+    feed_var(ClientInfo, Words, [?PH_CLIENTID | Acc]);
+feed_var(ClientInfo = #{clientid := ClientId}, [?PH_CLIENTID | Words], Acc) ->
+    feed_var(ClientInfo, Words, [ClientId | Acc]);
+feed_var(ClientInfo = #{username := undefined}, [?PH_USERNAME | Words], Acc) ->
+    feed_var(ClientInfo, Words, [?PH_USERNAME | Acc]);
+feed_var(ClientInfo = #{username := Username}, [?PH_USERNAME | Words], Acc) ->
+    feed_var(ClientInfo, Words, [Username | Acc]);
+feed_var(ClientInfo, [W | Words], Acc) ->
+    feed_var(ClientInfo, Words, [W | Acc]).

+ 2 - 1
apps/emqx_authz/test/emqx_authz_SUITE.erl

@@ -21,6 +21,7 @@
 -include("emqx_authz.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
@@ -107,7 +108,7 @@ set_special_configs(_App) ->
                    <<"password">> => <<"ee">>,
                    <<"auto_reconnect">> => true,
                    <<"ssl">> => #{<<"enable">> => false},
-                   <<"cmd">> => <<"HGETALL mqtt_authz:%u">>
+                   <<"cmd">> => <<"HGETALL mqtt_authz:", ?PH_USERNAME/binary>>
                   }).
 -define(SOURCE6, #{<<"type">> => <<"file">>,
                    <<"enable">> => true,

+ 2 - 1
apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl

@@ -21,6 +21,7 @@
 -include("emqx_authz.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 -define(HOST, "http://127.0.0.1:18083/").
 -define(API_VERSION, "v5").
@@ -77,7 +78,7 @@
                    <<"password">> => <<"ee">>,
                    <<"auto_reconnect">> => true,
                    <<"ssl">> => #{<<"enable">> => false},
-                   <<"cmd">> => <<"HGETALL mqtt_authz:%u">>
+                   <<"cmd">> => <<"HGETALL mqtt_authz:", ?PH_USERNAME/binary>>
                   }).
 -define(SOURCE6, #{<<"type">> => <<"file">>,
                    <<"enable">> => true,

+ 3 - 2
apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl

@@ -21,6 +21,7 @@
 -include("emqx_authz.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
@@ -55,12 +56,12 @@ set_special_configs(_App) ->
 
 init_per_testcase(t_authz, Config) ->
     mria:dirty_write(#emqx_acl{who = {?ACL_TABLE_USERNAME, <<"test_username">>},
-                               rules = [{allow, publish, <<"test/%u">>},
+                               rules = [{allow, publish, <<"test/", ?PH_S_USERNAME>>},
                                         {allow, subscribe, <<"eq #">>}
                                        ]
                               }),
     mria:dirty_write(#emqx_acl{who = {?ACL_TABLE_CLIENTID, <<"test_clientid">>},
-                               rules = [{allow, publish, <<"test/%c">>},
+                               rules = [{allow, publish, <<"test/", ?PH_S_CLIENTID>>},
                                         {deny, subscribe, <<"eq #">>}
                                        ]
                               }),

+ 3 - 3
apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl

@@ -21,6 +21,7 @@
 -include("emqx_authz.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
@@ -74,10 +75,10 @@ set_special_configs(_App) ->
 -define(SOURCE2,[#{<<"topics">> => [<<"eq #">>],
                  <<"permission">> => <<"allow">>,
                  <<"action">> => <<"all">>}]).
--define(SOURCE3,[#{<<"topics">> => [<<"test/%c">>],
+-define(SOURCE3,[#{<<"topics">> => [<<"test/", ?PH_CLIENTID/binary>>],
                  <<"permission">> => <<"allow">>,
                  <<"action">> => <<"subscribe">>}]).
--define(SOURCE4,[#{<<"topics">> => [<<"test/%u">>],
+-define(SOURCE4,[#{<<"topics">> => [<<"test/", ?PH_USERNAME/binary>>],
                  <<"permission">> => <<"allow">>,
                  <<"action">> => <<"publish">>}]).
 
@@ -131,4 +132,3 @@ t_authz(_) ->
     ?assertEqual(deny,  emqx_access_control:authorize(
                           ClientInfo3, publish,   <<"test">>)), % nomatch
     ok.
-

+ 3 - 3
apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl

@@ -21,6 +21,7 @@
 -include("emqx_authz.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 -define(CONF_DEFAULT, <<"authorization: {sources: []}">>).
 
@@ -76,8 +77,8 @@ set_special_configs(_App) ->
                  ]).
 -define(SOURCE1, [[<<"all">>, <<"deny">>, <<"#">>]]).
 -define(SOURCE2, [[<<"all">>, <<"allow">>, <<"eq #">>]]).
--define(SOURCE3, [[<<"subscribe">>, <<"allow">>, <<"test/%c">>]]).
--define(SOURCE4, [[<<"publish">>, <<"allow">>, <<"test/%u">>]]).
+-define(SOURCE3, [[<<"subscribe">>, <<"allow">>, <<"test/", ?PH_CLIENTID/binary>>]]).
+-define(SOURCE4, [[<<"publish">>, <<"allow">>, <<"test/", ?PH_USERNAME/binary>>]]).
 
 %%------------------------------------------------------------------------------
 %% Testcases
@@ -129,4 +130,3 @@ t_authz(_) ->
     ?assertEqual(deny,  emqx_access_control:authorize(
                           ClientInfo3, publish,   <<"test">>)), % nomatch
     ok.
-

+ 3 - 3
apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl

@@ -21,6 +21,7 @@
 -include("emqx_authz.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
@@ -74,8 +75,8 @@ set_special_configs(_App) ->
                  ]).
 -define(SOURCE1, [{<<"all">>, <<"deny">>, <<"#">>}]).
 -define(SOURCE2, [{<<"all">>, <<"allow">>, <<"eq #">>}]).
--define(SOURCE3, [{<<"subscribe">>, <<"allow">>, <<"test/%c">>}]).
--define(SOURCE4, [{<<"publish">>, <<"allow">>, <<"test/%u">>}]).
+-define(SOURCE3, [{<<"subscribe">>, <<"allow">>, <<"test/", ?PH_CLIENTID/binary>>}]).
+-define(SOURCE4, [{<<"publish">>, <<"allow">>, <<"test/", ?PH_USERNAME/binary>>}]).
 
 %%------------------------------------------------------------------------------
 %% Testcases
@@ -127,4 +128,3 @@ t_authz(_) ->
     ?assertEqual(deny,  emqx_access_control:authorize(
                           ClientInfo3, publish,   <<"test">>)), % nomatch
     ok.
-

+ 4 - 4
apps/emqx_authz/test/emqx_authz_redis_SUITE.erl

@@ -21,6 +21,7 @@
 -include("emqx_authz.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 -define(CONF_DEFAULT, <<"authorization: {sources: []}">>).
 
 all() ->
@@ -45,7 +46,7 @@ init_per_suite(Config) ->
                <<"password">> => <<"ee">>,
                <<"auto_reconnect">> => true,
                <<"ssl">> => #{<<"enable">> => false},
-               <<"cmd">> => <<"HGETALL mqtt_authz:%u">>
+               <<"cmd">> => <<"HGETALL mqtt_authz:", ?PH_USERNAME/binary>>
               }],
     {ok, _} = emqx_authz:update(replace, Rules),
     Config.
@@ -68,8 +69,8 @@ set_special_configs(emqx_authz) ->
 set_special_configs(_App) ->
     ok.
 
--define(SOURCE1, [<<"test/%u">>, <<"publish">>]).
--define(SOURCE2, [<<"test/%c">>, <<"publish">>]).
+-define(SOURCE1, [<<"test/", ?PH_USERNAME/binary>>, <<"publish">>]).
+-define(SOURCE2, [<<"test/", ?PH_CLIENTID/binary>>, <<"publish">>]).
 -define(SOURCE3, [<<"#">>, <<"subscribe">>]).
 
 %%------------------------------------------------------------------------------
@@ -113,4 +114,3 @@ t_authz(_) ->
     ?assertEqual(deny,
         emqx_access_control:authorize(ClientInfo, publish, <<"#">>)),
     ok.
-

+ 5 - 4
apps/emqx_authz/test/emqx_authz_rule_SUITE.erl

@@ -21,15 +21,16 @@
 -include("emqx_authz.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
+-include_lib("emqx/include/emqx_placeholder.hrl").
 
 -define(SOURCE1, {deny,  all}).
 -define(SOURCE2, {allow, {ipaddr,  "127.0.0.1"}, all, [{eq, "#"}, {eq, "+"}]}).
--define(SOURCE3, {allow, {ipaddrs, ["127.0.0.1", "192.168.1.0/24"]}, subscribe, ["%c"]}).
+-define(SOURCE3, {allow, {ipaddrs, ["127.0.0.1", "192.168.1.0/24"]}, subscribe, [?PH_S_CLIENTID]}).
 -define(SOURCE4, {allow, {'and', [{client, "test"}, {user, "test"}]}, publish, ["topic/test"]}).
 -define(SOURCE5, {allow, {'or',
                           [{username, {re, "^test"}},
                            {clientid, {re, "test?"}}]},
-                  publish, ["%u", "%c"]}).
+                  publish, [?PH_S_USERNAME, ?PH_S_CLIENTID]}).
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
@@ -67,7 +68,7 @@ t_compile(_) ->
                   {ipaddrs,[{{127,0,0,1},{127,0,0,1},32},
                             {{192,168,1,0},{192,168,1,255},24}]},
                   subscribe,
-                  [{pattern,[<<"%c">>]}]
+                  [{pattern,[?PH_CLIENTID]}]
                }, emqx_authz_rule:compile(?SOURCE3)),
 
     ?assertMatch({allow,
@@ -79,7 +80,7 @@ t_compile(_) ->
     ?assertMatch({allow,
                   {'or', [{username, {re_pattern, _, _, _, _}},
                           {clientid, {re_pattern, _, _, _, _}}]},
-                  publish, [{pattern, [<<"%u">>]},  {pattern, [<<"%c">>]}]
+                  publish, [{pattern, [?PH_USERNAME]},  {pattern, [?PH_CLIENTID]}]
                  }, emqx_authz_rule:compile(?SOURCE5)),
     ok.
 

+ 7 - 5
apps/emqx_auto_subscribe/src/emqx_auto_subscribe_placeholder.erl

@@ -15,6 +15,8 @@
 %%--------------------------------------------------------------------
 -module(emqx_auto_subscribe_placeholder).
 
+-include_lib("emqx/include/emqx_placeholder.hrl").
+
 -export([generate/1]).
 
 -export([to_topic_table/3]).
@@ -40,13 +42,13 @@ to_topic_table(PHs, ClientInfo, ConnInfo) ->
 
 generate(<<"">>, Result) ->
     lists:reverse(Result);
-generate(<<"${clientid}", Tail/binary>>, Result) ->
+generate(<<?PH_S_CLIENTID, Tail/binary>>, Result) ->
     generate(Tail, [clientid | Result]);
-generate(<<"${username}", Tail/binary>>, Result) ->
+generate(<<?PH_S_USERNAME, Tail/binary>>, Result) ->
     generate(Tail, [username | Result]);
-generate(<<"${host}", Tail/binary>>, Result) ->
+generate(<<?PH_S_HOST, Tail/binary>>, Result) ->
     generate(Tail, [host | Result]);
-generate(<<"${port}", Tail/binary>>, Result) ->
+generate(<<?PH_S_PORT, Tail/binary>>, Result) ->
     generate(Tail, [port | Result]);
 generate(<<Char:8, Tail/binary>>, []) ->
     generate(Tail, [<<Char:8>>]);
@@ -62,7 +64,7 @@ to_topic([Binary | PTs], C, Co, Res) when is_binary(Binary) ->
 to_topic([clientid | PTs], C = #{clientid := ClientID}, Co, Res) ->
     to_topic(PTs, C, Co, [ClientID | Res]);
 to_topic([username | PTs], C = #{username := undefined}, Co, Res) ->
-    to_topic(PTs, C, Co, [<<"${username}">> | Res]);
+    to_topic(PTs, C, Co, [?PH_USERNAME | Res]);
 to_topic([username | PTs], C = #{username := Username}, Co, Res) ->
     to_topic(PTs, C, Co, [Username | Res]);
 to_topic([host | PTs], C, Co = #{peername := {Host, _}}, Res) ->

+ 1 - 1
apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl

@@ -35,7 +35,7 @@ gateway.lwm2m {
   lifetime_max = 86400s
   qmode_time_window = 22
   auto_observe = false
-  mountpoint = \"lwm2m/%u\"
+  mountpoint = \"lwm2m/${username}\"
   update_msg_publish_condition = contains_object_list
   translators {
     command = {topic = \"/dn/#\", qos = 0}

+ 1 - 1
apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl

@@ -35,7 +35,7 @@ gateway.lwm2m {
   lifetime_max = 86400s
   qmode_time_window = 200
   auto_observe = false
-  mountpoint = \"lwm2m/%u\"
+  mountpoint = \"lwm2m/${username}\"
   update_msg_publish_condition = contains_object_list
   translators {
     command = {topic = \"/dn/#\", qos = 0}