Commits

Joel Rivera committed 44e7b8b

Add an Impersonate handler to the GOAuth middleware.
Update the fixed listing for the endpoint tool parameters.
Set the documentation on the appropiate module of endpoint.py

Comments (0)

Files changed (4)

lib/galaxy/tools/actions/globus.py

 import logging
 
 from galaxy.tools import actions
-from galaxy.datatypes.sniff import guess_ext
-
 
 log = logging.getLogger(__name__)
 

lib/galaxy/tools/parameters/globus/__init__.py

-"""Dynamic parameters to customize the experience of the globus endpoints.
-
-The way that gets rendered can be as a textfield or selectfield it
-depends if the configuration parameters are set in the universe.wsgi file.
-
-Config parameters:
-
-  - globus_dynamic_endpoints:
-    If is set and equals True and also the GlobusAuthentication middleware is enabled
-    then will take precedence of the fixed endpoints directive, and it will generate
-    the paths for the files dynamically.
-  - "globus_fixed_endpoints":
-    If is set and equals True then use the next two parameters
-    to limit the selection to those two list of endpoints.
-    And if the `globus_fixed_files` directive is set, then show a file browser
-    with those files for the specific endpoint.  
-    - globus_src_endpoints
-    - globus_dst_endpoints
-      A list of comma separated endpoints names, e.g.:
-        'go#ep1, go#ep2'
-    - globus_fixed_files
-      A json string of the form:
-       {ENDPOINT_A: [{DIRECTORY1: [FILE1, FILE2,..., FILEn]},
-                     {DIRECTORY2: [FILE1, FILE2,..., FILEn]},
-                     ...
-                     {DIRECTORYn: [FILE1, FILE2,..., FILEn]}],
-        ENDPOINT_B: [...],
-        ...}
-         
-To use this is required to add the path to the class in `tool_parameters_conf.xml`
-    <toolparameter    name="gsrc_endpoint"
-      parameter="galaxy.tools.parameters.globus:SourceEndpoint" />
-    <toolparameter   name="gdst_endpoint"
-      parameter="galaxy.tools.parameters.globus:DestEndpoint" />
-    <toolparameter name="gsrc_path"
-      parameter="galaxy.tools.parameters.globus:SourceEndpointPath" />
-"""
 from .endpoint import (
     SourceEndpointPath,
     SourceEndpoint,

lib/galaxy/tools/parameters/globus/endpoint.py

+"""Dynamic parameters to customize the experience of the globus endpoints.
+
+The way that gets rendered can be as a textfield or selectfield it
+depends if the configuration parameters are set in the universe.wsgi file.
+
+Config parameters:
+
+  - globus_dynamic_endpoints:
+    If is set and equals True and also the GlobusAuthentication middleware is enabled
+    then it will take precedence of the fixed endpoints directive and generate
+    the paths for the files dynamically.
+  - "globus_fixed_endpoints":
+    If is set and equals True then use the next two parameters
+    to limit the selection to those two list of endpoints; if the `globus_fixed_files`
+    directive is set  show a file browser with the files on the endpoint.  
+    - globus_src_endpoints
+    - globus_dst_endpoints
+      A list of comma separated endpoints names, e.g.:
+        'go#ep1, go#ep2'
+    - globus_fixed_files
+      A json string of the form:
+       {ENDPOINT_A: [{DIRECTORY1: [FILE1, FILE2,..., FILEn]},
+                     {DIRECTORY2: [FILE1, FILE2,..., FILEn]},
+                     ...
+                     {DIRECTORYn: [FILE1, FILE2,..., FILEn]},
+                     FILE1, FILE2,...],
+        ENDPOINT_B: [...],
+        ...}
+         
+To use this is required to add the path to the class in `tool_parameters_conf.xml`
+    <toolparameter    name="gsrc_endpoint"
+      parameter="galaxy.tools.parameters.globus:SourceEndpoint" />
+    <toolparameter   name="gdst_endpoint"
+      parameter="galaxy.tools.parameters.globus:DestEndpoint" />
+    <toolparameter name="gsrc_path"
+      parameter="galaxy.tools.parameters.globus:SourceEndpointPath" />
+"""
 import json
 import logging
 
     def _inline_json_paths(self):
         # globus_fxe_input_size: is the size of the text field that is shown
         # in case that there is no files for the specific endpoint.
+        def append_files_of_directory(id_, files, file_list):
+            for dir_name, chfiles in files.items():
+                pid = 'p%s' % id_
+                file_list.append({'name': dir_name,
+                                  'type': 'dir',
+                                  'id': pid})
+                for file_name in chfiles:
+                    file_list.append({'name': file_name,
+                                      'type': 'file',
+                                      'childOf': pid})
         paths = json.loads(self.json_paths)
         json_paths = {}
-        for ep_name, dirs in paths.items():
+        for ep_name, content in paths.items():
             elements = []
-            for  i, dir_files in enumerate(dirs): 
-                for (dir_name, files) in dir_files.items():
-                    pid = 'p%s' % i
-                    elements.append({'name': dir_name,
-                                     'type': 'dir',
-                                     'id': pid})
-                    for file_name in files:
-                        elements.append({'name': file_name,
-                                         'type': 'file',
-                                         'childOf': pid})
+            for  i, filedata in enumerate(content):
+                if isinstance(filedata, dict): # is a directory
+                    append_files_of_directory(i, filedata, elements)
+                else:
+                    elements.append({'name': filedata,
+                                     'type': 'file',
+                                     'id': 'f:%s' % i})
             json_paths[ep_name] = elements
         return """<script type="text/javascript">
         var globus_fxe_paths = %s;
         var globus_fxe_input_size = %s;
+        $(document).ready(function(){
+         	var gobrowser = new GlobusOnlineBrowser();
+        	gobrowser.setup();
+         });
         </script>
         """ % (json.dumps(json_paths), self.size)
 
-        
+
     def get_html(self, *args, **kwargs):
         hidden_field = super(FixedEndpoint, self).get_html(*args, **kwargs)
         html_parts = []

lib/galaxy/web/framework/ext/globus/middleware/auth.py

 from Cookie import BaseCookie
 from cgi import parse_qs
 from datetime import datetime
+from cStringIO import StringIO
 
 import nexus
 from nexus import token_utils
     AUTHENTICATED = 'AUTHENTICATED'
     NOT_AUTHORIZED = 'NOT_AUTHORIZED'
     NOT_ALLOWED = 'NOT_ALLOWED'
+    IMPERSONATE = 'IMPERSONATE' 
     API_CALL = 'API_CALL'
+    # Redundant names just to avoid any string typos.
 
     def __init__(self, app, nexclient, nexsecret,  nexserver=None,
                  groupid=None, gaccount_cmd=None):
                                              in_memory_storage=self.storage),
             self.NOT_AUTHORIZED: NotAuthorized(app, nc),
             self.NOT_ALLOWED: NotAllowed(app, nc),
