Author: rjollos
Date: Thu Jun 20 23:36:12 2013
New Revision: 1495238

URL: http://svn.apache.org/r1495238
Log:
Refs #514: Implemented authentication middleware for custom web bootstrap 
handlers. Patch by Olemis.

Modified:
    bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py
    bloodhound/trunk/trac/trac/hooks.py
    bloodhound/trunk/trac/trac/web/standalone.py

Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py
URL: 
http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py?rev=1495238&r1=1495237&r2=1495238&view=diff
==============================================================================
--- bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py (original)
+++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py Thu Jun 20 
23:36:12 2013
@@ -120,4 +120,5 @@ class ProductRequestWithSession(RequestW
 
 class ProductRequestFactory(RequestFactoryBase):
     def create_request(self, env, environ, start_response):
-        return ProductRequestWithSession(env, environ, start_response)
+        return ProductRequestWithSession(env, environ, start_response) \
+            if env else RequestWithSession(environ, start_response)

Modified: bloodhound/trunk/trac/trac/hooks.py
URL: 
http://svn.apache.org/viewvc/bloodhound/trunk/trac/trac/hooks.py?rev=1495238&r1=1495237&r2=1495238&view=diff
==============================================================================
--- bloodhound/trunk/trac/trac/hooks.py (original)
+++ bloodhound/trunk/trac/trac/hooks.py Thu Jun 20 23:36:12 2013
@@ -107,6 +107,12 @@ class BootstrapHandlerBase(object):
         || trac.locale ||  || Target locale ||
         || trac.base_url || TRAC_BASE_URL || Trac base URL hint ||
 
+        A new entry named 'trac.env_name' identifying environment SHOULD be
+        added (e.g. used by tracd to choose authentication realms). 
+        As a side-effect the WSGI environment dict (i.e. `environ`) may be
+        modified in many different ways to prepare it for subsequent
+        dispatching.
+
         This method may handle the request (e.g. render environment index page)
         in case environment lookup yields void results. In that case it MUST 
         invoke WSGI `write` callable returned by `start_response` and raise 
@@ -114,6 +120,7 @@ class BootstrapHandlerBase(object):
 
         :param environ: WSGI environment dict
         :param start_response: WSGI callback for starting the response
+        :return: environment object
         :throws RequestDone: if the request is fully processed while loading
                              target environment e.g. environment index page
         :throws EnvironmentError: if it is impossible to find a way to locate
@@ -125,6 +132,45 @@ class BootstrapHandlerBase(object):
         """
         raise NotImplementedError("Must override method 'open_environment'")
 
+    def default_probe_environment(self, environ):
+        """By default it will invoke `open_environment` and discard the
+        resulting environment object. This approach is generic but not
+        efficient. Should be overridden whenever possible. 
+        """
+        # If the expected configuration keys aren't found in the WSGI 
environment,
+        # try looking them up in the process environment variables
+        environ.setdefault('trac.env_path', os.getenv('TRAC_ENV'))
+        environ.setdefault('trac.env_parent_dir',
+                           os.getenv('TRAC_ENV_PARENT_DIR'))
+        environ.setdefault('trac.env_index_template',
+                           os.getenv('TRAC_ENV_INDEX_TEMPLATE'))
+        environ.setdefault('trac.template_vars',
+                           os.getenv('TRAC_TEMPLATE_VARS'))
+        environ.setdefault('trac.locale', '')
+        environ.setdefault('trac.base_url',
+                           os.getenv('TRAC_BASE_URL'))
+
+        try:
+            self.open_environment(environ, 
+                                  lambda status, headers: (lambda data: None))
+        except Exception:
+            # Handle all exceptions; else potential HTTP protocol violation
+            pass
+
+    def probe_environment(self, environ):
+        """This method is aimed at providing a lightweight version of
+        `open_environment` by solely applying upon `environ` the side effects 
+        needed to dispatch the request in environment context.
+
+        By default it will invoke `open_environment` and discard the
+        resulting environment object. Specialized versions will have the chance
+        to implement more efficient strategies in case environment
+        instantiation may be avoided. 
+
+        :return: None
+        """
+        self.default_probe_environment(environ)
+        
     def create_request(self, env, environ, start_response):
         """Instantiate request object used in subsequent request dispatching
         
@@ -148,7 +194,9 @@ class DefaultBootstrapHandler(BootstrapH
 
     def open_environment(self, environ, start_response):
         env_path = environ.get('trac.env_path')
-        if not env_path:
+        if env_path:
+            environ['trac.env_name'] = os.path.basename(env_path)
+        else:
             env_parent_dir = environ.get('trac.env_parent_dir')
             env_paths = environ.get('trac.env_paths')
             if env_parent_dir or env_paths:
@@ -163,7 +211,8 @@ class DefaultBootstrapHandler(BootstrapH
                     send_project_index(environ, start_response, env_parent_dir,
                                        env_paths)
                     raise RequestDone
-    
+
+                environ['trac.env_name'] = env_name
                 errmsg = None
     
                 # To make the matching patterns of request handlers work, we 
append

Modified: bloodhound/trunk/trac/trac/web/standalone.py
URL: 
http://svn.apache.org/viewvc/bloodhound/trunk/trac/trac/web/standalone.py?rev=1495238&r1=1495237&r2=1495238&view=diff
==============================================================================
--- bloodhound/trunk/trac/trac/web/standalone.py (original)
+++ bloodhound/trunk/trac/trac/web/standalone.py Thu Jun 20 23:36:12 2013
@@ -27,6 +27,7 @@ import sys
 from SocketServer import ThreadingMixIn
 
 from trac import __version__ as VERSION
+from trac.hooks import load_bootstrap_handler
 from trac.util import autoreload, daemon
 from trac.web.auth import BasicAuthentication, DigestAuthentication
 from trac.web.main import dispatch_request
@@ -59,6 +60,31 @@ class AuthenticationMiddleware(object):
         return self.application(environ, start_response)
 
 
+class BootstrapAuthenticationMiddleware(AuthenticationMiddleware):
+    """Authentication middleware for custom web bootstrap handlers
+    """
+    def __call__(self, environ, start_response):
+        bootstrap_ep = os.getenv('TRAC_BOOTSTRAP_HANDLER')
+        environ.setdefault('trac.bootstrap_handler', bootstrap_ep)
+
+        # Preserve original environ and probe dispatching
+        temp_environ = environ.copy()
+        bootstrap = load_bootstrap_handler(bootstrap_ep)
+        bootstrap.probe_environment(temp_environ)
+
+        path_info = temp_environ.get('PATH_INFO', '')
+        path_parts = filter(None, path_info.split('/'))
+        env_name = temp_environ.get('trac.env_name')
+        if path_parts and path_parts[0] == 'login' and env_name:
+            auth = self.auths.get(env_name, self.auths.get('*'))
+            if auth:
+                remote_user = auth.do_auth(environ, start_response)
+                if not remote_user:
+                    return []
+                environ['REMOTE_USER'] = remote_user
+        return self.application(environ, start_response)
+
+
 class BasePathMiddleware(object):
 
     def __init__(self, application, base_path):
@@ -269,15 +295,19 @@ def main():
     if parser.has_option('pidfile') and options.pidfile:
         options.pidfile = os.path.abspath(options.pidfile)
 
-    wsgi_app = TracEnvironMiddleware(dispatch_request,
-                                     options.env_parent_dir, args,
-                                     options.single_env)
+    wsgi_app = dispatch_request
+
     if auths:
         if options.single_env:
             project_name = os.path.basename(args[0])
-            wsgi_app = AuthenticationMiddleware(wsgi_app, auths, project_name)
+            wsgi_app = BootstrapAuthenticationMiddleware(wsgi_app, auths, 
project_name)
         else:
-            wsgi_app = AuthenticationMiddleware(wsgi_app, auths)
+            wsgi_app = BootstrapAuthenticationMiddleware(wsgi_app, auths)
+
+    wsgi_app = TracEnvironMiddleware(wsgi_app,
+                                     options.env_parent_dir, args,
+                                     options.single_env)
+
     base_path = options.base_path.strip('/')
     if base_path:
         wsgi_app = BasePathMiddleware(wsgi_app, base_path)


Reply via email to