diff --git a/apps/emqx/src/emqx_channel.erl b/apps/emqx/src/emqx_channel.erl index 5ca26ba4e..871de163e 100644 --- a/apps/emqx/src/emqx_channel.erl +++ b/apps/emqx/src/emqx_channel.erl @@ -260,7 +260,7 @@ init( is_bridge => false, is_superuser => false, enable_authn => maps:get(enable_authn, Opts, true), - attrs => #{} + client_attrs => #{} }, Zone ), @@ -1730,15 +1730,16 @@ do_authenticate(Credential, #channel{clientinfo = ClientInfo} = Channel) -> %% Authentication result may include: %% 1. `is_superuser': The superuser flag from various backends %% 2. `acl': ACL rules from JWT, HTTP auth backend -%% 3. `attrs': Extra client attributes from JWT, HTTP auth backend +%% 3. `client_attrs': Extra client attributes from JWT, HTTP auth backend +%% 4. Maybe more non-standard fileds used by hook callbacks merge_auth_result(ClientInfo, AuthResult0) when is_map(ClientInfo) andalso is_map(AuthResult0) -> - IsSuperuser = maps:get(is_superuser, AuthResult, false), - AuthResult = maps:without([attrs], AuthResult0), - Attrs0 = maps:get(attrs, ClientInfo, #{}), - Attrs1 = maps:get(attrs, AuthResult0, #{}), + IsSuperuser = maps:get(is_superuser, AuthResult0, false), + AuthResult = maps:without([client_attrs], AuthResult0), + Attrs0 = maps:get(client_attrs, ClientInfo, #{}), + Attrs1 = maps:get(client_attrs, AuthResult0, #{}), Attrs = maps:merge(Attrs0, Attrs1), maps:merge( - ClientInfo#{attrs => Attrs}, + ClientInfo#{client_attrs => Attrs}, AuthResult#{is_superuser => IsSuperuser} ). diff --git a/apps/emqx/src/emqx_types.erl b/apps/emqx/src/emqx_types.erl index 3883991b4..3361798cf 100644 --- a/apps/emqx/src/emqx_types.erl +++ b/apps/emqx/src/emqx_types.erl @@ -191,7 +191,7 @@ cn => binary(), dn => binary(), %% extra attributes - attrs => client_attrs(), + client_attrs => client_attrs(), atom() => term() }. -type client_attrs() :: #{binary() => binary()}. diff --git a/apps/emqx_auth/src/emqx_authn/emqx_authn_utils.erl b/apps/emqx_auth/src/emqx_authn/emqx_authn_utils.erl index bf17ca950..80da32b0b 100644 --- a/apps/emqx_auth/src/emqx_authn/emqx_authn_utils.erl +++ b/apps/emqx_auth/src/emqx_authn/emqx_authn_utils.erl @@ -32,6 +32,7 @@ render_urlencoded_str/2, render_sql_params/2, is_superuser/1, + client_attrs/1, bin/1, ensure_apps_started/1, cleanup_resources/0, @@ -204,6 +205,11 @@ is_superuser(#{<<"is_superuser">> := Value}) -> is_superuser(#{}) -> #{is_superuser => false}. +client_attrs(#{<<"client_attrs">> := Attrs}) -> + #{client_attrs => Attrs}; +client_attrs(_) -> + #{client_attrs => #{}}. + ensure_apps_started(bcrypt) -> {ok, _} = application:ensure_all_started(bcrypt), ok; diff --git a/apps/emqx_auth_http/src/emqx_authn_http.erl b/apps/emqx_auth_http/src/emqx_authn_http.erl index 4efa69042..5cbffb394 100644 --- a/apps/emqx_auth_http/src/emqx_authn_http.erl +++ b/apps/emqx_auth_http/src/emqx_authn_http.erl @@ -198,7 +198,7 @@ handle_response(Headers, Body) -> case maps:get(<<"result">>, NBody, <<"ignore">>) of <<"allow">> -> IsSuperuser = emqx_authn_utils:is_superuser(NBody), - Attrs = maps:get(<<"attrs">>, NBody, #{}), + Attrs = emqx_authn_utils:client_attrs(NBody), Result = maps:merge(IsSuperuser, Attrs), {ok, Result}; <<"deny">> -> diff --git a/apps/emqx_auth_http/test/emqx_authn_http_SUITE.erl b/apps/emqx_auth_http/test/emqx_authn_http_SUITE.erl index 12211bab8..576a22203 100644 --- a/apps/emqx_auth_http/test/emqx_authn_http_SUITE.erl +++ b/apps/emqx_auth_http/test/emqx_authn_http_SUITE.erl @@ -533,7 +533,7 @@ samples() -> {ok, Req, State} end, config_params => #{}, - result => {ok, #{is_superuser => false, attrs => #{}}} + result => {ok, #{is_superuser => false, client_attrs => #{}}} }, %% get request with json body response @@ -548,7 +548,7 @@ samples() -> {ok, Req, State} end, config_params => #{}, - result => {ok, #{is_superuser => true, attrs => #{}}} + result => {ok, #{is_superuser => true, client_attrs => #{}}} }, %% get request with url-form-encoded body response @@ -566,7 +566,7 @@ samples() -> {ok, Req, State} end, config_params => #{}, - result => {ok, #{is_superuser => true, attrs => #{}}} + result => {ok, #{is_superuser => true, client_attrs => #{}}} }, %% get request with response of unknown encoding @@ -608,7 +608,7 @@ samples() -> <<"method">> => <<"post">>, <<"headers">> => #{<<"content-type">> => <<"application/json">>} }, - result => {ok, #{is_superuser => false, attrs => #{}}} + result => {ok, #{is_superuser => false, client_attrs => #{}}} }, %% simple post request, application/x-www-form-urlencoded @@ -634,7 +634,7 @@ samples() -> <<"application/x-www-form-urlencoded">> } }, - result => {ok, #{is_superuser => false, attrs => #{}}} + result => {ok, #{is_superuser => false, client_attrs => #{}}} }, %% simple post request for placeholders, application/json @@ -669,7 +669,7 @@ samples() -> <<"cert_common_name">> => ?PH_CERT_CN_NAME } }, - result => {ok, #{is_superuser => false, attrs => #{}}} + result => {ok, #{is_superuser => false, client_attrs => #{}}} }, %% custom headers diff --git a/apps/emqx_auth_jwt/src/emqx_authn_jwt.erl b/apps/emqx_auth_jwt/src/emqx_authn_jwt.erl index 45fd1d60a..2a12f5acf 100644 --- a/apps/emqx_auth_jwt/src/emqx_authn_jwt.erl +++ b/apps/emqx_auth_jwt/src/emqx_authn_jwt.erl @@ -219,10 +219,11 @@ verify(undefined, _, _, _) -> verify(JWT, JWKs, VerifyClaims, AclClaimName) -> case do_verify(JWT, JWKs, VerifyClaims) of {ok, Extra} -> + IsSuperuser = emqx_authn_utils:is_superuser(Extra), + Attrs = emqx_authn_utils:client_attrs(Extra), try ACL = acl(Extra, AclClaimName), - Attrs = maps:get(<<"attrs">>, Extra, #{}), - Result = maps:merge(Attrs, ACL), + Result = maps:merge(IsSuperuser, maps:merge(ACL, Attrs)), {ok, Result} catch throw:{bad_acl_rule, Reason} -> @@ -245,20 +246,18 @@ verify(JWT, JWKs, VerifyClaims, AclClaimName) -> end. acl(Claims, AclClaimName) -> - Acl = - case Claims of - #{AclClaimName := Rules} -> - #{ - acl => #{ - rules => parse_rules(Rules), - source_for_logging => jwt, - expire => maps:get(<<"exp">>, Claims, undefined) - } - }; - _ -> - #{} - end, - maps:merge(emqx_authn_utils:is_superuser(Claims), Acl). + case Claims of + #{AclClaimName := Rules} -> + #{ + acl => #{ + rules => parse_rules(Rules), + source_for_logging => jwt, + expire => maps:get(<<"exp">>, Claims, undefined) + } + }; + _ -> + #{} + end. do_verify(_JWT, [], _VerifyClaims) -> {error, invalid_signature};