WAMP runtime : changes from dporopat and agregorcic, adding CRA (-s) and changed way to load WAMP conf (-c)
authorEdouard Tisserant
Tue, 09 Jan 2018 15:08:08 +0100
changeset 1893 971de876b1af
parent 1892 daf40a1e7607
child 1894 f224383cc883
WAMP runtime : changes from dporopat and agregorcic, adding CRA (-s) and changed way to load WAMP conf (-c)
- added Challenge Response Authentication,
- use -s commandline switch to give the shared secret.
- WAMP configuration now either given as -c commandline switch
or taken as default wampconf.json in project files.
Beremiz_service.py
runtime/WampClient.py
--- a/Beremiz_service.py	Tue Jan 09 14:52:56 2018 +0100
+++ b/Beremiz_service.py	Tue Jan 09 15:08:08 2018 +0100
@@ -52,6 +52,7 @@
            -t        - enable/disable Twisted web interface (0:disable 1:enable) (default:1)
            -w        - web server port or "off" (default:8009)
            -c        - WAMP client config file or "off" (default:wampconf.json)
+           -s        - WAMP client secret, given as a file or "off"
            -e        - python extension (absolute path .py)
 
            working_dir - directory where are stored PLC files
@@ -70,7 +71,8 @@
 given_ip = None
 port = 3000
 webport = 8009
-wampconf = "wampconf.json"
+wampsecret = None
+wampconf = None
 servicename = None
 autostart = False
 enablewx = True
@@ -105,6 +107,8 @@
         webport = None if a == "off" else int(a)
     elif o == "-c":
         wampconf = None if a == "off" else a
+    elif o == "-s":
+        wampsecret = None if a == "off" else a
     elif o == "-e":
         extensions.append(a)
     else:
@@ -596,9 +600,21 @@
 
     if wampconf is not None:
         try:
-            WC.RegisterWampClient(wampconf)
-            pyruntimevars["wampsession"] = WC.GetSession
-            WC.SetServer(pyroserver)
+            wampconf_project = os.path.join(WorkingDir, "wampconf.json")
+            _wampconf = WC.LoadWampClientConf(wampconf_project) # if project WAMP config is added
+
+            if not _wampconf:
+                # loaded wamp config file path forced parameter -c
+                _wampconf = WC.LoadWampClientConf(wampconf)
+            else:
+                wampconf = wampconf_project
+
+            if _wampconf and _wampconf["url"]:
+                WC.RegisterWampClient(wampconf, wampsecret)
+                pyruntimevars["wampsession"] = WC.GetSession
+                WC.SetServer(pyroserver)
+            else:
+                print(_("WAMP config is not defined."))
         except Exception, e:
             print(_("WAMP client startup failed. "), e)
 
--- a/runtime/WampClient.py	Tue Jan 09 14:52:56 2018 +0100
+++ b/runtime/WampClient.py	Tue Jan 09 15:08:08 2018 +0100
@@ -26,10 +26,13 @@
 from __future__ import print_function
 import json
 
+import os
+import json
 from autobahn.twisted import wamp
 from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS
-from autobahn.wamp import types
+from autobahn.wamp import types, auth
 from autobahn.wamp.serializer import MsgPackSerializer
+from autobahn.wamp.exception import ApplicationError
 from twisted.internet.defer import inlineCallbacks
 from twisted.internet.protocol import ReconnectingClientFactory
 
@@ -66,6 +69,21 @@
 
 
 class WampSession(wamp.ApplicationSession):
+    def onConnect(self):
+        secret = self.config.extra["secret"]
+        if secret:
+            user = self.config.extra["ID"].encode('utf8')
+            self.join(u"Automation", [u"wampcra"], user)
+        else:
+            self.join(u"Automation")
+
+    def onChallenge(self, challenge):
+        if challenge.method == u"wampcra":
+            secret = self.config.extra["secret"].encode('utf8')
+            signature = auth.compute_wcs(secret, challenge.extra['challenge'].encode('utf8'))
+            return signature.decode("ascii")
+        else:
+            raise Exception("don't know how to handle authmethod {}".format(challenge.method))
 
     @inlineCallbacks
     def onJoin(self, details):
@@ -100,22 +118,40 @@
 
 
 def LoadWampClientConf(wampconf):
+    try:
+        WSClientConf = json.load(open(wampconf))
+        return WSClientConf
+    except ValueError, ve:
+        print(_("WAMP load error: "), ve)
+        return None
+    except Exception:
+        return None
 
-    WSClientConf = json.load(open(wampconf))
-    return WSClientConf
+def LoadWampSecret(secretfname):
+    try:
+        WSClientWampSecret = open(secretfname, 'rb').read()
+        return WSClientWampSecret
+    except ValueError, ve:
+        print(_("Wamp secret load error:"), ve)
+        return None
+    except Exception:
+        return None
 
 
-def RegisterWampClient(wampconf):
+def RegisterWampClient(wampconf, secretfname):
 
     WSClientConf = LoadWampClientConf(wampconf)
 
-    # start logging to console
-    # log.startLogging(sys.stdout)
+    if not WSClientConf:
+        print _("WAMP client connection not established!")
+        return
+
+    WampSecret = LoadWampSecret(secretfname)
 
     # create a WAMP application session factory
     component_config = types.ComponentConfig(
         realm=WSClientConf["realm"],
-        extra={"ID": WSClientConf["ID"]})
+        extra=WSClientConf)
     session_factory = wamp.ApplicationSessionFactory(
         config=component_config)
     session_factory.session = WampSession
@@ -124,9 +160,7 @@
     transport_factory = ReconnectingWampWebSocketClientFactory(
         session_factory,
         url=WSClientConf["url"],
-        serializers=[MsgPackSerializer()],
-        debug=False,
-        debug_wamp=False)
+        serializers=[MsgPackSerializer()])
 
     # start the client from a Twisted endpoint
     conn = connectWS(transport_factory)