Example #1
0
def get_api_user(
        security: IdEncodingHelper = depends(IdEncodingHelper),
        user_manager: UserManager = depends(UserManager),
        key: Optional[str] = Query(None),
        x_api_key: Optional[str] = Header(None),
        run_as:
    Optional[EncodedDatabaseIdField] = Header(
        default=None,
        title='Run as User',
        description=
        ('The user ID that will be used to effectively make this API call. '
         'Only admins and designated users can make API calls on behalf of other users.'
         ))) -> Optional[User]:
    api_key = key or x_api_key
    if not api_key:
        return None
    user = user_manager.by_api_key(api_key=api_key)
    if run_as:
        if user_manager.user_can_do_run_as(user):
            try:
                decoded_run_as_id = security.decode_id(run_as)
            except Exception:
                raise UserInvalidRunAsException
            return user_manager.by_id(decoded_run_as_id)
        else:
            raise UserCannotRunAsException
    return user
Example #2
0
    def get_workflow(this):
        from galaxy import util
        from galaxy.webapps.galaxy.controllers.workflow import WorkflowController
        from galaxy.workflow.extract import extract_workflow
        from galaxy.workflow.extract import summarize

        tmpuser = this.user
        if not this.user:
            tmpusername = os.getenv('GALAXY_DEFAULT_WORKFLOWGENERATOR_USER', os.environ['GALAXY_DEFAULT_ADMIN_USER'])
            if not tmpusername:
                tmpuser = UserManager(this.trans.app).admins()[0]
            tmpuser = this.trans.sa_session.query(this.trans.app.model.User).filter_by(username=tmpusername,deleted=False).all()[0]

        #html = WorkflowController(this.trans.app).build_from_current_history(this.trans)
        #use reimplementation since controller does user=trans.get_user() || error

        jobs, warnings = summarize(this.trans)
        html = this.trans.fill_template("workflow/build_from_current_history.mako", jobs=jobs, warnings=warnings, history=this.history)
        
        job_ids = re.findall('job_ids.+value="([^"]+)',html)
        dataset_ids = re.findall('dataset_ids.+value="([^"]+)',html)
        dataset_names = re.findall('dataset_names.+value="([^"]+)',html)
        dataset_collection_ids = re.findall('dataset_collection_ids.+value="(\d+)',html)
        dataset_collection_names = re.findall('dataset_collection_names.+value="(\d+)',html)

        dataset_names = util.listify(dataset_names)
        dataset_collection_names = util.listify(dataset_collection_names)
        stored = extract_workflow(
            this.trans,
            user=tmpuser,
            job_ids=job_ids,
            dataset_ids=dataset_ids,
            dataset_collection_ids=dataset_collection_ids,
            workflow_name='de.STAIR Guide Workflow',
            dataset_names=dataset_names,
            dataset_collection_names=dataset_collection_names
        )

        this.workflow = WorkflowController(this.trans.app)._workflow_to_dict(this.trans, stored)

        # reimplement deletion which originally makes use of get_stored_workflow which failes in case of anon user
        stored.deleted = True
        tmpuser.stored_workflow_menu_entries = [entry for entry in tmpuser.stored_workflow_menu_entries if entry.stored_workflow != stored]
        this.trans.sa_session.add(stored)
        this.trans.sa_session.flush()

        return {
            'workflow': this.workflow
        }
Example #3
0
    def __init__(self, config=None, **kwargs):
        self.config = config or MockAppConfig(**kwargs)
        self.security = self.config.security
        self.name = kwargs.get('name', 'galaxy')
        self.object_store = objectstore.build_object_store_from_config(
            self.config)
        self.model = mapping.init("/tmp",
                                  self.config.database_connection,
                                  create_tables=True,
                                  object_store=self.object_store)
        self.security_agent = self.model.security_agent
        self.visualizations_registry = MockVisualizationsRegistry()
        self.tag_handler = tags.GalaxyTagHandler(self.model.context)
        self.quota_agent = quota.DatabaseQuotaAgent(self.model)
        self.init_datatypes()
        self.job_config = Bunch(dynamic_params=None, destinations={})
        self.tool_data_tables = {}
        self.dataset_collections_service = None
        self.container_finder = NullContainerFinder()
        self._toolbox_lock = MockLock()
        self.tool_shed_registry = Bunch(tool_sheds={})
        self.genome_builds = GenomeBuilds(self)
        self.job_manager = NoopManager()
        self.application_stack = ApplicationStack()
        self.auth_manager = AuthManager(self)
        self.user_manager = UserManager(self)
        self.execution_timer_factory = Bunch(
            get_timer=StructuredExecutionTimer)

        def url_for(*args, **kwds):
            return "/mock/url"

        self.url_for = url_for
Example #4
0
def get_api_user(security: IdEncodingHelper = depends(IdEncodingHelper),
                 user_manager: UserManager = depends(UserManager),
                 key: Optional[str] = Query(None),
                 x_api_key: Optional[str] = Header(None),
                 run_as: Optional[EncodedDatabaseIdField] = Header(
                     None, title='Run as User',
                     description='Admins and ')) -> Optional[User]:
    api_key = key or x_api_key
    if not api_key:
        return None
    user = user_manager.by_api_key(api_key=api_key)
    if run_as:
        if user_manager.user_can_do_run_as(user):
            try:
                decoded_run_as_id = security.decode_id(run_as)
            except Exception:
                raise UserInvalidRunAsException
            return user_manager.by_id(decoded_run_as_id)
        else:
            raise UserCannotRunAsException
    return user
class BaseTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print('\n', '-' * 20, 'begin class', cls)

    @classmethod
    def tearDownClass(cls):
        print('\n', '-' * 20, 'end class', cls)

    def __init__(self, *args):
        unittest.TestCase.__init__(self, *args)

    def setUp(self):
        self.log('.' * 20, 'begin test', self)
        self.set_up_mocks()
        self.set_up_managers()
        self.set_up_trans()

    def set_up_mocks(self):
        self.trans = mock.MockTrans(admin_users=admin_users)
        self.app = self.trans.app

    def set_up_managers(self):
        self.user_mgr = UserManager(self.app)

    def set_up_trans(self):
        self.admin_user = self.user_mgr.create(self.trans,
                                               email=admin_email,
                                               username='******',
                                               password=default_password)
        self.trans.set_user(self.admin_user)
        self.trans.set_history(None)

    def tearDown(self):
        self.log('.' * 20, 'end test', self, '\n')

    def log(self, *args, **kwargs):
        print(*args, **kwargs)

    # ---- additional test types
    def assertKeys(self, obj, key_list):
        self.assertEqual(sorted(obj.keys()), sorted(key_list))

    def assertHasKeys(self, obj, key_list):
        for key in key_list:
            if key not in obj:
                self.fail('Missing key: ' + key)
        else:
            self.assertTrue(True, 'keys found in object')
Example #6
0
class BaseTestCase( unittest.TestCase ):

    @classmethod
    def setUpClass( cls ):
        print( '\n', '-' * 20, 'begin class', cls )

    @classmethod
    def tearDownClass( cls ):
        print( '\n', '-' * 20, 'end class', cls )

    def __init__( self, *args ):
        unittest.TestCase.__init__( self, *args )

    def setUp( self ):
        self.log( '.' * 20, 'begin test', self )
        self.set_up_mocks()
        self.set_up_managers()
        self.set_up_trans()

    def set_up_mocks( self ):
        self.trans = mock.MockTrans( admin_users=admin_users )
        self.app = self.trans.app

    def set_up_managers( self ):
        self.user_mgr = UserManager( self.app )

    def set_up_trans( self ):
        self.admin_user = self.user_mgr.create( self.trans,
            email=admin_email, username='******', password=default_password )
        self.trans.set_user( self.admin_user )
        self.trans.set_history( None )

    def tearDown( self ):
        self.log( '.' * 20, 'end test', self, '\n' )

    def log( self, *args, **kwargs ):
        print( *args, **kwargs )

    # ---- additional test types
    def assertKeys( self, obj, key_list ):
        self.assertEqual( sorted( obj.keys() ), sorted( key_list ) )

    def assertHasKeys( self, obj, key_list ):
        for key in key_list:
            if key not in obj:
                self.fail( 'Missing key: ' + key )
        else:
            self.assertTrue( True, 'keys found in object' )
