Add OpenID support

This commit is contained in:
guerler
2019-04-06 01:20:36 -04:00
parent 842297e2e9
commit 28f34c433e
12 changed files with 404 additions and 29 deletions
+38 -26
View File
@@ -110,7 +110,7 @@ galaxy:
# string to specify an external database instead. This string takes
# many options which are explained in detail in the config file
# documentation.
#database_connection: 'sqlite:///./database/universe.sqlite?isolation_level=IMMEDIATE'
#database_connection: sqlite:///./database/universe.sqlite?isolation_level=IMMEDIATE
# If the server logs errors about not having enough database pool
# connections, you will want to increase these values, or consider
@@ -163,7 +163,7 @@ galaxy:
# instances with pretested installs. The following option can be used
# to separate the tool shed install database (all other options listed
# above but prefixed with install_ are also available).
#install_database_connection: 'sqlite:///./database/universe.sqlite?isolation_level=IMMEDIATE'
#install_database_connection: sqlite:///./database/universe.sqlite?isolation_level=IMMEDIATE
# Setting the following option to true will cause Galaxy to
# automatically migrate the database forward after updates. This is
@@ -183,7 +183,7 @@ galaxy:
# can be locally developed or installed from Galaxy tool sheds.
# (config/tool_conf.xml.sample will be used if left unset and
# config/tool_conf.xml does not exist).
#tool_config_file: 'config/tool_conf.xml,config/shed_tool_conf.xml'
#tool_config_file: config/tool_conf.xml,config/shed_tool_conf.xml
# Enable / disable checking if any tools defined in the above non-shed
# tool_config_files (i.e., tool_conf.xml) have been migrated from the
@@ -245,7 +245,7 @@ galaxy:
# conda channels to enable by default (https://conda.io/docs/user-
# guide/tasks/manage-channels.html)
#conda_ensure_channels: 'iuc,conda-forge,bioconda,defaults'
#conda_ensure_channels: iuc,conda-forge,bioconda,defaults
# Use locally-built conda packages.
#conda_use_local: false
@@ -350,7 +350,7 @@ galaxy:
# Conda channels to use when building Docker or Singularity containers
# using involucro.
#mulled_channels: 'conda-forge,bioconda'
#mulled_channels: conda-forge,bioconda
# Enable automatic polling of relative tool sheds to see if any
# updates are available for installed repositories. Ideally only one
@@ -582,7 +582,7 @@ galaxy:
# URL of the support resource for the galaxy instance. Used in
# activation emails.
#instance_resource_url: 'https://galaxyproject.org/'
#instance_resource_url: https://galaxyproject.org/
# E-mail domains blacklist is used for filtering out users that are
# using disposable email address during the registration. If their
@@ -609,7 +609,7 @@ galaxy:
# Shown in warning box to users that were not activated yet. In use
# only if activation_grace_period is set.
#inactivity_box_content: 'Your account has not been activated yet. Feel free to browse around and see what''s available, but you won''t be able to upload data or run jobs until you have verified your email address.'
#inactivity_box_content: Your account has not been activated yet. Feel free to browse around and see what's available, but you won't be able to upload data or run jobs until you have verified your email address.
# Password expiration period (in days). Users are required to change
# their password every x days. Users will be redirected to the change
@@ -640,7 +640,7 @@ galaxy:
# Main, Test and Archaea browsers, but the default if left commented
# is to not allow any display sites to bypass security (you must
# uncomment the line below to allow them).
#display_servers: 'hgw1.cse.ucsc.edu,hgw2.cse.ucsc.edu,hgw3.cse.ucsc.edu,hgw4.cse.ucsc.edu,hgw5.cse.ucsc.edu,hgw6.cse.ucsc.edu,hgw7.cse.ucsc.edu,hgw8.cse.ucsc.edu,lowepub.cse.ucsc.edu'
#display_servers: hgw1.cse.ucsc.edu,hgw2.cse.ucsc.edu,hgw3.cse.ucsc.edu,hgw4.cse.ucsc.edu,hgw5.cse.ucsc.edu,hgw6.cse.ucsc.edu,hgw7.cse.ucsc.edu,hgw8.cse.ucsc.edu,lowepub.cse.ucsc.edu
# To disable the old-style display applications that are hardcoded
# into datatype classes, set enable_old_display_applications = False.
@@ -694,7 +694,7 @@ galaxy:
# your machine on the virtualbox network (vboxnet0) setup for the
# Docker host VM. This can found by running ifconfig and using the IP
# address of the network vboxnet0.
#galaxy_infrastructure_url: 'http://localhost:8080'
#galaxy_infrastructure_url: http://localhost:8080
# If the above URL cannot be determined ahead of time in dynamic
# environments but the port which should be used to access Galaxy can
@@ -716,26 +716,26 @@ galaxy:
#helpsite_url: ''
# The URL linked by the "Wiki" link in the "Help" menu.
#wiki_url: 'https://galaxyproject.org/'
#wiki_url: https://galaxyproject.org/
# The URL linked by the "Support" link in the "Help" menu.
#support_url: 'https://galaxyproject.org/support/'
#support_url: https://galaxyproject.org/support/
# The URL linked by the "How to Cite Galaxy" link in the "Help" menu.
#citation_url: 'https://galaxyproject.org/citing-galaxy'
#citation_url: https://galaxyproject.org/citing-galaxy
# The URL linked by the "Search" link in the "Help" menu.
#search_url: 'https://galaxyproject.org/search/'
#search_url: https://galaxyproject.org/search/
# The URL linked by the "Mailing Lists" link in the "Help" menu.
#mailing_lists_url: 'https://galaxyproject.org/mailing-lists'
#mailing_lists_url: https://galaxyproject.org/mailing-lists
# The URL linked by the "Videos" link in the "Help" menu.
#screencasts_url: 'https://vimeo.com/galaxyproject'
#screencasts_url: https://vimeo.com/galaxyproject
# Points to the GenomeSpace UI service which will be used by the
# GenomeSpace importer and exporter tools
#genomespace_ui_url: 'https://gsui.genomespace.org/jsui/'
#genomespace_ui_url: https://gsui.genomespace.org/jsui/
# The URL linked by the "Terms and Conditions" link in the "Help"
# menu, as well as on the user registration and login forms and in the
@@ -907,7 +907,7 @@ galaxy:
# The golang proxy needs to know how to talk to your docker daemon.
# Currently TLS is not supported, that will come in an update.
#dynamic_proxy_golang_docker_address: 'unix:///var/run/docker.sock'
#dynamic_proxy_golang_docker_address: unix:///var/run/docker.sock
# The golang proxy uses a RESTful HTTP API for communication with
# Galaxy instead of a JSON or SQLite file for IPC. If you do not
@@ -1041,7 +1041,7 @@ galaxy:
# Heartbeat log filename. Can accept the template variables
# {server_name} and {pid}
#heartbeat_log: 'heartbeat_{server_name}.log'
#heartbeat_log: heartbeat_{server_name}.log
# Log to Sentry Sentry is an open source logging and error aggregation
# platform. Setting sentry_dsn will enable the Sentry middleware and
@@ -1432,6 +1432,18 @@ galaxy:
# to set this on public servers.
#master_api_key: changethis
# Enable authentication via OpenID. Allows users to log in to their
# Galaxy account by authenticating with an OpenID provider.
#enable_openid: false
# If OpenID is enabled, this configuration file specifies providers to
# use. Falls back to the .sample variant in config if default does not
# exist.
#openid_config_file: config/openid_conf.xml
# If OpenID is enabled, consumer cache directory to use.
#openid_consumer_cache_path: database/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.
@@ -1448,7 +1460,7 @@ galaxy:
# The URL to the myExperiment instance being used (omit scheme but
# include port)
#myexperiment_url: 'www.myexperiment.org:80'
#myexperiment_url: www.myexperiment.org:80
# Enable Galaxy's "Upload via FTP" interface. You'll need to install
# and configure an FTP server (we've used ProFTPd since it can use
@@ -1470,7 +1482,7 @@ galaxy:
# Python string template used to determine an FTP upload directory for
# a particular user.
#ftp_upload_dir_template: '${ftp_upload_dir}/${ftp_upload_dir_identifier}'
#ftp_upload_dir_template: ${ftp_upload_dir}/${ftp_upload_dir_identifier
# This should be set to False to prevent Galaxy from deleting uploaded
# FTP files as it imports them.
@@ -1704,22 +1716,22 @@ galaxy:
# Define toolbox filters (https://galaxyproject.org/user-defined-
# toolbox-filters/) that users may use to restrict the tools to
# display.
#user_tool_filters: 'examples:restrict_upload_to_admins, examples:restrict_encode'
#user_tool_filters: examples:restrict_upload_to_admins, examples:restrict_encode
# Define toolbox filters (https://galaxyproject.org/user-defined-
# toolbox-filters/) that users may use to restrict the tool sections
# to display.
#user_tool_section_filters: 'examples:restrict_text'
#user_tool_section_filters: examples:restrict_text
# Define toolbox filters (https://galaxyproject.org/user-defined-
# toolbox-filters/) that users may use to restrict the tool labels to
# display.
#user_tool_label_filters: 'examples:restrict_upload_to_admins, examples:restrict_encode'
#user_tool_label_filters: examples:restrict_upload_to_admins, examples:restrict_encode
# The base module(s) that are searched for modules for toolbox
# filtering (https://galaxyproject.org/user-defined-toolbox-filters/)
# functions.
#toolbox_filter_base_modules: 'galaxy.tools.toolbox.filters,galaxy.tools.filters'
#toolbox_filter_base_modules: galaxy.tools.toolbox.filters,galaxy.tools.filters
# Galaxy uses AMQP internally for communicating between processes.
# For example, when reloading the toolbox or locking job execution,
@@ -1731,13 +1743,13 @@ galaxy:
# not specified either, Galaxy will automatically create and use a
# separate sqlite database located in your <galaxy>/database folder
# (indicated in the commented out line below).
#amqp_internal_connection: 'sqlalchemy+sqlite:///./database/control.sqlite?isolation_level=IMMEDIATE'
#amqp_internal_connection: sqlalchemy+sqlite:///./database/control.sqlite?isolation_level=IMMEDIATE
# Galaxy real time communication server settings
#enable_communication_server: false
# Galaxy real time communication server settings
#communication_server_host: 'http://localhost'
#communication_server_host: http://localhost
# Galaxy real time communication server settings
#communication_server_port: 7070
+5
View File
@@ -0,0 +1,5 @@
<?xml version="1.0"?>
<openid>
<provider file="genomespace.xml" />
<provider file="launchpad.xml" />
</openid>
+1 -1
View File
@@ -95,7 +95,7 @@ reports:
# Galaxy instances, so sqlite (and the default value below) is not
# supported. An SQLAlchemy connection string should be used specify an
# external database.
#database_connection: 'sqlite:///./database/universe.sqlite?isolation_level=IMMEDIATE'
#database_connection: sqlite:///./database/universe.sqlite?isolation_level=IMMEDIATE
# Where dataset files are stored.
#file_path: database/files
+2 -2
View File
@@ -89,7 +89,7 @@ tool_shed:
# string to specify an external database instead. This string takes
# many options which are explained in detail in the config file
# documentation.
#database_connection: 'sqlite:///./database/community.sqlite?isolation_level=IMMEDIATE'
#database_connection: sqlite:///./database/community.sqlite?isolation_level=IMMEDIATE
# Where the hgweb.config file is stored. The default is the Galaxy
# installation directory.
@@ -253,7 +253,7 @@ tool_shed:
#smtp_ssl: false
# The URL linked by the "Support" link in the "Help" menu.
#support_url: 'https://galaxyproject.org/support/'
#support_url: https://galaxyproject.org/support/
# Address to join mailing list
#mailing_join_addr: galaxy-announce-join@bx.psu.edu
+33
View File
@@ -2943,6 +2943,39 @@
:Type: str
~~~~~~~~~~~~~~~~~
``enable_openid``
~~~~~~~~~~~~~~~~~
:Description:
Enable authentication via OpenID. Allows users to log in to their
Galaxy account by authenticating with an OpenID provider.
:Default: ``false``
:Type: bool
~~~~~~~~~~~~~~~~~~~~~~
``openid_config_file``
~~~~~~~~~~~~~~~~~~~~~~
:Description:
If OpenID is enabled, this configuration file specifies providers
to use. Falls back to the .sample variant in config if default
does not exist.
:Default: ``config/openid_conf.xml``
:Type: str
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``openid_consumer_cache_path``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description:
If OpenID is enabled, consumer cache directory to use.
:Default: ``database/openid_consumer_cache``
:Type: str
~~~~~~~~~~~~~~~~~~~~
``enable_tool_tags``
~~~~~~~~~~~~~~~~~~~~
+5
View File
@@ -19,6 +19,7 @@ from galaxy.managers.histories import HistoryManager
from galaxy.managers.libraries import LibraryManager
from galaxy.managers.tools import DynamicToolManager
from galaxy.model.tags import GalaxyTagHandler
from galaxy.openid.providers import OpenIDProviders
from galaxy.queue_worker import GalaxyQueueWorker
from galaxy.tools.cache import (
ToolCache,
@@ -38,6 +39,7 @@ from galaxy.visualization.data_providers.registry import DataProviderRegistry
from galaxy.visualization.genomes import Genomes
from galaxy.visualization.plugins.registry import VisualizationsRegistry
from galaxy.web import url_for
from galaxy.web.framework import openid_manager
from galaxy.web.proxy import ProxyManager
from galaxy.web.stack import application_stack_instance
from galaxy.web.stack.database_heartbeat import DatabaseHeartbeat
@@ -168,6 +170,9 @@ class UniverseApplication(config.ConfiguresGalaxyMixin):
self.quota_agent = galaxy.quota.NoQuotaAgent(self.model)
# Heartbeat for thread profiling
self.heartbeat = None
if self.config.enable_openid:
self.openid_manager = openid_manager.OpenIDManager(self.config.openid_consumer_cache_path)
self.openid_providers = OpenIDProviders.from_file(self.config.openid_config_file)
from galaxy import auth
self.auth_manager = auth.AuthManager(self)
# Start the heartbeat process if configured and available (wait until
+3
View File
@@ -55,6 +55,7 @@ PATH_DEFAULTS = dict(
workflow_resource_params_file=['config/workflow_resource_params_conf.xml', 'workflow_resource_params_conf.xml'],
migrated_tools_config=['migrated_tools_conf.xml', 'config/migrated_tools_conf.xml'],
object_store_config_file=['config/object_store_conf.xml', 'object_store_conf.xml'],
openid_config_file=['config/openid_conf.xml', 'openid_conf.xml', 'config/openid_conf.xml.sample'],
shed_data_manager_config_file=['shed_data_manager_conf.xml', 'config/shed_data_manager_conf.xml'],
shed_tool_data_table_config=['shed_tool_data_table_conf.xml', 'config/shed_tool_data_table_conf.xml'],
tool_sheds_config_file=['config/tool_sheds_conf.xml', 'tool_sheds_conf.xml', 'config/tool_sheds_conf.xml.sample'],
@@ -202,6 +203,7 @@ class Configuration(object):
if override_tempdir:
tempfile.tempdir = self.new_file_path
self.shared_home_dir = kwargs.get("shared_home_dir", None)
self.openid_consumer_cache_path = resolve_path(kwargs.get("openid_consumer_cache_path", "database/openid_consumer_cache"), self.root)
self.cookie_path = kwargs.get("cookie_path", "/")
self.enable_quotas = string_as_bool(kwargs.get('enable_quotas', False))
self.enable_unique_workflow_defaults = string_as_bool(kwargs.get('enable_unique_workflow_defaults', False))
@@ -363,6 +365,7 @@ class Configuration(object):
self.communication_server_host = kwargs.get('communication_server_host', 'http://localhost')
self.communication_server_port = int(kwargs.get('communication_server_port', '7070'))
self.persistent_communication_rooms = listify(kwargs.get("persistent_communication_rooms", []), do_strip=True)
self.enable_openid = string_as_bool(kwargs.get('enable_openid', 'False'))
self.enable_quotas = string_as_bool(kwargs.get('enable_quotas', 'False'))
# Tasked job runner.
self.use_tasked_jobs = string_as_bool(kwargs.get('use_tasked_jobs', False))
+3
View File
@@ -0,0 +1,3 @@
"""
OpenID functionality
"""
+147
View File
@@ -0,0 +1,147 @@
"""
Contains OpenID provider functionality
"""
import logging
import os
import six
from galaxy.util import parse_xml, string_as_bool
from galaxy.util.odict import odict
log = logging.getLogger(__name__)
NO_PROVIDER_ID = 'None'
RESERVED_PROVIDER_IDS = [NO_PROVIDER_ID]
class OpenIDProvider(object):
'''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('Specified OpenID Provider uses a reserved id: %s' % (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(object):
'''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('Failed to load OpenID Providers: %s' % (e))
return cls()
@classmethod
def from_elem(cls, xml_root):
oid_elem = xml_root
providers = odict()
for elem in oid_elem.findall('provider'):
try:
provider = OpenIDProvider.from_file(os.path.join('openid', elem.get('file')))
providers[provider.id] = provider
log.debug('Loaded OpenID provider: %s (%s)' % (provider.name, provider.id))
except Exception as e:
log.error('Failed to add OpenID provider: %s' % (e))
return cls(providers)
def __init__(self, providers=None):
if providers:
self.providers = providers
else:
self.providers = odict()
self._banned_identifiers = [provider.op_endpoint_url for provider in self.providers.values() if provider.never_associate_with_user]
def __iter__(self):
for provider in six.itervalues(self.providers):
yield provider
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)
@@ -0,0 +1,75 @@
"""
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(object):
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(object):
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, 'w'))
return pickle.load(open(session_file))
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, 'w'))
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
@@ -2186,6 +2186,29 @@ mapping:
need to bootstrap Galaxy, you probably do not want to set this on public
servers.
enable_openid:
type: bool
default: false
required: false
desc: |
Enable authentication via OpenID. Allows users to log in to their Galaxy
account by authenticating with an OpenID provider.
openid_config_file:
type: str
default: config/openid_conf.xml
required: false
desc: |
If OpenID is enabled, this configuration file specifies providers to use.
Falls back to the .sample variant in config if default does not exist.
openid_consumer_cache_path:
type: str
default: database/openid_consumer_cache
required: false
desc: |
If OpenID is enabled, consumer cache directory to use.
enable_tool_tags:
type: bool
default: false
@@ -0,0 +1,69 @@
"""
Contains the OpenID interface in the Universe class
"""
import logging
from markupsafe import escape
import galaxy.util
from galaxy import web
from galaxy.web import error, url_for
from galaxy.web.base.controller import BaseUIController
log = logging.getLogger(__name__)
class OpenID(BaseUIController):
@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 = trans.app.openid_manager.get_consumer(trans)
openid_provider = kwd.get('openid_provider', '')
if openid_provider:
openid_provider_obj = trans.app.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 was not specified or 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('No OpenID services are available at %s' % openid_provider_obj.op_endpoint_url)
except Exception as e:
return 'Failed to begin OpenID authentication: %s' % str(e)
if request is not None:
trans.app.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)
trans.app.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'})
trans.app.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'''
if not trans.app.config.enable_openid:
return trans.show_error_message('OpenID authentication is not enabled in this instance of Galaxy')
consumer = trans.app.openid_manager.get_consumer(trans)
info = consumer.complete(kwd, trans.request.url)
display_identifier = info.getDisplayIdentifier()
openid_provider = kwd.get('openid_provider', None)
if info.status == trans.app.openid_manager.FAILURE and display_identifier:
return trans.show_error_message("Login via OpenID failed. The technical reason for this follows, please include this message in your email if you need to %s to resolve this problem: %s" % (contact, info.message))
elif info.status == trans.app.openid_manager.SUCCESS:
if info.endpoint.canonicalID:
display_identifier = info.endpoint.canonicalID
openid_provider_obj = trans.app.openid_providers.get(openid_provider)
openid_provider_obj.post_authentication(trans, trans.app.openid_manager, info)
return trans.show_message("Processed OpenID authentication. Click <a href='%s'>here</a> to return." % url_for("/"))