[X2Go-Commits] x2gobroker.git - build-main (branch) updated: 0.0.1.0-81-g2d21a9d

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


The branch, build-main has been updated
       via  2d21a9df895b5c66269e05c827bcbb5da612eb08 (commit)
      from  9bab6a6a97e22a86c16b5c22c4a2390a8664d3be (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:
 debian/changelog                  |   12 +++-
 sbin/x2gobroker                   |    5 +-
 x2gobroker/basicauth.py           |   55 +++++++++++++++++
 x2gobroker/brokers/base_broker.py |    3 -
 x2gobroker/uccsjson.py            |   26 ++++----
 x2gobroker/web/uccs.py            |  123 +++++++++++++++++++------------------
 6 files changed, 143 insertions(+), 81 deletions(-)
 create mode 100644 x2gobroker/basicauth.py

The diff of changes is:
diff --git a/debian/changelog b/debian/changelog
index c0ab3f0..c50551a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,12 @@
-x2gobroker (0.0.1.2-0~x2go1) UNRELEASED; urgency=low
-
-  * Continue development...
+x2gobroker (0.0.2.0-0~x2go1) UNRELEASED; urgency=low
+
+  * New upstream version (0.0.2.0):
+    - Add a UCCS-like web frontend UI that allows unity greeter to offer
+      X2Go session logins. At the time of writing this, on the system running
+      Unity Greeter it requires a patched remote-login-service (see LP:1172943,
+      LP:1172318) and patched unity-greeter (LP:1172928, LP:1172877).
+      Additionally the system running Unity Greeter requires the extra packages
+      lightdm-remote-session-x2go and libpam-x2go.
 
  -- Mike Gabriel <mike.gabriel at das-netzwerkteam.de>  Tue, 23 Apr 2013 23:26:21 +0200
 
diff --git a/sbin/x2gobroker b/sbin/x2gobroker
index aff9f8d..c2ee335 100755
--- a/sbin/x2gobroker
+++ b/sbin/x2gobroker
@@ -114,10 +114,11 @@ import x2gobroker.web.extras
 
 # define the web.py URLs
 urls = ( ('/plain/(.*)', x2gobroker.web.plain.X2GoBrokerWeb,),
-         ('/uccs/(.*)', x2gobroker.web.uccs.X2GoBrokerWeb,),
+         ('/uccs/[a-zA-Z]*(/*)$', x2gobroker.web.uccs.X2GoBrokerWeb,),
+         ('/uccs/(.*)/api/([0-9])(/*)$', x2gobroker.web.uccs.X2GoBrokerWebAPI,),
 #        ('/json/(.*)', x2gobroker.web.json.X2GoBrokerWeb,),
 #        ('/html/(.*)', x2gobroker.web.html.X2GoBrokerWeb,),
-         ('/pubkeys(|/)$', x2gobroker.web.extras.X2GoBrokerPubKeyService,),
+         ('/pubkeys(/*)$', x2gobroker.web.extras.X2GoBrokerPubKeyService,),
        )
 
 settings = {
diff --git a/x2gobroker/basicauth.py b/x2gobroker/basicauth.py
new file mode 100644
index 0000000..f48da4c
--- /dev/null
+++ b/x2gobroker/basicauth.py
@@ -0,0 +1,55 @@
+#!/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>
+#
+# 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.
+
+# modules
+import base64
+
+def require_basic_auth(realm, validate_callback):
+    def require_basic_auth_decorator(handler_class):
+        def wrap_execute(handler_execute):
+            def require_basic_auth(handler, kwargs):
+                def create_auth_header():
+                    handler.set_status(401)
+                    handler.set_header('WWW-Authenticate', 'Basic realm="{realm}"'.format(realm=realm))
+                    handler._transforms = []
+                    handler.finish()
+
+                auth_header = handler.request.headers.get('Authorization')
+                if auth_header is None or not auth_header.startswith('Basic '):
+                    create_auth_header()
+                else:
+                    auth_decoded = base64.decodestring(auth_header[6:])
+                    username, kwargs['basicauth_pass'] = [ unicode(s) for s in auth_decoded.split(':', 2) ]
+                    kwargs['basicauth_user'], access = validate_callback(username, kwargs['basicauth_pass'])
+                    if access:
+                        return True
+                    else:
+                        create_auth_header()
+            def _execute(self, transforms, *args, **kwargs):
+                if not require_basic_auth(self, kwargs):
+                    return False
+                return handler_execute(self, transforms, *args, **kwargs)
+            return _execute
+
+        handler_class._execute = wrap_execute(handler_class._execute)
+        return handler_class
+    return require_basic_auth_decorator
diff --git a/x2gobroker/brokers/base_broker.py b/x2gobroker/brokers/base_broker.py
index 3cac792..2ce0ba4 100644
--- a/x2gobroker/brokers/base_broker.py
+++ b/x2gobroker/brokers/base_broker.py
@@ -731,9 +731,6 @@ class X2GoBroker(object):
 
         access = False
         access = self._do_authenticate(username=username, password=password)
-        if not access and "@" in username:
-            _username = username.split('@')[0]
-            access = self._do_authenticate(username=_username, password=password)
         logger_broker.debug('base_broker.X2GoBroker.check_access(): result of authentication check is: {access}'.format(access=access))
 
         ### HANDLING OF DYNAMIC AUTHENTICATION ID HASHES
diff --git a/x2gobroker/uccsjson.py b/x2gobroker/uccsjson.py
index ca61dab..8393a59 100644
--- a/x2gobroker/uccsjson.py
+++ b/x2gobroker/uccsjson.py
@@ -1,3 +1,5 @@
+# -*- 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>
@@ -59,7 +61,7 @@ class ManagementServer():
         """
         if isinstance(ts_name, str):
             self.DefaultServer = unicode(ts_name)
-        elif isinstance(domain, unicode):
+        elif isinstance(ts_name, unicode):
             self.DefaultServer = ts_name
         else:
             raise TypeError("set_default expects a string argument")
@@ -87,7 +89,7 @@ class ManagementServer():
         Dump this instance as JSON object.
 
         """
-        return json.dumps(self, default=convert_to_builtin_type, sort_keys=True, indent=4)
+        return json.dumps(self, default=convert_to_builtin_type, sort_keys=True, indent=2)
 
 
 # NOT USED!!!
@@ -102,7 +104,7 @@ class RDPServer():
     Instantiate a UCCS compatible RDP server session profile object.
 
     """
-    def __init__(self, host, name, username=None, password=None):
+    def __init__(self, host, name, username='', password=''):
         """\
         @param host: hostname of RDP server host
         @type host: C{unicode}
@@ -114,9 +116,9 @@ class RDPServer():
         @type password: C{unicode}
 
         """
-        self.URL = unicode(host)
+        self.URL = 'http://{url}/'.format(url=unicode(host))
         self.Name = unicode(name)
-        self.Protocol = u'freerdp'
+        self.Protocol = u'rdp'
         self.DomainRequired = True
         self.Username = unicode(username)
         self.Password = unicode(password)
@@ -143,7 +145,7 @@ class RDPServer():
         Dump this instance as JSON object.
 
         """
-        return json.dumps(self, default=convert_to_builtin_type, sort_keys=True, indent=4)
+        return json.dumps(self, default=convert_to_builtin_type, sort_keys=True, indent=2)
 
 
 class ICAServer():
@@ -151,7 +153,7 @@ class ICAServer():
     Instantiate a UCCS compatible ICA server session profile object.
 
     """
-    def __init__(self, host, name, username=None, password=None):
+    def __init__(self, host, name, username='', password=''):
         """\
         @param host: hostname of ICA server host
         @type host: C{unicode}
@@ -163,7 +165,7 @@ class ICAServer():
         @type password: C{unicode}
 
         """
-        self.URL = unicode(host)
+        self.URL = 'http://{url}/'.format(url=unicode(host))
         self.Name = unicode(name)
         self.Protocol = u'ica'
         self.DomainRequired = unicode(True)
@@ -192,7 +194,7 @@ class ICAServer():
         Dump this instance as JSON object.
 
         """
-        return json.dumps(self, default=convert_to_builtin_type, sort_keys=True, indent=4)
+        return json.dumps(self, default=convert_to_builtin_type, sort_keys=True, indent=2)
 
 
 class X2GoServer():
@@ -200,7 +202,7 @@ class X2GoServer():
     Instantiate a UCCS compatible X2Go Server session profile object.
 
     """
-    def __init__(self, host, name, username=None, password=None):
+    def __init__(self, host, name, username='', password=''):
         """\
         @param host: hostname of X2Go Server host
         @type host: C{unicode}
@@ -212,7 +214,7 @@ class X2GoServer():
         @type password: C{unicode}
 
         """
-        self.URL = unicode(host)
+        self.URL = 'http://{url}/'.format(url=unicode(host))
         self.Name = unicode(name)
         self.Protocol = u'x2go'
         self.SessionTypeRequired = True
@@ -241,5 +243,5 @@ class X2GoServer():
         Dump this instance as JSON object.
 
         """
-        return json.dumps(self, default=convert_to_builtin_type, sort_keys=True, indent=4)
+        return json.dumps(self, default=convert_to_builtin_type, sort_keys=True, indent=2)
 
diff --git a/x2gobroker/web/uccs.py b/x2gobroker/web/uccs.py
index db59f24..041ea81 100644
--- a/x2gobroker/web/uccs.py
+++ b/x2gobroker/web/uccs.py
@@ -21,59 +21,50 @@
 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
 # modules
-import types
 import re
 import base64
+import datetime
 import tornado.web
-from tornado.escape import native_str, parse_qs_bytes
 
 # Python X2Go Broker modules
 import x2gobroker.defaults
 
 from x2gobroker.loggers import logger_broker, logger_error
 import x2gobroker.uccsjson
+import x2gobroker.basicauth
+
+
+def credentials_validate(username, password):
 
-def require_basic_auth(realm, validate_callback):
-    def require_basic_auth_decorator(handler_class):
-        def wrap_execute(handler_execute):
-            def require_basic_auth(handler, kwargs):
-                def create_auth_header():
-                    handler.set_status(401)
-                    handler.set_header('WWW-Authenticate', 'Basic realm="{realm}"'.format(realm=realm))
-                    handler._transforms = []
-                    handler.finish()
-
-                auth_header = handler.request.headers.get('Authorization')
-                if auth_header is None or not auth_header.startswith('Basic '):
-                    create_auth_header()
-                else:
-                    auth_decoded = base64.decodestring(auth_header[6:])
-                    kwargs['basicauth_user'], kwargs['basicauth_pass'] = [ unicode(s) for s in auth_decoded.split(':', 2) ]
-                    if validate_callback(handler_class, kwargs['basicauth_user'], kwargs['basicauth_pass']):
-                        return True
-                    else:
-                        create_auth_header()
-            def _execute(self, transforms, *args, **kwargs):
-                if not require_basic_auth(self, kwargs):
-                    return False
-                return handler_execute(self, transforms, *args, **kwargs)
-            return _execute
-
-        handler_class._execute = wrap_execute(handler_class._execute)
-        return handler_class
-    return require_basic_auth_decorator
-
-
-def credentials_validate(handler_class, username, password):
     import x2gobroker.brokers.base_broker
     # FIXME: with the below hack, the backend broker detection in X2GoBrokerWeb is disabled, only global options
     #        from x2gobroker.conf are available here...
-    return x2gobroker.brokers.base_broker.X2GoBroker().check_access(username=username, password=password)
+    broker = x2gobroker.brokers.base_broker.X2GoBroker()
+    broker.enable()
+    access = broker.check_access(username=username, password=password)
+    # UCCS only allows email addresses for remote login 
+    if not access and "@" in username:
+        username = username.split('@')[0]
+        access = broker.check_access(username=username, password=password)
+    return username, access
 
 
- at require_basic_auth('Authentication required', credentials_validate)
 class X2GoBrokerWeb(tornado.web.RequestHandler):
 
+    def get(self, path):
+        if x2gobroker.defaults.X2GOBROKER_DEBUG:
+            logger_broker.warn('GET http request detected, if unwanted: disable X2GOBROKER_DEBUG')
+            return self.head(path)
+        raise tornado.web.HTTPError(405)
+
+    def head(self, path):
+        self.write(unicode(datetime.datetime.utcnow()))
+        return
+
+
+ at x2gobroker.basicauth.require_basic_auth('Authentication required', credentials_validate)
+class X2GoBrokerWebAPI(tornado.web.RequestHandler):
+
     http_header_items = {
         'Content-Type': 'text/plain; charset=utf-8',
         'Expires': '+1h',
@@ -84,30 +75,26 @@ class X2GoBrokerWeb(tornado.web.RequestHandler):
         for http_header_item in self.http_header_items.keys():
             self.set_header(http_header_item, self.http_header_items[http_header_item])
 
-    def get(self, backend, basicauth_user, basicauth_pass):
-        if x2gobroker.defaults.X2GOBROKER_DEBUG:
-            self._gen_http_header()
-            logger_broker.warn('GET http request detected, if unwanted: disable X2GOBROKER_DEBUG')
-            return self.head(backend, basicauth_user, basicauth_pass)
-        raise tornado.web.HTTPError(404)
+    def get(self, *args, **kwargs):
+
+        self._gen_http_header()
 
-    def head(self, backend, basicauth_user, basicauth_pass):
+        backend = args[0]
+        api_version = args[1]
+        try:
+            api_version = int(api_version)
+        except TypeError:
+            api_version = 4
 
         if not backend:
-            backend = x2gobroker.defaults.X2GOBROKER_DEFAULT_BACKEND
+            self.backend = x2gobroker.defaults.X2GOBROKER_DEFAULT_BACKEND
         else:
-            backend = backend.rstrip('/')
-
-        api_version = 4
-        if re.match('.*/api/[0-9].*', backend):
-            # get the first and the third item as backend, api_version
-            backend, api_version = backend.split('/')[:3:2]
-            api_version = int(api_version)
+            self.backend = backend.rstrip('/')
 
         try:
             # dynamically detect broker backend from given URL
-            exec("import x2gobroker.brokers.{backend}_broker".format(backend=backend))
-            exec("self.broker_backend = x2gobroker.brokers.{backend}_broker.X2GoBroker()".format(backend=backend))
+            exec("import x2gobroker.brokers.{backend}_broker".format(backend=self.backend))
+            exec("self.broker_backend = x2gobroker.brokers.{backend}_broker.X2GoBroker()".format(backend=self.backend))
         except ImportError:
             # throw a 404 if the backend does not exist
             raise tornado.web.HTTPError(404)
@@ -121,27 +108,34 @@ class X2GoBrokerWeb(tornado.web.RequestHandler):
         # set the client address for the broker backend
         ip = self.request.remote_ip
         if ip:
-            logger_broker.info('client address is {address}'.format(address=ip))
             self.broker_backend.set_client_address(ip)
+            logger_broker.info('client address is {address}'.format(address=ip))
         elif not x2gobroker.defaults.X2GOBROKER_DEBUG:
             # if the client IP is not set, we pretend to have nothing on offer
             logger_error.error('client could not provide an IP address, pretending: 404 Not Found')
             raise tornado.web.HTTPError(404)
 
-        username, password = basicauth_user, basicauth_pass
-        cookie = ''
+        ###
+        ### CONFIRM SUCCESSFUL AUTHENTICATION FIRST
+        ###
 
-        output = ''
+        try:
+            username = kwargs['basicauth_user']
+        except KeyError:
+            raise tornado.web.HTTPError(401)
 
+        cookie = ''
         logger_broker.debug ('Authenticated as username: {username}, with password: <hidden>'.format(username=username))
 
         ###
-        ### CONFIRM SUCCESSFUL AUTHENTICATION FIRST
+        ### GENERATE UCCS JSON TREE
         ###
 
+        output = ''
+
         profiles = self.broker_backend.list_profiles(username)
         urlbase = self.broker_backend.get_global_value('my-uccs-url-base').rstrip('/')
-        ms = x2gobroker.uccsjson.ManagementServer('{urlbase}/uccs/{backend}'.format(urlbase=urlbase, backend=backend), 'X2Go Session Broker')
+        ms = x2gobroker.uccsjson.ManagementServer('{urlbase}/uccs/{backend}/'.format(urlbase=urlbase, backend=backend), 'X2Go Session Broker')
 
         profile_ids = profiles.keys()
         profile_ids.sort()
@@ -149,14 +143,21 @@ class X2GoBrokerWeb(tornado.web.RequestHandler):
         for profile_id in profile_ids:
 
             if profiles[profile_id][u'directrdp']:
-                pass
+                ts = x2gobroker.uccsjson.RDPServer(
+                        host='{hostname}'.format(hostname=profiles[profile_id][u'host'][0]),
+                        name=profiles[profile_id][u'name'],
+                        username=profiles[profile_id][u'user'],
+                )
+                ts.set_domain('LOCAL')
             else:
                 ts = x2gobroker.uccsjson.X2GoServer(
-                        host='{hostname}:{port}'.format(hostname=profiles[profile_id][u'host'], port=profiles[profile_id][u'sshport']),
+                        host='{hostname}:{port}'.format(hostname=profiles[profile_id][u'host'][0], port=profiles[profile_id][u'sshport']),
                         name=profiles[profile_id][u'name'],
                         username=profiles[profile_id][u'user'],
                 )
+                ts.set_session_type(profiles[profile_id]['command'])
             ms.add_terminalserver(ts)
+            ms.set_default(ts.Name)
 
         output += ms.toJson()
 


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