emqx / emqx-auth-ldap

EMQX LDAP Authentication Plugin
https://www.emqx.io
Apache License 2.0
7 stars 15 forks source link

Restricting users' access to topics with the emqx_auth_ldap plugin #75

Open mbenitod opened 5 years ago

mbenitod commented 5 years ago

Hello!

I downloaded openLDAP, installed it in ubuntu and configured it by adding the schemes you propose with the command ldapadd. Everything works perfectly, I can query the database and I can use a MQTT client to test the users that are in the database.

I have configured: mqtt.allow_anonymous = false

So far so good.

The problem comes when I try to restrict access, i.e. that user A can only subscribe to topic "home" for example; or that user B can only publish to topic "garden" but not to the rest of topics.

I have used your emqx.io.ldif. I have tried the following (I write only the fragments of interest):

uid: mqttuserA isEnabled: TRUE mqttPublishTopic: mqttuserA/pub/1 mqttPublishTopic: mqttuserA/pub/+ mqttPublishTopic: mqttuserA/pub/# mqttSubscriptionTopic: mqttuserA/sub/1 mqttSubscriptionTopic: mqttuserA/sub/+ mqttSubscriptionTopic: mqttuserA/sub/# mqttPubSubTopic: mqttuserA/pubsub/1 mqttPubSubTopic: mqttuserA/pubsub/+ mqttPubSubTopic: mqttuserA/pubsub/#

uid: mqttuserB isEnabled: TRUE mqttPublishTopic: mqttuserB/pub/1 mqttPublishTopic: mqttuserB/pub/+ mqttPublishTopic: mqttuserB/pub/#/home mqttSubscriptionTopic: mqttuserB/sub/1 mqttSubscriptionTopic: mqttuserB/sub/+ mqttSubscriptionTopic: mqttuserB/sub/#/home mqttPubSubTopic: mqttuserB/pubsub/1 mqttPubSubTopic: mqttuserB/pubsub/+ mqttPubSubTopic: mqttuserB/pubsub/#/home

uid: mqttuserC isEnabled: TRUE mqttSubscriptionTopic: mqttuserC/sub/1 mqttSubscriptionTopic: mqttuserC/sub/+ mqttSubscriptionTopic: mqttuserC/sub/home

uid: mqttuserD isEnabled: TRUE mqttPublishTopic: mqttuserD/pub/1 mqttPublishTopic: mqttuserD/pub/garden

The 4 users are different but:

What am I doing wrong? How can I modify the emqx.io.ldif so that a user can only subscribe to one topic for example? Nor do I understand very well why it is always the same sequence: 1,+,#

If you could help me, I'd really appreciate it. Greetings!

dwatkin5 commented 4 years ago

Hello, did this ever get resolved?

ssr7 commented 4 years ago

I have the same issue. I installed lasted version

emqx_ctl broker sysdescr : EMQ X Broker version : 4.0.4 uptime : 7 minutes, 34 seconds datetime : 2020-03-13 00:44:52

and I installed Openldap on Ubuntu 18.04

