Browse Source

style(authn): reformat authn subdir source files

JianBo He 3 years ago
parent
commit
3022ee081d

+ 192 - 118
apps/emqx_authn/src/enhanced_authn/emqx_enhanced_authn_scram_mnesia.erl

@@ -23,47 +23,54 @@
 -behaviour(hocon_schema).
 -behaviour(emqx_authentication).
 
--export([ namespace/0
-        , roots/0
-        , fields/1
-        ]).
-
--export([ refs/0
-        , create/2
-        , update/2
-        , authenticate/2
-        , destroy/1
-        ]).
-
--export([ add_user/2
-        , delete_user/2
-        , update_user/3
-        , lookup_user/2
-        , list_users/2
-        ]).
-
--export([ query/4
-        , format_user_info/1
-        , group_match_spec/1]).
+-export([
+    namespace/0,
+    roots/0,
+    fields/1
+]).
+
+-export([
+    refs/0,
+    create/2,
+    update/2,
+    authenticate/2,
+    destroy/1
+]).
+
+-export([
+    add_user/2,
+    delete_user/2,
+    update_user/3,
+    lookup_user/2,
+    list_users/2
+]).
+
+-export([
+    query/4,
+    format_user_info/1,
+    group_match_spec/1
+]).
 
 -define(TAB, ?MODULE).
--define(AUTHN_QSCHEMA, [ {<<"like_username">>, binary}
-                       , {<<"user_group">>, binary}]).
+-define(AUTHN_QSCHEMA, [
+    {<<"like_username">>, binary},
+    {<<"user_group">>, binary}
+]).
 -define(QUERY_FUN, {?MODULE, query}).
 
--type(user_group() :: binary()).
+-type user_group() :: binary().
 
 -export([mnesia/1]).
 
 -boot_mnesia({mnesia, [boot]}).
 
--record(user_info,
-        { user_id
-        , stored_key
-        , server_key
-        , salt
-        , is_superuser
-        }).
+-record(user_info, {
+    user_id,
+    stored_key,
+    server_key,
+    salt,
+    is_superuser
+}).
 
 -reflect_type([user_group/0]).
 
@@ -72,14 +79,15 @@
 %%------------------------------------------------------------------------------
 
 %% @doc Create or replicate tables.
--spec(mnesia(boot | copy) -> ok).
+-spec mnesia(boot | copy) -> ok.
 mnesia(boot) ->
     ok = mria:create_table(?TAB, [
-                {rlog_shard, ?AUTH_SHARD},
-                {storage, disc_copies},
-                {record_name, user_info},
-                {attributes, record_info(fields, user_info)},
-                {storage_properties, [{ets, [{read_concurrency, true}]}]}]).
+        {rlog_shard, ?AUTH_SHARD},
+        {storage, disc_copies},
+        {record_name, user_info},
+        {attributes, record_info(fields, user_info)},
+        {storage_properties, [{ets, [{read_concurrency, true}]}]}
+    ]).
 
 %%------------------------------------------------------------------------------
 %% Hocon Schema
@@ -90,10 +98,11 @@ namespace() -> "authn-scram-builtin_db".
 roots() -> [?CONF_NS].
 
 fields(?CONF_NS) ->
-    [ {mechanism, emqx_authn_schema:mechanism('scram')}
-    , {backend, emqx_authn_schema:backend('built_in_database')}
-    , {algorithm, fun algorithm/1}
-    , {iteration_count, fun iteration_count/1}
+    [
+        {mechanism, emqx_authn_schema:mechanism('scram')},
+        {backend, emqx_authn_schema:backend('built_in_database')},
+        {algorithm, fun algorithm/1},
+        {iteration_count, fun iteration_count/1}
     ] ++ emqx_authn_schema:common_fields().
 
 algorithm(type) -> hoconsc:enum([sha256, sha512]);
@@ -109,23 +118,33 @@ iteration_count(_) -> undefined.
 %%------------------------------------------------------------------------------
 
 refs() ->
-   [hoconsc:ref(?MODULE, ?CONF_NS)].
-
-create(AuthenticatorID,
-       #{algorithm := Algorithm,
-         iteration_count := IterationCount}) ->
-    State = #{user_group => AuthenticatorID,
-              algorithm => Algorithm,
-              iteration_count => IterationCount},
+    [hoconsc:ref(?MODULE, ?CONF_NS)].
+
+create(
+    AuthenticatorID,
+    #{
+        algorithm := Algorithm,
+        iteration_count := IterationCount
+    }
+) ->
+    State = #{
+        user_group => AuthenticatorID,
+        algorithm => Algorithm,
+        iteration_count => IterationCount
+    },
     {ok, State}.
 
-
 update(Config, #{user_group := ID}) ->
     create(ID, Config).
 
-authenticate(#{auth_method := AuthMethod,
-               auth_data := AuthData,
-               auth_cache := AuthCache}, State) ->
+authenticate(
+    #{
+        auth_method := AuthMethod,
+        auth_data := AuthData,
+        auth_cache := AuthCache
+    },
+    State
+) ->
     case ensure_auth_method(AuthMethod, State) of
         true ->
             case AuthCache of
@@ -144,13 +163,22 @@ destroy(#{user_group := UserGroup}) ->
     MatchSpec = group_match_spec(UserGroup),
     trans(
         fun() ->
-            ok = lists:foreach(fun(UserInfo) ->
-                                  mnesia:delete_object(?TAB, UserInfo, write)
-                               end, mnesia:select(?TAB, MatchSpec, write))
-        end).
-
-add_user(#{user_id := UserID,
-           password := Password} = UserInfo, #{user_group := UserGroup} = State) ->
+            ok = lists:foreach(
+                fun(UserInfo) ->
+                    mnesia:delete_object(?TAB, UserInfo, write)
+                end,
+                mnesia:select(?TAB, MatchSpec, write)
+            )
+        end
+    ).
+
+add_user(
+    #{
+        user_id := UserID,
+        password := Password
+    } = UserInfo,
+    #{user_group := UserGroup} = State
+) ->
     trans(
         fun() ->
             case mnesia:read(?TAB, {UserGroup, UserID}, write) of
@@ -161,7 +189,8 @@ add_user(#{user_id := UserID,
                 [_] ->
                     {error, already_exist}
             end
-        end).
+        end
+    ).
 
 delete_user(UserID, #{user_group := UserGroup}) ->
     trans(
@@ -172,30 +201,42 @@ delete_user(UserID, #{user_group := UserGroup}) ->
                 [_] ->
                     mnesia:delete(?TAB, {UserGroup, UserID}, write)
             end
-        end).
-
-update_user(UserID, User,
-            #{user_group := UserGroup} = State) ->
+        end
+    ).
+
+update_user(
+    UserID,
+    User,
+    #{user_group := UserGroup} = State
+) ->
     trans(
         fun() ->
             case mnesia:read(?TAB, {UserGroup, UserID}, write) of
                 [] ->
                     {error, not_found};
                 [#user_info{is_superuser = IsSuperuser} = UserInfo] ->
-                    UserInfo1 = UserInfo#user_info{is_superuser = maps:get(is_superuser, User, IsSuperuser)},
-                    UserInfo2 = case maps:get(password, User, undefined) of
-                                    undefined ->
-                                        UserInfo1;
-                                    Password ->
-                                        {StoredKey, ServerKey, Salt} = esasl_scram:generate_authentication_info(Password, State),
-                                        UserInfo1#user_info{stored_key = StoredKey,
-                                                            server_key = ServerKey,
-                                                            salt       = Salt}
-                                end,
+                    UserInfo1 = UserInfo#user_info{
+                        is_superuser = maps:get(is_superuser, User, IsSuperuser)
+                    },
+                    UserInfo2 =
+                        case maps:get(password, User, undefined) of
+                            undefined ->
+                                UserInfo1;
+                            Password ->
+                                {StoredKey, ServerKey, Salt} = esasl_scram:generate_authentication_info(
+                                    Password, State
+                                ),
+                                UserInfo1#user_info{
+                                    stored_key = StoredKey,
+                                    server_key = ServerKey,
+                                    salt = Salt
+                                }
+                        end,
                     mnesia:write(?TAB, UserInfo2, write),
                     {ok, format_user_info(UserInfo2)}
             end
-        end).
+        end
+    ).
 
 lookup_user(UserID, #{user_group := UserGroup}) ->
     case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of
@@ -214,14 +255,23 @@ list_users(QueryString, #{user_group := UserGroup}) ->
 
 query(Tab, {QString, []}, Continuation, Limit) ->
     Ms = ms_from_qstring(QString),
-    emqx_mgmt_api:select_table_with_count(Tab, Ms, Continuation, Limit,
-                                          fun format_user_info/1);
-
+    emqx_mgmt_api:select_table_with_count(
+        Tab,
+        Ms,
+        Continuation,
+        Limit,
+        fun format_user_info/1
+    );
 query(Tab, {QString, FuzzyQString}, Continuation, Limit) ->
     Ms = ms_from_qstring(QString),
     FuzzyFilterFun = fuzzy_filter_fun(FuzzyQString),
-    emqx_mgmt_api:select_table_with_count(Tab, {Ms, FuzzyFilterFun}, Continuation, Limit,
-                                          fun format_user_info/1).
+    emqx_mgmt_api:select_table_with_count(
+        Tab,
+        {Ms, FuzzyFilterFun},
+        Continuation,
+        Limit,
+        fun format_user_info/1
+    ).
 
 %%--------------------------------------------------------------------
 %% Match funcs
@@ -229,14 +279,18 @@ query(Tab, {QString, FuzzyQString}, Continuation, Limit) ->
 %% Fuzzy username funcs
 fuzzy_filter_fun(Fuzzy) ->
     fun(MsRaws) when is_list(MsRaws) ->
-        lists:filter( fun(E) -> run_fuzzy_filter(E, Fuzzy) end
-                    , MsRaws)
+        lists:filter(
+            fun(E) -> run_fuzzy_filter(E, Fuzzy) end,
+            MsRaws
+        )
     end.
 
 run_fuzzy_filter(_, []) ->
     true;
-run_fuzzy_filter( E = #user_info{user_id = {_, UserID}}
-                , [{username, like, UsernameSubStr} | Fuzzy]) ->
+run_fuzzy_filter(
+    E = #user_info{user_id = {_, UserID}},
+    [{username, like, UsernameSubStr} | Fuzzy]
+) ->
     binary:match(UserID, UsernameSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy).
 
 %%------------------------------------------------------------------------------
@@ -252,13 +306,17 @@ ensure_auth_method(_, _) ->
 
 check_client_first_message(Bin, _Cache, #{iteration_count := IterationCount} = State) ->
     RetrieveFun = fun(Username) ->
-                    retrieve(Username, State)
-                end,
-    case esasl_scram:check_client_first_message(
-             Bin,
-             #{iteration_count => IterationCount,
-               retrieve => RetrieveFun}
-         ) of
+        retrieve(Username, State)
+    end,
+    case
+        esasl_scram:check_client_first_message(
+            Bin,
+            #{
+                iteration_count => IterationCount,
+                retrieve => RetrieveFun
+            }
+        )
+    of
         {continue, ServerFirstMessage, Cache} ->
             {continue, ServerFirstMessage, Cache};
         ignore ->
@@ -268,10 +326,12 @@ check_client_first_message(Bin, _Cache, #{iteration_count := IterationCount} = S
     end.
 
 check_client_final_message(Bin, #{is_superuser := IsSuperuser} = Cache, #{algorithm := Alg}) ->
-    case esasl_scram:check_client_final_message(
-             Bin,
-             Cache#{algorithm => Alg}
-         ) of
+    case
+        esasl_scram:check_client_final_message(
+            Bin,
+            Cache#{algorithm => Alg}
+        )
+    of
         {ok, ServerFinalMessage} ->
             {ok, #{is_superuser => IsSuperuser}, ServerFinalMessage};
         {error, _Reason} ->
@@ -280,23 +340,31 @@ check_client_final_message(Bin, #{is_superuser := IsSuperuser} = Cache, #{algori
 
 add_user(UserGroup, UserID, Password, IsSuperuser, State) ->
     {StoredKey, ServerKey, Salt} = esasl_scram:generate_authentication_info(Password, State),
-    UserInfo = #user_info{user_id      = {UserGroup, UserID},
-                          stored_key   = StoredKey,
-                          server_key   = ServerKey,
-                          salt         = Salt,
-                          is_superuser = IsSuperuser},
+    UserInfo = #user_info{
+        user_id = {UserGroup, UserID},
+        stored_key = StoredKey,
+        server_key = ServerKey,
+        salt = Salt,
+        is_superuser = IsSuperuser
+    },
     mnesia:write(?TAB, UserInfo, write).
 
 retrieve(UserID, #{user_group := UserGroup}) ->
     case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of
-        [#user_info{stored_key   = StoredKey,
-                    server_key   = ServerKey,
-                    salt         = Salt,
-                    is_superuser = IsSuperuser}] ->
-            {ok, #{stored_key => StoredKey,
-                   server_key => ServerKey,
-                   salt => Salt,
-                   is_superuser => IsSuperuser}};
+        [
+            #user_info{
+                stored_key = StoredKey,
+                server_key = ServerKey,
+                salt = Salt,
+                is_superuser = IsSuperuser
+            }
+        ] ->
+            {ok, #{
+                stored_key => StoredKey,
+                server_key => ServerKey,
+                salt => Salt,
+                is_superuser => IsSuperuser
+            }};
         [] ->
             {error, not_found}
     end.
