From d0fb11c015880539bcc8b8e2d1b79bdeacbb3330 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Mon, 31 Jan 2022 18:15:01 +0100 Subject: [PATCH] Drop OpenID post authentication protocols --- doc/source/admin/galaxy_options.rst | 32 +--- lib/galaxy/config/config_manage.py | 2 + lib/galaxy/config/sample/galaxy.yml.sample | 13 +- lib/galaxy/config/schemas/config_schema.yml | 15 -- lib/galaxy/managers/configuration.py | 1 - lib/galaxy/openid/__init__.py | 3 - lib/galaxy/openid/openid_conf.xml | 3 - lib/galaxy/openid/openid_manager.py | 75 --------- lib/galaxy/openid/providers.py | 144 ------------------ .../webapps/galaxy/controllers/openid.py | 74 --------- packages/app/galaxy/openid | 1 - packages/app/setup.py | 1 - test/integration/test_config_defaults.py | 1 - test/unit/config/test_config_values.py | 1 - 14 files changed, 12 insertions(+), 354 deletions(-) delete mode 100644 lib/galaxy/openid/__init__.py delete mode 100644 lib/galaxy/openid/openid_conf.xml delete mode 100644 lib/galaxy/openid/openid_manager.py delete mode 100644 lib/galaxy/openid/providers.py delete mode 100644 lib/galaxy/webapps/galaxy/controllers/openid.py delete mode 120000 packages/app/galaxy/openid diff --git a/doc/source/admin/galaxy_options.rst b/doc/source/admin/galaxy_options.rst index 4f465bb6c33..93f7fafa547 100644 --- a/doc/source/admin/galaxy_options.rst +++ b/doc/source/admin/galaxy_options.rst @@ -3701,28 +3701,6 @@ :Type: str -~~~~~~~~~~~~~~~~~ -``enable_openid`` -~~~~~~~~~~~~~~~~~ - -:Description: - Enable access to post-authentication options via OpenID. -:Default: ``false`` -:Type: bool - - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``openid_consumer_cache_path`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:Description: - If OpenID is enabled, consumer cache directory to use. - The value of this option will be resolved with respect to - . -:Default: ``openid_consumer_cache`` -:Type: str - - ~~~~~~~~~~~~~~~~~~~~ ``enable_tool_tags`` ~~~~~~~~~~~~~~~~~~~~ @@ -4823,13 +4801,17 @@ :Default: ``plugins/welcome_page/new_user/static/topics/`` :Type: str -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +~~~~~~~~~~~~~~~~~~~~~ ``vault_config_file`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~ :Description: - Vault configuration + Vault config file. The value of this option will be resolved with respect to . :Default: ``vault_conf.yml`` :Type: str + + + diff --git a/lib/galaxy/config/config_manage.py b/lib/galaxy/config/config_manage.py index 9467cb7d603..26638a11ab4 100644 --- a/lib/galaxy/config/config_manage.py +++ b/lib/galaxy/config/config_manage.py @@ -313,6 +313,8 @@ OPTION_ACTIONS = { 'communication_server_port': _DeprecatedAndDroppedAction(), 'persistent_communication_rooms': _DeprecatedAndDroppedAction(), 'legacy_eager_objectstore_initialization': _DeprecatedAndDroppedAction(), + 'enable_openid': _DeprecatedAndDroppedAction(), + 'openid_consumer_cache_path': _DeprecatedAndDroppedAction(), } diff --git a/lib/galaxy/config/sample/galaxy.yml.sample b/lib/galaxy/config/sample/galaxy.yml.sample index 3893a456178..e5b5e06decd 100644 --- a/lib/galaxy/config/sample/galaxy.yml.sample +++ b/lib/galaxy/config/sample/galaxy.yml.sample @@ -1811,14 +1811,6 @@ galaxy: # production server. #master_api_key: null - # Enable access to post-authentication options via OpenID. - #enable_openid: false - - # If OpenID is enabled, consumer cache directory to use. - # The value of this option will be resolved with respect to - # . - #openid_consumer_cache_path: openid_consumer_cache - # Enable tool tags (associating tools with tags). This has its own # option since its implementation has a few performance implications # on startup for large servers. @@ -2353,7 +2345,8 @@ galaxy: # is relative to galaxy/static #welcome_directory: plugins/welcome_page/new_user/static/topics/ - # Vault config file + # Vault config file. # The value of this option will be resolved with respect to # . - vault_config_file: vault_conf.yml + #vault_config_file: vault_conf.yml + diff --git a/lib/galaxy/config/schemas/config_schema.yml b/lib/galaxy/config/schemas/config_schema.yml index 3e861caed96..7769e908e78 100644 --- a/lib/galaxy/config/schemas/config_schema.yml +++ b/lib/galaxy/config/schemas/config_schema.yml @@ -2701,21 +2701,6 @@ mapping: a real admin user account via API. You should probably not set this on a production server. - enable_openid: - type: bool - default: false - required: false - desc: | - Enable access to post-authentication options via OpenID. - - openid_consumer_cache_path: - type: str - default: openid_consumer_cache - path_resolves_to: cache_dir - required: false - desc: | - If OpenID is enabled, consumer cache directory to use. - enable_tool_tags: type: bool default: false diff --git a/lib/galaxy/managers/configuration.py b/lib/galaxy/managers/configuration.py index ea0fec99c13..2201abe6e1f 100644 --- a/lib/galaxy/managers/configuration.py +++ b/lib/galaxy/managers/configuration.py @@ -147,7 +147,6 @@ class ConfigSerializer(base.ModelSerializer): 'helpsite_url': _use_config, 'lims_doc_url': _defaults_to("https://usegalaxy.org/u/rkchak/p/sts"), 'default_locale': _use_config, - 'enable_openid': _use_config, 'enable_tool_recommendations': _use_config, 'enable_account_interface': _use_config, 'tool_recommendation_model_path': _use_config, diff --git a/lib/galaxy/openid/__init__.py b/lib/galaxy/openid/__init__.py deleted file mode 100644 index d196c842445..00000000000 --- a/lib/galaxy/openid/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -OpenID functionality -""" diff --git a/lib/galaxy/openid/openid_conf.xml b/lib/galaxy/openid/openid_conf.xml deleted file mode 100644 index 5730ae4dd86..00000000000 --- a/lib/galaxy/openid/openid_conf.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/lib/galaxy/openid/openid_manager.py b/lib/galaxy/openid/openid_manager.py deleted file mode 100644 index 549da906e80..00000000000 --- a/lib/galaxy/openid/openid_manager.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -Manage the OpenID consumer and related data stores. -""" - -import logging -import os -import pickle - -try: - from openid import oidutil - from openid.consumer import consumer - from openid.extensions import sreg - from openid.store import filestore -except ImportError: - oidutil = None - - class FakeConsumer: - def __getattr__(x, y): - return None - consumer = FakeConsumer() - - -OPENID_IMPORT_MESSAGE = ('The Python openid package is required to use this ' - 'feature, please install it') - -log = logging.getLogger(__name__) - - -def oidlog(message, level=0): - log.debug(message) - - -if oidutil is not None: - oidutil.log = oidlog - - -class OpenIDManager: - def __init__(self, cache_path): - assert oidutil is not None, OPENID_IMPORT_MESSAGE - self.session_path = os.path.join(cache_path, 'session') - self.store_path = os.path.join(cache_path, 'store') - for dir in self.session_path, self.store_path: - if not os.path.exists(dir): - os.makedirs(dir) - self.store = filestore.FileOpenIDStore(self.store_path) - - def get_session(self, trans): - session_file = os.path.join(self.session_path, str(trans.galaxy_session.id)) - if not os.path.exists(session_file): - pickle.dump(dict(), open(session_file, 'wb')) - return pickle.load(open(session_file, 'rb')) - - def persist_session(self, trans, oidconsumer): - session_file = os.path.join(self.session_path, str(trans.galaxy_session.id)) - pickle.dump(oidconsumer.session, open(session_file, 'wb')) - - def get_consumer(self, trans): - return consumer.Consumer(self.get_session(trans), self.store) - - def add_sreg(self, trans, request, required=None, optional=None): - if required is None: - required = [] - if optional is None: - optional = [] - sreg_request = sreg.SRegRequest(required=required, optional=optional) - request.addExtension(sreg_request) - - def get_sreg(self, info): - return sreg.SRegResponse.fromSuccessResponse(info) - - # so I don't have to expose all of openid.consumer.consumer - FAILURE = consumer.FAILURE - SUCCESS = consumer.SUCCESS - CANCEL = consumer.CANCEL - SETUP_NEEDED = consumer.SETUP_NEEDED diff --git a/lib/galaxy/openid/providers.py b/lib/galaxy/openid/providers.py deleted file mode 100644 index 151d08e59d9..00000000000 --- a/lib/galaxy/openid/providers.py +++ /dev/null @@ -1,144 +0,0 @@ -""" -Contains OpenID provider functionality -""" -import logging -import os - - -from galaxy.util import parse_xml, string_as_bool - - -log = logging.getLogger(__name__) - -NO_PROVIDER_ID = 'None' -RESERVED_PROVIDER_IDS = [NO_PROVIDER_ID] - - -class OpenIDProvider: - '''An OpenID Provider object.''' - @classmethod - def from_file(cls, filename): - return cls.from_elem(parse_xml(filename).getroot()) - - @classmethod - def from_elem(cls, xml_root): - provider_elem = xml_root - provider_id = provider_elem.get('id', None) - provider_name = provider_elem.get('name', provider_id) - op_endpoint_url = provider_elem.find('op_endpoint_url') - if op_endpoint_url is not None: - op_endpoint_url = op_endpoint_url.text - never_associate_with_user = string_as_bool(provider_elem.get('never_associate_with_user', 'False')) - assert (provider_id and provider_name and op_endpoint_url), Exception("OpenID Provider improperly configured") - assert provider_id not in RESERVED_PROVIDER_IDS, Exception(f'Specified OpenID Provider uses a reserved id: {provider_id}') - sreg_required = [] - sreg_optional = [] - use_for = {} - store_user_preference = {} - use_default_sreg = True - for elem in provider_elem.findall('sreg'): - use_default_sreg = False - for field_elem in elem.findall('field'): - sreg_name = field_elem.get('name') - assert sreg_name, Exception('A name is required for a sreg element') - if string_as_bool(field_elem.get('required')): - sreg_required.append(sreg_name) - else: - sreg_optional.append(sreg_name) - for use_elem in field_elem.findall('use_for'): - use_for[use_elem.get('name')] = sreg_name - for store_user_preference_elem in field_elem.findall('store_user_preference'): - store_user_preference[store_user_preference_elem.get('name')] = sreg_name - if use_default_sreg: - sreg_required = None - sreg_optional = None - use_for = None - return cls(provider_id, provider_name, op_endpoint_url, sreg_required=sreg_required, sreg_optional=sreg_optional, use_for=use_for, store_user_preference=store_user_preference, never_associate_with_user=never_associate_with_user) - - def __init__(self, id, name, op_endpoint_url, sreg_required=None, sreg_optional=None, use_for=None, store_user_preference=None, never_associate_with_user=None): - '''When sreg options are not specified, defaults are used.''' - self.id = id - self.name = name - self.op_endpoint_url = op_endpoint_url - if sreg_optional is None: - self.sreg_optional = ['nickname', 'email'] - else: - self.sreg_optional = sreg_optional - if sreg_required: - self.sreg_required = sreg_required - else: - self.sreg_required = [] - if use_for is not None: - self.use_for = use_for - else: - self.use_for = {} - if 'nickname' in (self.sreg_optional + self.sreg_required): - self.use_for['username'] = 'nickname' - if 'email' in (self.sreg_optional + self.sreg_required): - self.use_for['email'] = 'email' - if store_user_preference: - self.store_user_preference = store_user_preference - else: - self.store_user_preference = {} - if never_associate_with_user: - self.never_associate_with_user = True - else: - self.never_associate_with_user = False - - def post_authentication(self, trans, openid_manager, info): - sreg_attributes = openid_manager.get_sreg(info) - for store_pref_name, store_pref_value_name in self.store_user_preference.items(): - if store_pref_value_name in (self.sreg_optional + self.sreg_required): - trans.user.preferences[store_pref_name] = sreg_attributes.get(store_pref_value_name) - else: - raise Exception('Only sreg is currently supported.') - trans.sa_session.add(trans.user) - trans.sa_session.flush() - - def has_post_authentication_actions(self): - return bool(self.store_user_preference) - - -class OpenIDProviders: - '''Collection of OpenID Providers''' - NO_PROVIDER_ID = NO_PROVIDER_ID - - @classmethod - def from_file(cls, filename): - try: - return cls.from_elem(parse_xml(filename).getroot()) - except Exception as e: - log.error(f'Failed to load OpenID Providers: {e}') - return cls() - - @classmethod - def from_elem(cls, xml_root): - oid_elem = xml_root - providers = {} - for elem in oid_elem.findall('provider'): - try: - provider = OpenIDProvider.from_file(os.path.join('lib/galaxy/openid', elem.get('file'))) - providers[provider.id] = provider - log.debug(f'Loaded OpenID provider: {provider.name} ({provider.id})') - except Exception as e: - log.error(f'Failed to add OpenID provider: {e}') - return cls(providers) - - def __init__(self, providers=None): - if providers: - self.providers = providers - else: - self.providers = {} - self._banned_identifiers = [provider.op_endpoint_url for provider in self.providers.values() if provider.never_associate_with_user] - - def __iter__(self): - yield from self.providers.values() - - def get(self, name, default=None): - if name in self.providers: - return self.providers[name] - else: - return default - - def new_provider_from_identifier(self, identifier): - return OpenIDProvider(None, identifier, identifier, never_associate_with_user=identifier in self._banned_identifiers) diff --git a/lib/galaxy/webapps/galaxy/controllers/openid.py b/lib/galaxy/webapps/galaxy/controllers/openid.py deleted file mode 100644 index 865b4d794b4..00000000000 --- a/lib/galaxy/webapps/galaxy/controllers/openid.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -Contains the OpenID interface in the Universe class -""" - -import logging - -from galaxy import web -from galaxy.openid.openid_manager import OpenIDManager -from galaxy.openid.providers import OpenIDProviders -from galaxy.structured_app import StructuredApp -from galaxy.util import unicodify -from galaxy.web import url_for -from galaxy.webapps.base.controller import BaseUIController - -log = logging.getLogger(__name__) - - -class OpenID(BaseUIController): - - def __init__(self, app: StructuredApp): - super().__init__(app) - if app.config.enable_openid: - self.openid_manager = OpenIDManager(app.config.openid_consumer_cache_path) - self.openid_providers = OpenIDProviders.from_file('lib/galaxy/openid/openid_conf.xml') - - @web.expose - def openid_auth(self, trans, **kwd): - '''Handles user request to access an OpenID provider''' - if not trans.app.config.enable_openid: - return trans.show_error_message("OpenID authentication is not enabled in this instance of Galaxy.") - consumer = self.openid_manager.get_consumer(trans) - openid_provider = kwd.get('openid_provider') - if openid_provider: - openid_provider_obj = self.openid_providers.get(openid_provider) - else: - return trans.show_error_message("An OpenID provider was not specified.") - if not openid_provider_obj: - return trans.show_error_message("An OpenID provider is invalid.") - process_url = trans.request.base.rstrip('/') + url_for(controller='openid', action='openid_process', openid_provider=openid_provider) - request = None - try: - request = consumer.begin(openid_provider_obj.op_endpoint_url) - if request is None: - return trans.show_error_message(f"No OpenID services are available at {openid_provider_obj.op_endpoint_url}.") - except Exception as e: - return trans.show_error_message(f"Failed to begin OpenID authentication: {unicodify(e)}.") - if request is not None: - self.openid_manager.add_sreg(trans, request, required=openid_provider_obj.sreg_required, optional=openid_provider_obj.sreg_optional) - if request.shouldSendRedirect(): - redirect_url = request.redirectURL( - trans.request.base, process_url) - self.openid_manager.persist_session(trans, consumer) - return trans.response.send_redirect(redirect_url) - else: - form = request.htmlMarkup(trans.request.base, process_url, form_tag_attrs={'id': 'openid_message', 'target': '_top'}) - self.openid_manager.persist_session(trans, consumer) - return form - return trans.show_error_message("OpenID request failed.") - - @web.expose - def openid_process(self, trans, **kwd): - '''Handle's response from OpenID Providers''' - return_link = f"Click here to return." - if not trans.app.config.enable_openid: - return trans.show_error_message(f"OpenID authentication is not enabled in this instance of Galaxy. {return_link}") - consumer = self.openid_manager.get_consumer(trans) - info = consumer.complete(kwd, trans.request.url) - openid_provider = kwd.get('openid_provider', None) - if info.status == self.openid_manager.SUCCESS: - openid_provider_obj = self.openid_providers.get(openid_provider) - openid_provider_obj.post_authentication(trans, self.openid_manager, info) - return trans.show_message(f"Processed OpenID authentication. {return_link}") - else: - return trans.show_error_message(f"Authentication via OpenID failed: {info.message}. {return_link}") diff --git a/packages/app/galaxy/openid b/packages/app/galaxy/openid deleted file mode 120000 index e0bf26b2d37..00000000000 --- a/packages/app/galaxy/openid +++ /dev/null @@ -1 +0,0 @@ -../../../lib/galaxy/openid \ No newline at end of file diff --git a/packages/app/setup.py b/packages/app/setup.py index 4812c204bfe..b07f8886ee7 100644 --- a/packages/app/setup.py +++ b/packages/app/setup.py @@ -49,7 +49,6 @@ PACKAGES = [ 'galaxy.jobs.runners.util.job_script', 'galaxy.jobs.splitters', 'galaxy.managers', - 'galaxy.openid', 'galaxy.schema', 'galaxy.tools', 'galaxy.tools.actions', diff --git a/test/integration/test_config_defaults.py b/test/integration/test_config_defaults.py index ce52047eaf1..5938e6957ce 100644 --- a/test/integration/test_config_defaults.py +++ b/test/integration/test_config_defaults.py @@ -81,7 +81,6 @@ PATH_CONFIG_PROPERTIES = [ 'object_store_config_file', 'oidc_backends_config_file', 'oidc_config_file', - 'openid_consumer_cache_path', 'sanitize_allowlist_file', 'shed_data_manager_config_file', 'shed_tool_config_file', diff --git a/test/unit/config/test_config_values.py b/test/unit/config/test_config_values.py index 73ee753583e..6a4306be3c9 100644 --- a/test/unit/config/test_config_values.py +++ b/test/unit/config/test_config_values.py @@ -139,7 +139,6 @@ class ExpectedValues: 'object_store_config_file': self._in_config_dir('object_store_conf.xml'), 'oidc_backends_config_file': self._in_config_dir('oidc_backends_config.xml'), 'oidc_config_file': self._in_config_dir('oidc_config.xml'), - 'openid_consumer_cache_path': self._in_cache_dir('openid_consumer_cache'), 'sanitize_allowlist_file': self._in_managed_config_dir('sanitize_allowlist.txt'), 'shed_data_manager_config_file': self._in_managed_config_dir('shed_data_manager_conf.xml'), 'shed_tool_config_file': self._in_managed_config_dir('shed_tool_conf.xml'),