From fed27536d60b4ccd4feeb23019d156867653bc33 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Fri, 14 May 2021 15:58:48 +0300 Subject: [PATCH] Add WebAuditLog + SSL support --- Orchestrator/OrchestratorSettings.py | 8 +++ .../Orchestrator/BackwardCompatibility.py | 13 +++++ Sources/pyOpenRPA/Orchestrator/Server.py | 36 ++++++++------ .../Orchestrator/SettingsTemplate.py | 16 ++---- .../Orchestrator/__Orchestrator__.py | 11 ++-- Wiki/ENG_Guide/html/Orchestrator/02_Defs.html | 47 +++++++++++++++--- .../Orchestrator/03_gSettingsTemplate.html | 17 +++---- .../html/Orchestrator/04_HowToUse.html | 8 +++ .../Orchestrator/__Orchestrator__.html | 45 +++++++++++++++-- Wiki/ENG_Guide/html/genindex.html | 2 + Wiki/ENG_Guide/html/objects.inv | Bin 1444 -> 1456 bytes Wiki/ENG_Guide/html/searchindex.js | 2 +- .../markdown/Orchestrator/02_Defs.md | 41 +++++++++++++++ .../Orchestrator/03_gSettingsTemplate.md | 17 +++---- .../markdown/Orchestrator/04_HowToUse.md | 8 +++ 15 files changed, 211 insertions(+), 60 deletions(-) diff --git a/Orchestrator/OrchestratorSettings.py b/Orchestrator/OrchestratorSettings.py index ea8012f9..c7cab19d 100644 --- a/Orchestrator/OrchestratorSettings.py +++ b/Orchestrator/OrchestratorSettings.py @@ -24,6 +24,14 @@ elif __name__ == "__main__": # New init way - allow run as module -m PyOpenRPA.O # TEST Add Supertoken for the all access between robots Orchestrator.UACSuperTokenUpdate(inGSettings=gSettings, inSuperTokenStr="1992-04-03-0643-ru-b4ff-openrpa52zzz") + # Add 2 interfaces! + gSettings["ServerDict"]["ListenDict"]["Int2"]={ + "AddressStr":"", + "PortInt":8080, + "CertFilePEMPathStr":"test.pem", + "ServerInstance": None + } + # Restore DUMP Orchestrator.OrchestratorSessionRestore(inGSettings=gSettings) diff --git a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py index 6c340444..d1d128e6 100644 --- a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py +++ b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py @@ -455,3 +455,16 @@ def Update(inGSettings): } if lL: lL.warning( f"Backward compatibility (v1.2.1 to v1.2.2): Add new key RecoveryDict in ProcessorDict > RobotRDPActive") # Log about compatibility + # Add new key ServerDict > ListenDict + if "ListenDict" not in inGSettings["ServerDict"]: + lPortInt = inGSettings.get("ServerDict",{}).get("ListenPort",80) + inGSettings["ServerDict"]["ListenDict"] = { + "Default": { + "AddressStr": "", + "PortInt": lPortInt, + "CertFilePEMPathStr": None, + "ServerInstance": None + } + } + if lL: lL.warning( + f"Backward compatibility (v1.2.2 to v1.2.3): Add new key ServerDict > ListenDict. Transfer port from ServerDict > ListenPort") # Log about compatibility \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/Server.py b/Sources/pyOpenRPA/Orchestrator/Server.py index 6b0a64d5..ebafc1d8 100644 --- a/Sources/pyOpenRPA/Orchestrator/Server.py +++ b/Sources/pyOpenRPA/Orchestrator/Server.py @@ -534,17 +534,25 @@ class RobotDaemonServer(Thread): # Update the global dict ServerSettings.SettingsUpdate(inGlobalDict) def run(self): - inServerAddress="" - inPort = gSettingsDict["ServerDict"]["ListenPort"] - # Server settings - # Choose port 8080, for port 80, which is normally used for a http server, you need root access - server_address = (inServerAddress, inPort) - #httpd = HTTPServer(server_address, testHTTPServer_RequestHandler) - # Logging - gSettingsDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}") - #httpd.serve_forever() - httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler) - #httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, - # certfile='yourpemfile.pem') - #print('Starting server, use to stop') - httpd.serve_forever() + lL = gSettingsDict.get("Logger",None) + try: + lServerDict = gSettingsDict["ServerDict"]["ListenDict"][self.name] + lAddressStr=lServerDict["AddressStr"] + lPortInt=lServerDict["PortInt"] + lCertFilePathStr = lServerDict["CertFilePEMPathStr"] + if lCertFilePathStr == "": lCertFilePathStr = None + # Server settings + # Choose port 8080, for port 80, which is normally used for a http server, you need root access + server_address = (lAddressStr, lPortInt) + #httpd = HTTPServer(server_address, testHTTPServer_RequestHandler) + #httpd.serve_forever() + httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler) + if lCertFilePathStr is not None: + httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile=lCertFilePathStr) + if lL: lL.info(f"Web Server init (with SSL). Name: {self.name}, Listen URL: {lAddressStr}, Listen port: {lPortInt}, Cert path: {lCertFilePathStr}") + else: + if lL: lL.info(f"Web Server init. Name: {self.name}, Listen URL: {lAddressStr}, Listen port: {lPortInt}") + #print('Starting server, use to stop') + httpd.serve_forever() + except Exception as e: + if lL: lL.exception(f"Web Server execution exception") diff --git a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py index 4a89ee9d..fa523301 100644 --- a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py +++ b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py @@ -43,21 +43,13 @@ def __Create__(): "AgentConnectionLifetimeSecFloat": 300.0, # Time in seconds to handle the open connection to the Agent "AgentLoopSleepSecFloat": 2.0, # Time in seconds to sleep between loops when check to send some activity to the agent "WorkingDirectoryPathStr": None, # Will be filled automatically - "RequestTimeoutSecFloat": 300, # Time to handle request in seconds - "ListenPort_": "Порт, по которому можно подключиться к демону", - "ListenPort": 80, - "ListenURLList": [ - { - "Description": "Local machine test", - "URL_": "Сетевое расположение сервера демона", - "URL": "" - } - ], + "RequestTimeoutSecFloat": 300, # Time to handle request in seconds, "ListenDict": { # Prototype - "localhost":{ + "Default":{ "AddressStr":"", "PortInt":80, - "CertFilePEMPathStr":"" + "CertFilePEMPathStr":"", + "ServerInstance": None } }, "AccessUsers": { # Default - all URL is blocked diff --git a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py index ff99628c..f3f9f5f6 100644 --- a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py +++ b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py @@ -2009,10 +2009,13 @@ def Orchestrator(inGSettings, inDumpRestoreBool = True, inRunAsAdministratorBool lDaemonLastDateTime=datetime.datetime.now() gSettingsDict["ServerDict"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings - #Инициализация сервера - lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict) - lThreadServer.start() - if lL: lL.info("Web server has been started") #Logging + #Инициализация сервера (инициализация всех интерфейсов) + lListenDict = gSettingsDict.get("ServerDict",{}).get("ListenDict",{}) + for lItemKeyStr in lListenDict: + lItemDict = lListenDict[lItemKeyStr] + lThreadServer = Server.RobotDaemonServer(lItemKeyStr, gSettingsDict) + lThreadServer.start() + lItemDict["ServerInstance"] = lThreadServer # Init the RobotScreenActive in another thread lRobotScreenActiveThread = threading.Thread(target= Monitor.CheckScreen) diff --git a/Wiki/ENG_Guide/html/Orchestrator/02_Defs.html b/Wiki/ENG_Guide/html/Orchestrator/02_Defs.html index e5675265..988250de 100644 --- a/Wiki/ENG_Guide/html/Orchestrator/02_Defs.html +++ b/Wiki/ENG_Guide/html/Orchestrator/02_Defs.html @@ -411,25 +411,28 @@

