abs Posted May 31 Share Posted May 31 First of all my sincere thanks to the developers of WebDriver wrappers. I have read the AutoIT wiki about webdriver and managed to write script that is meant to launch the website via CyberArk. The script works pretty well. The requirement I have though is to create the browser session under a domain account. Reason for such ask is due to the other websites embedded within the parent website (Kafka) that use integrated windows authentication and for that, the session must use RunAs capability to create the browser session under domain account, enter the credentials in primary website and login. Then if end users open the other websites hyperlinked within the primary website, it should use the IWA instead of popping up the windows authentication dialog. The other alternative is to simply launch msedge executable using RunAs and use the Send/ ControlSend commands to sign in to primary website. It works that way and child websites open just fine. However, this approach is highly prone to errors due to losing focus, sending credentials in wrong fields and no way to read a certain class before credentials are sent. Can someone please help me with my goal of running the webdriver session using RunAs please ? I have written following script and have used RunAs for running the driver but the win authentication dialog is still coming up meaning the session didn't use RunAs at all. expandcollapse popup#AutoIt3Wrapper_UseX64=n Opt("MustDeclareVars", 1) AutoItSetOption("WinTitleMatchMode", 3) ; EXACT_MATCH! ;============================================================ ; Kafka Web Portal ; ---------------------------------------------------------- ; Description : PSM Dispatcher for CDP WEB PORTAL ; Created : May 28, 2024 ; Abhishek Singh ; Developed and compiled in AutoIt 3.3.14.1 ;============================================================ ; Uses AutoIT Web driver UDF ;============================================================ #include "PSMGenericClientWrapper.au3" #include <GUIConstantsEx.au3> #include <wd_Core.au3> #include <wd_helper.au3> #include <wd_cdp.au3> #include <wd_capabilities.au3> #include <Json.au3> #include <BinaryCall.au3> #include <WinHttp.au3> #include <WinHttpConstants.au3> ;================================ ; Consts & Globals ;================================ Global Const $DISPATCHER_NAME = "Kafka WebApp" Global Const $MESSAGE_TITLE = "PSM-Kafka-WebApp" Global Const $ERROR_MESSAGE_TITLE = "PSM " & $DISPATCHER_NAME & " Dispatcher error message" Global Const $LOG_MESSAGE_PREFIX = $DISPATCHER_NAME & " Dispatcher - " Global $TargetUsername ;Will be fetched from the PSM Session Global $TargetPassword ;Will be fetched from the PSM Session Global $TargetAddress ;Will be fetched from the PSM Session Global $DriverPath ; Will be fetched from the PSM Session Global $BrowserPath ; Will be fetched from the PSM Session Global $TargetDomain Global $ConnectionClientPID = 0 Global $sDesiredCapabilities, $sSession ;======================================= ; Code ;======================================= Exit Main() ; #FUNCTION# ==================================================================================================================== ; Name...........: FetchSessionProperties ; Description ...: Fetches properties required for the session from the PSM ; Parameters ....: None ; Return values .: None ; =============================================================================================================================== Func FetchSessionProperties() If (PSMGenericClient_GetSessionProperty("Username", $TargetUsername) <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf If (PSMGenericClient_GetSessionProperty("Password", $TargetPassword) <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf if (PSMGenericClient_GetSessionProperty("PSMRemoteMachine", $TargetAddress) <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf if (PSMGenericClient_GetSessionProperty("LogonDomain", $TargetDomain) <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf if (PSMGenericClient_GetSessionProperty("DriverPath", $DriverPath) <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf if (PSMGenericClient_GetSessionProperty("BrowserPath", $BrowserPath) <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf EndFunc ;*=*=*=*=*=*=*=*=*=*=*=*=*= ; DO NOT CHANGE FROM HERE ;*=*=*=*=*=*=*=*=*=*=*=*=*= ;======================================= ; Main ;======================================= Func Main() ; Init PSM Dispatcher utils wrapper ; MessageUserOn($MESSAGE_TITLE, "The PSM is about to log you on automatically which may take several seconds...") If (PSMGenericClient_Init() <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf LogWrite("Successfully initialized Dispatcher Utils Wrapper") LogWrite("Mapping local drives") If (PSMGenericClient_MapTSDrives() <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf ; Get the dispatcher parameters FetchSessionProperties() MessageUserOn($MESSAGE_TITLE, "Starting " & $DISPATCHER_NAME & "...") LogWrite("Starting client application") ;Open MS Edge. SetupEdge() will terminate the process If Edge wasn't loaded properly. No need to check PID here. $_WD_DEBUG = $_WD_DEBUG_None $sSession = SetupEdge() ;_WD_Navigate($sSession, $sURL) ; Used for navigating to open browser session _WD_LoadWait($sSession) LogWrite("Finished loading chrome") $ConnectionClientPID = WinGetProcess("[CLASS:Chrome_WidgetWin_1]") LogWrite($ConnectionClientPID) if ($ConnectionClientPID == 0) Then Error(StringFormat("Failed to execute process [%s]", $ConnectionClientPID, @error)) EndIf LogWrite("Entered LoginProcess()") ; References to HTML elements in the login process _WD_LoadWait($sSession) BlockAllInput() Local $oUserName = _WD_FindElement($sSession, $_WD_LOCATOR_ByXPath, "//*[@id='j_username']") _WD_ElementAction($sSession, $oUserName, 'value', $TargetUsername) Local $oPassword = _WD_FindElement($sSession, $_WD_LOCATOR_ByXPath, "//*[@id='j_password']") _WD_ElementAction($sSession, $oPassword, 'value', $TargetPassword) Local $SignIn = _WD_FindElement($sSession, $_WD_LOCATOR_ByLinkText, "Sign In") _WD_ElementAction($sSession, $SignIn, 'click') Send("{Enter}") _WD_LoadWait($sSession) _WD_Shutdown() UnblockAllBlockProhibited() Local $FinalWindow = WinWaitActive("[REGEXPTITLE:(?i)(Cloudera.*|Manager.*)]", "", 20) WinActivate($FinalWindow) WinSetState($FinalWindow, "", @SW_SHOW) LogWrite("Finished LoginProcess() successfully") ;Send PID to PSM as early as possible so recording/monitoring can begin LogWrite("sending PID to PSM") If (PSMGenericClient_SendPID($ConnectionClientPID) <> $PSM_ERROR_SUCCESS) Then Error(PSMGenericClient_PSMGetLastErrorString()) EndIf MessageUserOff() LogWrite("Terminating Dispatcher Utils Wrapper") PSMGenericClient_Term() Return $PSM_ERROR_SUCCESS EndFunc ;================================== ; Functions ;================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: Error ; Description ...: An exception handler - displays an error message and terminates the dispatcher ; Parameters ....: $ErrorMessage - Error message to display ; $Code - [Optional] Exit error code ; =============================================================================================================================== Func Error($ErrorMessage, $Code = -1) ; If the dispatcher utils DLL was already initialized, write an error log message and terminate the wrapper If (PSMGenericClient_IsInitialized()) Then LogWrite($ErrorMessage, $LOG_LEVEL_ERROR) PSMGenericClient_Term() EndIf MessageUserOn("ERROR - PROCESS IS SHUTTING DOWN", $ErrorMessage) sleep($g_ErrorMessageTime) ; If the connection component was already invoked, terminate it If ($ConnectionClientPID <> 0) Then ProcessClose($ConnectionClientPID) $ConnectionClientPID = 0 EndIf Exit $Code EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: LogWrite ; Description ...: Write a PSMWinSCPDispatcher log message to standard PSM log file ; Parameters ....: $sMessage - [IN] The message to write ; $LogLevel - [Optional] [IN] Defined If the message should be handled as an error message or as a trace messge ; Return values .: $PSM_ERROR_SUCCESS - Success, otherwise error - Use PSMGenericClient_PSMGetLastErrorString for details. ; =============================================================================================================================== Func LogWrite($sMessage, $LogLevel = $LOG_LEVEL_TRACE) Return PSMGenericClient_LogWrite($LOG_MESSAGE_PREFIX & $sMessage, $LogLevel) EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: AssertErrorLevel ; Description ...: Checks If error level is <> 0. If so, write to log and call error. ; Parameters ....: $error_code - the error code from last function call (@error) ; $message - Message to show to user as well as write to log ; $code - exit code (default -1) ; Return values .: None ; =============================================================================================================================== Func AssertErrorLevel($error_code, $message, $code = -1) ;Unblock input so user can exit If ($error_code <> 0) Then LogWrite(StringFormat("AssertErrorLevel - %s :: @error = %d", $message, $error_code), $LOG_LEVEL_ERROR) Error($message, $code) EndIf EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: MessageUserOn ; Description ...: Writes a message to the user, and keeps it indefinitely (until function call to MessageUserOff) ; Parameters ....: $msgTitle - Title of the message ; $msgBody - Body of the message ; Return values .: none ; =============================================================================================================================== Func MessageUserOn(Const ByRef $msgTitle, Const ByRef $msgBody) SplashOff() SplashTextOn ($msgTitle, $msgBody, -1, 54, -1, -1, 0, "Tahoma", 9, -1) EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: MessageUserOff ; Description ...: See SplashOff() ; Parameters ....: ; ; Return values .: none ; =============================================================================================================================== Func MessageUserOff() SplashOff() EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: BlockAllInput ; Description ...: Blocks all input (mouse & keyboard). Use when login process runs and visible, so user can't ; manipulate the process ; Parameters ....: ; Return values .: none ; =============================================================================================================================== Func BlockAllInput() LogWrite("Blocking Input") ;Block all input - mouse and keyboard If IsDeclared("s_KeyboardKeys_Buffer") <> 0 Then _BlockInputEx(1) AssertErrorLevel(@error, StringFormat("Could not block all input. Aborting... @error: %d", @error)) Else BlockInput(1) AssertErrorLevel(@error, StringFormat("Could not block all input. Aborting... @error: %d", @error)) EndIf EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: UnblockAllBlockProhibited ; Description ...: Allows all input from the user, except for prohibited keys (such as F11). ; Parameters ....: ; ; Return values .: none ; =============================================================================================================================== Func UnblockAllBlockProhibited() If IsDeclared("s_KeyboardKeys_Buffer") <> 0 Then _BlockInputEx(0) _BlockInputEx(3, "", "{F11}|{Ctrl}") ;Ctrl - also +C? +V?... Else BlockInput(0) EndIf EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: SetupEdge ; Description ...: Prepares Webdriver capabilities ; Parameters ....: None ; Return values .: $sDesiredCapabilities ; =============================================================================================================================== Func SetupEdge() Local $sURL = "https://" & $TargetAddress Local $sDriver = RunAs($TargetUsername, $TargetDomain, $TargetPassword, 2, $DriverPath, "", @SW_HIDE) _WD_Option('Driver', $sDriver) _WD_Option('Port', 9515) _WD_Option('DriverParams', '--verbose --log-path="' & @ScriptDir & '\msedge.log"') Local $sDesiredCapabilities = '{"capabilities": {"alwaysMatch": {"ms:edgeOptions": {"args": [ "start-maximized" , "--app=' & $sURL & '"], "binary": "' & StringReplace (@ProgramFilesDir, "\", "/") & '/Microsoft/Edge/Application/msedge.exe", "excludeSwitches": [ "enable-automation"]}}}}' _WD_Startup() $sSession = _WD_CreateSession($sDesiredCapabilities) Return $sSession EndFunc Link to comment Share on other sites More sharing options...
Danp2 Posted June 1 Share Posted June 1 22 hours ago, abs said: Local $sDriver = RunAs($TargetUsername, $TargetDomain, $TargetPassword, 2, $DriverPath, "", @SW_HIDE) This is supposed to be the name of the driver executable, not a PID. Try the following before calling _WD_Startup -- Use RunAs to launch the executable manually _WD_Option('driverdetect', true) Latest Webdriver UDF Release Webdriver Wiki FAQs Link to comment Share on other sites More sharing options...
abs Posted June 1 Author Share Posted June 1 Thanks @Danp2, I will try your suggestion today. Is there anything I remove from the existing code when defining the _WD_Option ? Link to comment Share on other sites More sharing options...
abs Posted June 1 Author Share Posted June 1 4 hours ago, abs said: Thanks @Danp2, I will try your suggestion today. Is there anything I remove from the existing code when defining the _WD_Option ? Hi @Danp2, I updated the SetupEdge() function with below but the session still doesn't inherit the domain credentials. It is worth mentioning that the executables are launched by local user and hence the need to use RunAs capability to support the IWA. I did write another script too that uses RunAs to open the msedge executable and open website but that uses Send commands to enter the credentials and highly sensitive to losing screen focus, send password in wrong field etc. When it does login successfully, the embedded URLs (use windows authentication) open just fine in next tab. The webdriver script returns error 403 in browser when sub URLs are opened. Func SetupEdge() Local $sURL = "https://" & $TargetAddress RunAs($TargetUsername, $TargetDomain, $TargetPassword, 2, $DriverPath, "", @SW_HIDE) ; As advised by DanP2 _WD_Option('driverdetect', true) _WD_Option('Port', 9515) _WD_Option('DriverParams', '--verbose --log-path="' & @ScriptDir & '\msedge.log"') Local $sDesiredCapabilities = '{"capabilities": {"alwaysMatch": {"ms:edgeOptions": {"args": [ "start-maximized" , "--app=' & $sURL & '"], "binary": "' & StringReplace (@ProgramFilesDir, "\", "/") & '/Microsoft/Edge/Application/msedge.exe", "excludeSwitches": [ "enable-automation"]}}}}' _WD_Startup() $sSession = _WD_CreateSession($sDesiredCapabilities) Return $sSession EndFunc Link to comment Share on other sites More sharing options...
Danp2 Posted June 1 Share Posted June 1 You still need to have something like this in your setup routine -- _WD_Option('Driver', 'msedgedriver.exe') Without this, I suspect that _WD_Startup is aborting with an error. Also, I would recommend commenting out this line in your code -- $_WD_DEBUG = $_WD_DEBUG_None That way you can examine the debugging logs to troubleshoot your script. Latest Webdriver UDF Release Webdriver Wiki FAQs Link to comment Share on other sites More sharing options...
abs Posted June 1 Author Share Posted June 1 9 minutes ago, Danp2 said: You still need to have something like this in your setup routine -- _WD_Option('Driver', 'msedgedriver.exe') Without this, I suspect that _WD_Startup is aborting with an error. Also, I would recommend commenting out this line in your code -- $_WD_DEBUG = $_WD_DEBUG_None That way you can examine the debugging logs to troubleshoot your script. Thanks Dan. I updated the function and also removed the Debug_None from script. The 403 is still there. Can't wrap my head round what might cause the domain creds to not work for webdriver utility. I will update the script to use chromedriver instead and see if that helps. Func SetupEdge() Local $sURL = "https://" & $TargetAddress _WD_Option('Driver', 'msedgedriver.exe') _WD_Option('Port', 9515) _WD_Option('DriverParams', '--verbose --log-path="' & @ScriptDir & '\msedge.log"') RunAs($TargetUsername, $TargetDomain, $TargetPassword, 2, $DriverPath, "", @SW_HIDE) ; As advised by DanP2 _WD_Option('driverdetect', true) Local $sDesiredCapabilities = '{"capabilities": {"alwaysMatch": {"ms:edgeOptions": {"args": [ "start-maximized" , "--app=' & $sURL & '"], "binary": "' & StringReplace (@ProgramFilesDir, "\", "/") & '/Microsoft/Edge/Application/msedge.exe", "excludeSwitches": [ "enable-automation"]}}}}' _WD_Startup() $sSession = _WD_CreateSession($sDesiredCapabilities) Return $sSession EndFunc Link to comment Share on other sites More sharing options...
Danp2 Posted June 1 Share Posted June 1 You just reminded me that this won't work with Edgedriver. See here for full details. Latest Webdriver UDF Release Webdriver Wiki FAQs Link to comment Share on other sites More sharing options...
abs Posted June 1 Author Share Posted June 1 58 minutes ago, Danp2 said: You just reminded me that this won't work with Edgedriver. See here for full details. Thanks Dan. In my case, the edge webdriver does open the browser and interact with DOM elements and finish the signin in seconds just fine. No error. What it fails to do is open the other links within the main website and return with 403 error. I also noticed the webdriver session doesn't really honour tabbed browsing. When you hit a link within the session, the new page with error 403 opens in a new window instead of another tab. That's not the default behaviour of Edge though (tabbed browsing is enabled in GPO). If I launch the website manually, all the pages open in next tab. It kind of all makes sense to me now. As I mentioned earlier, the driver is run by a local account (not domain), so RunAs is a must to let that local account create browser session as a domain account to honour windows authentication used by other URLs within parent website. Presumably, these embedded websites are configured with kerberos authentication in which case all the individual DNS entries have to be allowed in sites to zones assignment list through GPO and also enable ntlm or negotiate under HTTP basic authentication policy. I will give it a go on Monday and share the findings here. May be the problem wasn't RunAs at all. Link to comment Share on other sites More sharing options...
Solution abs Posted June 18 Author Solution Share Posted June 18 Update: Problem was with Kerberos authentication breaking sso. RunAs is working like a charm with below. Func SetupEdge() _WD_Option('Driver', 'msedgedriver.exe') _WD_Option('Port', 9515) _WD_Option('DriverParams', '--debug --log-path="' & @appDataDir & '\msedge.log"') RunAs($TargetUsername, $TargetDomain, $TargetPassword, 2, $DriverPath, "", @SW_HIDE) ; As advised by DanP2 _WD_Option('driverdetect', true) ; Run the website in application mode Local $sURL = "https://" & $TargetAddress Local $sDesiredCapabilities = '{"capabilities": {"alwaysMatch": {"ms:edgeOptions": {"args": [ "start-maximized" , "--app=' & $sURL & '"], "binary": "' & StringReplace (@ProgramFilesDir, "\", "/") & '/Microsoft/Edge/Application/msedge.exe", "excludeSwitches": [ "enable-automation"]}}}}' ;Local $sDesiredCapabilities = '{"capabilities": {"alwaysMatch": {"ms:edgeOptions": {"args": [ "start-maximized", "user-data-dir=C:\\Users\\' & @UserName & '\\AppData\\Local\\Microsoft\\Edge\\User Data\\", "profile-directory=Default"], "excludeSwitches": [ "enable-automation"]}}}}' _WD_Startup() $sSession = _WD_CreateSession($sDesiredCapabilities) Return $sSession EndFunc Thanks @Danp2 Regards MarkIT 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now