slapd -V @(#) $OpenLDAP: slapd (Ubuntu) (Aug 8 2019 18:08:36) $ Debian OpenLDAP Maintainers pkg-openldap-devel@lists.alioth.debian.org

My config for using auth ldap :

vim /etc/emqx/plugins/emqx_auth_ldap.conf auth.ldap.servers = 127.0.0.1 auth.ldap.port = 389 auth.ldap.pool = 8 auth.ldap.bind_dn = cn=admin,dc=test,dc=com auth.ldap.bind_password = monaliza auth.ldap.timeout = 30s auth.ldap.device_dn = ou=Device,,dc=test,dc=com auth.ldap.match_objectclass = mqttUser auth.ldap.username.attributetype = uid auth.ldap.password.attributetype = userPassword auth.ldap.ssl = false

and part of emqx.conf for disable anonymous user login

vim /etc/emqx/emqx.conf allow_anonymous = false acl_nomatch = deny acl_file = /etc/emqx/acl.conf enable_acl_cache = on ....

and also I never changed acl.conf

cat /etc/acl.conf %%-------------------------------------------------------------------- %% ACL %% %% -type(who() :: all | binary() | %% {ipaddr, esockd_access:cidr()} | %% {client, binary()} | %% {user, binary()}). %% %% -type(access() :: subscribe | publish | pubsub). %% %% -type(topic() :: binary()). %% %% -type(rule() :: {allow, all} | %% {allow, who(), access(), list(topic())} | %% {deny, all} | %% {deny, who(), access(), list(topic())}). %%--------------------------------------------------------------------

{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.

{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.

{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.

{allow, all}

Notice: I had to edit emqx schema(change mqttDevice from structural to auxiliary ) because open ldap dose not allow to add two structural class chain [()] (https://stackoverflow.com/questions/36910899/ldap-multiple-structural-objectclasses) I added user to ldap:

version: 1 dn: uid=test,ou=Device,dc=test,dc=com objectClass: mqttUser objectClass: mqttSecurity objectClass: mqttDevice objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson cn: test sn: tes uid: test isEnabled: TRUE mqttSubscriptionTopic: test userPassword: {SHA512}sEEll9zqgTZVV03FSlt0lnz4UxfwMyolkb55U6AW+N5WIA6zfVulk7 HkqifOpconEA+U3M1bBLrlyt1EVNumfQ==

I do below scenario: 1) connect to emqx -->OK 2) subscribe to topic: test --> OK 3)subscribe to topic: test2 --> I got error but the connection is connect and i can receive message from test2 topic

Stack Error:

2020-03-13 00:58:47.368 [error] <<"160838220">>@127.0.0.1:34352 [Hooks] Failed to execute {fun emqx_acl_ldap:check_acl/5, [#{device_dn => "ou=Device,dc=test,dc=com", match_objectclass => "mqttUser", password_attr => "userPassword", username_attr => "uid"}]}: {function_clause, [{emqx_acl_ldap, match, [<<"test2">>, undefined], [{file, "/emqx-rel/_build/emqx-pkg/lib/emqx_auth_ldap/src/emqx_acl_ldap.erl"}, {line,76}]}, {emqx_acl_ldap, check_acl,5, [{file, "/emqx-rel/_build/emqx-pkg/lib/emqx_auth_ldap/src/emqx_acl_ldap.erl"}, {line,40}]}, {emqx_hooks, safe_execute,2, [{file, "/emqx-rel/_build/emqx-pkg/lib/emqx/src/emqx_hooks.erl"}, {line,164}]}, {emqx_hooks, do_run_fold,3, [{file, "/emqx-rel/_build/emqx-pkg/lib/emqx/src/emqx_hooks.erl"}, {line,143}]}, {emqx_access_control, do_check_acl,3, [{file, "/emqx-rel/_build/emqx-pkg/lib/emqx/src/emqx_access_control.erl"}, {line,83}]}, {emqx_access_control, check_acl_cache,3, [{file, "/emqx-rel/_build/emqx-pkg/lib/emqx/src/emqx_access_control.erl"}, {line,57}]}, {emqx_channel, check_sub_acl,2, [{file, "/emqx-rel/_build/emqx-pkg/lib/emqx/src/emqx_channel.erl"}, {line,1146}]}, {emqx_channel, check_subscribe,3, [{file, "/emqx-rel/_build/emqx-pkg/lib/emqx/src/emqx_channel.erl"}, {line,1136}]}]} 2020-03-13 00:58:47.370 [debug] <<"160838220">>@127.0.0.1:34352 [MQTT] SEND SUBACK(Q0, R0, D0, PacketId=13, ReasonCodes=[0])

I tested this issue on version 3.2.7. In version 3.2.3 i received error but after error the connection disconnected. Stack error in version 3.2.3:

2020-03-12 12:34:23.301 [debug] 160838220@172.16.111.47:51168 [LDAP] search dn:"ou=Device,dc=dev,dc=labs,dc=arissystem,dc=com" filter:{equalityMatch, {'AttributeValueAssertion', "objectClass", "mqttUser"}}, attribute:"mqttSubscriptionTopic" 2020-03-12 12:34:23.303 [debug] 160838220@172.16.111.47:51168 [Channel] Terminated for function_clause 2020-03-12 12:34:23.304 [info] 160838220@172.16.111.47:51168 [Protocol] Shutdown for function_clause

rname":"K6t76hyv4x5q1b58euJbYdA2tpPatOT0","reason":"function_clause"} 2020-03-12 12:34:23.346 [error] 160838220@172.16.111.47:51168 State machine <0.7386.9> terminating Last event = {cast, {incoming, {mqtt_packet, {mqtt_packet_header,8,false,1,false}, {mqtt_packet_subscribe,1,undefined, [{<<"aaa">>,

{nl => 0,qos => 0,rap => 0,rc => 0,

                                rh => 0}}]},
                        undefined}}}