@@ -315,15 +383,21 @@ format_user_info(#user_info{user_id = {_, UserID}, is_superuser = IsSuperuser})
     #{user_id => UserID, is_superuser => IsSuperuser}.
 
 ms_from_qstring(QString) ->
-    [Ms] = lists:foldl(fun({user_group, '=:=', UserGroup}, AccIn) ->
-                               [group_match_spec(UserGroup) | AccIn];
-                          (_, AccIn) ->
-                               AccIn
-                       end, [], QString),
+    [Ms] = lists:foldl(
+        fun
+            ({user_group, '=:=', UserGroup}, AccIn) ->
+                [group_match_spec(UserGroup) | AccIn];
+            (_, AccIn) ->
+                AccIn
+        end,
+        [],
+        QString
+    ),
     Ms.
 
 group_match_spec(UserGroup) ->
     ets:fun2ms(
-      fun(#user_info{user_id = {Group, _}} = User) when Group =:= UserGroup ->
-              User
-      end).
+        fun(#user_info{user_id = {Group, _}} = User) when Group =:= UserGroup ->
+            User
+        end
+    ).

+ 8 - 5
apps/emqx_authn/src/proto/emqx_authn_proto_v1.erl

@@ -18,9 +18,10 @@
 
 -behaviour(emqx_bpapi).
 
--export([ introduced_in/0
-        , lookup_from_all_nodes/3
-        ]).
+-export([
+    introduced_in/0,
+    lookup_from_all_nodes/3
+]).
 
 -include_lib("emqx/include/bpapi.hrl").
 
@@ -30,6 +31,8 @@ introduced_in() ->
     "5.0.0".
 
 -spec lookup_from_all_nodes([node()], atom(), binary()) ->
-          emqx_rpc:erpc_multicall().
+    emqx_rpc:erpc_multicall().
 lookup_from_all_nodes(Nodes, ChainName, AuthenticatorID) ->
-    erpc:multicall(Nodes, emqx_authn_api, lookup_from_local_node, [ChainName, AuthenticatorID], ?TIMEOUT).
+    erpc:multicall(
+        Nodes, emqx_authn_api, lookup_from_local_node, [ChainName, AuthenticatorID], ?TIMEOUT
+    ).

+ 151 - 92
apps/emqx_authn/src/simple_authn/emqx_authn_http.erl

@@ -24,18 +24,20 @@
 -behaviour(hocon_schema).
 -behaviour(emqx_authentication).
 
--export([ namespace/0
-        , roots/0
-        , fields/1
-        , validations/0
-        ]).
-
--export([ refs/0
-        , create/2
-        , update/2
-        , authenticate/2
-        , destroy/1
-        ]).
+-export([
+    namespace/0,
+    roots/0,
+    fields/1,
+    validations/0
+]).
+
+-export([
+    refs/0,
+    create/2,
+    update/2,
+    authenticate/2,
+    destroy/1
+]).
 
 %%------------------------------------------------------------------------------
 %% Hocon Schema
@@ -44,35 +46,47 @@
 namespace() -> "authn-http".
 
 roots() ->
-    [ {?CONF_NS,
-       hoconsc:mk(hoconsc:union(refs()),
-                  #{})}
+    [
+        {?CONF_NS,
+            hoconsc:mk(
+                hoconsc:union(refs()),
+                #{}
+            )}
     ].
 
 fields(get) ->
-    [ {method, #{type => get, default => post}}
-    , {headers, fun headers_no_content_type/1}
+    [
+        {method, #{type => get, default => post}},
+        {headers, fun headers_no_content_type/1}
     ] ++ common_fields();
-
 fields(post) ->
-    [ {method, #{type => post, default => post}}
-    , {headers, fun headers/1}
+    [
+        {method, #{type => post, default => post}},
+        {headers, fun headers/1}
     ] ++ common_fields().
 
 common_fields() ->
-    [ {mechanism, emqx_authn_schema:mechanism('password_based')}
-    , {backend, emqx_authn_schema:backend(http)}
-    , {url, fun url/1}
-    , {body, map([{fuzzy, term(), binary()}])}
-    , {request_timeout, fun request_timeout/1}
-    ] ++ emqx_authn_schema:common_fields()
-    ++ maps:to_list(maps:without([ base_url
-                                 , pool_type],
-                    maps:from_list(emqx_connector_http:fields(config)))).
+    [
+        {mechanism, emqx_authn_schema:mechanism('password_based')},
+        {backend, emqx_authn_schema:backend(http)},
+        {url, fun url/1},
+        {body, map([{fuzzy, term(), binary()}])},
+        {request_timeout, fun request_timeout/1}
+    ] ++ emqx_authn_schema:common_fields() ++
+        maps:to_list(
+            maps:without(
+                [
+                    base_url,
+                    pool_type
+                ],
+                maps:from_list(emqx_connector_http:fields(config))
+            )
+        ).
 
 validations() ->
-    [ {check_ssl_opts, fun check_ssl_opts/1}
-    , {check_headers, fun check_headers/1}
+    [
+        {check_ssl_opts, fun check_ssl_opts/1},
+        {check_headers, fun check_headers/1}
     ].
 
 url(type) -> binary();
@@ -80,21 +94,27 @@ url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
 url(required) -> true;
 url(_) -> undefined.
 
-headers(type) -> map();
+headers(type) ->
+    map();
 headers(converter) ->
     fun(Headers) ->
-       maps:merge(default_headers(), transform_header_name(Headers))
+        maps:merge(default_headers(), transform_header_name(Headers))
     end;
-headers(default) -> default_headers();
-headers(_) -> undefined.
+headers(default) ->
+    default_headers();
+headers(_) ->
+    undefined.
 
-headers_no_content_type(type) -> map();
+headers_no_content_type(type) ->
+    map();
 headers_no_content_type(converter) ->
     fun(Headers) ->
-       maps:merge(default_headers_no_content_type(), transform_header_name(Headers))
+        maps:merge(default_headers_no_content_type(), transform_header_name(Headers))
     end;
-headers_no_content_type(default) -> default_headers_no_content_type();
-headers_no_content_type(_) -> undefined.
+headers_no_content_type(default) ->
+    default_headers_no_content_type();
+headers_no_content_type(_) ->
+    undefined.
 
 request_timeout(type) -> emqx_schema:duration_ms();
 request_timeout(default) -> <<"5s">>;
@@ -105,36 +125,51 @@ request_timeout(_) -> undefined.
 %%------------------------------------------------------------------------------
 
 refs() ->
-    [ hoconsc:ref(?MODULE, get)
-    , hoconsc:ref(?MODULE, post)
+    [
+        hoconsc:ref(?MODULE, get),
+        hoconsc:ref(?MODULE, post)
     ].
 
 create(_AuthenticatorID, Config) ->
     create(Config).
 
-create(#{method := Method,
-         url := RawURL,
-         headers := Headers,
-         body := Body,
-         request_timeout := RequestTimeout} = Config) ->
+create(
+    #{
+        method := Method,
+        url := RawURL,
+        headers := Headers,
+        body := Body,
+        request_timeout := RequestTimeout
+    } = Config
+) ->
     {BsaeUrlWithPath, Query} = parse_fullpath(RawURL),
     URIMap = parse_url(BsaeUrlWithPath),
     ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
-    State = #{method                    => Method,
-              path                      => maps:get(path, URIMap),
-              base_query_template       => emqx_authn_utils:parse_deep(
-                                             cow_qs:parse_qs(to_bin(Query))),
-              headers                   => maps:to_list(Headers),
-              body_template             => emqx_authn_utils:parse_deep(
-                                             maps:to_list(Body)),
-              request_timeout           => RequestTimeout,
-              resource_id => ResourceId},
-    case emqx_resource:create_local(ResourceId,
-                                    ?RESOURCE_GROUP,
-                                    emqx_connector_http,
-                                    Config#{base_url => maps:remove(query, URIMap),
-                                            pool_type => random},
-                                            #{}) of
+    State = #{
+        method => Method,
+        path => maps:get(path, URIMap),
+        base_query_template => emqx_authn_utils:parse_deep(
+            cow_qs:parse_qs(to_bin(Query))
+        ),
+        headers => maps:to_list(Headers),
+        body_template => emqx_authn_utils:parse_deep(
+            maps:to_list(Body)
+        ),
+        request_timeout => RequestTimeout,
+        resource_id => ResourceId
+    },
+    case
+        emqx_resource:create_local(
+            ResourceId,
+            ?RESOURCE_GROUP,
+            emqx_connector_http,
+            Config#{
+                base_url => maps:remove(query, URIMap),
+                pool_type => random
+            },
+            #{}
+        )
+    of
         {ok, already_created} ->
             {ok, State};
         {ok, _} ->
@@ -154,13 +189,20 @@ update(Config, State) ->
 
 authenticate(#{auth_method := _}, _) ->
     ignore;
-authenticate(Credential, #{resource_id := ResourceId,
-                           method := Method,
-                           request_timeout := RequestTimeout} = State) ->
+authenticate(
+    Credential,
+    #{
+        resource_id := ResourceId,
+        method := Method,
+        request_timeout := RequestTimeout
+    } = State
+) ->
     Request = generate_request(Credential, State),
     case emqx_resource:query(ResourceId, {Method, Request, RequestTimeout}) of
-        {ok, 204, _Headers} -> {ok, #{is_superuser => false}};
-        {ok, 200, _Headers} -> {ok, #{is_superuser => false}};
+        {ok, 204, _Headers} ->
+            {ok, #{is_superuser => false}};
+        {ok, 200, _Headers} ->
+            {ok, #{is_superuser => false}};
         {ok, 200, Headers, Body} ->
             ContentType = proplists:get_value(<<"content-type">>, Headers, <<"application/json">>),
             case safely_parse_body(ContentType, Body) of
@@ -173,24 +215,32 @@ authenticate(Credential, #{resource_id := ResourceId,
                     {ok, #{is_superuser => false}}
             end;
         {error, Reason} ->
-            ?SLOG(error, #{msg => "http_server_query_failed",
-                           resource => ResourceId,
-                           reason => Reason}),
+            ?SLOG(error, #{
+                msg => "http_server_query_failed",
+                resource => ResourceId,
+                reason => Reason
+            }),
             ignore;
         Other ->
             Output = may_append_body(#{resource => ResourceId}, Other),
             case erlang:element(2, Other) of
                 Code5xx when Code5xx >= 500 andalso Code5xx < 600 ->
-                    ?SLOG(error, Output#{msg => "http_server_error",
-                                         code => Code5xx}),
+                    ?SLOG(error, Output#{
+                        msg => "http_server_error",
+                        code => Code5xx
+                    }),
                     ignore;
                 Code4xx when Code4xx >= 400 andalso Code4xx < 500 ->
-                    ?SLOG(warning, Output#{msg => "refused_by_http_server",
-                                           code => Code4xx}),
+                    ?SLOG(warning, Output#{
+                        msg => "refused_by_http_server",
+                        code => Code4xx
+                    }),
                     {error, not_authorized};
                 OtherCode ->
-                    ?SLOG(error, Output#{msg => "undesired_response_code",
-                                           code => OtherCode}),
+                    ?SLOG(error, Output#{
+                        msg => "undesired_response_code",
+                        code => OtherCode
+                    }),
                     ignore
             end
     end.
@@ -207,22 +257,29 @@ parse_fullpath(RawURL) ->
     cow_http:parse_fullpath(to_bin(RawURL)).
 
 default_headers() ->
-    maps:put(<<"content-type">>,
-             <<"application/json">>,
-             default_headers_no_content_type()).
+    maps:put(
+        <<"content-type">>,
+        <<"application/json">>,
+        default_headers_no_content_type()
+    ).
 
 default_headers_no_content_type() ->
-    #{ <<"accept">> => <<"application/json">>
-     , <<"cache-control">> => <<"no-cache">>
-     , <<"connection">> => <<"keep-alive">>
-     , <<"keep-alive">> => <<"timeout=30, max=1000">>
-     }.
+    #{
+        <<"accept">> => <<"application/json">>,
+        <<"cache-control">> => <<"no-cache">>,
+        <<"connection">> => <<"keep-alive">>,
+        <<"keep-alive">> => <<"timeout=30, max=1000">>
+    }.
 
 transform_header_name(Headers) ->
-    maps:fold(fun(K0, V, Acc) ->
-                  K = list_to_binary(string:to_lower(to_list(K0))),
-                  maps:put(K, V, Acc)
-              end, #{}, Headers).
+    maps:fold(
+        fun(K0, V, Acc) ->
+            K = list_to_binary(string:to_lower(to_list(K0))),
+            maps:put(K, V, Acc)
+        end,
+        #{},
+        Headers
+    ).
 
 check_ssl_opts(Conf) ->
     {BaseUrlWithPath, _Query} = parse_fullpath(get_conf_val("url", Conf)),
@@ -250,11 +307,13 @@ parse_url(URL) ->
             URIMap
     end.
 
-generate_request(Credential, #{method := Method,
-                               path := Path,
-                               base_query_template := BaseQueryTemplate,
-                               headers := Headers,
-                               body_template := BodyTemplate}) ->
+generate_request(Credential, #{
+    method := Method,
+    path := Path,
+    base_query_template := BaseQueryTemplate,
+    headers := Headers,
+    body_template := BodyTemplate
+}) ->
     Body = emqx_authn_utils:render_deep(BodyTemplate, Credential),
     NBaseQuery = emqx_authn_utils:render_deep(BaseQueryTemplate, Credential),
     case Method of

+ 93 - 69
apps/emqx_authn/src/simple_authn/emqx_authn_jwks_connector.erl

@@ -22,23 +22,25 @@
 -include_lib("jose/include/jose_jwk.hrl").
 -include_lib("snabbkaffe/include/snabbkaffe.hrl").
 
+-export([
+    start_link/1,
+    stop/1
+]).
 
--export([ start_link/1
-        , stop/1
-        ]).
-
--export([ get_jwks/1
-        , update/2
-        ]).
+-export([
+    get_jwks/1,
+    update/2
+]).
 
 %% gen_server callbacks
--export([ init/1
-        , handle_call/3
-        , handle_cast/2
-        , handle_info/2
-        , terminate/2
-        , code_change/3
-        ]).
+-export([
+    init/1,
+    handle_call/3,
+    handle_cast/2,
+    handle_info/2,
+    terminate/2,
+    code_change/3
+]).
 
 %%--------------------------------------------------------------------
 %% APIs
@@ -67,11 +69,9 @@ init([Opts]) ->
 
 handle_call(get_cached_jwks, _From, #{jwks := Jwks} = State) ->
     {reply, {ok, Jwks}, State};
-
 handle_call({update, Opts}, _From, _State) ->
     NewState = handle_options(Opts),
     {reply, ok, refresh_jwks(NewState)};
-
 handle_call(_Req, _From, State) ->
     {reply, ok, State}.
 
@@ -80,47 +80,53 @@ handle_cast(_Msg, State) ->
 
 handle_info({refresh_jwks, _TRef, refresh}, #{request_id := RequestID} = State) ->
     case RequestID of
-        undefined -> ok;
+        undefined ->
+            ok;
         _ ->
             ok = httpc:cancel_request(RequestID),
             receive
                 {http, _} -> ok
             after 0 ->
-                    ok
+                ok
             end
     end,
     {noreply, refresh_jwks(State)};
-
-handle_info({http, {RequestID, Result}},
-            #{request_id := RequestID, endpoint := Endpoint} = State0) ->
+handle_info(
+    {http, {RequestID, Result}},
+    #{request_id := RequestID, endpoint := Endpoint} = State0
+) ->
     ?tp(debug, jwks_endpoint_response, #{request_id => RequestID}),
     State1 = State0#{request_id := undefined},
-    NewState = case Result of
-                   {error, Reason} ->
-                       ?SLOG(warning, #{msg => "failed_to_request_jwks_endpoint",
-                                        endpoint => Endpoint,
-                                        reason => Reason}),
-                       State1;
-                   {StatusLine, Headers, Body} ->
-                       try
-                           JWKS = jose_jwk:from(emqx_json:decode(Body, [return_maps])),
-                           {_, JWKs} = JWKS#jose_jwk.keys,
-                           State1#{jwks := JWKs}
-                       catch _:_ ->
-                                 ?SLOG(warning, #{msg => "invalid_jwks_returned",
-                                                  endpoint => Endpoint,
-                                                  status => StatusLine,
-                                                  headers => Headers,
-                                                  body => Body}),
-                                 State1
-                       end
-               end,
+    NewState =
+        case Result of
+            {error, Reason} ->
+                ?SLOG(warning, #{
+                    msg => "failed_to_request_jwks_endpoint",
+                    endpoint => Endpoint,
+                    reason => Reason
+                }),
+                State1;
+            {StatusLine, Headers, Body} ->
+                try
+                    JWKS = jose_jwk:from(emqx_json:decode(Body, [return_maps])),
+                    {_, JWKs} = JWKS#jose_jwk.keys,
+                    State1#{jwks := JWKs}
+                catch
+                    _:_ ->
+                        ?SLOG(warning, #{
+                            msg => "invalid_jwks_returned",
+                            endpoint => Endpoint,
+                            status => StatusLine,
+                            headers => Headers,
+                            body => Body
+                        }),
+                        State1
+                end
+        end,
     {noreply, NewState};
-
 handle_info({http, {_, _}}, State) ->
     %% ignore
     {noreply, State};
-
 handle_info(_Info, State) ->
     {noreply, State}.
 
@@ -135,32 +141,50 @@ code_change(_OldVsn, State, _Extra) ->
 %% Internal functions
 %%--------------------------------------------------------------------
 
-handle_options(#{endpoint := Endpoint,
-                 refresh_interval := RefreshInterval0,
-                 ssl_opts := SSLOpts}) ->
-    #{endpoint => Endpoint,
-      refresh_interval => limit_refresh_interval(RefreshInterval0),
-      ssl_opts => maps:to_list(SSLOpts),
-      jwks => [],
-      request_id => undefined}.
-
-refresh_jwks(#{endpoint := Endpoint,
-               ssl_opts := SSLOpts} = State) ->
-    HTTPOpts = [ {timeout, 5000}
-               , {connect_timeout, 5000}
-               , {ssl, SSLOpts}
-               ],
-    NState = case httpc:request(get, {Endpoint, [{"Accept", "application/json"}]}, HTTPOpts,
-                                [{body_format, binary}, {sync, false}, {receiver, self()}]) of
-                 {error, Reason} ->
-                     ?tp(warning, jwks_endpoint_request_fail, #{endpoint => Endpoint,
-                                                                http_opts => HTTPOpts,
-                                                                reason => Reason}),
-                     State;
-                 {ok, RequestID} ->
-                     ?tp(debug, jwks_endpoint_request_ok, #{request_id => RequestID}),
-                     State#{request_id := RequestID}
-             end,
+handle_options(#{
+    endpoint := Endpoint,
+    refresh_interval := RefreshInterval0,
+    ssl_opts := SSLOpts
+}) ->
+    #{
+        endpoint => Endpoint,
+        refresh_interval => limit_refresh_interval(RefreshInterval0),
+        ssl_opts => maps:to_list(SSLOpts),
+        jwks => [],
+        request_id => undefined
+    }.
+
+refresh_jwks(
+    #{
+        endpoint := Endpoint,
+        ssl_opts := SSLOpts
+    } = State
+) ->
+    HTTPOpts = [
+        {timeout, 5000},
+        {connect_timeout, 5000},
+        {ssl, SSLOpts}
+    ],
+    NState =
+        case
+            httpc:request(
+                get,
+                {Endpoint, [{"Accept", "application/json"}]},
+                HTTPOpts,
+                [{body_format, binary}, {sync, false}, {receiver, self()}]
+            )
+        of
+            {error, Reason} ->
+                ?tp(warning, jwks_endpoint_request_fail, #{
+                    endpoint => Endpoint,
+                    http_opts => HTTPOpts,
+                    reason => Reason
+                }),
+                State;
+            {ok, RequestID} ->
+                ?tp(debug, jwks_endpoint_request_ok, #{request_id => RequestID}),
+                State#{request_id := RequestID}
+        end,
     ensure_expiry_timer(NState).
 
 ensure_expiry_timer(State = #{refresh_interval := Interval}) ->

+ 146 - 108
apps/emqx_authn/src/simple_authn/emqx_authn_jwt.erl

@@ -23,17 +23,19 @@
 -behaviour(hocon_schema).
 -behaviour(emqx_authentication).
 
--export([ namespace/0
-        , roots/0
-        , fields/1
-        ]).
-
--export([ refs/0
-        , create/2
-        , update/2
-        , authenticate/2
-        , destroy/1
-        ]).
+-export([
+    namespace/0,
+    roots/0,
+    fields/1
+]).
+
+-export([
+    refs/0,
+    create/2,
+    update/2,
+    authenticate/2,
+    destroy/1
+]).
 
 %%------------------------------------------------------------------------------
 %% Hocon Schema
@@ -42,49 +44,56 @@
 namespace() -> "authn-jwt".
 
 roots() ->
-    [ {?CONF_NS,
-       hoconsc:mk(hoconsc:union(refs()),
-                  #{})}
+    [
+        {?CONF_NS,
+            hoconsc:mk(
+                hoconsc:union(refs()),
+                #{}
+            )}
     ].
 
 fields('hmac-based') ->
-    [ {use_jwks, {enum, [false]}}
-    , {algorithm, {enum, ['hmac-based']}}
-    , {secret, fun secret/1}
-    , {secret_base64_encoded, fun secret_base64_encoded/1}
+    [
+        {use_jwks, {enum, [false]}},
+        {algorithm, {enum, ['hmac-based']}},
+        {secret, fun secret/1},
+        {secret_base64_encoded, fun secret_base64_encoded/1}
     ] ++ common_fields();
-
 fields('public-key') ->
-    [ {use_jwks, {enum, [false]}}
-    , {algorithm, {enum, ['public-key']}}
-    , {certificate, fun certificate/1}
+    [
+        {use_jwks, {enum, [false]}},
+        {algorithm, {enum, ['public-key']}},
+        {certificate, fun certificate/1}
     ] ++ common_fields();
-
 fields('jwks') ->
-    [ {use_jwks, {enum, [true]}}
-    , {endpoint, fun endpoint/1}
-    , {refresh_interval, fun refresh_interval/1}
-    , {ssl, #{type => hoconsc:union([ hoconsc:ref(?MODULE, ssl_enable)
-                                    , hoconsc:ref(?MODULE, ssl_disable)
-                                    ]),
-              default => #{<<"enable">> => false}}}
+    [
+        {use_jwks, {enum, [true]}},
+        {endpoint, fun endpoint/1},
+        {refresh_interval, fun refresh_interval/1},
+        {ssl, #{
+            type => hoconsc:union([
+                hoconsc:ref(?MODULE, ssl_enable),
+                hoconsc:ref(?MODULE, ssl_disable)
+            ]),
+            default => #{<<"enable">> => false}
+        }}
     ] ++ common_fields();
-
 fields(ssl_enable) ->
-    [ {enable, #{type => true}}
-    , {cacertfile, fun cacertfile/1}
-    , {certfile, fun certfile/1}
-    , {keyfile, fun keyfile/1}
-    , {verify, fun verify/1}
-    , {server_name_indication, fun server_name_indication/1}
+    [
+        {enable, #{type => true}},
+        {cacertfile, fun cacertfile/1},
+        {certfile, fun certfile/1},
+        {keyfile, fun keyfile/1},
+        {verify, fun verify/1},
+        {server_name_indication, fun server_name_indication/1}
     ];
-
 fields(ssl_disable) ->
-    [ {enable, #{type => false}} ].
+    [{enable, #{type => false}}].
 
 common_fields() ->
-    [ {mechanism, emqx_authn_schema:mechanism('jwt')}
-    , {verify_claims, fun verify_claims/1}
+    [
+        {mechanism, emqx_authn_schema:mechanism('jwt')},
+        {verify_claims, fun verify_claims/1}
     ] ++ emqx_authn_schema:common_fields().
 
 secret(type) -> binary();
@@ -121,24 +130,29 @@ verify(_) -> undefined.
 server_name_indication(type) -> string();
 server_name_indication(_) -> undefined.
 
-verify_claims(type) -> list();
-verify_claims(default) -> #{};
-verify_claims(validator) -> [fun do_check_verify_claims/1];
+verify_claims(type) ->
+    list();
+verify_claims(default) ->
+    #{};
+verify_claims(validator) ->
+    [fun do_check_verify_claims/1];
 verify_claims(converter) ->
     fun(VerifyClaims) ->
         [{to_binary(K), V} || {K, V} <- maps:to_list(VerifyClaims)]
     end;
-verify_claims(_) -> undefined.
+verify_claims(_) ->
+    undefined.
 
 %%------------------------------------------------------------------------------
 %% APIs
 %%------------------------------------------------------------------------------
 
 refs() ->
-   [ hoconsc:ref(?MODULE, 'hmac-based')
-   , hoconsc:ref(?MODULE, 'public-key')
-   , hoconsc:ref(?MODULE, 'jwks')
-   ].
+    [
+        hoconsc:ref(?MODULE, 'hmac-based'),
+        hoconsc:ref(?MODULE, 'public-key'),
+        hoconsc:ref(?MODULE, 'jwks')
+    ].
 
 create(_AuthenticatorID, Config) ->
     create(Config).
@@ -146,18 +160,22 @@ create(_AuthenticatorID, Config) ->
 create(#{verify_claims := VerifyClaims} = Config) ->
     create2(Config#{verify_claims => handle_verify_claims(VerifyClaims)}).
 
-update(#{use_jwks := false} = Config,
-       #{jwk := Connector})
-  when is_pid(Connector) ->
+update(
+    #{use_jwks := false} = Config,
+    #{jwk := Connector}
+) when
+    is_pid(Connector)
+->
     _ = emqx_authn_jwks_connector:stop(Connector),
     create(Config);
-
 update(#{use_jwks := false} = Config, _State) ->
     create(Config);
-
-update(#{use_jwks := true} = Config,
-       #{jwk := Connector} = State)
-  when is_pid(Connector) ->
+update(
+    #{use_jwks := true} = Config,
+    #{jwk := Connector} = State
+) when
+    is_pid(Connector)
+->
     ok = emqx_authn_jwks_connector:update(Connector, connector_opts(Config)),
     case maps:get(verify_cliams, Config, undefined) of
         undefined ->
@@ -165,21 +183,23 @@ update(#{use_jwks := true} = Config,
         VerifyClaims ->
             {ok, State#{verify_claims => handle_verify_claims(VerifyClaims)}}
     end;
-
 update(#{use_jwks := true} = Config, _State) ->
     create(Config).
 
 authenticate(#{auth_method := _}, _) ->
     ignore;
-authenticate(Credential = #{password := JWT}, #{jwk := JWK,
-                                                verify_claims := VerifyClaims0}) ->
-    JWKs = case erlang:is_pid(JWK) of
-               false ->
-                   [JWK];
-               true ->
-                   {ok, JWKs0} = emqx_authn_jwks_connector:get_jwks(JWK),
-                   JWKs0
-           end,
+authenticate(Credential = #{password := JWT}, #{
+    jwk := JWK,
+    verify_claims := VerifyClaims0
+}) ->
+    JWKs =
+        case erlang:is_pid(JWK) of
+            false ->
+                [JWK];
+            true ->
+                {ok, JWKs0} = emqx_authn_jwks_connector:get_jwks(JWK),
+                JWKs0
+        end,
     VerifyClaims = replace_placeholder(VerifyClaims0, Credential),
     case verify(JWT, JWKs, VerifyClaims) of
         {ok, Extra} -> {ok, Extra};
@@ -197,41 +217,54 @@ destroy(_) ->
 %% Internal functions
 %%--------------------------------------------------------------------
 
-create2(#{use_jwks := false,
-          algorithm := 'hmac-based',
-          secret := Secret0,
-          secret_base64_encoded := Base64Encoded,
-          verify_claims := VerifyClaims}) ->
+create2(#{
+    use_jwks := false,
+    algorithm := 'hmac-based',
+    secret := Secret0,
+    secret_base64_encoded := Base64Encoded,
+    verify_claims := VerifyClaims
+}) ->
     case may_decode_secret(Base64Encoded, Secret0) of
         {error, Reason} ->
             {error, Reason};
         Secret ->
             JWK = jose_jwk:from_oct(Secret),
-            {ok, #{jwk => JWK,
-                   verify_claims => VerifyClaims}}
+            {ok, #{
+                jwk => JWK,
+                verify_claims => VerifyClaims
+            }}
     end;
-
-create2(#{use_jwks := false,
-          algorithm := 'public-key',
-          certificate := Certificate,
-          verify_claims := VerifyClaims}) ->
+create2(#{
+    use_jwks := false,
+    algorithm := 'public-key',
+    certificate := Certificate,
+    verify_claims := VerifyClaims
+}) ->
     JWK = create_jwk_from_pem_or_file(Certificate),
-    {ok, #{jwk => JWK,
-           verify_claims => VerifyClaims}};
-
-create2(#{use_jwks := true,
-          verify_claims := VerifyClaims} = Config) ->
+    {ok, #{
+        jwk => JWK,
+        verify_claims => VerifyClaims
+    }};
+create2(
+    #{
+        use_jwks := true,
+        verify_claims := VerifyClaims
+    } = Config
+) ->
     case emqx_authn_jwks_connector:start_link(connector_opts(Config)) of
         {ok, Connector} ->
-            {ok, #{jwk => Connector,
-                   verify_claims => VerifyClaims}};
+            {ok, #{
+                jwk => Connector,
+                verify_claims => VerifyClaims
+            }};
         {error, Reason} ->
             {error, Reason}
     end.
 
-create_jwk_from_pem_or_file(CertfileOrFilePath)
-  when is_binary(CertfileOrFilePath);
-       is_list(CertfileOrFilePath) ->
+create_jwk_from_pem_or_file(CertfileOrFilePath) when
+    is_binary(CertfileOrFilePath);
+    is_list(CertfileOrFilePath)
+->
     case filelib:is_file(CertfileOrFilePath) of
         true ->
             jose_jwk:from_pem_file(CertfileOrFilePath);
@@ -240,18 +273,20 @@ create_jwk_from_pem_or_file(CertfileOrFilePath)
     end.
 
 connector_opts(#{ssl := #{enable := Enable} = SSL} = Config) ->
-    SSLOpts = case Enable of
-                  true -> maps:without([enable], SSL);
-                  false -> #{}
-              end,
+    SSLOpts =
+        case Enable of
+            true -> maps:without([enable], SSL);
+            false -> #{}
+        end,
     Config#{ssl_opts => SSLOpts}.
 
-
-may_decode_secret(false, Secret) -> Secret;
+may_decode_secret(false, Secret) ->
+    Secret;
 may_decode_secret(true, Secret) ->
-    try base64:decode(Secret)
+    try
+        base64:decode(Secret)
     catch
-        error : _ ->
+        error:_ ->
             {error, {invalid_parameter, secret}}
     end.
 
@@ -288,15 +323,18 @@ verify(JWS, [JWK | More], VerifyClaims) ->
 
 verify_claims(Claims, VerifyClaims0) ->
     Now = os:system_time(seconds),
-    VerifyClaims = [{<<"exp">>, fun(ExpireTime) ->
-                                    Now < ExpireTime
-                                end},
-                    {<<"iat">>, fun(IssueAt) ->
-                                    IssueAt =< Now
-                                end},
-                    {<<"nbf">>, fun(NotBefore) ->
-                                    NotBefore =< Now
-                                end}] ++ VerifyClaims0,
+    VerifyClaims =
+        [
+            {<<"exp">>, fun(ExpireTime) ->
+                Now < ExpireTime
+            end},
+            {<<"iat">>, fun(IssueAt) ->
+                IssueAt =< Now
+            end},
+            {<<"nbf">>, fun(NotBefore) ->
+                NotBefore =< Now
+            end}
+        ] ++ VerifyClaims0,
     do_verify_claims(Claims, VerifyClaims).
 
 do_verify_claims(_Claims, []) ->
@@ -327,8 +365,8 @@ do_check_verify_claims([]) ->
     true;
 do_check_verify_claims([{Name, Expected} | More]) ->
     check_claim_name(Name) andalso
-    check_claim_expected(Expected) andalso
-    do_check_verify_claims(More).
+        check_claim_expected(Expected) andalso
+        do_check_verify_claims(More).
 
 check_claim_name(exp) ->
     false;

+ 188 - 113
apps/emqx_authn/src/simple_authn/emqx_authn_mnesia.erl

@@ -23,40 +23,45 @@
 -behaviour(hocon_schema).
 -behaviour(emqx_authentication).
 
--export([ namespace/0
-        , roots/0
-        , fields/1
-        ]).
-
--export([ refs/0
-        , create/2
-        , update/2
-        , authenticate/2
-        , destroy/1
-        ]).
-
--export([ import_users/2
-        , add_user/2
-        , delete_user/2
-        , update_user/3
-        , lookup_user/2
-        , list_users/2
-        ]).
-
--export([ query/4
-        , format_user_info/1
-        , group_match_spec/1]).
+-export([
+    namespace/0,
+    roots/0,
+    fields/1
+]).
+
+-export([
+    refs/0,
+    create/2,
+    update/2,
+    authenticate/2,
+    destroy/1
+]).
+
+-export([
+    import_users/2,
+    add_user/2,
+    delete_user/2,
+    update_user/3,
+    lookup_user/2,
+    list_users/2
+]).
+
+-export([
+    query/4,
+    format_user_info/1,
+    group_match_spec/1
+]).
 
 -type user_id_type() :: clientid | username.
 -type user_group() :: binary().
 -type user_id() :: binary().
 
--record(user_info,
-        { user_id :: {user_group(), user_id()}
-        , password_hash :: binary()
-        , salt :: binary()
-        , is_superuser :: boolean()
-        }).
+-record(user_info, {
+    user_id :: {user_group(), user_id()},
+    password_hash :: binary(),
+    salt :: binary(),
+    is_superuser :: boolean()
+}).
 
 -reflect_type([user_id_type/0]).
 
@@ -65,9 +70,11 @@
 -boot_mnesia({mnesia, [boot]}).
 
 -define(TAB, ?MODULE).
--define(AUTHN_QSCHEMA, [ {<<"like_username">>, binary}
-                       , {<<"like_clientid">>, binary}
-                       , {<<"user_group">>, binary}]).
+-define(AUTHN_QSCHEMA, [
+    {<<"like_username">>, binary},
+    {<<"like_clientid">>, binary},
+    {<<"user_group">>, binary}
+]).
 -define(QUERY_FUN, {?MODULE, query}).
 
 %%------------------------------------------------------------------------------
@@ -75,14 +82,15 @@
 %%------------------------------------------------------------------------------
 
 %% @doc Create or replicate tables.
--spec(mnesia(boot | copy) -> ok).
+-spec mnesia(boot | copy) -> ok.
 mnesia(boot) ->
     ok = mria:create_table(?TAB, [
-                {rlog_shard, ?AUTH_SHARD},
-                {storage, disc_copies},
-                {record_name, user_info},
-                {attributes, record_info(fields, user_info)},
-                {storage_properties, [{ets, [{read_concurrency, true}]}]}]).
+        {rlog_shard, ?AUTH_SHARD},
+        {storage, disc_copies},
+        {record_name, user_info},
+        {attributes, record_info(fields, user_info)},
+        {storage_properties, [{ets, [{read_concurrency, true}]}]}
+    ]).
 
 %%------------------------------------------------------------------------------
 %% Hocon Schema
@@ -93,10 +101,11 @@ namespace() -> "authn-builtin_db".
 roots() -> [?CONF_NS].
 
 fields(?CONF_NS) ->
-    [ {mechanism, emqx_authn_schema:mechanism('password_based')}
-    , {backend, emqx_authn_schema:backend('built_in_database')}
-    , {user_id_type, fun user_id_type/1}
-    , {password_hash_algorithm, fun emqx_authn_password_hashing:type_rw/1}
+    [
+        {mechanism, emqx_authn_schema:mechanism('password_based')},
+        {backend, emqx_authn_schema:backend('built_in_database')},
+        {user_id_type, fun user_id_type/1},
+        {password_hash_algorithm, fun emqx_authn_password_hashing:type_rw/1}
     ] ++ emqx_authn_schema:common_fields().
 
 user_id_type(type) -> user_id_type();
@@ -108,15 +117,21 @@ user_id_type(_) -> undefined.
 %%------------------------------------------------------------------------------
 
 refs() ->
-   [hoconsc:ref(?MODULE, ?CONF_NS)].
-
-create(AuthenticatorID,
-       #{user_id_type := Type,
-         password_hash_algorithm := Algorithm}) ->
+    [hoconsc:ref(?MODULE, ?CONF_NS)].
+
+create(
+    AuthenticatorID,
+    #{
+        user_id_type := Type,
+        password_hash_algorithm := Algorithm
+    }
+) ->
     ok = emqx_authn_password_hashing:init(Algorithm),
-    State = #{user_group => AuthenticatorID,
-              user_id_type => Type,
-              password_hash_algorithm => Algorithm},
+    State = #{
+        user_group => AuthenticatorID,
+        user_id_type => Type,
+        password_hash_algorithm => Algorithm
+    },
     {ok, State}.
 
 update(Config, #{user_group := ID}) ->
@@ -124,17 +139,24 @@ update(Config, #{user_group := ID}) ->
 
 authenticate(#{auth_method := _}, _) ->
     ignore;
-authenticate(#{password := Password} = Credential,
-             #{user_group := UserGroup,
-               user_id_type := Type,
-               password_hash_algorithm := Algorithm}) ->
+authenticate(
+    #{password := Password} = Credential,
+    #{
+        user_group := UserGroup,
+        user_id_type := Type,
+        password_hash_algorithm := Algorithm
+    }
+) ->
     UserID = get_user_identity(Credential, Type),
     case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of
         [] ->
             ignore;
         [#user_info{password_hash = PasswordHash, salt = Salt, is_superuser = IsSuperuser}] ->
-            case emqx_authn_password_hashing:check_password(
-                   Algorithm, Salt, PasswordHash, Password) of
+            case
+                emqx_authn_password_hashing:check_password(
+                    Algorithm, Salt, PasswordHash, Password
+                )
+            of
                 true -> {ok, #{is_superuser => IsSuperuser}};
                 false -> {error, bad_username_or_password}
             end
@@ -142,14 +164,15 @@ authenticate(#{password := Password} = Credential,
 
 destroy(#{user_group := UserGroup}) ->
     trans(
-      fun() ->
-              ok = lists:foreach(
-                     fun(User) ->
-                             mnesia:delete_object(?TAB, User, write)
-                     end,
-                     mnesia:select(?TAB, group_match_spec(UserGroup), write))
-      end).
-
+        fun() ->
+            ok = lists:foreach(
+                fun(User) ->
+                    mnesia:delete_object(?TAB, User, write)
+                end,
+                mnesia:select(?TAB, group_match_spec(UserGroup), write)
+            )
+        end
+    ).
 
 import_users(Filename0, State) ->
     Filename = to_binary(Filename0),
@@ -164,10 +187,16 @@ import_users(Filename0, State) ->
             {error, {unsupported_file_format, Extension}}
     end.
 
-add_user(#{user_id := UserID,
-           password := Password} = UserInfo,
-         #{user_group := UserGroup,
-           password_hash_algorithm := Algorithm}) ->
+add_user(
+    #{
+        user_id := UserID,
+        password := Password
+    } = UserInfo,
+    #{
+        user_group := UserGroup,
+        password_hash_algorithm := Algorithm
+    }
+) ->
     trans(
         fun() ->
             case mnesia:read(?TAB, {UserGroup, UserID}, write) of
@@ -179,7 +208,8 @@ add_user(#{user_id := UserID,
                 [_] ->
                     {error, already_exist}
             end
-        end).
+        end
+    ).
 
 delete_user(UserID, #{user_group := UserGroup}) ->
     trans(
@@ -190,31 +220,44 @@ delete_user(UserID, #{user_group := UserGroup}) ->
                 [_] ->
                     mnesia:delete(?TAB, {UserGroup, UserID}, write)
             end
-        end).
-
-update_user(UserID, UserInfo,
-            #{user_group := UserGroup,
-              password_hash_algorithm := Algorithm}) ->
+        end
+    ).
+
+update_user(
+    UserID,
+    UserInfo,
+    #{
+        user_group := UserGroup,
+        password_hash_algorithm := Algorithm
+    }
+) ->
     trans(
         fun() ->
             case mnesia:read(?TAB, {UserGroup, UserID}, write) of
                 [] ->
                     {error, not_found};
-                [#user_info{ password_hash = PasswordHash
-                           , salt = Salt
-                           , is_superuser = IsSuperuser}] ->
+                [
+                    #user_info{
+                        password_hash = PasswordHash,
+                        salt = Salt,
+                        is_superuser = IsSuperuser
+                    }
+                ] ->
                     NSuperuser = maps:get(is_superuser, UserInfo, IsSuperuser),
-                    {NPasswordHash, NSalt} = case UserInfo of
-                                                 #{password := Password} ->
-                                                     emqx_authn_password_hashing:hash(
-                                                       Algorithm, Password);
-                                                 #{} ->
-                                                     {PasswordHash, Salt}
-                                             end,
+                    {NPasswordHash, NSalt} =
+                        case UserInfo of
+                            #{password := Password} ->
+                                emqx_authn_password_hashing:hash(
+                                    Algorithm, Password
+                                );
+                            #{} ->
+                                {PasswordHash, Salt}
+                        end,
                     insert_user(UserGroup, UserID, NPasswordHash, NSalt, NSuperuser),
                     {ok, #{user_id => UserID, is_superuser => NSuperuser}}
             end
-        end).
+        end
+    ).
 
 lookup_user(UserID, #{user_group := UserGroup}) ->
     case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of
@@ -233,14 +276,23 @@ list_users(QueryString, #{user_group := UserGroup}) ->
 
 query(Tab, {QString, []}, Continuation, Limit) ->
     Ms = ms_from_qstring(QString),
-    emqx_mgmt_api:select_table_with_count(Tab, Ms, Continuation, Limit,
-                                          fun format_user_info/1);
-
+    emqx_mgmt_api:select_table_with_count(
+        Tab,
+        Ms,
+        Continuation,
+        Limit,
+        fun format_user_info/1
+    );
 query(Tab, {QString, FuzzyQString}, Continuation, Limit) ->
     Ms = ms_from_qstring(QString),
     FuzzyFilterFun = fuzzy_filter_fun(FuzzyQString),
-    emqx_mgmt_api:select_table_with_count(Tab, {Ms, FuzzyFilterFun}, Continuation, Limit,
-                                          fun format_user_info/1).
+    emqx_mgmt_api:select_table_with_count(
+        Tab,
+        {Ms, FuzzyFilterFun},
+        Continuation,
+        Limit,
+        fun format_user_info/1
+    ).
 
 %%--------------------------------------------------------------------
 %% Match funcs
@@ -248,17 +300,23 @@ query(Tab, {QString, FuzzyQString}, Continuation, Limit) ->
 %% Fuzzy username funcs
 fuzzy_filter_fun(Fuzzy) ->
     fun(MsRaws) when is_list(MsRaws) ->
-        lists:filter( fun(E) -> run_fuzzy_filter(E, Fuzzy) end
-                    , MsRaws)
+        lists:filter(
+            fun(E) -> run_fuzzy_filter(E, Fuzzy) end,
+            MsRaws
+        )
     end.
 
 run_fuzzy_filter(_, []) ->
     true;
-run_fuzzy_filter( E = #user_info{user_id = {_, UserID}}
-                , [{username, like, UsernameSubStr} | Fuzzy]) ->
+run_fuzzy_filter(
+    E = #user_info{user_id = {_, UserID}},
+    [{username, like, UsernameSubStr} | Fuzzy]
+) ->
     binary:match(UserID, UsernameSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy);
-run_fuzzy_filter( E = #user_info{user_id = {_, UserID}}
-                , [{clientid, like, ClientIDSubStr} | Fuzzy]) ->
+run_fuzzy_filter(
+    E = #user_info{user_id = {_, UserID}},
+    [{clientid, like, ClientIDSubStr} | Fuzzy]
+) ->
     binary:match(UserID, ClientIDSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy).
 
 %%------------------------------------------------------------------------------
@@ -297,9 +355,15 @@ import_users_from_csv(Filename, #{user_group := UserGroup}) ->
 
 import(_UserGroup, []) ->
     ok;
-import(UserGroup, [#{<<"user_id">> := UserID,
-                     <<"password_hash">> := PasswordHash} = UserInfo | More])
-  when is_binary(UserID) andalso is_binary(PasswordHash) ->
+import(UserGroup, [
+    #{
+        <<"user_id">> := UserID,
+        <<"password_hash">> := PasswordHash
+    } = UserInfo
+    | More
+]) when
+    is_binary(UserID) andalso is_binary(PasswordHash)
+->
     Salt = maps:get(<<"salt">>, UserInfo, <<>>),
     IsSuperuser = maps:get(<<"is_superuser">>, UserInfo, false),
     insert_user(UserGroup, UserID, PasswordHash, Salt, IsSuperuser),
@@ -313,8 +377,11 @@ import(UserGroup, File, Seq) ->
         {ok, Line} ->
             Fields = binary:split(Line, [<<",">>, <<" ">>, <<"\n">>], [global, trim_all]),
             case get_user_info_by_seq(Fields, Seq) of
-                {ok, #{user_id := UserID,
-                       password_hash := PasswordHash} = UserInfo} ->
+                {ok,
+                    #{
+                        user_id := UserID,
+                        password_hash := PasswordHash
+                    } = UserInfo} ->
                     Salt = maps:get(salt, UserInfo, <<>>),
                     IsSuperuser = maps:get(is_superuser, UserInfo, false),
                     insert_user(UserGroup, UserID, PasswordHash, Salt, IsSuperuser),
@@ -360,10 +427,12 @@ get_user_info_by_seq(_, _, _) ->
     {error, bad_format}.
 
 insert_user(UserGroup, UserID, PasswordHash, Salt, IsSuperuser) ->
-     UserInfo = #user_info{user_id = {UserGroup, UserID},
-                           password_hash = PasswordHash,
-                           salt = Salt,
-                           is_superuser = IsSuperuser},
+    UserInfo = #user_info{
+        user_id = {UserGroup, UserID},
+        password_hash = PasswordHash,
+        salt = Salt,
+        is_superuser = IsSuperuser
+    },
     mnesia:write(?TAB, UserInfo, write).
 
 %% TODO: Support other type
