beremiz

6077e101bb68
Parents 1d7c241a101a
Children fd9bfe601d10
WAMP: IDE generates its own PSK to connect to server.
--- a/Beremiz_cli.py Tue Mar 04 14:36:27 2025 +0100
+++ b/Beremiz_cli.py Tue Mar 04 17:20:26 2025 +0100
@@ -101,6 +101,15 @@
return session.controller.stop_project()
return processor
+@cli.command()
+@pass_session
+@ensure_controller
+def connect(session):
+ """Connect to PLC."""
+ def processor():
+ return session.controller.connect_project()
+ return processor
+
@cli.result_callback()
@pass_session
--- a/CLIController.py Tue Mar 04 14:36:27 2025 +0100
+++ b/CLIController.py Tue Mar 04 17:20:26 2025 +0100
@@ -152,6 +152,11 @@
return 0 if self._Stop() else 1
+ @with_project_loaded
+ @connected
+ def connect_project(self):
+
+ return 0
def finish(self):
global ToDoBeforeQuit
--- a/PSKManagement.py Tue Mar 04 14:36:27 2025 +0100
+++ b/PSKManagement.py Tue Mar 04 17:20:26 2025 +0100
@@ -5,9 +5,13 @@
import os
+from os.path import join, exists
import time
import json
from zipfile import ZipFile
+from binascii import b2a_base64
+
+from util.paths import AppDataPath
# PSK Management Data model :
# [[ID,Desc, LastKnownURI, LastConnect]]
@@ -166,3 +170,25 @@
SaveData(project_path, data)
return data
+
+def GetIDEIdentity():
+ own_keystore = AppDataPath("keystore", "own")
+ if not exists(own_keystore):
+ os.makedirs(own_keystore)
+
+ own_identity = join(own_keystore, "default.psk")
+ if exists(own_identity):
+ ID, _sep, PSK = open(own_identity).read().partition(':')
+ secretstring = PSK.rstrip('\n\r')
+ else:
+ ID = os.urandom(8).hex()
+ # secret string length is 256
+ # b2a_base64 output len is 4/3 input len
+ secret = os.urandom(192) # int(256/1.3333)
+ secretstring = b2a_base64(secret).decode()
+
+ PSKstring = ID+":"+secretstring
+ with open(own_identity, 'w') as f:
+ f.write(PSKstring)
+
+ return ID, secretstring
--- a/connectors/WAMP/__init__.py Tue Mar 04 14:36:27 2025 +0100
+++ b/connectors/WAMP/__init__.py Tue Mar 04 17:20:26 2025 +0100
@@ -51,7 +51,7 @@
class WampSession(wamp.ApplicationSession):
def onConnect(self):
- user = self.config.extra["ID"]
+ user = self.config.extra["IDE_ID"]
self.join(self.config.realm, ["wampcra"], user)
def onChallenge(self, challenge):
@@ -76,7 +76,7 @@
global _WampSession
_WampSession = self
_WampSessionEvent.set()
- print('WAMP session joined for :', self.config.extra["ID"])
+ print('WAMP session joined for :', self.config.extra["IDE_ID"])
def onLeave(self, details):
global _WampSession
@@ -86,17 +86,18 @@
def _WAMP_connector_factory(cls, uri, confnodesroot):
"""
- WAMP://127.0.0.1:12345/path#realm#ID
- WAMPS://127.0.0.1:12345/path#realm#ID
+ WAMP://127.0.0.1:12345/path#realm#PLC_ID
+ WAMPS://127.0.0.1:12345/path#realm#PLC_ID
"""
scheme, location = uri.split("://")
- urlpath, realm, ID = location.split('#')
+ urlpath, realm, PLC_ID = location.split('#')
urlprefix = {"WAMP": "ws",
"WAMPS": "wss"}[scheme]
url = urlprefix+"://"+urlpath
CN = urlpath.split("/")[0].split(":")[0]
try:
- secret = PSK.GetSecret(confnodesroot.ProjectPath, ID)
+
+ IDE_ID, secret = PSK.GetIDEIdentity()
trust_store = Cert.GetCertPath(confnodesroot.ProjectPath, CN)
except Exception as e:
confnodesroot.logger.write_error(
@@ -113,7 +114,7 @@
component_config = types.ComponentConfig(
realm=str(realm),
extra={
- "ID": ID,
+ "IDE_ID": IDE_ID,
"secret": secret
})
session_factory = wamp.ApplicationSessionFactory(
@@ -169,7 +170,7 @@
# reactor.stop()
def WampSessionProcMapper(self, funcname):
- wampfuncname = str('.'.join((ID, funcname)))
+ wampfuncname = str('.'.join((PLC_ID, funcname)))
def catcher_func(*args, **kwargs):
if _WampSession is not None:
--- a/tests/cli_tests/wamp_test.bash Tue Mar 04 14:36:27 2025 +0100
+++ b/tests/cli_tests/wamp_test.bash Tue Mar 04 17:20:26 2025 +0100
@@ -2,7 +2,7 @@
rm -f ./CLI_OK ./PLC_OK ./PLC_CONNECTED
-# Start runtime one first time to generate PSK
+# Start runtime one first time to generate PLC PSK
$BEREMIZPYTHONPATH $BEREMIZPATH/Beremiz_service.py -s psk.txt -n test_wamp_ID -x 0 &
PLC_PID=$!
res=110 # default to ETIMEDOUT
@@ -25,7 +25,38 @@
exit $res
fi
-IFS=':' read -r wamp_ID wamp_secret < psk.txt
+IFS=':' read -r PLC_wamp_ID PLC_wamp_secret < psk.txt
+
+# Prepare test project
+cp -a $BEREMIZPATH/tests/projects/wamp .
+
+# Start CLI one first time to generate IDE PSK
+IDE_PSK=$HOME/.local/share/beremiz/keystore/own/default.psk
+rm -f $IDE_PSK
+$BEREMIZPYTHONPATH $BEREMIZPATH/Beremiz_cli.py -k \
+ --project-home wamp connect &
+CLI_PID=$!
+res=110 # default to ETIMEDOUT
+c=5
+while ((c--)); do
+ if [[ -a $IDE_PSK ]]; then
+ echo got IDE PSK.
+ res=0 # OK success
+ break
+ else
+ echo waiting IDE PSK.... $c
+ sleep 1
+ fi
+done
+
+kill $CLI_PID
+
+if [ "$res" != "0" ] ; then
+ echo timeout generating IDE PSK.
+ exit $res
+fi
+
+IFS=':' read -r IDE_wamp_ID IDE_wamp_secret < $IDE_PSK
# Prepare crossbar server configuration
mkdir -p .crossbar
@@ -34,7 +65,6 @@
-addext "subjectAltName = DNS:localhost" \
-out ./.crossbar/server.crt
-
cat > .crossbar/config.json <<JsonEnd
{
"version": 2,
@@ -87,8 +117,12 @@
"wampcra": {
"type": "static",
"users": {
- "${wamp_ID}": {
- "secret": "${wamp_secret}",
+ "${IDE_wamp_ID}": {
+ "secret": "${IDE_wamp_secret}",
+ "role": "authenticated"
+ },
+ "${PLC_wamp_ID}": {
+ "secret": "${PLC_wamp_secret}",
"role": "authenticated"
}
}
@@ -129,7 +163,7 @@
# Prepare runtime Wamp config
cat > wampconf.json <<JsonEnd
{
- "ID": "${wamp_ID}",
+ "ID": "${PLC_wamp_ID}",
"active": true,
"protocolOptions": {
"autoPingInterval": 60,
@@ -182,12 +216,7 @@
exit $res
fi
-# Prepare test project
-cp -a $BEREMIZPATH/tests/projects/wamp .
-# place PSK so that IDE already knows runtime
-mkdir -p wamp/psk
-cp psk.txt wamp/psk/${wamp_ID}.secret
-# Re-use self-signed server cert for client
+# Re-use self-signed server cert for client in test project
mkdir -p wamp/cert
cp .crossbar/server.crt wamp/cert/localhost.crt
@@ -195,7 +224,7 @@
# used in tests instead of 127.0.0.1
# Use CLI to build transfer and start PLC
-setsid $BEREMIZPYTHONPATH $BEREMIZPATH/Beremiz_cli.py -k \
+$BEREMIZPYTHONPATH $BEREMIZPATH/Beremiz_cli.py -k \
--project-home wamp build transfer run &> >(
echo "Start CLI loop"
while read line; do
--- a/util/paths.py Tue Mar 04 14:36:27 2025 +0100
+++ b/util/paths.py Tue Mar 04 17:20:26 2025 +0100
@@ -61,3 +61,12 @@
Return path of files in Beremiz project
"""
return os.path.join(AbsParentDir(__file__, 1), *names)
+
+def AppDataPath(*names):
+ """
+ Return path of files in Beremiz project
+ """
+ if os.name == "posix":
+ return os.path.join(os.environ["HOME"], ".local", "share", "beremiz", *names)
+
+ return os.path.join(os.environ["APPDATA"], "Beremiz", *names)