Merge pull request #8351 from HJianBo/compatible-password-field
Authn: backword compatibility for 4.x authn data
This commit is contained in:
commit
094ed05897
|
@ -204,6 +204,9 @@ jobs:
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: make coveralls
|
run: make coveralls
|
||||||
|
- name: get coveralls logs
|
||||||
|
if: failure()
|
||||||
|
run: cat rebar3.crashdump
|
||||||
|
|
||||||
# do this in a separate job
|
# do this in a separate job
|
||||||
upload_coverdata:
|
upload_coverdata:
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||||
{VSN,
|
{VSN,
|
||||||
[{"0.1.0",[{load_module,emqx_authn_utils,brutal_purge,soft_purge,[]}]}],
|
[{"0.1.0",[
|
||||||
[{"0.1.0",[{load_module,emqx_authn_utils,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_utils,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_authn_redis,brutal_purge,soft_purge,[]}]
|
||||||
|
}]}.
|
||||||
|
|
|
@ -72,13 +72,25 @@ start_resource_if_enabled(Result, _ResourceId, _Config) ->
|
||||||
|
|
||||||
check_password_from_selected_map(_Algorithm, _Selected, undefined) ->
|
check_password_from_selected_map(_Algorithm, _Selected, undefined) ->
|
||||||
{error, bad_username_or_password};
|
{error, bad_username_or_password};
|
||||||
check_password_from_selected_map(
|
check_password_from_selected_map(Algorithm, Selected, Password) ->
|
||||||
Algorithm, #{<<"password_hash">> := Hash} = Selected, Password
|
Hash = maps:get(
|
||||||
) ->
|
<<"password_hash">>,
|
||||||
Salt = maps:get(<<"salt">>, Selected, <<>>),
|
Selected,
|
||||||
case emqx_authn_password_hashing:check_password(Algorithm, Salt, Hash, Password) of
|
maps:get(<<"password">>, Selected, undefined)
|
||||||
true -> ok;
|
),
|
||||||
false -> {error, bad_username_or_password}
|
case Hash of
|
||||||
|
undefined ->
|
||||||
|
{error, not_authorized};
|
||||||
|
_ ->
|
||||||
|
Salt = maps:get(<<"salt">>, Selected, <<>>),
|
||||||
|
case
|
||||||
|
emqx_authn_password_hashing:check_password(
|
||||||
|
Algorithm, Salt, Hash, Password
|
||||||
|
)
|
||||||
|
of
|
||||||
|
true -> ok;
|
||||||
|
false -> {error, bad_username_or_password}
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
parse_deep(Template) ->
|
parse_deep(Template) ->
|
||||||
|
@ -160,10 +172,14 @@ make_resource_id(Name) ->
|
||||||
|
|
||||||
handle_var({var, Name}, undefined) ->
|
handle_var({var, Name}, undefined) ->
|
||||||
error({cannot_get_variable, Name});
|
error({cannot_get_variable, Name});
|
||||||
|
handle_var({var, <<"peerhost">>}, PeerHost) ->
|
||||||
|
emqx_placeholder:bin(inet:ntoa(PeerHost));
|
||||||
handle_var(_, Value) ->
|
handle_var(_, Value) ->
|
||||||
emqx_placeholder:bin(Value).
|
emqx_placeholder:bin(Value).
|
||||||
|
|
||||||
handle_sql_var({var, Name}, undefined) ->
|
handle_sql_var({var, Name}, undefined) ->
|
||||||
error({cannot_get_variable, Name});
|
error({cannot_get_variable, Name});
|
||||||
|
handle_sql_var({var, <<"peerhost">>}, PeerHost) ->
|
||||||
|
emqx_placeholder:bin(inet:ntoa(PeerHost));
|
||||||
handle_sql_var(_, Value) ->
|
handle_sql_var(_, Value) ->
|
||||||
emqx_placeholder:sql_data(Value).
|
emqx_placeholder:sql_data(Value).
|
||||||
|
|
|
@ -138,27 +138,16 @@ authenticate(
|
||||||
{ok, []} ->
|
{ok, []} ->
|
||||||
ignore;
|
ignore;
|
||||||
{ok, Values} ->
|
{ok, Values} ->
|
||||||
case merge(Fields, Values) of
|
Selected = merge(Fields, Values),
|
||||||
#{<<"password_hash">> := _} = Selected ->
|
case
|
||||||
case
|
emqx_authn_utils:check_password_from_selected_map(
|
||||||
emqx_authn_utils:check_password_from_selected_map(
|
Algorithm, Selected, Password
|
||||||
Algorithm, Selected, Password
|
)
|
||||||
)
|
of
|
||||||
of
|
ok ->
|
||||||
ok ->
|
{ok, emqx_authn_utils:is_superuser(Selected)};
|
||||||
{ok, emqx_authn_utils:is_superuser(Selected)};
|
{error, Reason} ->
|
||||||
{error, Reason} ->
|
{error, Reason}
|
||||||
{error, Reason}
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
?SLOG(error, #{
|
|
||||||
msg => "cannot_find_password_hash_field",
|
|
||||||
cmd => Command,
|
|
||||||
keys => NKey,
|
|
||||||
fields => Fields,
|
|
||||||
resource => ResourceId
|
|
||||||
}),
|
|
||||||
ignore
|
|
||||||
end;
|
end;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?SLOG(error, #{
|
?SLOG(error, #{
|
||||||
|
@ -210,8 +199,8 @@ parse_cmd(Cmd) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
check_fields(Fields) ->
|
check_fields(Fields) ->
|
||||||
HasPassHash = lists:member("password_hash", Fields),
|
HasPassHash = lists:member("password_hash", Fields) orelse lists:member("password", Fields),
|
||||||
KnownFields = ["password_hash", "salt", "is_superuser"],
|
KnownFields = ["password_hash", "password", "salt", "is_superuser"],
|
||||||
UnknownFields = [F || F <- Fields, not lists:member(F, KnownFields)],
|
UnknownFields = [F || F <- Fields, not lists:member(F, KnownFields)],
|
||||||
|
|
||||||
case {HasPassHash, UnknownFields} of
|
case {HasPassHash, UnknownFields} of
|
||||||
|
|
|
@ -29,8 +29,10 @@
|
||||||
-define(HTTP_PORT, 32333).
|
-define(HTTP_PORT, 32333).
|
||||||
-define(HTTP_PATH, "/auth").
|
-define(HTTP_PATH, "/auth").
|
||||||
-define(CREDENTIALS, #{
|
-define(CREDENTIALS, #{
|
||||||
|
clientid => <<"clienta">>,
|
||||||
username => <<"plain">>,
|
username => <<"plain">>,
|
||||||
password => <<"plain">>,
|
password => <<"plain">>,
|
||||||
|
peerhost => {127, 0, 0, 1},
|
||||||
listener => 'tcp:default',
|
listener => 'tcp:default',
|
||||||
protocol => mqtt
|
protocol => mqtt
|
||||||
}).
|
}).
|
||||||
|
@ -390,6 +392,32 @@ samples() ->
|
||||||
result => {ok, #{is_superuser => false}}
|
result => {ok, #{is_superuser => false}}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
%% simple post request for placeholders, application/json
|
||||||
|
#{
|
||||||
|
handler => fun(Req0, State) ->
|
||||||
|
{ok, RawBody, Req1} = cowboy_req:read_body(Req0),
|
||||||
|
#{
|
||||||
|
<<"username">> := <<"plain">>,
|
||||||
|
<<"password">> := <<"plain">>,
|
||||||
|
<<"clientid">> := <<"clienta">>,
|
||||||
|
<<"peerhost">> := <<"127.0.0.1">>
|
||||||
|
} = jiffy:decode(RawBody, [return_maps]),
|
||||||
|
Req = cowboy_req:reply(200, Req1),
|
||||||
|
{ok, Req, State}
|
||||||
|
end,
|
||||||
|
config_params => #{
|
||||||
|
<<"method">> => <<"post">>,
|
||||||
|
<<"headers">> => #{<<"content-type">> => <<"application/json">>},
|
||||||
|
<<"body">> => #{
|
||||||
|
<<"clientid">> => ?PH_CLIENTID,
|
||||||
|
<<"username">> => ?PH_USERNAME,
|
||||||
|
<<"password">> => ?PH_PASSWORD,
|
||||||
|
<<"peerhost">> => ?PH_PEERHOST
|
||||||
|
}
|
||||||
|
},
|
||||||
|
result => {ok, #{is_superuser => false}}
|
||||||
|
},
|
||||||
|
|
||||||
%% custom headers
|
%% custom headers
|
||||||
#{
|
#{
|
||||||
handler => fun(Req0, State) ->
|
handler => fun(Req0, State) ->
|
||||||
|
|
|
@ -453,6 +453,28 @@ user_seeds() ->
|
||||||
<<"password_hash_algorithm">> => #{<<"name">> => <<"bcrypt">>}
|
<<"password_hash_algorithm">> => #{<<"name">> => <<"bcrypt">>}
|
||||||
},
|
},
|
||||||
result => {error, bad_username_or_password}
|
result => {error, bad_username_or_password}
|
||||||
|
},
|
||||||
|
|
||||||
|
#{
|
||||||
|
data => #{
|
||||||
|
password =>
|
||||||
|
<<"a3c7f6b085c3e5897ffb9b86f18a9d905063f8550a74444b5892e193c1b50428">>,
|
||||||
|
is_superuser => <<"1">>
|
||||||
|
},
|
||||||
|
credentials => #{
|
||||||
|
clientid => <<"sha256_no_salt">>,
|
||||||
|
password => <<"sha256_no_salt">>
|
||||||
|
},
|
||||||
|
key => <<"mqtt_user:sha256_no_salt">>,
|
||||||
|
config_params => #{
|
||||||
|
%% Needs to be compatible with emqx 4.x auth data
|
||||||
|
<<"cmd">> => <<"HMGET mqtt_user:${clientid} password is_superuser">>,
|
||||||
|
<<"password_hash_algorithm">> => #{
|
||||||
|
<<"name">> => <<"sha256">>,
|
||||||
|
<<"salt_position">> => <<"disable">>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
result => {ok, #{is_superuser => true}}
|
||||||
}
|
}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue