From 98384361a7c49ad4e0ff0127fd923a8b72cc910a Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 8 Dec 2015 21:04:11 -0400 Subject: [feat] adapt to use cred-based authentication for imap This includes getting the token for the imap authentication, and displaying it on the help window. - Resolves: #4469 - Releases: 0.10.0 --- changes/next-changelog.rst | 5 ++-- src/leap/bitmask/backend/api.py | 2 ++ src/leap/bitmask/backend/components.py | 23 ++++++++++++++++++ src/leap/bitmask/backend/leapbackend.py | 7 ++++++ src/leap/bitmask/backend/leapsignaler.py | 1 + src/leap/bitmask/gui/mainwindow.py | 18 +++++++++++++- src/leap/bitmask/services/mail/imap.py | 31 ++++++++++++------------ src/leap/bitmask/services/mail/imapcontroller.py | 8 +++--- 8 files changed, 71 insertions(+), 24 deletions(-) diff --git a/changes/next-changelog.rst b/changes/next-changelog.rst index 77094e78..c359b4e2 100644 --- a/changes/next-changelog.rst +++ b/changes/next-changelog.rst @@ -1,4 +1,4 @@ -0.9.2 - xxx +0.10.0 - xxx +++++++++++++++++++++++++++++++ Please add lines to this file, they will be moved to the CHANGELOG.rst during @@ -11,8 +11,9 @@ I've added a new category `Misc` so we can track doc/style/packaging stuff. Features ~~~~~~~~ - `#7552 `_: Improve UI message and add some margin above the msg box. -- `#7552 `_: Improve UI message and add some margin above the msg box. - `#7656 `_: Adapt to multi-user aware events. +- `#4469 `_: Display randomly generated service token on the Help Window. +- `#1234 `_: Description of the new feature corresponding with issue #1234. - New feature without related issue number. Bugfixes diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py index 48aa2090..134a2d56 100644 --- a/src/leap/bitmask/backend/api.py +++ b/src/leap/bitmask/backend/api.py @@ -57,6 +57,7 @@ API = ( "soledad_change_password", "soledad_close", "soledad_load_offline", + "soledad_get_service_token", "tear_fw_down", "bitmask_root_vpn_down", "user_cancel_login", @@ -135,6 +136,7 @@ SIGNALS = ( "soledad_offline_finished", "soledad_password_change_error", "soledad_password_change_ok", + "soledad_got_service_token", "srp_auth_bad_user_or_password", "srp_auth_connection_error", "srp_auth_error", diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index 5f34d290..a07d3bad 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -763,6 +763,7 @@ class Soledad(object): self._signaler = signaler self._soledad_bootstrapper = SoledadBootstrapper(signaler) self._soledad_defer = None + self._service_tokens = {} def bootstrap(self, username, domain, password): """ @@ -786,6 +787,7 @@ class Soledad(object): provider_config, username, password, download_if_needed=True) self._soledad_defer.addCallback(self._set_proxies_cb) + self._soledad_defer.addCallback(self._set_service_tokens_cb) else: if self._signaler is not None: self._signaler.signal(self._signaler.soledad_bootstrap_failed) @@ -793,6 +795,21 @@ class Soledad(object): return self._soledad_defer + def _set_service_tokens_cb(self, result): + + def register_imap_token(imap_token): + self._service_tokens['imap'] = imap_token + if self._signaler is not None: + self._signaler.signal( + self._signaler.soledad_got_service_token, + ('imap', imap_token)) + + sol = self._soledad_bootstrapper.soledad + d = sol.get_or_create_service_token('imap') + d.addCallback(register_imap_token) + d.addCallback(lambda _: result) + return d + def _set_proxies_cb(self, _): """ Update the soledad and keymanager proxies to reference the ones created @@ -803,6 +820,12 @@ class Soledad(object): zope.proxy.setProxiedObject(self._keymanager_proxy, self._soledad_bootstrapper.keymanager) + def get_service_token(self, service): + """ + Get an authentication token for a given service. + """ + return self._service_tokens.get(service, '') + def load_offline(self, username, password, uuid): """ Load the soledad database in offline mode. diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py index cf45c4f8..d0668a1c 100644 --- a/src/leap/bitmask/backend/leapbackend.py +++ b/src/leap/bitmask/backend/leapbackend.py @@ -35,6 +35,7 @@ class LeapBackend(Backend): """ Backend server subclass, used to implement the API methods. """ + def __init__(self, bypass_checks=False, frontend_pid=None): """ Constructor for the backend. @@ -438,6 +439,12 @@ class LeapBackend(Backend): """ self._soledad.load_offline(username, password, uuid) + def soledad_get_service_token(self, service): + """ + Attempt to get an authentication token for a given service. + """ + self._soledad.get_service_token(service) + def soledad_cancel_bootstrap(self): """ Cancel the ongoing soledad bootstrapping process (if any). diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py index 1ac51f5e..13a9fa5f 100644 --- a/src/leap/bitmask/backend/leapsignaler.py +++ b/src/leap/bitmask/backend/leapsignaler.py @@ -97,6 +97,7 @@ class LeapSignaler(SignalerQt): soledad_offline_finished = QtCore.Signal() soledad_password_change_error = QtCore.Signal() soledad_password_change_ok = QtCore.Signal() + soledad_got_service_token = QtCore.Signal(object) srp_auth_bad_user_or_password = QtCore.Signal() srp_auth_connection_error = QtCore.Signal() diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index a8a4e41d..189a6295 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -407,6 +407,10 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): sig.soledad_invalid_auth_token.connect( self._mail_status.set_soledad_invalid_auth_token) + self._service_tokens = {} + sig.soledad_got_service_token.connect( + self._set_service_tokens) + # TODO: connect this with something # sig.soledad_cancelled_bootstrap.connect() @@ -1033,6 +1037,13 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): msg = msg.format(ver=VERSION, ver_hash=VERSION_HASH[:10], greet=greet) QtGui.QMessageBox.about(self, title, msg) + def _set_service_tokens(self, data): + """ + Set the received service token. + """ + service, token = data + self._service_tokens[service] = token + def _help(self): """ TRIGGERS: @@ -1063,7 +1074,12 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): manual_imap = self.tr("IMAP: localhost, port {0}".format(IMAP_PORT)) manual_smtp = self.tr("SMTP: localhost, port {0}".format(smtp_port)) manual_username = self.tr("Username: your full email address") - manual_password = self.tr("Password: any non-empty text") + + # TODO this should be a widget that allows to be copied to the + # clipboard. + imap_token = (self._service_tokens.get('imap', None) + or "??? (log in to unlock)") + manual_password = self.tr("Password: ") + "%s" % (imap_token, ) msg = help_url + self.tr( "

