njh / ruby-mqtt

Pure Ruby gem that implements the MQTT protocol, a lightweight protocol for publish/subscribe messaging.
http://www.rubydoc.info/gems/mqtt
MIT License
538 stars 135 forks source link

Unable to authenticate #122

Closed beraybentesen closed 4 years ago

beraybentesen commented 4 years ago
MQTT::Client.connect(
  :host => 'IP address',
  :username => 'abc',
  :password => 'abc',
  :ssl => false,
  :port => 1883

in Go, I am able to connect with tcp://ip:port

njh commented 4 years ago
beraybentesen commented 4 years ago

Broker: EMQX Error: if I add tcp:// -> getaddrinfo: nodename nor servname provided, or not known (SocketError) without tcp:// -> Connection refused: bad user name or password (MQTT::ProtocolException)

However, authentication information is correct. Works well with Go, Nodejs, C etc.

Broker log: I haven't checked yet, but I will tomorrow.

njh commented 4 years ago

tcp:// URIs are not supported. But MQTT URIs are: https://github.com/mqtt/mqtt.github.io/wiki/URI-Scheme

beraybentesen commented 4 years ago

@njh Thanks for quick response. Is it possible to add support easily or is it another kind of process ?

njh commented 4 years ago

Sorry, I don't understand the question?

Is this not working for you?

MQTT::Client.connect(
  :host => '192.168.1.100',
  :username => 'abc',
  :password => 'abc',
  :ssl => false,
  :port => 1883
)
beraybentesen commented 4 years ago

Unfortunately, I receive : Connection refused: bad user name or password (MQTT::ProtocolException)

We were able to connect only if we provide tcp:// at the beginning for any mqtt client library.

beraybentesen commented 4 years ago

Also verified that broker requires that the client library should parse tcp:// endpoint.

njh commented 4 years ago

Sorry, I am still very confused about what you are trying to do and what isn't working. I am going to install EMQX and see what is required to get it working.

Also verified that broker requires that the client library should parse tcp:// endpoint.

I don't think that can be true. tcp:// is not part of any MQTT specification.

beraybentesen commented 4 years ago

The Ruby client should parse the tcp://.. schema to a IP addr and Port.

Their response was that.

I am trying to send data to the broker. mqtt://ipaddress:port or ipaddress:port not working. Other libraries support tcp://ipaddress:port URI schema.

Thank you for support,

njh commented 4 years ago

Do you have a list of libraries you have tried that use the tcp: URI scheme? It would be good to try and get everyone to move over to using the mqtt: URI scheme.

njh commented 4 years ago

I have given EMQX a go on my local machine. I have outlined all the steps I have gone through to get to a working test.

Out of the box emqx seems to allow anonymous connections and ignores the username and password if provided.

To turn on authentication, I edited etc/emqx.conf:

allow_anonymous = false

I then setup a username and password in etc/plugins/emqx_auth_username.conf:

auth.user.1.username = abc
auth.user.1.password = abc

And changed:

auth.user.password_hash = plain

Then I started emqx on the console:

./bin/emqx console

And in a separate window enabled the username authentication plugin:

./bin/emqx_ctl plugins load emqx_auth_username

I then first tested publishing using the mosquitto command line tools.

Example subscribe using CLI:

mosquitto_sub -t '#' -v -d -u abc -P abc

Then in a separate window, publish using CLI:

mosquitto_pub -h '127.0.0.1' -t 'test' -m 'hello' -u abc -P abc

Verified that authentication is working with no username / password:

$ mosquitto_sub -t '#' -v -d
Client mosq/cnoLLBEkE9hdlnMgKC sending CONNECT
Client mosq/cnoLLBEkE9hdlnMgKC received CONNACK (5)
Connection Refused: not authorised.
Client mosq/cnoLLBEkE9hdlnMgKC sending DISCONNECT

Example ruby publish:

MQTT::Client.connect(
  :host => '127.0.0.1',
  :username => 'abc',
  :password => 'abc',
) do |client|
  client.publish('test', "The time is: #{Time.now}")
end

Example ruby subscribe:

MQTT::Client.connect(
  :host => '127.0.0.1',
  :username => 'abc',
  :password => 'abc',
) do |client|
  client.get('#') do |topic,message|
    puts "#{topic}: #{message}"
  end
end

So I am unable to reproduce your authentication problems with EMQX + Ruby MQTT.

beraybentesen commented 4 years ago

Libraries we are currently using are :

For the EQMX Authentication, we use HTTP Authentication plugin with our internal APIs. (https://github.com/emqx/emqx-auth-http). I can send an email ip / username / password if that would be helpful to produce the scenario.

beraybentesen commented 4 years ago

Update: Arduino mqtt library managed to connect with just IP address. However I had to use setId method.

Update 2: It seems library auto generate id :

clientid=MjkyMzc4NTQ5MDg5NTQ2Mjg4ODIxNDY4NjE0NjQ5NDQ2NDA &username=84520378-1a48-4462-b216-ee38b1543018 &password=wpJSpGTYnvphoKwIgfAa

I manually printed from our endpoints to understand.

:client_id => "id", fixed the connection problem.

beraybentesen commented 4 years ago

@njh Happy to confirm that finally managed to get it working. After settings all default settings, connection worked pretty well. Thank you for spending time on emqx and support.

MQTT::Client.connect( :host => "ip", :port => 1883, :client_id => "abc", :username => "abc", :password => "abc", :keep_alive => 15, :clean_session => false, :ack_timeout => 15, :will_topic =>"abc", :will_payload => '{"one":1,"two":2}', :will_qos => 0, :will_retain => false, :ssl => false

njh commented 4 years ago

I am glad you got it working.

You shouldn't need to pass in all the default options - maybe try deleting them one by one and work out which ones are important for you?

beraybentesen commented 4 years ago

It turns out only ack timeout was necessary. But it was a good experiment to play with other options.