From 971c5e2217d17f4dab68336c9d8f562ca63fc84b Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 13 Nov 2012 00:14:53 +0900 Subject: check credentials on login branch plus fix repaint on populateErrors on login page, should refactor to ToBeValidated class or something similar, with the other paintEvent functions that implement the painting of errors coming from the "next" validating page. --- src/leap/gui/firstrun/login.py | 118 +++++++++++++++++++------- src/leap/gui/firstrun/providersetup.py | 75 ++++++++++++++--- src/leap/gui/firstrun/regvalidation.py | 150 +++++++++++++++++---------------- 3 files changed, 230 insertions(+), 113 deletions(-) diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index ae4b23c6..4271c774 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -4,7 +4,7 @@ LogIn Page, used inf First Run Wizard from PyQt4 import QtCore from PyQt4 import QtGui -import requests +#import requests from leap.gui.firstrun.mixins import UserFormMixIn @@ -18,6 +18,7 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): self.setTitle("Log In") self.setSubTitle("Log in with your credentials.") + self.current_page = "login" self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -68,30 +69,89 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # pagewizard methods + #### begin possible refactor + + def populateErrors(self): + # XXX could move this to ValidationMixin + # used in providerselect and register too + + errors = self.wizard().get_validation_error( + self.current_page) + prev_er = getattr(self, 'prevalidation_error', None) + showerr = self.validationMsg.setText + + if not errors and prev_er: + showerr(prev_er) + return + + if errors: + bad_str = getattr(self, 'bad_string', None) + cur_str = self.userNameLineEdit.text() + + if bad_str is None: + # first time we fall here. + # save the current bad_string value + self.bad_string = cur_str + showerr(errors) + else: + if prev_er: + showerr(prev_er) + return + # not the first time + if cur_str == bad_str: + showerr(errors) + else: + showerr('') + + def cleanup_errormsg(self): + """ + we reset bad_string to None + should be called before leaving the page + """ + self.bad_string = None + + def paintEvent(self, event): + """ + we hook our populate errors + on paintEvent because we need it to catch + when user enters the page coming from next, + and initializePage does not cover that case. + Maybe there's a better event to hook upon. + """ + super(LogInPage, self).paintEvent(event) + self.populateErrors() + + def set_prevalidation_error(self, error): + self.prevalidation_error = error + + #### end possible refactor + def nextId(self): wizard = self.wizard() if not wizard: return - if wizard.is_provider_setup is True: - next_ = 'connecting' if wizard.is_provider_setup is False: - next_ = 'providersetup' + next_ = 'providersetupvalidation' + if wizard.is_provider_setup is True: + # XXX bad name, ok, gonna change that + next_ = 'signupvalidation' return wizard.get_page_index(next_) def initializePage(self): + super(LogInPage, self).initializePage() self.userNameLineEdit.setText('username@provider.example.org') self.userNameLineEdit.cursorPositionChanged.connect( self.onUserNameEdit) self.initial_username_sample = True def validatePage(self): - wizard = self.wizard() - eipconfigchecker = wizard.eipconfigchecker() + #wizard = self.wizard() + #eipconfigchecker = wizard.eipconfigchecker() full_username = self.userNameLineEdit.text() password = self.userPasswordLineEdit.text() if full_username.count('@') != 1: - self.set_validation_status( + self.set_prevalidation_error( "Username must be in the username@provider form.") return False @@ -100,33 +160,33 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): self.setField('login_userName', username) self.setField('login_userPassword', password) + #################################################### + # Validation logic: + # move to provider setup page + #################################################### # Able to contact domain? # can get definition? # two-by-one - try: - eipconfigchecker.fetch_definition(domain=domain) - + #try: + #eipconfigchecker.fetch_definition(domain=domain) +# # we're using requests here for all # the possible error cases that it catches. - except requests.exceptions.ConnectionError as exc: - self.set_validation_status(exc.message[1]) - return False - except requests.exceptions.HTTPError as exc: - self.set_validation_status(exc.message) - return False - wizard.set_providerconfig( - eipconfigchecker.defaultprovider.config) - - # XXX validate user? or we leave that for later? - # I think the best thing to do for that is - # continue to provider setup page, and if - # we catch authentication error there, redirect - # again to this page (by clicking "next" to - # come here). - # Rationale is that we need to verify server certs - # and so on. - - # mark that we came from login page. + #except requests.exceptions.ConnectionError as exc: + #self.set_validation_status(exc.message[1]) + #return False + #except requests.exceptions.HTTPError as exc: + #self.set_validation_status(exc.message) + #return False + #wizard.set_providerconfig( + #eipconfigchecker.defaultprovider.config) + #################################################### + + # XXX I think this is not needed + # since we're also checking for the is_signup field. self.wizard().from_login = True + # some cleanup before we leave the page + self.cleanup_errormsg() + return True diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index a1710a3a..3fb9a19b 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -2,17 +2,24 @@ Provider Setup Validation Page, used if First Run Wizard """ +import logging from PyQt4 import QtGui +from leap.base import auth from leap.gui.progress import ValidationPage from leap.gui.constants import APP_LOGO, pause_for_user +logger = logging.getLogger(__name__) + class ProviderSetupValidationPage(ValidationPage): def __init__(self, parent=None): super(ProviderSetupValidationPage, self).__init__(parent) + is_signup = self.field("is_signup") + self.is_signup = is_signup + self.setTitle("Setting up provider") #self.setSubTitle( #"auto configuring provider...") @@ -25,14 +32,56 @@ class ProviderSetupValidationPage(ValidationPage): """ executes actual checks in a separate thread """ - domain = self.field('provider_domain') + full_domain = self.field('provider_domain') wizard = self.wizard() pconfig = wizard.providerconfig - pCertChecker = wizard.providercertchecker - certchecker = pCertChecker(domain=domain) + #pCertChecker = wizard.providercertchecker + #certchecker = pCertChecker(domain=full_domain) + pCertChecker = wizard.providercertchecker( + domain=full_domain) update_signal.emit('head_sentinel', 0) + + ###################################### + if not self.is_signup: + # We come from login page. + # We try a call to an authenticated + # page here as a mean to catch + # srp authentication errors while + # we are still at one page's reach + # of the login credentials input page. + # (so we're able to go back an correct) + + step = "fetch_eipcert" + update_signal.emit('validating credentials', 20) + + unamek = 'login_userName' + passwk = 'login_userPassword' + + username = self.field(unamek) + password = self.field(passwk) + credentials = username, password + + ################# + # FIXME #BUG #638 + verify = False + + try: + pCertChecker.download_new_client_cert( + credentials=credentials, + verify=verify) + + except auth.SRPAuthenticationError as exc: + self.set_error( + step, + "Authentication error: %s" % exc.message) + return False + + pause_for_user() + + ####################################### + update_signal.emit('Fetching CA certificate', 30) pause_for_user() @@ -48,7 +97,7 @@ class ProviderSetupValidationPage(ValidationPage): # (Check with the trusted fingerprints dict # or something smart) - certchecker.download_ca_cert( + pCertChecker.download_ca_cert( uri=ca_cert_uri, verify=False) pause_for_user() @@ -59,7 +108,7 @@ class ProviderSetupValidationPage(ValidationPage): # XXX get fingerprint dict (types) #sha256_fpr = ca_cert_fingerprint.split('=')[1] - #validate_fpr = certchecker.check_ca_cert_fingerprint( + #validate_fpr = pCertChecker.check_ca_cert_fingerprint( #fingerprint=sha256_fpr) #if not validate_fpr: # XXX update validationMsg @@ -70,7 +119,7 @@ class ProviderSetupValidationPage(ValidationPage): #api_uri = pconfig.get('api_uri', None) #try: - #api_cert_verified = certchecker.verify_api_https(api_uri) + #api_cert_verified = pCertChecker.verify_api_https(api_uri) #except requests.exceptions.SSLError as exc: #logger.error('BUG #638. %s' % exc.message) # XXX RAISE! See #638 @@ -95,15 +144,18 @@ class ProviderSetupValidationPage(ValidationPage): called after _do_checks has finished (connected to checker thread finished signal) """ + prevpage = "providerselection" if self.is_signup else "login" wizard = self.wizard() + if self.errors: - print 'going back with errors' + logger.debug('going back with errors') + name, first_error = self.pop_first_error() wizard.set_validation_error( - 'providerselection', - 'error on provider setup') + prevpage, + first_error) self.go_back() else: - print 'going next' + logger.debug('going next') self.go_next() def nextId(self): @@ -114,5 +166,6 @@ class ProviderSetupValidationPage(ValidationPage): if is_signup is True: next_ = 'signup' if is_signup is False: - next_ = 'connecting' + # XXX bad name. change to connect again. + next_ = 'signupvalidation' return wizard.get_page_index(next_) diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index b1308051..e85c2ac6 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -28,15 +28,20 @@ logger = logging.getLogger(__name__) class RegisterUserValidationPage(ValidationPage): def __init__(self, parent=None): - # XXX TODO: - # We should check if we come from signup - # or login, and change title / first step - # accordingly. - super(RegisterUserValidationPage, self).__init__(parent) - self.setTitle("User Creation") - self.setSubTitle( - "Registering account with provider.") + is_signup = self.field("is_signup") + self.is_signup = is_signup + + if is_signup: + title = "User Creation" + subtitle = "Registering account with provider." + else: + title = "Connecting..." + # XXX uh... really? + subtitle = "Checking connection with provider." + + self.setTitle(title) + self.setSubTitle(subtitle) self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -61,12 +66,12 @@ class RegisterUserValidationPage(ValidationPage): # Set Credentials. # username and password are in different fields # if they were stored in log_in or sign_up pages. + is_signup = self.is_signup - from_login = self.wizard().from_login unamek_base = 'userName' passwk_base = 'userPassword' - unamek = 'login_%s' % unamek_base if from_login else unamek_base - passwk = 'login_%s' % passwk_base if from_login else passwk_base + unamek = 'login_%s' % unamek_base if not is_signup else unamek_base + passwk = 'login_%s' % passwk_base if not is_signup else passwk_base username = self.field(unamek) password = self.field(passwk) @@ -77,73 +82,73 @@ class RegisterUserValidationPage(ValidationPage): domain=full_domain) ########################################### - # XXX this only should be setup - # if not from_login. - - signup = auth.LeapSRPRegister( - schema="https", - provider=full_domain, - verify=verify) + # only if from signup + if is_signup: + signup = auth.LeapSRPRegister( + schema="https", + provider=full_domain, + verify=verify) update_signal.emit("head_sentinel", 0) ################################################## # 1) register user ################################################## - # XXX this only should be DONE - # if NOT from_login. - - step = "register" - update_signal.emit("checking availability", 20) - update_signal.emit("registering with provider", 40) - logger.debug('registering user') - - try: - ok, req = signup.register_user( - username, password) + # only if from signup. + + if is_signup: + + step = "register" + update_signal.emit("checking availability", 20) + update_signal.emit("registering with provider", 40) + logger.debug('registering user') + + try: + ok, req = signup.register_user( + username, password) + + except socket.timeout: + self.set_error( + step, + "Error connecting to provider (timeout)") + pause_for_user() + return False + + except requests.exceptions.ConnectionError as exc: + logger.error(exc.message) + self.set_error( + step, + "Error connecting to provider " + "(connection error)") + # XXX we should signal a BAD step + pause_for_user() + update_signal.emit("connection error!", 50) + pause_for_user() + return False + + # XXX check for != OK instead??? + + if req.status_code in (404, 500): + self.set_error( + step, + "Error during registration (%s)" % req.status_code) + pause_for_user() + return False + + validation_msgs = json.loads(req.content) + errors = validation_msgs.get('errors', None) + logger.debug('validation errors: %s' % validation_msgs) + + if errors and errors.get('login', None): + # XXX this sometimes catch the blank username + # but we're not allowing that (soon) + self.set_error( + step, + 'Username not available.') + pause_for_user() + return False - except socket.timeout: - self.set_error( - step, - "Error connecting to provider (timeout)") pause_for_user() - return False - - except requests.exceptions.ConnectionError as exc: - logger.error(exc.message) - self.set_error( - step, - "Error connecting to provider " - "(connection error)") - # XXX we should signal a BAD step - pause_for_user() - update_signal.emit("connection error!", 50) - pause_for_user() - return False - - # XXX check for != OK instead??? - - if req.status_code in (404, 500): - self.set_error( - step, - "Error during registration (%s)" % req.status_code) - pause_for_user() - return False - - validation_msgs = json.loads(req.content) - errors = validation_msgs.get('errors', None) - logger.debug('validation errors: %s' % validation_msgs) - - if errors and errors.get('login', None): - # XXX this sometimes catch the blank username - # but we're not allowing that (soon) - self.set_error( - step, - 'Username not available.') - pause_for_user() - return False - - pause_for_user() ################################################## # 2) fetching eip service config @@ -168,7 +173,7 @@ class RegisterUserValidationPage(ValidationPage): ################################################## # 3) getting client certificate ################################################## - + # XXX maybe only do this if we come from signup step = "fetch_eipcert" fetching_clientcert_msg = "Fetching eip certificate" update_signal.emit(fetching_clientcert_msg, 80) @@ -233,8 +238,7 @@ class RegisterUserValidationPage(ValidationPage): called after _do_checks has finished (connected to checker thread finished signal) """ - is_signup = self.field("is_signup") - prevpage = "signup" if is_signup else "login" + prevpage = "signup" if self.is_signup else "login" wizard = self.wizard() if self.errors: -- cgit v1.2.3