@@ -392,15 +461,21 @@ format_user_info(#user_info{user_id = {_, UserID}, is_superuser = IsSuperuser})
     #{user_id => UserID, is_superuser => IsSuperuser}.
 
 ms_from_qstring(QString) ->
-    [Ms] = lists:foldl(fun({user_group, '=:=', UserGroup}, AccIn) ->
-                               [group_match_spec(UserGroup) | AccIn];
-                          (_, AccIn) ->
-                               AccIn
-                       end, [], QString),
+    [Ms] = lists:foldl(
+        fun
+            ({user_group, '=:=', UserGroup}, AccIn) ->
+                [group_match_spec(UserGroup) | AccIn];
+            (_, AccIn) ->
+                AccIn
+        end,
+        [],
+        QString
+    ),
     Ms.
 
 group_match_spec(UserGroup) ->
     ets:fun2ms(
-      fun(#user_info{user_id = {Group, _}} = User) when Group =:= UserGroup ->
-              User
-      end).
+        fun(#user_info{user_id = {Group, _}} = User) when Group =:= UserGroup ->
+            User
+        end
+    ).

+ 101 - 70
apps/emqx_authn/src/simple_authn/emqx_authn_mongodb.erl

@@ -23,18 +23,20 @@
 -behaviour(hocon_schema).
 -behaviour(emqx_authentication).
 
--export([ namespace/0
-        , roots/0
-        , fields/1
-        , desc/1
-        ]).
-
--export([ refs/0
-        , create/2
-        , update/2
-        , authenticate/2
-        , destroy/1
-        ]).
+-export([
+    namespace/0,
+    roots/0,
+    fields/1,
+    desc/1
+]).
+
+-export([
+    refs/0,
+    create/2,
+    update/2,
+    authenticate/2,
+    destroy/1
+]).
 
 %%------------------------------------------------------------------------------
 %% Hocon Schema
@@ -43,16 +45,18 @@
 namespace() -> "authn-mongodb".
 
 roots() ->
-    [ {?CONF_NS, hoconsc:mk(hoconsc:union(refs()),
-                            #{})}
+    [
+        {?CONF_NS,
+            hoconsc:mk(
+                hoconsc:union(refs()),
+                #{}
+            )}
     ].
 
 fields(standalone) ->
     common_fields() ++ emqx_connector_mongo:fields(single);
-
 fields('replica-set') ->
     common_fields() ++ emqx_connector_mongo:fields(rs);
-
 fields('sharded-cluster') ->
     common_fields() ++ emqx_connector_mongo:fields(sharded).
 
@@ -66,26 +70,30 @@ desc(_) ->
     undefined.
 
 common_fields() ->
-    [ {mechanism, emqx_authn_schema:mechanism('password_based')}
-    , {backend, emqx_authn_schema:backend(mongodb)}
-    , {collection, fun collection/1}
-    , {selector, fun selector/1}
-    , {password_hash_field, fun password_hash_field/1}
-    , {salt_field, fun salt_field/1}
-    , {is_superuser_field, fun is_superuser_field/1}
-    , {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1}
+    [
+        {mechanism, emqx_authn_schema:mechanism('password_based')},
+        {backend, emqx_authn_schema:backend(mongodb)},
+        {collection, fun collection/1},
+        {selector, fun selector/1},
+        {password_hash_field, fun password_hash_field/1},
+        {salt_field, fun salt_field/1},
+        {is_superuser_field, fun is_superuser_field/1},
+        {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1}
     ] ++ emqx_authn_schema:common_fields().
 
 collection(type) -> binary();
 collection(desc) -> "Collection used to store authentication data.";
 collection(_) -> undefined.
 
-selector(type) -> map();
-selector(desc) -> "Statement that is executed during the authentication process. "
-                  "Commands can support following wildcards:\n"
-                  " - `${username}`: substituted with client's username\n"
-                  " - `${clientid}`: substituted with the clientid";
-selector(_) -> undefined.
+selector(type) ->
+    map();
+selector(desc) ->
+    "Statement that is executed during the authentication process. "
+    "Commands can support following wildcards:\n"
+    " - `${username}`: substituted with client's username\n"
+    " - `${clientid}`: substituted with the clientid";
+selector(_) ->
+    undefined.
 
 password_hash_field(type) -> binary();
 password_hash_field(desc) -> "Document field that contains password hash.";
@@ -106,9 +114,10 @@ is_superuser_field(_) -> undefined.
 %%------------------------------------------------------------------------------
 
 refs() ->
-    [ hoconsc:ref(?MODULE, standalone)
-    , hoconsc:ref(?MODULE, 'replica-set')
-    , hoconsc:ref(?MODULE, 'sharded-cluster')
+    [
+        hoconsc:ref(?MODULE, standalone),
+        hoconsc:ref(?MODULE, 'replica-set'),
+        hoconsc:ref(?MODULE, 'sharded-cluster')
     ].
 
 create(_AuthenticatorID, Config) ->
@@ -117,24 +126,32 @@ create(_AuthenticatorID, Config) ->
 create(#{selector := Selector} = Config) ->
     SelectorTemplate = emqx_authn_utils:parse_deep(Selector),
     State = maps:with(
-              [collection,
-               password_hash_field,
-               salt_field,
-               is_superuser_field,
-               password_hash_algorithm,
-               salt_position],
-              Config),
+        [
+            collection,
+            password_hash_field,
+            salt_field,
+            is_superuser_field,
+            password_hash_algorithm,
+            salt_position
+        ],
+        Config
+    ),
     #{password_hash_algorithm := Algorithm} = State,
     ok = emqx_authn_password_hashing:init(Algorithm),
     ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
     NState = State#{
-               selector_template => SelectorTemplate,
-               resource_id => ResourceId},
-    case emqx_resource:create_local(ResourceId,
-                                    ?RESOURCE_GROUP,
-                                    emqx_connector_mongo,
-                                    Config,
-                                    #{}) of
+        selector_template => SelectorTemplate,
+        resource_id => ResourceId
+    },
+    case
+        emqx_resource:create_local(
+            ResourceId,
+            ?RESOURCE_GROUP,
+            emqx_connector_mongo,
+            Config,
+            #{}
+        )
+    of
         {ok, already_created} ->
             {ok, NState};
         {ok, _} ->
@@ -154,30 +171,39 @@ update(Config, State) ->
 
 authenticate(#{auth_method := _}, _) ->
     ignore;
-authenticate(#{password := Password} = Credential,
-             #{collection := Collection,
-               selector_template := SelectorTemplate,
-               resource_id := ResourceId} = State) ->
+authenticate(
+    #{password := Password} = Credential,
+    #{
+        collection := Collection,
+        selector_template := SelectorTemplate,
+        resource_id := ResourceId
+    } = State
+) ->
     Selector = emqx_authn_utils:render_deep(SelectorTemplate, Credential),
     case emqx_resource:query(ResourceId, {find_one, Collection, Selector, #{}}) of
-        undefined -> ignore;
+        undefined ->
+            ignore;
         {error, Reason} ->
-            ?SLOG(error, #{msg => "mongodb_query_failed",
-                           resource => ResourceId,
-                           collection => Collection,
-                           selector => Selector,
-                           reason => Reason}),
+            ?SLOG(error, #{
+                msg => "mongodb_query_failed",
+                resource => ResourceId,
+                collection => Collection,
+                selector => Selector,
+                reason => Reason
+            }),
             ignore;
         Doc ->
             case check_password(Password, Doc, State) of
                 ok ->
                     {ok, is_superuser(Doc, State)};
                 {error, {cannot_find_password_hash_field, PasswordHashField}} ->
-                    ?SLOG(error, #{msg => "cannot_find_password_hash_field",
-                                   resource => ResourceId,
-                                   collection => Collection,
-                                   selector => Selector,
-                                   password_hash_field => PasswordHashField}),
+                    ?SLOG(error, #{
+                        msg => "cannot_find_password_hash_field",
+                        resource => ResourceId,
+                        collection => Collection,
+                        selector => Selector,
+                        password_hash_field => PasswordHashField
+                    }),
                     ignore;
                 {error, Reason} ->
                     {error, Reason}
@@ -194,18 +220,23 @@ destroy(#{resource_id := ResourceId}) ->
 
 check_password(undefined, _Selected, _State) ->
     {error, bad_username_or_password};
-check_password(Password,
-               Doc,
-               #{password_hash_algorithm := Algorithm,
-                 password_hash_field := PasswordHashField} = State) ->
+check_password(
+    Password,
+    Doc,
+    #{
+        password_hash_algorithm := Algorithm,
+        password_hash_field := PasswordHashField
+    } = State
+) ->
     case maps:get(PasswordHashField, Doc, undefined) of
         undefined ->
             {error, {cannot_find_password_hash_field, PasswordHashField}};
         Hash ->
-            Salt = case maps:get(salt_field, State, undefined) of
-                       undefined -> <<>>;
-                       SaltField -> maps:get(SaltField, Doc, <<>>)
-                   end,
+            Salt =
+                case maps:get(salt_field, State, undefined) of
+                    undefined -> <<>>;
+                    SaltField -> maps:get(SaltField, Doc, <<>>)
+                end,
             case emqx_authn_password_hashing:check_password(Algorithm, Salt, Hash, Password) of
                 true -> ok;
                 false -> {error, bad_username_or_password}

+ 70 - 48
apps/emqx_authn/src/simple_authn/emqx_authn_mysql.erl

@@ -23,17 +23,19 @@
 -behaviour(hocon_schema).
 -behaviour(emqx_authentication).
 
--export([ namespace/0
-        , roots/0
-        , fields/1
-        ]).
-
--export([ refs/0
-        , create/2
-        , update/2
-        , authenticate/2
-        , destroy/1
-        ]).
+-export([
+    namespace/0,
+    roots/0,
+    fields/1
+]).
+
+-export([
+    refs/0,
+    create/2,
+    update/2,
+    authenticate/2,
+    destroy/1
+]).
 
 %%------------------------------------------------------------------------------
 %% Hocon Schema
@@ -44,13 +46,14 @@ namespace() -> "authn-mysql".
 roots() -> [?CONF_NS].
 
 fields(?CONF_NS) ->
-    [ {mechanism, emqx_authn_schema:mechanism('password_based')}
-    , {backend, emqx_authn_schema:backend(mysql)}
-    , {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1}
-    , {query, fun query/1}
-    , {query_timeout, fun query_timeout/1}
-    ] ++ emqx_authn_schema:common_fields()
-    ++ emqx_connector_mysql:fields(config).
+    [
+        {mechanism, emqx_authn_schema:mechanism('password_based')},
+        {backend, emqx_authn_schema:backend(mysql)},
+        {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1},
+        {query, fun query/1},
+        {query_timeout, fun query_timeout/1}
+    ] ++ emqx_authn_schema:common_fields() ++
+        emqx_connector_mysql:fields(config).
 
 query(type) -> string();
 query(_) -> undefined.
@@ -64,28 +67,37 @@ query_timeout(_) -> undefined.
 %%------------------------------------------------------------------------------
 
 refs() ->
-   [hoconsc:ref(?MODULE, ?CONF_NS)].
+    [hoconsc:ref(?MODULE, ?CONF_NS)].
 
 create(_AuthenticatorID, Config) ->
     create(Config).
 
-create(#{password_hash_algorithm := Algorithm,
-         query := Query0,
-         query_timeout := QueryTimeout
-        } = Config) ->
+create(
+    #{
+        password_hash_algorithm := Algorithm,
+        query := Query0,
+        query_timeout := QueryTimeout
+    } = Config
+) ->
     ok = emqx_authn_password_hashing:init(Algorithm),
     {Query, PlaceHolders} = emqx_authn_utils:parse_sql(Query0, '?'),
     ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
