def _registration_finished(self, ok, req): if ok: user_domain = self._username + "@" + self._domain message = "<font color='green'><h3>" message += self.tr("User %s successfully registered.") % ( user_domain, ) message += "</h3></font>" self._set_register_status(message) self.ui.lblPassword2.clearFocus() self._set_registration_fields_visibility(False) # Allow the user to remember his password if has_keyring(): self.ui.chkRemember.setVisible(True) self.ui.chkRemember.setEnabled(True) self.page(self.REGISTER_USER_PAGE).set_completed() self.button(QtGui.QWizard.BackButton).setEnabled(False) else: old_username = self._username self._username = None self._password = None error_msg = self.tr("Unknown error") try: content, _ = get_content(req) json_content = json.loads(content) error_msg = json_content.get("errors").get("login")[0] if not error_msg.istitle(): error_msg = "%s %s" % (old_username, error_msg) except Exception as e: logger.error("Unknown error: %r" % (e,)) self._set_register_status(error_msg, error=True) self.ui.btnRegister.setEnabled(True)
def _download_config(self, *args): """ Downloads the SMTP config for the given provider """ leap_assert(self._provider_config, "We need a provider configuration!") logger.debug("Downloading SMTP config for %s" % (self._provider_config.get_domain(),)) headers = {} mtime = get_mtime(os.path.join(self._smtp_config .get_path_prefix(), "leap", "providers", self._provider_config.get_domain(), "smtp-service.json")) if self._download_if_needed and mtime: headers['if-modified-since'] = mtime api_version = self._provider_config.get_api_version() # there is some confusion with this uri, config_uri = "%s/%s/config/smtp-service.json" % ( self._provider_config.get_api_uri(), api_version) logger.debug('Downloading SMTP config from: %s' % config_uri) srp_auth = SRPAuth(self._provider_config) session_id = srp_auth.get_session_id() cookies = None if session_id: cookies = {"_session_id": session_id} res = self._session.get(config_uri, verify=self._provider_config .get_ca_cert_path(), headers=headers, cookies=cookies) res.raise_for_status() self._smtp_config.set_api_version(api_version) # Not modified if res.status_code == 304: logger.debug("SMTP definition has not been modified") self._smtp_config.load(os.path.join( "leap", "providers", self._provider_config.get_domain(), "smtp-service.json")) else: smtp_definition, mtime = get_content(res) self._smtp_config.load(data=smtp_definition, mtime=mtime) self._smtp_config.save(["leap", "providers", self._provider_config.get_domain(), "smtp-service.json"])
def _download_config(self, *args): """ Downloads the EIP config for the given provider """ leap_assert(self._provider_config, "We need a provider configuration!") logger.debug("Downloading EIP config for %s" % (self._provider_config.get_domain(),)) api_version = self._provider_config.get_api_version() self._eip_config = EIPConfig() self._eip_config.set_api_version(api_version) headers = {} mtime = get_mtime(os.path.join(self._eip_config .get_path_prefix(), "leap", "providers", self._provider_config.get_domain(), "eip-service.json")) if self._download_if_needed and mtime: headers['if-modified-since'] = mtime # there is some confusion with this uri, # it's in 1/config/eip, config/eip and config/1/eip... config_uri = "%s/%s/config/eip-service.json" % ( self._provider_config.get_api_uri(), api_version) logger.debug('Downloading eip config from: %s' % config_uri) res = self._session.get(config_uri, verify=self._provider_config .get_ca_cert_path(), headers=headers, timeout=REQUEST_TIMEOUT) res.raise_for_status() # Not modified if res.status_code == 304: logger.debug("EIP definition has not been modified") else: eip_definition, mtime = get_content(res) self._eip_config.load(data=eip_definition, mtime=mtime) self._eip_config.save(["leap", "providers", self._provider_config.get_domain(), "eip-service.json"])
def download_service_config(provider_config, service_config, session, download_if_needed=True): """ Downloads config for a given service. :param provider_config: an instance of ProviderConfig :type provider_config: ProviderConfig :param service_config: an instance of a particular Service config. :type service_config: BaseConfig :param session: an instance of a fetcher.session (currently we're using requests only, but it can be anything that implements that interface) :type session: requests.sessions.Session """ service_name = service_config.name service_json = "{0}-service.json".format(service_name) headers = {} mtime = get_mtime(os.path.join(util.get_path_prefix(), "leap", "providers", provider_config.get_domain(), service_json)) if download_if_needed and mtime: headers['if-modified-since'] = mtime api_version = provider_config.get_api_version() config_uri = "%s/%s/config/%s-service.json" % ( provider_config.get_api_uri(), api_version, service_name) logger.debug('Downloading %s config from: %s' % ( service_name.upper(), config_uri)) # XXX make and use @with_srp_auth decorator srp_auth = SRPAuth(provider_config) session_id = srp_auth.get_session_id() token = srp_auth.get_token() cookies = None if session_id is not None: cookies = {"_session_id": session_id} # API v2 will only support token auth, but in v1 we can send both if token is not None: headers["Authorization"] = 'Token token="{0}"'.format(token) verify = provider_config.get_ca_cert_path() if verify: verify = verify.encode(sys.getfilesystemencoding()) res = session.get(config_uri, verify=verify, headers=headers, timeout=REQUEST_TIMEOUT, cookies=cookies) res.raise_for_status() service_config.set_api_version(api_version) # Not modified service_path = ("leap", "providers", provider_config.get_domain(), service_json) if res.status_code == 304: logger.debug( "{0} definition has not been modified".format( service_name.upper())) service_config.load(os.path.join(*service_path)) else: service_definition, mtime = get_content(res) service_config.load(data=service_definition, mtime=mtime) service_config.save(service_path)
def register_user(self, username, password): """ Registers a user with the validator based on the password provider :param username: username to register :type username: str :param password: password for this username :type password: str :returns: if the registration went ok or not, and the returned status code of of the request :rtype: (bool, int) """ username = username.lower().encode('utf-8') password = password.encode('utf-8') salt, verifier = self._srp.create_salted_verification_key( username, password, self._hashfun, self._ng) user_data = { self.USER_LOGIN_KEY: username, self.USER_VERIFIER_KEY: binascii.hexlify(verifier), self.USER_SALT_KEY: binascii.hexlify(salt) } uri = self._get_registration_uri() logger.debug('Post to uri: %s' % uri) logger.debug("Will try to register user = %s" % (username,)) ok = False req = None try: req = self._session.post(uri, data=user_data, timeout=SIGNUP_TIMEOUT, verify=self._provider_config. get_ca_cert_path()) except requests.exceptions.RequestException as exc: logger.error(exc.message) else: ok = req.ok status_code = self.STATUS_ERROR if req is not None: status_code = req.status_code if not ok: try: content, _ = get_content(req) json_content = json.loads(content) error_msg = json_content.get("errors").get("login")[0] if not error_msg.istitle(): error_msg = "%s %s" % (username, error_msg) logger.error(error_msg) except Exception as e: logger.error("Unknown error: %r" % (e, )) return ok, status_code
def _download_provider_info(self, *args): """ Downloads the provider.json defition """ leap_assert(self._domain, "Cannot download provider info without a domain") logger.debug("Downloading provider info for %r" % (self._domain)) # -------------------------------------------------------------- # TODO factor out with the download routines in services. # Watch out! We're handling the verify paramenter differently here. headers = {} domain = self._domain.encode(sys.getfilesystemencoding()) provider_json = os.path.join(util.get_path_prefix(), get_provider_path(domain)) if domain in PinnedProviders.domains() and \ not os.path.exists(provider_json): mkdir_p(os.path.join(os.path.dirname(provider_json), "keys", "ca")) cacert = os.path.join(os.path.dirname(provider_json), "keys", "ca", "cacert.pem") PinnedProviders.save_hardcoded(domain, provider_json, cacert) mtime = get_mtime(provider_json) if self._download_if_needed and mtime: headers['if-modified-since'] = mtime uri = "https://%s/%s" % (self._domain, "provider.json") verify = self.verify if mtime: # the provider.json exists # So, we're getting it from the api.* and checking against # the provider ca. try: provider_config = ProviderConfig() provider_config.load(provider_json) uri = provider_config.get_api_uri() + '/provider.json' verify = provider_config.get_ca_cert_path() except MissingCACert: # no ca? then download from main domain again. pass if verify: verify = verify.encode(sys.getfilesystemencoding()) logger.debug("Requesting for provider.json... " "uri: {0}, verify: {1}, headers: {2}".format( uri, verify, headers)) res = self._session.get(uri.encode('idna'), verify=verify, headers=headers, timeout=REQUEST_TIMEOUT) res.raise_for_status() logger.debug("Request status code: {0}".format(res.status_code)) min_client_version = res.headers.get(self.MIN_CLIENT_VERSION, '0') # Not modified if res.status_code == 304: logger.debug("Provider definition has not been modified") # -------------------------------------------------------------- # end refactor, more or less... # XXX Watch out, have to check the supported api yet. else: if flags.APP_VERSION_CHECK: # TODO split if not provider.supports_client(min_client_version): self._signaler.signal( self._signaler.prov_unsupported_client) raise UnsupportedClientVersionError() provider_definition, mtime = get_content(res) provider_config = ProviderConfig() provider_config.load(data=provider_definition, mtime=mtime) provider_config.save(["leap", "providers", domain, "provider.json"]) if flags.API_VERSION_CHECK: # TODO split api_version = provider_config.get_api_version() if provider.supports_api(api_version): logger.debug("Provider definition has been modified") else: api_supported = ', '.join(provider.SUPPORTED_APIS) error = ('Unsupported provider API version. ' 'Supported versions are: {0}. ' 'Found: {1}.').format(api_supported, api_version) logger.error(error) self._signaler.signal(self._signaler.prov_unsupported_api) raise UnsupportedProviderAPI(error)
def _process_challenge(self, salt_B, username): """ Given the salt and B processes the auth challenge and generates the M2 parameter Might raise SRPAuthenticationError based: SRPAuthenticationError SRPAuthBadDataFromServer SRPAuthConnectionError SRPAuthJSONDecodeError SRPAuthBadUserOrPassword :param salt_B: salt and B parameters for the username :type salt_B: tuple :param username: username for this session :type username: str :return: the M2 SRP parameter :rtype: str """ logger.debug("Processing challenge...") try: salt, B = salt_B unhex_salt = self._safe_unhexlify(salt) unhex_B = self._safe_unhexlify(B) except (TypeError, ValueError) as e: logger.error("Bad data from server: %r" % (e,)) raise SRPAuthBadDataFromServer( self.tr("The data sent from the server had errors")) M = self._srp_user.process_challenge(unhex_salt, unhex_B) auth_url = "%s/%s/%s/%s" % (self._provider_config.get_api_uri(), self._provider_config. get_api_version(), "sessions", username) auth_data = { self.CLIENT_AUTH_KEY: binascii.hexlify(M) } try: auth_result = self._session.put(auth_url, data=auth_data, verify=self._provider_config. get_ca_cert_path(), timeout=REQUEST_TIMEOUT) except requests.exceptions.ConnectionError as e: logger.error("No connection made (HAMK): %r" % (e,)) raise SRPAuthConnectionError(self.tr("Could not connect to " "the server")) try: content, mtime = reqhelper.get_content(auth_result) except JSONDecodeError: raise SRPAuthJSONDecodeError("Bad JSON content in auth result") if auth_result.status_code == 422: error = "" try: error = json.loads(content).get("errors", "") except ValueError: logger.error("Problem parsing the received response: %s" % (content,)) except AttributeError: logger.error("Expecting a dict but something else was " "received: %s", (content,)) logger.error("[%s] Wrong password (HAMK): [%s]" % (auth_result.status_code, error)) raise SRPAuthBadUserOrPassword(self._WRONG_USER_PASS) if auth_result.status_code not in (200,): logger.error("No valid response (HAMK): " "Status code = %s. Content = %r" % (auth_result.status_code, content)) raise SRPAuthBadStatusCode(self.tr("Unknown error (%s)") % (auth_result.status_code,)) return json.loads(content)
def _start_authentication(self, _, username): """ Sends the first request for authentication to retrieve the salt and B parameter Might raise all SRPAuthenticationError based: SRPAuthenticationError SRPAuthConnectionError SRPAuthBadStatusCode SRPAuthNoSalt SRPAuthNoB :param _: IGNORED, output from the previous callback (None) :type _: IGNORED :param username: username to login :type username: str :return: salt and B parameters :rtype: tuple """ logger.debug("Starting authentication process...") try: auth_data = { self.LOGIN_KEY: username, self.A_KEY: binascii.hexlify(self._srp_a) } sessions_url = "%s/%s/%s/" % \ (self._provider_config.get_api_uri(), self._provider_config.get_api_version(), "sessions") ca_cert_path = self._provider_config.get_ca_cert_path() ca_cert_path = ca_cert_path.encode(sys.getfilesystemencoding()) init_session = self._session.post(sessions_url, data=auth_data, verify=ca_cert_path, timeout=REQUEST_TIMEOUT) # Clean up A value, we don't need it anymore self._srp_a = None except requests.exceptions.ConnectionError as e: logger.error("No connection made (salt): %r" % (e,)) raise SRPAuthConnectionError("Could not establish a " "connection") except Exception as e: logger.error("Unknown error: %r" % (e,)) raise SRPAuthenticationError("Unknown error: %r" % (e,)) content, mtime = reqhelper.get_content(init_session) if init_session.status_code not in (200,): logger.error("No valid response (salt): " "Status code = %r. Content: %r" % (init_session.status_code, content)) if init_session.status_code == 422: raise SRPAuthBadUserOrPassword(self._WRONG_USER_PASS) raise SRPAuthBadStatusCode(self.tr("There was a problem with" " authentication")) json_content = json.loads(content) salt = json_content.get("salt", None) B = json_content.get("B", None) if salt is None: logger.error("No salt parameter sent") raise SRPAuthNoSalt(self.tr("The server did not send " "the salt parameter")) if B is None: logger.error("No B parameter sent") raise SRPAuthNoB(self.tr("The server did not send " "the B parameter")) return salt, B
def _process_challenge(self, salt_B, username): """ Given the salt and B processes the auth challenge and generates the M2 parameter Might raise SRPAuthenticationError based: SRPAuthenticationError SRPAuthBadDataFromServer SRPAuthConnectionError SRPAuthJSONDecodeError SRPAuthBadUserOrPassword :param salt_B: salt and B parameters for the username :type salt_B: tuple :param username: username for this session :type username: str :return: the M2 SRP parameter :rtype: str """ logger.debug("Processing challenge...") try: salt, B = salt_B unhex_salt = self._safe_unhexlify(salt) unhex_B = self._safe_unhexlify(B) except (TypeError, ValueError) as e: logger.error("Bad data from server: %r" % (e, )) raise SRPAuthBadDataFromServer() M = self._srp_user.process_challenge(unhex_salt, unhex_B) auth_url = "%s/%s/%s/%s" % (self._provider_config.get_api_uri(), self._provider_config.get_api_version(), "sessions", username) auth_data = {self.CLIENT_AUTH_KEY: binascii.hexlify(M)} try: auth_result = self._session.put( auth_url, data=auth_data, verify=self._provider_config.get_ca_cert_path(), timeout=REQUEST_TIMEOUT) except requests.exceptions.ConnectionError as e: logger.error("No connection made (HAMK): %r" % (e, )) raise SRPAuthConnectionError() try: content, mtime = reqhelper.get_content(auth_result) except JSONDecodeError: logger.error("Bad JSON content in auth result.") raise SRPAuthJSONDecodeError() if auth_result.status_code == 422: error = "" try: error = json.loads(content).get("errors", "") except ValueError: logger.error("Problem parsing the received response: %s" % (content, )) except AttributeError: logger.error( "Expecting a dict but something else was " "received: %s", (content, )) logger.error("[%s] Wrong password (HAMK): [%s]" % (auth_result.status_code, error)) raise SRPAuthBadUserOrPassword() if auth_result.status_code not in (200, ): logger.error("No valid response (HAMK): " "Status code = %s. Content = %r" % (auth_result.status_code, content)) raise SRPAuthBadStatusCode() return json.loads(content)
def _start_authentication(self, _, username): """ Sends the first request for authentication to retrieve the salt and B parameter Might raise all SRPAuthenticationError based: SRPAuthenticationError SRPAuthConnectionError SRPAuthBadStatusCode SRPAuthNoSalt SRPAuthNoB :param _: IGNORED, output from the previous callback (None) :type _: IGNORED :param username: username to login :type username: str :return: salt and B parameters :rtype: tuple """ logger.debug("Starting authentication process...") try: auth_data = { self.LOGIN_KEY: username, self.A_KEY: binascii.hexlify(self._srp_a) } sessions_url = "%s/%s/%s/" % \ (self._provider_config.get_api_uri(), self._provider_config.get_api_version(), "sessions") ca_cert_path = self._provider_config.get_ca_cert_path() ca_cert_path = ca_cert_path.encode(sys.getfilesystemencoding()) init_session = self._session.post(sessions_url, data=auth_data, verify=ca_cert_path, timeout=REQUEST_TIMEOUT) # Clean up A value, we don't need it anymore self._srp_a = None except requests.exceptions.ConnectionError as e: logger.error("No connection made (salt): {0!r}".format(e)) raise SRPAuthConnectionError() except Exception as e: logger.error("Unknown error: %r" % (e, )) raise SRPAuthenticationError() content, mtime = reqhelper.get_content(init_session) if init_session.status_code not in (200, ): logger.error("No valid response (salt): " "Status code = %r. Content: %r" % (init_session.status_code, content)) if init_session.status_code == 422: logger.error("Invalid username or password.") raise SRPAuthBadUserOrPassword() logger.error("There was a problem with authentication.") raise SRPAuthBadStatusCode() json_content = json.loads(content) salt = json_content.get("salt", None) B = json_content.get("B", None) if salt is None: logger.error("The server didn't send the salt parameter.") raise SRPAuthNoSalt() if B is None: logger.error("The server didn't send the B parameter.") raise SRPAuthNoB() return salt, B
def _download_provider_info(self, *args): """ Downloads the provider.json defition """ leap_assert(self._domain, "Cannot download provider info without a domain") logger.debug("Downloading provider info for %r" % (self._domain)) # -------------------------------------------------------------- # TODO factor out with the download routines in services. # Watch out! We're handling the verify paramenter differently here. headers = {} domain = self._domain.encode(sys.getfilesystemencoding()) provider_json = os.path.join(util.get_path_prefix(), get_provider_path(domain)) if domain in PinnedProviders.domains() and \ not os.path.exists(provider_json): mkdir_p(os.path.join(os.path.dirname(provider_json), "keys", "ca")) cacert = os.path.join(os.path.dirname(provider_json), "keys", "ca", "cacert.pem") PinnedProviders.save_hardcoded(domain, provider_json, cacert) mtime = get_mtime(provider_json) if self._download_if_needed and mtime: headers['if-modified-since'] = mtime uri = "https://%s/%s" % (self._domain, "provider.json") verify = self.verify if mtime: # the provider.json exists # So, we're getting it from the api.* and checking against # the provider ca. try: provider_config = ProviderConfig() provider_config.load(provider_json) uri = provider_config.get_api_uri() + '/provider.json' verify = provider_config.get_ca_cert_path() except MissingCACert: # no ca? then download from main domain again. pass if verify: verify = verify.encode(sys.getfilesystemencoding()) logger.debug("Requesting for provider.json... " "uri: {0}, verify: {1}, headers: {2}".format( uri, verify, headers)) res = self._session.get(uri.encode('idna'), verify=verify, headers=headers, timeout=REQUEST_TIMEOUT) res.raise_for_status() logger.debug("Request status code: {0}".format(res.status_code)) min_client_version = res.headers.get(self.MIN_CLIENT_VERSION, '0') # Not modified if res.status_code == 304: logger.debug("Provider definition has not been modified") # -------------------------------------------------------------- # end refactor, more or less... # XXX Watch out, have to check the supported api yet. else: if flags.APP_VERSION_CHECK: # TODO split if not provider.supports_client(min_client_version): if self._signaler is not None: self._signaler.signal( self._signaler.prov_unsupported_client) raise UnsupportedClientVersionError() provider_definition, mtime = get_content(res) provider_config = ProviderConfig() provider_config.load(data=provider_definition, mtime=mtime) provider_config.save( ["leap", "providers", domain, "provider.json"]) if flags.API_VERSION_CHECK: # TODO split api_version = provider_config.get_api_version() if provider.supports_api(api_version): logger.debug("Provider definition has been modified") else: api_supported = ', '.join(provider.SUPPORTED_APIS) error = ('Unsupported provider API version. ' 'Supported versions are: {0}. ' 'Found: {1}.').format(api_supported, api_version) logger.error(error) if self._signaler is not None: self._signaler.signal( self._signaler.prov_unsupported_api) raise UnsupportedProviderAPI(error)
def _download_provider_info(self, *args): """ Downloads the provider.json defition """ leap_assert(self._domain, "Cannot download provider info without a domain") logger.debug("Downloading provider info for %s" % (self._domain)) headers = {} provider_json = os.path.join( ProviderConfig().get_path_prefix(), "leap", "providers", self._domain, "provider.json") mtime = get_mtime(provider_json) if self._download_if_needed and mtime: headers['if-modified-since'] = mtime uri = "https://%s/%s" % (self._domain, "provider.json") verify = not self._bypass_checks if mtime: # the provider.json exists provider_config = ProviderConfig() provider_config.load(provider_json) try: verify = provider_config.get_ca_cert_path() uri = provider_config.get_api_uri() + '/provider.json' except MissingCACert: # get_ca_cert_path fails if the certificate does not exists. pass logger.debug("Requesting for provider.json... " "uri: {0}, verify: {1}, headers: {2}".format( uri, verify, headers)) res = self._session.get(uri, verify=verify, headers=headers, timeout=REQUEST_TIMEOUT) res.raise_for_status() logger.debug("Request status code: {0}".format(res.status_code)) # Not modified if res.status_code == 304: logger.debug("Provider definition has not been modified") else: provider_definition, mtime = get_content(res) provider_config = ProviderConfig() provider_config.load(data=provider_definition, mtime=mtime) provider_config.save(["leap", "providers", self._domain, "provider.json"]) api_version = provider_config.get_api_version() if SupportedAPIs.supports(api_version): logger.debug("Provider definition has been modified") else: api_supported = ', '.join(SupportedAPIs.SUPPORTED_APIS) error = ('Unsupported provider API version. ' 'Supported versions are: {}. ' 'Found: {}.').format(api_supported, api_version) logger.error(error) raise UnsupportedProviderAPI(error)