From 1210f84664933371c03d9c53832474d5084b2dbe Mon Sep 17 00:00:00 2001 From: NaruX Date: Thu, 8 Mar 2018 15:27:46 +0100 Subject: [PATCH] =?UTF-8?q?IP=20Pr=C3=BCfung=20f=C3=BCr=20XML-RPC=20begonn?= =?UTF-8?q?en.=20Pr=C3=BCft=20lediglich=20auf=20IP=20und=20noch=20keine=20?= =?UTF-8?q?Level?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/helper.html | 221 +++++++++++++++++++++++++++++++++++++ doc/index.html | 6 + doc/proginit.html | 32 ------ doc/revpipyload.html | 50 +-------- doc/xrpcserver.html | 151 +++++++++++++++++++++++++ eric-revpipyload.api | 20 +++- eric-revpipyload.bas | 2 + revpipyload.e4p | 4 +- revpipyload/helper.py | 66 +++++++++++ revpipyload/revpipyload.py | 16 +-- revpipyload/xrpcserver.py | 88 +++++++++++++++ 11 files changed, 559 insertions(+), 97 deletions(-) create mode 100644 doc/helper.html create mode 100644 doc/xrpcserver.html create mode 100644 revpipyload/xrpcserver.py diff --git a/doc/helper.html b/doc/helper.html new file mode 100644 index 0000000..ffb07cc --- /dev/null +++ b/doc/helper.html @@ -0,0 +1,221 @@ + + +helper + + + +

+helper

+

+Helperfunktionen fuer das gesamte RevPiPyLoad-System. +

+

+Global Attributes

+ + +
None
+

+Classes

+ + + + + +
IpAclManagerVerwaltung fuer IP Adressen und deren ACL Level.
+

+Functions

+ + + + + + + + + + + + + + +
_ipmatchPrueft IP gegen ACL List und gibt ACL aus.
_setuprtKonfiguriert Programm fuer den RT-Scheduler.
_zeroprocimgSetzt Prozessabbild auf NULL.
refullmatchre.fullmatch wegen alter python version aus wheezy nachgebaut.
+

+ +

IpAclManager

+

+Verwaltung fuer IP Adressen und deren ACL Level. +

+

+Derived from

+None +

+Class Attributes

+ + +
acl
+

+Class Methods

+ + +
None
+

+Methods

+ + + + + + + + + + + + + + + + + +
IpAclManagerInit IpAclManager class.
__get_aclGetter fuer den rohen ACL-String.
__refullmatchre.fullmatch wegen alter python version aus wheezy nachgebaut.
__set_aclUebernimmt neue ACL-Liste fuer die Ausertung der Level.
get_acllevelPrueft IP gegen ACL List und gibt ACL-Wert aus.
+

+Static Methods

+ + +
None
+ +

+IpAclManager (Constructor)

+IpAclManager(acl=None, minlevel=0, maxlevel=1) +

+Init IpAclManager class. +

+
acl
+
+ACL Liste fuer Berechtigungen als +
+
+

+IpAclManager.__get_acl

+__get_acl() +

+Getter fuer den rohen ACL-String. + return ACLs als +

+

+IpAclManager.__refullmatch

+__refullmatch(regex, string) +

+re.fullmatch wegen alter python version aus wheezy nachgebaut. +

+
regex
+
+RegEx Statement +
string
+
+Zeichenfolge gegen die getestet wird +
+
+
Returns:
+
+True, wenn komplett passt sonst False +
+
+

+IpAclManager.__set_acl

+__set_acl(value) +

+Uebernimmt neue ACL-Liste fuer die Ausertung der Level. +

+
value
+
+Neue ACL-Liste als +
+
+

+IpAclManager.get_acllevel

+get_acllevel(ipaddress) +

+Prueft IP gegen ACL List und gibt ACL-Wert aus. +

+
ipaddress
+
+zum pruefen +
+
+
Returns:
+
+int() ACL Wert oder -1 wenn nicht gefunden +
+
+
Up
+

+ +

_ipmatch

+_ipmatch(ipaddress, dict_acl) +

+Prueft IP gegen ACL List und gibt ACL aus. +