-    State = #{password_hash_algorithm => Algorithm,
-              query => Query,
-              placeholders => PlaceHolders,
-              query_timeout => QueryTimeout,
-              resource_id => ResourceId},
-    case emqx_resource:create_local(ResourceId,
-                                    ?RESOURCE_GROUP,
-                                    emqx_connector_mysql,
-                                    Config,
-                                    #{}) of
+    State = #{
+        password_hash_algorithm => Algorithm,
+        query => Query,
+        placeholders => PlaceHolders,
+        query_timeout => QueryTimeout,
+        resource_id => ResourceId
+    },
+    case
+        emqx_resource:create_local(
+            ResourceId,
+            ?RESOURCE_GROUP,
+            emqx_connector_mysql,
+            Config,
+            #{}
+        )
+    of
         {ok, already_created} ->
             {ok, State};
         {ok, _} ->
@@ -105,31 +117,41 @@ update(Config, State) ->
 
 authenticate(#{auth_method := _}, _) ->
     ignore;
-authenticate(#{password := Password} = Credential,
-             #{placeholders := PlaceHolders,
-               query := Query,
-               query_timeout := Timeout,
-               resource_id := ResourceId,
-               password_hash_algorithm := Algorithm}) ->
+authenticate(
+    #{password := Password} = Credential,
+    #{
+        placeholders := PlaceHolders,
+        query := Query,
+        query_timeout := Timeout,
+        resource_id := ResourceId,
+        password_hash_algorithm := Algorithm
+    }
+) ->
     Params = emqx_authn_utils:render_sql_params(PlaceHolders, Credential),
     case emqx_resource:query(ResourceId, {sql, Query, Params, Timeout}) of
