form_based_credentials_backend.py revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import util 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FormBasedCredentialsBackend(object): 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._logged_in = False 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def IsAlreadyLoggedIn(self, tab): 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return tab.EvaluateJavaScript(self.logged_in_javascript) 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @property 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def credentials_type(self): 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @property 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def url(self): 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @property 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def login_form_id(self): 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @property 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def login_button_javascript(self): 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci """Some sites have custom JS to log in.""" 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return None 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @property 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def login_input_id(self): 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @property 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def password_input_id(self): 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @property 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def logged_in_javascript(self): 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci """Evaluates to true iff already logged in.""" 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci raise NotImplementedError() 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def IsLoggedIn(self): 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return self._logged_in 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def _ResetLoggedInState(self): 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Makes the backend think we're not logged in even though we are. 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Should only be used in unit tests to simulate --dont-override-profile. 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._logged_in = False 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def _WaitForLoginState(self, action_runner): 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci """Waits until it can detect either the login form, or already logged in.""" 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci condition = '(document.querySelector("#%s") !== null) || (%s)' % ( 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.login_form_id, self.logged_in_javascript) 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci action_runner.WaitForJavaScriptCondition(condition, 60) 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def _SubmitLoginFormAndWait(self, action_runner, tab, username, password): 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci """Submits the login form and waits for the navigation.""" 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci email_id = 'document.querySelector("#%s #%s").value = "%s"; ' % ( 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.login_form_id, self.login_input_id, username) 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci password = 'document.querySelector("#%s #%s").value = "%s"; ' % ( 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.login_form_id, self.password_input_id, password) 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tab.ExecuteJavaScript(email_id) 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tab.ExecuteJavaScript(password) 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if self.login_button_javascript: 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tab.ExecuteJavaScript(self.login_button_javascript) 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci else: 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tab.ExecuteJavaScript( 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'document.getElementById("%s").submit();' % self.login_form_id) 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # Wait for the form element to disappear as confirmation of the navigation. 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci action_runner.WaitForNavigate() 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def LoginNeeded(self, tab, action_runner, config): 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Logs in to a test account. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RuntimeError: if could not get credential information. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self._logged_in: 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'username' not in config or 'password' not in config: 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message = ('Credentials for "%s" must include username and password.' % 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.credentials_type) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise RuntimeError(message) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logging.debug('Logging into %s account...' % self.credentials_type) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if 'url' in config: 968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) url = config['url'] 978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) else: 988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) url = self.url 998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 1018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) logging.info('Loading %s...', url) 1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) tab.Navigate(url) 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._WaitForLoginState(action_runner) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if self.IsAlreadyLoggedIn(tab): 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._logged_in = True 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._SubmitLoginFormAndWait( 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci action_runner, tab, config['username'], config['password']) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._logged_in = True 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) except util.TimeoutException: 1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) logging.warning('Timed out while loading: %s', url) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def LoginNoLongerNeeded(self, tab): # pylint: disable=W0613 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert self._logged_in 120