From 2d1841779388136cd0c7e657ef02ae7d023ae252 Mon Sep 17 00:00:00 2001 From: Dorian Zedler Date: Wed, 18 Aug 2021 18:48:17 +0200 Subject: [PATCH] Initial commit --- .gitignore | 1 + backend/__pycache__/dbHelper.cpython-38.pyc | Bin 0 -> 2458 bytes backend/__pycache__/mqttClient.cpython-38.pyc | Bin 0 -> 1491 bytes backend/dbHelper.py | 96 ++++++++++++++++++ backend/mlmAccess.py | 48 +++++++++ docker-compose.yml | 45 ++++++++ mock-actor/mock-actor.py | 28 +++++ 7 files changed, 218 insertions(+) create mode 100644 .gitignore create mode 100644 backend/__pycache__/dbHelper.cpython-38.pyc create mode 100644 backend/__pycache__/mqttClient.cpython-38.pyc create mode 100644 backend/dbHelper.py create mode 100644 backend/mlmAccess.py create mode 100644 docker-compose.yml create mode 100644 mock-actor/mock-actor.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3af0ccb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/data diff --git a/backend/__pycache__/dbHelper.cpython-38.pyc b/backend/__pycache__/dbHelper.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..71bdff4df417d6fac3ab41816ba6ebb171a39f28 GIT binary patch literal 2458 zcmah~OK;mo5Z+xrM9Yt)PMWmoi%lO0fgn1xMh|%)MkFT&Y{jtb1`yEF6ql~$P^7#| zrm-NOl55d(Z_+V;r^mhaRP@+e5EPwRO0;YjD2bh&eb3DI&F=2vVwJ%6*UBfs$~+-| zU}N?(pz#ojya|F6PGiz8YTBlc31{4RO}O!jwHc=^;+cQKJkktN&VCFU52469h={Z) zC%A&M*Q9N5gPTyB+~PLW7O!vzYMamTD%2G|&ljL}_#$6|dX8U$lP;_3W>D`uiQ;}F zLJHeXKh!Hw9zl^`gUHAs#k1fXIEh=oSVQ8oAvt6tV@yCdIe{JRrkab>Fo+LQnJH7G zX{P2jOWh9i{52XB=E58c#(xNNV*o%zIIi$=a4ke-c5j z*NsG!)V7YZgEXm?w$(a8_&iE@jZflnr+=&*-|r^f%=ayf!x9KWZOV%OonsHKoW}3Y zbnb;fVlZ_eO;9w%Y_L*wC*R{JiA0b^(iPEB-W3sdv!D}0J4m>TF_PunruI-=f_(}N z9Tv+VR7G1_@1T(qsY0y5@~m~}NWBxHC)3Xc1sGcxw+70PjL49VsaQfYIXeNA59x>v zEp7}c{DAn#7#d@$YjaHZ?J=XU?$8`rV?qfxfdy7`ZSdQAv(?z%ao3wWPu;y2y(2%! zvjaZ}<30D*UN6m)te>qQX%FduXSsH2r;8OUIbyze7 zzXXNT6UJjHc5sqO4XSqOO+d8Q7S_y~H%XCRaWYz)mY&{R_#FD=$w^O!zZ&HH(uLo#CgJ!{6~k6|nE z2?|8yoY6q0a+N+9Eg-Z?FSD~Ym$S~;jI$jmdg-^I06>^{Xs@MHj!jaIf#u-CzBvKS z7@0ch3NHq~mKVkDR(*A+aUQF3xYgL1Nv`{6^JH%}(*V#5$p(GpP6hm@Neg3l%Rz`B zrk19H_y9G`A@L!K8z}VkRo-C&@mhx>uYw@Vv_({tbl;zL_=rKkt`2_w>UlAAnM<_Dp5Mm6s`_7xa~RDAPn)Jn!`} z$ME`T&rgiO`>B0t(%2088v&et&MFPS53ouW>~!c79en=3W;MMkK7*M5zOSmj-%EKO zqrTw#M|ltzBjO6|ED$$+Z|Q6jUtkkKExZ1&)EI b_(BN}1$NAMRqg@-FRXfiPp!oLU@P`7Xn{x~ literal 0 HcmV?d00001 diff --git a/backend/__pycache__/mqttClient.cpython-38.pyc b/backend/__pycache__/mqttClient.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..780374ba6875943806c870af8ff62874e6f31897 GIT binary patch literal 1491 zcmZux&5qkP5GM6+)!zJI+W<`i_|P77$SOG$=ph@V*q}KSYb+4-q5>6Uk-OGL6160i zU?a8$_yntZc`ehXNH{N@cU-;+iVsR7_%Q9Wk0%v{Ef=~ut9kN zQ+*E$BaD`$q86c~vJy(kE5a;hzbDMTu@aln*CcX2!b!5oaorylC@)}|NSq{;k;Gz@ zS?>vW+RTA}hq=syf0y|XDd?xC+3A(mCuPBFozuN=7|nxuf)W3KMUzX4(f*trN|9&fN+@0Y?i2Fy8KfFbdZ&VC zCEoC`K16MhlRK^Avd$`=Ht$l!bsvg49YY(r;!0%~ymuQ})H?CUy<}Pn(WK`>^0!<@ zR_`cYp7-96<_99bf}8*OHC~B|$4tl~tK*jwWr;wx@Hbv)w=$ zr{VDz5H!@7rfcBk0WsW|3cCRYHCfYJsJ0Cq?NBW{yN%p!EZi}C`HSx1$v_Ba^LK?_ z%_UcDspq+1eBK?tZkH;T#d4%ei>AoCN7e4hNOlY^ji?om4eQ;*vvye)YK1-{4M_Fi z``s75S1r`V;F{P^pFE8m8NdsBTWKf^H739lzZt?tuAIQW#E$F(tOJ(mtas1L>_R1$ z%ngUbGR1?~0QX=j)5G+x9nu3D((b{(aQ|FCITE!UDDOJxIVdCYw&@xRQ6A7`_S(L5 zM%e**M4h=HduTU^dyDSg78J>IUc3e1JGa&6kALb8wmSx^<8HduuY@}84!4@*IxFfq zKKMBD4O$ZG3Lwg^OOdhOV;l)gToWj$iq@MJ(>1lnpT3fB~R0SnxL^$E56b_M_d literal 0 HcmV?d00001 diff --git a/backend/dbHelper.py b/backend/dbHelper.py new file mode 100644 index 0000000..8b05a57 --- /dev/null +++ b/backend/dbHelper.py @@ -0,0 +1,96 @@ +import pymysql +import json + +class MaDbHelper: + def __init__(self): + self.mysqlConn = pymysql.connect(host='localhost', + user='root', + passwd='MlmAccess', + db='MlmAccess', + port=4306) + + self.mysqlCur = self.mysqlConn.cursor() + + def _initDb(self): + """ + Generates required tables and users + """ + + """ + CREATE TABLE vmq_auth_acl + ( + mountpoint VARCHAR(10) NOT NULL, + client_id VARCHAR(128) NOT NULL, + username VARCHAR(128) NOT NULL, + password VARCHAR(128), + publish_acl TEXT, + subscribe_acl TEXT, + CONSTRAINT vmq_auth_acl_primary_key PRIMARY KEY (mountpoint, client_id, username) + ) + """ + + def addUser(self, username, password, publishAclPatterns, subscribeAclPatterns): + + if self.userExists(username): + return False + + query = "INSERT INTO `vmq_auth_acl` (`mountpoint`, `client_id`, `username`, `password`, `publish_acl`, `subscribe_acl`) VALUES (%s, %s, %s, PASSWORD(%s), %s, %s);" + + self.mysqlCur.execute( + query, + ( + "", + username, + username, + password, + self._convertAclPatternList(publishAclPatterns), + self._convertAclPatternList(subscribeAclPatterns) + ) + ) + + self.mysqlConn.commit() + + return True + + def userExists(self, username): + query = "SELECT username FROM `vmq_auth_acl` WHERE username=%s" + + self.mysqlCur.execute( + query, + (username) + ) + + result = self.mysqlCur.fetchone() + return result is not None + + + def updateUser(self, username, password, publishAclPatterns, subscribeAclPatterns): + if self.userExists(username): + return self._updateUser(username, password, publishAclPatterns, subscribeAclPatterns) + else: + return False + + def _updateUser(self, username, password, publishAclPatterns, subscribeAclPatterns): + + query = """ + UPDATE `vmq_auth_acl` + SET `password`=PASSWORD(%s), `publish_acl`=%s, `subscribe_acl`=%s + WHERE `username`=%s; + """ + + self.mysqlCur.execute( + query, + ( + password, + self._convertAclPatternList(publishAclPatterns), + self._convertAclPatternList(subscribeAclPatterns), + username + ) + ) + + self.mysqlConn.commit() + + def _convertAclPatternList(self, patternList): + patternMapLabda = lambda pattern: {"pattern": pattern} + patternList = list(map(patternMapLabda, patternList)) + return json.dumps(patternList) \ No newline at end of file diff --git a/backend/mlmAccess.py b/backend/mlmAccess.py new file mode 100644 index 0000000..a8f93d5 --- /dev/null +++ b/backend/mlmAccess.py @@ -0,0 +1,48 @@ +import paho.mqtt.client as mqtt +from dbHelper import MaDbHelper + +class MlmAccess: + def __init__(self): + self._initDb() + self._initMqtt() + + def _initDb(self): + self.db = MaDbHelper() + initUsers = [ + ("backend", "backend", ["mlmAccess/#"], ["mlmAccess/#"]), + ("pair-actor", "pair-actor", ["mlmAccess/pair/request/actor"], ["mlmAccess/pair/response/actor"]) + ] + + for username, password, publishAclPatterns, subscribeAclPatterns in initUsers: + if not self.db.addUser(username, password, publishAclPatterns, subscribeAclPatterns): + self.db.updateUser(username, password, publishAclPatterns, subscribeAclPatterns) + + def _initMqtt(self): + self.mqtt = client = mqtt.Client(client_id="backend") + self.mqtt.username_pw_set("backend", "backend") + + self.mqtt.on_connect = self._mqttOnConnect + self.mqtt.on_message = self._mqttOnMessage + + print("connecting to broker") + print(self.mqtt.connect("localhost", 1883, 60)) + + self.mqtt.loop_forever() + + def _mqttOnConnect(self, client, userdata, flags, rc): + print("Connected with result code "+str(rc)) + + if rc != 0: + print("") + + print(client.subscribe("mlmAccess/pair/request/actor")) + + def _mqttOnMessage(self, client, userdata, message): + print("message received " ,str(message.payload.decode("utf-8"))) + print("message topic=",message.topic) + print("message qos=",message.qos) + print("message retain flag=",message.retain) + + +if __name__ == "__main__": + MlmAccess() \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b09ee00 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,45 @@ +services: + broker: + image: vernemq/vernemq:1.11.0 + environment: + - DOCKER_VERNEMQ_ACCEPT_EULA=yes + - DOCKER_VERNEMQ_PLUGINS__VMQ_PASSWD=off + - DOCKER_VERNEMQ_PLUGINS__VMQ_ACL=off + - DOCKER_VERNEMQ_PLUGINS__VMQ_DIVERSITY=on + - DOCKER_VERNEMQ_VMQ_DIVERSITY__AUTH_MYSQL__ENABLED=on + - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__HOST=mysql-server + - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PORT=3306 + - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__USER=root + - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PASSWORD=MlmAccess + - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__DATABASE=MlmAccess + - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PASSWORD_HASH_METHOD=password + ports: + - 1883:1883 + - 8883:8883 + - 8888:8888 + volumes: + - ./data/vernemq/data:/vernemq/data + - ./data/vernemq/log:/vernemq/log + + mysql-server: + image: mariadb + restart: always + command: --default-authentication-plugin=mysql_native_password + environment: + - MYSQL_ROOT_PASSWORD=MlmAccess + - MARIADB_DATABASE=MlmAccess + volumes: + - "./data/mysql:/var/lib/mysql" + ports: + - 4306:3306 + + phpmyadmin: + image: phpmyadmin/phpmyadmin + restart: always + environment: + - PMA_HOST=mysql-server + - PMA_USER=root + - PMA_PASSWORD=MlmAccess + - UPLOAD_LIMIT=512M + ports: + - "4081:80" diff --git a/mock-actor/mock-actor.py b/mock-actor/mock-actor.py new file mode 100644 index 0000000..9f0ac84 --- /dev/null +++ b/mock-actor/mock-actor.py @@ -0,0 +1,28 @@ +import paho.mqtt.client as mqtt + +# The callback for when the client receives a CONNACK response from the server. +def on_connect(client, userdata, flags, rc): + print("Connected with result code "+str(rc)) + # Subscribing in on_connect() means that if we lose the connection and + # reconnect then subscriptions will be renewed. + print("Subscribing to topic","mlmAccess/pair/response/actor") + print(client.subscribe("mlmAccess/pair/response/actor")) + print("Publishing message to topic","mlmAccess/pair/request/actor") + print(client.publish("mlmAccess/pair/request/actor", "101")) + +def on_message(client, userdata, message): + print("message received " ,str(message.payload.decode("utf-8"))) + print("message topic=",message.topic) + print("message qos=",message.qos) + print("message retain flag=",message.retain) + +client = mqtt.Client(client_id="pair-actor") +client.username_pw_set("pair-actor", "pair-actor") + +client.on_connect = on_connect +client.on_message = on_message + +print("connecting to broker") +print(client.connect("localhost", 1883, 60)) + +client.loop_forever() \ No newline at end of file