From 528497f7c42f81d4114eeccc559ad16366c423dd Mon Sep 17 00:00:00 2001 From: John Chilton Date: Mon, 18 Mar 2019 11:51:02 -0400 Subject: [PATCH] Refactor galaxy.web.security into galaxy.security.idencoding. I want to be able to use this class in galaxy.model and it doesn't have any dependnecies on "web" stuff so I'd like to move it out of galaxy.model and into galaxy.security. galaxy.model shouldn't have dependencies on galaxy.web (and doesn't after the recent 976f5ad3677fbf4f9850e6bf43d9455a81cd5f42), so this pre-emptively ensures it doesn't require these dependencies for https://github.com/galaxyproject/galaxy/pull/7367. This has the benefit of also eliminating any galaxy.web dependencies from the generic test base file (test/base/testcase.py) which has long been a goal of mine as well. There are places we legimately use ID encoding and decoding for security (i.e. job files API) but for the most part it doesn't provide security for API endpoints and this causes confusion repeatedly, so I've started the process of renaming the contained class SecurityHelper to something I feel makes it clearer this is just about encoding and decoding IDs. --- lib/galaxy/config.py | 4 ++-- .../__init__.py => security/idencoding.py} | 2 +- lib/galaxy/webapps/reports/app.py | 4 ++-- lib/galaxy/webapps/tool_shed/app.py | 5 ++--- scripts/communication/communication_server.py | 4 ++-- scripts/helper.py | 4 ++-- scripts/pages_identifier_conversion.py | 4 ++-- scripts/secret_decoder_ring.py | 4 ++-- .../create_user_with_api_key.py | 4 ++-- test/base/testcase.py | 5 ++--- test/shed_functional/base/twilltestcase.py | 4 ++-- ...rity_helper.py => test_id_encode_decode.py} | 18 +++++++++--------- test/unit/unittest_utils/galaxy_mock.py | 6 +++--- test/unit/workflows/workflow_support.py | 4 ++-- 14 files changed, 35 insertions(+), 37 deletions(-) rename lib/galaxy/{web/security/__init__.py => security/idencoding.py} (99%) rename test/unit/{test_security_helper.py => test_id_encode_decode.py} (88%) diff --git a/lib/galaxy/config.py b/lib/galaxy/config.py index e529fddf706..cf65d4e7d84 100644 --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -1124,8 +1124,8 @@ class ConfiguresGalaxyMixin(object): self.object_store = build_object_store_from_config(self.config, **kwds) def _configure_security(self): - from galaxy.web import security - self.security = security.SecurityHelper(id_secret=self.config.id_secret) + from galaxy.security import idencoding + self.security = idencoding.IdEncodingHelper(id_secret=self.config.id_secret) def _configure_tool_shed_registry(self): import tool_shed.tool_shed_registry diff --git a/lib/galaxy/web/security/__init__.py b/lib/galaxy/security/idencoding.py similarity index 99% rename from lib/galaxy/web/security/__init__.py rename to lib/galaxy/security/idencoding.py index d7486aacb1b..1f9a15739fc 100644 --- a/lib/galaxy/web/security/__init__.py +++ b/lib/galaxy/security/idencoding.py @@ -18,7 +18,7 @@ MAXIMUM_ID_SECRET_LENGTH = int(MAXIMUM_ID_SECRET_BITS / 8) KIND_TOO_LONG_MESSAGE = "Galaxy coding error, keep encryption 'kinds' smaller to utilize more bites of randomness from id_secret values." -class SecurityHelper(object): +class IdEncodingHelper(object): def __init__(self, **config): id_secret = config['id_secret'] diff --git a/lib/galaxy/webapps/reports/app.py b/lib/galaxy/webapps/reports/app.py index 27318ae99cd..25d12eb9688 100644 --- a/lib/galaxy/webapps/reports/app.py +++ b/lib/galaxy/webapps/reports/app.py @@ -3,7 +3,7 @@ import sys import time import galaxy.model -from galaxy.web import security +from galaxy.security import idencoding from galaxy.web.stack import application_stack_instance from . import config @@ -36,7 +36,7 @@ class UniverseApplication(object): else: self.targets_mysql = 'mysql' in self.config.database_connection # Security helper - self.security = security.SecurityHelper(id_secret=self.config.id_secret) + self.security = idencoding.IdEncodingHelper(id_secret=self.config.id_secret) # used for cachebusting -- refactor this into a *SINGLE* UniverseApplication base. self.server_starttime = int(time.time()) diff --git a/lib/galaxy/webapps/tool_shed/app.py b/lib/galaxy/webapps/tool_shed/app.py index 332dc82ea64..0fdd8ecec6d 100644 --- a/lib/galaxy/webapps/tool_shed/app.py +++ b/lib/galaxy/webapps/tool_shed/app.py @@ -11,8 +11,8 @@ import tool_shed.repository_types.registry from galaxy import tools from galaxy.config import configure_logging from galaxy.model.tags import CommunityTagHandler +from galaxy.security import idencoding from galaxy.util.dbkeys import GenomeBuilds -from galaxy.web import security from galaxy.web.stack import application_stack_instance from tool_shed.grids.repository_grid_filter_manager import RepositoryGridFilterManager from . import config @@ -51,8 +51,7 @@ class UniverseApplication(object): self.model = mapping.init(self.config.file_path, db_url, self.config.database_engine_options) - # Initialize the Tool Shed security helper. - self.security = security.SecurityHelper(id_secret=self.config.id_secret) + self.security = idencoding.IdEncodingHelper(id_secret=self.config.id_secret) # initialize the Tool Shed tag handler. self.tag_handler = CommunityTagHandler(self) # Initialize the Tool Shed tool data tables. Never pass a configuration file here diff --git a/scripts/communication/communication_server.py b/scripts/communication/communication_server.py index 1909bfcb447..3288aa459de 100755 --- a/scripts/communication/communication_server.py +++ b/scripts/communication/communication_server.py @@ -50,9 +50,9 @@ from flask_socketio import ( sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, 'lib'))) import galaxy.config +from galaxy.security.idencoding import IdEncodingHelper from galaxy.util.sanitize_html import sanitize_html from galaxy.util.script import app_properties_from_args, populate_config_args -from galaxy.web.security import SecurityHelper logging.basicConfig() log = logging.getLogger(__name__) @@ -77,7 +77,7 @@ if "id_secret" not in app_properties: id_secret = app_properties.get('id_secret', 'dangerous_default') -security_helper = SecurityHelper(id_secret=id_secret) +security_helper = IdEncodingHelper(id_secret=id_secret) # And get access to the models # Login manager to manage current_user functionality login_manager = flask_login.LoginManager() diff --git a/scripts/helper.py b/scripts/helper.py index 1bf36fb9e4e..7ed11afaec9 100644 --- a/scripts/helper.py +++ b/scripts/helper.py @@ -13,8 +13,8 @@ import sys sys.path.insert(1, os.path.join(os.path.dirname(__file__), os.pardir, 'lib')) import galaxy.config +from galaxy.security import idencoding from galaxy.util.script import app_properties_from_args, populate_config_args -from galaxy.web import security parser = argparse.ArgumentParser() populate_config_args(parser) @@ -26,7 +26,7 @@ args = parser.parse_args() app_properties = app_properties_from_args(args) config = galaxy.config.Configuration(**app_properties) -helper = security.SecurityHelper(id_secret=app_properties.get('id_secret')) +helper = idencoding.IdEncodingHelper(id_secret=app_properties.get('id_secret')) model = galaxy.config.init_models_from_config(config) if args.encode_id: diff --git a/scripts/pages_identifier_conversion.py b/scripts/pages_identifier_conversion.py index b7139e8e77d..ce914938f21 100644 --- a/scripts/pages_identifier_conversion.py +++ b/scripts/pages_identifier_conversion.py @@ -10,10 +10,10 @@ import galaxy import galaxy.app import galaxy.config from galaxy.objectstore import build_object_store_from_config +from galaxy.security.idencoding import IdEncodingHelper from galaxy.util import unicodify from galaxy.util.bunch import Bunch from galaxy.util.script import app_properties_from_args, populate_config_args -from galaxy.web.security import SecurityHelper from galaxy.webapps.galaxy.controllers.page import _PageContentProcessor, _placeholderRenderForSave @@ -26,7 +26,7 @@ def main(argv): properties = app_properties_from_args(args) config = galaxy.config.Configuration(**properties) secret = args.secret_key or config.id_secret - security_helper = SecurityHelper(id_secret=secret) + security_helper = IdEncodingHelper(id_secret=secret) object_store = build_object_store_from_config(config) if not config.database_connection: print("The database connection is empty. If you are using the default value, please uncomment that in your galaxy.yml") diff --git a/scripts/secret_decoder_ring.py b/scripts/secret_decoder_ring.py index 9ccbcba5ff7..a70dd711b66 100644 --- a/scripts/secret_decoder_ring.py +++ b/scripts/secret_decoder_ring.py @@ -9,9 +9,9 @@ import sys sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'lib'))) +from galaxy.security.idencoding import IdEncodingHelper from galaxy.util import unicodify from galaxy.util.script import app_properties_from_args, populate_config_args -from galaxy.web.security import SecurityHelper logging.basicConfig() log = logging.getLogger(__name__) @@ -35,7 +35,7 @@ if "id_secret" not in app_properties: id_secret = app_properties.get('id_secret', 'dangerous_default') -security_helper = SecurityHelper(id_secret=id_secret) +security_helper = IdEncodingHelper(id_secret=id_secret) # And get access to the models # Login manager to manage current_user functionality diff --git a/scripts/tool_shed/bootstrap_tool_shed/create_user_with_api_key.py b/scripts/tool_shed/bootstrap_tool_shed/create_user_with_api_key.py index 13cb8165710..f91cdd356f8 100644 --- a/scripts/tool_shed/bootstrap_tool_shed/create_user_with_api_key.py +++ b/scripts/tool_shed/bootstrap_tool_shed/create_user_with_api_key.py @@ -13,7 +13,7 @@ sys.path.insert(1, os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, sys.path.insert(1, os.path.join(os.path.dirname(__file__))) import galaxy.webapps.tool_shed.config as tool_shed_config -from galaxy.web import security +from galaxy.security.idencoding import IdEncodingHelper from galaxy.webapps.tool_shed.model import mapping from bootstrap_util import admin_user_info # noqa: I100,I201 @@ -40,7 +40,7 @@ class BootstrapApplication(object): self.config.database_connection, engine_options={}, create_tables=False) - self.security = security.SecurityHelper(id_secret=self.config.id_secret) + self.security = IdEncodingHelper(id_secret=self.config.id_secret) self.hgweb_config_manager = self.model.hgweb_config_manager self.hgweb_config_manager.hgweb_config_dir = self.config.hgweb_config_dir print('Using hgweb.config file: ', self.hgweb_config_manager.hgweb_config) diff --git a/test/base/testcase.py b/test/base/testcase.py index 02cda1500c4..c73824250f6 100644 --- a/test/base/testcase.py +++ b/test/base/testcase.py @@ -4,8 +4,8 @@ import logging import os import unittest +from galaxy.security import idencoding from galaxy.tools.verify.test_data import TestDataResolver -from galaxy.web import security from .driver_util import GalaxyTestDriver, setup_keep_outdir, target_url_parts log = logging.getLogger(__name__) @@ -14,8 +14,7 @@ log = logging.getLogger(__name__) class FunctionalTestCase(unittest.TestCase): def setUp(self): - # Security helper - self.security = security.SecurityHelper(id_secret='changethisinproductiontoo') + self.security = idencoding.IdEncodingHelper(id_secret='changethisinproductiontoo') self.history_id = os.environ.get('GALAXY_TEST_HISTORY_ID', None) self.host, self.port, self.url = target_url_parts() self.test_data_resolver = TestDataResolver() diff --git a/test/shed_functional/base/twilltestcase.py b/test/shed_functional/base/twilltestcase.py index 0e333731a5a..61cd0443e34 100644 --- a/test/shed_functional/base/twilltestcase.py +++ b/test/shed_functional/base/twilltestcase.py @@ -29,8 +29,8 @@ import galaxy.model.tool_shed_install as galaxy_model import galaxy.util import galaxy.webapps.tool_shed.util.hgweb_config from base.testcase import FunctionalTestCase # noqa: I100,I201,I202 +from galaxy.security import idencoding # noqa: I201 from galaxy.util import unicodify # noqa: I201 -from galaxy.web import security # noqa: I201 from tool_shed.util import hg_util, xml_util from tool_shed.util.encoding_util import tool_shed_encode from . import common, test_db_util @@ -52,7 +52,7 @@ class ShedTwillTestCase(FunctionalTestCase): def setUp(self): # Security helper - self.security = security.SecurityHelper(id_secret='changethisinproductiontoo') + self.security = idencoding.IdEncodingHelper(id_secret='changethisinproductiontoo') self.history_id = None self.hgweb_config_dir = os.environ.get('TEST_HG_WEB_CONFIG_DIR') self.hgweb_config_manager = galaxy.webapps.tool_shed.util.hgweb_config.HgWebConfigManager() diff --git a/test/unit/test_security_helper.py b/test/unit/test_id_encode_decode.py similarity index 88% rename from test/unit/test_security_helper.py rename to test/unit/test_id_encode_decode.py index c87497ea58e..d7aa10e7383 100644 --- a/test/unit/test_security_helper.py +++ b/test/unit/test_id_encode_decode.py @@ -1,23 +1,23 @@ # -*- coding: utf-8 -*- -from galaxy.web import security +from galaxy.security import idencoding -test_helper_1 = security.SecurityHelper(id_secret="secu1") -test_helper_2 = security.SecurityHelper(id_secret="secu2") +test_helper_1 = idencoding.IdEncodingHelper(id_secret="secu1") +test_helper_2 = idencoding.IdEncodingHelper(id_secret="secu2") def test_maximum_length_handling_ascii(): # Test that id secrets can be up to 56 characters long. - longest_id_secret = "m" * security.MAXIMUM_ID_SECRET_LENGTH - helper = security.SecurityHelper(id_secret=longest_id_secret) + longest_id_secret = "m" * idencoding.MAXIMUM_ID_SECRET_LENGTH + helper = idencoding.IdEncodingHelper(id_secret=longest_id_secret) helper.encode_id(1) # Test that security helper will catch if the id secret is too long. threw_exception = False - longer_id_secret = "m" * (security.MAXIMUM_ID_SECRET_LENGTH + 1) + longer_id_secret = "m" * (idencoding.MAXIMUM_ID_SECRET_LENGTH + 1) try: - security.SecurityHelper(id_secret=longer_id_secret) + idencoding.IdEncodingHelper(id_secret=longer_id_secret) except Exception: threw_exception = True @@ -44,14 +44,14 @@ def test_maximum_length_handling_ascii(): def test_maximum_length_handling_nonascii(): longest_id_secret = "◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎" - helper = security.SecurityHelper(id_secret=longest_id_secret) + helper = idencoding.IdEncodingHelper(id_secret=longest_id_secret) helper.encode_id(1) # Test that security helper will catch if the id secret is too long. threw_exception = False longer_id_secret = "◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎" try: - security.SecurityHelper(id_secret=longer_id_secret) + idencoding.IdEncodingHelper(id_secret=longer_id_secret) except Exception: threw_exception = True diff --git a/test/unit/unittest_utils/galaxy_mock.py b/test/unit/unittest_utils/galaxy_mock.py index bfcd8aa5578..b04d4411005 100644 --- a/test/unit/unittest_utils/galaxy_mock.py +++ b/test/unit/unittest_utils/galaxy_mock.py @@ -14,10 +14,10 @@ from galaxy.auth import AuthManager from galaxy.datatypes import registry from galaxy.jobs.manager import NoopManager from galaxy.model import mapping, tags +from galaxy.security import idencoding from galaxy.tools.deps.containers import NullContainerFinder from galaxy.util.bunch import Bunch from galaxy.util.dbkeys import GenomeBuilds -from galaxy.web import security from galaxy.web.stack import ApplicationStack @@ -110,7 +110,7 @@ class MockAppConfig(Bunch): def __init__(self, root=None, **kwargs): Bunch.__init__(self, **kwargs) root = root or '/tmp' - self.security = security.SecurityHelper(id_secret='6e46ed6483a833c100e68cc3f1d0dd76') + self.security = idencoding.IdEncodingHelper(id_secret='6e46ed6483a833c100e68cc3f1d0dd76') self.use_remote_user = kwargs.get('use_remote_user', False) self.file_path = '/tmp' self.jobs_directory = '/tmp' @@ -155,7 +155,7 @@ class MockWebapp(object): def __init__(self, **kwargs): self.name = kwargs.get('name', 'galaxy') - self.security = security.SecurityHelper(id_secret='6e46ed6483a833c100e68cc3f1d0dd76') + self.security = idencoding.IdEncodingHelper(id_secret='6e46ed6483a833c100e68cc3f1d0dd76') class MockTrans(object): diff --git a/test/unit/workflows/workflow_support.py b/test/unit/workflows/workflow_support.py index 14dffa3af80..fbe498466ca 100644 --- a/test/unit/workflows/workflow_support.py +++ b/test/unit/workflows/workflow_support.py @@ -4,8 +4,8 @@ import yaml from galaxy import model from galaxy.model import mapping +from galaxy.security.idencoding import IdEncodingHelper from galaxy.util import bunch -from galaxy.web.security import SecurityHelper class MockTrans(object): @@ -47,7 +47,7 @@ class TestApp(object): ) self.toolbox = TestToolbox() self.datatypes_registry = TestDatatypesRegistry() - self.security = SecurityHelper(id_secret="testing") + self.security = IdEncodingHelper(id_secret="testing") class TestDatatypesRegistry(object):