This is an automated email from the git hooks/post-receive script. x2go pushed a change to branch master in repository python-x2go. from 9fc8c3e fix _get_profile_parameter() in profile backend's base.py file adds 3088eda some code beautifications adds 86d185a Default to xdg-open as default PDF viewer command. new f5f6f6d Provide session profile backend for a http broker. new 41395ef debian/control: Add dependencies: python-requests, python-simplejson. new 921ee10 python-x2go.spec: Add dependencies: python-requests, python-simplejson. 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: debian/changelog | 7 ++ debian/control | 2 + python-x2go.spec | 2 + x2go/backends/control/plain.py | 5 + x2go/backends/profiles/base.py | 210 +++++++++++++++++++++++++++++---- x2go/backends/profiles/file.py | 16 +++ x2go/backends/profiles/httpbroker.py | 215 +++++++++++++++++++++++++++++++--- x2go/client.py | 40 +++++-- x2go/defaults.py | 4 +- x2go/inifiles.py | 4 +- x2go/printactions.py | 4 +- x2go/registry.py | 1 + x2go/utils.py | 27 +++-- 13 files changed, 473 insertions(+), 64 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 master in repository python-x2go. commit 41395efd535b6a7e5ba989dc4b600dff3d5ddb21 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Tue Mar 18 01:10:09 2014 +0100 debian/control: Add dependencies: python-requests, python-simplejson. --- debian/changelog | 2 ++ debian/control | 2 ++ 2 files changed, 4 insertions(+) diff --git a/debian/changelog b/debian/changelog index 3d7ff02..bd49fad 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,8 @@ python-x2go (0.5.0.0-0x2go1) UNRELEASED; urgency=low - Default to xdg-open as default PDF viewer command. - Provide basic session profile backend for a http broker. - Make session profile backends more unicode robust. + * debian/control: + + Add dependencies: python-requests, python-simplejson. -- Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Sun, 05 Jan 2014 16:35:57 +0100 diff --git a/debian/control b/debian/control index b49c765..aac1ed3 100644 --- a/debian/control +++ b/debian/control @@ -27,6 +27,8 @@ Depends: ${misc:Depends}, python-gevent (>= 0.13.6-0~), python-paramiko (>= 1.8.0-0~), + python-requests, + python-simplejson, python-xlib, nxproxy Recommends: -- 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 master in repository python-x2go. commit 921ee103af7fc59a5442336151128ac40ab08cb3 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Tue Mar 18 01:11:03 2014 +0100 python-x2go.spec: Add dependencies: python-requests, python-simplejson. --- debian/changelog | 2 ++ python-x2go.spec | 2 ++ 2 files changed, 4 insertions(+) diff --git a/debian/changelog b/debian/changelog index bd49fad..95e8c64 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,8 @@ python-x2go (0.5.0.0-0x2go1) UNRELEASED; urgency=low - Make session profile backends more unicode robust. * debian/control: + Add dependencies: python-requests, python-simplejson. + * python-x2go.spec: + + Add dependencies: python-requests, python-simplejson. -- Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Sun, 05 Jan 2014 16:35:57 +0100 diff --git a/python-x2go.spec b/python-x2go.spec index 63f75e9..c7b3860 100644 --- a/python-x2go.spec +++ b/python-x2go.spec @@ -29,6 +29,8 @@ Requires: nxproxy Requires: python-gevent Requires: python-paramiko Requires: python-xlib +Requires: python-requests +Requires: python-simplejson %description X2Go is a server based computing environment with: -- 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 master in repository python-x2go. commit f5f6f6db53dff875a642583da56c0ada78a47231 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Tue Mar 4 13:58:21 2014 +0100 Provide session profile backend for a http broker. --- debian/changelog | 2 + x2go/backends/control/plain.py | 5 + x2go/backends/profiles/base.py | 210 +++++++++++++++++++++++++++++---- x2go/backends/profiles/file.py | 16 +++ x2go/backends/profiles/httpbroker.py | 215 +++++++++++++++++++++++++++++++--- x2go/client.py | 40 +++++-- x2go/defaults.py | 2 +- x2go/inifiles.py | 4 +- x2go/registry.py | 1 + x2go/utils.py | 27 +++-- 10 files changed, 461 insertions(+), 61 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0c28057..3d7ff02 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,8 @@ python-x2go (0.5.0.0-0x2go1) UNRELEASED; urgency=low not really used by third-party products, if at all). - Fix setting default values in X2GoClientXConfig class. - Default to xdg-open as default PDF viewer command. + - Provide basic session profile backend for a http broker. + - Make session profile backends more unicode robust. -- Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Sun, 05 Jan 2014 16:35:57 +0100 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 6985f9a..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(): @@ -74,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): """\ @@ -90,6 +90,29 @@ 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_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} + + """ + 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): + """\ + 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 @@ -99,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): """\ @@ -126,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']: @@ -151,10 +175,74 @@ class X2GoSessionProfiles(): _metatype = 'RDP/direct' else: _metatype = 'not supported' - self._profile_metatypes[_profile_id] = _metatype + self._profile_metatypes[_profile_id] = unicode(_metatype) 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. @@ -220,28 +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)) + value = 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(): + 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 - value = _profile_config[parameter] + if type(value) is types.StringType: + value = unicode(value) - 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 + _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): @@ -303,7 +394,7 @@ class X2GoSessionProfiles(): @rtype: C{bool} """ - return profile_id in self.profile_ids + return unicode(profile_id) in self.profile_ids @property def profile_names(self): @@ -326,7 +417,7 @@ class X2GoSessionProfiles(): @rtype: C{bool} """ - return profile_name in self.profile_names + return unicode(profile_name) in self.profile_names def to_profile_id(self, profile_name): """\ @@ -341,7 +432,7 @@ class X2GoSessionProfiles(): """ _profile_ids = [ p for p in self.profile_ids if self.to_profile_name(p) == profile_name ] if len(_profile_ids) == 1: - return _profile_ids[0] + return unicode(_profile_ids[0]) elif len(_profile_ids) == 0: return None else: @@ -360,9 +451,9 @@ class X2GoSessionProfiles(): """ _profile_config = self.get_profile_config(profile_id=profile_id) if _profile_config.has_key('name'): - return _profile_config['name'] + return unicode(_profile_config['name']) else: - return '' + return u'' def add_profile(self, profile_id=None, force_add=False, **kwargs): """\ @@ -396,7 +487,7 @@ class X2GoSessionProfiles(): self._cached_profile_ids = [] self._cached_profile_names = [] - return profile_id + return unicode(profile_id) def delete_profile(self, profile_id_or_name): """\ @@ -440,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: @@ -462,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) @@ -495,6 +593,8 @@ class X2GoSessionProfiles(): _profile_id = profile_id_or_name else: raise X2GoProfileException('No session profile with id or name ,,%s\'\' exists.' % profile_id_or_name) + if _profile_id is not None: + _profile_id = unicode(_profile_id) return _profile_id def to_session_params(self, profile_id_or_name=None, profile_id=None): @@ -557,3 +657,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..0f08336 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 @@ -90,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) @@ -98,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): @@ -108,3 +118,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 0d27cb4..569e851 100644 --- a/x2go/backends/profiles/httpbroker.py +++ b/x2go/backends/profiles/httpbroker.py @@ -26,8 +26,16 @@ applications. """ __NAME__ = 'x2gosessionprofiles-pylib' +import re +import requests +import copy +import types +try: import simplejson as json +except ImportError: import json + # Python X2Go modules -from x2go.defaults import X2GO_SESSIONPROFILE_DEFAULTS +from x2go.defaults import X2GO_SESSIONPROFILE_DEFAULTS as _X2GO_SESSIONPROFILE_DEFAULTS +from x2go.defaults import CURRENT_LOCAL_USER as _CURRENT_LOCAL_USER import x2go.backends.profiles.base as base import x2go.log as log @@ -35,14 +43,27 @@ from x2go.x2go_exceptions import X2GoNotImplementedYetException class X2GoSessionProfiles(base.X2GoSessionProfiles): - defaultSessionProfile = X2GO_SESSIONPROFILE_DEFAULTS + defaultSessionProfile = _X2GO_SESSIONPROFILE_DEFAULTS - def __init__(self, session_profile_defaults=None, logger=None, loglevel=log.loglevel_DEFAULT): + def __init__(self, session_profile_defaults=None, + broker_url="http://localhost:8080/json/", + broker_username=None, + broker_password=None, + broker_noauth=False, + logger=None, loglevel=log.loglevel_DEFAULT, + **kwargs): """\ Retrieve X2Go session profiles from a HTTP(S) session broker. @param session_profile_defaults: a default session profile @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 @@ -51,7 +72,139 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): @type loglevel: C{int} """ + 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 + self.broker_password = broker_password + self.broker_url = broker_url + base.X2GoSessionProfiles.__init__(self, session_profile_defaults=session_profile_defaults, logger=logger, loglevel=loglevel) + 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 + + 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): + 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_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_listprofiles(self): + if self.broker_url is not None: + 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) + 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 {} + + 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(unicode(profile_id)): + del self._broker_profile_cache[unicode(profile_id)] def _populate_session_profiles(self): """\ @@ -62,31 +215,61 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): @rtype: C{dict} """ - session_profiles = LOAD + if self.broker_noauth or \ + self.broker_username and self.broker_password: - for session_profile in session_profiles: - for key, default_value in self.defaultSessionProfile.iteritems(): - if not self.iniConfig.has_option(session_profile, key): - self._storeValue(session_profile, key, default_value) - # update cached meta type session profile information - self.get_profile_metatype(session_profile) + 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 "BROKER CLIENT: WRITING SESSION PROFILES IS NOT SUPPORTED" + print "not suported, yet" def _delete_profile(self, profile_id): - print "BROKER CLIENT: DELETING SESSION PROFILES IS NOT SUPPORTED" + del self.session_profiles[unicode(profile_id)] def _update_value(self, profile_id, option, value): - print "BROKER CLIENT: MODIFYING SESSION PROFILES IS NOT SUPPORTED" + if type(value) is types.StringType: + value = unicode(value) + self.session_profiles[unicode(profile_id)][unicode(option)] = value def _get_profile_parameter(self, profile_id, option, key_type): - print "TODO" + return key_type(self.session_profiles[unicode(profile_id)][unicode(option)]) def _get_profile_options(self, profile_id): - print "TODO" + return self.session_profiles[unicode(profile_id)].keys() def _get_profile_ids(self): - print "TODO" + 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 debba28..b1fa978 100644 --- a/x2go/client.py +++ b/x2go/client.py @@ -182,6 +182,9 @@ class X2GoClient(object): profiles_backend=_BACKENDS['X2GoSessionProfiles']['default'], 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, @@ -215,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) @@ -268,6 +277,11 @@ class X2GoClient(object): self.info_backend = utils._get_backend_class(info_backend, "X2GoServerSessionInfo") 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.lower().startswith('ssh'): + profiles_backend = 'sshbroker' + 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") self.printing_backend = utils._get_backend_class(printing_backend, "X2GoClientPrinting") @@ -288,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) + 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: @@ -864,18 +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 - 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: @@ -886,8 +909,10 @@ class X2GoClient(object): if known_hosts is None: known_hosts = os.path.join(_LOCAL_HOME, self.ssh_rootdir, 'known_hosts') + if _profile_id: - 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'] @@ -897,7 +922,8 @@ class X2GoClient(object): if k in kwargs.keys(): _params[k] = kwargs[k] - server = _params['server'] + 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