emqx_authz_postgresql.erl 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqx_authz_postgresql).
  17. -include_lib("emqx/include/logger.hrl").
  18. -include_lib("emqx/include/emqx_placeholder.hrl").
  19. -include_lib("epgsql/include/epgsql.hrl").
  20. -behaviour(emqx_authz_source).
  21. %% AuthZ Callbacks
  22. -export([
  23. description/0,
  24. create/1,
  25. update/1,
  26. destroy/1,
  27. authorize/4
  28. ]).
  29. -ifdef(TEST).
  30. -compile(export_all).
  31. -compile(nowarn_export_all).
  32. -endif.
  33. -define(ALLOWED_VARS, [
  34. ?VAR_USERNAME,
  35. ?VAR_CLIENTID,
  36. ?VAR_PEERHOST,
  37. ?VAR_CERT_CN_NAME,
  38. ?VAR_CERT_SUBJECT,
  39. ?VAR_NS_CLIENT_ATTRS
  40. ]).
  41. description() ->
  42. "AuthZ with PostgreSQL".
  43. create(#{query := SQL0} = Source) ->
  44. {SQL, PlaceHolders} = emqx_auth_utils:parse_sql(SQL0, '$n', ?ALLOWED_VARS),
  45. ResourceID = emqx_authz_utils:make_resource_id(emqx_postgresql),
  46. {ok, _Data} = emqx_authz_utils:create_resource(
  47. ResourceID,
  48. emqx_postgresql,
  49. Source#{prepare_statement => #{ResourceID => SQL}}
  50. ),
  51. Source#{annotations => #{id => ResourceID, placeholders => PlaceHolders}}.
  52. update(#{query := SQL0, annotations := #{id := ResourceID}} = Source) ->
  53. {SQL, PlaceHolders} = emqx_auth_utils:parse_sql(SQL0, '$n', ?ALLOWED_VARS),
  54. case
  55. emqx_authz_utils:update_resource(
  56. emqx_postgresql,
  57. Source#{prepare_statement => #{ResourceID => SQL}}
  58. )
  59. of
  60. {error, Reason} ->
  61. error({load_config_error, Reason});
  62. {ok, Id} ->
  63. Source#{annotations => #{id => Id, placeholders => PlaceHolders}}
  64. end.
  65. destroy(#{annotations := #{id := Id}}) ->
  66. emqx_authz_utils:remove_resource(Id).
  67. authorize(
  68. Client,
  69. Action,
  70. Topic,
  71. #{
  72. annotations := #{
  73. id := ResourceID,
  74. placeholders := Placeholders
  75. }
  76. }
  77. ) ->
  78. Vars = emqx_authz_utils:vars_for_rule_query(Client, Action),
  79. RenderedParams = emqx_auth_utils:render_sql_params(Placeholders, Vars),
  80. case
  81. emqx_resource:simple_sync_query(ResourceID, {prepared_query, ResourceID, RenderedParams})
  82. of
  83. {ok, Columns, Rows} ->
  84. do_authorize(Client, Action, Topic, column_names(Columns), Rows);
  85. {error, Reason} ->
  86. ?SLOG(error, #{
  87. msg => "query_postgresql_error",
  88. reason => Reason,
  89. params => RenderedParams,
  90. resource_id => ResourceID
  91. }),
  92. nomatch
  93. end.
  94. do_authorize(_Client, _Action, _Topic, _ColumnNames, []) ->
  95. nomatch;
  96. do_authorize(Client, Action, Topic, ColumnNames, [Row | Tail]) ->
  97. case emqx_authz_utils:do_authorize(postgresql, Client, Action, Topic, ColumnNames, Row) of
  98. nomatch ->
  99. do_authorize(Client, Action, Topic, ColumnNames, Tail);
  100. {matched, Permission} ->
  101. {matched, Permission}
  102. end.
  103. column_names(Columns) ->
  104. lists:map(
  105. fun(#column{name = Name}) -> Name end,
  106. Columns
  107. ).