[X2Go-Commits] x2gobroker.git - build-main (branch) updated: 01ed711dba1fea373f1b212b40c1a50f61436ed4

X2Go dev team git-admin at x2go.org
Sun May 19 13:04:30 CEST 2013


The branch, build-main has been updated
       via  01ed711dba1fea373f1b212b40c1a50f61436ed4 (commit)
      from  92a791df1fcefa36560ed18b326ab0cc1ea5a5f2 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 etc/x2gobroker.conf                       |    4 +-
 sbin/x2gobroker                           |  153 ++++----------
 x2gobroker/{ => backends}/__init__.py     |    3 -
 x2gobroker/{ => backends}/base.py         |   88 ++++++---
 x2gobroker/{ => backends}/ldap.py         |    0
 x2gobroker/{ => backends}/simple.py       |   20 +-
 x2gobroker/{ => backends}/zeroconf.py     |   18 +-
 x2gobroker/config.py                      |  308 +++++++++++++++++++++++++++++
 x2gobroker/defaults.py                    |   13 +-
 x2gobroker/utils.py                       |   82 ++++++++
 x2gobroker/{ => web}/__init__.py          |    3 -
 sbin/x2gobroker => x2gobroker/web/html.py |  121 ++++++------
 x2gobroker/{__init__.py => web/json.py}   |   12 +-
 13 files changed, 587 insertions(+), 238 deletions(-)
 copy x2gobroker/{ => backends}/__init__.py (97%)
 rename x2gobroker/{ => backends}/base.py (61%)
 rename x2gobroker/{ => backends}/ldap.py (100%)
 rename x2gobroker/{ => backends}/simple.py (71%)
 rename x2gobroker/{ => backends}/zeroconf.py (77%)
 create mode 100644 x2gobroker/config.py
 create mode 100644 x2gobroker/utils.py
 copy x2gobroker/{ => web}/__init__.py (97%)
 copy sbin/x2gobroker => x2gobroker/web/html.py (53%)
 mode change 100755 => 100644
 copy x2gobroker/{__init__.py => web/json.py} (70%)

The diff of changes is:
diff --git a/etc/x2gobroker.conf b/etc/x2gobroker.conf
index 0123e60..ec6f4a9 100644
--- a/etc/x2gobroker.conf
+++ b/etc/x2gobroker.conf
@@ -63,8 +63,8 @@ use-authid = false
 # below value to true
 use-static-authid = true
 
-# Make up your own static_authid below...
-static-authid = <aaaavveeeerrrrryyyyylooonnnnggggssttrrriiinnnggg>
+# Make up your own authid below...
+authid = <aaaavveeeerrrrryyyyylooonnnnggggssttrrriiinnnggg>
 
 # X2Go Session Broker knows about two output formats: a text/html based output
 # and a text/json based output. The different outputs run under different URLs
diff --git a/sbin/x2gobroker b/sbin/x2gobroker
index 0b42c84..b5f3b48 100755
--- a/sbin/x2gobroker
+++ b/sbin/x2gobroker
@@ -23,132 +23,57 @@
 import sys
 import os
 import web
+import argparse
 
 try:
     import x2gobroker
 except ImportError:
     sys.path.insert(0, os.path.join(os.getcwd(), '..'))
 
-# FIXME: here we have to add some code that genuinely detects the session broker backend...
-broker_backend = "zeroconf"
-
-# load the requested broker
-if broker_backend == "zeroconf":
-    import x2gobroker.zeroconf as broker
-elif broker_backend == "simple":
-    import x2gobroker.simple as broker
-elif broker_backend == "ldap":
-    import x2gobroker.ldap as broker
-
-
-urls = ( '/', 'x2gobroker' )
-
-
-class x2gobroker:
-
-    broker_backend = broker.X2GoBroker()
-
-    http_header_items = {
-        'Content-Type': 'text/html; charset=utf-8',
-        'Expires': '+1h',
-    }
-
-    page = web.template.Template("""$def with (html_header_items, output)
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
-<head>
-$for meta_tag in html_header_items["meta"]:
-    <meta $meta_tag="$html_header_items["meta"][meta_tag]">
-<title>$html_header_items['title']</title>
-</head>
+# parse-in potential command line options
+cmdline_args = None
+if __name__ == "__main__":
+    import setproctitle
+    setproctitle.setproctitle(os.path.basename(sys.argv[0]))
 
-<body>
-$output
-</body>
-</html>
-"""
-    )
-    html_header_items = {
-        'title':  'X2Go Session Broker',
-        'meta': {
-            'author': 'X2Go Developers <x2go-dev at lists.berlios.de>',
-            'charset': 'utf-8',
-            'keywords': 'X2Go',
-            'description': 'X2Go Session Broker',
-        },
+    daemon_options = [
+        {'args':['-C','--config-file'], 'default': None, 'metavar': 'CONFIG_FILE', 'help': 'Specify a special configuration file name, default is: /etc/x2go/x2gobroker.conf', },
+        {'args':['-b', '--bind'], 'default': '127.0.0.1:8080', 'metavar': 'BIND_ADDRESS', 'help': 'The [address:]port that the web.py http-engine shall bind to (default: 127.0.0.1:8080)', },
+    ]
+    p = argparse.ArgumentParser(description='X2Go Session Broker (Standalone Daemon)',\
+                                formatter_class=argparse.RawDescriptionHelpFormatter, \
+                                add_help=True, argument_default=None)
+    p_daemon = p.add_argument_group('standalone-daemon arguments')
+
+    for (p_group, opts) in ( (p_daemon, daemon_options), ):
+        for opt in opts:
+            args = opt['args']
+            del opt['args']
+            p_group.add_argument(*args, **opt)
+
+    cmdline_args = p.parse_args()
+
+    ### FIXME: not working yet for the config_file diversion via -C option
+    broker_kwargs = {
+        'config_file': cmdline_args.config_file,
     }
 
-    def _gen_http_header(self):
-
-        for http_header_item in self.http_header_items.keys():
-            web.header(http_header_item, self.http_header_items[http_header_item])
-
-    def GET(self):
-
-        data = web.input()
-        output = ''
-
-        self._gen_http_header()
-
-
-        # FIXME: the ,,testcon'' task can be object to DoS attacks...
-        if hasattr(data, 'task') and data.task == 'testcon':
-
-            ###
-            ### TEST THE CONNECTION
-            ###
-
-            return self.broker_backend.test_connection()
-
-        if hasattr(data, 'user') and hasattr(data, 'password') and self.broker_backend.check_access(username=data.user, password=data.password):
-
-            ###
-            ### PERFORM INITIAL AUTHENTICATION
-            ###
-
-            output += "<strong>Access granted</strong><br />"
-            output += "AUTHID: {authid}<br />".format(authid=self.broker_backend.get_next_authid(username=data.user))
-            return self.page(self.html_header_items, output)
-
-        else:
-            return self.page(self.html_header_items, "<hr>Access denied")
-
-        if hasattr(data, 'user') and hasattr(data, 'authid'):
-
-            ###
-            ### X2GO BROKER TASKS
-            ###
-
-            if self.broker_backend.check_access(username=data.user, authid=data.authid):
-
-                if hasattr(data, 'task'):
-                    task = data.task
-
-                    if task == 'listsessions':
-
-                        output += self.broker_backend.list_sessions()
-
-                    if task == 'selectsession':
-
-                        if hasattr(data, 'sid'):
-
-                            output += self.broker_backend.select_session(session_name=data.sid)
-
-                    if task == 'setpass':
-
-                        if hasattr(data, 'oldpass') and hasattr(data, 'newpass'):
-
-                            output += self.broker_backend.change_password(new=data.newpass, old=data.oldpass)
-
-                return self.page(self.html_header_items, output)
-
-            else:
-                return self.page(self.html_header_items, "<hr>Access denied")
+# import classes serving the different web.py URLs
+from x2gobroker.web.html import *
+#from x2gobroker.web.json import *
 
+# define the web.py URLs
+urls = ( '/html/(.*)', 'X2GoBrokerWebHtml',
+#         '/json/(.*)', 'X2GoBrokerWebJson',
+       )
 
+# run the web.py standalone daemon...
 if __name__ == "__main__":
-    import setproctitle
-    setproctitle.setproctitle(os.path.basename(sys.argv[0]))
+    if len(sys.argv) <= 1:
+        sys.argv.append('')
+        sys.argv.append('')
+    sys.argv[1] = cmdline_args.bind
+    sys.argv[2:] = []
     app = web.application(urls, globals())
     app.internalerror = web.debugerror
     app.run()
diff --git a/x2gobroker/__init__.py b/x2gobroker/backends/__init__.py
similarity index 97%
copy from x2gobroker/__init__.py
copy to x2gobroker/backends/__init__.py
index ad8c1e4..11b7f8f 100644
--- a/x2gobroker/__init__.py
+++ b/x2gobroker/backends/__init__.py
@@ -18,6 +18,3 @@
 # Free Software Foundation, Inc.,
 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
-__VERSION__ = '0.0.0.1'
-
-
diff --git a/x2gobroker/base.py b/x2gobroker/backends/base.py
similarity index 61%
rename from x2gobroker/base.py
rename to x2gobroker/backends/base.py
index a1fe0ca..f5228f7 100644
--- a/x2gobroker/base.py
+++ b/x2gobroker/backends/base.py
@@ -28,6 +28,9 @@ __NAME__ = 'x2gobroker-pylib'
 import types
 import uuid
 
+# X2Go Broker modules
+import x2gobroker.config
+
 class X2GoBroker(object):
     """\
     X2GoBrokerBASE is an abstract class for X2Go broker implementations.
@@ -40,12 +43,16 @@ class X2GoBroker(object):
         L{ldap.X2GoBroker}
 
     """
-    def __init__(self):
+
+    def __init__(self, config_file="/etc/x2go/x2gobroker.conf"):
         """\
         Initialize a new X2GoBroker instance to control X2Go session through an
         X2Go Client with an intermediate session broker.
+
         """
-        self._authid_dict = {}
+        self.config = x2gobroker.config.X2GoBrokerConfigFile()
+
+        self._dynamic_authid_map = {}
 
     def __del__(self):
         """\
@@ -54,6 +61,29 @@ class X2GoBroker(object):
         """
         pass
 
+    def get_global_config(self):
+        """\
+        Get the global section of the configuration file.
+
+        @return: all global configuration parameters
+        @rtype: C{dict}
+
+        """
+        return self.config.get_global_config()
+
+    def get_backend_config(self, backend='zeroconf'):
+        """\
+        Get the configuration section of a specific backend.
+
+        @param backend: the name of the backend
+        @type backend: C{str}
+
+        @return: all backend configuration parameters
+        @rtype: C{dict}
+
+        """
+        return self.config.get_backend_config(backend=backend)
+
     def test_connection(self):
         #if($cgi->param('task') eq 'testcon')
         #{
@@ -66,7 +96,7 @@ class X2GoBroker(object):
         #}
         return 'OK'
 
-    def check_access(self, username='', password='', authid=None):
+    def check_access(self, username='', password='', authid=None, ):
         """\
         Check if a given user with a given password may gain access to the
         X2Go session broker.
@@ -80,32 +110,44 @@ class X2GoBroker(object):
         @rtype: C{bool}
 
         """
+        ### FOR INTRANET LOAD BALANCER WE MAY JUST ALLOW ACCESS TO EVERYONE
+        ### This is handled through the config file, normally /etc/x2go/x2gobroker.conf
 
-        ### IMPLEMENT YOUR AUTHENTICATION LOGIC FIRST, then call base.X2GoBroker.check_access
-        ### to finalize the authentication process.
+        if not self.config.get_value('global', 'check-credentials'):
+            return True
 
-        # Before calling this code, you have to evaluate username and password.
-        #
-        # If the credentials (username, password) are considered as valid then
-        # set authid to True.
-        #
-        # If credentials are invalid, set authid to None.
+        ### IMPLEMENT YOUR AUTHENTICATION LOGIC IN THE self._check_access(**kwargs) METHOD
+        ### when inheriting from the base.X2GoBroker class.
 
-        if type(authid) is types.StringType:
-            authid = unicode(authid)
+        access = False
+        access = self._check_access(username=username, password=password, authid=authid)
 
-        if type(authid) is types.UnicodeType:
+        # using authid as extra security?
+        if self.config.get_value('global', 'use-authid'):
 
-            if authid == self._authid_dict[username]:
-                self._authid_dict[username] = uuid.uuid5(namespace=authid, name=username)
-                return True
+            if type(authid) is types.StringType:
+                authid = unicode(authid)
 
-        elif type(authid) is types.BooleanType and authid is True:
-            # generate a first uuid, initialize the connection
-            self._authid_dict[username] = uuid.uuid4()
-            return True
+            if self.config.get_value('global', 'use-static-authid'):
 
-        return False
+                # evaluate access based on static authentication ID feature
+                access = access and ( authid == self.config.get_value('global', 'authid') )
+
+            else:
+
+                # evaluate access based on dynamic authentication ID feature
+                if self._dynamic_authid_map.has_key(username):
+                    access = access and ( authid == self._dynamic_authid_map[username] )
+                    if access:
+                        self._dynamic_authid_map[username] = uuid.uuid5(namespace=authid, name=username)
+
+                else:
+                    access = access and ( authid == self.config.get_value('global', 'authid') )
+                    if access:
+                        # generate a first uuid, initialize the dynamic authencation ID security feature
+                        self._dynamic_authid_map[username] = uuid.uuid4()
+
+        return access
 
     def get_next_authid(self, username):
         """\
@@ -119,7 +161,7 @@ class X2GoBroker(object):
 
         """
         try:
-            return self._authid_dict[username]
+            return self._dynamic_authid_map[username]
         except KeyError:
             return None
 
diff --git a/x2gobroker/ldap.py b/x2gobroker/backends/ldap.py
similarity index 100%
rename from x2gobroker/ldap.py
rename to x2gobroker/backends/ldap.py
diff --git a/x2gobroker/simple.py b/x2gobroker/backends/simple.py
similarity index 71%
rename from x2gobroker/simple.py
rename to x2gobroker/backends/simple.py
index ea3fc87..923676e 100644
--- a/x2gobroker/simple.py
+++ b/x2gobroker/backends/simple.py
@@ -25,21 +25,21 @@ X2goBrokerSIMPLE class - a simple X2GoBroker implementations that uses text-base
 __NAME__ = 'x2gobroker-pylib'
 
 # modules
+import pam
+
+# Python X2GoBroker modules
 import x2gobroker.base
 
 class X2GoBroker(x2gobroker.base.X2GoBroker):
     """\
 
     """
-    def __init__(self):
-        """\
-
-        """
-        x2gobroker.base.X2GoBroker.__init__(self)
-
-    def __del__(self):
-        """\
+    def check_access(self, username='', password='', authid=None):
 
-        """
-        x2gobroker.base.X2GoBroker.__del__(self)
+        # do a simple PAM authentication against the PAM service ,,x2gobroker''
+        if username and password:
+            if pam.authenticate(username, password, service="x2gobroker"):
+                return True
+        return False
 
+        return x2gobroker.base.X2GoBroker.check_access(self, username=username, password=password, authid=authid)
diff --git a/x2gobroker/zeroconf.py b/x2gobroker/backends/zeroconf.py
similarity index 77%
rename from x2gobroker/zeroconf.py
rename to x2gobroker/backends/zeroconf.py
index af0da2d..3598e68 100644
--- a/x2gobroker/zeroconf.py
+++ b/x2gobroker/backends/zeroconf.py
@@ -28,23 +28,19 @@ __NAME__ = 'x2gobroker-pylib'
 import pam
 import subprocess
 
-import x2gobroker.base
+import base
 
 from x2gobroker.defaults import X2GOBROKER_AGENT_CMD as _X2GOBROKER_AGENT_CMD
 
-class X2GoBroker(x2gobroker.base.X2GoBroker):
+class X2GoBroker(base.X2GoBroker):
 
-    def check_access(self, username='', password='', authid=None):
+    def _check_access(self, username='', password='', authid=None):
 
         # do a simple PAM authentication against the PAM service ,,x2gobroker''
-        if authid is None:
-            if username and password:
-                if pam.authenticate(username, password, service="x2gobroker"):
-                    authid = True
-                else:
-                    authid = None
-
-        return x2gobroker.base.X2GoBroker.check_access(self, username=username, password=password, authid=authid)
+        if username and password:
+            if pam.authenticate(username, password, service="x2gobroker"):
+                return True
+        return False
 
     def list_sessions(self, username):
 
diff --git a/x2gobroker/config.py b/x2gobroker/config.py
new file mode 100644
index 0000000..99531ae
--- /dev/null
+++ b/x2gobroker/config.py
@@ -0,0 +1,308 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2010-2012 by Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+#
+# X2Go Session Broker is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# X2Go Session Broker is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# This code was initially written by for the Python X2Go project:
+#       2010 Dick Kniep <dick.kniep at lindix.nl>
+#
+
+"""\
+X2goProcessIniFile - helper class for parsing .ini files
+
+"""
+__NAME__ = 'x2goinifiles-pylib'
+
+# modules
+import os
+import ConfigParser
+import types
+import cStringIO
+
+# Python X2GoBroker modules
+import x2gobroker.utils
+
+from x2gobroker.defaults import X2GOBROKER_HOME as _X2GOBROKER_HOME
+from x2gobroker.defaults import X2GOBROKER_CONFIG_DEFAULTS as _X2GOBROKER_CONFIG_DEFAULTS
+
+class X2GoBrokerConfigFile(object):
+    """
+    Class for processing a ini-file like configuration file.
+
+    If entries are omitted in such a config file, they are filled with
+    default values (as hard-coded in Python X2goBroker), so the resulting objects 
+    always contain the same fields.
+
+    The default values are also used to define a data type for each configuration
+    option. An on-the-fly type conversion takes place when loading the configuration
+    file.
+
+    """
+    defaultValues = {
+        'none': {
+            'none': 'empty', 
+            },
+        }
+    write_user_config = False
+    user_config_file = None
+
+    def __init__(self, config_files='/etc/x2go/x2gobroker.conf', defaults=None):
+        """\
+        @param config_files: a list of configuration file names (e.g. a global filename and a user's home
+            directory filename)
+        @type config_files: C{list}
+        @param defaults: a cascaded Python dicitionary structure with ini file defaults (to override
+            Python X2goBroker's hard-coded defaults in L{defaults}
+        @type defaults: C{dict}
+
+        """
+        # make sure a None type gets turned into list type
+        if not config_files:
+            config_files = []
+
+        # allow string/unicode objects as config_files, as well
+        if type(config_files) in (types.StringType, types.UnicodeType):
+            config_files = [config_files]
+        self.config_files = config_files
+
+        if x2gobroker.utils._checkConfigFileDefaults(defaults):
+            self.defaultValues = defaults
+        else:
+            self.defaultValues = _X2GOBROKER_CONFIG_DEFAULTS
+
+        # we purposefully do not inherit the ConfigParser class
+        # here as we do not want to run into name conflicts between
+        # X2GoBroker config file options and method / property names in
+        # SafeConfigParser... This is a pre-cautious approach...
+        self.iniConfig = ConfigParser.ConfigParser(self.defaultValues)
+        self.iniConfig.optionxform = str
+
+        _create_file = False
+        for file_name in self.config_files:
+            if file_name.startswith(_X2GOBROKER_HOME):
+                if not os.path.exists(file_name):
+                    x2gobroker.utils.touch_file(file_name)
+                    _create_file = True
+                break
+
+        self.load()
+
+        if _create_file:
+            self.write_user_config = True
+            self.write()
+
+    def __repr__(self):
+        result = 'X2goConfigFile('
+        for p in dir(self):
+            if '__' in p or not p in self.__dict__ or type(p) is types.InstanceType: continue
+            result += p + '=' + str(self.__dict__[p]) + ','
+        result = result.strip(',')
+        return result + ')'
+
+    def load(self):
+        """\
+        R(e-r)ead configuration file(s).
+
+        """
+        _found_config_files = self.iniConfig.read(self.config_files)
+
+        for file_name in _found_config_files:
+            if file_name.startswith(os.path.normpath(_X2GOBROKER_HOME)):
+                # we will use the first file found in the user's home dir for writing modifications
+                self.user_config_file = file_name
+                break
+
+        self.config_files = _found_config_files
+        self._fill_defaults()
+
+    def _storeValue(self, section, key, value):
+        """\
+        Stores a value for a given section and key.
+
+        This methods affects a SafeConfigParser object held in
+        RAM. No configuration file is affected by this 
+        method. To write the configuration to disk use
+        the L{write()} method.
+
+        @param section: the ini file section
+        @type section: C{str}
+        @param key: the ini file key in the given section
+        @type key: C{str}
+        @param value: the value for the given section and key
+        @type value: C{str}, C{list}, C{booAl}, ...
+
+        """
+        if type(value) == type(u''):
+            value = value.encode(x2gobroker.utils.get_encoding())
+        if type(value) is types.BooleanType:
+            self.iniConfig.set(section, key, str(int(value)))
+        elif type(value) in (types.ListType, types.TupleType):
+            self.iniConfig.set(section, key, ", ".join(value))
+        else:
+            self.iniConfig.set(section, key, str(value))
+
+    def _fill_defaults(self):
+        """\
+        Fills a C{SafeConfigParser} object with the default config file 
+        values as pre-defined in Python X2GoBroker or. This SafeConfigParser 
+        object is held in RAM. No configuration file is affected by this 
+        method.
+
+        """
+        for section, sectionvalue in self.defaultValues.items():
+            for key, value in sectionvalue.items():
+                if self.iniConfig.has_option(section, key): continue
+                if not self.iniConfig.has_section(section):
+                    self.iniConfig.add_section(section)
+                self._storeValue(section, key, value)
+
+    def update_value(self, section, key, value):
+        """\
+        Change a value for a given section and key. This method
+        does not have any effect on configuration files.
+
+        @param section: the ini file section
+        @type section: C{str}
+        @param key: the ini file key in the given section
+        @type key: C{str}
+        @param value: the value for the given section and key
+        @type value: C{str}, C{list}, C{bool}, ...
+
+        """
+        if not self.iniConfig.has_section(section):
+            self.iniConfig.add_section(section)
+        self._storeValue(section, key, value)
+        self.write_user_config = True
+
+    def write(self):
+        """\
+        Write the ini file modifications (SafeConfigParser object) from RAM to disk.
+
+        For writing the first of the C{config_files} specified on instance construction
+        that is writable will be used.
+
+        """
+        if self.user_config_file and self.write_user_config:
+            fd = open(self.user_config_file, 'wb')
+            self.iniConfig.write(fd)
+            fd.close()
+            self.write_user_config = False
+
+    def get_type(self, section, key):
+        """\
+        Retrieve a value type for a given section and key. The returned
+        value type is based on the default values dictionary.
+
+        @param section: the ini file section
+        @type section: C{str}
+        @param key: the ini file key in the given section
+        @type key: C{str}
+
+        @return: a Python variable type 
+        @rtype: class
+
+        """
+        return type(self.defaultValues[section][key])
+
+    def get_value(self, section, key, key_type=None):
+        """\
+        Retrieve a value for a given section and key.
+
+        @param section: the ini file section
+        @type section: C{str}
+        @param key: the ini file key in the given section
+        @type key: C{str}
+
+        @return: the value for the given section and key
+        @rtype: class
+
+        """
+        if key_type is None:
+            key_type = self.get_type(section, key)
+        if self.iniConfig.has_option(section, key):
+            if key_type is types.BooleanType:
+                return self.iniConfig.getboolean(section, key)
+            elif key_type is types.IntType:
+                return self.iniConfig.getint(section, key)
+            elif key_type is types.ListType:
+                _val = self.iniConfig.get(section, key)
+                _val = _val.strip()
+                if _val.startswith('[') and _val.endswith(']'):
+                    return eval(_val)
+                elif ',' in _val:
+                    _val = [ v.strip() for v in _val.split(',') ]
+                else:
+                    _val = [ _val ]
+                return _val
+            else:
+                _val = self.iniConfig.get(section, key)
+                return _val.decode(x2gobroker.utils.get_encoding())
+    get = get_value
+    __call__ = get_value
+
+    def get_section(self, section):
+        """\
+        Get all keys and values for a certain section of the config file.
+
+        @param section: the name of the section to get
+        @type section: C{str}
+
+        @return: the section with all keys and values
+        @rtype: C{dict}
+
+        """
+        _section_config = {}
+        for option in self.iniConfig.options(section):
+            if option not in self.iniConfig.sections():
+                _section_config[option] = self.get(section, option, key_type=self.get_type(section, option))
+
+        return _section_config
+
+    def get_global_config(self):
+        """\
+        Get the global section of the configuration file.
+
+        @return: all global configuration parameters
+        @rtype: C{dict}
+
+        """
+        return self.get_section('global')
+
+    def get_backend_config(self, backend='zeroconf'):
+        """\
+        Get the configuration section of a specific backend.
+
+        @param backend: the name of the backend
+        @type backend: C{str}
+
+        @return: all backend configuration parameters
+        @rtype: C{dict}
+
+        """
+        return self.get_section(backend)
+
+    @property
+    def printable_config_file(self):
+        """\
+        Returns a printable configuration file as a multi-line string.
+
+        """
+        stdout = cStringIO.StringIO()
+        self.iniConfig.write(stdout)
+        _ret_val = stdout.getvalue()
+        stdout.close()
+        return _ret_val
diff --git a/x2gobroker/defaults.py b/x2gobroker/defaults.py
index d3de516..b9dc3c6 100644
--- a/x2gobroker/defaults.py
+++ b/x2gobroker/defaults.py
@@ -19,8 +19,13 @@
 # Free Software Foundation, Inc.,
 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
+# modules
+import os
 import uuid
 
+# the home directory of the user that the daemon/cgi runs as
+X2GOBROKER_HOME = os.path.normpath(os.path.expanduser('~'))
+
 # FIXME: this path must not be hard-coded
 X2GOBROKER_AGENT_CMD="/usr/lib/x2gobroker-agent"
 
@@ -30,14 +35,14 @@ X2GOBROKER_CONFIG_DEFAULTS = {
         'backend': 'zeroconf',
         'check-credentials': True,
         'use-authid': False,
-        'use-static-authid': true,
-        'static-authid': uuid.uuid4(),
+        'use-static-authid': True,
+        'authid': uuid.uuid4(),
         'enable-html-output':  True,
         'enable-json-output': False,
     },
     'zeroconf': {
         'enable': True,
-    }
+    },
     'simple': {
         'enable': False,
         'session-profiles': '/etc/x2go/x2gobroker-simple-sessionprofiles.conf',
@@ -48,7 +53,7 @@ X2GOBROKER_CONFIG_DEFAULTS = {
         'session-profiles': '/etc/x2go/x2gobroker-loadbalancer-sessionprofiles.conf',
         'server-list-PROFILENAME1': ['server1.profile1.mydomain.tld','server2.profile1.mydomain.tld','server3.profile1.mydomain.tld',],
         'server-list-PROFILENAME2': ['server1.profile2.mydomain.tld','server2.profile2.mydomain.tld',],
-    }
+    },
     'ldap': {
         'enable': False,
         'uri': 'ldap://localhost:389',
diff --git a/x2gobroker/utils.py b/x2gobroker/utils.py
new file mode 100644
index 0000000..1a74ed8
--- /dev/null
+++ b/x2gobroker/utils.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2012 by Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+# Copyright (C) 2012 by Oleksandr Shneyder <oleksandr.shneyder at obviously-nice.de>
+# Copyright (C) 2012 by Heinz-Markus Graesing <heinz-m.graesing at obviously-nice.de>
+#
+# X2Go Session Broker is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# X2Go Session Broker is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import os
+import sys
+import types
+import locale
+
+def _checkConfigFileDefaults(data_structure):
+    """\
+    Check an ini-file-like data structure.
+
+    @param data_structure: an ini-file-like data structure
+    @type data_structure: C{dict} of C{dict}s
+
+    @return: C{True} if C{data_structure} matches that of an ini file data structure
+    @rtype: C{bool}
+
+    """
+    if data_structure is None:
+        return False
+    if type(data_structure) is not types.DictType:
+        return False
+    for sub_dict in data_structure.values():
+        if type(sub_dict) is not types.DictType:
+            return False
+    return True
+
+
+def touch_file(filename, mode='a'):
+    """\
+    Imitates the behaviour of the GNU/touch command.
+
+    @param filename: name of the file to touch
+    @type filename: C{str}
+    @param mode: the file mode (as used for Python file objects)
+    @type mode: C{str}
+
+    """
+    if not os.path.isdir(os.path.dirname(filename)):
+        os.makedirs(os.path.dirname(filename), mode=00700)
+    f = open(filename, mode=mode)
+    f.close()
+
+
+def get_encoding():
+    """\
+    Detect systems default character encoding.
+
+    @return: The system's local character encoding.
+    @rtype: C{str}
+
+    """
+    try:
+        encoding = locale.getdefaultlocale()[1]
+        if encoding is None:
+            raise BaseException
+    except:
+        try:
+            encoding = sys.getdefaultencoding()
+        except:
+            encoding = 'ascii'
+    return encoding
+
diff --git a/x2gobroker/__init__.py b/x2gobroker/web/__init__.py
similarity index 97%
copy from x2gobroker/__init__.py
copy to x2gobroker/web/__init__.py
index ad8c1e4..11b7f8f 100644
--- a/x2gobroker/__init__.py
+++ b/x2gobroker/web/__init__.py
@@ -18,6 +18,3 @@
 # Free Software Foundation, Inc.,
 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
-__VERSION__ = '0.0.0.1'
-
-
diff --git a/sbin/x2gobroker b/x2gobroker/web/html.py
old mode 100755
new mode 100644
similarity index 53%
copy from sbin/x2gobroker
copy to x2gobroker/web/html.py
index 0b42c84..f83bc1b
--- a/sbin/x2gobroker
+++ b/x2gobroker/web/html.py
@@ -20,33 +20,10 @@
 # Free Software Foundation, Inc.,
 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
-import sys
-import os
+# modules
 import web
 
-try:
-    import x2gobroker
-except ImportError:
-    sys.path.insert(0, os.path.join(os.getcwd(), '..'))
-
-# FIXME: here we have to add some code that genuinely detects the session broker backend...
-broker_backend = "zeroconf"
-
-# load the requested broker
-if broker_backend == "zeroconf":
-    import x2gobroker.zeroconf as broker
-elif broker_backend == "simple":
-    import x2gobroker.simple as broker
-elif broker_backend == "ldap":
-    import x2gobroker.ldap as broker
-
-
-urls = ( '/', 'x2gobroker' )
-
-
-class x2gobroker:
-
-    broker_backend = broker.X2GoBroker()
+class X2GoBrokerWebHtml:
 
     http_header_items = {
         'Content-Type': 'text/html; charset=utf-8',
@@ -83,72 +60,86 @@ $output
         for http_header_item in self.http_header_items.keys():
             web.header(http_header_item, self.http_header_items[http_header_item])
 
-    def GET(self):
+    def GET(self, backend):
+
+        if not backend:
+            backend = 'zeroconf'
+        else:
+            backend = backend.rstrip('/')
+
+        # silence pyflakes...
+        broker_backend = None
+        exec("import x2gobroker.backends.{backend}".format(backend=backend))
+        exec("broker_backend = x2gobroker.backends.{backend}.X2GoBroker()".format(backend=backend))
+        global_config = broker_backend.get_global_config()
+        backend_config = broker_backend.get_backend_config(backend)
 
         data = web.input()
+        try: username = data.user
+        except AttributeError: username = ''
+        try: password = data.password
+        except AttributeError: password = ''
+        try: authid = data.authid
+        except AttributeError: authid = ''
+        try: task = data.task
+        except AttributeError: task = ''
+        try: session_name = data.sid
+        except AttributeError: session_name = ''
+        try: new_password = data.newpass
+        except AttributeError: new_password = ''
+
         output = ''
 
         self._gen_http_header()
 
-
         # FIXME: the ,,testcon'' task can be object to DoS attacks...
-        if hasattr(data, 'task') and data.task == 'testcon':
+        if task == 'testcon':
 
             ###
             ### TEST THE CONNECTION
             ###
 
-            return self.broker_backend.test_connection()
+            return broker_backend.test_connection()
 
-        if hasattr(data, 'user') and hasattr(data, 'password') and self.broker_backend.check_access(username=data.user, password=data.password):
+        if broker_backend.check_access(username=username, password=password, authid=authid):
 
-            ###
-            ### PERFORM INITIAL AUTHENTICATION
-            ###
+            if not task:
+                ###
+                ### PERFORM A TEST AUTHENTICATION
+                ###
 
-            output += "<strong>Access granted</strong><br />"
-            output += "AUTHID: {authid}<br />".format(authid=self.broker_backend.get_next_authid(username=data.user))
-            return self.page(self.html_header_items, output)
+                if global_config['use-authid']:
 
-        else:
-            return self.page(self.html_header_items, "<hr>Access denied")
-
-        if hasattr(data, 'user') and hasattr(data, 'authid'):
-
-            ###
-            ### X2GO BROKER TASKS
-            ###
-
-            if self.broker_backend.check_access(username=data.user, authid=data.authid):
+                    ### FIXME: make up a nice protocol for this, disabled for now
+                    #output += "AUTHID: {authid}<br />".format(authid=broker_backend.get_next_authid(username=data.user))
+                    pass
 
-                if hasattr(data, 'task'):
-                    task = data.task
+                output += "<strong>Access granted</strong><br />"
+                return self.page(self.html_header_items, output)
 
-                    if task == 'listsessions':
+            else:
 
-                        output += self.broker_backend.list_sessions()
+                ###
+                ### X2GO BROKER TASKS
+                ###
 
-                    if task == 'selectsession':
+                if task == 'listsessions':
 
-                        if hasattr(data, 'sid'):
+                    output += broker_backend.list_sessions()
 
-                            output += self.broker_backend.select_session(session_name=data.sid)
+                if task == 'selectsession':
 
-                    if task == 'setpass':
+                    if session_name:
 
-                        if hasattr(data, 'oldpass') and hasattr(data, 'newpass'):
+                        output += broker_backend.select_session(session_name=session_name)
 
-                            output += self.broker_backend.change_password(new=data.newpass, old=data.oldpass)
+                if task == 'setpass':
 
-                return self.page(self.html_header_items, output)
+                    if new_password:
 
-            else:
-                return self.page(self.html_header_items, "<hr>Access denied")
+                        output += broker_backend.change_password(new_password=new_password)
 
+            return self.page(self.html_header_items, output)
 
-if __name__ == "__main__":
-    import setproctitle
-    setproctitle.setproctitle(os.path.basename(sys.argv[0]))
-    app = web.application(urls, globals())
-    app.internalerror = web.debugerror
-    app.run()
+        else:
+            return self.page(self.html_header_items, "<hr>Access denied")
diff --git a/x2gobroker/__init__.py b/x2gobroker/web/json.py
similarity index 70%
copy from x2gobroker/__init__.py
copy to x2gobroker/web/json.py
index ad8c1e4..b879b77 100644
--- a/x2gobroker/__init__.py
+++ b/x2gobroker/web/json.py
@@ -1,7 +1,9 @@
-# -*- coding: utf-8 -*-
+#!/usr/bin/env python
 
+# This file is part of the  X2Go Project - http://www.x2go.org
+# Copyright (C) 2011-2012 by Oleksandr Shneyder <oleksandr.shneyder at obviously-nice.de>
+# Copyright (C) 2011-2012 by Heinz-Markus Graesing <heinz-m.graesing at obviously-nice.de>
 # Copyright (C) 2012 by Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
-# Copyright (C) 2012 by Oleksandr Shneyder <oleksandr.shneyder at obviously-nice.de>
 #
 # X2Go Session Broker is free software; you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as published by
@@ -18,6 +20,10 @@
 # Free Software Foundation, Inc.,
 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
-__VERSION__ = '0.0.0.1'
+# modules
+import web
 
+class X2GoBrokerWebJson:
 
+    # MUSIC OF THE FUTURE
+    pass
\ No newline at end of file


hooks/post-receive
-- 
x2gobroker.git (HTTP(S) Session broker for X2Go)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "x2gobroker.git" (HTTP(S) Session broker for X2Go).




More information about the x2go-commits mailing list