| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- %%--------------------------------------------------------------------
- %% Copyright (c) 2020-2023 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_authz_postgresql).
- -include_lib("emqx/include/logger.hrl").
- -include_lib("emqx/include/emqx_placeholder.hrl").
- -include_lib("epgsql/include/epgsql.hrl").
- -behaviour(emqx_authz_source).
- %% AuthZ Callbacks
- -export([
- description/0,
- create/1,
- update/1,
- destroy/1,
- authorize/4
- ]).
- -ifdef(TEST).
- -compile(export_all).
- -compile(nowarn_export_all).
- -endif.
- -define(ALLOWED_VARS, [
- ?VAR_USERNAME,
- ?VAR_CLIENTID,
- ?VAR_PEERHOST,
- ?VAR_CERT_CN_NAME,
- ?VAR_CERT_SUBJECT
- ]).
- description() ->
- "AuthZ with PostgreSQL".
- create(#{query := SQL0} = Source) ->
- {SQL, PlaceHolders} = emqx_authz_utils:parse_sql(SQL0, '$n', ?ALLOWED_VARS),
- ResourceID = emqx_authz_utils:make_resource_id(emqx_postgresql),
- {ok, _Data} = emqx_authz_utils:create_resource(
- ResourceID,
- emqx_postgresql,
- Source#{prepare_statement => #{ResourceID => SQL}}
- ),
- Source#{annotations => #{id => ResourceID, placeholders => PlaceHolders}}.
- update(#{query := SQL0, annotations := #{id := ResourceID}} = Source) ->
- {SQL, PlaceHolders} = emqx_authz_utils:parse_sql(SQL0, '$n', ?ALLOWED_VARS),
- case
- emqx_authz_utils:update_resource(
- emqx_postgresql,
- Source#{prepare_statement => #{ResourceID => SQL}}
- )
- of
- {error, Reason} ->
- error({load_config_error, Reason});
- {ok, Id} ->
- Source#{annotations => #{id => Id, placeholders => PlaceHolders}}
- end.
- destroy(#{annotations := #{id := Id}}) ->
- emqx_authz_utils:remove_resource(Id).
- authorize(
- Client,
- Action,
- Topic,
- #{
- annotations := #{
- id := ResourceID,
- placeholders := Placeholders
- }
- }
- ) ->
- Vars = emqx_authz_utils:vars_for_rule_query(Client, Action),
- RenderedParams = emqx_authz_utils:render_sql_params(Placeholders, Vars),
- case
- emqx_resource:simple_sync_query(ResourceID, {prepared_query, ResourceID, RenderedParams})
- of
- {ok, Columns, Rows} ->
- do_authorize(Client, Action, Topic, column_names(Columns), Rows);
- {error, Reason} ->
- ?SLOG(error, #{
- msg => "query_postgresql_error",
- reason => Reason,
- params => RenderedParams,
- resource_id => ResourceID
- }),
- nomatch
- end.
- do_authorize(_Client, _Action, _Topic, _ColumnNames, []) ->
- nomatch;
- do_authorize(Client, Action, Topic, ColumnNames, [Row | Tail]) ->
- try
- emqx_authz_rule:match(
- Client, Action, Topic, emqx_authz_utils:parse_rule_from_row(ColumnNames, Row)
- )
- of
- {matched, Permission} -> {matched, Permission};
- nomatch -> do_authorize(Client, Action, Topic, ColumnNames, Tail)
- catch
- error:Reason:Stack ->
- ?SLOG(error, #{
- msg => "match_rule_error",
- reason => Reason,
- rule => Row,
- stack => Stack
- }),
- do_authorize(Client, Action, Topic, ColumnNames, Tail)
- end.
- column_names(Columns) ->
- lists:map(
- fun(#column{name = Name}) -> Name end,
- Columns
- ).
|