Example #7
0
    def __init__(self, config=None, **kwargs):
        super().__init__()
        self[BasicApp] = self
        self[MinimalManagerApp] = self
        self[StructuredApp] = self
        self.config = config or MockAppConfig(**kwargs)
        self.security = self.config.security
        self[idencoding.IdEncodingHelper] = self.security
        self.name = kwargs.get('name', 'galaxy')
        self.object_store = objectstore.build_object_store_from_config(
            self.config)
        self.model = mapping.init("/tmp",
                                  self.config.database_connection,
                                  create_tables=True,
                                  object_store=self.object_store)
        self[SharedModelMapping] = self.model
        self[GalaxyModelMapping] = self.model
        self[scoped_session] = self.model.context
        self.security_agent = self.model.security_agent
        self.visualizations_registry = MockVisualizationsRegistry()
        self.tag_handler = tags.GalaxyTagHandler(self.model.context)
        self[tags.GalaxyTagHandler] = self.tag_handler
        self.quota_agent = quota.DatabaseQuotaAgent(self.model)
        self.init_datatypes()
        self.job_config = Bunch(dynamic_params=None,
                                destinations={},
                                use_messaging=False,
                                assign_handler=lambda *args, **kwargs: None)
        self.tool_data_tables = {}
        self.dataset_collections_service = None
        self.container_finder = NullContainerFinder()
        self._toolbox_lock = MockLock()
        self.tool_shed_registry = Bunch(tool_sheds={})
        self.genome_builds = GenomeBuilds(self)
        self.job_manager = NoopManager()
        self.application_stack = ApplicationStack()
        self.auth_manager = AuthManager(self.config)
        self.user_manager = UserManager(self)
        self.execution_timer_factory = Bunch(
            get_timer=StructuredExecutionTimer)
        self.is_job_handler = False
        rebind_container_to_task(self)

        def url_for(*args, **kwds):
            return "/mock/url"

        self.url_for = url_for
Example #8
0
    def __init__(self, config=None, **kwargs):
        super().__init__()
        config = config or MockAppConfig(**kwargs)
        GalaxyDataTestApp.__init__(self, config=config, **kwargs)
        self[BasicSharedApp] = self
        self[MinimalManagerApp] = self
        self[StructuredApp] = self
        self[idencoding.IdEncodingHelper] = self.security
        self.name = kwargs.get('name', 'galaxy')
        self[SharedModelMapping] = self.model
        self[GalaxyModelMapping] = self.model
        self[galaxy_scoped_session] = self.model.context
        self.visualizations_registry = MockVisualizationsRegistry()
        self.tag_handler = tags.GalaxyTagHandler(self.model.context)
        self[tags.GalaxyTagHandler] = self.tag_handler
        self.quota_agent = quota.DatabaseQuotaAgent(self.model)
        self.job_config = Bunch(
            dynamic_params=None,
            destinations={},
            use_messaging=False,
            assign_handler=lambda *args, **kwargs: None
        )
        self.tool_data_tables = ToolDataTableManager(tool_data_path=self.config.tool_data_path)
        self.dataset_collections_service = None
        self.container_finder = NullContainerFinder()
        self._toolbox_lock = MockLock()
        self.tool_shed_registry = Bunch(tool_sheds={})
        self.genome_builds = GenomeBuilds(self)
        self.job_manager = NoopManager()
        self.application_stack = ApplicationStack()
        self.auth_manager = AuthManager(self.config)
        self.user_manager = UserManager(self)
        self.execution_timer_factory = Bunch(get_timer=StructuredExecutionTimer)
        self.file_sources = Bunch(to_dict=lambda *args, **kwargs: {})
        self.interactivetool_manager = Bunch(create_interactivetool=lambda *args, **kwargs: None)
        self.is_job_handler = False
        self.biotools_metadata_source = None
        rebind_container_to_task(self)

        def url_for(*args, **kwds):
            return "/mock/url"
        self.url_for = url_for
class BaseTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print('\n', '-' * 20, 'begin class', cls)

    @classmethod
    def tearDownClass(cls):
        print('\n', '-' * 20, 'end class', cls)

    def __init__(self, *args):
        unittest.TestCase.__init__(self, *args)

    def setUp(self):
        self.log('.' * 20, 'begin test', self)
        self.set_up_mocks()
        self.set_up_managers()
        self.set_up_trans()

    def set_up_mocks(self):
        self.trans = mock.MockTrans(admin_users=admin_users)
        self.app = self.trans.app

    def set_up_managers(self):
        self.user_mgr = UserManager(self.app)

    def set_up_trans(self):
        self.admin_user = self.user_mgr.create(self.trans,
                                               email=admin_email,
                                               username='******',
                                               password=default_password)
        self.trans.set_user(self.admin_user)
        self.trans.set_history(None)

    def tearDown(self):
        self.log('.' * 20, 'end test', self, '\n')

    def log(self, *args, **kwargs):
        print(*args, **kwargs)
Example #10
0
 def set_up_managers( self ):
     self.user_manager = UserManager( self.app )
Example #11
0
class BaseTestCase( test_utils.unittest.TestCase ):

    @classmethod
    def setUpClass( cls ):
        print( '\n', '-' * 20, 'begin class', cls )

    @classmethod
    def tearDownClass( cls ):
        print( '\n', '-' * 20, 'end class', cls )

    def __init__( self, *args ):
        test_utils.unittest.TestCase.__init__( self, *args )

    def setUp( self ):
        self.log( '.' * 20, 'begin test', self )
        self.set_up_mocks()
        self.set_up_managers()
        self.set_up_trans()

    def set_up_mocks( self ):
        self.trans = galaxy_mock.MockTrans( admin_users=admin_users )
        self.app = self.trans.app

    def set_up_managers( self ):
        self.user_manager = UserManager( self.app )

    def set_up_trans( self ):
        self.admin_user = self.user_manager.create( email=admin_email, username='******', password=default_password )
        self.trans.set_user( self.admin_user )
        self.trans.set_history( None )

    def tearDown( self ):
        self.log( '.' * 20, 'end test', self, '\n' )

    def log( self, *args, **kwargs ):
        print( *args, **kwargs )

    # ---- additional test types
    TYPES_NEEDING_NO_SERIALIZERS = ( basestring, bool, type( None ), int, float )

    def assertKeys( self, obj, key_list ):
        self.assertEqual( sorted( obj.keys() ), sorted( key_list ) )

    def assertHasKeys( self, obj, key_list ):
        for key in key_list:
            if key not in obj:
                self.fail( 'Missing key: ' + key )
        else:
            self.assertTrue( True, 'keys found in object' )

    def assertNullableBasestring( self, item ):
        if not isinstance( item, ( basestring, type( None ) ) ):
            self.fail( 'Non-nullable basestring: ' + str( type( item ) ) )
        # TODO: len mod 8 and hex re
        self.assertTrue( True, 'is nullable basestring: ' + str( item ) )

    def assertEncodedId( self, item ):
        if not isinstance( item, basestring ):
            self.fail( 'Non-string: ' + str( type( item ) ) )
        # TODO: len mod 8 and hex re
        self.assertTrue( True, 'is id: ' + item )

    def assertNullableEncodedId( self, item ):
        if item is None:
            self.assertTrue( True, 'nullable id is None' )
        else:
            self.assertEncodedId( item )

    def assertDate( self, item ):
        if not isinstance( item, basestring ):
            self.fail( 'Non-string: ' + str( type( item ) ) )
        # TODO: no great way to parse this fully (w/o python-dateutil)
        # TODO: re?
        self.assertTrue( True, 'is date: ' + item )

    def assertUUID( self, item ):
        if not isinstance( item, basestring ):
            self.fail( 'Non-string: ' + str( type( item ) ) )
        # TODO: re for d4d76d69-80d4-4ed7-80c7-211ebcc1a358
        self.assertTrue( True, 'is uuid: ' + item )

    def assertORMFilter( self, item, msg=None ):
        if not isinstance( item, sqlalchemy.sql.elements.BinaryExpression ):
            self.fail( 'Not an orm filter: ' + str( type( item ) ) )
        self.assertTrue( True, msg or ( 'is an orm filter: ' + str( item ) ) )

    def assertFnFilter( self, item, msg=None ):
        if not item or not callable( item ):
            self.fail( 'Not a fn filter: ' + str( type( item ) ) )
        self.assertTrue( True, msg or ( 'is a fn filter: ' + str( item ) ) )

    def assertIsJsonifyable( self, item ):
        # TODO: use galaxy's override
        self.assertIsInstance( json.dumps( item ), basestring )
