Skip to content

Commit 67bc950

Browse files
Merge pull request #12617 from rabbitmq/amqp-log-macro
Use log macros for AMQP
2 parents df0b767 + dbd9ede commit 67bc950

File tree

8 files changed

+440
-84
lines changed

8 files changed

+440
-84
lines changed

deps/rabbit/src/rabbit_access_control.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ check_user_id0(ClaimedUserName, #user{username = ActualUserName,
249249
end.
250250

251251
-spec update_state(User :: rabbit_types:user(), NewState :: term()) ->
252-
{'ok', rabbit_types:auth_user()} |
252+
{'ok', rabbit_types:user()} |
253253
{'refused', string()} |
254254
{'error', any()}.
255255

deps/rabbit/src/rabbit_amqp_management.erl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,19 @@ handle_http_req(<<"GET">>,
381381
Bindings0 = rabbit_binding:list_for_source_and_destination(SrcXName, DstName),
382382
Bindings = [B || B = #binding{key = K} <- Bindings0, K =:= Key],
383383
RespPayload = encode_bindings(Bindings),
384-
{<<"200">>, RespPayload, PermCaches}.
384+
{<<"200">>, RespPayload, PermCaches};
385+
386+
handle_http_req(<<"PUT">>,
387+
[<<"auth">>, <<"tokens">>],
388+
_Query,
389+
ReqPayload,
390+
_Vhost,
391+
_User,
392+
ConnPid,
393+
PermCaches) ->
394+
{binary, Token} = ReqPayload,
395+
ok = rabbit_amqp_reader:set_credential(ConnPid, Token),
396+
{<<"204">>, null, PermCaches}.
385397

386398
decode_queue({map, KVList}) ->
387399
M = lists:foldl(

deps/rabbit/src/rabbit_amqp_reader.erl

Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77

88
-module(rabbit_amqp_reader).
99

10+
-include_lib("kernel/include/logger.hrl").
1011
-include_lib("rabbit_common/include/rabbit.hrl").
1112
-include_lib("amqp10_common/include/amqp10_types.hrl").
1213
-include("rabbit_amqp.hrl").
1314

1415
-export([init/1,
1516
info/2,
16-
mainloop/2]).
17+
mainloop/2,
18+
set_credential/2]).
1719

1820
-export([system_continue/3,
1921
system_terminate/4,
@@ -53,6 +55,7 @@
5355
channel_max :: non_neg_integer(),
5456
auth_mechanism :: sasl_init_unprocessed | {binary(), module()},
5557
auth_state :: term(),
58+
credential_timer :: undefined | reference(),
5659
properties :: undefined | {map, list(tuple())}
5760
}).
5861

@@ -139,6 +142,11 @@ server_properties() ->
139142
Props = [{{symbol, <<"node">>}, {utf8, atom_to_binary(node())}} | Props1],
140143
{map, Props}.
141144

145+
-spec set_credential(pid(), binary()) -> ok.
146+
set_credential(Pid, Credential) ->
147+
Pid ! {set_credential, Credential},
148+
ok.
149+
142150
%%--------------------------------------------------------------------------
143151

144152
inet_op(F) -> rabbit_misc:throw_on_error(inet_error, F).
@@ -243,6 +251,8 @@ handle_other({'$gen_cast', {force_event_refresh, _Ref}}, State) ->
243251
State;
244252
handle_other(terminate_connection, _State) ->
245253
stop;
254+
handle_other({set_credential, Cred}, State) ->
255+
set_credential0(Cred, State);
246256
handle_other(credential_expired, State) ->
247257
Error = error_frame(?V_1_0_AMQP_ERROR_UNAUTHORIZED_ACCESS, "credential expired", []),
248258
handle_exception(State, 0, Error);
@@ -320,16 +330,14 @@ error_frame(Condition, Fmt, Args) ->
320330

321331
handle_exception(State = #v1{connection_state = closed}, Channel,
322332
#'v1_0.error'{description = {utf8, Desc}}) ->
323-
rabbit_log_connection:error(
324-
"Error on AMQP 1.0 connection ~tp (~tp), channel number ~b:~n~tp",
325-
[self(), closed, Channel, Desc]),
333+
?LOG_ERROR("Error on AMQP 1.0 connection ~tp (~tp), channel number ~b:~n~tp",
334+
[self(), closed, Channel, Desc]),
326335
State;
327336
handle_exception(State = #v1{connection_state = CS}, Channel,
328337
Error = #'v1_0.error'{description = {utf8, Desc}})
329338
when ?IS_RUNNING(State) orelse CS =:= closing ->
330-
rabbit_log_connection:error(
331-
"Error on AMQP 1.0 connection ~tp (~tp), channel number ~b:~n~tp",
332-
[self(), CS, Channel, Desc]),
339+
?LOG_ERROR("Error on AMQP 1.0 connection ~tp (~tp), channel number ~b:~n~tp",
340+
[self(), CS, Channel, Desc]),
333341
close(Error, State);
334342
handle_exception(State, _Channel, Error) ->
335343
silent_close_delay(),
@@ -416,21 +424,23 @@ handle_connection_frame(
416424
},
417425
helper_sup = HelperSupPid,
418426
sock = Sock} = State0) ->
419-
logger:update_process_metadata(#{amqp_container => ContainerId}),
420427
Vhost = vhost(Hostname),
428+
logger:update_process_metadata(#{amqp_container => ContainerId,
429+
vhost => Vhost,
430+
user => Username}),
421431
ok = check_user_loopback(State0),
422432
ok = check_vhost_exists(Vhost, State0),
423433
ok = check_vhost_alive(Vhost),
424434
ok = rabbit_access_control:check_vhost_access(User, Vhost, {socket, Sock}, #{}),
425435
ok = check_vhost_connection_limit(Vhost, Username),
426436
ok = check_user_connection_limit(Username),
427-
ok = ensure_credential_expiry_timer(User),
437+
Timer = maybe_start_credential_expiry_timer(User),
428438
rabbit_core_metrics:auth_attempt_succeeded(<<>>, Username, amqp10),
429439
notify_auth(user_authentication_success, Username, State0),
430-
rabbit_log_connection:info(
431-
"Connection from AMQP 1.0 container '~ts': user '~ts' authenticated "
432-
"using SASL mechanism ~s and granted access to vhost '~ts'",
433-
[ContainerId, Username, Mechanism, Vhost]),
440+
?LOG_INFO(
441+
"Connection from AMQP 1.0 container '~ts': user '~ts' authenticated "
442+
"using SASL mechanism ~s and granted access to vhost '~ts'",
443+
[ContainerId, Username, Mechanism, Vhost]),
434444

435445
OutgoingMaxFrameSize = case ClientMaxFrame of
436446
undefined ->
@@ -499,17 +509,18 @@ handle_connection_frame(
499509
outgoing_max_frame_size = OutgoingMaxFrameSize,
500510
channel_max = EffectiveChannelMax,
501511
properties = Properties,
502-
timeout = ReceiveTimeoutMillis},
512+
timeout = ReceiveTimeoutMillis,
513+
credential_timer = Timer},
503514
heartbeater = Heartbeater},
504515
State = start_writer(State1),
505516
HostnameVal = case Hostname of
506517
undefined -> undefined;
507518
null -> undefined;
508519
{utf8, Val} -> Val
509520
end,
510-
rabbit_log:debug(
511-
"AMQP 1.0 connection.open frame: hostname = ~ts, extracted vhost = ~ts, idle-time-out = ~p",
512-
[HostnameVal, Vhost, IdleTimeout]),
521+
?LOG_DEBUG(
522+
"AMQP 1.0 connection.open frame: hostname = ~ts, extracted vhost = ~ts, idle-time-out = ~p",
523+
[HostnameVal, Vhost, IdleTimeout]),
513524

514525
Infos = infos(?CONNECTION_EVENT_KEYS, State),
515526
ok = rabbit_core_metrics:connection_created(
@@ -768,16 +779,16 @@ notify_auth(EventType, Username, State) ->
768779
rabbit_event:notify(EventType, EventProps).
769780

770781
track_channel(ChannelNum, SessionPid, #v1{tracked_channels = Channels} = State) ->
771-
rabbit_log:debug("AMQP 1.0 created session process ~p for channel number ~b",
772-
[SessionPid, ChannelNum]),
782+
?LOG_DEBUG("AMQP 1.0 created session process ~p for channel number ~b",
783+
[SessionPid, ChannelNum]),
773784
_Ref = erlang:monitor(process, SessionPid, [{tag, {'DOWN', ChannelNum}}]),
774785
State#v1{tracked_channels = maps:put(ChannelNum, SessionPid, Channels)}.
775786

776787
untrack_channel(ChannelNum, SessionPid, #v1{tracked_channels = Channels0} = State) ->
777788
case maps:take(ChannelNum, Channels0) of
778789
{SessionPid, Channels} ->
779-
rabbit_log:debug("AMQP 1.0 closed session process ~p with channel number ~b",
780-
[SessionPid, ChannelNum]),
790+
?LOG_DEBUG("AMQP 1.0 closed session process ~p with channel number ~b",
791+
[SessionPid, ChannelNum]),
781792
State#v1{tracked_channels = Channels};
782793
_ ->
783794
State
@@ -871,39 +882,57 @@ check_user_connection_limit(Username) ->
871882
end.
872883

873884

874-
%% TODO Provide a means for the client to refresh the credential.
875-
%% This could be either via:
876-
%% 1. SASL (if multiple authentications are allowed on the same AMQP 1.0 connection), see
877-
%% https://datatracker.ietf.org/doc/html/rfc4422#section-3.8 , or
878-
%% 2. Claims Based Security (CBS) extension, see https://docs.oasis-open.org/amqp/amqp-cbs/v1.0/csd01/amqp-cbs-v1.0-csd01.html
879-
%% and https://github.com/rabbitmq/rabbitmq-server/issues/9259
880-
%% 3. Simpler variation of 2. where a token is put to a special /token node.
881-
%%
882-
%% If the user does not refresh their credential on time (the only implementation currently),
883-
%% close the entire connection as we must assume that vhost access could have been revoked.
884-
%%
885-
%% If the user refreshes their credential on time (to be implemented), the AMQP reader should
886-
%% 1. rabbit_access_control:check_vhost_access/4
887-
%% 2. send a message to all its sessions which should then erase the permission caches and
888-
%% re-check all link permissions (i.e. whether reading / writing to exchanges / queues is still allowed).
889-
%% 3. cancel the current timer, and set a new timer
890-
%% similary as done for Stream connections, see https://github.com/rabbitmq/rabbitmq-server/issues/10292
891-
ensure_credential_expiry_timer(User) ->
885+
set_credential0(Cred,
886+
State = #v1{connection = #v1_connection{
887+
user = User0,
888+
vhost = Vhost,
889+
credential_timer = OldTimer} = Conn,
890+
tracked_channels = Chans,
891+
sock = Sock}) ->
892+
?LOG_INFO("updating credential", []),
893+
case rabbit_access_control:update_state(User0, Cred) of
894+
{ok, User} ->
895+
try rabbit_access_control:check_vhost_access(User, Vhost, {socket, Sock}, #{}) of
896+
ok ->
897+
maps:foreach(fun(_ChanNum, Pid) ->
898+
rabbit_amqp_session:reset_authz(Pid, User)
899+
end, Chans),
900+
case OldTimer of
901+
undefined -> ok;
902+
Ref -> ok = erlang:cancel_timer(Ref, [{info, false}])
903+
end,
904+
NewTimer = maybe_start_credential_expiry_timer(User),
905+
State#v1{connection = Conn#v1_connection{
906+
user = User,
907+
credential_timer = NewTimer}}
908+
catch _:Reason ->
909+
Error = error_frame(?V_1_0_AMQP_ERROR_UNAUTHORIZED_ACCESS,
910+
"access to vhost ~s failed for new credential: ~p",
911+
[Vhost, Reason]),
912+
handle_exception(State, 0, Error)
913+
end;
914+
Err ->
915+
Error = error_frame(?V_1_0_AMQP_ERROR_UNAUTHORIZED_ACCESS,
916+
"credential update failed: ~p",
917+
[Err]),
918+
handle_exception(State, 0, Error)
919+
end.
920+
921+
maybe_start_credential_expiry_timer(User) ->
892922
case rabbit_access_control:expiry_timestamp(User) of
893923
never ->
894-
ok;
924+
undefined;
895925
Ts when is_integer(Ts) ->
896926
Time = (Ts - os:system_time(second)) * 1000,
897-
rabbit_log:debug(
898-
"Credential expires in ~b ms frow now (absolute timestamp = ~b seconds since epoch)",
899-
[Time, Ts]),
927+
?LOG_DEBUG(
928+
"credential expires in ~b ms frow now (absolute timestamp = ~b seconds since epoch)",
929+
[Time, Ts]),
900930
case Time > 0 of
901931
true ->
902-
_TimerRef = erlang:send_after(Time, self(), credential_expired),
903-
ok;
932+
erlang:send_after(Time, self(), credential_expired);
904933
false ->
905934
protocol_error(?V_1_0_AMQP_ERROR_UNAUTHORIZED_ACCESS,
906-
"Credential expired ~b ms ago", [abs(Time)])
935+
"credential expired ~b ms ago", [abs(Time)])
907936
end
908937
end.
909938

