- Delete obsolete users

- Alter pairing credentials to allow panel pairing
- Start working on panel workflow
This commit is contained in:
Dorian Zedler 2021-08-23 13:59:38 +02:00
parent 23f4d4ced9
commit c8d5b4a7f3
Signed by: dozedler
GPG key ID: 989DE36109AFA354
7 changed files with 89 additions and 16 deletions

View file

@ -4,17 +4,59 @@ The backend server of MlmAccess
# Workflows # Workflows
## Pairing ## Pairing
###### Actor
A new actor can pair like this: A new actor can pair like this:
1. Connect to the broker using `pair-actor` as username and the pair secret as password 1. Connect to the broker using `pair` as username and the pair secret as password
2. Subscribe to `mlmAccess/pair/response/actor` 2. Subscribe to `mlmAccess/pair/response/actor`
3. Publish its desired ID to `mlmAccess/pair/request/actor` 3. Publish its desired ID to `mlmAccess/pair/request/actor`
4. The backend will publish the password for the actor to `mlmAccess/pair/response/actor` in case of success 4. The backend will publish the password for the actor to `mlmAccess/pair/response/actor` in case of success
5. In case of an error, the backend will publish an empty string to `mlmAccess/pair/response/actor` 5. In case of an error, the backend will publish an empty string to `mlmAccess/pair/response/actor`
6. The actor may now connect using `actor-{id}` as username and the password it got in 4 6. The actor may now connect using `actor-{id}` as username and the password it got in 4
## Actor normal operation ###### Panel
During normal operation (after pairing) the actor has to follow this workflow: A new panel can pair in the same way as a new actor. Every occurence of `actor` as to be replaced by `panel`, though.
1. The actor subscribes to `mlmAccess/actor/{id}/action`
2. The actor publishes its status to `mlmAccess/actor/{id}/status` ## Actor
3. The backend will publish a requested state change to `mlmAccess/actor/{id}/action` The actor should subscribe to:
4. The actor will publish its state to `mlmAccess/actor/{id}/status` to let the backend know that the action was executed successfully - `mlmAccess/actor/{id}/action`
The actor can publish to:
- `mlmAccess/actor/{id}/status`
### Action execution
If the backend requests an action to be executed, the actor follows this workflow:
1. The backend will publish a requested action to `mlmAccess/actor/{id}/action`
2. The actor will publish its state to `mlmAccess/actor/{id}/status` to let the backend know that the action was executed successfully. This will also happen when the state of the actor is unchanged.
### Status change
If the status of the actor changes it follows this workflow:
1. The actor publishes its status to `mlmAccess/actor/{id}/status`
## Panel
### Authentication workflow
The authentication workflow looks like this:
1. The user presents their RFID Chip to the reader
2. The panel publishes the id to `mlmAccess/panel/{id}/authentication/request`
3. The backend pulishes a JSON object to `mlmAccess/panel/{id}/authentication/response` which looks like this:
`{"status": 200, "data": {"fullName": "Max Mustermann", ...}}` the status is an int which can be either 200(success) or 404(id not found)
4. If the status is 200, the panel continues with the normal operation workflow
5. If the status is 404, the panel continues with the initial user registration workflow
### Initial user registration
The initial user registration could work like this:
1. The user inputs its member ID
2. The user inputs its birthdate
3. The panel publishes a JSON object to `mlmAccess/panel/{id}/registration/request` which looks like this:
`{"memberId": "1234", "rfidId": "abcde"}`
4. The backend pulishes a JSON object to `mlmAccess/panel/{id}/registration/response` which looks like this:
`{"status": 200, "data": {"fullName": "Max Mustermann", ...}}` the status is an int which can be either 200(success), 404(memberId not found) or 401(authentication failed / rfidId not found)
5. If the status is 200, the panel continues with the normal operation workflow
6. Otherwise, the panel shows an error and goes back to idle.
### Normal operation
The normal operation after authentication looks like this:
1. The user enters the id of the actor they want to unlock
2. The panel publishes a JSON object to `mlmAccess/panel/{id}/actor/request` which looks like this:
`{"rfidId": "abcde", "actorId": "101"}`
4. The backend pulishes a JSON object to `mlmAccess/panel/{id}/registration/response` which looks like this:
`{"status": 200}` the status is an int which can be either 200(success), 404(actor id not found) or 401(authentication failed / rfidID not found), 403(forbidden)
5. The panel gives Feedback to the user and goes back to idle

View file

@ -90,6 +90,21 @@ class MaDbHelper:
return users return users
def deleteUser(self, username):
if not self.userExists(username):
return False
query = "DELETE FROM `vmq_auth_acl` WHERE username=%s;"
self.mysqlCur.execute(
query,
(username)
)
self.mysqlConn.commit()
return True
def _updateUser(self, username, password, publishAclPatterns, subscribeAclPatterns): def _updateUser(self, username, password, publishAclPatterns, subscribeAclPatterns):
query = """ query = """

17
backend/mlmAccess.py Normal file → Executable file
View file

