This is an automated email from the git hooks/post-receive script. x2go pushed a change to branch brokerclient in repository python-x2go. from 36ec609 more work on session broker client code (connecting to a session now works) new d3917a5 only convert string values to unicode new 16903f5 broker client: hide all broker specific functionalities from X2GoClient class by moving the broker logic into the broker session profiles backend new 6af6993 more work on the broker implementation The 3 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Summary of changes: x2go/backends/control/plain.py | 5 + x2go/backends/profiles/base.py | 198 +++++++++++++++++++++++++++---- x2go/backends/profiles/file.py | 16 +++ x2go/backends/profiles/httpbroker.py | 212 +++++++++++++++++++++++++--------- x2go/client.py | 49 +++++--- x2go/defaults.py | 2 +- x2go/inifiles.py | 4 +- x2go/registry.py | 1 + x2go/utils.py | 27 +++-- 9 files changed, 406 insertions(+), 108 deletions(-) -- Alioth's /srv/git/_hooks_/post-receive-email on /srv/git/code.x2go.org/python-x2go.git
This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch brokerclient in repository python-x2go. commit d3917a53d1d14fefad4f85f62772b1d93ce0b829 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Thu Mar 13 00:02:52 2014 +0100 only convert string values to unicode --- x2go/backends/profiles/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x2go/backends/profiles/base.py b/x2go/backends/profiles/base.py index 541e521..4a59692 100644 --- a/x2go/backends/profiles/base.py +++ b/x2go/backends/profiles/base.py @@ -240,7 +240,10 @@ class X2GoSessionProfiles(): _export_path = ':'.join(_path.split(':')[:-1]) value[_export_path] = _auto_export_path - return unicode(value) + if type(value) is types.StringType: + value = unicode(value) + + return value else: raise X2GoProfileException('no such session profile parameter: %s' % parameter) -- Alioth's /srv/git/_hooks_/post-receive-email on /srv/git/code.x2go.org/python-x2go.git
This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch brokerclient in repository python-x2go. commit 16903f56f3abb79655fcb25b3e01885f8ae87e71 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Sat Mar 15 10:02:28 2014 +0100 broker client: hide all broker specific functionalities from X2GoClient class by moving the broker logic into the broker session profiles backend --- x2go/backends/profiles/base.py | 75 ++++++++++++++++++++++++++++++++++ x2go/backends/profiles/file.py | 8 ++++ x2go/backends/profiles/httpbroker.py | 37 ++++++++++++----- x2go/client.py | 12 +++--- 4 files changed, 115 insertions(+), 17 deletions(-) diff --git a/x2go/backends/profiles/base.py b/x2go/backends/profiles/base.py index 4a59692..8364c93 100644 --- a/x2go/backends/profiles/base.py +++ b/x2go/backends/profiles/base.py @@ -92,6 +92,23 @@ class X2GoSessionProfiles(): _profile_id = self.check_profile_id_or_name(self, profile_id_or_name) return self.get_profile_config(profile_id=_profile_id) + def init_profile_cache(self, profile_id): + """\ + Some session profile backends (e.g. the broker backends cache + dynamic session profile data). On new connections, it is + recommented to (re-)initialize these caches. + + """ + return self._init_profile_cache(profile_id) + + def _init_profile_cache(self, profile_id): + """\ + Inherit from this class to (re-)initialize profile ID based + cache storage. + + """ + pass + def populate_session_profiles(self): """\ Load a session profile set from the configuration storage @@ -564,3 +581,61 @@ class X2GoSessionProfiles(): """ return [] + def get_server_hostname(self, profile_id): + """\ + Retrieve host name of the X2Go Server configured in a session profile. + + @param profile_id: the profile's unique ID + @type profile_id: C{str} + + @return: the host name of the X2Go Server configured by the session profile + of the given profile ID + @rtype: C{list} + + """ + return self._get_server_hostname(profile_id) + + def _get_server_hostname(self, profile_id): + """\ + Inherit from this class and provide a way for actually obtaining + a the server host name for a given profile ID. + + @param profile_id: the profile's unique ID + @type profile_id: C{str} + + @return: the host name of the X2Go Server configured by the session profile + of the given profile ID + @rtype: C{list} + + """ + return u'localhost' + + def get_server_port(self, profile_id): + """\ + Retrieve SSH port of the X2Go Server configured in a session profile. + + @param profile_id: the profile's unique ID + @type profile_id: C{str} + + @return: the SSH port of the X2Go Server configured by the session profile + of the given profile ID + @rtype: C{list} + + """ + return self._get_server_port(profile_id) + + def _get_server_hostname(self, profile_id): + """\ + Inherit from this class and provide a way for actually obtaining + a the server SSH port for a given profile ID. + + @param profile_id: the profile's unique ID + @type profile_id: C{str} + + @return: the SSH port of the X2Go Server configured by the session profile + of the given profile ID + @rtype: C{list} + + """ + return 22 + diff --git a/x2go/backends/profiles/file.py b/x2go/backends/profiles/file.py index 9e7edcf..7147295 100644 --- a/x2go/backends/profiles/file.py +++ b/x2go/backends/profiles/file.py @@ -26,6 +26,8 @@ applications. """ __NAME__ = 'x2gosessionprofiles-pylib' +import types + # Python X2Go modules from x2go.defaults import X2GO_SESSIONPROFILES_CONFIGFILES as _X2GO_SESSIONPROFILES_CONFIGFILES import x2go.backends.profiles.base as base @@ -108,3 +110,9 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles, inifiles.X2GoIniFile): def _get_profile_ids(self): return [ s for s in self.iniConfig.sections() if s != "none" ] + + def _get_server_hostname(self, profile_id): + return self.get_profile_config(profile_id)['host'] + + def _get_server_port(self, profile_id): + return self.get_profile_config(profile_id)['sshport'] diff --git a/x2go/backends/profiles/httpbroker.py b/x2go/backends/profiles/httpbroker.py index c2f8f12..e4e3dfd 100644 --- a/x2go/backends/profiles/httpbroker.py +++ b/x2go/backends/profiles/httpbroker.py @@ -87,6 +87,8 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): base.X2GoSessionProfiles.__init__(self, session_profile_defaults=session_profile_defaults, logger=logger, loglevel=loglevel) self.logger("Using session broker at URL: %s" % self.broker_url, log.loglevel_NOTICE) + self._broker_profile_cache = {} + def get_broker_username(self): return self.broker_username @@ -117,16 +119,23 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): return payload['profiles'] if payload['task'] == 'listprofiles' else {} def broker_selectsession(self, profile_id): - request_data = { - 'task': 'selectsession', - 'profile-id': profile_id, - 'user': self.broker_username, - 'password': self.broker_password, - } - r = requests.post(self.broker_url, data=request_data) - if r.status_code == 200 and r.headers['content-type'].startswith("text/json"): - payload = json.loads(r.text) - return payload['selected_session'] if payload['task'] == 'selectsession' else {} + if not self._broker_profile_cache.has_key(profile_id) or not self._broker_profile_cache[profile_id]: + request_data = { + 'task': 'selectsession', + 'profile-id': profile_id, + 'user': self.broker_username, + 'password': self.broker_password, + } + r = requests.post(self.broker_url, data=request_data) + if r.status_code == 200 and r.headers['content-type'].startswith("text/json"): + payload = json.loads(r.text) + self._broker_profile_cache[profile_id] = payload['selected_session'] if payload['task'] == 'selectsession' else {} + + return self._broker_profile_cache[profile_id] + + def _init_profile_cache(self, profile_id): + if self._broker_profile_cache.has_key(profile_id): + del self._broker_profile_cache.has_key[profile_id] def _populate_session_profiles(self): """\ @@ -171,3 +180,11 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): def _get_profile_ids(self): self.session_profiles.keys() return self.session_profiles.keys() + + def _get_server_hostname(self, profile_id): + selected_session = self.broker_selectsession(profile_id) + return selected_session['server'] + + def _get_server_port(self, profile_id): + selected_session = self.broker_selectsession(profile_id) + return int(selected_session['port']) diff --git a/x2go/client.py b/x2go/client.py index d23d807..b7eec91 100644 --- a/x2go/client.py +++ b/x2go/client.py @@ -871,7 +871,6 @@ class X2GoClient(object): """ # detect profile name and profile id properly - if profile_id and self.session_profiles.has_profile_id(profile_id): _p = profile_id elif profile_name and self.session_profiles.has_profile_name(profile_name): @@ -899,6 +898,9 @@ class X2GoClient(object): if _p: + # initialize session profile cache + self.session_profiles.init_profile_cache(profile_id) + _params = self.session_profiles.to_session_params(profile_id=_profile_id) del _params['profile_name'] @@ -907,12 +909,8 @@ class X2GoClient(object): if k in kwargs.keys(): _params[k] = kwargs[k] - if hasattr(self.session_profiles, 'broker_selectsession'): - selected_session = self.session_profiles.broker_selectsession(_p) - server = selected_session['server'] - _params['port'] = int(selected_session['port']) - else: - server = _params['server'] + server = self.session_profiles.get_server_hostname(_p) + _params['port'] = self.session_profiles.get_server_port(_p) del _params['server'] _params['client_instance'] = self -- Alioth's /srv/git/_hooks_/post-receive-email on /srv/git/code.x2go.org/python-x2go.git
This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch brokerclient in repository python-x2go. commit 6af69935177f1d3bbae432b4a783d06de1dd2176 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Tue Mar 18 01:05:05 2014 +0100 more work on the broker implementation --- x2go/backends/control/plain.py | 5 + x2go/backends/profiles/base.py | 130 ++++++++++++++++++----- x2go/backends/profiles/file.py | 8 ++ x2go/backends/profiles/httpbroker.py | 195 ++++++++++++++++++++++++---------- x2go/client.py | 43 +++++--- x2go/defaults.py | 2 +- x2go/inifiles.py | 4 +- x2go/registry.py | 1 + x2go/utils.py | 27 +++-- 9 files changed, 306 insertions(+), 109 deletions(-) diff --git a/x2go/backends/control/plain.py b/x2go/backends/control/plain.py index bb0ec98..fa756df 100644 --- a/x2go/backends/control/plain.py +++ b/x2go/backends/control/plain.py @@ -51,6 +51,7 @@ import x2go.defaults as defaults import x2go.checkhosts as checkhosts from x2go.defaults import BACKENDS as _BACKENDS +from x2go.defaults import CURRENT_LOCAL_USER as _current_user import x2go._paramiko x2go._paramiko.monkey_patch_paramiko() @@ -817,6 +818,10 @@ class X2GoControlSession(paramiko.SSHClient): """ _fake_hostname = None + if not username: + self.logger('no username specified, cannot connect without username', loglevel=log.loglevel_ERROR) + raise paramiko.AuthenticationException('no username specified, cannot connect without username') + if type(password) not in (types.StringType, types.UnicodeType): password = '' if type(sshproxy_password) not in (types.StringType, types.UnicodeType): diff --git a/x2go/backends/profiles/base.py b/x2go/backends/profiles/base.py index 8364c93..641e5e4 100644 --- a/x2go/backends/profiles/base.py +++ b/x2go/backends/profiles/base.py @@ -36,7 +36,7 @@ from x2go.defaults import X2GO_DESKTOPSESSIONS as _X2GO_DESKTOPSESSIONS import x2go.log as log import x2go.utils as utils -from x2go.x2go_exceptions import X2GoNotImplementedYetException +from x2go.x2go_exceptions import X2GoProfileException class X2GoSessionProfiles(): @@ -64,8 +64,6 @@ class X2GoSessionProfiles(): self._cached_profile_names = [] self._profiles_need_profile_id_renewal = [] self.write_user_config = False - self.config_files = None - self.user_config_file = None if logger is None: self.logger = log.X2GoLogger(loglevel=loglevel) @@ -76,7 +74,7 @@ class X2GoSessionProfiles(): if utils._checkSessionProfileDefaults(session_profile_defaults): self.defaultSessionProfile = session_profile_defaults - self.session_profiles = self.populate_session_profiles() + self.populate_session_profiles() def __call__(self, profile_id_or_name): """\ @@ -92,14 +90,20 @@ class X2GoSessionProfiles(): _profile_id = self.check_profile_id_or_name(self, profile_id_or_name) return self.get_profile_config(profile_id=_profile_id) - def init_profile_cache(self, profile_id): + def init_profile_cache(self, profile_id_or_name): """\ Some session profile backends (e.g. the broker backends cache dynamic session profile data). On new connections, it is recommented to (re-)initialize these caches. + @param profile_id_or_name: profile ID or profile name + @type profile_id_or_name: C{str} + """ - return self._init_profile_cache(profile_id) + profile_id = self.check_profile_id_or_name(profile_id_or_name) + + # allow backend specific clean-up + self._init_profile_cache(profile_id) def _init_profile_cache(self, profile_id): """\ @@ -118,7 +122,7 @@ class X2GoSessionProfiles(): @rtype: C{dict} """ - return self. _populate_session_profiles() + self.session_profiles = self. _populate_session_profiles() def _populate_session_profiles(self): """\ @@ -145,6 +149,7 @@ class X2GoSessionProfiles(): """ _profile_id = self.check_profile_id_or_name(profile_id_or_name) + if not self._profile_metatypes.has_key(_profile_id) or force: _config = self.get_profile_config(_profile_id) if _config['host']: @@ -174,6 +179,70 @@ class X2GoSessionProfiles(): else: return self._profile_metatypes[_profile_id] + def is_mutable(self, profile_id_or_name): + """\ + Check if a given profile name (or ID) is mutable or not. + + @param profile_id_or_name: profile name or profile ID + @type profile_id_or_name: C{str} + + @return: C{True} if the session profile of the specified name/ID is mutable + @rtype: C{bool} + + """ + try: + profile_id = self.check_profile_id_or_name(profile_id_or_name) + return self._is_mutable(profile_id) + except X2GoProfileException: + return None + + def _is_mutable(self, profile_id): + """\ + Inherit from this base class and provide your own decision making + code here if a given profile ID is mutable or not. + + @param profile_id: profile ID + @type profile_id: C{str} + + @return: C{True} if the session profile of the specified ID is mutable + @rtype: C{bool} + + """ + return False + + def supports_mutable_profiles(self): + """\ + Check if the current session profile backend supports + mutable session profiles. + + @return: list of mutable profiles + @rtype: C{list) + + """ + return self._supports_mutable_profiles() + + def _supports_mutable_profiles(self): + """\ + Inherit from this base class and provide your own decision making + code here if a your session profile backend supports mutable + session profiles or not. + + @return: list of mutable profiles + @rtype: C{list) + + """ + return False + + def mutable_profile_ids(self): + """\ + List all mutable session profiles. + + @return: List up all session profile IDs of mutable session profiles. + @rtype: C{bool} + + """ + return [ p for p in self.profile_ids if self._is_mutable(p) ] + def write(self): """\ Store session profile data to the storage backend. @@ -239,31 +308,31 @@ class X2GoSessionProfiles(): _profile_id = profile_id or self.check_profile_id_or_name(profile_id_or_name) _profile_config = {} for option in self._get_profile_options(_profile_id): - _profile_config[option] = self._get_profile_parameter(_profile_id, option, key_type=self.get_profile_option_type(option)) - - if parameter is not None: - if parameter in _profile_config.keys(): + value = self._get_profile_parameter(_profile_id, option, key_type=self.get_profile_option_type(option)) - value = _profile_config[parameter] + if option == 'export': + _strvalue = value.replace(',', ';').strip().strip('"').strip().strip(';').strip() + value = {} + if _strvalue: + _export_paths = _strvalue.split(';') + for _path in _export_paths: + if not re.match('.*:(0|1)$', _path): _path = '%s:1' % _path + _auto_export_path = re.match('.*:1$', _path) and True or False + _export_path = ':'.join(_path.split(':')[:-1]) + value[_export_path] = _auto_export_path - if parameter == 'export': - _strvalue = value.replace(',', ';').strip().strip('"').strip().strip(';').strip() - value = {} - if _strvalue: - _export_paths = _strvalue.split(';') - for _path in _export_paths: - if not re.match('.*:(0|1)$', _path): _path = '%s:1' % _path - _auto_export_path = re.match('.*:1$', _path) and True or False - _export_path = ':'.join(_path.split(':')[:-1]) - value[_export_path] = _auto_export_path + if type(value) is types.StringType: + value = unicode(value) - if type(value) is types.StringType: - value = unicode(value) + _profile_config[option] = value + if parameter is not None: + if parameter in _profile_config.keys(): + value = _profile_config[parameter] return value - else: raise X2GoProfileException('no such session profile parameter: %s' % parameter) + return _profile_config def default_profile_config(self): @@ -462,11 +531,14 @@ class X2GoSessionProfiles(): except X2GoProfileException: profile_id = profile_id_or_name + if not self.is_mutable(profile_id): + raise X2GoProfileException("session profile cannot be modified, it is marked as immutable") + if option == 'name': profile_name = value current_profile_name = self.get_value(profile_id, option) if not profile_name: - raise X2GoProfileException('profile name for profile id %s may not be empty' % profile_id) + raise X2GoProfileException('profile name for profile id %s must not be empty' % profile_id) else: self._cached_profile_names = [] if profile_name != current_profile_name and profile_name in self.profile_names: @@ -484,6 +556,10 @@ class X2GoSessionProfiles(): _config = self.get_profile_config(profile_id=profile_id) if _config.has_key('host') and _config['host'] != value: self._profiles_need_profile_id_renewal.append(profile_id) + if type(value) is types.TupleType: + value = list(value) + if type(value) is not types.ListType: + value = value.split(',') self._update_value(profile_id, option, value) @@ -608,7 +684,7 @@ class X2GoSessionProfiles(): @rtype: C{list} """ - return u'localhost' + return [u'localhost'] def get_server_port(self, profile_id): """\ diff --git a/x2go/backends/profiles/file.py b/x2go/backends/profiles/file.py index 7147295..0f08336 100644 --- a/x2go/backends/profiles/file.py +++ b/x2go/backends/profiles/file.py @@ -92,6 +92,12 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles, inifiles.X2GoIniFile): self.get_profile_metatype(session_profile) return session_profiles + def _is_mutable(self, profile_id): + return True + + def _supports_mutable_profiles(self): + return True + def _write(self): self._write_user_config = self.write_user_config return inifiles.X2GoIniFile.write(self) @@ -100,6 +106,8 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles, inifiles.X2GoIniFile): self.iniConfig.remove_section(profile_id) def _update_value(self, profile_id, option, value): + if option == 'host': + value = ','.join(value) inifiles.X2GoIniFile.update_value(self, profile_id, option, value) def _get_profile_parameter(self, profile_id, option, key_type): diff --git a/x2go/backends/profiles/httpbroker.py b/x2go/backends/profiles/httpbroker.py index e4e3dfd..569e851 100644 --- a/x2go/backends/profiles/httpbroker.py +++ b/x2go/backends/profiles/httpbroker.py @@ -26,9 +26,9 @@ applications. """ __NAME__ = 'x2gosessionprofiles-pylib' -import copy import re import requests +import copy import types try: import simplejson as json except ImportError: import json @@ -49,6 +49,7 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): broker_url="http://localhost:8080/json/", broker_username=None, broker_password=None, + broker_noauth=False, logger=None, loglevel=log.loglevel_DEFAULT, **kwargs): """\ @@ -58,6 +59,11 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): @type session_profile_defaults: C{dict} @param broker_url: URL for accessing the X2Go Session Broker @type broker_url: C{str} + @param broker_password: use this password for authentication against the X2Go Session Broker (avoid + password string in the C{broker_URL} parameter is highly recommended) + @type broker_password: C{str} + @param broker_noauth: the X2Go Session Broker accepts connections without authentication + @type broker_noauth: C{bool} @param logger: you can pass an L{X2GoLogger} object to the L{X2GoSessionProfilesHTTPSBROKER} constructor @type logger: L{X2GoLogger} instance @@ -66,28 +72,46 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): @type loglevel: C{int} """ - match = re.match('^(?P<protocol>(http(|s)))://(|(?P<user>[a-zA-Z0-9_\.-]+)(|:(?P<password>.*))@)(?P<hostname>[a-zA-Z0-9\.-]+)(|:(?P<port>[0-9]+))($|/(?P<path>.*)$)', broker_url) - p = match.groupdict() - if p['user']: - self.broker_username = p['user'] + self.broker_noauth = broker_noauth + if broker_url.upper() != "HTTP": + match = re.match('^(?P<protocol>(http(|s)))://(|(?P<user>[a-zA-Z0-9_\.-]+)(|:(?P<password>.*))@)(?P<hostname>[a-zA-Z0-9\.-]+)(|:(?P<port>[0-9]+))($|/(?P<path>.*)$)', broker_url) + p = match.groupdict() + if p['user']: + self.broker_username = p['user'] + else: + self.broker_username = broker_username + if not self.broker_noauth: + if p['password']: + self.broker_password = p['password'] + else: + self.broker_password = broker_password + else: + self.broker_password = None + + # fine-tune the URL + p['path'] = "/{path}".format(**p) + if p['port'] is not None: + p['port'] = ":{port}".format(**p) + + self.broker_url = "{protocol}://{hostname}{port}{path}".format(**p) + else: self.broker_username = broker_username - if p['password']: - self.broker_password = p['password'] - else: self.broker_password = broker_password - - # fine-tune the URL - p['path'] = "/{path}".format(**p) - if p['port'] is not None: - p['port'] = ":{port}".format(**p) - - self.broker_url = "{protocol}://{hostname}{port}{path}".format(**p) + self.broker_url = broker_url base.X2GoSessionProfiles.__init__(self, session_profile_defaults=session_profile_defaults, logger=logger, loglevel=loglevel) - self.logger("Using session broker at URL: %s" % self.broker_url, log.loglevel_NOTICE) + if self.broker_url != "HTTP": + self.logger("Using session broker at URL: %s" % self.broker_url, log.loglevel_NOTICE) self._broker_profile_cache = {} + self._mutable_profile_ids = None + self._broker_auth_successful = None + + self._broker_type = "http" + + def get_broker_noauth(self): + return self.broker_noauth def get_broker_username(self): return self.broker_username @@ -95,47 +119,92 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): def get_broker_url(self): return self.broker_url + def set_broker_url(self, broker_url): + self.broker_url = broker_url + + def get_broker_type(self): + return self._broker_type + def broker_simpleauth(self, broker_username, broker_password): - request_data = { - 'user': broker_username, - 'password': broker_password, - } - r = requests.post(self.broker_url, data=request_data) - if r.status_code == 200: - self.broker_username = broker_username - self.broker_password = broker_password - return True + if self.broker_url is not None: + request_data = { + 'user': broker_username or '', + 'password': broker_password or '', + } + r = requests.post(self.broker_url, data=request_data) + if r.status_code == 200: + self.broker_username = broker_username or '' + self.broker_password = broker_password or '' + self._broker_auth_successful = True + return True + self._broker_auth_successful = False return False - def broker_listprofiles(self): - request_data = { - 'task': 'listprofiles', - 'user': self.broker_username, - 'password': self.broker_password, - } - r = requests.post(self.broker_url, data=request_data) - if r.status_code == 200 and r.headers['content-type'].startswith("text/json"): - payload = json.loads(r.text) - return payload['profiles'] if payload['task'] == 'listprofiles' else {} + def broker_disconnect(self): + _profile_ids = copy.deepcopy(self.profile_ids) + + # forget nearly everything... + for profile_id in _profile_ids: + self.init_profile_cache(profile_id) + try: del self._profile_metatypes[profile_id] + except KeyError: pass + try: self._profiles_need_profile_id_renewal.remove(profile_id) + except ValueError: pass + try: self._cached_profile_names.remove(self.to_profile_name(profile_id)) + except ValueError: pass + try: self._cached_profile_ids.remove(profile_id) + except ValueError: pass + del self.session_profiles[profile_id] + self._mutable_profile_ids = None + self._broker_auth_successful = False + self.broker_password = None + + def is_broker_authenticated(self): + if self._broker_auth_successful is None: + # do a test auth against the given broker URL + self.broker_simpleauth(self.broker_username, self.broker_password) + return self._broker_auth_successful - def broker_selectsession(self, profile_id): - if not self._broker_profile_cache.has_key(profile_id) or not self._broker_profile_cache[profile_id]: + def broker_listprofiles(self): + if self.broker_url is not None: request_data = { - 'task': 'selectsession', - 'profile-id': profile_id, + 'task': 'listprofiles', 'user': self.broker_username, 'password': self.broker_password, } r = requests.post(self.broker_url, data=request_data) if r.status_code == 200 and r.headers['content-type'].startswith("text/json"): payload = json.loads(r.text) - self._broker_profile_cache[profile_id] = payload['selected_session'] if payload['task'] == 'selectsession' else {} + if payload.has_key('mutable_profile_ids'): + self._mutable_profile_ids = payload['mutable_profile_ids'] + self._broker_auth_successful = True + return payload['profiles'] if payload['task'] == 'listprofiles' else {} + self._broker_auth_successful = False + return {} - return self._broker_profile_cache[profile_id] + def broker_selectsession(self, profile_id): + if self.broker_url is not None: + if not self._broker_profile_cache.has_key(profile_id) or not self._broker_profile_cache[profile_id]: + request_data = { + 'task': 'selectsession', + 'profile-id': profile_id, + 'user': self.broker_username, + 'password': self.broker_password, + } + r = requests.post(self.broker_url, data=request_data) + if r.status_code == 200 and r.headers['content-type'].startswith("text/json"): + payload = json.loads(r.text) + self._broker_profile_cache[profile_id] = payload['selected_session'] if payload['task'] == 'selectsession' else {} + self._broker_auth_successful = True + else: + self._broker_auth_successful = False + self._broker_profile_cache[profile_id] + return self._broker_profile_cache[profile_id] + return {} def _init_profile_cache(self, profile_id): - if self._broker_profile_cache.has_key(profile_id): - del self._broker_profile_cache.has_key[profile_id] + if self._broker_profile_cache.has_key(unicode(profile_id)): + del self._broker_profile_cache[unicode(profile_id)] def _populate_session_profiles(self): """\ @@ -146,22 +215,38 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): @rtype: C{dict} """ - session_profiles = self.broker_listprofiles() - _session_profiles = copy.deepcopy(session_profiles) - - for session_profile in _session_profiles: - session_profile = unicode(session_profile) - for key, default_value in self.defaultSessionProfile.iteritems(): - key = unicode(key) - if type(default_value) is types.StringType: - default_value = unicode(default_value) - if not session_profiles[session_profile].has_key(key): - session_profiles[session_profile][key] = default_value + if self.broker_noauth or \ + self.broker_username and self.broker_password: + + session_profiles = self.broker_listprofiles() + _session_profiles = copy.deepcopy(session_profiles) + + for session_profile in _session_profiles: + session_profile = unicode(session_profile) + for key, default_value in self.defaultSessionProfile.iteritems(): + key = unicode(key) + if type(default_value) is types.StringType: + default_value = unicode(default_value) + if not session_profiles[session_profile].has_key(key): + session_profiles[session_profile][key] = default_value + + else: + session_profiles = {} return session_profiles + def _is_mutable(self, profile_id): + if type(self._mutable_profile_ids) is types.ListType and profile_id in self._mutable_profile_ids: + return True + return False + + def _supports_mutable_profiles(self): + if type(self._mutable_profile_ids) is types.ListType: + return True + return False + def _write(self): - print "not suported" + print "not suported, yet" def _delete_profile(self, profile_id): del self.session_profiles[unicode(profile_id)] diff --git a/x2go/client.py b/x2go/client.py index b7eec91..b1fa978 100644 --- a/x2go/client.py +++ b/x2go/client.py @@ -183,6 +183,8 @@ class X2GoClient(object): settings_backend=_BACKENDS['X2GoClientSettings']['default'], printing_backend=_BACKENDS['X2GoClientPrinting']['default'], broker_url=None, + broker_password=None, + broker_noauth=False, client_rootdir=None, sessions_rootdir=None, ssh_rootdir=None, @@ -216,6 +218,12 @@ class X2GoClient(object): @type settings_backend: C{str} @param printing_backend: X2Go client printing backend to use @type printing_backend: C{str} + @param broker_url: URL pointing to the X2Go Session Broker + @type broker_url: C{str} + @param broker_password: use this password for authentication against the X2Go Session Broker + @type broker_password: C{str} + @param broker_noauth: accessing the X2Go Session Broker works without credentials + @type broker_noauth: C{bool} @param client_rootdir: client base dir (default: ~/.x2goclient) @type client_rootdir: C{str} @param sessions_rootdir: sessions base dir (default: ~/.x2go) @@ -270,9 +278,9 @@ class X2GoClient(object): self.list_backend = utils._get_backend_class(list_backend, "X2GoServerSessionList") self.proxy_backend = utils._get_backend_class(proxy_backend, "X2GoProxy") if broker_url is not None: - if broker_url.startswith('ssh://'): + if broker_url.lower().startswith('ssh'): profiles_backend = 'sshbroker' - elif broker_url.startswith('http://') or broker_url.startswith('https://'): + elif broker_url.lower().startswith('http'): profiles_backend = 'httpbroker' self.profiles_backend = utils._get_backend_class(profiles_backend, "X2GoSessionProfiles") self.settings_backend = utils._get_backend_class(settings_backend, "X2GoClientSettings") @@ -294,7 +302,7 @@ class X2GoClient(object): _settings_config_file = os.path.join(self.client_rootdir, _X2GO_SETTINGS_FILENAME) _printing_config_file = os.path.join(self.client_rootdir, _X2GO_PRINTING_FILENAME) _xconfig_config_file = os.path.join(self.client_rootdir, _X2GO_XCONFIG_FILENAME) - self.session_profiles = self.profiles_backend(config_files=[_sessions_config_file], logger=self.logger, broker_url=broker_url) + self.session_profiles = self.profiles_backend(config_files=[_sessions_config_file], logger=self.logger, broker_url=broker_url, broker_password=broker_password, broker_noauth=broker_noauth) self.client_settings = self.settings_backend(config_files=[_settings_config_file], logger=self.logger) self.client_printing = self.printing_backend(config_files=[_printing_config_file], client_instance=self, logger=self.logger) else: @@ -870,22 +878,27 @@ class X2GoClient(object): @rtype: C{str} """ + _p = None # detect profile name and profile id properly if profile_id and self.session_profiles.has_profile_id(profile_id): _p = profile_id elif profile_name and self.session_profiles.has_profile_name(profile_name): _p = profile_name - elif profile_id and self.session_profiles.check_profile_id_or_name(profile_id): - _p = self.session_profiles.check_profile_id_or_name(profile_id) - elif profile_name and self.session_profiles.check_profile_id_or_name(profile_name): - _p = self.session_profiles.check_profile_id_or_name(profile_name) - else: - _p = None - + elif profile_id: + try: + _p = self.session_profiles.check_profile_id_or_name(profile_id) + except x2go_exceptions.X2GoProfileException: + pass + elif profile_name: + try: + _p = self.session_profiles.check_profile_id_or_name(profile_name) + except x2go_exceptions.X2GoProfileException: + pass if _p: - _profile_id = self.session_profiles.check_profile_id_or_name(_p) _profile_name = self.session_profiles.to_profile_name(_profile_id) + else: + _profile_id = None # test if session_name has already been registered. If yes, return it immediately. if type(session_name) is types.StringType: @@ -896,10 +909,10 @@ class X2GoClient(object): if known_hosts is None: known_hosts = os.path.join(_LOCAL_HOME, self.ssh_rootdir, 'known_hosts') - if _p: + if _profile_id: # initialize session profile cache - self.session_profiles.init_profile_cache(profile_id) + self.session_profiles.init_profile_cache(_profile_id) _params = self.session_profiles.to_session_params(profile_id=_profile_id) del _params['profile_name'] @@ -909,8 +922,8 @@ class X2GoClient(object): if k in kwargs.keys(): _params[k] = kwargs[k] - server = self.session_profiles.get_server_hostname(_p) - _params['port'] = self.session_profiles.get_server_port(_p) + server = self.session_profiles.get_server_hostname(_profile_id) + _params['port'] = self.session_profiles.get_server_port(_profile_id) del _params['server'] _params['client_instance'] = self diff --git a/x2go/defaults.py b/x2go/defaults.py index 59373f4..ee785a5 100644 --- a/x2go/defaults.py +++ b/x2go/defaults.py @@ -296,7 +296,7 @@ X2GO_SESSIONPROFILE_DEFAULTS = { 'usekbd': True, 'layout': 'us', 'type': 'pc105/us', 'variant': '', 'sound': False, 'soundsystem': 'pulse', 'startsoundsystem': False, 'soundtunnel':True, 'defsndport':True, 'sndport':4713, 'name': 'NEW_PROFILE', 'icon': ':icons/128x128/x2gosession.png', - 'host': 'server.mydomain', 'user': CURRENT_LOCAL_USER, 'key': '', 'sshport': 22, 'krblogin': False, 'forwardsshagent': False, + 'host': ['server.mydomain'], 'user': CURRENT_LOCAL_USER, 'key': '', 'sshport': 22, 'krblogin': False, 'forwardsshagent': False, 'rootless': True, 'applications': X2GO_GENERIC_APPLICATIONS, 'command':'TERMINAL', 'published': False, 'directrdp': False, 'directrdpsettings': '', 'rdpclient': 'rdesktop', 'rdpport': 3389, 'rdpoptions': '-u X2GO_USER -p X2GO_PASSWORD', 'rdpserver': '', diff --git a/x2go/inifiles.py b/x2go/inifiles.py index e363bee..1bc10d4 100644 --- a/x2go/inifiles.py +++ b/x2go/inifiles.py @@ -52,7 +52,6 @@ class X2GoIniFile(object): always contain the same fields. """ - user_config_file = None def __init__(self, config_files, defaults=None, logger=None, loglevel=log.loglevel_DEFAULT): """\ @@ -70,6 +69,7 @@ class X2GoIniFile(object): @type loglevel: C{int} """ + self.user_config_file = None self._write_user_config = True # make sure a None type gets turned into list type @@ -102,8 +102,8 @@ class X2GoIniFile(object): if not os.path.exists(file_name): utils.touch_file(file_name) _create_file = True + self.user_config_file = file_name break - self.load() if _create_file: diff --git a/x2go/registry.py b/x2go/registry.py index 66ad62f..ffe0708 100644 --- a/x2go/registry.py +++ b/x2go/registry.py @@ -560,6 +560,7 @@ class X2GoSessionRegistry(object): try: del _params['profile_id'] except: pass + print _params['port'] s = session.X2GoSession(server=server, control_session=control_session, profile_id=profile_id, profile_name=profile_name, session_name=session_name, diff --git a/x2go/utils.py b/x2go/utils.py index 13b2fe6..7f182ed 100644 --- a/x2go/utils.py +++ b/x2go/utils.py @@ -272,18 +272,27 @@ def _convert_SessionProfileOptions_2_SessionParams(options): _export = _params['export'] del _params['export'] - # fix for wrong export field usage in PyHoca-GUI/CLI and python-x2go before 20110923 - _export = _export.replace(",", ";") + if type(_export) is types.DictType: - _export = _export.strip().strip('"').strip().strip(';').strip() - _export_list = [ f for f in _export.split(';') if f ] + # since Python X2Go 0.5.0.0 + _params['share_local_folders'] = _export.keys() + + else: + + # before Python X2Go 0.5.0.0 (analysing the INI file's format for the export field) - _params['share_local_folders'] = [] - for _shared_folder in _export_list: # fix for wrong export field usage in PyHoca-GUI/CLI and python-x2go before 20110923 - if not ":" in _shared_folder: _shared_folder = "%s:1" % _shared_folder - if _shared_folder.split(":")[-1] == "1": - _params['share_local_folders'].append(":".join(_shared_folder.split(":")[:-1])) + _export = _export.replace(",", ";") + + _export = _export.strip().strip('"').strip().strip(';').strip() + _export_list = [ f for f in _export.split(';') if f ] + + _params['share_local_folders'] = [] + for _shared_folder in _export_list: + # fix for wrong export field usage in PyHoca-GUI/CLI and python-x2go before 20110923 + if not ":" in _shared_folder: _shared_folder = "%s:1" % _shared_folder + if _shared_folder.split(":")[-1] == "1": + _params['share_local_folders'].append(":".join(_shared_folder.split(":")[:-1])) if options['fullscreen']: _params['geometry'] = 'fullscreen' -- Alioth's /srv/git/_hooks_/post-receive-email on /srv/git/code.x2go.org/python-x2go.git