{0}

" diff --git a/src/leap/bitmask/services/mail/imap.py b/src/leap/bitmask/services/mail/imap.py index b06c1d4a..54935f8c 100644 --- a/src/leap/bitmask/services/mail/imap.py +++ b/src/leap/bitmask/services/mail/imap.py @@ -20,11 +20,14 @@ Initialization of imap service import os import sys +from twisted.python import log + from leap.bitmask.logs.utils import get_logger from leap.mail.constants import INBOX_NAME from leap.mail.imap.service import imap from leap.mail.incoming.service import IncomingMail, INCOMING_CHECK_PERIOD -from twisted.python import log +from leap.mail.mail import Account + logger = get_logger() @@ -57,11 +60,13 @@ def get_mail_check_period(): return period -def start_imap_service(*args, **kwargs): +def start_imap_service(soledad_sessions): """ Initializes and run imap service. - :returns: LeapIMAPFactory instance + :returns: the port as returned by the reactor when starts listening, and + the factory for the protocol. + :rtype: tuple """ from leap.bitmask.config import flags logger.debug('Launching imap service') @@ -70,10 +75,10 @@ def start_imap_service(*args, **kwargs): log.startLogging(open(flags.MAIL_LOGFILE, 'w')) log.startLogging(sys.stdout) - return imap.run_service(*args, **kwargs) + return imap.run_service(soledad_sessions) -def start_incoming_mail_service(keymanager, soledad, imap_factory, userid): +def start_incoming_mail_service(keymanager, soledad, userid): """ Initalizes and starts the incomming mail service. @@ -81,19 +86,13 @@ def start_incoming_mail_service(keymanager, soledad, imap_factory, userid): """ def setUpIncomingMail(inbox): incoming_mail = IncomingMail( - keymanager, - soledad, - inbox.collection, - userid, + keymanager, soledad, + inbox, userid, check_period=get_mail_check_period()) return incoming_mail - # XXX: do I really need to know here how to get a mailbox?? - # XXX: ideally, the parent service in mail would take care of initializing - # the account, and passing the mailbox to the incoming service. - # In an even better world, we just would subscribe to a channel that would - # pass us the serialized object to be inserted. - acc = imap_factory.theAccount - d = acc.callWhenReady(lambda _: acc.getMailbox(INBOX_NAME)) + acc = Account(soledad) + d = acc.callWhenReady(lambda _: acc.get_collection_by_mailbox(INBOX_NAME)) d.addCallback(setUpIncomingMail) + d.addErrback(log.err) return d diff --git a/src/leap/bitmask/services/mail/imapcontroller.py b/src/leap/bitmask/services/mail/imapcontroller.py index 5053d897..855fb74b 100644 --- a/src/leap/bitmask/services/mail/imapcontroller.py +++ b/src/leap/bitmask/services/mail/imapcontroller.py @@ -60,9 +60,9 @@ class IMAPController(object): """ logger.debug('Starting imap service') + soledad_sessions = {userid: self._soledad} self.imap_port, self.imap_factory = imap.start_imap_service( - self._soledad, - userid=userid) + soledad_sessions) def start_and_assign_incoming_service(incoming_mail): # this returns a deferred that will be called when the looping call @@ -74,9 +74,7 @@ class IMAPController(object): if offline is False: d = imap.start_incoming_mail_service( - self._keymanager, - self._soledad, - self.imap_factory, + self._keymanager, self._soledad, userid) d.addCallback(start_and_assign_incoming_service) d.addErrback(lambda f: logger.error(f.printTraceback())) -- cgit v1.2.3