| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- %%--------------------------------------------------------------------
- %% Copyright (c) 2021-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
- %%
- %% Licensed under the Apache License, Version 2.0 (the "License");
- %% you may not use this file except in compliance with the License.
- %% You may obtain a copy of the License at
- %%
- %% http://www.apache.org/licenses/LICENSE-2.0
- %%
- %% Unless required by applicable law or agreed to in writing, software
- %% distributed under the License is distributed on an "AS IS" BASIS,
- %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- %% See the License for the specific language governing permissions and
- %% limitations under the License.
- %%--------------------------------------------------------------------
- -module(emqx_authn_postgresql).
- -include_lib("emqx_auth/include/emqx_authn.hrl").
- -include_lib("emqx/include/logger.hrl").
- -include_lib("epgsql/include/epgsql.hrl").
- -behaviour(emqx_authn_provider).
- -export([
- create/2,
- update/2,
- authenticate/2,
- destroy/1
- ]).
- -ifdef(TEST).
- -compile(export_all).
- -compile(nowarn_export_all).
- -endif.
- %%------------------------------------------------------------------------------
- %% APIs
- %%------------------------------------------------------------------------------
- create(_AuthenticatorID, Config) ->
- create(Config).
- create(Config0) ->
- ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
- {Config, State} = parse_config(Config0, ResourceId),
- {ok, _Data} = emqx_authn_utils:create_resource(
- ResourceId,
- emqx_postgresql,
- Config
- ),
- {ok, State#{resource_id => ResourceId}}.
- update(Config0, #{resource_id := ResourceId} = _State) ->
- {Config, NState} = parse_config(Config0, ResourceId),
- case emqx_authn_utils:update_resource(emqx_postgresql, Config, ResourceId) of
- {error, Reason} ->
- error({load_config_error, Reason});
- {ok, _} ->
- {ok, NState#{resource_id => ResourceId}}
- end.
- destroy(#{resource_id := ResourceId}) ->
- _ = emqx_resource:remove_local(ResourceId),
- ok.
- authenticate(#{auth_method := _}, _) ->
- ignore;
- authenticate(#{password := undefined}, _) ->
- {error, bad_username_or_password};
- 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:simple_sync_query(ResourceId, {prepared_query, ResourceId, Params}) of
- {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
- ok ->
- {ok, emqx_authn_utils:is_superuser(Selected)};
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- ?TRACE_AUTHN_PROVIDER(error, "postgresql_query_failed", #{
- resource => ResourceId,
- params => Params,
- reason => Reason
- }),
- ignore
- end.
- parse_config(
- #{
- query := Query0,
- password_hash_algorithm := Algorithm
- } = Config,
- ResourceId
- ) ->
- ok = emqx_authn_password_hashing:init(Algorithm),
- {Query, PlaceHolders} = emqx_authn_utils:parse_sql(Query0, '$n'),
- State = #{
- placeholders => PlaceHolders,
- password_hash_algorithm => Algorithm
- },
- {Config#{prepare_statement => #{ResourceId => Query}}, State}.
|