-        {ok, _Columns, []} -> ignore;
+        {ok, _Columns, []} ->
+            ignore;
         {ok, Columns, [Row | _]} ->
             Selected = maps:from_list(lists:zip(Columns, Row)),
-            case emqx_authn_utils:check_password_from_selected_map(
-                  Algorithm, Selected, Password) of
+            case
+                emqx_authn_utils:check_password_from_selected_map(
+                    Algorithm, Selected, Password
+                )
+            of
                 ok ->
                     {ok, emqx_authn_utils:is_superuser(Selected)};
                 {error, Reason} ->
                     {error, Reason}
             end;
         {error, Reason} ->
-            ?SLOG(error, #{msg => "mysql_query_failed",
-                           resource => ResourceId,
-                           query => Query,
-                           params => Params,
-                           timeout => Timeout,
-                           reason => Reason}),
+            ?SLOG(error, #{
+                msg => "mysql_query_failed",
+                resource => ResourceId,
+                query => Query,
+                params => Params,
+                timeout => Timeout,
+                reason => Reason
+            }),
             ignore
     end.
 

+ 61 - 36
apps/emqx_authn/src/simple_authn/emqx_authn_pgsql.erl

@@ -24,17 +24,19 @@
 -behaviour(hocon_schema).
 -behaviour(emqx_authentication).
 