** When server state = {connected, {state,esockd_transport,#Port<0.847>, {{172,16,111,47},51168}, undefined,running,100, {pstate,external,

Fun,

                                {{192,168,110,198},1883},
                                {{172,16,111,47},51168},
                                nossl,4,<<"MQTT">>,<<"160838220">>,
                                false,<0.7386.9>,undefined,undefined,
                                <<"K6t76hyv4x5q1b58euJbYdA2tpPatOT0">>,
                                <0.7388.9>,true,#{},undefined,undefined,
                                60,false,
                                #{msg => 0,pkt => 1},
                                #{msg => 0,pkt => 1},
                                true,
                                {1584,3858,430672},
                                #{from_client => 0,to_client => 0},
                                emqx_channel,
                                #{anonymous => false,
                                  auth_result => success,
                                  client_id => <<"160838220">>,
                                  mountpoint => undefined,
                                  peername => {{172,16,111,47},51168},
                                  sockname => {{192,168,110,198},1883},
                                  username =>
                                      <<"K6t76hyv4x5q1b58euJbYdA2tpPatOT0">>,
                                  ws_cookie => undefined,zone => external},
                                undefined},
                            {none,#{max_size => 1048576,version => 4}},
                            {emqx_gc,
                                #{cnt => {1000,998},
                                  oct => {1048576,1048470}}},
                            {keepalive,#Fun<emqx_channel.3.102180930>,96,
                                45,
                                {keepalive,check},
                                #Ref<0.519790091.4199546882.208929>,0},
                            undefined,undefined,undefined,true,
                            #Ref<0.519790091.4198498305.169525>,15000}}

Reason for termination = error:function_clause Callback mode = [state_functions,state_enter] Stacktrace = [{emqx_acl_ldap,match, [<<"aaa">>,undefined], [{file,"/emqx_temp/emqx_rel/_checkouts/emqx_auth_ldap/src/emqx_acl_ldap.erl"}, {line,71}]}, {emqx_acl_ldap,check_acl,5, [{file,"/emqx_temp/emqx_rel/_checkouts/emqx_auth_ldap/src/emqx_acl_ldap.erl"}, {line,37}]}, {emqx_hooks,do_run_fold,3, [{file,"/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_hooks.erl"}, {line,131}]}, {emqx_access_control,do_check_acl,3, [{file,"/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_access_control.erl"}, {line,59}]}, {emqx_access_control,check_acl,3, [{file,"/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_access_control.erl"}, {line,50}]}, {emqx_protocol,do_acl_check,5, [{file,"/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_protocol.erl"}, {line,1059}]}, {emqx_protocol,process,2, [{file,"/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_protocol.erl"}, {line,505}]}, {emqx_channel,handle_incoming,3, [{file,"/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_channel.erl"}, {line,433}]}] 2020-03-12 12:34:23.369 [error] 160838220@172.16.111.47:51168 crasher: initial call: emqx_channel:init/1 pid: <0.7386.9> registered_name: [] exception error: no function clause matching emqx_acl_ldap:match(<<"aaa">>,undefined) (/emqx_temp/emqx_rel/_checkouts/emqx_auth_ldap/src/emqx_acl_ldap.erl, line 71) in function emqx_acl_ldap:check_acl/5 (/emqx_temp/emqx_rel/_checkouts/emqx_auth_ldap/src/emqx_acl_ldap.erl, line 37) in call from emqx_hooks:do_run_fold/3 (/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_hooks.erl, line 131) in call from emqx_access_control:do_check_acl/3 (/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_access_control.erl, line 59) in call from emqx_access_control:check_acl/3 (/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_access_control.erl, line 50) in call from emqx_protocol:do_acl_check/5 (/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_protocol.erl, line 1059) in call from emqx_protocol:process/2 (/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_protocol.erl, line 505) in call from emqx_channel:handle_incoming/3 (/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_channel.erl, line 433) ancestors: [<0.1629.0>,<0.1628.0>,esockd_sup,<0.1354.0>] message_queue_len: 1 messages: [{'EXIT',#Port<0.847>,normal}] links: [<0.7388.9>,<0.1629.0>] dictionary: [{rand_seed, {#{bits => 58,jump => #Fun, next => #Fun,type => exrop, uniform => #Fun, uniform_n => #Fun, weak_low_bits => 1}, [178081116545152031|1464167546552973]}}, {incoming_bytes,106}, {'$logger_metadata$',

{client_id => <<"160838220">>,

                    peername => "172.16.111.47:51168"}},
              {force_shutdown_policy,
                  #{max_heap_size => 838860800,message_queue_len => 8000}},
              {guid,{1584003863304671,268568750988506,1}}]

:

{max_heap_size => 838860800,message_queue_len => 8000}},

              {guid,{1584003863304671,268568750988506,1}}]
trap_exit: true
status: running
heap_size: 17731
stack_size: 27
reductions: 532586

neighbours: 2020-03-12 12:34:23.371 [error] supervisor: 'esockd_connection_sup - <0.1629.0>' errorContext: connection_crashed reason: {function_clause, [{emqx_acl_ldap,match, [<<"aaa">>,undefined], [{file, "/emqx_temp/emqx_rel/_checkouts/emqx_auth_ldap/src/emqx_acl_ldap.erl"}, {line,71}]}, {emqx_acl_ldap,check_acl,5, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx_auth_ldap/src/emqx_acl_ldap.erl"}, {line,37}]}, {emqx_hooks,do_run_fold,3, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_hooks.erl"}, {line,131}]}, {emqx_access_control,do_check_acl,3, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_access_control.erl"}, {line,59}]}, {emqx_access_control,check_acl,3, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_access_control.erl"}, {line,50}]}, {emqx_protocol,do_acl_check,5, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_protocol.erl"}, {line,1059}]}, : {emqx_protocol,process,2, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_protocol.erl"}, {line,505}]}, {emqx_channel,handle_incoming,3, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_channel.erl"}, {line,433}]}]} offender: [{pid,<0.7386.9>}, {name,connection}, {mfargs,{emqx_channel,start_link, [[{deflate_options,[]}, {max_conn_rate,1000}, {active_n,100}, {zone,external}]]}}] 2020-03-12 12:34:23.371 [error] 160838220 WebHook: Session terminated, cannot encode the reason: {shutdown, {function_clause, [{emqx_acl_ldap, match, [<<"aaa">>, undefined], [{file, "/emqx_temp/emqx_rel/_checkouts/emqx_auth_ldap/src/emqx_acl_ldap.erl"}, {line,71}]}, {emqx_acl_ldap, check_acl,5, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx_auth_ldap/src/emqx_acl_ldap.erl"}, {line,37}]}, {emqx_hooks, do_run_fold,3, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_hooks.erl"}, {line,131}]}, {emqx_access_control, do_check_acl,3, : [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_hooks.erl"}, {line,131}]}, {emqx_access_control, do_check_acl,3, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_access_control.erl"}, {line,59}]}, {emqx_access_control, check_acl,3, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_access_control.erl"}, {line,50}]}, {emqx_protocol, do_acl_check,5, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_protocol.erl"}, {line,1059}]}, {emqx_protocol, process,2, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_protocol.erl"}, {line,505}]}, {emqx_channel, handle_incoming,3, [{file, "/emqx_temp/emqx_rel/_checkouts/emqx/src/emqx_channel.erl"}, {line,433}]}]}}

I also tested on 389 ldap directory. So i am sure this problem does not related to ldap productions

ssr7 commented 4 years ago

I think emqx ldap acl module has problem

kevin-olbrich commented 3 years ago

~~I can see EMQX fetching mqttSubscriptionTopic and mqttPubSubTopic from LDAP (on sub request) but the data is simply ignored. All users can subscribe to all topics, regardless of their ACLs.~~

Edit: replacing "{allow, all}." with "{deny, all}." in acl.conf seems to make it work. I was mislead by the code in the ldap module and the debug output. Rules set up in acl.conf still override a failure in ldap's acl check.