Example #12
0
def get_api_user(user_manager: UserManager = Depends(get_user_manager), key: Optional[str] = Query(None), x_api_key: Optional[str] = Header(None)) -> Optional[User]:
    api_key = key or x_api_key
    if not api_key:
        return None
    return user_manager.by_api_key(api_key=api_key)
Example #13
0
 def set_up_managers(self):
     self.user_manager = UserManager(self.app)
Example #14
0
    def update_tours(this):
        from galaxy.managers.users import UserManager

        if UserManager(this.trans.app).is_admin(this.user):
            this.trans.app.tour_registry.load_tours()
Example #15
0
    def get_user(this):
        from galaxy.managers.users import UserManager

        return {
            'isadmin': UserManager(this.trans.app).is_admin(this.user)
        }
Example #16
0
class GalaxyWebTransaction(base.DefaultWebTransaction,
                           context.ProvidesAppContext, context.ProvidesUserContext, context.ProvidesHistoryContext):
    """
    Encapsulates web transaction specific state for the Galaxy application
    (specifically the user's "cookie" session and history)
    """

    def __init__(self, environ, app, webapp, session_cookie=None):
        self.app = app
        self.webapp = webapp
        self.security = webapp.security
        self.user_manager = UserManager(app)
        self.session_manager = GalaxySessionManager(app.model)
        base.DefaultWebTransaction.__init__(self, environ)
        self.setup_i18n()
        self.expunge_all()
        config = self.app.config
        self.debug = asbool(config.get('debug', False))
        x_frame_options = getattr(config, 'x_frame_options', None)
        if x_frame_options:
            self.response.headers['X-Frame-Options'] = x_frame_options
        # Flag indicating whether we are in workflow building mode (means
        # that the current history should not be used for parameter values
        # and such).
        self.workflow_building_mode = False
        self.__user = None
        self.galaxy_session = None
        self.error_message = None

        # set any cross origin resource sharing headers if configured to do so
        self.set_cors_headers()

        if self.environ.get('is_api_request', False):
            # With API requests, if there's a key, use it and associate the
            # user with the transaction.
            # If not, check for an active session but do not create one.
            # If an error message is set here, it's sent back using
            # trans.show_error in the response -- in expose_api.
            self.error_message = self._authenticate_api(session_cookie)
        elif self.app.name == "reports":
            self.galaxy_session = None
        else:
            # This is a web request, get or create session.
            self._ensure_valid_session(session_cookie)
        if self.galaxy_session:
            # When we've authenticated by session, we have to check the
            # following.
            # Prevent deleted users from accessing Galaxy
            if config.use_remote_user and self.galaxy_session.user.deleted:
                self.response.send_redirect(url_for('/static/user_disabled.html'))
            if config.require_login:
                self._ensure_logged_in_user(environ, session_cookie)
            if config.session_duration:
                # TODO DBTODO All ajax calls from the client need to go through
                # a single point of control where we can do things like
                # redirect/etc.  This is API calls as well as something like 40
                # @web.json requests that might not get handled well on the
                # clientside.
                #
                # Make sure we're not past the duration, and either log out or
                # update timestamp.
                now = datetime.datetime.now()
                if self.galaxy_session.last_action:
                    expiration_time = self.galaxy_session.last_action + datetime.timedelta(minutes=config.session_duration)
                else:
                    expiration_time = now
                    self.galaxy_session.last_action = now - datetime.timedelta(seconds=1)
                    self.sa_session.add(self.galaxy_session)
                    self.sa_session.flush()
                if expiration_time < now:
                    # Expiration time has passed.
                    self.handle_user_logout()
                    if self.environ.get('is_api_request', False):
                        self.response.status = 401
                        self.user = None
                        self.galaxy_session = None
                    else:
                        self.response.send_redirect(url_for(controller='root',
                                                     action='login',
                                                     message="You have been logged out due to inactivity.  Please log in again to continue using Galaxy.",
                                                     status='info',
                                                     use_panels=True))
                else:
                    self.galaxy_session.last_action = now
                    self.sa_session.add(self.galaxy_session)
                    self.sa_session.flush()

    def setup_i18n(self):
        locales = []
        if 'HTTP_ACCEPT_LANGUAGE' in self.environ:
            # locales looks something like: ['en', 'en-us;q=0.7', 'ja;q=0.3']
            client_locales = self.environ['HTTP_ACCEPT_LANGUAGE'].split(',')
            for locale in client_locales:
                try:
                    locales.append(Locale.parse(locale.split(';')[0].strip(), sep='-').language)
                except Exception as e:
                    log.debug("Error parsing locale '%s'. %s: %s", locale, type(e), e)
        if not locales:
            # Default to English
            locales = 'en'
        t = Translations.load(dirname='locale', locales=locales, domain='ginga')
        self.template_context.update(dict(_=t.ugettext, n_=t.ugettext, N_=t.ungettext))

    def set_cors_allow(self, name=None, value=None):
        acr = 'Access-Control-Request-'
        if name is None:
            for key in self.request.headers.keys():
                if key.startswith(acr):
                    self.set_cors_allow(name=key[len(acr):], value=value)
        else:
            resp_name = f'Access-Control-Allow-{name}'
            if value is None:
                value = self.request.headers.get(acr + name, None)
            if value:
                self.response.headers[resp_name] = value
            elif resp_name in self.response.headers:
                del self.response.headers[resp_name]

    def set_cors_origin(self, origin=None):
        if origin is None:
            origin = self.request.headers.get("Origin", None)
        if origin:
            self.response.headers['Access-Control-Allow-Origin'] = origin
        elif 'Access-Control-Allow-Origin' in self.response.headers:
            del self.response.headers['Access-Control-Allow-Origin']

    def set_cors_headers(self):
        """Allow CORS requests if configured to do so by echoing back the
        request's 'Origin' header (if any) as the response header
        'Access-Control-Allow-Origin'

        Preflight OPTIONS requests to the API work by routing all OPTIONS
        requests to a single method in the authenticate API (options method),
        setting CORS headers, and responding OK.

        NOTE: raising some errors (such as httpexceptions), will remove the
        header (e.g. client will get both CORS error and 404 inside that)
        """

        # do not set any access control headers if not configured for it (common case)
        if not self.app.config.get('allowed_origin_hostnames', None):
            return
        # do not set any access control headers if there's no origin header on the request
        origin_header = self.request.headers.get("Origin", None)
        if not origin_header:
            return

        # singular match
        def matches_allowed_origin(origin, allowed_origin):
            if isinstance(allowed_origin, str):
                return origin == allowed_origin
            match = allowed_origin.match(origin)
            return match and match.group() == origin

        # check for '*' or compare to list of allowed
        def is_allowed_origin(origin):
            # localhost uses no origin header (== null)
            if not origin:
                return False
            for allowed_origin in self.app.config.allowed_origin_hostnames:
                if allowed_origin == '*' or matches_allowed_origin(origin, allowed_origin):
                    return True
            return False

        # boil origin header down to hostname
        origin = urlparse(origin_header).hostname
        # check against the list of allowed strings/regexp hostnames, echo original if cleared
        if is_allowed_origin(origin):
            self.set_cors_origin(origin=origin_header)

    def get_user(self):
        """Return the current user if logged in or None."""
        user = self.__user
        if not user and self.galaxy_session:
            user = self.galaxy_session.user
            self.__user = user
        return user

    def set_user(self, user):
        """Set the current user."""
        if self.galaxy_session:
            if user.bootstrap_admin_user:
                self.galaxy_session.user = user
                self.sa_session.add(self.galaxy_session)
                self.sa_session.flush()
        self.__user = user

    user = property(get_user, set_user)

    def get_cookie(self, name='galaxysession'):
        """Convenience method for getting a session cookie"""
        try:
            # If we've changed the cookie during the request return the new value
            if name in self.response.cookies:
                return self.response.cookies[name].value
            else:
                return self.request.cookies[name].value
        except Exception:
            return None

    def set_cookie(self, value, name='galaxysession', path='/', age=90, version='1'):
        """Convenience method for setting a session cookie"""
        # The galaxysession cookie value must be a high entropy 128 bit random number encrypted
        # using a server secret key.  Any other value is invalid and could pose security issues.
        self.response.cookies[name] = unicodify(value)
        self.response.cookies[name]['path'] = path
        self.response.cookies[name]['max-age'] = 3600 * 24 * age  # 90 days
        tstamp = time.localtime(time.time() + 3600 * 24 * age)
        self.response.cookies[name]['expires'] = time.strftime('%a, %d-%b-%Y %H:%M:%S GMT', tstamp)
        self.response.cookies[name]['version'] = version
        https = self.request.environ["wsgi.url_scheme"] == "https"
        if https:
            self.response.cookies[name]['secure'] = True
        try:
            self.response.cookies[name]['httponly'] = True
        except CookieError as e:
            log.warning(f"Error setting httponly attribute in cookie '{name}': {e}")
        if self.app.config.cookie_domain is not None:
            self.response.cookies[name]['domain'] = self.app.config.cookie_domain

    def _authenticate_api(self, session_cookie):
        """
        Authenticate for the API via key or session (if available).
        """
        api_key = self.request.params.get('key', None) or self.request.headers.get('x-api-key', None)
        secure_id = self.get_cookie(name=session_cookie)
        api_key_supplied = self.environ.get('is_api_request', False) and api_key
        if api_key_supplied:
            # Sessionless API transaction, we just need to associate a user.
            try:
                user = self.user_manager.by_api_key(api_key)
            except AuthenticationFailed as e:
                return str(e)
            self.set_user(user)
        elif secure_id:
            # API authentication via active session
            # Associate user using existing session
            # This will throw an exception under remote auth with anon users.
            try:
                self._ensure_valid_session(session_cookie)
            except Exception:
                log.exception("Exception during Session-based API authentication, this was most likely an attempt to use an anonymous cookie under remote authentication (so, no user), which we don't support.")
                self.user = None
                self.galaxy_session = None
        else:
            # Anonymous API interaction -- anything but @expose_api_anonymous will fail past here.
            self.user = None
            self.galaxy_session = None

    def _ensure_valid_session(self, session_cookie, create=True):
        """
        Ensure that a valid Galaxy session exists and is available as
        trans.session (part of initialization)

        Support for universe_session and universe_user cookies has been
        removed as of 31 Oct 2008.
        """
        # Try to load an existing session
        secure_id = self.get_cookie(name=session_cookie)
        galaxy_session = None
        prev_galaxy_session = None
        user_for_new_session = None
        invalidate_existing_session = False
        # Track whether the session has changed so we can avoid calling flush
        # in the most common case (session exists and is valid).
        galaxy_session_requires_flush = False
        if secure_id:
            # Decode the cookie value to get the session_key
            try:
                session_key = self.security.decode_guid(secure_id)
                if session_key:
                    galaxy_session = self.session_manager.get_session_from_session_key(session_key=session_key)
            except Exception:
                # We'll end up creating a new galaxy_session
                session_key = None
        # If remote user is in use it can invalidate the session and in some
        # cases won't have a cookie set above, so we need to to check some
        # things now.
        if self.app.config.use_remote_user:
            remote_user_email = self.environ.get(self.app.config.remote_user_header, None)
            if galaxy_session:
                if remote_user_email and galaxy_session.user is None:
                    # No user, associate
                    galaxy_session.user = self.get_or_create_remote_user(remote_user_email)
                    galaxy_session_requires_flush = True
                elif (remote_user_email and
                      (galaxy_session.user.email != remote_user_email) and
                      ((not self.app.config.allow_user_impersonation) or
                       (remote_user_email not in self.app.config.admin_users_list))):
                    # Session exists but is not associated with the correct
                    # remote user, and the currently set remote_user is not a
                    # potentially impersonating admin.
                    invalidate_existing_session = True
                    user_for_new_session = self.get_or_create_remote_user(remote_user_email)
                    log.warning("User logged in as '%s' externally, but has a cookie as '%s' invalidating session",
                                remote_user_email, galaxy_session.user.email)
            elif remote_user_email:
                # No session exists, get/create user for new session
                user_for_new_session = self.get_or_create_remote_user(remote_user_email)
            if ((galaxy_session and galaxy_session.user is None) and user_for_new_session is None):
                raise Exception("Remote Authentication Failure - user is unknown and/or not supplied.")
        else:
            if galaxy_session is not None and galaxy_session.user and galaxy_session.user.external:
                # Remote user support is not enabled, but there is an existing
                # session with an external user, invalidate
                invalidate_existing_session = True
                log.warning("User '%s' is an external user with an existing session, invalidating session since external auth is disabled",
                            galaxy_session.user.email)
            elif galaxy_session is not None and galaxy_session.user is not None and galaxy_session.user.deleted:
                invalidate_existing_session = True
                log.warning("User '%s' is marked deleted, invalidating session" % galaxy_session.user.email)
        # Do we need to invalidate the session for some reason?
        if invalidate_existing_session:
            prev_galaxy_session = galaxy_session
            prev_galaxy_session.is_valid = False
            galaxy_session = None
        # No relevant cookies, or couldn't find, or invalid, so create a new session
        if galaxy_session is None:
            galaxy_session = self.__create_new_session(prev_galaxy_session, user_for_new_session)
            galaxy_session_requires_flush = True
            self.galaxy_session = galaxy_session
            self.__update_session_cookie(name=session_cookie)
        else:
            self.galaxy_session = galaxy_session
        # Do we need to flush the session?
        if galaxy_session_requires_flush:
            self.sa_session.add(galaxy_session)
            # FIXME: If prev_session is a proper relation this would not
            #        be needed.
            if prev_galaxy_session:
                self.sa_session.add(prev_galaxy_session)
            self.sa_session.flush()
        # If the old session was invalid, get a new (or existing default,
        # unused) history with our new session
        if invalidate_existing_session:
            self.get_or_create_default_history()

    def _ensure_logged_in_user(self, environ, session_cookie):
        # The value of session_cookie can be one of
        # 'galaxysession' or 'galaxycommunitysession'
        # Currently this method does nothing unless session_cookie is 'galaxysession'
        if session_cookie == 'galaxysession' and self.galaxy_session.user is None:
            # TODO: re-engineer to eliminate the use of allowed_paths
            # as maintenance overhead is far too high.
            allowed_paths = [
                # client app route
                # TODO: might be better as '/:username/login', '/:username/logout'
                url_for(controller='root', action='login'),
                # mako app routes
                url_for(controller='user', action='login'),
                url_for(controller='user', action='logout'),
                url_for(controller='user', action='reset_password'),
                url_for(controller='user', action='change_password'),
                # TODO: do any of these still need to bypass require login?
                url_for(controller='user', action='api_keys'),
                url_for(controller='user', action='create'),
                url_for(controller='user', action='index'),
                url_for(controller='user', action='manage_user_info'),
                url_for(controller='user', action='set_default_permissions'),
            ]
            # append the welcome url to allowed paths if we'll show it at the login screen
            if self.app.config.show_welcome_with_login:
                allowed_paths.append(url_for(controller='root', action='welcome'))

            # prevent redirect when UCSC server attempts to get dataset contents as 'anon' user
            display_as = url_for(controller='root', action='display_as')
            if self.app.datatypes_registry.get_display_sites('ucsc') and self.request.path == display_as:
                try:
                    host = socket.gethostbyaddr(self.environ['REMOTE_ADDR'])[0]
                except(OSError, socket.herror, socket.gaierror, socket.timeout):
                    host = None
                if host in UCSC_SERVERS:
                    return
            # prevent redirect for external, enabled display applications getting dataset contents
            external_display_path = url_for(controller='', action='display_application')
            if self.request.path.startswith(external_display_path):
                request_path_split = self.request.path.split('/')
                try:
                    if (self.app.datatypes_registry.display_applications.get(request_path_split[-5]) and
                            request_path_split[-4] in self.app.datatypes_registry.display_applications.get(request_path_split[-5]).links and
                            request_path_split[-3] != 'None'):
                        return
                except IndexError:
                    pass
            authnz_controller_base = url_for(controller='authnz', action='index')
            if self.request.path.startswith(authnz_controller_base):
                #  All authnz requests pass through
                return
            # redirect to root if the path is not in the list above
            if self.request.path not in allowed_paths:
                login_url = url_for(controller='root', action='login', redirect=self.request.path)
                self.response.send_redirect(login_url)

    def __create_new_session(self, prev_galaxy_session=None, user_for_new_session=None):
        """
        Create a new GalaxySession for this request, possibly with a connection
        to a previous session (in `prev_galaxy_session`) and an existing user
        (in `user_for_new_session`).

        Caller is responsible for flushing the returned session.
        """
        session_key = self.security.get_new_guid()
        galaxy_session = self.app.model.GalaxySession(
            session_key=session_key,
            is_valid=True,
            remote_host=self.request.remote_host,
            remote_addr=self.request.remote_addr,
            referer=self.request.headers.get('Referer', None))
        if prev_galaxy_session:
            # Invalidated an existing session for some reason, keep track
            galaxy_session.prev_session_id = prev_galaxy_session.id
        if user_for_new_session:
            # The new session should be associated with the user
            galaxy_session.user = user_for_new_session
        return galaxy_session

    def get_or_create_remote_user(self, remote_user_email):
        """
        Create a remote user with the email remote_user_email and return it
        """
        if not self.app.config.use_remote_user:
            return None
        if getattr(self.app.config, "normalize_remote_user_email", False):
            remote_user_email = remote_user_email.lower()
        user = self.sa_session.query(self.app.model.User).filter(self.app.model.User.table.c.email == remote_user_email).first()
        if user:
            # GVK: June 29, 2009 - This is to correct the behavior of a previous bug where a private
            # role and default user / history permissions were not set for remote users.  When a
            # remote user authenticates, we'll look for this information, and if missing, create it.
            if not self.app.security_agent.get_private_user_role(user):
                self.app.security_agent.create_private_user_role(user)
            if 'webapp' not in self.environ or self.environ['webapp'] != 'tool_shed':
                if not user.default_permissions:
                    self.app.security_agent.user_set_default_permissions(user)
                    self.app.security_agent.user_set_default_permissions(user, history=True, dataset=True)
        elif user is None:
            username = remote_user_email.split('@', 1)[0].lower()
            random.seed()
            user = self.app.model.User(email=remote_user_email)
            user.set_random_password(length=12)
            user.external = True
            # Replace invalid characters in the username
            for char in [x for x in username if x not in string.ascii_lowercase + string.digits + '-' + '.']:
                username = username.replace(char, '-')
            # Find a unique username - user can change it later
            if self.sa_session.query(self.app.model.User).filter_by(username=username).first():
                i = 1
                while self.sa_session.query(self.app.model.User).filter_by(username=(username + '-' + str(i))).first():
                    i += 1
                username += '-' + str(i)
            user.username = username
            self.sa_session.add(user)
            self.sa_session.flush()
            self.app.security_agent.create_private_user_role(user)
            # We set default user permissions, before we log in and set the default history permissions
            if 'webapp' not in self.environ or self.environ['webapp'] != 'tool_shed':
                self.app.security_agent.user_set_default_permissions(user)
            # self.log_event( "Automatically created account '%s'", user.email )
        return user

    @property
    def cookie_path(self):
        return self.app.config.cookie_path or url_for('/')

    def __update_session_cookie(self, name='galaxysession'):
        """
        Update the session cookie to match the current session.
        """
        self.set_cookie(self.security.encode_guid(self.galaxy_session.session_key),
                        name=name, path=self.cookie_path)

    def check_user_library_import_dir(self, user):
        if getattr(self.app.config, "user_library_import_dir_auto_creation", False):
            # try to create a user library import directory
            try:
                safe_makedirs(os.path.join(self.app.config.user_library_import_dir, user.email))
            except ConfigurationError as e:
                self.log_event(unicodify(e))

    def user_checks(self, user):
        """
        This could contain more checks around a user upon login
        """
        self.check_user_library_import_dir(user)

    def _associate_user_history(self, user, prev_galaxy_session=None):
        """
        Associate the user's last accessed history (if exists) with their new session
        """
        history = None
        set_permissions = False
        try:
            users_last_session = user.galaxy_sessions[0]
        except Exception:
            users_last_session = None
        if (prev_galaxy_session and
                prev_galaxy_session.current_history and not
                prev_galaxy_session.current_history.deleted and
                prev_galaxy_session.current_history.datasets and
                (prev_galaxy_session.current_history.user is None or
                 prev_galaxy_session.current_history.user == user)):
            # If the previous galaxy session had a history, associate it with the new session, but only if it didn't
            # belong to a different user.
            history = prev_galaxy_session.current_history
            if prev_galaxy_session.user is None:
                # Increase the user's disk usage by the amount of the previous history's datasets if they didn't already
                # own it.
                for hda in history.datasets:
                    user.adjust_total_disk_usage(hda.quota_amount(user))
                # Only set default history permissions if the history is from the previous session and anonymous
                set_permissions = True
        elif self.galaxy_session.current_history:
            history = self.galaxy_session.current_history
        if (not history and users_last_session and
                users_last_session.current_history and not
                users_last_session.current_history.deleted):
            history = users_last_session.current_history
        elif not history:
            history = self.get_history(create=True, most_recent=True)
        if history not in self.galaxy_session.histories:
            self.galaxy_session.add_history(history)
        if history.user is None:
            history.user = user
        self.galaxy_session.current_history = history
        if set_permissions:
            self.app.security_agent.history_set_default_permissions(history, dataset=True, bypass_manage_permission=True)
        self.sa_session.add_all((prev_galaxy_session, self.galaxy_session, history))

    def handle_user_login(self, user):
        """
        Login a new user (possibly newly created)
           - do some 'system' checks (if any) for this user
           - create a new session
           - associate new session with user
           - if old session had a history and it was not associated with a user, associate it with the new session,
             otherwise associate the current session's history with the user
           - add the disk usage of the current session to the user's total disk usage
        """
        self.user_checks(user)
        self.app.security_agent.create_user_role(user, self.app)
        # Set the previous session
        prev_galaxy_session = self.galaxy_session
        prev_galaxy_session.is_valid = False
        # Define a new current_session
        self.galaxy_session = self.__create_new_session(prev_galaxy_session, user)
        if self.webapp.name == 'galaxy':
            cookie_name = 'galaxysession'
            self._associate_user_history(user, prev_galaxy_session)
        else:
            cookie_name = 'galaxycommunitysession'
            self.sa_session.add_all((prev_galaxy_session, self.galaxy_session))
        self.sa_session.flush()
        # This method is not called from the Galaxy reports, so the cookie will always be galaxysession
        self.__update_session_cookie(name=cookie_name)

    def handle_user_logout(self, logout_all=False):
        """
        Logout the current user:
           - invalidate the current session
           - create a new session with no user associated
        """
        prev_galaxy_session = self.galaxy_session
        prev_galaxy_session.is_valid = False
        self.galaxy_session = self.__create_new_session(prev_galaxy_session)
        self.sa_session.add_all((prev_galaxy_session, self.galaxy_session))
        galaxy_user_id = prev_galaxy_session.user_id
        if logout_all and galaxy_user_id is not None:
            for other_galaxy_session in (self.sa_session.query(self.app.model.GalaxySession)
                                         .filter(and_(self.app.model.GalaxySession.table.c.user_id == galaxy_user_id,
                                                      self.app.model.GalaxySession.table.c.is_valid == true(),
                                                      self.app.model.GalaxySession.table.c.id != prev_galaxy_session.id))):
                other_galaxy_session.is_valid = False
                self.sa_session.add(other_galaxy_session)
        self.sa_session.flush()
        if self.webapp.name == 'galaxy':
            # This method is not called from the Galaxy reports, so the cookie will always be galaxysession
            self.__update_session_cookie(name='galaxysession')
        elif self.webapp.name == 'tool_shed':
            self.__update_session_cookie(name='galaxycommunitysession')

    def get_galaxy_session(self):
        """
        Return the current galaxy session
        """
        return self.galaxy_session

    def get_history(self, create=False, most_recent=False):
        """
        Load the current history.

            - If that isn't available, we find the most recently updated history.
            - If *that* isn't available, we get or create the default history.

        Transactions will not always have an active history (API requests), so
        None is a valid response.
        """
        history = None
        if self.galaxy_session:
            if hasattr(self.galaxy_session, 'current_history'):
                history = self.galaxy_session.current_history
        if not history and most_recent:
            history = self.get_most_recent_history()
        if not history and util.string_as_bool(create):
            history = self.get_or_create_default_history()
        return history

    def set_history(self, history):
        if history and not history.deleted:
            self.galaxy_session.current_history = history
        self.sa_session.add(self.galaxy_session)
        self.sa_session.flush()

    history = property(get_history, set_history)

    def get_or_create_default_history(self):
        """
        Gets or creates a default history and associates it with the current
        session.
        """

        # There must be a user to fetch a default history.
        if not self.galaxy_session.user:
            return self.new_history()

        # Look for default history that (a) has default name + is not deleted and
        # (b) has no datasets. If suitable history found, use it; otherwise, create
        # new history.
        unnamed_histories = self.sa_session.query(self.app.model.History).filter_by(
            user=self.galaxy_session.user,
            name=self.app.model.History.default_name,
            deleted=False)
        default_history = None
        for history in unnamed_histories:
            if len(history.datasets) == 0:
                # Found suitable default history.
                default_history = history
                break

        # Set or create history.
        if default_history:
            history = default_history
            self.set_history(history)
        else:
            history = self.new_history()

        return history

    def get_most_recent_history(self):
        """
        Gets the most recently updated history.
        """
        # There must be a user to fetch histories, and without a user we have
        # no recent history.
        if not self.galaxy_session.user:
            return None
        try:
            recent_history = self.sa_session.query(self.app.model.History).filter_by(
                user=self.galaxy_session.user,
                deleted=False).order_by(self.app.model.History.update_time.desc()).first()
        except NoResultFound:
            return None
        self.set_history(recent_history)
        return recent_history

    def new_history(self, name=None):
        """
        Create a new history and associate it with the current session and
        its associated user (if set).
        """
        # Create new history
        history = self.app.model.History()
        if name:
            history.name = name
        # Associate with session
        history.add_galaxy_session(self.galaxy_session)
        # Make it the session's current history
        self.galaxy_session.current_history = history
        # Associate with user
        if self.galaxy_session.user:
            history.user = self.galaxy_session.user
        # Track genome_build with history
        history.genome_build = self.app.genome_builds.default_value
        # Set the user's default history permissions
        self.app.security_agent.history_set_default_permissions(history)
        # Save
        self.sa_session.add_all((self.galaxy_session, history))
        self.sa_session.flush()
        return history

    @base.lazy_property
    def template_context(self):
        return dict()

    def set_message(self, message, type=None):
        """
        Convenience method for setting the 'message' and 'message_type'
        element of the template context.
        """
        self.template_context['message'] = message
        if type:
            self.template_context['status'] = type

    def get_message(self):
        """
        Convenience method for getting the 'message' element of the template
        context.
        """
        return self.template_context['message']

    def show_message(self, message, type='info', refresh_frames=None, cont=None, use_panels=False, active_view=""):
        """
        Convenience method for displaying a simple page with a single message.

        `type`: one of "error", "warning", "info", or "done"; determines the
                type of dialog box and icon displayed with the message

        `refresh_frames`: names of frames in the interface that should be
                          refreshed when the message is displayed
        """
        refresh_frames = refresh_frames or []
        return self.fill_template("message.mako", status=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels, active_view=active_view)

    def show_error_message(self, message, refresh_frames=None, use_panels=False, active_view=""):
        """
        Convenience method for displaying an error message. See `show_message`.
        """
        refresh_frames = refresh_frames or []
        return self.show_message(message, 'error', refresh_frames, use_panels=use_panels, active_view=active_view)

    def show_ok_message(self, message, refresh_frames=None, use_panels=False, active_view=""):
        """
        Convenience method for displaying an ok message. See `show_message`.
        """
        refresh_frames = refresh_frames or []
        return self.show_message(message, 'done', refresh_frames, use_panels=use_panels, active_view=active_view)

    def show_warn_message(self, message, refresh_frames=None, use_panels=False, active_view=""):
        """
        Convenience method for displaying an warn message. See `show_message`.
        """
        refresh_frames = refresh_frames or []
        return self.show_message(message, 'warning', refresh_frames, use_panels=use_panels, active_view=active_view)

    @property
    def session_csrf_token(self):
        token = ''
        if self.galaxy_session:
            token = self.security.encode_id(
                self.galaxy_session.id, kind="csrf"
            )
        return token

    def check_csrf_token(self, payload):
        session_csrf_token = payload.get("session_csrf_token")
        if not session_csrf_token:
            return "No session token set, denying request."
        elif session_csrf_token != self.session_csrf_token:
            return "Wrong session token found, denying request."

    def fill_template(self, filename, **kwargs):
        """
        Fill in a template, putting any keyword arguments on the context.
        """
        # call get_user so we can invalidate sessions from external users,
        # if external auth has been disabled.
        self.get_user()
        if filename.endswith(".mako"):
            return self.fill_template_mako(filename, **kwargs)
        else:
            template = Template(file=os.path.join(self.app.config.template_path, filename),
                                searchList=[kwargs, self.template_context, dict(caller=self, t=self, h=helpers, util=util, request=self.request, response=self.response, app=self.app)])
            return str(template)

    def fill_template_mako(self, filename, template_lookup=None, **kwargs):
        template_lookup = template_lookup or self.webapp.mako_template_lookup
        template = template_lookup.get_template(filename)

        data = dict(caller=self, t=self, trans=self, h=helpers, util=util, request=self.request, response=self.response, app=self.app)
        data.update(self.template_context)
        data.update(kwargs)
        return template.render(**data)

    def stream_template_mako(self, filename, **kwargs):
        template = self.webapp.mako_template_lookup.get_template(filename)
        data = dict(caller=self, t=self, trans=self, h=helpers, util=util, request=self.request, response=self.response, app=self.app)
        data.update(self.template_context)
        data.update(kwargs)

        def render(environ, start_response):
            response_write = start_response(self.response.wsgi_status(), self.response.wsgi_headeritems())

            class StreamBuffer:
                def write(self, d):
                    response_write(d.encode('utf-8'))
            buffer = StreamBuffer()
            context = mako.runtime.Context(buffer, **data)
            template.render_context(context)
            return []
        return render

    def fill_template_string(self, template_string, context=None, **kwargs):
        """
        Fill in a template, putting any keyword arguments on the context.
        """
        template = Template(source=template_string,
                            searchList=[context or kwargs, dict(caller=self)])
        return str(template)
