소스 검색

feat: add 'is_empty_val' and 'not' functions to variform

zmstone 1 년 전
부모
커밋
ca87f0a43e

+ 2 - 2
apps/emqx_auth_cinfo/README.md

@@ -4,7 +4,7 @@ This application implements an extended authentication for EMQX Enterprise editi
 
 Client-info (of type `cinfo`) authentication is a lightweight authentication mechanism which checks client properties and attributes against user defined rules.
 The rules make use of the Variform expression to define match conditions, and the authentication result when match is found.
-For example, to quickly fencing off clients without a username, the match condition can be `str_eq(username, '')` associated with a attributes result `deny`.
+For example, to quickly fencing off clients without a username, the match condition can be `is_empty_val(username)` associated with a attributes result `deny`.
 
 The new authenticator config look is like below.
 
@@ -21,7 +21,7 @@ authentication = [
       # deny clients with empty username and client ID starts with 'v1-'
       {
         # when is_match is an array, it yields 'true' if all individual checks yield 'true'
-        is_match = ["str_eq(username, '')", "str_eq(nth(1,tokens(clientid,'-')), 'v1')"]
+        is_match = ["is_empty_val(username)", "str_eq(nth(1,tokens(clientid,'-')), 'v1')"]
         result = deny
       }
       # if all checks are exhausted without an 'allow' or a 'deny' result, continue to the next authentication

+ 2 - 2
apps/emqx_auth_cinfo/test/emqx_authn_cinfo_SUITE.erl

@@ -42,7 +42,7 @@ t_username_equal_clientid(_) ->
     Checks =
         [
             #{
-                is_match => <<"str_eq(username, '')">>,
+                is_match => <<"is_empty_val(username)">>,
                 result => deny
             },
             #{
@@ -105,7 +105,7 @@ t_multiple_is_match_expressions(_) ->
             %% use AND to connect multiple is_match expressions
             %% this one means username is not empty, and clientid is 'super'
             is_match => [
-                <<"str_neq('', username)">>, <<"str_eq(clientid, 'super')">>
+                <<"not(is_empty_val(username))">>, <<"str_eq(clientid, 'super')">>
             ],
             result => allow
         }

+ 16 - 1
apps/emqx_utils/src/emqx_variform_bif.erl

@@ -53,7 +53,9 @@
     join_to_string/1,
     join_to_string/2,
     unescape/1,
-    any_to_str/1
+    any_to_str/1,
+    is_empty_val/1,
+    'not'/1
 ]).
 
 %% Array functions
@@ -594,6 +596,19 @@ num_gte(A, B) ->
     R = num_comp(A, B),
     R =:= gt orelse R =:= eq.
 
+%% @doc Return 'true' if the argument is `undefined`, `null` or empty string, or empty array.
+is_empty_val(undefined) -> true;
+is_empty_val(null) -> true;
+is_empty_val(<<>>) -> true;
+is_empty_val([]) -> true;
+is_empty_val(_) -> false.
+
+%% @doc The 'not' operation for boolean values and strings.
+'not'(true) -> false;
+'not'(false) -> true;
+'not'(<<"true">>) -> <<"false">>;
+'not'(<<"false">>) -> <<"true">>.
+
 %%------------------------------------------------------------------------------
 %% System
 %%------------------------------------------------------------------------------

+ 21 - 0
apps/emqx_utils/test/emqx_variform_bif_tests.erl

@@ -79,3 +79,24 @@ system_test() ->
     EnvNameBin = erlang:list_to_binary(EnvName),
     os:putenv("EMQXVAR_" ++ EnvName, EnvVal),
     ?assertEqual(erlang:list_to_binary(EnvVal), emqx_variform_bif:getenv(EnvNameBin)).
+
+empty_val_test_() ->
+    F = fun(X) -> emqx_variform_bif:is_empty_val(X) end,
+    [
+        ?_assert(F(undefined)),
+        ?_assert(F(null)),
+        ?_assert(F(<<>>)),
+        ?_assert(F([])),
+        ?_assertNot(F(true)),
+        ?_assertNot(F(false)),
+        ?_assertNot(F(<<"a">>))
+    ].
+
+bool_not_test_() ->
+    Not = fun(X) -> emqx_variform_bif:'not'(X) end,
+    [
+        ?_assertEqual(<<"false">>, Not(<<"true">>)),
+        ?_assertEqual(<<"true">>, Not(<<"false">>)),
+        ?_assertEqual(true, Not(false)),
+        ?_assertEqual(false, Not(true))
+    ].

+ 1 - 1
changes/ee/feat-13810.en.md

@@ -2,4 +2,4 @@ Add clinet-info authentication.
 
 Client-info (of type `cinfo`) authentication is a lightweight authentication mechanism which checks client properties and attributes against user defined rules.
 The rules make use of the Variform expression to define match conditions, and the authentication result when match is found.
-For example, to quickly fence off clients without a username, the match condition can be `str_eq(username, '')` associated with a check result `deny`.
+For example, to quickly fence off clients without a username, the match condition can be `is_empty_val(username)` associated with a check result `deny`.

+ 1 - 1
rel/config/ee-examples/cinfo-authn.conf

@@ -10,7 +10,7 @@ authentication = [
       # deny clients with empty username and client ID starts with 'v1-'
       {
         # when is_match is an array, it yields 'true' if all individual checks yield 'true'
-        is_match = ["str_eq(username, '')", "str_eq(nth(1,tokens(clientid,'-')), 'v1')"]
+        is_match = ["is_empty_val(username)", "str_eq(nth(1,tokens(clientid,'-')), 'v1')"]
         result = deny
       }
       # if all checks are exhausted without an 'allow' or a 'deny' result, continue to the next authentication