diff --git a/README.md b/README.md index 9a45ceb..ad8f535 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ Or, in the classic config format (`rabbitmq.config`, prior to 3.7.0) or `advance ]. Authentication requests will be packed into the headers of incoming -messages. There are three types of request: `login`, `check_vhost` and -`check_resource`. Responses should be returned in the message +messages. There are four types of request: `login`, `check_vhost`, +`check_resource` and `check_topic`. Responses should be returned in the message body. Responses to `login` requests should be "refused" if login is unsuccessful or a comma-separated list of tags for the user if login is successful. Responses to the other types should be the words diff --git a/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/AuthBackend.java b/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/AuthBackend.java index e6a4929..8345d99 100644 --- a/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/AuthBackend.java +++ b/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/AuthBackend.java @@ -13,6 +13,12 @@ boolean checkVhost(String username, String vhost); boolean checkResource(String username, + String vhost, + String resourceName, + ResourceType resourceType, + ResourcePermission permission); + + boolean checkTopic(String username, String vhost, String resourceName, ResourceType resourceType, diff --git a/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/AuthServer.java b/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/AuthServer.java index 65f1fe0..acfc0be 100644 --- a/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/AuthServer.java +++ b/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/AuthServer.java @@ -45,8 +45,16 @@ else if (action.equals("check_resource")) { get("vhost", headers), get("name", headers), ResourceType.valueOf(getU("resource", headers)), - ResourcePermission.valueOf(getU("permission", headers)), - get("routing_key", headers))); + ResourcePermission.valueOf(getU("permission", headers)))); + } + else if (action.equals("check_topic")) { + return bool(authBackend.checkTopic( + get("username", headers), + get("vhost", headers), + get("name", headers), + ResourceType.valueOf(getU("resource", headers)), + ResourcePermission.valueOf(getU("permission", headers)), + get("routing_key", headers))); } throw new RuntimeException("Unexpected action " + action); diff --git a/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/examples/ExampleAuthBackend.java b/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/examples/ExampleAuthBackend.java index 3997399..d8f9551 100644 --- a/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/examples/ExampleAuthBackend.java +++ b/examples/rabbitmq-auth-backend-java/src/com/rabbitmq/authbackend/examples/ExampleAuthBackend.java @@ -38,12 +38,16 @@ public boolean checkResource(String username, String vhost, String resourceName, ResourceType resourceType, - ResourcePermission permission, - String routingKey) { - if(resourceType == ResourceType.TOPIC) { - return routingKey.startsWith("a"); - } else { - return true; - } + ResourcePermission permission) { + return true; + } + + public boolean checkTopic(String username, + String vhost, + String resourceName, + ResourceType resourceType, + ResourcePermission permission, + String routingKey) { + return routingKey.startsWith("a"); } } diff --git a/src/rabbit_auth_backend_amqp.erl b/src/rabbit_auth_backend_amqp.erl index f9d4999..410eb2e 100644 --- a/src/rabbit_auth_backend_amqp.erl +++ b/src/rabbit_auth_backend_amqp.erl @@ -24,7 +24,7 @@ -export([description/0]). -export([user_login_authentication/2, user_login_authorization/1, - check_vhost_access/3, check_resource_access/3]). + check_vhost_access/3, check_resource_access/3, check_topic_access/4]). -behaviour(gen_server). @@ -64,26 +64,37 @@ check_vhost_access(#auth_user{username = Username}, VHost, _Sock) -> infinity). check_resource_access(#auth_user{username = Username}, - #resource{virtual_host = VHost, kind = Type, name = Name, options = Options}, + #resource{virtual_host = VHost, kind = Type, name = Name}, Permission) -> - OptionsHeaders = resource_options_as_headers(Options), gen_server:call(?SERVER, {check_resource, [{username, Username}, {vhost, VHost}, {resource, Type}, {name, Name}, - {permission, Permission}] ++ OptionsHeaders}, + {permission, Permission}]}, + infinity). + +check_topic_access(#auth_user{username = Username}, + #resource{virtual_host = VHost, kind = topic = Type, name = Name}, + Permission, + Context) -> + OptionsHeaders = context_as_headers(Context), + gen_server:call(?SERVER, {check_topic, [{username, Username}, + {vhost, VHost}, + {resource, Type}, + {name, Name}, + {permission, Permission}] ++ OptionsHeaders}, infinity). %%-------------------------------------------------------------------- -resource_options_as_headers(Options) when is_map(Options) -> +context_as_headers(Options) when is_map(Options) -> % filter options that would erase fixed parameters [{rabbit_data_coercion:to_atom(Key), maps:get(Key, Options)} || Key <- maps:keys(Options), lists:member( rabbit_data_coercion:to_atom(Key), ?CHECK_RESOURCE_ACCESS_HEADERS) =:= false]; -resource_options_as_headers(_) -> +context_as_headers(_) -> []. init([]) -> @@ -134,6 +145,9 @@ handle_call({check_vhost, Args}, _From, State) -> handle_call({check_resource, Args}, _From, State) -> {reply, bool_rpc([{action, check_resource} | Args], State), State}; +handle_call({check_topic, Args}, _From, State) -> + {reply, bool_rpc([{action, check_topic} | Args], State), State}; + handle_call(_Req, _From, State) -> {reply, unknown_request, State}.