+
ipaddress
+
+zum pruefen +
dict_acl
+
+ACL Dict gegen die IP zu pruefen ist +
+
+
Returns:
+
+int() ACL Wert oder -1 wenn nicht gefunden +
+
+
Up
+

+ +

_setuprt

+_setuprt(pid, evt_exit) +

+Konfiguriert Programm fuer den RT-Scheduler. +

+
pid
+
+PID, der angehoben werden soll +
+
+
Returns:
+
+None +
+
+
Up
+

+ +

_zeroprocimg

+_zeroprocimg() +

+Setzt Prozessabbild auf NULL. +

+
Up
+

+ +

refullmatch

+refullmatch(regex, string) +

+re.fullmatch wegen alter python version aus wheezy nachgebaut. +

+
regex
+
+RegEx Statement +
string
+
+Zeichenfolge gegen die getestet wird +
+
+
Returns:
+
+True, wenn komplett passt sonst False +
+
+
Up
+
+ \ No newline at end of file diff --git a/doc/index.html b/doc/index.html index 51a6d4c..eb76236 100644 --- a/doc/index.html +++ b/doc/index.html @@ -13,6 +13,9 @@ Table of contents Modules + + + @@ -30,6 +33,9 @@ Modules + + +
helperHelperfunktionen fuer das gesamte RevPiPyLoad-System.
logsystem Modul fuer die Verwaltung der Logdateien.
revpipyload Revolution Pi Python PLC Loader.
xrpcserverXML-RPC Server anpassungen fuer Absicherung.
\ No newline at end of file diff --git a/doc/proginit.html b/doc/proginit.html index ecfaf75..92782af 100644 --- a/doc/proginit.html +++ b/doc/proginit.html @@ -23,12 +23,6 @@ Classes Functions - - - - - - @@ -37,32 +31,6 @@ Functions
_setuprtKonfiguriert Programm fuer den RT-Scheduler.
_zeroprocimgSetzt Prozessabbild auf NULL.
cleanup Clean up program.


- -

_setuprt

-_setuprt(pid, evt_exit) -

-Konfiguriert Programm fuer den RT-Scheduler. -

-
pid
-
-PID, der angehoben werden soll -
-
-
Returns:
-
-None -
-
-
Up
-

- -

_zeroprocimg

-_zeroprocimg() -

-Setzt Prozessabbild auf NULL. -

-
Up
-

cleanup

cleanup() diff --git a/doc/revpipyload.html b/doc/revpipyload.html index 4197674..d7a7855 100644 --- a/doc/revpipyload.html +++ b/doc/revpipyload.html @@ -45,13 +45,7 @@ Classes

Functions

- - - - - - - +
_ipmatchPrueft IP gegen ACL List und gibt ACL aus.
refullmatchre.fullmatch wegen alter python version aus wheezy nachgebaut.
None


@@ -505,47 +499,5 @@ Statuscode:
Up
-

- -

_ipmatch

-_ipmatch(ipaddress, dict_acl) -

-Prueft IP gegen ACL List und gibt ACL aus. -

-
ipaddress
-
-zum pruefen -
dict_acl
-
-ACL Dict gegen die IP zu pruefen ist -
-
-
Returns:
-
-int() ACL Wert oder -1 wenn nicht gefunden -
-
-
Up
-

- -

refullmatch

-refullmatch(regex, string) -

-re.fullmatch wegen alter python version aus wheezy nachgebaut. -

-
regex
-
-RegEx Statement -
string
-
-Zeichenfolge gegen die getestet wird -
-
-
Returns:
-
-True, wenn komplett passt sonst False -
-
-
Up

\ No newline at end of file diff --git a/doc/xrpcserver.html b/doc/xrpcserver.html new file mode 100644 index 0000000..cfabcee --- /dev/null +++ b/doc/xrpcserver.html @@ -0,0 +1,151 @@ + + +xrpcserver + + + +

+xrpcserver

+

+XML-RPC Server anpassungen fuer Absicherung. +

+

+Global Attributes

+ + +
None
+

+Classes

+ + + + + + + + +
SaveXMLRPCRequestHandlerVerwaltet die XML-Requests und prueft Berechtigungen.
SaveXMLRPCServerErstellt einen erweiterten XMLRPCServer.
+

