• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

emqx / emqx / 12583614476

02 Jan 2025 02:04PM UTC coverage: 82.082%. First build
12583614476

Pull #14286

github

web-flow
Merge c9df97f1e into d5a56c20b
Pull Request #14286: Implement node-level authentication/authorization cache

305 of 338 new or added lines in 29 files covered. (90.24%)

56808 of 69209 relevant lines covered (82.08%)

15216.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.57
/apps/emqx_auth/src/emqx_authz/emqx_authz_api_cache.erl
1
%%--------------------------------------------------------------------
2
%% Copyright (c) 2020-2025 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

17
-module(emqx_authz_api_cache).
18

19
-behaviour(minirest_api).
20

21
-include_lib("hocon/include/hoconsc.hrl").
22
-include("emqx_authz.hrl").
23

24
-export([
25
    api_spec/0,
26
    paths/0,
27
    schema/1
28
]).
29

30
-export([
31
    fields/1,
32
    namespace/0
33
]).
34

35
-export([
36
    clean_cache/2,
37
    node_cache/2,
38
    node_cache_status/2,
39
    node_cache_reset/2
40
]).
41

42
-import(hoconsc, [ref/2]).
43
-import(emqx_dashboard_swagger, [error_codes/2]).
44

45
-define(BAD_REQUEST, 'BAD_REQUEST').
46
-define(INTERNAL_ERROR, 'INTERNAL_ERROR').
47

48
api_spec() ->
49
    emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
112✔
50

51
paths() ->
52
    [
112✔
53
        "/authorization/cache",
54
        "/authorization/node_cache",
55
        "/authorization/node_cache/status",
56
        "/authorization/node_cache/reset"
57
    ].
58

59
%%--------------------------------------------------------------------
60
%% Schema for each URI
61
%%--------------------------------------------------------------------
62

63
schema("/authorization/cache") ->
64
    #{
113✔
65
        'operationId' => clean_cache,
66
        delete =>
67
            #{
68
                description => ?DESC(authorization_cache_delete),
69
                responses =>
70
                    #{
71
                        204 => <<"No Content">>,
72
                        400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad Request">>)
73
                    }
74
            }
75
    };
76
schema("/authorization/node_cache") ->
77
    #{
115✔
78
        'operationId' => node_cache,
79
        get => #{
80
            description => ?DESC(authorization_node_cache_get),
81
            responses => #{
82
                200 => emqx_dashboard_swagger:schema_with_example(
83
                    ref(?MODULE, response_authz_node_cache),
84
                    authz_node_cache_example()
85
                )
86
            }
87
        },
88
        put => #{
89
            description => ?DESC(authorization_node_cache_put),
90
            'requestBody' => emqx_dashboard_swagger:schema_with_example(
91
                ref(?MODULE, response_authz_node_cache),
92
                authz_node_cache_example()
93
            ),
94
            responses => #{
95
                204 => <<"Authentication cache updated">>,
96
                400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
97
            }
98
        }
99
    };
100
schema("/authorization/node_cache/status") ->
101
    #{
114✔
102
        'operationId' => node_cache_status,
103
        get => #{
104
            description => ?DESC(authorization_node_cache_status_get),
105
            responses => #{
106
                200 => emqx_dashboard_swagger:schema_with_example(
107
                    ref(emqx_auth_cache_schema, status),
108
                    authz_node_cache_status_example()
109
                ),
110
                500 => error_codes([?INTERNAL_ERROR], <<"Internal Service Error">>)
111
            }
112
        }
113
    };
114
schema("/authorization/node_cache/reset") ->
115
    #{
113✔
116
        'operationId' => node_cache_reset,
117
        post =>
118
            #{
119
                description => ?DESC(authorization_node_cache_reset_post),
120
                responses =>
121
                    #{
122
                        204 => <<"No Content">>,
123
                        500 => error_codes([?INTERNAL_ERROR], <<"Internal Service Error">>)
124
                    }
125
            }
126
    }.
127

128
%%--------------------------------------------------------------------
129
%% Handlers
130
%%--------------------------------------------------------------------
131

132
clean_cache(delete, _) ->
133
    case emqx_mgmt:clean_authz_cache_all() of
