roadtx: support for device code auth in selenium scenarios (primarily for testing scenarios)

This commit is contained in:
Dirk-jan Mollema
2023-10-10 18:31:34 +02:00
parent 7319334d7e
commit bfe2f916f2
2 changed files with 36 additions and 16 deletions
+5 -1
View File
@@ -337,6 +337,10 @@ def main():
kdbauth_parser.add_argument('--federated',
action='store_true',
help='Fill in password on Federation server login page (assumes AD FS)')
kdbauth_parser.add_argument('--device-code',
action='store',
help='Authenticate with the given device code')
# Interactive auth using Selenium - inject PRT
@@ -705,7 +709,7 @@ def main():
if not service:
return
selauth.driver = selauth.get_webdriver(service)
result = selauth.selenium_login(url, args.username, password, otpseed, keep=args.keep_open, capture=args.capture_code, federated=args.federated)
result = selauth.selenium_login(url, args.username, password, otpseed, keep=args.keep_open, capture=args.capture_code, federated=args.federated, devicecode=args.device_code)
if args.capture_code:
if result:
print(f'Captured auth code: {result}')
+31 -15
View File
@@ -97,12 +97,19 @@ class SeleniumAuthentication():
otpseed = None
return userpassword, otpseed
def selenium_login(self, url, identity=None, password=None, otpseed=None, keep=False, capture=False, federated=False):
def selenium_login(self, url, identity=None, password=None, otpseed=None, keep=False, capture=False, federated=False, devicecode=None):
'''
Selenium based login with optional autofill of whatever is provided
'''
driver = self.driver
# Change if using device code auth
if devicecode:
url = 'https://login.microsoftonline.com/common/oauth2/deviceauth'
driver.get(url)
# Enter code first if device code flow
if devicecode:
el = WebDriverWait(driver, 3000).until(lambda d: d.find_element(By.ID, "otc"))
el.send_keys(devicecode + Keys.ENTER)
if identity and not 'login_hint' in url:
el = WebDriverWait(driver, 3000).until(lambda d: d.find_element(By.ID, "i0116"))
el.send_keys(identity + Keys.ENTER)
@@ -157,20 +164,29 @@ class SeleniumAuthentication():
# No MFA?
pass
try:
WebDriverWait(driver, 120).until(lambda d: '?code=' in d.current_url)
res = urlparse(driver.current_url)
params = parse_qs(res.query)
code = params['code'][0]
if not keep:
driver.close()
if capture:
return code
return self.auth.authenticate_with_code_native(code, self.redirurl)
except TimeoutException:
if not keep:
driver.close()
raise AuthenticationException('Authentication did not complete within time limit')
if devicecode:
try:
els = WebDriverWait(driver, 10).until(lambda d: d.find_element(By.ID, "idSIButton9"))
els.click()
except TimeoutException:
if not keep:
driver.close()
raise AuthenticationException('Could not complete device code auth within the time limit (button not found: idSIButton9)')
else:
try:
WebDriverWait(driver, 120).until(lambda d: '?code=' in d.current_url)
res = urlparse(driver.current_url)
params = parse_qs(res.query)
code = params['code'][0]
if not keep:
driver.close()
if capture:
return code
return self.auth.authenticate_with_code_native(code, self.redirurl)
except TimeoutException:
if not keep:
driver.close()
raise AuthenticationException('Authentication did not complete within time limit')
return False
def selenium_login_with_prt(self, url, identity=None, password=None, otpseed=None, keep=False, prtcookie=None, capture=False):