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

Tim Watson tim at rabbitmq.com
Tue Dec 11 17:13:50 GMT 2012


HOLD ON.

If your plugin is packaged as an .ez file (which rabbit plugins usually are) then I wonder if the .so file is not accessible? This is a known issue with drivers, as no operating system I know of will allow dynamic loading from a non file system location. On the other hand, I think rabbit unpacks plugins that are enabled into RABBITMQ_PLUGINS_EXPAND_DIR - can you see the dynamic library (.so or .dylib) file in there?

Anyway, my suspicion is that when you're loading the NIF, it is not in the file system location you think it is. This could be because of the way plugins are expanded, but I'm just guessing there TBH. More likely perhaps, the name that you pass to code:priv_dir/1 is wrong. You're currently using `begin {ok, A} = application:get_application(?MODULE), A end` and I wonder if that's returning what you think it is? And *also* do you know if the application is actually fully loaded (and its environment setup correctly in the erlang node's application controller) at the time which the on_load target is being called? Perhaps calling application:get_env/1 is  not such a good idea when initialising a NIF. Instead of doing that, try hard coding it:

init() ->
  Kinit = filename:join(code:priv_dir(rabbit_auth_backend_kerberos), "/kinit.so"),
  erlang:load_nif(Kinit, 0).

On 11 Dec 2012, at 17:07, Tim Watson wrote:

> 
> On 11 Dec 2012, at 16:20, Simon Lundström wrote:
> 
>> That was easy. The only hard thing was to get it to compile correctly on
>> OS X = ).
> 
> Glad it was, and *not at all surprised* it's a pain on OSX - I frequently have issues there as well with .dylib vs .so and whatnot when making linked-in drivers.
> 
>> (Note to future readers see
>> <http://stackoverflow.com/questions/8288358/erlang-nif-test-os-x-lion>)
>> 
> 
> Thanks for sharing that with the list!
> 
>> The NIF needs to be loaded at some point and from the examples and
>> documentation I've found that it's done via -on_load, like this:
>> <https://github.com/simmel/rabbitmq-auth-backend-kerberos/blob/use_nif/src/rabbit_auth_backend_kerberos.erl#L10-L14>
>> 
> 
> That *is* the correct way to load a NIF.
> 
>> However, I've tried using -on_load before in my plugin and it didn't
>> work. I suspected that the -behaviour had some magic which involved
>> -on_load and using -on_load in your model bricks that. I worked around
>> needing -on_load and forgot about it. However, now I need it again. This
>> is from the error log:
>> 
> 
> -behaviour doesn't affect NIFs at all AFAIK - that behaviour attribute just tells the compiler to puke unless certain functions are defined and exported, and generates a behaviour_info/2 function. Hmn, perhaps that latter part *does* interfere with NIFs, but I've never heard of that before.
> 
>> When logging in via AMQP:
>> 
>> =ERROR REPORT==== 11-Dec-2012::09:57:02 ===
>> closing AMQP connection <0.287.0> (130.237.168.221:48736 -> 77.238.35.76:5671):
>> {channel0_error,starting,
>>   {error,undef,'connection.start_ok',
>>       [{rabbit_auth_backend_kerberos,check_user_login,
>>            [<<"simlu">>,[{password,<<"notmypassword">>}]]},
> 
> 
> That's not saying check_user_login is undefined. In fact, check_user_login is not even part of the NIF infrastructure. It looks like it's saying 'connection.start_ok' is undefined. Hmn - doesn't make much sense to me I'm afraid. What happens if you move the NIF part out into another module, using the -on_load attribute there and then just call that utility module from your plugin?
> 
> -module(kinit).
> 
> -export([init/0, kinit/2]).
> -on_load(init/0).
> 
> init() ->
>  Kinit = code:priv_dir(?APPLICATION) ++ "/kinit.so",
>  erlang:load_nif(Kinit, 0).
> 
> kinit(User, Password) -> exit(nif_library_not_loaded).
> 
> 
> And then in rabbit_auth_backend_kerberos just call:
> 
> case kinit:kinit(User, PassWd) of .....
> 
> Anyway, if you put the NIF part into another module, you *should* be able to test it outside of rabbit my doing something like:
> 
> $ erl -sname foo
> banner. .....
> % ok = application:start(rabbit_auth_backend_kerberos).
> ok
> % X = kinit:kinit("auser", "password").
> << a term >>
> % io:format("~p~n", [X]).
> 
> 
> Then if it *still* doesn't work when you're running it inside rabbit we might need to consider other things that could be going wrong (such as the NIF init magic). 
> 
> Cheers,
> Tim
> 
>>        {rabbit_access_control,'-check_user_login/2-fun-0-',4},
>>        {lists,foldl,3},
>>        {rabbit_reader,auth_phase,2},
>>        {rabbit_reader,handle_method0,3},
>>        {rabbit_reader,handle_input,3},
>>        {rabbit_reader,recvloop,2},
>>        {rabbit_reader,start_connection,7}]}}
>> 
>> when using the API (this is in the sasl log):
>> 
>> =CRASH REPORT==== 11-Dec-2012::11:51:04 ===
>> crasher:
>>   initial call: mochiweb_acceptor:init/3
>>   pid: <0.256.0>
>>   registered_name: []
>>   exception error: undefined function rabbit_auth_backend_kerberos:check_user_login/2
>>     in function  rabbit_access_control:'-check_user_login/2-fun-0-'/4
>>     in call from lists:foldl/3
>>     in call from rabbit_mgmt_app:'-make_loop/0-fun-0-'/4
>>     in call from mochiweb_http:headers/5
>>   ancestors: [rabbit_mochiweb_web_mgmt,rabbit_mochiweb_sup,<0.132.0>]
>>   messages: []
>>   links: [<0.252.0>]
>>   dictionary: []
>>   trap_exit: false
>>   status: running
>>   heap_size: 4181
>>   stack_size: 24
>>   reductions: 1467
>> neighbours:
>> 
>> 
>> Thanks,
>> - Simon
>> _______________________________________________
>> rabbitmq-discuss mailing list
>> rabbitmq-discuss at lists.rabbitmq.com
>> https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss
> 
> _______________________________________________
> rabbitmq-discuss mailing list
> rabbitmq-discuss at lists.rabbitmq.com
> https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss



More information about the rabbitmq-discuss mailing list