diff options
| -rw-r--r-- | src/rabbit_access_control.erl | 11 | ||||
| -rw-r--r-- | src/rabbit_channel.erl | 48 | ||||
| -rw-r--r-- | src/rabbit_reader.erl | 2 |
3 files changed, 43 insertions, 18 deletions
diff --git a/src/rabbit_access_control.erl b/src/rabbit_access_control.erl index 06eef8308d..5cb38115fb 100644 --- a/src/rabbit_access_control.erl +++ b/src/rabbit_access_control.erl @@ -21,7 +21,7 @@ -export([check_user_pass_login/2, check_user_login/2, check_user_loopback/2, check_vhost_access/4, check_resource_access/4, check_topic_access/4]). --export([update_state/2]). +-export([can_use_permission_cache/1, update_state/2]). %%---------------------------------------------------------------------------- @@ -222,7 +222,7 @@ check_access(Fun, Module, ErrStr, ErrArgs, ErrName) -> -spec update_state(User :: rabbit_types:user(), NewState :: term()) -> {'ok', rabbit_types:auth_user()} | - {'refused', string(), [any()]} | + {'refused', string()} | {'error', any()}. update_state(User = #user{authz_backends = Backends0}, NewState) -> @@ -247,3 +247,10 @@ update_state(User = #user{authz_backends = Backends0}, NewState) -> {ok, Pairs} -> {ok, User#user{authz_backends = lists:reverse(Pairs)}}; Else -> Else end. + +-spec can_use_permission_cache(User :: rabbit_types:user()) -> boolean(). + +%% Returns false if any of the backends support credential expiration, +%% otherwise returns true. +can_use_permission_cache(#user{authz_backends = Backends}) -> + not lists:any(fun ({Module, _State}) -> Module:state_can_expire() end, Backends). diff --git a/src/rabbit_channel.erl b/src/rabbit_channel.erl index 852b03e859..9cc7debd53 100644 --- a/src/rabbit_channel.erl +++ b/src/rabbit_channel.erl @@ -468,7 +468,7 @@ source(Pid, Source) when is_pid(Pid) -> false -> {error, channel_terminated} end. --spec update_user_state(pid(), rabbit_types:user()) -> 'ok' | {error, channel_terminated}. +-spec update_user_state(pid(), rabbit_types:auth_user()) -> 'ok' | {error, channel_terminated}. update_user_state(Pid, UserState) when is_pid(Pid) -> case erlang:is_process_alive(Pid) of @@ -499,6 +499,8 @@ init([Channel, ReaderPid, WriterPid, ConnPid, ConnName, Protocol, User, VHost, _ -> Limiter0 end, + %% Process dictionary is used here because permission cache already uses it. MK. + put(permission_cache_enabled, rabbit_access_control:can_use_permission_cache(User)), MaxMessageSize = get_max_message_size(), ConsumerTimeout = get_consumer_timeout(), State = #ch{cfg = #conf{state = starting, @@ -984,7 +986,14 @@ return_queue_declare_ok(#resource{name = ActualName}, message_count = MessageCount, consumer_count = ConsumerCount}). -check_resource_access(User, Resource, Perm, Context) -> +%% permission cache must not be used (one of the authz +%% backends supports credential expiration) +check_resource_access(User, Resource, Perm, Context, false = _Enabled) -> + ok = rabbit_access_control:check_resource_access( + User, Resource, Perm, Context); + +%% permission cache enabled +check_resource_access(User, Resource, Perm, Context, _Enabled) -> V = {Resource, Context, Perm}, Cache = case get(permission_cache) of @@ -1004,19 +1013,19 @@ clear_permission_cache() -> erase(permission_cache), ok. check_configure_permitted(Resource, User, Context) -> - check_resource_access(User, Resource, configure, Context). + check_resource_access(User, Resource, configure, Context, get(permission_cache_enabled)). check_write_permitted(Resource, User, Context) -> - check_resource_access(User, Resource, write, Context). + check_resource_access(User, Resource, write, Context, get(permission_cache_enabled)). check_read_permitted(Resource, User, Context) -> - check_resource_access(User, Resource, read, Context). + check_resource_access(User, Resource, read, Context, get(permission_cache_enabled)). check_write_permitted_on_topic(Resource, User, ConnPid, RoutingKey, ChSrc) -> - check_topic_authorisation(Resource, User, ConnPid, RoutingKey, ChSrc, write). + check_topic_authorisation(Resource, User, ConnPid, RoutingKey, ChSrc, write, get(permission_cache_enabled)). check_read_permitted_on_topic(Resource, User, ConnPid, RoutingKey, ChSrc) -> - check_topic_authorisation(Resource, User, ConnPid, RoutingKey, ChSrc, read). + check_topic_authorisation(Resource, User, ConnPid, RoutingKey, ChSrc, read, get(permission_cache_enabled)). check_user_id_header(#'P_basic'{user_id = undefined}, _) -> ok; @@ -1052,20 +1061,29 @@ check_internal_exchange(_) -> ok. check_topic_authorisation(Resource = #exchange{type = topic}, - User, none, RoutingKey, _ChSrc, Permission) -> + User, none, RoutingKey, _ChSrc, Permission, PermCacheEnabled) -> %% Called from outside the channel by mgmt API AmqpParams = [], - check_topic_authorisation(Resource, User, AmqpParams, RoutingKey, Permission); + do_check_topic_authorisation(Resource, User, AmqpParams, RoutingKey, Permission, PermCacheEnabled); check_topic_authorisation(Resource = #exchange{type = topic}, - User, ConnPid, RoutingKey, ChSrc, Permission) when is_pid(ConnPid) -> + User, ConnPid, RoutingKey, ChSrc, Permission, PermCacheEnabled) when is_pid(ConnPid) -> AmqpParams = get_amqp_params(ConnPid, ChSrc), - check_topic_authorisation(Resource, User, AmqpParams, RoutingKey, Permission); -check_topic_authorisation(_, _, _, _, _, _) -> + do_check_topic_authorisation(Resource, User, AmqpParams, RoutingKey, Permission, PermCacheEnabled); +check_topic_authorisation(_, _, _, _, _, _, _) -> ok. -check_topic_authorisation(#exchange{name = Name = #resource{virtual_host = VHost}, type = topic}, - User = #user{username = Username}, - AmqpParams, RoutingKey, Permission) -> +do_check_topic_authorisation(#exchange{name = Name = #resource{virtual_host = VHost}, type = topic}, + User = #user{username = Username}, + AmqpParams, RoutingKey, Permission, false = _PermCacheEnabled) -> + Resource = Name#resource{kind = topic}, + VariableMap = build_topic_variable_map(AmqpParams, VHost, Username), + Context = #{routing_key => RoutingKey, + variable_map => VariableMap}, + ok = rabbit_access_control:check_topic_access( + User, Resource, Permission, Context); +do_check_topic_authorisation(#exchange{name = Name = #resource{virtual_host = VHost}, type = topic}, + User = #user{username = Username}, + AmqpParams, RoutingKey, Permission, _PermCacheEnabled) -> Resource = Name#resource{kind = topic}, VariableMap = build_topic_variable_map(AmqpParams, VHost, Username), Context = #{routing_key => RoutingKey, diff --git a/src/rabbit_reader.erl b/src/rabbit_reader.erl index 4e47a7ea11..f45c79cc16 100644 --- a/src/rabbit_reader.erl +++ b/src/rabbit_reader.erl @@ -1293,7 +1293,7 @@ handle_method0(#'connection.update_secret'{new_secret = NewSecret, reason = Reas %% Therefore we optimistically do no error handling here. MK. lists:foreach(fun(Ch) -> rabbit_log:debug("Updating user/auth backend state for channel ~p", [Ch]), - rabbit_channel:update_user_state(Ch, User1) + _ = rabbit_channel:update_user_state(Ch, User1) end, all_channels()), ok = send_on_channel0(Sock, #'connection.update_secret_ok'{}, Protocol), rabbit_log_connection:info( |