UACUserDictGet(inRequest)

Return user UAC hierarchy dict of the inRequest object.

-

WebCPUpdate(inGSettings, inCPKeyStr[, …])

+

WebAuditMessageCreate(inRequest[, …])

+

Create message string with request user details (IP, Login etc…).

+ +

WebCPUpdate(inGSettings, inCPKeyStr[, …])

Add control panel HTML, JSON generator or JS when page init

-

WebURLConnectDef(inGSettings, inMethodStr, …)

+

WebURLConnectDef(inGSettings, inMethodStr, …)

Connect URL to DEF

-

WebURLConnectFile(inGSettings, inMethodStr, …)

+

WebURLConnectFile(inGSettings, inMethodStr, …)

Connect URL to File

-

WebURLConnectFolder(inGSettings, …)

+

WebURLConnectFolder(inGSettings, …)

Connect URL to Folder

-

WebUserInfoGet(inRequest)

+

WebUserInfoGet(inRequest)

Return User info about request

-

WebUserIsSuperToken(inRequest, inGSettings)

+

WebUserIsSuperToken(inRequest, inGSettings)

Return bool if request is authentificated with supetoken (token which is never expires)

-

WebUserUACHierarchyGet(inRequest)

+

WebUserUACHierarchyGet(inRequest)