@ -1,3 +1,5 @@
#!/usr/bin/python3
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
from dbHelper import MaDbHelper from dbHelper import MaDbHelper
from pairingHandler import MaPairingHandler from pairingHandler import MaPairingHandler
@ -23,13 +25,17 @@ class MlmAccess:
self._db = MaDbHelper(self._config) self._db = MaDbHelper(self._config)
initUsers = [ initUsers = [
("backend", self._config["MQTT_BACKEND_PASSWORD"], ["mlmAccess/#"], ["mlmAccess/#"]), ("backend", self._config["MQTT_BACKEND_PASSWORD"], ["mlmAccess/#"], ["mlmAccess/#"]),
("pair-actor", self._config["PAIR_SECRET"], ["mlmAccess/pair/request/actor"], ["mlmAccess/pair/response/actor"]) ("pair", self._config["PAIR_SECRET"], ["mlmAccess/pair/request/#"], ["mlmAccess/pair/response/#"])
] ]
for username, password, publishAclPatterns, subscribeAclPatterns in initUsers: for username, password, publishAclPatterns, subscribeAclPatterns in initUsers:
if not self._db.addUser(username, password, publishAclPatterns, subscribeAclPatterns): if not self._db.addUser(username, password, publishAclPatterns, subscribeAclPatterns):
self._db.updateUser(username, password, publishAclPatterns, subscribeAclPatterns) self._db.updateUser(username, password, publishAclPatterns, subscribeAclPatterns)
obsoleteSystemUsers = ["pair-actor"]
for username in obsoleteSystemUsers:
self._db.deleteUser(username)
def _initMqtt(self): def _initMqtt(self):
logging.info("Initializing MQTT") logging.info("Initializing MQTT")
self._mqtt = client = mqtt.Client(client_id="backend") self._mqtt = client = mqtt.Client(client_id="backend")
@ -51,8 +57,13 @@ class MlmAccess:
for user in self._db.getAllUsers(): for user in self._db.getAllUsers():
if user.startswith("actor-"): if user.startswith("actor-"):
actorSubject = f"mlmAccess/actor/{user.replace('actor-', '')}/status" actorSubject = f"mlmAccess/actor/{user.replace('actor-', '')}/status"
logging.info(f"* {actorSubject}") elif user.startswith("panel-"):
client.subscribe(actorSubject) actorSubject = "mlmAccess/panel"
else:
continue
logging.info(f"* {actorSubject}")
client.subscribe(actorSubject)
# call hooks of child objects # call hooks of child objects
self._pairingHanlder._mqttOnConnect(client, userdata, flags, rc) self._pairingHanlder._mqttOnConnect(client, userdata, flags, rc)

View file

@ -8,6 +8,9 @@ class MaPairingHandler:
def handlePairingRequest(self, topic, message): def handlePairingRequest(self, topic, message):
if "actor" in topic: if "actor" in topic:
self._handleActorPairRequest(message) self._handleActorPairRequest(message)
elif "panel" in topic:
pass
#self.
else: else:
logging.warn(f"Invalid pairing request: {topic}, {message}, Device type not know.") logging.warn(f"Invalid pairing request: {topic}, {message}, Device type not know.")

View file

@ -3,7 +3,9 @@ import logging, coloredlogs
coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s') coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s')
PAIR_ID = "101" PAIR_ID = "1"
DEVICE_TYPE = "actor" # actor or panel
PAIR_SECRET = "pair-secret"
def on_connect(client, userdata, flags, rc): def on_connect(client, userdata, flags, rc):
global PAIR_ID global PAIR_ID
@ -14,10 +16,10 @@ def on_connect(client, userdata, flags, rc):
logging.info("Successfully connected to MQTT broker") logging.info("Successfully connected to MQTT broker")
client.subscribe("mlmAccess/pair/response/actor") client.subscribe(f"mlmAccess/pair/response/{DEVICE_TYPE}")
logging.info("Requesting pairing") logging.info("Requesting pairing")
client.publish("mlmAccess/pair/request/actor", PAIR_ID) client.publish(f"mlmAccess/pair/request/{DEVICE_TYPE}", PAIR_ID)
def on_message(client, userdata, message): def on_message(client, userdata, message):
messageContent = str(message.payload.decode("utf-8")) messageContent = str(message.payload.decode("utf-8"))
@ -29,8 +31,8 @@ def on_message(client, userdata, message):
logging.error("Pairing was not successfull!") logging.error("Pairing was not successfull!")
exit(1) exit(1)
client = mqtt.Client(client_id="pair-actor") client = mqtt.Client(client_id=f"pair")
client.username_pw_set("pair-actor", "pair-actor") client.username_pw_set(f"pair", f"pair-secret")
client.on_connect = on_connect client.on_connect = on_connect
client.on_message = on_message client.on_message = on_message

View file

@ -5,6 +5,6 @@ export MLMACCESS_MYSQL_PASSWORD=MlmAccess
export MLMACCESS_MYSQL_DATABASE=MlmAccess export MLMACCESS_MYSQL_DATABASE=MlmAccess
export MLMACCESS_MYSQL_HOST=localhost export MLMACCESS_MYSQL_HOST=localhost
export MLMACCESS_MQTT_HOST=localhost export MLMACCESS_MQTT_HOST=localhost
export MLMACCESS_PAIR_SECRET=pair-actor export MLMACCESS_PAIR_SECRET=pair-secret
python3 backend/mlmAccess.py python3 backend/mlmAccess.py