+            self.IMPERSONATE: Impersonate(app, nc, lock=users_lock,
+                                          active_users=actu,
+                                          in_memory_storage=self.storage),
         #            self.API_CALL: APICall(app)
         }
+        # The API_CALL is no enabled right now but is meant to pass the request
+        # untouched I just didn't have a particular use case right now but
+        # this middleware is going to be an issue if we try to use the api
+        # from another process outside the browser.
+        self.check_expired_tokens = False 
         # currently is not required to verify for the expiration time
         # it gives by default an expiration date of 1 year and
-        # apparently is not publicaly implemented at nexux.api...
-        self.check_expired_tokens = False 
+        # apparently is not publicly implemented at nexus.api...
         
     def __call__(self, environ, start_response):
         session = self._session(environ)
         qs = parse_qs(environ['QUERY_STRING'])
-        name, params = self._detect_type_of_request(session, environ['PATH_INFO'], qs)
+        name, params = self._detect_type_of_request(session, environ, qs)
         handler = self.handlers[name]
         return handler(session, start_response, environ, *params)
 
-    def _detect_type_of_request(self, session, path, qs):
+    def _handle_oauth_flow(self, session, qs):
+        if 'action' in qs:
+            action = qs['action'][0]
+            if action == 'logout' and \
+                   session in self.active_users:
+                return self.LOGOUT, ()
+            elif action == 'user_not_allowed':
+                user_not_allowed = None
+                if 'user' in qs:
+                    user_not_allowed = qs['user'][0]
+                    return self.NOT_ALLOWED, (user_not_allowed,)
+        if 'code' in qs:
+            code = qs['code'][0]
+            return self.LOGIN, (code,)
+        return None
+
+    def _detect_type_of_request(self, session, env, qs):
         """Always return a type of request and the arguments
         required for the handler.
         
         :returns: handler_name, (params)
         """
