Merge pull request #8374 from JimMoen/fix-authn-http
fix(authn): authn http `is_superuser` field
This commit is contained in:
commit
8d4907eedd
|
@ -2,20 +2,24 @@
|
|||
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||
{VSN,
|
||||
[{"5.0.0",
|
||||
[{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_quic_connection,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_config,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_schema,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_release,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_authentication,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_metrics,brutal_purge,soft_purge,[]},
|
||||
{add_module,emqx_exclusive_subscription},
|
||||
{apply, {emqx_exclusive_subscription, on_add_module, []}},
|
||||
{apply,{emqx_exclusive_subscription,on_add_module,[]}},
|
||||
{load_module,emqx_broker,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mqtt_caps,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_topic,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_relup}]},
|
||||
{<<".*">>,[]}],
|
||||
[{"5.0.0",
|
||||
[{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_quic_connection,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_config,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_schema,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_release,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_authentication,brutal_purge,soft_purge,[]},
|
||||
|
@ -23,7 +27,7 @@
|
|||
{load_module,emqx_broker,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mqtt_caps,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_topic,brutal_purge,soft_purge,[]},
|
||||
{apply, {emqx_exclusive_subscription, on_delete_module, []}},
|
||||
{apply,{emqx_exclusive_subscription,on_delete_module,[]}},
|
||||
{delete_module,emqx_exclusive_subscription},
|
||||
{load_module,emqx_relup}]},
|
||||
{<<".*">>,[]}]}.
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
%% -*- mode: erlang -*-
|
||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||
{VSN,
|
||||
[{"0.1.0",[
|
||||
[{"0.1.0",
|
||||
[{load_module,emqx_authn_http,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_authn_utils,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_authn_redis,brutal_purge,soft_purge,[]}]
|
||||
}],
|
||||
[{"0.1.0",[
|
||||
{load_module,emqx_authn_redis,brutal_purge,soft_purge,[]}]},
|
||||
{<<".*">>,[]}],
|
||||
[{"0.1.0",
|
||||
[{load_module,emqx_authn_http,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_authn_utils,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_authn_redis,brutal_purge,soft_purge,[]}]
|
||||
}]}.
|
||||
{load_module,emqx_authn_redis,brutal_purge,soft_purge,[]}]},
|
||||
{<<".*">>,[]}]}.
|
||||
|
|
|
@ -135,6 +135,18 @@ render_sql_params(ParamList, Credential) ->
|
|||
#{return => rawlist, var_trans => fun handle_sql_var/2}
|
||||
).
|
||||
|
||||
%% true
|
||||
is_superuser(#{<<"is_superuser">> := <<"true">>}) ->
|
||||
#{is_superuser => true};
|
||||
is_superuser(#{<<"is_superuser">> := true}) ->
|
||||
#{is_superuser => true};
|
||||
is_superuser(#{<<"is_superuser">> := <<"1">>}) ->
|
||||
#{is_superuser => true};
|
||||
is_superuser(#{<<"is_superuser">> := I}) when
|
||||
is_integer(I) andalso I >= 1
|
||||
->
|
||||
#{is_superuser => true};
|
||||
%% false
|
||||
is_superuser(#{<<"is_superuser">> := <<"">>}) ->
|
||||
#{is_superuser => false};
|
||||
is_superuser(#{<<"is_superuser">> := <<"0">>}) ->
|
||||
|
@ -145,10 +157,25 @@ is_superuser(#{<<"is_superuser">> := null}) ->
|
|||
#{is_superuser => false};
|
||||
is_superuser(#{<<"is_superuser">> := undefined}) ->
|
||||
#{is_superuser => false};
|
||||
is_superuser(#{<<"is_superuser">> := <<"false">>}) ->
|
||||
#{is_superuser => false};
|
||||
is_superuser(#{<<"is_superuser">> := false}) ->
|
||||
#{is_superuser => false};
|
||||
is_superuser(#{<<"is_superuser">> := MaybeBinInt}) when
|
||||
is_binary(MaybeBinInt)
|
||||
->
|
||||
try binary_to_integer(MaybeBinInt) of
|
||||
Int when Int >= 1 ->
|
||||
#{is_superuser => true};
|
||||
Int when Int =< 0 ->
|
||||
#{is_superuser => false}
|
||||
catch
|
||||
error:badarg ->
|
||||
#{is_superuser => false}
|
||||
end;
|
||||
%% fallback to default
|
||||
is_superuser(#{<<"is_superuser">> := _}) ->
|
||||
#{is_superuser => true};
|
||||
#{is_superuser => false};
|
||||
is_superuser(#{}) ->
|
||||
#{is_superuser => false}.
|
||||
|
||||
|
|
|
@ -191,48 +191,21 @@ authenticate(
|
|||
case emqx_resource:query(ResourceId, {Method, Request, RequestTimeout}) of
|
||||
{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
|
||||
{ok, NBody} ->
|
||||
%% TODO: Return by user property
|
||||
UserProperty = maps:remove(<<"is_superuser">>, NBody),
|
||||
IsSuperuser = emqx_authn_utils:is_superuser(NBody),
|
||||
{ok, IsSuperuser#{user_property => UserProperty}};
|
||||
{error, _Reason} ->
|
||||
{ok, #{is_superuser => false}}
|
||||
end;
|
||||
handle_response(Headers, Body);
|
||||
{ok, _StatusCode, _Headers} = Response ->
|
||||
log_response(ResourceId, Response),
|
||||
ignore;
|
||||
{ok, _StatusCode, _Headers, _Body} = Response ->
|
||||
log_response(ResourceId, Response),
|
||||
ignore;
|
||||
{error, 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
|
||||
}),
|
||||
ignore;
|
||||
Code4xx when Code4xx >= 400 andalso Code4xx < 500 ->
|
||||
?SLOG(warning, Output#{
|
||||
msg => "refused_by_http_server",
|
||||
code => Code4xx
|
||||
}),
|
||||
{error, not_authorized};
|
||||
OtherCode ->
|
||||
?SLOG(error, Output#{
|
||||
msg => "undesired_response_code",
|
||||
code => OtherCode
|
||||
}),
|
||||
ignore
|
||||
end
|
||||
ignore
|
||||
end.
|
||||
|
||||
destroy(#{resource_id := ResourceId}) ->
|
||||
|
@ -366,20 +339,43 @@ qs([{K, V} | More], Acc) ->
|
|||
serialize_body(<<"application/json">>, Body) ->
|
||||
emqx_json:encode(Body);
|
||||
serialize_body(<<"application/x-www-form-urlencoded">>, Body) ->
|
||||
qs(Body).
|
||||
qs(maps:to_list(Body)).
|
||||
|
||||
handle_response(Headers, Body) ->
|
||||
ContentType = proplists:get_value(<<"content-type">>, Headers),
|
||||
case safely_parse_body(ContentType, Body) of
|
||||
{ok, NBody} ->
|
||||
case maps:get(<<"result">>, NBody, <<"ignore">>) of
|
||||
<<"allow">> ->
|
||||
Res = emqx_authn_utils:is_superuser(NBody),
|
||||
%% TODO: Return by user property
|
||||
{ok, Res#{user_property => maps:get(<<"user_property">>, NBody, #{})}};
|
||||
<<"deny">> ->
|
||||
{error, not_authorized};
|
||||
<<"ignore">> ->
|
||||
ignore;
|
||||
_ ->
|
||||
ignore
|
||||
end;
|
||||
{error, _Reason} ->
|
||||
ignore
|
||||
end.
|
||||
|
||||
safely_parse_body(ContentType, Body) ->
|
||||
try parse_body(ContentType, Body) of
|
||||
Result -> Result
|
||||
try
|
||||
parse_body(ContentType, Body)
|
||||
catch
|
||||
_Class:_Reason ->
|
||||
{error, invalid_body}
|
||||
end.
|
||||
|
||||
parse_body(<<"application/json">>, Body) ->
|
||||
parse_body(<<"application/json", _/binary>>, Body) ->
|
||||
{ok, emqx_json:decode(Body, [return_maps])};
|
||||
parse_body(<<"application/x-www-form-urlencoded">>, Body) ->
|
||||
{ok, maps:from_list(cow_qs:parse_qs(Body))};
|
||||
parse_body(<<"application/x-www-form-urlencoded", _/binary>>, Body) ->
|
||||
Flags = [<<"result">>, <<"is_superuser">>],
|
||||
RawMap = maps:from_list(cow_qs:parse_qs(Body)),
|
||||
NBody = maps:with(Flags, RawMap),
|
||||
{ok, NBody};
|
||||
parse_body(ContentType, _) ->
|
||||
{error, {unsupported_content_type, ContentType}}.
|
||||
|
||||
|
@ -395,6 +391,26 @@ encode_path(Path) ->
|
|||
Parts = string:split(Path, "/", all),
|
||||
lists:flatten(["/" ++ Part || Part <- lists:map(fun uri_encode/1, Parts)]).
|
||||
|
||||
log_response(ResourceId, 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
|
||||
});
|
||||
Code4xx when Code4xx >= 400 andalso Code4xx < 500 ->
|
||||
?SLOG(warning, Output#{
|
||||
msg => "refused_by_http_server",
|
||||
code => Code4xx
|
||||
});
|
||||
OtherCode ->
|
||||
?SLOG(error, Output#{
|
||||
msg => "undesired_response_code",
|
||||
code => OtherCode
|
||||
})
|
||||
end.
|
||||
|
||||
to_list(A) when is_atom(A) ->
|
||||
atom_to_list(A);
|
||||
to_list(B) when is_binary(B) ->
|
||||
|
|
|
@ -37,6 +37,29 @@
|
|||
protocol => mqtt
|
||||
}).
|
||||
|
||||
-define(SERVER_RESPONSE_JSON(Result), ?SERVER_RESPONSE_JSON(Result, false)).
|
||||
-define(SERVER_RESPONSE_JSON(Result, IsSuperuser),
|
||||
jiffy:encode(#{
|
||||
result => Result,
|
||||
is_superuser => IsSuperuser
|
||||
})
|
||||
).
|
||||
|
||||
-define(SERVER_RESPONSE_URLENCODE(Result), ?SERVER_RESPONSE_URLENCODE(Result, false)).
|
||||
-define(SERVER_RESPONSE_URLENCODE(Result, IsSuperuser),
|
||||
list_to_binary(
|
||||
"result=" ++
|
||||
uri_encode(Result) ++ "&" ++
|
||||
"is_superuser=" ++
|
||||
uri_encode(IsSuperuser)
|
||||
)
|
||||
).
|
||||
|
||||
-define(EXCEPTION_ALLOW, ?EXCEPTION_ALLOW(false)).
|
||||
-define(EXCEPTION_ALLOW(IsSuperuser), {ok, #{is_superuser := IsSuperuser}}).
|
||||
-define(EXCEPTION_DENY, {error, not_authorized}).
|
||||
-define(EXCEPTION_IGNORE, ignore).
|
||||
|
||||
all() ->
|
||||
emqx_common_test_helpers:all(?MODULE).
|
||||
|
||||
|
@ -149,9 +172,12 @@ t_destroy(_Config) ->
|
|||
{create_authenticator, ?GLOBAL, AuthConfig}
|
||||
),
|
||||
|
||||
Headers = #{<<"content-type">> => <<"application/json">>},
|
||||
Response = ?SERVER_RESPONSE_JSON(allow),
|
||||
|
||||
ok = emqx_authn_http_test_server:set_handler(
|
||||
fun(Req0, State) ->
|
||||
Req = cowboy_req:reply(200, Req0),
|
||||
Req = cowboy_req:reply(200, Headers, Response, Req0),
|
||||
{ok, Req, State}
|
||||
end
|
||||
),
|
||||
|
@ -161,9 +187,12 @@ t_destroy(_Config) ->
|
|||
|
||||
Credentials = maps:with([username, password], ?CREDENTIALS),
|
||||
|
||||
{ok, _} = emqx_authn_http:authenticate(
|
||||
Credentials,
|
||||
State
|
||||
?assertMatch(
|
||||
?EXCEPTION_ALLOW,
|
||||
emqx_authn_http:authenticate(
|
||||
Credentials,
|
||||
State
|
||||
)
|
||||
),
|
||||
|
||||
emqx_authn_test_lib:delete_authenticators(
|
||||
|
@ -173,7 +202,7 @@ t_destroy(_Config) ->
|
|||
|
||||
% Authenticator should not be usable anymore
|
||||
?assertMatch(
|
||||
ignore,
|
||||
?EXCEPTION_IGNORE,
|
||||
emqx_authn_http:authenticate(
|
||||
Credentials,
|
||||
State
|
||||
|
@ -190,14 +219,20 @@ t_update(_Config) ->
|
|||
{create_authenticator, ?GLOBAL, IncorrectConfig}
|
||||
),
|
||||
|
||||
Headers = #{<<"content-type">> => <<"application/json">>},
|
||||
Response = ?SERVER_RESPONSE_JSON(allow),
|
||||
|
||||
ok = emqx_authn_http_test_server:set_handler(
|
||||
fun(Req0, State) ->
|
||||
Req = cowboy_req:reply(200, Req0),
|
||||
Req = cowboy_req:reply(200, Headers, Response, Req0),
|
||||
{ok, Req, State}
|
||||
end
|
||||
),
|
||||
|
||||
{error, not_authorized} = emqx_access_control:authenticate(?CREDENTIALS),
|
||||
?assertMatch(
|
||||
?EXCEPTION_DENY,
|
||||
emqx_access_control:authenticate(?CREDENTIALS)
|
||||
),
|
||||
|
||||
% We update with config with correct query, provider should update and work properly
|
||||
{ok, _} = emqx:update_config(
|
||||
|
@ -205,7 +240,10 @@ t_update(_Config) ->
|
|||
{update_authenticator, ?GLOBAL, <<"password_based:http">>, CorrectConfig}
|
||||
),
|
||||
|
||||
{ok, _} = emqx_access_control:authenticate(?CREDENTIALS).
|
||||
?assertMatch(
|
||||
?EXCEPTION_ALLOW,
|
||||
emqx_access_control:authenticate(?CREDENTIALS)
|
||||
).
|
||||
|
||||
t_is_superuser(_Config) ->
|
||||
Config = raw_http_auth_config(),
|
||||
|
@ -215,33 +253,56 @@ t_is_superuser(_Config) ->
|
|||
),
|
||||
|
||||
Checks = [
|
||||
{json, <<"0">>, false},
|
||||
{json, <<"">>, false},
|
||||
{json, null, false},
|
||||
{json, 0, false},
|
||||
%% {ContentType, ExpectedIsSuperuser, ResponseIsSuperuser}
|
||||
%% Is Superuser
|
||||
{json, true, <<"1">>},
|
||||
{json, true, 1},
|
||||
{json, true, 123},
|
||||
{json, true, <<"true">>},
|
||||
{json, true, true},
|
||||
|
||||
{json, <<"1">>, true},
|
||||
{json, <<"val">>, true},
|
||||
{json, 1, true},
|
||||
{json, 123, true},
|
||||
%% Not Superuser
|
||||
{json, false, <<"">>},
|
||||
{json, false, <<"0">>},
|
||||
{json, false, 0},
|
||||
{json, false, null},
|
||||
{json, false, undefined},
|
||||
{json, false, <<"false">>},
|
||||
{json, false, false},
|
||||
|
||||
{form, <<"0">>, false},
|
||||
{form, <<"">>, false},
|
||||
{json, false, <<"val">>},
|
||||
|
||||
{form, <<"1">>, true},
|
||||
{form, <<"val">>, true}
|
||||
%% Is Superuser
|
||||
{form, true, <<"1">>},
|
||||
{form, true, 1},
|
||||
{form, true, 123},
|
||||
{form, true, <<"true">>},
|
||||
{form, true, true},
|
||||
|
||||
%% Not Superuser
|
||||
{form, false, <<"">>},
|
||||
{form, false, <<"0">>},
|
||||
{form, false, 0},
|
||||
|
||||
{form, false, null},
|
||||
{form, false, undefined},
|
||||
{form, false, <<"false">>},
|
||||
{form, false, false},
|
||||
|
||||
{form, false, <<"val">>}
|
||||
],
|
||||
|
||||
lists:foreach(fun test_is_superuser/1, Checks).
|
||||
|
||||
test_is_superuser({Kind, Value, ExpectedValue}) ->
|
||||
test_is_superuser({Kind, ExpectedValue, ServerResponse}) ->
|
||||
{ContentType, Res} =
|
||||
case Kind of
|
||||
json ->
|
||||
{<<"application/json">>, jiffy:encode(#{is_superuser => Value})};
|
||||
{<<"application/json; charset=utf-8">>,
|
||||
?SERVER_RESPONSE_JSON(allow, ServerResponse)};
|
||||
form ->
|
||||
{<<"application/x-www-form-urlencoded">>,
|
||||
iolist_to_binary([<<"is_superuser=">>, Value])}
|
||||
{<<"application/x-www-form-urlencoded; charset=utf-8">>,
|
||||
?SERVER_RESPONSE_URLENCODE(allow, ServerResponse)}
|
||||
end,
|
||||
|
||||
ok = emqx_authn_http_test_server:set_handler(
|
||||
|
@ -257,10 +318,58 @@ test_is_superuser({Kind, Value, ExpectedValue}) ->
|
|||
),
|
||||
|
||||
?assertMatch(
|
||||
{ok, #{is_superuser := ExpectedValue}},
|
||||
?EXCEPTION_ALLOW(ExpectedValue),
|
||||
emqx_access_control:authenticate(?CREDENTIALS)
|
||||
).
|
||||
|
||||
t_ignore_allow_deny(_Config) ->
|
||||
Config = raw_http_auth_config(),
|
||||
{ok, _} = emqx:update_config(
|
||||
?PATH,
|
||||
{create_authenticator, ?GLOBAL, Config}
|
||||
),
|
||||
|
||||
Checks = [
|
||||
%% only one chain, ignore by authn http and deny by default
|
||||
{deny, ?SERVER_RESPONSE_JSON(ignore)},
|
||||
|
||||
{{allow, true}, ?SERVER_RESPONSE_JSON(allow, true)},
|
||||
{{allow, false}, ?SERVER_RESPONSE_JSON(allow)},
|
||||
{{allow, false}, ?SERVER_RESPONSE_JSON(allow, false)},
|
||||
|
||||
{deny, ?SERVER_RESPONSE_JSON(deny)},
|
||||
{deny, ?SERVER_RESPONSE_JSON(deny, true)},
|
||||
{deny, ?SERVER_RESPONSE_JSON(deny, false)}
|
||||
],
|
||||
|
||||
lists:foreach(fun test_ignore_allow_deny/1, Checks).
|
||||
|
||||
test_ignore_allow_deny({ExpectedValue, ServerResponse}) ->
|
||||
ok = emqx_authn_http_test_server:set_handler(
|
||||
fun(Req0, State) ->
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
ServerResponse,
|
||||
Req0
|
||||
),
|
||||
{ok, Req, State}
|
||||
end
|
||||
),
|
||||
|
||||
case ExpectedValue of
|
||||
{allow, IsSuperuser} ->
|
||||
?assertMatch(
|
||||
?EXCEPTION_ALLOW(IsSuperuser),
|
||||
emqx_access_control:authenticate(?CREDENTIALS)
|
||||
);
|
||||
deny ->
|
||||
?assertMatch(
|
||||
?EXCEPTION_DENY,
|
||||
emqx_access_control:authenticate(?CREDENTIALS)
|
||||
)
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Helpers
|
||||
%%------------------------------------------------------------------------------
|
||||
|
@ -287,11 +396,16 @@ samples() ->
|
|||
password := <<"plain">>
|
||||
} = cowboy_req:match_qs([username, password], Req0),
|
||||
|
||||
Req = cowboy_req:reply(200, Req0),
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
jiffy:encode(#{result => allow, is_superuser => false}),
|
||||
Req0
|
||||
),
|
||||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{},
|
||||
result => {ok, #{is_superuser => false}}
|
||||
result => {ok, #{is_superuser => false, user_property => #{}}}
|
||||
},
|
||||
|
||||
%% get request with json body response
|
||||
|
@ -300,7 +414,7 @@ samples() ->
|
|||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
jiffy:encode(#{is_superuser => true}),
|
||||
jiffy:encode(#{result => allow, is_superuser => true}),
|
||||
Req0
|
||||
),
|
||||
{ok, Req, State}
|
||||
|
@ -318,7 +432,7 @@ samples() ->
|
|||
<<"content-type">> =>
|
||||
<<"application/x-www-form-urlencoded">>
|
||||
},
|
||||
<<"is_superuser=true">>,
|
||||
<<"is_superuser=true&result=allow">>,
|
||||
Req0
|
||||
),
|
||||
{ok, Req, State}
|
||||
|
@ -342,7 +456,8 @@ samples() ->
|
|||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{},
|
||||
result => {ok, #{is_superuser => false}}
|
||||
%% only one chain, ignore by authn http and deny by default
|
||||
result => {error, not_authorized}
|
||||
},
|
||||
|
||||
%% simple post request, application/json
|
||||
|
@ -353,14 +468,19 @@ samples() ->
|
|||
<<"username">> := <<"plain">>,
|
||||
<<"password">> := <<"plain">>
|
||||
} = jiffy:decode(RawBody, [return_maps]),
|
||||
Req = cowboy_req:reply(200, Req1),
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
jiffy:encode(#{result => allow, is_superuser => false}),
|
||||
Req1
|
||||
),
|
||||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{
|
||||
<<"method">> => <<"post">>,
|
||||
<<"headers">> => #{<<"content-type">> => <<"application/json">>}
|
||||
},
|
||||
result => {ok, #{is_superuser => false}}
|
||||
result => {ok, #{is_superuser => false, user_property => #{}}}
|
||||
},
|
||||
|
||||
%% simple post request, application/x-www-form-urlencoded
|
||||
|
@ -371,7 +491,12 @@ samples() ->
|
|||
<<"username">> := <<"plain">>,
|
||||
<<"password">> := <<"plain">>
|
||||
} = maps:from_list(PostVars),
|
||||
Req = cowboy_req:reply(200, Req1),
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
jiffy:encode(#{result => allow, is_superuser => false}),
|
||||
Req1
|
||||
),
|
||||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{
|
||||
|
@ -381,15 +506,7 @@ samples() ->
|
|||
<<"application/x-www-form-urlencoded">>
|
||||
}
|
||||
},
|
||||
result => {ok, #{is_superuser => false}}
|
||||
}#{
|
||||
%% 204 code
|
||||
handler => fun(Req0, State) ->
|
||||
Req = cowboy_req:reply(204, Req0),
|
||||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{},
|
||||
result => {ok, #{is_superuser => false}}
|
||||
result => {ok, #{is_superuser => false, user_property => #{}}}
|
||||
},
|
||||
|
||||
%% simple post request for placeholders, application/json
|
||||
|
@ -402,7 +519,12 @@ samples() ->
|
|||
<<"clientid">> := <<"clienta">>,
|
||||
<<"peerhost">> := <<"127.0.0.1">>
|
||||
} = jiffy:decode(RawBody, [return_maps]),
|
||||
Req = cowboy_req:reply(200, Req1),
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
jiffy:encode(#{result => allow, is_superuser => false}),
|
||||
Req1
|
||||
),
|
||||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{
|
||||
|
@ -415,7 +537,7 @@ samples() ->
|
|||
<<"peerhost">> => ?PH_PEERHOST
|
||||
}
|
||||
},
|
||||
result => {ok, #{is_superuser => false}}
|
||||
result => {ok, #{is_superuser => false, user_property => #{}}}
|
||||
},
|
||||
|
||||
%% custom headers
|
||||
|
@ -426,6 +548,17 @@ samples() ->
|
|||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{},
|
||||
%% only one chain, ignore by authn http and deny by default
|
||||
result => {error, not_authorized}
|
||||
},
|
||||
|
||||
%% 204 code
|
||||
#{
|
||||
handler => fun(Req0, State) ->
|
||||
Req = cowboy_req:reply(204, Req0),
|
||||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{},
|
||||
result => {ok, #{is_superuser => false}}
|
||||
},
|
||||
|
||||
|
@ -436,6 +569,7 @@ samples() ->
|
|||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{},
|
||||
%% only one chain, ignore by authn http and deny by default
|
||||
result => {error, not_authorized}
|
||||
},
|
||||
|
||||
|
@ -446,6 +580,7 @@ samples() ->
|
|||
{ok, Req, State}
|
||||
end,
|
||||
config_params => #{},
|
||||
%% only one chain, ignore by authn http and deny by default
|
||||
result => {error, not_authorized}
|
||||
},
|
||||
|
||||
|
@ -456,6 +591,7 @@ samples() ->
|
|||
{ok, Req0, State}
|
||||
end,
|
||||
config_params => #{},
|
||||
%% only one chain, ignore by authn http and deny by default
|
||||
result => {error, not_authorized}
|
||||
}
|
||||
].
|
||||
|
@ -465,3 +601,15 @@ start_apps(Apps) ->
|
|||
|
||||
stop_apps(Apps) ->
|
||||
lists:foreach(fun application:stop/1, Apps).
|
||||
|
||||
uri_encode(T) ->
|
||||
emqx_http_lib:uri_encode(to_list(T)).
|
||||
|
||||
to_list(A) when is_atom(A) ->
|
||||
atom_to_list(A);
|
||||
to_list(N) when is_integer(N) ->
|
||||
integer_to_list(N);
|
||||
to_list(B) when is_binary(B) ->
|
||||
binary_to_list(B);
|
||||
to_list(L) when is_list(L) ->
|
||||
L.
|
||||
|
|
|
@ -167,6 +167,8 @@ cert_path(FileName) ->
|
|||
cowboy_handler(Req0, State) ->
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
jiffy:encode(#{result => allow, is_superuser => false}),
|
||||
Req0
|
||||
),
|
||||
{ok, Req, State}.
|
||||
|
|
|
@ -225,9 +225,10 @@ t_is_superuser(_Config) ->
|
|||
{null, false},
|
||||
{false, false},
|
||||
{0, false},
|
||||
{<<"val">>, false},
|
||||
|
||||
{<<"1">>, true},
|
||||
{<<"val">>, true},
|
||||
{<<"123">>, true},
|
||||
{1, true},
|
||||
{123, true},
|
||||
{true, true}
|
||||
|
|
|
@ -243,7 +243,7 @@ t_is_superuser(_Config) ->
|
|||
{is_superuser_str, "", false},
|
||||
{is_superuser_str, null, false},
|
||||
{is_superuser_str, "1", true},
|
||||
{is_superuser_str, "val", true},
|
||||
{is_superuser_str, "val", false},
|
||||
|
||||
{is_superuser_int, 0, false},
|
||||
{is_superuser_int, null, false},
|
||||
|
|
|
@ -1,21 +1,19 @@
|
|||
%% -*- mode: erlang -*-
|
||||
{VSN,
|
||||
[ {"0.1.0",
|
||||
[
|
||||
{add_module, emqx_conf_proto_v2},
|
||||
{load_module,emqx_conf_schema,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_conf,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_conf_app,brutal_purge,soft_purge,[]}
|
||||
]},
|
||||
{<<".*">>, []}
|
||||
[{"0.1.0",
|
||||
[{add_module, emqx_conf_proto_v2},
|
||||
{load_module,emqx_conf_schema,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_conf,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_conf_app,brutal_purge,soft_purge,[]}
|
||||
]},
|
||||
{<<".*">>, []}
|
||||
],
|
||||
[ {"0.1.0",
|
||||
[
|
||||
{delete_module, emqx_conf_proto_v2},
|
||||
{load_module,emqx_conf_schema,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_conf,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_conf_app,brutal_purge,soft_purge,[]}
|
||||
]},
|
||||
{<<".*">>, []}
|
||||
[{"0.1.0",
|
||||
[{delete_module, emqx_conf_proto_v2},
|
||||
{load_module,emqx_conf_schema,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_conf,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_conf_app,brutal_purge,soft_purge,[]}
|
||||
]},
|
||||
{<<".*">>, []}
|
||||
]
|
||||
}.
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
%% -*- mode: erlang -*-
|
||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||
{VSN,
|
||||
[{"5.0.0", [
|
||||
{load_module,emqx_dashboard_api,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_dashboard_token,brutal_purge,soft_purge,[]}
|
||||
]},
|
||||
[{"5.0.0",
|
||||
[{load_module,emqx_dashboard,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_dashboard_api,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_dashboard_token,brutal_purge,soft_purge,[]}]},
|
||||
{<<".*">>,[]}],
|
||||
[{"5.0.0", [
|
||||
{load_module,emqx_dashboard_api,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_dashboard_token,brutal_purge,soft_purge,[]}
|
||||
]},
|
||||
[{"5.0.0",
|
||||
[{load_module,emqx_dashboard,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_dashboard_api,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_dashboard_token,brutal_purge,soft_purge,[]}]},
|
||||
{<<".*">>,[]}]}.
|
||||
|
|
|
@ -141,12 +141,14 @@ on_start_auth(authn_http) ->
|
|||
%% set handler for test server
|
||||
Handler = fun(Req0, State) ->
|
||||
ct:pal("Authn Req:~p~nState:~p~n", [Req0, State]),
|
||||
Headers = #{<<"content-type">> => <<"application/json">>},
|
||||
Response = jiffy:encode(#{result => allow, is_superuser => false}),
|
||||
case cowboy_req:match_qs([username, password], Req0) of
|
||||
#{
|
||||
username := <<"admin">>,
|
||||
password := <<"public">>
|
||||
} ->
|
||||
Req = cowboy_req:reply(200, Req0);
|
||||
Req = cowboy_req:reply(200, Headers, Response, Req0);
|
||||
_ ->
|
||||
Req = cowboy_req:reply(400, Req0)
|
||||
end,
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
%% -*- mode: erlang -*-
|
||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||
{VSN,
|
||||
[{"5.0.0",[
|
||||
{load_module,emqx_mgmt_cli,brutal_purge,soft_purge,[]},
|
||||
{add_module,emqx_management_proto_v2},
|
||||
{load_module,emqx_mgmt_api_clients,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_publish,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_listeners,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_configs,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_util,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt,brutal_purge,soft_purge,[]}
|
||||
]},
|
||||
[{"5.0.0",
|
||||
[{load_module,emqx_mgmt_api_nodes,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_cli,brutal_purge,soft_purge,[]},
|
||||
{add_module,emqx_management_proto_v2},
|
||||
{load_module,emqx_mgmt_api_clients,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_publish,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_listeners,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_configs,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_util,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt,brutal_purge,soft_purge,[]}]},
|
||||
{<<".*">>,[]}],
|
||||
[{"5.0.0",[
|
||||
{load_module,emqx_mgmt_cli,brutal_purge,soft_purge,[]},
|
||||
{delete_module,emqx_management_proto_v2},
|
||||
{load_module,emqx_mgmt_api_clients,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_publish,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_listeners,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_configs,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_util,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt,brutal_purge,soft_purge,[]}
|
||||
]},
|
||||
[{"5.0.0",
|
||||
[{load_module,emqx_mgmt_api_nodes,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_cli,brutal_purge,soft_purge,[]},
|
||||
{delete_module,emqx_management_proto_v2},
|
||||
{load_module,emqx_mgmt_api_clients,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_publish,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_listeners,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_api_configs,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt_util,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_mgmt,brutal_purge,soft_purge,[]}]},
|
||||
{<<".*">>,[]}]}.
|
||||
|
|
Loading…
Reference in New Issue