简体   繁体   English

针对 WSO2 消息代理的 MQTT Oauth2 身份验证

[英]MQTT Oauth2 authentication against WSO2 Message broker

I want to get a MQTT broker to authenticate with an OAUTH2 server.我想让 MQTT 代理向 OAUTH2 服务器进行身份验证。

I am coding the MQTT client in Python 3 using Paho.我正在使用 Paho 在 Python 3 中编写 MQTT 客户端。

I have succesfullly connected to the IS to obtain the access token.我已成功连接到 IS 以获取访问令牌。

I have succeesfully sent json messages through the MQTT Message Broker.我已通过 MQTT 消息代理成功发送 json 消息。

I have configured WSO2 Message Broker and Identity Server to work together following the oficial instructions.我已按照官方说明配置 WSO2 Message Broker 和 Identity Server 一起工作。

When I try to connect with the authentication information I cannot get to send correctly the acces token to be processed.当我尝试连接身份验证信息时,我无法正确发送要处理的访问令牌。

client = mqtt.Client("oauthmqttcli") 
client.connect(broker_address, port=1883) #connect to broker
client.username_pw_set(access_token)
client.publish("test","{'a':'b'}")

In the logs I see this:在日志中我看到了这个:

TID: [] [] [2018-09-21 10:56:33,019] ERROR {org.dna.mqtt.wso2.MqttLogExceptionHandler} -  ValueEvent exception occurred on disruptor. {org.dna.mqtt.wso2.MqttLogExceptionHandler}
java.lang.NullPointerException
        at org.dna.mqtt.moquette.messaging.spi.impl.ProtocolProcessor.processPublish(ProtocolProcessor.java:390)
        at org.dna.mqtt.moquette.messaging.spi.impl.SimpleMessaging.onEvent(SimpleMessaging.java:171)
        at org.dna.mqtt.moquette.messaging.spi.impl.SimpleMessaging.onEvent(SimpleMessaging.java:47)
        at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:128)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
TID: [] [] [2018-09-21 10:56:33,026] ERROR {org.dna.mqtt.moquette.server.netty.metrics.MessageMetricsHandler} -  Connection reset by peer {org.dna.mqtt.moquette.server.netty.metrics.MessageMetricsHandler}
java.io.IOException: Connection reset by peer
        at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
        at sun.nio.ch.IOUtil.read(IOUtil.java:192)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
        at io.netty.buffer.UnpooledUnsafeDirectByteBuf.setBytes(UnpooledUnsafeDirectByteBuf.java:446)
        at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:881)
        at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:225)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:119)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
        at java.lang.Thread.run(Thread.java:748)
TID: [] [] [2018-09-21 10:56:33,027]  INFO {org.dna.mqtt.moquette.messaging.spi.impl.ProtocolProcessor} -  Lost connection with client oauthmqttcli {org.dna.mqtt.moquette.messaging.spi.impl.ProtocolProcessor}
TID: [] [] [2018-09-21 10:56:33,027]  WARN {org.dna.mqtt.moquette.messaging.spi.impl.ProtocolProcessor} -  MQTTAuthorizationSubject for client ID oauthmqttcli is not removed since the entry does not exist {org.dna.mqtt.moquette.messaging.spi.impl.ProtocolProcessor}

How can I send the access token to the server to be accessed?如何将访问令牌发送到要访问的服务器? Where is the Message Broker searching for the access token? Message Broker 在哪里搜索访问令牌?

I finally found it.我终于找到了。 The access token must be sent as a username with a blank password.访问令牌必须作为带有空白密码的用户名发送。

client = mqtt.Client("dev7") 
client.username_pw_set(username=access_token,password="")
client.connect(broker_address, port=broker_port) #connect to broker
print("Connected")
client.publish("test","{'c':'Payload!'}")
print("Sending message")

I was working on a prototype for my research project using a similar setup as yours with the only exception that I am using Keycloak as my authentication server (AS).我正在使用与您的设置类似的设置为我的研究项目制作原型,唯一的例外是我使用 Keycloak 作为我的身份验证服务器 (AS)。 I have managed to publish and subscribe to messages via broker without the authentication mechanism in place and have also successfully obtained the access token and token validation output from the keycloak validation endpoint.我已经设法在没有身份验证机制的情况下通过代理发布和订阅消息,并且还成功地从 keycloak 验证端点获得了访问令牌和令牌验证输出。

