[X2Go-Commits] [python-x2go] 01/03: Provide session profile backend for a http broker.

git-admin at x2go.org git-admin at x2go.org
Tue Mar 18 01:11:40 CET 2014


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 at 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 at 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



More information about the x2go-commits mailing list