--export([ namespace/0
-        , roots/0
-        , fields/1
-        ]).
-
--export([ refs/0
-        , create/2
-        , update/2
-        , authenticate/2
-        , destroy/1
-        ]).
+-export([
+    namespace/0,
+    roots/0,
+    fields/1
+]).
+
+-export([
+    refs/0,
+    create/2,
+    update/2,
+    authenticate/2,
+    destroy/1
+]).
 
 -ifdef(TEST).
 -compile(export_all).
@@ -50,13 +52,14 @@ namespace() -> "authn-postgresql".
 roots() -> [?CONF_NS].
 
 fields(?CONF_NS) ->
-    [ {mechanism, emqx_authn_schema:mechanism('password_based')}
-    , {backend, emqx_authn_schema:backend(postgresql)}
-    , {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1}
-    , {query, fun query/1}
+    [
+        {mechanism, emqx_authn_schema:mechanism('password_based')},
+        {backend, emqx_authn_schema:backend(postgresql)},
+        {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1},
+        {query, fun query/1}
     ] ++
-    emqx_authn_schema:common_fields() ++
-    proplists:delete(named_queries, emqx_connector_pgsql:fields(config)).
+        emqx_authn_schema:common_fields() ++
+        proplists:delete(named_queries, emqx_connector_pgsql:fields(config)).
 
 query(type) -> string();
 query(_) -> undefined.
@@ -71,17 +74,29 @@ refs() ->
 create(_AuthenticatorID, Config) ->
     create(Config).
 
-create(#{query := Query0,
-         password_hash_algorithm := Algorithm} = Config) ->
+create(
+    #{
+        query := Query0,
+        password_hash_algorithm := Algorithm
+    } = Config
+) ->
     ok = emqx_authn_password_hashing:init(Algorithm),
     {Query, PlaceHolders} = emqx_authn_utils:parse_sql(Query0, '$n'),
     ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
