diff --git a/Orchestrator/OrchestratorSettings.py b/Orchestrator/OrchestratorSettings.py index bfa2928b..7583e82b 100644 --- a/Orchestrator/OrchestratorSettings.py +++ b/Orchestrator/OrchestratorSettings.py @@ -39,9 +39,12 @@ if __name__ == "__main__": # New init way - allow run as module -m PyOpenRPA.Orc # del lUACClientDict["pyOpenRPADict"]["RDPKeyDict"] # del lUACClientDict["pyOpenRPADict"]["AgentKeyDict"] # del lUACClientDict["pyOpenRPADict"]["CPKeyDict"] - Orchestrator.OrchestratorUACUpdate(inGSettings=gSettings, inADLoginStr="ND", inADStr="", inADIsDefaultBool=True, inURLList=[], inCPAllowKeyList=[], inRoleHierarchyAllowedDict=lUACClientDict) + #lUACClientDict["pyOpenRPADict"]["CPKeyDict"]["VersionCheck"]=True + #lUACClientDict["pyOpenRPADict"]["CPKeyDict"]["TEST"]=True + lUACClientDict["pyOpenRPADict"]["AgentKeyDict"]["DESKTOP----;ND"]=True + Orchestrator.OrchestratorUACUpdate(inGSettings=gSettings, inADLoginStr="ND", inADStr="", inADIsDefaultBool=True, inURLList=[], inRoleHierarchyAllowedDict=lUACClientDict) # TEST Add User IMaslov - Add Login IMaslov to superuser of the Orchestrator - Orchestrator.OrchestratorUACUpdate(inGSettings=gSettings, inADLoginStr="IMaslov", inADStr="", inADIsDefaultBool=True, inURLList=[], inCPAllowKeyList=[]) + Orchestrator.OrchestratorUACUpdate(inGSettings=gSettings, inADLoginStr="IMaslov", inADStr="", inADIsDefaultBool=True, inURLList=[]) # TEST Add Supertoken for the all access between robots Orchestrator.OrchestratorUACSuperTokenUpdate(inGSettings=gSettings, inSuperTokenStr="1992-04-03-0643-ru-b4ff-openrpa52zzz") diff --git a/Sources/Sandbox/Subprocess.py b/Sources/Sandbox/Subprocess.py index 938438d5..02f13372 100644 --- a/Sources/Sandbox/Subprocess.py +++ b/Sources/Sandbox/Subprocess.py @@ -1,20 +1,87 @@ -import subprocess -lCMD = "for /l %x in (1, 1, 5) do echo %x && ping 127.0.0.1 -n 2" -lCMD = "git status" -proc = subprocess.Popen(f'cmd /c {lCMD}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) -# proc = subprocess.Popen('notepad', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) -#proc = subprocess.Popen('cmd /c git status', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) -#proc = subprocess.run(f'cmd /c {lCMD}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) -print(123) -#import pdb -#pdb.set_trace() -#tmp = proc.stdout.read() -lListenBool = True -while lListenBool: - tmp = proc.stdout.readline() - if tmp == b"": - lListenBool = False - #tmp = proc.stdout - #print(tmp) - print(tmp.decode("cp866")) -print("Happy end") \ No newline at end of file +def subprocess(): + import subprocess + lCMD = "for /l %x in (1, 1, 5) do echo %x && ping 127.0.0.1 -n 2" + lCMD = "git status" + proc = subprocess.Popen(f'cmd /c {lCMD}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + # proc = subprocess.Popen('notepad', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + #proc = subprocess.Popen('cmd /c git status', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + #proc = subprocess.run(f'cmd /c {lCMD}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + print(123) + #import pdb + #pdb.set_trace() + #tmp = proc.stdout.read() + lListenBool = True + while lListenBool: + tmp = proc.stdout.readline() + if tmp == b"": + lListenBool = False + #tmp = proc.stdout + #print(tmp) + print(tmp.decode("cp866")) + print("Happy end") + +def merge(a, b, path=None): + "merges b into a" + if path is None: path = [] + for key in b: + if key in a: + if isinstance(a[key], dict) and isinstance(b[key], dict): + merge(a[key], b[key], path + [str(key)]) + elif a[key] == b[key]: + pass # same leaf value + else: + raise Exception('Conflict at %s' % '.'.join(path + [str(key)])) + else: + a[key] = b[key] + return a + +# works +#print(merge({1:{"a":"A"},2:{"b":"B"}}, {2:{"c":"C"},3:{"d":"D"}})) +# has conflict +#merge({1:{"a":"A"},2:{"b":"B"}}, {1:{"a":"A"},2:{"u":"C"}}) + +lUACClientDictOld = { + "pyOpenRPADict": { + "CPKeyDict": { # Empty dict - all access + "yy":1, + "Test":12 + # "CPKeyStr"{ + # } + }, + "RDPKeyDict": { # Empty dict - all access + # "RDPKeyStr"{ + # "FullscreenBool": True, + # "IgnoreBool":True, + # "ReconnectBool": True + # "NothingBool": True # USe option if you dont want to give some access to the RDP controls + # } + }, + "AgentKeyDict": { # Empty dict - all access + # "AgentKeyStr"{ + # } + }, + "AdminDict": { # Empty dict - all access + "LogViewerBool": True, # Show log viewer on the web page + "CMDInputBool": True, # Execute CMD on the server side and result to the logs + "ScreenshotViewerBool": True, # Show button to look screenshots + "RestartOrchestratorBool": True, # Restart orchestrator activity + "RestartOrchestratorGITPullBool": True, # Turn off (RDP remember) orc + git pull + Turn on (rdp remember) + "RestartPCBool": True, # Send CMD to restart pc + "NothingBool": True # USe option if you dont want to give some access to the RDP controls + }, + "ActivityDict": { # Empty dict - all access + "ActivityListExecuteBool": True, # Execute activity at the current thread + "ActivityListAppendProcessorQueueBool": True # Append activity to the processor queue + } + } + +} + +lUACClientDictNew = { + "pyOpenRPADict": { + "CPKeyDict": { # Empty dict - all access + "Test":True + } + } +} +print(merge(lUACClientDictOld, lUACClientDictNew)) \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py index e46e6470..0d938842 100644 --- a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py +++ b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py @@ -1,7 +1,7 @@ # Def to check inGSettings and update structure to the backward compatibility # !!! ATTENTION: Backward compatibility has been started from v1.1.13 !!! # So you can use config of the orchestrator 1.1.13 in new Orchestrator versions and all will be ok :) (hope it's true) -import win32security, json, datetime, time +import win32security, json, datetime, time, copy # # # # # # # # # # # # # # # # # # # # Backward compatibility Web defs up to v1.2.0 @@ -360,4 +360,27 @@ def Update(inGSettings): if "AgentDict" not in inGSettings: # Create new AgentDict structure inGSettings["AgentDict"]= {} if lL: lL.warning( - f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'AgentDict'") # Log about compatibility \ No newline at end of file + f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'AgentDict'") # Log about compatibility + # Alg to convert UAC ControlPanelAllawedList to UACClient hierarchy + # if inGSettings["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True: + # lUserRights = inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(), inRequest.OpenRPA["User"].upper())] + # if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]: + # lUACBool = False # UAC Check is not passed - False for user + lShowWarnBool = False + # # Convert to UACClient dict + lRuleDomainUserDeepCopyDict = copy.deepcopy(inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"]) + for lItemKeyTurple in lRuleDomainUserDeepCopyDict: + lDomainUpperStr = lItemKeyTurple[0] + lUserUpperStr = lItemKeyTurple[1] + lItemDict = lRuleDomainUserDeepCopyDict[lItemKeyTurple] + if "ControlPanelKeyAllowedList" in lItemDict: + lShowWarnBool = True + lUACClientDict = {"pyOpenRPADict":{"CPKeyDict":{}}} + for lAllowedKeyItemStr in lItemDict["ControlPanelKeyAllowedList"]: + lUACClientDict["pyOpenRPADict"]["CPKeyDict"][lAllowedKeyItemStr]=True # Convert + # Send update UACDict for user by the list + Orchestrator.OrchestratorUACUpdate(inGSettings=inGSettings,inADLoginStr=lUserUpperStr, inADStr=lDomainUpperStr, inRoleHierarchyAllowedDict=lUACClientDict) + # remove "ControlPanelKeyAllowedList" + del inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][lItemKeyTurple]["ControlPanelKeyAllowedList"] + if lShowWarnBool: # Show only 1 warning per all run + if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert CP allowed list to UAC Client hierarchy (consolidated)") # Log about compatibility diff --git a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py index e4fc5e7a..b5c4bab7 100644 --- a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py +++ b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py @@ -163,8 +163,8 @@ def OrchestratorSessionSave(inGSettings=None): ## Orchestrator session save return True # Update user access def OrchestratorUACUpdate(inGSettings, inADLoginStr, inADStr="", inADIsDefaultBool=True, inURLList=[], inCPAllowKeyList=[], inRoleHierarchyAllowedDict={}): - # Backward compatibility - if inURLList==[]: + lUserTurple = (inADStr.upper(),inADLoginStr.upper()) # Create turple key for inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"] + if inURLList==[] and lUserTurple not in inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"]: # Backward compatibility if user is not exist inURLList=[ { "Method": "GET", @@ -181,10 +181,14 @@ def OrchestratorUACUpdate(inGSettings, inADLoginStr, inADStr="", inADIsDefaultBo "FlagAccess": True } ] + # Check RoleHierarchyAllowedDict in gSettings for the old role hierarchy - include in result. + if lUserTurple in inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"] and "RoleHierarchyAllowedDict" in inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][lUserTurple]: + lRoleHierarchyAllowedOLDDict = inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][lUserTurple]["RoleHierarchyAllowedDict"] + Server.__ComplexDictMerge2to1__(in1Dict=inRoleHierarchyAllowedDict, in2Dict=lRoleHierarchyAllowedOLDDict) # Merge dict 2 into dict 1 + # Create Access item lRuleDomainUserDict = { "MethodMatchURLBeforeList": inURLList, - "ControlPanelKeyAllowedList": inCPAllowKeyList, #["TestControlPanel", "RobotRDPActive","RobotScreenActive", "ControlPanel_Template"] # If empty - all is allowed "RoleHierarchyAllowedDict": inRoleHierarchyAllowedDict } # Case add domain + user diff --git a/Sources/pyOpenRPA/Orchestrator/Server.py b/Sources/pyOpenRPA/Orchestrator/Server.py index db1b3406..81f9785b 100644 --- a/Sources/pyOpenRPA/Orchestrator/Server.py +++ b/Sources/pyOpenRPA/Orchestrator/Server.py @@ -26,6 +26,22 @@ from . import ServerSettings import copy +# Tool to merge complex dictionaries +def __ComplexDictMerge2to1__(in1Dict, in2Dict): + lPathList=None + if lPathList is None: lPathList = [] + for lKeyStr in in2Dict: + if lKeyStr in in1Dict: + if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict): + __ComplexDictMerge2to1__(in1Dict[lKeyStr], in2Dict[lKeyStr], lPathList + [str(lKeyStr)]) + elif in1Dict[lKeyStr] == in2Dict[lKeyStr]: + pass # same leaf value + else: + raise Exception('Conflict at %s' % '.'.join(lPathList + [str(lKeyStr)])) + else: + in1Dict[lKeyStr] = in2Dict[lKeyStr] + return in1Dict + #Authenticate function () # return dict # { @@ -194,6 +210,8 @@ def UserAccessCheckBefore(inMethod, inRequest): # HTTPRequestHandler class class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): # Def to check User Role access grants + def UACClientCheck(self, inRoleKeyList): # Alias + return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList) def UserRoleAccessAsk(self, inRoleKeyList): lResult = True # Init flag lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy diff --git a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py index e4b52691..4fa0f444 100644 --- a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py @@ -20,16 +20,19 @@ from . import SettingsTemplate # Generate CP # Return {"Key":{"",""}} def HiddenCPDictGenerate(inRequest, inGSettings): + dUAC = inRequest.UACClientCheck # Alias. + lUACCPTemplateKeyList=["pyOpenRPADict","CPKeyDict"] lL = inGSettings["Logger"] # Alias for logger # Create result JSON lCPDict = {} lRenderFunctionsRobotList = inGSettings["ControlPanelDict"]["RobotList"] for lItem in lRenderFunctionsRobotList: - lUACBool = True # Check if render function is applicable User Access Rights (UAC) - if inGSettings["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True: - lUserRights = inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(), inRequest.OpenRPA["User"].upper())] - if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]: - lUACBool = False # UAC Check is not passed - False for user + lUACBool = dUAC(inRoleKeyList=lUACCPTemplateKeyList+[lItem["KeyStr"]]) # Check if render function is applicable User Access Rights (UAC) + if lItem["KeyStr"]=="VersionCheck": lUACBool=True # For backward compatibility for the old fron version which not reload page when new orch version is comming + #if inGSettings["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True: + # lUserRights = inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(), inRequest.OpenRPA["User"].upper())] + # if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]: + # lUACBool = False # UAC Check is not passed - False for user if lUACBool: # Run function if UAC is TRUE # Выполнить вызов и записать результат # Call def (inRequest, inGSettings) or def (inGSettings) @@ -57,36 +60,44 @@ def HiddenCPDictGenerate(inRequest, inGSettings): # Return {"Key":{"",""}} def HiddenRDPDictGenerate(inRequest, inGSettings): + dUAC = inRequest.UACClientCheck # Alias. + lUACRDPTemplateKeyList=["pyOpenRPADict","RDPKeyDict"] lRDPDict = {"HandlebarsList":[]} # Iterate throught the RDP list for lRDPSessionKeyStrItem in inGSettings["RobotRDPActive"]["RDPList"]: - lRDPConfiguration = inGSettings["RobotRDPActive"]["RDPList"][ - lRDPSessionKeyStrItem] # Get the configuration dict - lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False, - "IsIgnoredBool": False} # Template - lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str - lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex - lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGSettings["RobotRDPActive"][ - "FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window - lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored - lRDPDict[lDataItemDict["SessionKeyStr"]].append(lDataItemDict) - lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict) - lHandlebarsDataItemDict["SessionKeyStr"]=lDataItemDict["SessionKeyStr"] - lRDPDict["HandlebarsList"].append(lHandlebarsDataItemDict) + # Check UAC + if dUAC(inRoleKeyList=lUACRDPTemplateKeyList+[lRDPSessionKeyStrItem]): + lRDPConfiguration = inGSettings["RobotRDPActive"]["RDPList"][ + lRDPSessionKeyStrItem] # Get the configuration dict + lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False, + "IsIgnoredBool": False} # Template + lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str + lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex + lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGSettings["RobotRDPActive"][ + "FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window + lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored + lRDPDict[lDataItemDict["SessionKeyStr"]].append(lDataItemDict) + lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict) + lHandlebarsDataItemDict["SessionKeyStr"]=lDataItemDict["SessionKeyStr"] + lRDPDict["HandlebarsList"].append(lHandlebarsDataItemDict) return lRDPDict # Return {"HostNameUpperStr;UserUpperStr":{"IsListenBool":True}, "HandlebarsList":[{"HostnameUpperStr":"","UserUpperStr":"","IsListenBool":True}]} def HiddenAgentDictGenerate(inRequest, inGSettings): + dUAC = inRequest.UACClientCheck # Alias. + lUACAgentTemplateKeyList=["pyOpenRPADict","AgentKeyDict"] lAgentDict = {"HandlebarsList":[]} # Iterate throught the RDP list for lAgentItemKeyStrItem in inGSettings["AgentDict"]: + # Check UAC lKeyStr = f"{lAgentItemKeyStrItem[0]};{lAgentItemKeyStrItem[1]}" # turple ("HostNameUpperStr","UserUpperStr") > Str "HostNameUpperStr;UserUpperStr" - lDataItemDict = inGSettings["AgentDict"][lAgentItemKeyStrItem] - lAgentDict[lKeyStr]=lDataItemDict - lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict) - lHandlebarsDataItemDict["HostnameUpperStr"]=lAgentItemKeyStrItem[0] - lHandlebarsDataItemDict["UserUpperStr"]=lAgentItemKeyStrItem[1] - lAgentDict["HandlebarsList"].append(lHandlebarsDataItemDict) + if dUAC(inRoleKeyList=lUACAgentTemplateKeyList+[lKeyStr]): + lDataItemDict = inGSettings["AgentDict"][lAgentItemKeyStrItem] + lAgentDict[lKeyStr]=lDataItemDict + lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict) + lHandlebarsDataItemDict["HostnameUpperStr"]=lAgentItemKeyStrItem[0] + lHandlebarsDataItemDict["UserUpperStr"]=lAgentItemKeyStrItem[1] + lAgentDict["HandlebarsList"].append(lHandlebarsDataItemDict) return lAgentDict diff --git a/changelog.md b/changelog.md index f5d815f5..0714dd28 100644 --- a/changelog.md +++ b/changelog.md @@ -71,6 +71,7 @@ - - def AgentOSFileTextDataStrCreate(inGSettings, inHostNameStr, inUserStr, inFilePathStr, inFileDataStr, inEncodingStr = "utf-8"): # Send text file to Agent (string) - Orc WEB: Create mGlobal.pyOpenRPA.ActivityListExecute({}) to test some activities from the front - Orc - add log about send activity to agent +- Orc RoleHierarchy - support RDP, Support Agent + buttons [1.1.0] After 2 month test prefinal with new improovements (+RobotRDPActive in Orchestrator + Easy ControlPanelTemplate) Beta before 1.1.0 (new way of OpenRPA with improvements. Sorry, but no backward compatibility)/ Backward compatibility will start from 1.0.1