1✔
134
        ok ->
135
            {204};
1✔
136
        {error, Reason} ->
137
            {400, #{
×
138
                code => <<"BAD_REQUEST">>,
139
                message => bin(Reason)
140
            }}
141
    end.
142

143
node_cache(get, _) ->
144
    RawConfig = emqx:get_raw_config([authorization, node_cache]),
2✔
145
    {200, emqx_auth_cache_schema:fill_defaults(RawConfig)};
2✔
146
node_cache(put, #{body := Config}) ->
147
    case update_config([authorization, node_cache], Config) of
1✔
148
        {ok, _} ->
149
            {204};
1✔
150
        {error, Reason} ->
NEW
151
            serialize_error(Reason)
×
152
    end.
153

154
node_cache_status(get, _) ->
155
    Nodes = mria:running_nodes(),
2✔
156
    LookupResult = emqx_auth_cache_proto_v1:metrics(Nodes, ?AUTHZ_CACHE),
2✔
157
    case is_ok(LookupResult) of
2✔
158
        {ok, ResList} ->
159
            NodeMetrics = lists:map(
2✔
160
                fun({Node, Metrics}) ->
161
                    #{node => Node, metrics => Metrics}
2✔
162
                end,
163
                ResList
164
            ),
165
            {_, Metrics} = lists:unzip(ResList),
2✔
166
            AggregatedMetrics = aggregate_metrics(Metrics),
2✔
167
            Response = #{
2✔
168
                node_metrics => NodeMetrics,
169
                metrics => AggregatedMetrics
170
            },
171
            {200, Response};
2✔
172
        {error, ErrL} ->
NEW
173
            {500, #{
×
174
                code => <<"INTERNAL_ERROR">>,
175
                message => bin(ErrL)
176
            }}
177
    end.
178

179
node_cache_reset(post, _) ->
180
    Nodes = mria:running_nodes(),
1✔
181
    case is_ok(emqx_auth_cache_proto_v1:reset(Nodes, ?AUTHZ_CACHE)) of
1✔
182
        {ok, _} ->
183
            {204};
1✔
184
        {error, ErrL} ->
NEW
185
            {500, #{
×
186
                code => <<"INTERNAL_ERROR">>,
187
                message => bin(ErrL)
188
            }}
189
    end.
190

191
%%--------------------------------------------------------------------
192
%% Internal functions
193
%%--------------------------------------------------------------------
194

195
update_config(Path, ConfigRequest) ->
196
    emqx_conf:update(Path, ConfigRequest, #{
1✔
197
        rawconf_with_defaults => true,
198
        override_to => cluster
199
    }).
200

NEW
201
bin(Term) -> erlang:iolist_to_binary(io_lib:format("~0p", [Term])).
×
202

203
serialize_error(Reason) ->
NEW
204
    {400, #{
×
205
        code => <<"BAD_REQUEST">>,
206
        message => bin(Reason)
207
    }}.
208

209
is_ok(ResL) ->
210
    case
3✔
211
        lists:filter(
212
            fun
213
                ({ok, _}) -> false;
3✔
NEW
214
                (_) -> true
×
215
            end,
216
            ResL
217
        )
218
    of
219
        [] -> {ok, [Res || {ok, Res} <- ResL]};
3✔
NEW
220
        ErrL -> {error, ErrL}
×
221
    end.
222

223
aggregate_metrics(Metrics) ->
224
    emqx_authn_api:aggregate_metrics(Metrics).
2✔
225

226
%%--------------------------------------------------------------------
227
%% Schema
228
%%--------------------------------------------------------------------
229

230
namespace() -> undefined.
336✔
231

232
fields(request_authz_node_cache) ->
NEW
233
    emqx_auth_cache_schema:fields(config);
×
234
fields(response_authz_node_cache) ->
235
    emqx_auth_cache_schema:fields(config).
113✔
236

237
%%--------------------------------------------------------------------
238
%% Schema examples
239
%%--------------------------------------------------------------------
240

241
authz_node_cache_example() ->
242
    emqx_auth_cache_schema:cache_settings_example().
230✔
243

244
authz_node_cache_status_example() ->
245
    emqx_auth_cache_schema:metrics_example().
114✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc