diff -Nru ubuntu-sso-client-3.0.0/debian/changelog ubuntu-sso-client-3.0.2/debian/changelog --- ubuntu-sso-client-3.0.0/debian/changelog 2012-05-07 18:52:55.000000000 +0000 +++ ubuntu-sso-client-3.0.2/debian/changelog 2012-06-29 21:00:31.000000000 +0000 @@ -1,3 +1,16 @@ +ubuntu-sso-client (3.0.2-0ubuntu1) precise-proposed; urgency=low + + * New upstream release. (LP: #1018991) + - Trap DBusExceptions when connecting to Session bus. (LP: #711413) + - Set strict and ca-cert-file properties on webkit. (LP: #882055) + - Remove back buttons in sign-in/up pages. (LP: #1009107) + * debian/patches: + - Remove the upstreamed patches. + * debian/watch: + - Update the watch file to use stable-3-0 series for 12.04. + + -- Rodney Dawes Fri, 29 Jun 2012 17:00:20 -0400 + ubuntu-sso-client (3.0.0-0ubuntu2) precise-proposed; urgency=low * debian/patches/01_lp-994632.patch: diff -Nru ubuntu-sso-client-3.0.0/debian/patches/00_bzr837-lp-960657.patch ubuntu-sso-client-3.0.2/debian/patches/00_bzr837-lp-960657.patch --- ubuntu-sso-client-3.0.0/debian/patches/00_bzr837-lp-960657.patch 2012-05-07 18:48:11.000000000 +0000 +++ ubuntu-sso-client-3.0.2/debian/patches/00_bzr837-lp-960657.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -=== modified file 'ubuntu_sso/gtk/gui.py' ---- old/ubuntu_sso/gtk/gui.py 2012-04-09 17:38:24 +0000 -+++ new/ubuntu_sso/gtk/gui.py 2012-04-11 16:49:02 +0000 -@@ -539,11 +539,12 @@ class UbuntuSSOClientGUI(object): - - msg = YES_TO_UPDATES % {'app_name': self.app_name} - self.yes_to_updates_checkbutton.set_label(msg) -- if self.tc_url: -- msg = YES_TO_TC % {'app_name': self.app_name} -- self.yes_to_tc_checkbutton.set_label(msg) -- self.tc_button.set_label(TC_BUTTON) -- else: -+ -+ msg = YES_TO_TC % {'app_name': self.app_name} -+ self.yes_to_tc_checkbutton.set_label(msg) -+ self.tc_button.set_label(TC_BUTTON) -+ -+ if not self.tc_url: - self.tc_vbox.hide() - self.login_button.set_label(LOGIN_BUTTON_LABEL) - -@@ -741,6 +742,7 @@ class UbuntuSSOClientGUI(object): - name = self.name_entry.get_text() - if not name: - self.name_entry.set_warning(FIELD_REQUIRED) -+ logger.warning('on_join_ok_button_clicked: name not set.') - error = True - - # check email -@@ -750,6 +752,7 @@ class UbuntuSSOClientGUI(object): - if msg is not None: - self.email1_entry.set_warning(msg) - self.email2_entry.set_warning(msg) -+ logger.warning('on_join_ok_button_clicked: email is not valid.') - error = True - - # check password -@@ -759,22 +762,30 @@ class UbuntuSSOClientGUI(object): - if msg is not None: - self.password1_entry.set_warning(msg) - self.password2_entry.set_warning(msg) -+ logger.warning('on_join_ok_button_clicked: password is not valid.') - error = True - - # check T&C -- if not self.yes_to_tc_checkbutton.get_active(): -+ if self.tc_url and not self.yes_to_tc_checkbutton.get_active(): - self._set_warning_message(self.tc_warning_label, - TC_NOT_ACCEPTED % {'app_name': self.app_name}) -+ logger.warning('on_join_ok_button_clicked: terms and conditions ' -+ 'not accepted.') - error = True - - captcha_solution = self.captcha_solution_entry.get_text() - if not captcha_solution: - self.captcha_solution_entry.set_warning(FIELD_REQUIRED) -+ logger.warning('on_join_ok_button_clicked: captcha solution not ' -+ 'set.') - error = True - - if error: -+ logger.warning('on_join_ok_button_clicked: validation failed.') - return - -+ logger.info('on_join_ok_button_clicked: validation success!') -+ - self._set_current_page(self.processing_vbox) - self.user_email = email1 - self.user_password = password1 - -=== modified file 'ubuntu_sso/gtk/tests/test_gui.py' ---- old/ubuntu_sso/gtk/tests/test_gui.py 2012-04-09 17:38:24 +0000 -+++ new/ubuntu_sso/gtk/tests/test_gui.py 2012-04-11 16:49:02 +0000 -@@ -473,8 +473,9 @@ class UbuntuSSOClientTestCase(BasicTestC - # match passwords - self.ui.password1_entry.set_text(PASSWORD) - self.ui.password2_entry.set_text(PASSWORD) -- # agree to TC -- self.ui.yes_to_tc_checkbutton.set_active(True) -+ if self.ui.tc_url: -+ # agree to TC, only if the tc_url is defined, so we catch errors -+ self.ui.yes_to_tc_checkbutton.set_active(True) - # resolve captcha properly - self.ui.captcha_solution_entry.set_text(CAPTCHA_SOLUTION) - -@@ -694,15 +695,15 @@ class EnterDetailsTestCase(UbuntuSSOClie - self.assertEqual(expected, actual, - msg % ('yes_to_tc_checkbutton', expected, actual)) - -- def test_checkbutton_is_checked_at_startup(self): -- """Checkbuttons are checked by default.""" -+ def test_updates_checkbutton_is_checked_at_startup(self): -+ """The 'yes to updates' checkbutton is checked by default.""" - msg = '%r is checked by default.' - name = 'yes_to_updates_checkbutton' - widget = getattr(self.ui, name) - self.assertTrue(widget.get_active(), msg % name) - -- def test_checkbutton_isnt_checked_at_startup(self): -- """Checkbuttons are checked by default.""" -+ def test_tc_checkbutton_is_not_checked_at_startup(self): -+ """The 'yes to T&C' checkbutton is not checked by default.""" - msg = '%r is checked by default.' - name = 'yes_to_tc_checkbutton' - widget = getattr(self.ui, name) -@@ -887,26 +888,22 @@ class EnterDetailsTestCase(UbuntuSSOClie - self.ui.on_captcha_generated(app_name=APP_NAME, captcha_id=CAPTCHA_ID) - self.assertEqual(self.ui.warning_label.get_text().decode('utf8'), '') - -+ def test_has_tc_link(self): -+ """The T&C button and checkbox are shown if the link is provided""" -+ self.assertEqual(self.ui.tc_button.get_visible(), True) -+ self.assertEqual(self.ui.yes_to_tc_checkbutton.get_visible(), True) - --class NoTermsAndConditionsTestCase(UbuntuSSOClientTestCase): -+ -+class NoTermsAndConditionsTestCase(EnterDetailsTestCase): - """Test suite for the user registration (with no t&c link).""" - - kwargs = dict(app_name=APP_NAME, tc_url='', help_text=HELP_TEXT) - -- def test_no_tc_link(self): -+ def test_has_tc_link(self): - """The T&C button and checkbox are not shown if no link is provided""" - self.assertEqual(self.ui.tc_vbox.get_visible(), False) - - --class TermsAndConditionsTestCase(UbuntuSSOClientTestCase): -- """Test suite for the user registration (terms & conditions page).""" -- -- def test_has_tc_link(self): -- """The T&C button and checkbox are shown if the link is provided""" -- self.assertEqual(self.ui.tc_button.get_visible(), True) -- self.assertEqual(self.ui.yes_to_tc_checkbutton.get_visible(), True) -- -- - class TermsAndConditionsBrowserTestCase(UbuntuSSOClientTestCase): - """Test suite for the terms & conditions browser.""" - - diff -Nru ubuntu-sso-client-3.0.0/debian/patches/01_lp-994632.patch ubuntu-sso-client-3.0.2/debian/patches/01_lp-994632.patch --- ubuntu-sso-client-3.0.0/debian/patches/01_lp-994632.patch 2012-05-07 18:27:17.000000000 +0000 +++ ubuntu-sso-client-3.0.2/debian/patches/01_lp-994632.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,232 +0,0 @@ -=== modified file 'ubuntu_sso/credentials.py' ---- old/ubuntu_sso/credentials.py 2012-04-09 17:38:24 +0000 -+++ new/ubuntu_sso/credentials.py 2012-05-04 19:10:20 +0000 -@@ -49,7 +49,12 @@ - - from twisted.internet import defer - --from ubuntu_sso import UI_EXECUTABLE_GTK, USER_CANCELLATION, USER_SUCCESS -+from ubuntu_sso import ( -+ UI_EXECUTABLE_GTK, -+ UI_EXECUTABLE_QT, -+ USER_CANCELLATION, -+ USER_SUCCESS, -+) - from ubuntu_sso.keyring import Keyring - from ubuntu_sso.logger import setup_logging - from ubuntu_sso.utils import get_bin_dir, runner -@@ -79,6 +84,10 @@ - """The user is not validated.""" - - -+class GUINotAvailableError(CredentialsError): -+ """No user graphical interface is available.""" -+ -+ - def handle_failures(msg): - """Handle failures using 'msg' as error message.""" - -@@ -153,14 +162,32 @@ - - @defer.inlineCallbacks - def _show_ui(self, login_only): -- """Shows the UI, connect outcome signals.""" -- ui_exe_path = os.path.join(get_bin_dir(), self.ui_executable) -- if not os.path.exists(ui_exe_path): -- logger.debug('Falling back to the GTK+ UI since the given %r ' -- 'does not exist', ui_exe_path) -- ui_exe_path = os.path.join(get_bin_dir(), UI_EXECUTABLE_GTK) -- -- assert os.path.exists(ui_exe_path) -+ """Show the UI and wait for it to finish. -+ -+ Upon analyzing returning code from the UI process, emit proper signals -+ to the caller. -+ -+ The caller can specify a preference for the UI (so far either GTK+ or -+ Qt UIs are available), but if the preferred one is not available, the -+ service will try to open any available UI. -+ -+ If no GUI is available, GUINotAvailableError will be raised. -+ -+ """ -+ guis = (self.ui_executable, UI_EXECUTABLE_GTK, UI_EXECUTABLE_QT) -+ for gui_exe_path in guis: -+ ui_exe_path = os.path.join(get_bin_dir(), gui_exe_path) -+ ui_exe_exists = os.path.exists(ui_exe_path) -+ logger.debug('Attempting to use the following executable as GUI: ' -+ '%r (exists? %r).', ui_exe_path, ui_exe_exists) -+ if not ui_exe_exists: -+ logger.error('The given UI path %r does not exist.', -+ ui_exe_path) -+ else: -+ break -+ else: -+ raise GUINotAvailableError('Can not find a GUI to present to the ' -+ 'user (tried with %r). Aborting.' % repr(guis)) - - args = [ui_exe_path] - for arg in ('app_name', 'help_text', 'ping_url', 'policy_url', - -=== modified file 'ubuntu_sso/tests/test_credentials.py' ---- old/ubuntu_sso/tests/test_credentials.py 2012-04-09 17:38:24 +0000 -+++ new/ubuntu_sso/tests/test_credentials.py 2012-05-04 19:10:20 +0000 -@@ -37,7 +37,7 @@ - - import ubuntu_sso.main - --from ubuntu_sso import credentials, utils -+from ubuntu_sso import credentials - from ubuntu_sso.credentials import ( - APP_NAME_KEY, - HELP_TEXT_KEY, -@@ -111,6 +111,8 @@ - class BasicTestCase(TestCase): - """Test case with a helper tracker.""" - -+ bin_dir = 'some/bin/dir' -+ - @defer.inlineCallbacks - def setUp(self): - """Init.""" -@@ -121,6 +123,8 @@ - self.memento.setLevel(logging.DEBUG) - credentials.logger.addHandler(self.memento) - -+ self.patch(credentials, 'get_bin_dir', lambda: self.bin_dir) -+ - def _set_called(self, *args, **kwargs): - """Set _called to True.""" - self._called = (args, kwargs) -@@ -285,8 +289,7 @@ - yield super(RegisterTestCase, self).setUp() - self.deferred = defer.Deferred() - self.patch_inner(self.fake_inner) -- self.exe_path = os.path.join(utils.get_bin_dir(), -- KWARGS[UI_EXECUTABLE_KEY]) -+ self.exe_path = os.path.join(self.bin_dir, KWARGS[UI_EXECUTABLE_KEY]) - self.inner_args = [ - self.exe_path, - '--app_name', APP_NAME, -@@ -347,11 +350,9 @@ - lambda kr, app: defer.succeed(None)) - self._next_inner_result = credentials.USER_SUCCESS - -- # patch os.path.exists so it also returns True when queried for the -- # faked exe_path -- really_exists = os.path.exists -+ # patch os.path.exists so it returns True for the faked exe_path - self.patch(credentials.os.path, 'exists', -- lambda path: path == self.exe_path or really_exists(path)) -+ lambda path: path == self.exe_path) - - result = yield self.method_call(**self.kwargs) - self.assertEqual(result, TOKEN) -@@ -368,34 +369,71 @@ - self._next_inner_result = credentials.USER_SUCCESS - - assert not os.path.exists(self.exe_path) -+ self.patch(credentials.os.path, 'exists', -+ lambda path: path.endswith(credentials.UI_EXECUTABLE_GTK)) - - result = yield self.method_call(**self.kwargs) - self.assertEqual(result, TOKEN) - - # the ui was opened and proper params were passed - args = yield self.deferred -- self.inner_args[0] = os.path.join(utils.get_bin_dir(), -+ self.inner_args[0] = os.path.join(self.bin_dir, - credentials.UI_EXECUTABLE_GTK) - self.assertEqual(self.inner_args, args) - - @defer.inlineCallbacks -+ def test_ui_executable_uses_qt_ui_if_gtk_not_available(self): -+ """The executable loads the QT UI if the GTK+ does not exist.""" -+ self.patch(credentials.Keyring, 'get_credentials', -+ lambda kr, app: defer.succeed(None)) -+ self._next_inner_result = credentials.USER_SUCCESS -+ -+ self.patch(credentials.os.path, 'exists', -+ lambda path: path.endswith(credentials.UI_EXECUTABLE_QT)) -+ -+ result = yield self.method_call(**self.kwargs) -+ self.assertEqual(result, TOKEN) -+ -+ # the ui was opened and proper params were passed -+ args = yield self.deferred -+ self.inner_args[0] = os.path.join(self.bin_dir, -+ credentials.UI_EXECUTABLE_QT) -+ self.assertEqual(self.inner_args, args) -+ -+ @defer.inlineCallbacks -+ def test_raises_exception_if_no_ui_available(self): -+ """If no GUI is available, raise GUINotAvailableError.""" -+ self.patch(credentials.Keyring, 'get_credentials', -+ lambda kr, app: defer.succeed(None)) -+ self.patch(credentials.os.path, 'exists', lambda path: False) -+ -+ f = self.method_call(**self.kwargs) -+ yield self.assertFailure(f, credentials.GUINotAvailableError) -+ -+ @defer.inlineCallbacks - def test_without_existent_token_and_return_code_cancel(self, exc=None): - """The operation returns exc if defined, else UserCancellationError.""" - self.patch(credentials.Keyring, 'get_credentials', - lambda kr, app: defer.succeed(None)) - self._next_inner_result = credentials.USER_CANCELLATION - -+ self.patch(credentials.os.path, 'exists', -+ lambda path: path == self.exe_path) -+ - if exc is None: - exc = credentials.UserCancellationError - yield self.assertFailure(self.method_call(**self.kwargs), exc) - - @defer.inlineCallbacks -- def test_without_existent_token_and_return_other(self, result=None): -+ def test_without_existent_token_and_return_other_code(self, result=None): - """The operation returns CredentialsError with 'result'.""" - self.patch(credentials.Keyring, 'get_credentials', - lambda kr, app: defer.succeed(None)) - self._next_inner_result = credentials.USER_CANCELLATION * 2 # other - -+ self.patch(credentials.os.path, 'exists', -+ lambda path: path == self.exe_path) -+ - exc = yield self.assertFailure(self.method_call(**self.kwargs), - credentials.CredentialsError) - if result is None: -@@ -422,6 +460,9 @@ - lambda kr, app: defer.succeed(None)) - self.patch_inner(self.fail_inner) - -+ self.patch(credentials.os.path, 'exists', -+ lambda path: path == self.exe_path) -+ - yield self.assertFailure(self.method_call(**self.kwargs), - SampleMiscException) - -@@ -478,14 +519,20 @@ - def test_ui_executable_falls_back_to_gtk(self): - """This check does not apply for this test case.""" - -+ def test_ui_executable_uses_qt_ui_if_gtk_not_available(self): -+ """This check does not apply for this test case.""" -+ -+ def test_raises_exception_if_no_ui_available(self): -+ """This check does not apply for this test case.""" -+ - def test_without_existent_token_and_return_code_cancel(self, exc=None): - """The operation returns UserNotValidatedError.""" - exc = credentials.UserNotValidatedError - return super(LoginEmailPasswordTestCase, self).\ - test_without_existent_token_and_return_code_cancel(exc=exc) - -- def test_without_existent_token_and_return_other(self, result=None): -+ def test_without_existent_token_and_return_other_code(self, result=None): - """The operation returns CredentialsError with 'result'.""" - result = 'foo' - return super(LoginEmailPasswordTestCase, self).\ -- test_without_existent_token_and_return_other(result=result) -+ test_without_existent_token_and_return_other_code(result=result) - diff -Nru ubuntu-sso-client-3.0.0/debian/patches/series ubuntu-sso-client-3.0.2/debian/patches/series --- ubuntu-sso-client-3.0.0/debian/patches/series 2012-05-07 18:29:16.000000000 +0000 +++ ubuntu-sso-client-3.0.2/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -00_bzr837-lp-960657.patch -01_lp-994632.patch diff -Nru ubuntu-sso-client-3.0.0/debian/watch ubuntu-sso-client-3.0.2/debian/watch --- ubuntu-sso-client-3.0.0/debian/watch 2012-05-07 18:48:11.000000000 +0000 +++ ubuntu-sso-client-3.0.2/debian/watch 2012-06-28 20:52:24.000000000 +0000 @@ -1,2 +1,2 @@ version=3 -http://launchpad.net/ubuntu-sso-client/stable-3-0/3.0.0/ .*/ubuntu-sso-client-([0-9.]+)\.tar\.gz +http://launchpad.net/ubuntu-sso-client/stable-3-0 .*/ubuntu-sso-client-([0-9.]+)\.tar\.gz diff -Nru ubuntu-sso-client-3.0.0/PKG-INFO ubuntu-sso-client-3.0.2/PKG-INFO --- ubuntu-sso-client-3.0.0/PKG-INFO 2012-04-10 18:38:48.000000000 +0000 +++ ubuntu-sso-client-3.0.2/PKG-INFO 2012-06-14 17:44:09.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: ubuntu-sso-client -Version: 3.0.0 +Version: 3.0.2 Summary: Ubuntu Single Sign-On client Home-page: https://launchpad.net/ubuntu-sso-client Author: Natalia Bidart diff -Nru ubuntu-sso-client-3.0.0/setup.py ubuntu-sso-client-3.0.2/setup.py --- ubuntu-sso-client-3.0.0/setup.py 2012-04-10 18:27:20.000000000 +0000 +++ ubuntu-sso-client-3.0.2/setup.py 2012-06-14 17:29:40.000000000 +0000 @@ -347,7 +347,7 @@ DistUtilsExtra.auto.setup( name='ubuntu-sso-client', - version='3.0.0', + version='3.0.2', license='GPL v3', author='Natalia Bidart', author_email='natalia.bidart@canonical.com', diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/credentials.py ubuntu-sso-client-3.0.2/ubuntu_sso/credentials.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/credentials.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/credentials.py 2012-06-14 17:29:22.000000000 +0000 @@ -49,7 +49,12 @@ from twisted.internet import defer -from ubuntu_sso import UI_EXECUTABLE_GTK, USER_CANCELLATION, USER_SUCCESS +from ubuntu_sso import ( + UI_EXECUTABLE_GTK, + UI_EXECUTABLE_QT, + USER_CANCELLATION, + USER_SUCCESS, +) from ubuntu_sso.keyring import Keyring from ubuntu_sso.logger import setup_logging from ubuntu_sso.utils import get_bin_dir, runner @@ -79,6 +84,10 @@ """The user is not validated.""" +class GUINotAvailableError(CredentialsError): + """No user graphical interface is available.""" + + def handle_failures(msg): """Handle failures using 'msg' as error message.""" @@ -153,14 +162,32 @@ @defer.inlineCallbacks def _show_ui(self, login_only): - """Shows the UI, connect outcome signals.""" - ui_exe_path = os.path.join(get_bin_dir(), self.ui_executable) - if not os.path.exists(ui_exe_path): - logger.debug('Falling back to the GTK+ UI since the given %r ' - 'does not exist', ui_exe_path) - ui_exe_path = os.path.join(get_bin_dir(), UI_EXECUTABLE_GTK) + """Show the UI and wait for it to finish. + + Upon analyzing returning code from the UI process, emit proper signals + to the caller. + + The caller can specify a preference for the UI (so far either GTK+ or + Qt UIs are available), but if the preferred one is not available, the + service will try to open any available UI. - assert os.path.exists(ui_exe_path) + If no GUI is available, GUINotAvailableError will be raised. + + """ + guis = (self.ui_executable, UI_EXECUTABLE_GTK, UI_EXECUTABLE_QT) + for gui_exe_path in guis: + ui_exe_path = os.path.join(get_bin_dir(), gui_exe_path) + ui_exe_exists = os.path.exists(ui_exe_path) + logger.debug('Attempting to use the following executable as GUI: ' + '%r (exists? %r).', ui_exe_path, ui_exe_exists) + if not ui_exe_exists: + logger.error('The given UI path %r does not exist.', + ui_exe_path) + else: + break + else: + raise GUINotAvailableError('Can not find a GUI to present to the ' + 'user (tried with %r). Aborting.' % repr(guis)) args = [ui_exe_path] for arg in ('app_name', 'help_text', 'ping_url', 'policy_url', diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/gtk/gui.py ubuntu-sso-client-3.0.2/ubuntu_sso/gtk/gui.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/gtk/gui.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/gtk/gui.py 2012-06-14 17:29:22.000000000 +0000 @@ -109,6 +109,12 @@ LARGE_MARKUP = u'%s' +# SSL properties and certs location +STRICT_SSL_PROP = 'ssl-strict' +CERTS_FILE_PROP = 'ssl-ca-file' +CA_CERT_FILE = '/etc/ssl/certs/ca-certificates.crt' + + def log_call(f): """Decorator to log call funtions.""" @@ -539,11 +545,12 @@ msg = YES_TO_UPDATES % {'app_name': self.app_name} self.yes_to_updates_checkbutton.set_label(msg) - if self.tc_url: - msg = YES_TO_TC % {'app_name': self.app_name} - self.yes_to_tc_checkbutton.set_label(msg) - self.tc_button.set_label(TC_BUTTON) - else: + + msg = YES_TO_TC % {'app_name': self.app_name} + self.yes_to_tc_checkbutton.set_label(msg) + self.tc_button.set_label(TC_BUTTON) + + if not self.tc_url: self.tc_vbox.hide() self.login_button.set_label(LOGIN_BUTTON_LABEL) @@ -741,6 +748,7 @@ name = self.name_entry.get_text() if not name: self.name_entry.set_warning(FIELD_REQUIRED) + logger.warning('on_join_ok_button_clicked: name not set.') error = True # check email @@ -750,6 +758,7 @@ if msg is not None: self.email1_entry.set_warning(msg) self.email2_entry.set_warning(msg) + logger.warning('on_join_ok_button_clicked: email is not valid.') error = True # check password @@ -759,22 +768,30 @@ if msg is not None: self.password1_entry.set_warning(msg) self.password2_entry.set_warning(msg) + logger.warning('on_join_ok_button_clicked: password is not valid.') error = True # check T&C - if not self.yes_to_tc_checkbutton.get_active(): + if self.tc_url and not self.yes_to_tc_checkbutton.get_active(): self._set_warning_message(self.tc_warning_label, TC_NOT_ACCEPTED % {'app_name': self.app_name}) + logger.warning('on_join_ok_button_clicked: terms and conditions ' + 'not accepted.') error = True captcha_solution = self.captcha_solution_entry.get_text() if not captcha_solution: self.captcha_solution_entry.set_warning(FIELD_REQUIRED) + logger.warning('on_join_ok_button_clicked: captcha solution not ' + 'set.') error = True if error: + logger.warning('on_join_ok_button_clicked: validation failed.') return + logger.info('on_join_ok_button_clicked: validation success!') + self._set_current_page(self.processing_vbox) self.user_email = email1 self.user_password = password1 @@ -942,11 +959,23 @@ self._set_current_page(self.processing_vbox) + def _webkit_init_ssl(self): + """Set the WebKit ssl strictness.""" + # delay the import of webkit to be able to build without it + from gi.repository import WebKit # pylint: disable=E0611 + + # Set the Soup session to be strict and use system CA certs + session = WebKit.get_default_session() + session.set_property(STRICT_SSL_PROP, True) + session.set_property(CERTS_FILE_PROP, CA_CERT_FILE) + def _add_webkit_browser(self): """Add the webkit browser for the t&c.""" # delay the import of webkit to be able to build without it from gi.repository import WebKit # pylint: disable=E0611 + self._webkit_init_ssl() + browser = WebKit.WebView() browser.connect('notify::load-status', diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/gtk/tests/test_gui.py ubuntu-sso-client-3.0.2/ubuntu_sso/gtk/tests/test_gui.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/gtk/tests/test_gui.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/gtk/tests/test_gui.py 2012-06-14 17:29:22.000000000 +0000 @@ -473,8 +473,9 @@ # match passwords self.ui.password1_entry.set_text(PASSWORD) self.ui.password2_entry.set_text(PASSWORD) - # agree to TC - self.ui.yes_to_tc_checkbutton.set_active(True) + if self.ui.tc_url: + # agree to TC, only if the tc_url is defined, so we catch errors + self.ui.yes_to_tc_checkbutton.set_active(True) # resolve captcha properly self.ui.captcha_solution_entry.set_text(CAPTCHA_SOLUTION) @@ -694,15 +695,15 @@ self.assertEqual(expected, actual, msg % ('yes_to_tc_checkbutton', expected, actual)) - def test_checkbutton_is_checked_at_startup(self): - """Checkbuttons are checked by default.""" + def test_updates_checkbutton_is_checked_at_startup(self): + """The 'yes to updates' checkbutton is checked by default.""" msg = '%r is checked by default.' name = 'yes_to_updates_checkbutton' widget = getattr(self.ui, name) self.assertTrue(widget.get_active(), msg % name) - def test_checkbutton_isnt_checked_at_startup(self): - """Checkbuttons are checked by default.""" + def test_tc_checkbutton_is_not_checked_at_startup(self): + """The 'yes to T&C' checkbutton is not checked by default.""" msg = '%r is checked by default.' name = 'yes_to_tc_checkbutton' widget = getattr(self.ui, name) @@ -887,26 +888,22 @@ self.ui.on_captcha_generated(app_name=APP_NAME, captcha_id=CAPTCHA_ID) self.assertEqual(self.ui.warning_label.get_text().decode('utf8'), '') + def test_has_tc_link(self): + """The T&C button and checkbox are shown if the link is provided""" + self.assertEqual(self.ui.tc_button.get_visible(), True) + self.assertEqual(self.ui.yes_to_tc_checkbutton.get_visible(), True) -class NoTermsAndConditionsTestCase(UbuntuSSOClientTestCase): + +class NoTermsAndConditionsTestCase(EnterDetailsTestCase): """Test suite for the user registration (with no t&c link).""" kwargs = dict(app_name=APP_NAME, tc_url='', help_text=HELP_TEXT) - def test_no_tc_link(self): + def test_has_tc_link(self): """The T&C button and checkbox are not shown if no link is provided""" self.assertEqual(self.ui.tc_vbox.get_visible(), False) -class TermsAndConditionsTestCase(UbuntuSSOClientTestCase): - """Test suite for the user registration (terms & conditions page).""" - - def test_has_tc_link(self): - """The T&C button and checkbox are shown if the link is provided""" - self.assertEqual(self.ui.tc_button.get_visible(), True) - self.assertEqual(self.ui.yes_to_tc_checkbutton.get_visible(), True) - - class TermsAndConditionsBrowserTestCase(UbuntuSSOClientTestCase): """Test suite for the terms & conditions browser.""" @@ -914,6 +911,7 @@ def setUp(self): yield super(TermsAndConditionsBrowserTestCase, self).setUp() self.patch(WebKit, 'WebView', FakedEmbeddedBrowser) + self.patch(self.ui, '_webkit_init_ssl', self._set_called) self.ui.tc_button.clicked() self.addCleanup(self.ui.tc_browser_vbox.hide) @@ -922,6 +920,12 @@ assert len(children) == 1 self.browser = children[0] + def test_ssl_validation(self): + """The browser is set to validate SSL.""" + self.assertEqual(self._called, ((), {}), + '_webkit_init_ssl should be called when creating a ' + 'webkit browser.') + def test_tc_browser_is_created_when_tc_page_is_shown(self): """The browser is created when the TC button is clicked.""" self.ui.on_tc_browser_notify_load_status(self.browser) diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/main/linux.py ubuntu-sso-client-3.0.2/ubuntu_sso/main/linux.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/main/linux.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/main/linux.py 2012-06-14 17:29:22.000000000 +0000 @@ -342,10 +342,15 @@ def __init__(self, root): self.root = root - self.bus = dbus.SessionBus() self.sso_login = None self.cred_manager = None + try: + self.bus = dbus.SessionBus() + except dbus.service.DBusException as e: + logger.exception(e) + shutdown_func() + def start(self): """Start listening, nothing async to be done in this platform.""" # Register DBus service for making sure we run only one instance diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/main/tests/test_linux.py ubuntu-sso-client-3.0.2/ubuntu_sso/main/tests/test_linux.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/main/tests/test_linux.py 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/main/tests/test_linux.py 2012-06-14 17:29:22.000000000 +0000 @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2012 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranties of +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# In addition, as a special exception, the copyright holders give +# permission to link the code of portions of this program with the +# OpenSSL library under certain conditions as described in each +# individual source file, and distribute linked combinations +# including the two. +# You must obey the GNU General Public License in all respects +# for all of the code used other than OpenSSL. If you modify +# file(s) with this exception, you may extend this exception to your +# version of the file(s), but you are not obligated to do so. If you +# do not wish to do so, delete this exception statement from your +# version. If you delete this exception statement from all source +# files in the program, then also delete it here. +"""Tests for the main SSO Linux client code.""" + +# pylint: disable=C0103 +do_tests = False +try: + import dbus + import dbus.service + from ubuntu_sso.main import linux as main + do_tests = True +except ImportError: + do_tests = False +# pylint enable=C0103 + +from ubuntuone.devtools.testcases import BaseTestCase, skipIf + + +@skipIf(do_tests != True, 'Tests only work with DBus and linux imports.') +class LinuxProxyTestCase(BaseTestCase): + """Test some Linux specific cases.""" + + def test_dbus_missing_exists_clean(self): + """Test that dbus-daemon not being available gives us a clean exit.""" + def patched(*args, **kwargs): + """Method to patch in for testing.""" + raise dbus.service.DBusException( + 'org.freedesktop.DBus.Error.NoServer') + + self.patch(dbus, "SessionBus", patched) + self.patch(main, "shutdown_func", patched) + self.assertRaises(dbus.service.DBusException, + main.UbuntuSSOProxy, None) diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/qt/current_user_sign_in_page.py ubuntu-sso-client-3.0.2/ubuntu_sso/qt/current_user_sign_in_page.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/qt/current_user_sign_in_page.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/qt/current_user_sign_in_page.py 2012-06-14 17:29:22.000000000 +0000 @@ -97,9 +97,7 @@ self.setButtonText(QtGui.QWizard.CancelButton, CANCEL_BUTTON) # Layout without custom button 1, # without finish button - self.wizard().setButtonLayout([ - QtGui.QWizard.BackButton, - QtGui.QWizard.Stretch]) + self.wizard().setButtonLayout([]) # Set sign_in_button as default when the page is shown. self.ui.sign_in_button.setDefault(True) diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/qt/setup_account_page.py ubuntu-sso-client-3.0.2/ubuntu_sso/qt/setup_account_page.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/qt/setup_account_page.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/qt/setup_account_page.py 2012-06-14 17:29:22.000000000 +0000 @@ -154,7 +154,6 @@ # Button setup self.wizard().setButtonLayout([ - QtGui.QWizard.BackButton, QtGui.QWizard.Stretch, QtGui.QWizard.CustomButton3]) diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/qt/tests/test_current_user_sign_in_page.py ubuntu-sso-client-3.0.2/ubuntu_sso/qt/tests/test_current_user_sign_in_page.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/qt/tests/test_current_user_sign_in_page.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/qt/tests/test_current_user_sign_in_page.py 2012-06-14 17:29:22.000000000 +0000 @@ -59,7 +59,7 @@ self.assertEqual(wizard.buttons_text[QtGui.QWizard.CancelButton], "Cancel") self.assertIn(('setButtonLayout', - (([QtGui.QWizard.BackButton, QtGui.QWizard.Stretch],), {})), + (([],), {})), wizard.called) self.assertTrue(button.properties['default']) self.assertFalse(button.isEnabled()) diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/qt/tests/test_setup_account.py ubuntu-sso-client-3.0.2/ubuntu_sso/qt/tests/test_setup_account.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/qt/tests/test_setup_account.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/qt/tests/test_setup_account.py 2012-06-14 17:29:22.000000000 +0000 @@ -207,8 +207,7 @@ self.ui.initializePage() # set up account button - expected = [QtGui.QWizard.BackButton, QtGui.QWizard.Stretch, - QtGui.QWizard.CustomButton3] + expected = [QtGui.QWizard.Stretch, QtGui.QWizard.CustomButton3] self.assertIn(('setButtonLayout', ((expected,), {})), self.ui.wizard().called) self.assertEqual(gui.SET_UP_ACCOUNT_BUTTON, diff -Nru ubuntu-sso-client-3.0.0/ubuntu_sso/tests/test_credentials.py ubuntu-sso-client-3.0.2/ubuntu_sso/tests/test_credentials.py --- ubuntu-sso-client-3.0.0/ubuntu_sso/tests/test_credentials.py 2012-04-10 18:27:00.000000000 +0000 +++ ubuntu-sso-client-3.0.2/ubuntu_sso/tests/test_credentials.py 2012-06-14 17:29:22.000000000 +0000 @@ -37,7 +37,7 @@ import ubuntu_sso.main -from ubuntu_sso import credentials, utils +from ubuntu_sso import credentials from ubuntu_sso.credentials import ( APP_NAME_KEY, HELP_TEXT_KEY, @@ -111,6 +111,8 @@ class BasicTestCase(TestCase): """Test case with a helper tracker.""" + bin_dir = 'some/bin/dir' + @defer.inlineCallbacks def setUp(self): """Init.""" @@ -121,6 +123,8 @@ self.memento.setLevel(logging.DEBUG) credentials.logger.addHandler(self.memento) + self.patch(credentials, 'get_bin_dir', lambda: self.bin_dir) + def _set_called(self, *args, **kwargs): """Set _called to True.""" self._called = (args, kwargs) @@ -285,8 +289,7 @@ yield super(RegisterTestCase, self).setUp() self.deferred = defer.Deferred() self.patch_inner(self.fake_inner) - self.exe_path = os.path.join(utils.get_bin_dir(), - KWARGS[UI_EXECUTABLE_KEY]) + self.exe_path = os.path.join(self.bin_dir, KWARGS[UI_EXECUTABLE_KEY]) self.inner_args = [ self.exe_path, '--app_name', APP_NAME, @@ -347,11 +350,9 @@ lambda kr, app: defer.succeed(None)) self._next_inner_result = credentials.USER_SUCCESS - # patch os.path.exists so it also returns True when queried for the - # faked exe_path - really_exists = os.path.exists + # patch os.path.exists so it returns True for the faked exe_path self.patch(credentials.os.path, 'exists', - lambda path: path == self.exe_path or really_exists(path)) + lambda path: path == self.exe_path) result = yield self.method_call(**self.kwargs) self.assertEqual(result, TOKEN) @@ -368,34 +369,71 @@ self._next_inner_result = credentials.USER_SUCCESS assert not os.path.exists(self.exe_path) + self.patch(credentials.os.path, 'exists', + lambda path: path.endswith(credentials.UI_EXECUTABLE_GTK)) result = yield self.method_call(**self.kwargs) self.assertEqual(result, TOKEN) # the ui was opened and proper params were passed args = yield self.deferred - self.inner_args[0] = os.path.join(utils.get_bin_dir(), + self.inner_args[0] = os.path.join(self.bin_dir, credentials.UI_EXECUTABLE_GTK) self.assertEqual(self.inner_args, args) @defer.inlineCallbacks + def test_ui_executable_uses_qt_ui_if_gtk_not_available(self): + """The executable loads the QT UI if the GTK+ does not exist.""" + self.patch(credentials.Keyring, 'get_credentials', + lambda kr, app: defer.succeed(None)) + self._next_inner_result = credentials.USER_SUCCESS + + self.patch(credentials.os.path, 'exists', + lambda path: path.endswith(credentials.UI_EXECUTABLE_QT)) + + result = yield self.method_call(**self.kwargs) + self.assertEqual(result, TOKEN) + + # the ui was opened and proper params were passed + args = yield self.deferred + self.inner_args[0] = os.path.join(self.bin_dir, + credentials.UI_EXECUTABLE_QT) + self.assertEqual(self.inner_args, args) + + @defer.inlineCallbacks + def test_raises_exception_if_no_ui_available(self): + """If no GUI is available, raise GUINotAvailableError.""" + self.patch(credentials.Keyring, 'get_credentials', + lambda kr, app: defer.succeed(None)) + self.patch(credentials.os.path, 'exists', lambda path: False) + + f = self.method_call(**self.kwargs) + yield self.assertFailure(f, credentials.GUINotAvailableError) + + @defer.inlineCallbacks def test_without_existent_token_and_return_code_cancel(self, exc=None): """The operation returns exc if defined, else UserCancellationError.""" self.patch(credentials.Keyring, 'get_credentials', lambda kr, app: defer.succeed(None)) self._next_inner_result = credentials.USER_CANCELLATION + self.patch(credentials.os.path, 'exists', + lambda path: path == self.exe_path) + if exc is None: exc = credentials.UserCancellationError yield self.assertFailure(self.method_call(**self.kwargs), exc) @defer.inlineCallbacks - def test_without_existent_token_and_return_other(self, result=None): + def test_without_existent_token_and_return_other_code(self, result=None): """The operation returns CredentialsError with 'result'.""" self.patch(credentials.Keyring, 'get_credentials', lambda kr, app: defer.succeed(None)) self._next_inner_result = credentials.USER_CANCELLATION * 2 # other + self.patch(credentials.os.path, 'exists', + lambda path: path == self.exe_path) + exc = yield self.assertFailure(self.method_call(**self.kwargs), credentials.CredentialsError) if result is None: @@ -422,6 +460,9 @@ lambda kr, app: defer.succeed(None)) self.patch_inner(self.fail_inner) + self.patch(credentials.os.path, 'exists', + lambda path: path == self.exe_path) + yield self.assertFailure(self.method_call(**self.kwargs), SampleMiscException) @@ -478,14 +519,20 @@ def test_ui_executable_falls_back_to_gtk(self): """This check does not apply for this test case.""" + def test_ui_executable_uses_qt_ui_if_gtk_not_available(self): + """This check does not apply for this test case.""" + + def test_raises_exception_if_no_ui_available(self): + """This check does not apply for this test case.""" + def test_without_existent_token_and_return_code_cancel(self, exc=None): """The operation returns UserNotValidatedError.""" exc = credentials.UserNotValidatedError return super(LoginEmailPasswordTestCase, self).\ test_without_existent_token_and_return_code_cancel(exc=exc) - def test_without_existent_token_and_return_other(self, result=None): + def test_without_existent_token_and_return_other_code(self, result=None): """The operation returns CredentialsError with 'result'.""" result = 'foo' return super(LoginEmailPasswordTestCase, self).\ - test_without_existent_token_and_return_other(result=result) + test_without_existent_token_and_return_other_code(result=result)