+Functions

+ + +
None
+

+ +

SaveXMLRPCRequestHandler

+

+Verwaltet die XML-Requests und prueft Berechtigungen. +

+

+Derived from

+SimpleXMLRPCRequestHandler +

+Class Attributes

+ + +
None
+

+Class Methods

+ + +
None
+

+Methods

+ + + + + +
parse_requestBerechtigungen pruefen.
+

+Static Methods

+ + +
None
+ +

+SaveXMLRPCRequestHandler.parse_request

+parse_request() +

+Berechtigungen pruefen. +

+
Returns:
+
+True, wenn Parsen erfolgreich war +
+
+
Up
+

+ +

SaveXMLRPCServer

+

+Erstellt einen erweiterten XMLRPCServer. +

+

+Derived from

+SimpleXMLRPCServer +

+Class Attributes

+ + +
aclmgr
+

+Class Methods

+ + +
None
+

+Methods

+ + + + + + + + + + + + + + +
SaveXMLRPCServerInit SaveXMLRPCServer class.
isAlivePrueft ob der XML RPC Server laeuft.
startStartet den XML-RPC Server.
stopStoppt den XML-RPC Server.
+

+Static Methods

+ + +
None
+ +

+SaveXMLRPCServer (Constructor)

+SaveXMLRPCServer(addr, logRequests=True, allow_none=False, use_builtin_types=False, acl="") +

+Init SaveXMLRPCServer class. +

+

+SaveXMLRPCServer.isAlive

+isAlive() +

+Prueft ob der XML RPC Server laeuft. +

+
Returns:
+
+True, wenn Server noch laeuft +
+
+

+SaveXMLRPCServer.start

+start() +

+Startet den XML-RPC Server. +

+

+SaveXMLRPCServer.stop

+stop() +

+Stoppt den XML-RPC Server. +