Return User UAC Hierarchy DICT Return {…}

@@ -1755,6 +1758,36 @@ Var 2 (Backward compatibility): inGSettings, inRDPSessionKeyStr, inHostStr, inPo +
+
+pyOpenRPA.Orchestrator.__Orchestrator__.WebAuditMessageCreate(inRequest, inOperationCodeStr='-', inMessageStr='-')[source]
+

Create message string with request user details (IP, Login etc…). Very actual for IT security in big company.

+
# USAGE
+from pyOpenRPA import Orchestrator
+
+lWebAuditMessageStr = Orchestrator.WebAuditMessageCreate(
+    inRequest = lRequest,
+    inOperationCodeStr = "OP_CODE_1",
+    inMessageStr="Success"):
+
+# Log the WebAudit message
+lLogger.info(lWebAuditMessageStr)
+
+
+
+
Parameters
+
    +
  • inRequest – HTTP request handler

  • +
  • inOperationCodeStr – operation code in string format (actual for IT audit in control panels)

  • +
  • inMessageStr – additional message after

  • +
+
+
Returns
+

format “WebAudit :: DOMAINUSER@101.121.123.12 :: operation code :: message”

+
+
+
+
pyOpenRPA.Orchestrator.__Orchestrator__.WebCPUpdate(inGSettings, inCPKeyStr, inHTMLRenderDef=None, inJSONGeneratorDef=None, inJSInitGeneratorDef=None)[source]
diff --git a/Wiki/ENG_Guide/html/Orchestrator/03_gSettingsTemplate.html b/Wiki/ENG_Guide/html/Orchestrator/03_gSettingsTemplate.html index 275cb1f2..ab177fa2 100644 --- a/Wiki/ENG_Guide/html/Orchestrator/03_gSettingsTemplate.html +++ b/Wiki/ENG_Guide/html/Orchestrator/03_gSettingsTemplate.html @@ -230,16 +230,15 @@ "AgentConnectionLifetimeSecFloat": 300.0, # Time in seconds to handle the open connection to the Agent "AgentLoopSleepSecFloat": 2.0, # Time in seconds to sleep between loops when check to send some activity to the agent "WorkingDirectoryPathStr": None, # Will be filled automatically - "RequestTimeoutSecFloat": 300, # Time to handle request in seconds - "ListenPort_": "Порт, по которому можно подключиться к демону", - "ListenPort": 80, - "ListenURLList": [ - { - "Description": "Local machine test", - "URL_": "Сетевое расположение сервера демона", - "URL": "" + "RequestTimeoutSecFloat": 300, # Time to handle request in seconds, + "ListenDict": { # Prototype + "Default":{ + "AddressStr":"", + "PortInt":80, + "CertFilePEMPathStr":"", + "ServerInstance": None } - ], + }, "AccessUsers": { # Default - all URL is blocked "FlagCredentialsAsk": True, # Turn on Authentication "RuleDomainUserDict": { diff --git a/Wiki/ENG_Guide/html/Orchestrator/04_HowToUse.html b/Wiki/ENG_Guide/html/Orchestrator/04_HowToUse.html index c949b53f..3d81484f 100644 --- a/Wiki/ENG_Guide/html/Orchestrator/04_HowToUse.html +++ b/Wiki/ENG_Guide/html/Orchestrator/04_HowToUse.html @@ -219,6 +219,14 @@ # TEST Add Supertoken for the all access between robots Orchestrator.UACSuperTokenUpdate(inGSettings=gSettings, inSuperTokenStr="1992-04-03-0643-ru-b4ff-openrpa52zzz") + # Add 2 interfaces! + gSettings["ServerDict"]["ListenDict"]["Int2"]={ + "AddressStr":"", + "PortInt":8080, + "CertFilePEMPathStr":"test.pem", + "ServerInstance": None + } + # Restore DUMP Orchestrator.OrchestratorSessionRestore(inGSettings=gSettings) diff --git a/Wiki/ENG_Guide/html/_modules/pyOpenRPA/Orchestrator/__Orchestrator__.html b/Wiki/ENG_Guide/html/_modules/pyOpenRPA/Orchestrator/__Orchestrator__.html index 76cae2ef..3e32b116 100644 --- a/Wiki/ENG_Guide/html/_modules/pyOpenRPA/Orchestrator/__Orchestrator__.html +++ b/Wiki/ENG_Guide/html/_modules/pyOpenRPA/Orchestrator/__Orchestrator__.html @@ -781,6 +781,40 @@ if inJSInitGeneratorDef is not None: inGSettings["CPDict"][inCPKeyStr]["JSInitGeneratorDef"] = inJSInitGeneratorDef + +
[docs]def WebAuditMessageCreate(inRequest, inOperationCodeStr="-", inMessageStr="-"): + """ + Create message string with request user details (IP, Login etc...). Very actual for IT security in big company. + + .. code-block:: python + + # USAGE + from pyOpenRPA import Orchestrator + + lWebAuditMessageStr = Orchestrator.WebAuditMessageCreate( + inRequest = lRequest, + inOperationCodeStr = "OP_CODE_1", + inMessageStr="Success"): + + # Log the WebAudit message + lLogger.info(lWebAuditMessageStr) + + :param inRequest: HTTP request handler + :param inOperationCodeStr: operation code in string format (actual for IT audit in control panels) + :param inMessageStr: additional message after + :return: format "WebAudit :: DOMAIN\\USER@101.121.123.12 :: operation code :: message" + """ + try: + lClientIPStr = inRequest.client_address[0] + lUserDict = WebUserInfoGet(inRequest=inRequest) + lDomainUpperStr = lUserDict["DomainUpperStr"] + lUserLoginStr = lUserDict["UserNameUpperStr"] + lResultStr = f"WebAudit :: {lDomainUpperStr}\\\\{lUserLoginStr}@{lClientIPStr} :: {inOperationCodeStr} :: {inMessageStr}" + except Exception as e: + print(str(e)) # Has no logger - must be dead alg branch + lResultStr = inMessageStr + return lResultStr
+
[docs]def WebUserInfoGet(inRequest): """ Return User info about request @@ -2156,10 +2190,13 @@ lDaemonLastDateTime=datetime.datetime.now() gSettingsDict["ServerDict"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings - #Инициализация сервера - lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict) - lThreadServer.start() - if lL: lL.info("Web server has been started") #Logging + #Инициализация сервера (инициализация всех интерфейсов) + lListenDict = gSettingsDict.get("ServerDict",{}).get("ListenDict",{}) + for lItemKeyStr in lListenDict: + lItemDict = lListenDict[lItemKeyStr] + lThreadServer = Server.RobotDaemonServer(lItemKeyStr, gSettingsDict) + lThreadServer.start() + lItemDict["ServerInstance"] = lThreadServer # Init the RobotScreenActive in another thread lRobotScreenActiveThread = threading.Thread(target= Monitor.CheckScreen) diff --git a/Wiki/ENG_Guide/html/genindex.html b/Wiki/ENG_Guide/html/genindex.html index 217c3105..820d613e 100644 --- a/Wiki/ENG_Guide/html/genindex.html +++ b/Wiki/ENG_Guide/html/genindex.html @@ -470,6 +470,8 @@

W

    +
  • WebAuditMessageCreate() (in module pyOpenRPA.Orchestrator.__Orchestrator__) +
  • WebCPUpdate() (in module pyOpenRPA.Orchestrator.__Orchestrator__)
  • WebURLConnectDef() (in module pyOpenRPA.Orchestrator.__Orchestrator__) diff --git a/Wiki/ENG_Guide/html/objects.inv b/Wiki/ENG_Guide/html/objects.inv index c4c064368ae1ddb3ad94d8cb70c37b88ec4c799d..b9703586b44514929dc14fc6d6395249d8145fab 100644 GIT binary patch delta 1352 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