deps/rabbit/src/rabbit_amqp_session.erl

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
-behaviour(gen_server).
1313

14+
-include_lib("kernel/include/logger.hrl").
1415
-include_lib("rabbit_common/include/rabbit.hrl").
1516
-include_lib("amqp10_common/include/amqp10_types.hrl").
1617
-include("rabbit_amqp.hrl").
@@ -90,7 +91,8 @@
9091
list_local/0,
9192
conserve_resources/3,
9293
check_resource_access/4,
93-
check_read_permitted_on_topic/4
94+
check_read_permitted_on_topic/4,
95+
reset_authz/2
9496
]).
9597

9698
-export([init/1,
@@ -393,6 +395,10 @@ init({ReaderPid, WriterPid, ChannelNum, MaxFrameSize, User, Vhost, ConnName,
393395
handle_max = ClientHandleMax}}) ->
394396
process_flag(trap_exit, true),
395397
rabbit_process_flag:adjust_for_message_handling_proc(),
398+
logger:update_process_metadata(#{channel_number => ChannelNum,
399+
connection => ConnName,
400+
vhost => Vhost,
401+
user => User#user.username}),
396402

397403
ok = pg:join(pg_scope(), self(), self()),
398404
Alarms0 = rabbit_alarm:register(self(), {?MODULE, conserve_resources, []}),
@@ -480,6 +486,10 @@ list_local() ->
480486
conserve_resources(Pid, Source, {_, Conserve, _}) ->
481487
gen_server:cast(Pid, {conserve_resources, Source, Conserve}).
482488

489+
-spec reset_authz(pid(), rabbit_types:user()) -> ok.
490+
reset_authz(Pid, User) ->
491+
gen_server:cast(Pid, {reset_authz, User}).
492+
483493
handle_call(Msg, _From, State) ->
484494
Reply = {error, {not_understood, Msg}},
485495
reply(Reply, State).
@@ -574,15 +584,26 @@ handle_cast({conserve_resources, Alarm, Conserve},
574584
noreply(State);
575585
handle_cast(refresh_config, #state{cfg = #cfg{vhost = Vhost} = Cfg} = State0) ->
576586
State = State0#state{cfg = Cfg#cfg{trace_state = rabbit_trace:init(Vhost)}},
577-
noreply(State).
587+
noreply(State);
588+
handle_cast({reset_authz, User}, #state{cfg = Cfg} = State0) ->
589+
State1 = State0#state{
590+
permission_cache = [],
591+
topic_permission_cache = [],
592+
cfg = Cfg#cfg{user = User}},
593+
try recheck_authz(State1) of
594+
State ->
595+
noreply(State)
596+
catch exit:#'v1_0.error'{} = Error ->
597+
log_error_and_close_session(Error, State1)
598+
end.
578599

579600
log_error_and_close_session(
580601
Error, State = #state{cfg = #cfg{reader_pid = ReaderPid,
581602
writer_pid = WriterPid,
582603
channel_num = Ch}}) ->
583604
End = #'v1_0.end'{error = Error},
584-
rabbit_log:warning("Closing session for connection ~p: ~tp",
585-
[ReaderPid, Error]),
605+
?LOG_WARNING("Closing session for connection ~p: ~tp",
606+
[ReaderPid, Error]),
586607
ok = rabbit_amqp_writer:send_command_sync(WriterPid, Ch, End),
587608
{stop, {shutdown, Error}, State}.
588609

@@ -869,8 +890,8 @@ destroy_outgoing_link(_, _, _, Acc) ->
869890
Acc.
870891

871892
detach(Handle, Link, Error = #'v1_0.error'{}) ->
872-
rabbit_log:warning("Detaching link handle ~b due to error: ~tp",
873-
[Handle, Error]),
893+
?LOG_WARNING("Detaching link handle ~b due to error: ~tp",
894+
[Handle, Error]),
874895
publisher_or_consumer_deleted(Link),
875896
#'v1_0.detach'{handle = ?UINT(Handle),
876897
closed = true,
@@ -961,8 +982,8 @@ handle_frame(#'v1_0.flow'{handle = Handle} = Flow,
961982
%% "If set to a handle that is not currently associated with
962983
%% an attached link, the recipient MUST respond by ending the
963984
%% session with an unattached-handle session error." [2.7.4]
964-
rabbit_log:warning(
965-
"Received Flow frame for unknown link handle: ~tp", [Flow]),
985+
?LOG_WARNING("Received Flow frame for unknown link handle: ~tp",
986+
[Flow]),
966987
protocol_error(
967988
?V_1_0_SESSION_ERROR_UNATTACHED_HANDLE,
968989
"Unattached link handle: ~b", [HandleInt])
@@ -2141,9 +2162,9 @@ handle_deliver(ConsumerTag, AckRequired,
21412162
outgoing_links = OutgoingLinks};
21422163
_ ->
21432164
%% TODO handle missing link -- why does the queue think it's there?
2144-
rabbit_log:warning(
2145-
"No link handle ~b exists for delivery with consumer tag ~p from queue ~tp",
2146-
[Handle, ConsumerTag, QName]),
2165+
?LOG_WARNING(
2166+
"No link handle ~b exists for delivery with consumer tag ~p from queue ~tp",
2167+
[Handle, ConsumerTag, QName]),
21472168
State
21482169
end.
21492170

@@ -2988,7 +3009,7 @@ credit_reply_timeout(QType, QName) ->
29883009
Fmt = "Timed out waiting for credit reply from ~s ~s. "
29893010
"Hint: Enable feature flag rabbitmq_4.0.0",
29903011
Args = [QType, rabbit_misc:rs(QName)],
2991-
rabbit_log:error(Fmt, Args),
3012+
?LOG_ERROR(Fmt, Args),
29923013
protocol_error(?V_1_0_AMQP_ERROR_INTERNAL_ERROR, Fmt, Args).
29933014

29943015
default(undefined, Default) -> Default;
@@ -3522,6 +3543,29 @@ check_topic_authorisation(#exchange{type = topic,
35223543
check_topic_authorisation(_, _, _, _, Cache) ->
35233544
Cache.
35243545

3546+
recheck_authz(#state{incoming_links = IncomingLinks,
3547+
outgoing_links = OutgoingLinks,
3548+
permission_cache = Cache0,
3549+
cfg = #cfg{user = User}
3550+
} = State) ->
3551+
?LOG_DEBUG("rechecking link authorizations", []),
3552+
Cache1 = maps:fold(
3553+
fun(_Handle, #incoming_link{exchange = X}, Cache) ->
3554+
case X of
3555+
#exchange{name = XName} ->
3556+
check_resource_access(XName, write, User, Cache);
3557+
#resource{} = XName ->
3558+
check_resource_access(XName, write, User, Cache);
3559+
to ->
3560+
Cache
3561+
end
3562+
end, Cache0, IncomingLinks),
3563+
Cache2 = maps:fold(
3564+
fun(_Handle, #outgoing_link{queue_name = QName}, Cache) ->
3565+
check_resource_access(QName, read, User, Cache)
3566+
end, Cache1, OutgoingLinks),
3567+
State#state{permission_cache = Cache2}.
3568+
35253569
check_user_id(Mc, User) ->
35263570
case rabbit_access_control:check_user_id(Mc, User) of
35273571
ok ->

0 commit comments

Comments
 (0)