+
Up
+
+ \ No newline at end of file diff --git a/eric-revpipyload.api b/eric-revpipyload.api index 0da5557..836c158 100644 --- a/eric-revpipyload.api +++ b/eric-revpipyload.api @@ -1,3 +1,13 @@ +helper.IpAclManager.__get_acl?6() +helper.IpAclManager.__refullmatch?6(regex, string) +helper.IpAclManager.__set_acl?6(value) +helper.IpAclManager.acl?7 +helper.IpAclManager.get_acllevel?4(ipaddress) +helper.IpAclManager?1(acl=None, minlevel=0, maxlevel=1) +helper._ipmatch?5(ipaddress, dict_acl) +helper._setuprt?5(pid, evt_exit) +helper._zeroprocimg?5() +helper.refullmatch?4(regex, string) logsystem.LogReader.closeall?4() logsystem.LogReader.load_applog?4(start, count) logsystem.LogReader.load_plclog?4(start, count) @@ -31,8 +41,6 @@ procimgserver.ProcimgServer.start?4() procimgserver.ProcimgServer.stop?4() procimgserver.ProcimgServer.values?4() procimgserver.ProcimgServer?1(xmlserver, aclmode) -proginit._setuprt?5(pid, evt_exit) -proginit._zeroprocimg?5() proginit.cleanup?4() proginit.configure?4() proginit.forked?7 @@ -74,7 +82,11 @@ revpipyload.RevPiPyLoad.xml_reload?4() revpipyload.RevPiPyLoad.xml_setconfig?4(dc, loadnow=False) revpipyload.RevPiPyLoad.xml_setpictoryrsc?4(filebytes, reset=False) revpipyload.RevPiPyLoad?1() -revpipyload._ipmatch?5(ipaddress, dict_acl) revpipyload.pyloadversion?7 revpipyload.re_ipacl?7 -revpipyload.refullmatch?4(regex, string) +xrpcserver.SaveXMLRPCRequestHandler.parse_request?4() +xrpcserver.SaveXMLRPCServer.aclmgr?7 +xrpcserver.SaveXMLRPCServer.isAlive?4() +xrpcserver.SaveXMLRPCServer.start?4() +xrpcserver.SaveXMLRPCServer.stop?4() +xrpcserver.SaveXMLRPCServer?1(addr, logRequests=True, allow_none=False, use_builtin_types=False, acl="") diff --git a/eric-revpipyload.bas b/eric-revpipyload.bas index ca3e92c..9333951 100644 --- a/eric-revpipyload.bas +++ b/eric-revpipyload.bas @@ -2,3 +2,5 @@ PipeLogwriter Thread RevPiPlc Thread RevPiSlave Thread RevPiSlaveDev Thread +SaveXMLRPCRequestHandler SimpleXMLRPCRequestHandler +SaveXMLRPCServer SimpleXMLRPCServer diff --git a/revpipyload.e4p b/revpipyload.e4p index 2616947..e3175a6 100644 --- a/revpipyload.e4p +++ b/revpipyload.e4p @@ -1,7 +1,7 @@ - + en_US @@ -21,8 +21,8 @@ revpipyload/logsystem.py revpipyload/plcsystem.py revpipyload/picontrolserver.py - revpipyload/xmlinterface.py revpipyload/helper.py + revpipyload/xrpcserver.py diff --git a/revpipyload/helper.py b/revpipyload/helper.py index 59c3c39..1534bd6 100644 --- a/revpipyload/helper.py +++ b/revpipyload/helper.py @@ -12,6 +12,72 @@ from re import match as rematch from subprocess import Popen, PIPE +class IpAclManager(): + + """Verwaltung fuer IP Adressen und deren ACL Level.""" + + def __init__(self, acl=None, minlevel=0, maxlevel=1): + """Init IpAclManager class. + @param acl ACL Liste fuer Berechtigungen als """ + if minlevel >= maxlevel: + raise ValueError("minlevel is smaller or equal than maxlevel") + + self.__dict_acl = {} + self.__rawacl = "" + self.__re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[" \ + + str(minlevel) + "-" + str(maxlevel) + "] ?)*" + + # Liste erstellen, wenn übergeben + if acl is not None: + self.__set_acl(acl) + + def __get_acl(self): + """Getter fuer den rohen ACL-String. + return ACLs als """ + return self.__rawacl + + def __refullmatch(self, regex, string): + """re.fullmatch wegen alter python version aus wheezy nachgebaut. + + @param regex RegEx Statement + @param string Zeichenfolge gegen die getestet wird + @return True, wenn komplett passt sonst False + + """ + m = rematch(regex, string) + return m is not None and m.end() == len(string) + + def __set_acl(self, value): + """Uebernimmt neue ACL-Liste fuer die Ausertung der Level. + @param value Neue ACL-Liste als """ + if type(value) != str: + raise ValueError("parameter acl must be ") + + if not self.__refullmatch(self.__re_ipacl, value): + raise ValueError("acl format ist not okay - 1.2.3.4,0 5.6.7.8,1") + + # Klassenwerte übernehmen + self.__dict_acl = {} + self.__rawacl = value + + # Liste neu füllen mit regex Strings + for ip_level in value.split(): + ip, level = ip_level.split(",", 1) + ip = ip.replace(".", "\\.").replace("*", "\\d{1,3}") + self.__dict_acl[ip] = int(level) + + def get_acllevel(self, ipaddress): + """Prueft IP gegen ACL List und gibt ACL-Wert aus. + @param ipaddress zum pruefen + @return int() ACL Wert oder -1 wenn nicht gefunden""" + for aclip in sorted(self.__dict_acl, reverse=True): + if self.__refullmatch(aclip, ipaddress): + return self.__dict_acl[aclip] + return -1 + + acl = property(__get_acl, __set_acl) + + def _ipmatch(ipaddress, dict_acl): """Prueft IP gegen ACL List und gibt ACL aus. diff --git a/revpipyload/revpipyload.py b/revpipyload/revpipyload.py index f4261f9..324192f 100755 --- a/revpipyload/revpipyload.py +++ b/revpipyload/revpipyload.py @@ -39,7 +39,6 @@ import os import signal import tarfile import zipfile -from concurrent import futures from configparser import ConfigParser from helper import refullmatch from json import loads as jloads @@ -48,7 +47,7 @@ from tempfile import mkstemp from threading import Event from time import asctime from xmlrpc.client import Binary -from xmlrpc.server import SimpleXMLRPCServer +from xrpcserver import SaveXMLRPCServer pyloadversion = "0.6.0" re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[0-1] ?)*" @@ -76,7 +75,6 @@ class RevPiPyLoad(): self.plc = None self.plc_pause = False self.tfile = {} - self.tpe = None self.xsrv = None self.xml_ps = None @@ -172,13 +170,14 @@ class RevPiPyLoad(): # XMLRPC-Server Instantiieren und konfigurieren if self.xmlrpc >= 1: proginit.logger.debug("create xmlrpc server") - self.xsrv = SimpleXMLRPCServer( + self.xsrv = SaveXMLRPCServer( ( "", int(self.globalconfig["DEFAULT"].get("xmlrpcport", 55123)) ), logRequests=False, - allow_none=True + allow_none=True, + acl=self.xmlrpcacl ) self.xsrv.register_introspection_functions() self.xsrv.register_multicall_functions() @@ -387,8 +386,7 @@ class RevPiPyLoad(): if self.xmlrpc >= 1: proginit.logger.info("start xmlrpc-server") - self.tpe = futures.ThreadPoolExecutor(max_workers=1) - self.tpe.submit(self.xsrv.serve_forever) + self.xsrv.start() if self.plcslave: # Slaveausfuehrung übergeben @@ -450,9 +448,7 @@ class RevPiPyLoad(): if self.xmlrpc >= 1: proginit.logger.info("shutting down xmlrpc-server") - self.xsrv.shutdown() - self.tpe.shutdown() - self.xsrv.server_close() + self.xsrv.stop() # Logreader schließen self.logr.closeall() diff --git a/revpipyload/xrpcserver.py b/revpipyload/xrpcserver.py new file mode 100644 index 0000000..cb03309 --- /dev/null +++ b/revpipyload/xrpcserver.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +# +# RevPiPyLoad +# +# Webpage: https://revpimodio.org/revpipyplc/ +# (c) Sven Sager, License: LGPLv3 +# +"""XML-RPC Server anpassungen fuer Absicherung.""" +from helper import IpAclManager +from concurrent import futures +from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler + + +class SaveXMLRPCServer(SimpleXMLRPCServer): + + """Erstellt einen erweiterten XMLRPCServer.""" + + aclmgr = IpAclManager() + + def __init__( + self, addr, logRequests=True, allow_none=False, + use_builtin_types=False, acl=""): + """Init SaveXMLRPCServer class.""" + + SaveXMLRPCServer.aclmgr.acl = acl + + # Vererbte Klasse instantiieren + super().__init__( + addr=addr, + requestHandler=SaveXMLRPCRequestHandler, + logRequests=logRequests, + allow_none=allow_none, + encoding="utf-8", + bind_and_activate=False, + use_builtin_types=use_builtin_types + ) + + # Klassenvariablen + self.tpe = futures.ThreadPoolExecutor(max_workers=1) + self.fut = None + + def isAlive(self): + """Prueft ob der XML RPC Server laeuft. + @return True, wenn Server noch laeuft""" + return False if self.fut is None else self.fut.running() + + def start(self): + """Startet den XML-RPC Server.""" + if self.fut is None: + self.server_bind() + self.server_activate() + self.fut = self.tpe.submit(self.serve_forever) + else: + raise RuntimeError("savexmlrpcservers can only be started once") + + def stop(self): + """Stoppt den XML-RPC Server.""" + if self.fut is not None: + self.shutdown() + self.tpe.shutdown() + self.server_close() + else: + raise RuntimeError("save xml rpc server was not started") + + +class SaveXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): + + """Verwaltet die XML-Requests und prueft Berechtigungen.""" + + def parse_request(self): + """Berechtigungen pruefen. + @return True, wenn Parsen erfolgreich war""" + # Request parsen und ggf. schon abbrechen + if not super().parse_request(): + return False + + # IP-Adresse prüfen + int_acl = SaveXMLRPCServer.aclmgr.get_acllevel(self.address_string()) + if int_acl >= 0: + return True + else: + self.send_error( + 401, + "IP '{}' not allowed with acl level '{}'" + "".format(self.address_string(), int_acl) + ) + + return False