emqx/apps/emqx_auth_mysql/src/emqx_auth_mysql.erl

92 lines
3.5 KiB
Erlang

%%--------------------------------------------------------------------
%% Copyright (c) 2020-2021 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_auth_mysql).
-include("emqx_auth_mysql.hrl").
-include_lib("emqx/include/emqx.hrl").
-include_lib("emqx/include/logger.hrl").
-include_lib("emqx/include/types.hrl").
-export([ register_metrics/0
, check/3
, description/0
]).
-define(EMPTY(Username), (Username =:= undefined orelse Username =:= <<>>)).
-spec(register_metrics() -> ok).
register_metrics() ->
lists:foreach(fun emqx_metrics:ensure/1, ?AUTH_METRICS).
check(ClientInfo = #{password := Password}, AuthResult,
#{auth_query := {AuthSql, AuthParams},
super_query := SuperQuery,
hash_type := HashType,
pool := Pool}) ->
CheckPass = case emqx_auth_mysql_cli:query(Pool, AuthSql, AuthParams, ClientInfo) of
{ok, [<<"password">>], [[PassHash]]} ->
check_pass({PassHash, Password}, HashType);
{ok, [<<"password">>, <<"salt">>], [[PassHash, Salt]]} ->
check_pass({PassHash, Salt, Password}, HashType);
{ok, _Columns, []} ->
{error, not_found};
{error, Reason} ->
?LOG(error, "[MySQL] query '~p' failed: ~p", [AuthSql, Reason]),
{error, Reason}
end,
case CheckPass of
ok ->
emqx_metrics:inc(?AUTH_METRICS(success)),
{stop, AuthResult#{is_superuser => is_superuser(Pool, SuperQuery, ClientInfo),
anonymous => false,
auth_result => success}};
{error, not_found} ->
emqx_metrics:inc(?AUTH_METRICS(ignore)), ok;
{error, ResultCode} ->
?LOG(error, "[MySQL] Auth from mysql failed: ~p", [ResultCode]),
emqx_metrics:inc(?AUTH_METRICS(failure)),
{stop, AuthResult#{auth_result => ResultCode, anonymous => false}}
end.
%%--------------------------------------------------------------------
%% Is Superuser?
%%--------------------------------------------------------------------
-spec(is_superuser(atom(), maybe({string(), list()}), emqx_types:client()) -> boolean()).
is_superuser(_Pool, undefined, _ClientInfo) -> false;
is_superuser(Pool, {SuperSql, Params}, ClientInfo) ->
case emqx_auth_mysql_cli:query(Pool, SuperSql, Params, ClientInfo) of
{ok, [_Super], [[1]]} ->
true;
{ok, [_Super], [[_False]]} ->
false;
{ok, [_Super], []} ->
false;
{error, _Error} ->
false
end.
check_pass(Password, HashType) ->
case emqx_passwd:check_pass(Password, HashType) of
ok -> ok;
{error, _Reason} -> {error, not_authorized}
end.
description() -> "Authentication with MySQL".