Example #17
0
class BaseTestCase(test_utils.unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print('\n', '-' * 20, 'begin class', cls)

    @classmethod
    def tearDownClass(cls):
        print('\n', '-' * 20, 'end class', cls)

    def __init__(self, *args):
        test_utils.unittest.TestCase.__init__(self, *args)

    def setUp(self):
        self.log('.' * 20, 'begin test', self)
        self.set_up_mocks()
        self.set_up_managers()
        self.set_up_trans()

    def set_up_mocks(self):
        self.trans = galaxy_mock.MockTrans(admin_users=admin_users)
        self.app = self.trans.app

    def set_up_managers(self):
        self.user_manager = UserManager(self.app)

    def set_up_trans(self):
        self.admin_user = self.user_manager.create(email=admin_email,
                                                   username='******',
                                                   password=default_password)
        self.trans.set_user(self.admin_user)
        self.trans.set_history(None)

    def tearDown(self):
        self.log('.' * 20, 'end test', self, '\n')

    def log(self, *args, **kwargs):
        print(*args, **kwargs)

    # ---- additional test types
    TYPES_NEEDING_NO_SERIALIZERS = (basestring, bool, type(None), int, float)

    def assertKeys(self, obj, key_list):
        self.assertEqual(sorted(obj.keys()), sorted(key_list))

    def assertHasKeys(self, obj, key_list):
        for key in key_list:
            if key not in obj:
                self.fail('Missing key: ' + key)
        else:
            self.assertTrue(True, 'keys found in object')

    def assertNullableBasestring(self, item):
        if not isinstance(item, (basestring, type(None))):
            self.fail('Non-nullable basestring: ' + str(type(item)))
        # TODO: len mod 8 and hex re
        self.assertTrue(True, 'is nullable basestring: ' + str(item))

    def assertEncodedId(self, item):
        if not isinstance(item, basestring):
            self.fail('Non-string: ' + str(type(item)))
        # TODO: len mod 8 and hex re
        self.assertTrue(True, 'is id: ' + item)

    def assertNullableEncodedId(self, item):
        if item is None:
            self.assertTrue(True, 'nullable id is None')
        else:
            self.assertEncodedId(item)

    def assertDate(self, item):
        if not isinstance(item, basestring):
            self.fail('Non-string: ' + str(type(item)))
        # TODO: no great way to parse this fully (w/o python-dateutil)
        # TODO: re?
        self.assertTrue(True, 'is date: ' + item)

    def assertUUID(self, item):
        if not isinstance(item, basestring):
            self.fail('Non-string: ' + str(type(item)))
        # TODO: re for d4d76d69-80d4-4ed7-80c7-211ebcc1a358
        self.assertTrue(True, 'is uuid: ' + item)

    def assertORMFilter(self, item, msg=None):
        if not isinstance(item, sqlalchemy.sql.elements.BinaryExpression):
            self.fail('Not an orm filter: ' + str(type(item)))
        self.assertTrue(True, msg or ('is an orm filter: ' + str(item)))

    def assertFnFilter(self, item, msg=None):
        if not item or not callable(item):
            self.fail('Not a fn filter: ' + str(type(item)))
        self.assertTrue(True, msg or ('is a fn filter: ' + str(item)))

    def assertIsJsonifyable(self, item):
        # TODO: use galaxy's override
        self.assertIsInstance(json.dumps(item), basestring)
Example #18
0
    def __init__(self, environ, app, webapp, session_cookie=None):
        self.app = app
        self.webapp = webapp
        self.security = webapp.security
        self.user_manager = UserManager(app)
        self.session_manager = GalaxySessionManager(app.model)
        base.DefaultWebTransaction.__init__(self, environ)
        self.setup_i18n()
        self.expunge_all()
        config = self.app.config
        self.debug = asbool(config.get('debug', False))
        x_frame_options = getattr(config, 'x_frame_options', None)
        if x_frame_options:
            self.response.headers['X-Frame-Options'] = x_frame_options
        # Flag indicating whether we are in workflow building mode (means
        # that the current history should not be used for parameter values
        # and such).
        self.workflow_building_mode = False
        self.__user = None
        self.galaxy_session = None
        self.error_message = None

        # set any cross origin resource sharing headers if configured to do so
        self.set_cors_headers()

        if self.environ.get('is_api_request', False):
            # With API requests, if there's a key, use it and associate the
            # user with the transaction.
            # If not, check for an active session but do not create one.
            # If an error message is set here, it's sent back using
            # trans.show_error in the response -- in expose_api.
            self.error_message = self._authenticate_api(session_cookie)
        elif self.app.name == "reports":
            self.galaxy_session = None
        else:
            # This is a web request, get or create session.
            self._ensure_valid_session(session_cookie)
        if self.galaxy_session:
            # When we've authenticated by session, we have to check the
            # following.
            # Prevent deleted users from accessing Galaxy
            if config.use_remote_user and self.galaxy_session.user.deleted:
                self.response.send_redirect(url_for('/static/user_disabled.html'))
            if config.require_login:
                self._ensure_logged_in_user(environ, session_cookie)
            if config.session_duration:
                # TODO DBTODO All ajax calls from the client need to go through
                # a single point of control where we can do things like
                # redirect/etc.  This is API calls as well as something like 40
                # @web.json requests that might not get handled well on the
                # clientside.
                #
                # Make sure we're not past the duration, and either log out or
                # update timestamp.
                now = datetime.datetime.now()
                if self.galaxy_session.last_action:
                    expiration_time = self.galaxy_session.last_action + datetime.timedelta(minutes=config.session_duration)
                else:
                    expiration_time = now
                    self.galaxy_session.last_action = now - datetime.timedelta(seconds=1)
                    self.sa_session.add(self.galaxy_session)
                    self.sa_session.flush()
                if expiration_time < now:
                    # Expiration time has passed.
                    self.handle_user_logout()
                    if self.environ.get('is_api_request', False):
                        self.response.status = 401
                        self.user = None
                        self.galaxy_session = None
                    else:
                        self.response.send_redirect(url_for(controller='root',
                                                     action='login',
                                                     message="You have been logged out due to inactivity.  Please log in again to continue using Galaxy.",
                                                     status='info',
                                                     use_panels=True))
                else:
                    self.galaxy_session.last_action = now
                    self.sa_session.add(self.galaxy_session)
                    self.sa_session.flush()
Example #19
0
    def __init__(self, **kwargs):
        if not log.handlers:
            # Paste didn't handle it, so we need a temporary basic log
            # configured.  The handler added here gets dumped and replaced with
            # an appropriately configured logger in configure_logging below.
            logging.basicConfig(level=logging.DEBUG)
        log.debug("python path is: %s", ", ".join(sys.path))
        self.name = 'galaxy'
        # is_webapp will be set to true when building WSGI app
        self.is_webapp = False
        self.startup_timer = ExecutionTimer()
        self.new_installation = False
        # Read config file and check for errors
        self.config = config.Configuration(**kwargs)
        self.config.check()
        config.configure_logging(self.config)
        self.execution_timer_factory = ExecutionTimerFactory(self.config)
        self.configure_fluent_log()
        # A lot of postfork initialization depends on the server name, ensure it is set immediately after forking before other postfork functions
        self.application_stack = application_stack_instance(app=self)
        self.application_stack.register_postfork_function(
            self.application_stack.set_postfork_server_name, self)
        self.config.reload_sanitize_whitelist(
            explicit='sanitize_whitelist_file' in kwargs)
        self.amqp_internal_connection_obj = galaxy.queues.connection_from_config(
            self.config)
        # queue_worker *can* be initialized with a queue, but here we don't
        # want to and we'll allow postfork to bind and start it.
        self.queue_worker = GalaxyQueueWorker(self)

        self._configure_tool_shed_registry()
        self._configure_object_store(fsmon=True)
        # Setup the database engine and ORM
        config_file = kwargs.get('global_conf', {}).get('__file__', None)
        if config_file:
            log.debug('Using "galaxy.ini" config file: %s', config_file)
        check_migrate_tools = self.config.check_migrate_tools
        self._configure_models(
            check_migrate_databases=self.config.check_migrate_databases,
            check_migrate_tools=check_migrate_tools,
            config_file=config_file)

        # Security helper
        self._configure_security()
        # Tag handler
        self.tag_handler = GalaxyTagHandler(self.model.context)
        self.dataset_collections_service = DatasetCollectionManager(self)
        self.history_manager = HistoryManager(self)
        self.hda_manager = HDAManager(self)
        self.workflow_manager = WorkflowsManager(self)
        self.dependency_resolvers_view = DependencyResolversView(self)
        self.test_data_resolver = test_data.TestDataResolver(
            file_dirs=self.config.tool_test_data_directories)
        self.library_folder_manager = FolderManager()
        self.library_manager = LibraryManager()
        self.dynamic_tool_manager = DynamicToolManager(self)

        # Tool Data Tables
        self._configure_tool_data_tables(from_shed_config=False)
        # Load dbkey / genome build manager
        self._configure_genome_builds(data_table_name="__dbkeys__",
                                      load_old_style=True)

        # Genomes
        self.genomes = Genomes(self)
        # Data providers registry.
        self.data_provider_registry = DataProviderRegistry()

        # Initialize job metrics manager, needs to be in place before
        # config so per-destination modifications can be made.
        self.job_metrics = job_metrics.JobMetrics(
            self.config.job_metrics_config_file, app=self)

        # Initialize error report plugins.
        self.error_reports = ErrorReports(self.config.error_report_file,
                                          app=self)

        # Initialize the job management configuration
        self.job_config = jobs.JobConfiguration(self)

        # Setup a Tool Cache
        self.tool_cache = ToolCache()
        self.tool_shed_repository_cache = ToolShedRepositoryCache(self)
        # Watch various config files for immediate reload
        self.watchers = ConfigWatchers(self)
        self._configure_tool_config_files()
        self.installed_repository_manager = InstalledRepositoryManager(self)
        self._configure_datatypes_registry(self.installed_repository_manager)
        galaxy.model.set_datatypes_registry(self.datatypes_registry)

        self._configure_toolbox()

        # Load Data Manager
        self.data_managers = DataManagers(self)
        # Load the update repository manager.
        self.update_repository_manager = UpdateRepositoryManager(self)
        # Load proprietary datatype converters and display applications.
        self.installed_repository_manager.load_proprietary_converters_and_display_applications(
        )
        # Load datatype display applications defined in local datatypes_conf.xml
        self.datatypes_registry.load_display_applications(self)
        # Load datatype converters defined in local datatypes_conf.xml
        self.datatypes_registry.load_datatype_converters(self.toolbox)
        # Load external metadata tool
        self.datatypes_registry.load_external_metadata_tool(self.toolbox)
        # Load history import/export tools.
        load_lib_tools(self.toolbox)
        # visualizations registry: associates resources with visualizations, controls how to render
        self.visualizations_registry = VisualizationsRegistry(
            self,
            directories_setting=self.config.visualization_plugins_directory,
            template_cache_dir=self.config.template_cache_path)
        # Tours registry
        self.tour_registry = ToursRegistry(self.config.tour_config_dir)
        # Webhooks registry
        self.webhooks_registry = WebhooksRegistry(self.config.webhooks_dir)
        # Load security policy.
        self.security_agent = self.model.security_agent
        self.host_security_agent = galaxy.model.security.HostAgent(
            model=self.security_agent.model,
            permitted_actions=self.security_agent.permitted_actions)
        # Load quota management.
        if self.config.enable_quotas:
            self.quota_agent = galaxy.quota.QuotaAgent(self.model)
        else:
            self.quota_agent = galaxy.quota.NoQuotaAgent(self.model)
        # Heartbeat for thread profiling
        self.heartbeat = None
        from galaxy import auth
        self.auth_manager = auth.AuthManager(self)
        self.user_manager = UserManager(self)
        # Start the heartbeat process if configured and available (wait until
        # postfork if using uWSGI)
        if self.config.use_heartbeat:
            if heartbeat.Heartbeat:
                self.heartbeat = heartbeat.Heartbeat(
                    self.config,
                    period=self.config.heartbeat_interval,
                    fname=self.config.heartbeat_log)
                self.heartbeat.daemon = True
                self.application_stack.register_postfork_function(
                    self.heartbeat.start)

        self.authnz_manager = None
        if self.config.enable_oidc:
            from galaxy.authnz import managers
            self.authnz_manager = managers.AuthnzManager(
                self, self.config.oidc_config,
                self.config.oidc_backends_config)

        self.sentry_client = None
        if self.config.sentry_dsn:

            def postfork_sentry_client():
                import raven
                self.sentry_client = raven.Client(
                    self.config.sentry_dsn,
                    transport=raven.transport.HTTPTransport)

            self.application_stack.register_postfork_function(
                postfork_sentry_client)

        # Transfer manager client
        if self.config.get_bool('enable_beta_job_managers', False):
            from galaxy.jobs import transfer_manager
            self.transfer_manager = transfer_manager.TransferManager(self)
        # Start the job manager
        from galaxy.jobs import manager
        self.job_manager = manager.JobManager(self)
        self.application_stack.register_postfork_function(
            self.job_manager.start)
        self.proxy_manager = ProxyManager(self.config)

        from galaxy.workflow import scheduling_manager
        # Must be initialized after job_config.
        self.workflow_scheduling_manager = scheduling_manager.WorkflowSchedulingManager(
            self)

        # Must be initialized after any component that might make use of stack messaging is configured. Alternatively if
        # it becomes more commonly needed we could create a prefork function registration method like we do with
        # postfork functions.
        self.application_stack.init_late_prefork()

        self.containers = {}
        if self.config.enable_beta_containers_interface:
            self.containers = build_container_interfaces(
                self.config.containers_config_file,
                containers_conf=self.config.containers_conf)

        self.interactivetool_manager = InteractiveToolManager(self)

        # Configure handling of signals
        handlers = {}
        if self.heartbeat:
            handlers[signal.SIGUSR1] = self.heartbeat.dump_signal_handler
        self._configure_signal_handlers(handlers)

        self.database_heartbeat = DatabaseHeartbeat(
            application_stack=self.application_stack)
        self.database_heartbeat.add_change_callback(self.watchers.change_state)
        self.application_stack.register_postfork_function(
            self.database_heartbeat.start)

        # Start web stack message handling
        self.application_stack.register_postfork_function(
            self.application_stack.start)
        self.application_stack.register_postfork_function(
            self.queue_worker.bind_and_start)
        # Delay toolbox index until after startup
        self.application_stack.register_postfork_function(
            lambda: send_local_control_task(self,
                                            'rebuild_toolbox_search_index'))

        self.model.engine.dispose()

        # Inject url_for for components to more easily optionally depend
        # on url_for.
        self.url_for = url_for

        self.server_starttime = int(time.time())  # used for cachebusting
        log.info("Galaxy app startup finished %s" % self.startup_timer)
Example #20
0
def get_user_manager(app: UniverseApplication = Depends(get_app)) -> UserManager:
    return UserManager(app)