-    State = #{placeholders => PlaceHolders,
-              password_hash_algorithm => Algorithm,
-              resource_id => ResourceId},
-    case emqx_resource:create_local(ResourceId, ?RESOURCE_GROUP, emqx_connector_pgsql,
-                                    Config#{named_queries => #{ResourceId => Query}},
-                                    #{}) of
+    State = #{
+        placeholders => PlaceHolders,
+        password_hash_algorithm => Algorithm,
+        resource_id => ResourceId
+    },
+    case
+        emqx_resource:create_local(
+            ResourceId,
+            ?RESOURCE_GROUP,
+            emqx_connector_pgsql,
+            Config#{named_queries => #{ResourceId => Query}},
+            #{}
+        )
+    of
         {ok, already_created} ->
             {ok, State};
         {ok, _} ->
@@ -101,28 +116,38 @@ update(Config, State) ->
 
 authenticate(#{auth_method := _}, _) ->
     ignore;
-authenticate(#{password := Password} = Credential,
-             #{placeholders := PlaceHolders,
-               resource_id := ResourceId,
-               password_hash_algorithm := Algorithm}) ->
+authenticate(
+    #{password := Password} = Credential,
+    #{
+        placeholders := PlaceHolders,
+        resource_id := ResourceId,
+        password_hash_algorithm := Algorithm
+    }
+) ->
     Params = emqx_authn_utils:render_sql_params(PlaceHolders, Credential),
     case emqx_resource:query(ResourceId, {prepared_query, ResourceId, Params}) of
-        {ok, _Columns, []} -> ignore;
+        {ok, _Columns, []} ->
+            ignore;
         {ok, Columns, [Row | _]} ->
             NColumns = [Name || #column{name = Name} <- Columns],
             Selected = maps:from_list(lists:zip(NColumns, erlang:tuple_to_list(Row))),
-            case emqx_authn_utils:check_password_from_selected_map(
-                  Algorithm, Selected, Password) of
+            case
+                emqx_authn_utils:check_password_from_selected_map(
+                    Algorithm, Selected, Password
+                )
+            of
                 ok ->
                     {ok, emqx_authn_utils:is_superuser(Selected)};
                 {error, Reason} ->
                     {error, Reason}
             end;
         {error, Reason} ->
-            ?SLOG(error, #{msg => "postgresql_query_failed",
-                           resource => ResourceId,
-                           params => Params,
-                           reason => Reason}),
+            ?SLOG(error, #{
+                msg => "postgresql_query_failed",
+                resource => ResourceId,
+                params => Params,
+                reason => Reason
+            }),
             ignore
     end.
 

+ 84 - 51
apps/emqx_authn/src/simple_authn/emqx_authn_redis.erl

@@ -23,17 +23,19 @@
 -behaviour(hocon_schema).
 -behaviour(emqx_authentication).
 
--export([ namespace/0
-        , roots/0
-        , fields/1
-        ]).
-
--export([ refs/0
-        , create/2
-        , update/2
-        , authenticate/2
-        , destroy/1
-        ]).
+-export([
+    namespace/0,
+    roots/0,
+    fields/1
+]).
+
+-export([
+    refs/0,
+    create/2,
+    update/2,
+    authenticate/2,
+    destroy/1
+]).
 
 %%------------------------------------------------------------------------------
 %% Hocon Schema
@@ -42,24 +44,27 @@
 namespace() -> "authn-redis".
 
 roots() ->
-    [ {?CONF_NS, hoconsc:mk(hoconsc:union(refs()),
-                            #{})}
+    [
+        {?CONF_NS,
+            hoconsc:mk(
+                hoconsc:union(refs()),
+                #{}
+            )}
     ].
 
 fields(standalone) ->
     common_fields() ++ emqx_connector_redis:fields(single);
-
 fields(cluster) ->
     common_fields() ++ emqx_connector_redis:fields(cluster);
-
 fields(sentinel) ->
     common_fields() ++ emqx_connector_redis:fields(sentinel).
 
 common_fields() ->
-    [ {mechanism, emqx_authn_schema:mechanism('password_based')}
-    , {backend, emqx_authn_schema:backend(redis)}
-    , {cmd, fun cmd/1}
-    , {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1}
+    [
+        {mechanism, emqx_authn_schema:mechanism('password_based')},
+        {backend, emqx_authn_schema:backend(redis)},
+        {cmd, fun cmd/1},
+        {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1}
     ] ++ emqx_authn_schema:common_fields().
 
 cmd(type) -> string();
@@ -70,30 +75,43 @@ cmd(_) -> undefined.
 %%------------------------------------------------------------------------------
 
 refs() ->
-    [ hoconsc:ref(?MODULE, standalone)
-    , hoconsc:ref(?MODULE, cluster)
-    , hoconsc:ref(?MODULE, sentinel)
+    [
+        hoconsc:ref(?MODULE, standalone),
+        hoconsc:ref(?MODULE, cluster),
+        hoconsc:ref(?MODULE, sentinel)
     ].
 
 create(_AuthenticatorID, Config) ->
     create(Config).
 
-create(#{cmd := Cmd,
-         password_hash_algorithm := Algorithm} = Config) ->
+create(
+    #{
+        cmd := Cmd,
+        password_hash_algorithm := Algorithm
+    } = Config
+) ->
     ok = emqx_authn_password_hashing:init(Algorithm),
     try
         NCmd = parse_cmd(Cmd),
         ok = emqx_authn_utils:ensure_apps_started(Algorithm),
         State = maps:with(
-                  [password_hash_algorithm, salt_position],
-                  Config),
+            [password_hash_algorithm, salt_position],
+            Config
+        ),
         ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
         NState = State#{
-                   cmd => NCmd,
-                   resource_id => ResourceId},
-        case emqx_resource:create_local(ResourceId, ?RESOURCE_GROUP,
-                                        emqx_connector_redis, Config,
-                                        #{}) of
+            cmd => NCmd,
+            resource_id => ResourceId
+        },
+        case
+            emqx_resource:create_local(
+                ResourceId,
+                ?RESOURCE_GROUP,
+                emqx_connector_redis,
+                Config,
+                #{}
+            )
+        of
             {ok, already_created} ->
                 {ok, NState};
             {ok, _} ->
@@ -121,38 +139,50 @@ update(Config, State) ->
 
 authenticate(#{auth_method := _}, _) ->
     ignore;
-authenticate(#{password := Password} = Credential,
-             #{cmd := {Command, KeyTemplate, Fields},
-               resource_id := ResourceId,
-               password_hash_algorithm := Algorithm}) ->
+authenticate(
+    #{password := Password} = Credential,
+    #{
+        cmd := {Command, KeyTemplate, Fields},
+        resource_id := ResourceId,
+        password_hash_algorithm := Algorithm
+    }
+) ->
     NKey = emqx_authn_utils:render_str(KeyTemplate, Credential),
     case emqx_resource:query(ResourceId, {cmd, [Command, NKey | Fields]}) of
-        {ok, []} -> ignore;
+        {ok, []} ->
+            ignore;
         {ok, Values} ->
             case merge(Fields, Values) of
                 #{<<"password_hash">> := _} = Selected ->
-                    case emqx_authn_utils:check_password_from_selected_map(
-                          Algorithm, Selected, Password) of
+                    case
+                        emqx_authn_utils:check_password_from_selected_map(
+                            Algorithm, Selected, Password
+                        )
+                    of
                         ok ->
                             {ok, emqx_authn_utils:is_superuser(Selected)};
                         {error, Reason} ->
                             {error, Reason}
                     end;
                 _ ->
-                    ?SLOG(error, #{msg => "cannot_find_password_hash_field",
-                                   cmd => Command,
-                                   keys => NKey,
-                                   fields => Fields,
-                                   resource => ResourceId}),
+                    ?SLOG(error, #{
+                        msg => "cannot_find_password_hash_field",
+                        cmd => Command,
+                        keys => NKey,
+                        fields => Fields,
+                        resource => ResourceId
+                    }),
                     ignore
             end;
         {error, Reason} ->
-            ?SLOG(error, #{msg => "redis_query_failed",
-                           resource => ResourceId,
-                           cmd => Command,
-                           keys => NKey,
-                           fields => Fields,
-                           reason => Reason}),
+            ?SLOG(error, #{
+                msg => "redis_query_failed",
+                resource => ResourceId,
+                cmd => Command,
+                keys => NKey,
+                fields => Fields,
+                reason => Reason
+            }),
             ignore
     end.
 
@@ -191,5 +221,8 @@ merge(Fields, Value) when not is_list(Value) ->
     merge(Fields, [Value]);
 merge(Fields, Values) ->
     maps:from_list(
-        [{list_to_binary(K), V}
-            || {K, V} <- lists:zip(Fields, Values), V =/= undefined]).
+        [
+            {list_to_binary(K), V}
+         || {K, V} <- lists:zip(Fields, Values), V =/= undefined
+        ]
+    ).