-        if path == '/':
-            if 'action' in qs:
-                action = qs['action'][0]
-                if action == 'logout' and \
-                       session in self.active_users:
-                    return self.LOGOUT, ()
-                elif action == 'user_not_allowed':
-                    user_not_allowed = None
-                    if 'user' in qs:
-                        user_not_allowed = qs['user'][0]
-                        return self.NOT_ALLOWED, (user_not_allowed,)
-            if 'code' in qs:
-                code = qs['code'][0]
-                return self.LOGIN, (code,)
+        if env['PATH_INFO'] == '/':
+            result = self._handle_oauth_flow(session, qs)
+            if result is not None:
+                return result
         ## elif path.startswith('/api/'):
-        ##     return self.API_CALL, ()
+        ##     return self.API_CALL, () 
+        if (env['REQUEST_METHOD'] == 'POST' and 
+            'HTTP_REFERER' in env and 
+            env['HTTP_REFERER'].endswith('/admin/impersonate')):
+                return self.IMPERSONATE, ()
         user_n_token = self._user_in_session(session)
         if user_n_token is not None:
             return self.AUTHENTICATED, user_n_token
                 'refresh': response.refresh_token,
                 'exp': expires}
 
-
     def _req_cookie(self, environ):
         cookie = BaseCookie()
         cookie.load(environ.get('HTTP_COOKIE', ''))
             else:
                 return session.value
 
-        
-    
 
-        
 class ActionHandler(object):
     required_args = set([])
 
                                               self.nexus_client.client),
                             'message': ''}
 
+
 class NotAllowed(ActionHandler):
     def __call__(self, session, start_response, environ, user):
         """Handle the case when the user is not allowed in this instance
         return AUTH_PAGE % {'url': globus_url(environ,
                                               self.nexus_client.client),
                             'message': message}
+
+
+class Impersonate(ActionHandler):
+    required_args = set(('active_users', 'in_memory_storage', 'lock'))
+
+    def __call__(self, session, start_response, environ):
+        impuser = self._catch_user_for_impersonate_request(session, environ)
+        def custom_start_response(status, headers, exc_info=None):
+            self._impersonate_session(session, environ, impuser)
+            return start_response('200 OK', headers, exc_info)
+        self._set_current_user(session, environ)
+        return self.app(environ, custom_start_response)
+
+    def _set_current_user(self, session, environ):
+        user, tokens = self.active_users[session]
+        environ['HTTP_REMOTE_USER'] = user['username'] 
+        environ['X-GLOBUS-USER'] = user['username']
+        environ['X-GLOBUS-TOKEN'] = tokens['access']
+        environ['globus.storage'] = self.in_memory_storage
+
+    def _impersonate_session(self, session, environ, email):
+        with self.lock:
+            self.active_users[session] = ({'username': email.split('@')[0]},
+                                          {'access': ''})
+
+    def _catch_user_for_impersonate_request(self, session, env):
+        body = env['wsgi.input'].read()
+        params = parse_qs(body)
+        env['wsgi.input'] = StringIO(body)
+        return params['email'][0]
+
+