mirror of
https://github.com/dirkjanm/ROADtools
synced 2026-06-08 13:48:32 +00:00
roadtx: support for device code auth in selenium scenarios (primarily for testing scenarios)
This commit is contained in:
@@ -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}')
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user