[rabbitmq-discuss] Creating an auth plugin (Kerberos)

Tim Watson tim at rabbitmq.com
Wed Dec 5 12:01:31 GMT 2012


On 5 Dec 2012, at 11:09, Simon MacMullen wrote:

> On 05/12/12 11:05, Simon Lundström wrote:
>> On Mon, 2012-12-03 at 11:21:55 +0000, Tim Watson wrote:
>>> If you want to avoid blocking (the reader! yes you do I would've
>>> thought) then you might consider using an 'insulator' process in
>>> which to open and interact with the port. This allows you to timeout
>>> and/or terminate the port without blocking the reader process - some
>>> port commands are blocking and if your C code (or external
>>> application or whatever) gets stuck then you could be in trouble.
>> Please elaborate on this. I've tried to find any information about using
>> an 'insulator' process. It's mentioned in the source code of eunit but that's
>> the only relevant hit I got. I understand what you mean by not blocking
>> the read process though but I thought using a port was async?
>> When I tested this, I could authenticate multiple users while
>> authentication was hanging?

Well, you've solved this in a different way is all. ;)

In your code, you do a couple of things that alleviate the need for an insulator. First of all, instead of communicating using stdio, you send your port commands asynchronously using `Port ! Command` which is not blocking. Secondly, in your loop (that gets data back from the port) you use `after 5000 -> [{error,timedout}|Acc]` to terminate the loop, so this won't block indefinitely either. As long as you're happy that authentication always has to work within 5 seconds then this approach is ok and you don't need to do anything else. If you want to allow longer authentication times and still terminate gracefully when, for example, the broker is being shut down, then you've got to do more work.

The reason you can authenticate multiple times is because of what Simon says below - there is *one reader (process) per connection* and the auth backend is just a module with functions that get called in the reader process. I hope that makes sense.

One thing I would suggest is that if you do hit `after 5000` and time out whilst waiting for the external program to complete, it *might* be a good idea to close the port so as not to leak resources. Check the open_port documentation for details.

> I'm not sure Tim's suggestion makes sense in fact. At this point the reader process *has* to block, it has to wait to see if the user can be authenticated before proceeding. And there is one reader per connection.

I'm not suggesting that the reader should *not* block whilst authenticating - of course it should. But what I *am* suggesting is that the way in which it blocks should be controlled carefully. My point was that an external resource such as a port program can potentially block indefinitely (unless an 'after' or similar timeout is in place) and that could make the reader unresponsive even to a supervision tree shutting down. By using an insulator process, you remain 'responsive' when, for example, a supervisor is sending you exit(ReaderPid, shutdown) messages that you *do* want to respond to. If you're stuck in erlang:port_command/2 or erlang:port_call/2 or whatever, then nothing except a brutal_kill will terminate the process, and we don't use brutal_kill to stop our supervision trees. This is the exact problem I've had to solve in systest, where we need to ensure a clean shutdown when a supervision tree is being taken out of action.

Anyway, this is not relevant as the OP is using `after 5000` to timeout the external call.

> Cheers, Simon
> -- 
> Simon MacMullen
> RabbitMQ, VMware

More information about the rabbitmq-discuss mailing list