from http.server import BaseHTTPRequestHandler, HTTPServer from socketserver import ThreadingMixIn import threading import json from threading import Thread import importlib import pdb import base64 import uuid import datetime import os #for path operations from http import cookies global gSettingsDict from . import ServerSettings #Authenticate function () # return dict # { # "Domain": "", #Empty if Auth is not success # "User": "" #Empty if Auth is not success # } def AuthenticateVerify(inRequest): lResult={"Domain": "", "User": ""} ###################################### #Way 1 - try to find AuthToken lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", "")) inRequest.OpenRPA = {} inRequest.OpenRPA["AuthToken"] = None #pdb.set_trace() if "AuthToken" in lCookies: lCookieAuthToken = lCookies.get("AuthToken", "").value if lCookieAuthToken: #Find AuthToken in GlobalDict if lCookieAuthToken in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}): #Auth Token Has Been Founded lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"] lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"] #Set auth token inRequest.OpenRPA["AuthToken"] = lCookieAuthToken #Exit earlier return lResult ###################################### #Way 2 - try to logon lHeaderAuthorization = inRequest.headers.get("Authorization", "").split(" ") if len(lHeaderAuthorization) == 2: llHeaderAuthorizationDecodedUserPasswordList = base64.b64decode(lHeaderAuthorization[1]).decode("utf-8").split( ":") lUser = llHeaderAuthorizationDecodedUserPasswordList[0] lPassword = llHeaderAuthorizationDecodedUserPasswordList[1] lDomain = "" if "\\" in lUser: lDomain = lUser.split("\\")[0] lUser = lUser.split("\\")[1] #Try to logon - use processor lLogonResult = Processor.Activity( { "Type": "WindowsLogon", "Domain": lDomain, "User": lUser, "Password": lPassword } ) #Check result if lLogonResult["Result"]: lResult["Domain"] = lLogonResult["Domain"] lResult["User"] = lLogonResult["User"] #Create token lAuthToken=str(uuid.uuid1()) gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {} gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"] gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"] gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now() #Set-cookie inRequest.OpenRPA["AuthToken"] = lAuthToken inRequest.OpenRPASetCookie = {} #New engine of server inRequest.OpenRPAResponseDict["SetCookies"]["AuthToken"] = lAuthToken #inRequest.OpenRPAResponse["Set-Cookie"]=[]lResult["Set-Cookie"] = lAuthToken #pdb.set_trace() #inRequest.send_header("Set-Cookie:", f"AuthToken={lAuthToken}") ###################################### return lResult def AuthenticateBlock(inRequest): # Send response status code inRequest.send_response(401) # Send headers inRequest.send_header('Content-type', 'text/html') inRequest.send_header('WWW-Authenticate', 'Basic') # Always ask login pass inRequest.end_headers() # Write content as utf-8 data inRequest.wfile.write(bytes("", "utf8")) #Check access before execute the action #return bool True - go execute, False - dont execute def UserAccessCheckBefore(inMethod, inRequest): # Help def - Get access flag from dict #pdb.set_trace() def HelpGetFlag(inAccessRuleItem, inRequest, inGlobalDict, inAuthenticateDict): if "FlagAccess" in inAccessRuleItem: return inAccessRuleItem["FlagAccess"] elif "FlagAccessDefRequestGlobalAuthenticate" in inAccessRuleItem: return inAccessRuleItem["FlagAccessDefRequestGlobalAuthenticate"](inRequest, inGlobalDict, inAuthenticateDict) ########################################## inMethod=inMethod.upper() #Prepare result false lResult = False lAuthToken = inRequest.OpenRPA["AuthToken"] #go next if user is identified lUserDict = None if lAuthToken: lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] #pdb.set_trace() ######################################## ######################################## #Check general before rule (without User domain) #Check rules for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []): #Go next execution if flag is false if not lResult: #Check if Method is identical if lAccessRuleItem["Method"].upper() == inMethod: #check Match type variant: BeginWith if lAccessRuleItem["MatchType"].upper() == "BEGINWITH": lURLPath = inRequest.path lURLPath = lURLPath.upper() if lURLPath.startswith(lAccessRuleItem["URL"].upper()): lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: Contains elif lAccessRuleItem["MatchType"].upper() == "CONTAINS": lURLPath = inRequest.path lURLPath = lURLPath.upper() if lURLPath.contains(lAccessRuleItem["URL"].upper()): lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: Equal elif lAccessRuleItem["MatchType"].upper() == "EQUAL": if lAccessRuleItem["URL"].upper() == inRequest.path.upper(): lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: EqualCase elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": if lAccessRuleItem["URL"] == inRequest.path: lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) ######################################### ######################################### #Do check if lResult is false if not lResult: #Check access by User Domain #Check rules to find first appicable #Check rules for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []): #Go next execution if flag is false if not lResult: #Check if Method is identical if lAccessRuleItem["Method"].upper() == inMethod: #check Match type variant: BeginWith if lAccessRuleItem["MatchType"].upper() == "BEGINWITH": lURLPath = inRequest.path lURLPath = lURLPath.upper() if lURLPath.startswith(lAccessRuleItem["URL"].upper()): lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) #check Match type variant: Contains elif lAccessRuleItem["MatchType"].upper() == "CONTAINS": lURLPath = inRequest.path lURLPath = lURLPath.upper() if lURLPath.contains(lAccessRuleItem["URL"].upper()): lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: Equal elif lAccessRuleItem["MatchType"].upper() == "EQUAL": if lAccessRuleItem["URL"].upper() == inRequest.path.upper(): lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) # check Match type variant: EqualCase elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": if lAccessRuleItem["URL"] == inRequest.path: lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) ##################################### ##################################### #Return lResult return lResult # HTTPRequestHandler class class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): #Tech def #return {"headers":[],"body":"","statuscode":111} def URLItemCheckDo(self, inURLItem, inMethod): ############################### #Tech sub def - do item ################################ def URLItemDo(inURLItem,inRequest,inGlobalDict): inResponseDict = inRequest.OpenRPAResponseDict #Set status code 200 inResponseDict["StatusCode"] = 200 #Content-type if "ResponseContentType" in inURLItem: inResponseDict["Headers"]["Content-type"] = inURLItem["ResponseContentType"] #If file path is set if "ResponseFilePath" in inURLItem: lFileObject = open(inURLItem["ResponseFilePath"], "rb") # Write content as utf-8 data inResponseDict["Body"] = lFileObject.read() # Закрыть файловый объект lFileObject.close() #If function is set if "ResponseDefRequestGlobal" in inURLItem: inURLItem["ResponseDefRequestGlobal"](inRequest, inGlobalDict) if "ResponseFolderPath" in inURLItem: lRequestPath = inRequest.path lFilePathSecondPart = lRequestPath.replace(inURLItem["URL"],"") lFilePath = os.path.join(inURLItem["ResponseFolderPath"],lFilePathSecondPart) #print(f"File full path {lFilePath}") #Check if file exist if os.path.exists(lFilePath) and os.path.isfile(lFilePath): lFileObject = open(lFilePath, "rb") # Write content as utf-8 data inResponseDict["Body"] = lFileObject.read() inResponseDict["ContentType"]= "application/octet-stream" # Закрыть файловый объект lFileObject.close() ############################################## if inURLItem["Method"].upper() == inMethod.upper(): # check Match type variant: BeginWith if inURLItem["MatchType"].upper() == "BEGINWITH": lURLPath = self.path lURLPath = lURLPath.upper() if lURLPath.startswith(inURLItem["URL"].upper()): URLItemDo(inURLItem, self, gSettingsDict) return True # check Match type variant: Contains elif inURLItem["MatchType"].upper() == "CONTAINS": lURLPath = self.path lURLPath = lURLPath.upper() if lURLPath.contains(inURLItem["URL"].upper()): URLItemDo(inURLItem, self, gSettingsDict) return True # check Match type variant: Equal elif inURLItem["MatchType"].upper() == "EQUAL": if inURLItem["URL"].upper() == self.path.upper(): URLItemDo(inURLItem, self, gSettingsDict) return True # check Match type variant: EqualCase elif inURLItem["MatchType"].upper() == "EQUALCASE": if inURLItem["URL"] == self.path: URLItemDo(inURLItem, self, gSettingsDict) return True return False #ResponseContentTypeFile def SendResponseContentTypeFile(self, inContentType, inFilePath): # Send response status code self.send_response(200) # Send headers self.send_header('Content-type', inContentType) #Check if var exist if hasattr(self, "OpenRPASetCookie"): self.send_header("Set-Cookie", f"AuthToken={self.OpenRPA['AuthToken']}") self.end_headers() lFileObject = open(inFilePath, "rb") # Write content as utf-8 data self.wfile.write(lFileObject.read()) #Закрыть файловый объект lFileObject.close() # ResponseContentTypeFile def ResponseDictSend(self): inResponseDict = self.OpenRPAResponseDict # Send response status code self.send_response(inResponseDict["StatusCode"]) # Send headers for lItemKey, lItemValue in inResponseDict["Headers"].items(): self.send_header(lItemKey, lItemValue) # Send headers: Set-Cookie for lItemKey, lItemValue in inResponseDict["SetCookies"].items(): self.send_header("Set-Cookie", f"{lItemKey}={lItemValue}") #Close headers section in response self.end_headers() # Write content as utf-8 data self.wfile.write(inResponseDict["Body"]) def do_GET(self): # Prepare result dict lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None} self.OpenRPAResponseDict = lResponseDict ##################################### #Do authentication #Check if authentication is turned on ##################################### lFlagAccessUserBlock=False lAuthenticateDict = {"Domain": "", "User": ""} if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): lAuthenticateDict = AuthenticateVerify(self) if not lAuthenticateDict["User"]: lFlagAccessUserBlock=True # Logging gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}") if lFlagAccessUserBlock: AuthenticateBlock(self) ##################################### else: #Check the user access (if flag) #################################### lFlagUserAccess = True #If need user authentication if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): lFlagUserAccess = UserAccessCheckBefore("GET", self) ###################################### if lFlagUserAccess: lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1]) ############################ #New server engine (url from global dict (URLList)) ############################ for lURLItem in gSettingsDict["Server"]["URLList"]: #Check if all condition are applied lFlagURLIsApplied=False lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET") if lFlagURLIsApplied: self.ResponseDictSend() return else: #Set access denied code # Send response status code self.send_response(403) # Send headers self.end_headers() # POST def do_POST(self): # Prepare result dict #pdb.set_trace() lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None} self.OpenRPAResponseDict = lResponseDict ##################################### #Do authentication #Check if authentication is turned on ##################################### lFlagAccessUserBlock=False lAuthenticateDict = {"Domain": "", "User": ""} if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): lAuthenticateDict = AuthenticateVerify(self) if not lAuthenticateDict["User"]: lFlagAccessUserBlock=True if lFlagAccessUserBlock: AuthenticateBlock(self) ##################################### else: #Check the user access (if flag) #################################### lFlagUserAccess = True #If need user authentication if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): lFlagUserAccess = UserAccessCheckBefore("POST", self) ###################################### if lFlagUserAccess: lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1]) ############################ #New server engine (url from global dict (URLList)) ############################ for lURLItem in gSettingsDict["Server"]["URLList"]: #Check if all condition are applied lFlagURLIsApplied=False lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST") if lFlagURLIsApplied: self.ResponseDictSend() return return else: #Set access denied code # Send response status code self.send_response(403) # Send headers self.end_headers() return #Logging #!Turn it on to stop print in console #def log_message(self, format, *args): # return class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): daemon_threads = True """Handle requests in a separate thread.""" def finish_request(self, request, client_address): request.settimeout(30) # "super" can not be used because BaseServer is not created from object HTTPServer.finish_request(self, request, client_address) #inGlobalDict # "JSONConfigurationDict": class RobotDaemonServer(Thread): def __init__(self,name,inGlobalDict): Thread.__init__(self) self.name = name # Update the global dict ServerSettings.SettingsUpdate(gSettingsDict) def run(self): inServerAddress=""; inPort = gSettingsDict["Server"]["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) #print('Starting server, use to stop') httpd.serve_forever()