summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rabbit_access_control.erl11
-rw-r--r--src/rabbit_channel.erl48
-rw-r--r--src/rabbit_reader.erl2
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(