However, when I implemented above sequence of tasks via a python script to authenticate the mqtt client so it can publish/subscribe.但是,当我通过 python 脚本实现上述任务序列以验证 mqtt 客户端以便它可以发布/订阅时。 I noticed that it is able to establish a connection but at the client end the connection closes.我注意到它能够建立连接,但在客户端连接关闭。 I suspect that this is due to the token not getting passed either due to wrong/invalid parameters or there is an issue with my token validation function我怀疑这是由于错误/无效参数或我的令牌验证功能存在问题而导致令牌未通过

Now, I would like you to look at my code and maybe tally it against yours to see if I am going wrong somewhere with token validation in the script.现在,我希望您查看我的代码,并可能将其与您的代码进行对比,看看我是否在脚本中的令牌验证某处出错。 I have been toiling with this for days!这几天我一直在苦苦挣扎! Thanks in advance!提前致谢!

import paho.mqtt.client as paho
import time
import sys
import json
import requests
from requests.auth import HTTPBasicAuth
broker="broker.lailaafreen.com"
port= 1884
sub_topic="test"

#-------------------------------------------------Function to get access token-----------------------------------------------------#

def get_token():
url = "https://gk.lailaafreen.com:8443/auth/realms/LailaRealm/protocol/openid-connect/token"

    payload = 'grant_type=client_credentials'
    headers = {
    'Content-Type':'application/x-www-form-urlencoded'
    }
    response = requests.post(url, headers=headers, data=payload, auth=HTTPBasicAuth("Raspi","24dce5b3-8cf1-41f7-9070-aa8a8e58c09f"))
    token = json.loads(response.text)
    return token["access_token"] 

mytoken = get_token()
print(mytoken)

#-----------------------------------------------------------Callback functions------------------------------------------------------#
def on_connect(client,userdata,flags, rc):
   print("Connected with code " +str(rc))
   client.subscribe(sub_topic)

def on_subscribe(client, userdata, mid, granted_qos):   #create function for callback
   print("subscribed with qos",granted_qos, "\n")
   pass
def on_message(client, userdata, message):
    print("message received  "  ,str(message.payload.decode("utf-8")))
def on_publish(client,userdata,mid):   #create function for callback
   print("data published mid=",mid, "\n")
   pass
def on_disconnect(client, userdata, rc):
   print("client disconnected")

#------------------------------------------------------------Connect to broker------------------------------------------------------#
client= paho.Client("Laila_Raspi",transport="websockets")       #create client object
#client.username_pw_set(username= "mytoken", password= "")
client.on_connect = on_connect
client.on_subscribe = on_subscribe       #assign function to callback
client.on_publish = on_publish        #assign function to callback
client.on_message = on_message        #assign function to callback
client.on_disconnect = on_disconnect

print("connecting to broker ",broker,"on port",port)
#client.connect("ws://broker.lailaafreen.com:1884")
client.connect(broker,port,60)           #establish connection

#--------------------------------Token validation-----------------------------------# 

def get_valid(token):
    url =  "https://gk.lailaafreen.com:8443/auth/realms/LailaRealm/protocol/openid-connect/userinfo"
#    url =  "https://gk.lailaafreen.com:8443/auth/realms/LailaRealm/protocol/openid-connect/token/introspect"
    payload = {}
#    payload = 'client_secret=24dce5b3-8cf1-41f7-9070-aa8a8e58c9f'
    headers = {'content-type': "multipart/form-data", 'Authorization': 'Bearer ' +mytoken}
    response = requests.post(url, headers=headers)
    valid = json.loads(response.text)
    return valid
print(get_valid(get_token()))

#--------------------------------Publish/Subscribe----------------------------------#

client.loop_start()
print("subscribing to ",sub_topic)
#client.subscribe(sub_topic)
time.sleep(3)
client.publish("test","message from Laila's raspberry")    #publish
time.sleep(4) 

client.disconnect()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM