galaxy-commits
Threads by month
- ----- 2026 -----
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
January 2015
- 2 participants
- 248 discussions
commit/galaxy-central: jmchilton: Attempt to fix bug introduced in 08f8850853d004bf8a456a147436a669.
by commits-noreply@bitbucket.org 05 Jan '15
by commits-noreply@bitbucket.org 05 Jan '15
05 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e34bf92384b6/
Changeset: e34bf92384b6
User: jmchilton
Date: 2015-01-05 15:05:46+00:00
Summary: Attempt to fix bug introduced in 08f8850853d004bf8a456a147436a669.
Thanks to Nicola for the bug report (https://bitbucket.org/galaxy/galaxy-central/commits/08f8850853d004bf8a456a1…)
Affected #: 1 file
diff -r 4e60046a38c4bf79c77e5232856208b7e52dc162 -r e34bf92384b6a6722657d83833fb52268865126d lib/galaxy/tools/toolbox/base.py
--- a/lib/galaxy/tools/toolbox/base.py
+++ b/lib/galaxy/tools/toolbox/base.py
@@ -483,8 +483,8 @@
return[ self._tools_by_id[ tool_id ] ]
return None
- def has_tool( self, tool_id, exact=False ):
- return self.get_tool( tool_id, exact=exact ) is not None
+ def has_tool( self, tool_id, tool_version=None, exact=False ):
+ return self.get_tool( tool_id, tool_version=tool_version, exact=exact ) is not None
def get_tool_id( self, tool_id ):
""" Take a tool id (potentially from a different Galaxy instance or that
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Slight modification to prevent unintentional (safe and unused, but still) reassignment of parameter 'value' in loop.
by commits-noreply@bitbucket.org 05 Jan '15
by commits-noreply@bitbucket.org 05 Jan '15
05 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4e60046a38c4/
Changeset: 4e60046a38c4
User: dannon
Date: 2015-01-05 14:06:01+00:00
Summary: Slight modification to prevent unintentional (safe and unused, but still) reassignment of parameter 'value' in loop.
Affected #: 1 file
diff -r f55708c39129ab2b293edb7ec54faa85506d2800 -r 4e60046a38c4bf79c77e5232856208b7e52dc162 lib/tool_shed/util/web_util.py
--- a/lib/tool_shed/util/web_util.py
+++ b/lib/tool_shed/util/web_util.py
@@ -4,7 +4,7 @@
ALLOWED_MAP = dict(map(lambda x: (x, raw_escape(x)), ALLOWED_ELEMENTS))
-def escape( value ):
+def escape( string ):
""" A tool shed variant of markupsafe.escape that allows a select few
HTML elements that are repeatedly used in messages created deep
in the toolshed components. Ideally abstract things would be produced
@@ -14,7 +14,7 @@
>>> escape("A <b>repo</b>")
u'A <b>repo</b>'
"""
- escaped = str( raw_escape( value ) )
+ escaped = str( raw_escape( string ) )
# Unescape few selected tags.
for key, value in ALLOWED_MAP.iteritems():
escaped = escaped.replace(value, key)
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Update tag latest_2014.10.06 for changeset 793d9cd5f9de
by commits-noreply@bitbucket.org 05 Jan '15
by commits-noreply@bitbucket.org 05 Jan '15
05 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/dff4071c13f9/
Changeset: dff4071c13f9
Branch: stable
User: natefoo
Date: 2015-01-05 14:00:18+00:00
Summary: Update tag latest_2014.10.06 for changeset 793d9cd5f9de
Affected #: 1 file
diff -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 -r dff4071c13f9b2908556583227766c65fcfb8a29 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -20,4 +20,4 @@
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
548ab24667d6206780237bd807f7d857a484c461 latest_2014.08.11
2092948937ac30ef82f71463a235c66d34987088 release_2014.10.06
-5834b1066462dd219f67c1c3cbd77c78e7cf3a6c latest_2014.10.06
+793d9cd5f9dec66ceafb36bc38f53453457056e6 latest_2014.10.06
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/13f767186d5e/
Changeset: 13f767186d5e
Branch: next-stable
User: dannon
Date: 2015-01-05 13:56:20+00:00
Summary: Merge stable.
Affected #: 3 files
diff -r 93a868eb314d257c21bb19380b360bcf0d8dd82c -r 13f767186d5e281a9d647f8e497d6aca48d03417 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -20,4 +20,4 @@
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
548ab24667d6206780237bd807f7d857a484c461 latest_2014.08.11
2092948937ac30ef82f71463a235c66d34987088 release_2014.10.06
-7086b87d83a9092cbece0fec6f3e3ed03266be0c latest_2014.10.06
+5834b1066462dd219f67c1c3cbd77c78e7cf3a6c latest_2014.10.06
https://bitbucket.org/galaxy/galaxy-central/commits/f55708c39129/
Changeset: f55708c39129
User: dannon
Date: 2015-01-05 13:56:37+00:00
Summary: Merge next-stable.
Affected #: 3 files
diff -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 -r f55708c39129ab2b293edb7ec54faa85506d2800 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -20,4 +20,4 @@
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
548ab24667d6206780237bd807f7d857a484c461 latest_2014.08.11
2092948937ac30ef82f71463a235c66d34987088 release_2014.10.06
-7086b87d83a9092cbece0fec6f3e3ed03266be0c latest_2014.10.06
+5834b1066462dd219f67c1c3cbd77c78e7cf3a6c latest_2014.10.06
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Fixes for over escaping in c2bed0a.
by commits-noreply@bitbucket.org 05 Jan '15
by commits-noreply@bitbucket.org 05 Jan '15
05 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/793d9cd5f9de/
Changeset: 793d9cd5f9de
Branch: stable
User: jmchilton
Date: 2014-12-27 22:30:59+00:00
Summary: Fixes for over escaping in c2bed0a.
Fixes dozens of tool functional tests.
Affected #: 9 files
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -7,7 +7,7 @@
from galaxy.web.form_builder import CheckboxField
from string import punctuation as PUNCTUATION
import galaxy.queue_worker
-from markupsafe import escape
+from tool_shed.util.web_util import escape
from tool_shed.util import shed_util_common as suc
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/galaxy/webapps/galaxy/controllers/admin.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin.py
@@ -17,7 +17,7 @@
from galaxy.web.params import QuotaParamParser
from tool_shed.util import common_util
from tool_shed.util import encoding_util
-from markupsafe import escape
+from tool_shed.util.web_util import escape
log = logging.getLogger( __name__ )
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -8,9 +8,9 @@
from galaxy.web.form_builder import CheckboxField
from galaxy.util import json
from galaxy.model.orm import or_
-from markupsafe import escape
import tool_shed.repository_types.util as rt_util
+from tool_shed.util.web_util import escape
from tool_shed.util import common_util
from tool_shed.util import encoding_util
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/galaxy/webapps/tool_shed/controllers/admin.py
--- a/lib/galaxy/webapps/tool_shed/controllers/admin.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/admin.py
@@ -3,7 +3,7 @@
from galaxy import util
from galaxy.util import inflector
from galaxy import web
-from markupsafe import escape
+from tool_shed.util.web_util import escape
from galaxy.web.base.controller import BaseUIController
from galaxy.web.base.controllers.admin import Admin
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -6,7 +6,6 @@
from time import strftime
from datetime import date
from datetime import datetime
-from markupsafe import escape
from galaxy import util
from galaxy import web
@@ -19,6 +18,7 @@
from tool_shed.capsule import capsule_manager
from tool_shed.dependencies.repository import relation_builder
+from tool_shed.util.web_util import escape
from tool_shed.galaxy_install import dependency_display
from tool_shed.metadata import repository_metadata_manager
from tool_shed.utility_containers import ToolShedUtilityContainerManager
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/galaxy/webapps/tool_shed/controllers/repository_review.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository_review.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository_review.py
@@ -2,7 +2,7 @@
import os
from sqlalchemy.sql.expression import func
-from markupsafe import escape
+from tool_shed.util.web_util import escape
from galaxy import util
from galaxy import web
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/galaxy/webapps/tool_shed/controllers/upload.py
--- a/lib/galaxy/webapps/tool_shed/controllers/upload.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/upload.py
@@ -9,7 +9,7 @@
from galaxy import web
from galaxy.datatypes import checkers
from galaxy.web.base.controller import BaseUIController
-from markupsafe import escape
+from tool_shed.util.web_util import escape
from tool_shed.dependencies import attribute_handlers
from tool_shed.galaxy_install import dependency_display
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/tool_shed/util/repository_util.py
--- a/lib/tool_shed/util/repository_util.py
+++ b/lib/tool_shed/util/repository_util.py
@@ -7,7 +7,7 @@
from galaxy import web
from galaxy.web.form_builder import build_select_field
from galaxy.webapps.tool_shed.model import directory_hash_id
-from markupsafe import escape
+from tool_shed.util.web_util import escape
from tool_shed.dependencies.repository import relation_builder
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 793d9cd5f9dec66ceafb36bc38f53453457056e6 lib/tool_shed/util/web_util.py
--- /dev/null
+++ b/lib/tool_shed/util/web_util.py
@@ -0,0 +1,21 @@
+from markupsafe import escape as raw_escape
+
+ALLOWED_ELEMENTS = ["<b>", "</b>", "<br/>"]
+ALLOWED_MAP = dict(map(lambda x: (x, raw_escape(x)), ALLOWED_ELEMENTS))
+
+
+def escape( value ):
+ """ A tool shed variant of markupsafe.escape that allows a select few
+ HTML elements that are repeatedly used in messages created deep
+ in the toolshed components. Ideally abstract things would be produced
+ in these components and messages in the views or client side - this is
+ what should be worked toward - but for now - we have this hack.
+
+ >>> escape("A <b>repo</b>")
+ u'A <b>repo</b>'
+ """
+ escaped = str( raw_escape( value ) )
+ # Unescape few selected tags.
+ for key, value in ALLOWED_MAP.iteritems():
+ escaped = escaped.replace(value, key)
+ return escaped
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Merged in erasche2/galaxy-central2 (pull request #619)
by commits-noreply@bitbucket.org 01 Jan '15
by commits-noreply@bitbucket.org 01 Jan '15
01 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ac1859e27eb0/
Changeset: ac1859e27eb0
User: jmchilton
Date: 2015-01-01 19:16:50+00:00
Summary: Merged in erasche2/galaxy-central2 (pull request #619)
Allow for shared secret between Galaxy and upstream proxies
Affected #: 9 files
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 config/galaxy.ini.sample
--- a/config/galaxy.ini.sample
+++ b/config/galaxy.ini.sample
@@ -713,6 +713,13 @@
# *not* include 'HTTP_' at the beginning of the header name.
#remote_user_header = HTTP_REMOTE_USER
+# If use_remote_user is enabled, anyone who can log in to the Galaxy host may
+# impersonate any other user by simply sending the appropriate header. Thus a
+# secret shared between the upstream proxy server, and Galaxy is required.
+# If anyone other than the Galaxy user is using the server, then apache/nginx should
+# pass a value in the header 'GX_SECRET' that is identical the one below
+#remote_user_secret = USING THE DEFAULT IS NOT SECURE!
+
# If use_remote_user is enabled, you can set this to a URL that will log your
# users out.
#remote_user_logout_href = None
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 config/tool_shed.ini.sample
--- a/config/tool_shed.ini.sample
+++ b/config/tool_shed.ini.sample
@@ -67,6 +67,13 @@
# https://wiki.galaxyproject.org/Admin/Config/ApacheProxy
#use_remote_user = False
+# If use_remote_user is enabled, anyone who can log in to the Galaxy host may
+# impersonate any other user by simply sending the appropriate header. Thus a
+# secret shared between the upstream proxy server, and Galaxy is required.
+# If anyone other than the Galaxy user is using the server, then apache/nginx should
+# pass a value in the header 'GX_SECRET' that is identical the one below
+#remote_user_secret = changethisinproductiontoo
+
# Configuration for debugging middleware
debug = true
use_lint = false
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -133,6 +133,7 @@
self.remote_user_maildomain = kwargs.get( "remote_user_maildomain", None )
self.remote_user_header = kwargs.get( "remote_user_header", 'HTTP_REMOTE_USER' )
self.remote_user_logout_href = kwargs.get( "remote_user_logout_href", None )
+ self.remote_user_secret = kwargs.get( "remote_user_secret", None )
self.require_login = string_as_bool( kwargs.get( "require_login", "False" ) )
self.allow_user_creation = string_as_bool( kwargs.get( "allow_user_creation", "True" ) )
self.allow_user_deletion = string_as_bool( kwargs.get( "allow_user_deletion", "False" ) )
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/util/__init__.py
--- a/lib/galaxy/util/__init__.py
+++ b/lib/galaxy/util/__init__.py
@@ -1119,6 +1119,8 @@
def safe_str_cmp(a, b):
+ """safely compare two strings in a timing-attack-resistant manner
+ """
if len(a) != len(b):
return False
rv = 0
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/web/framework/middleware/remoteuser.py
--- a/lib/galaxy/web/framework/middleware/remoteuser.py
+++ b/lib/galaxy/web/framework/middleware/remoteuser.py
@@ -3,6 +3,7 @@
"""
import socket
+from galaxy.util import safe_str_cmp
errorpage = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
@@ -37,12 +38,13 @@
class RemoteUser( object ):
- def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_header=None ):
+ def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_header=None, remote_user_secret_header=None ):
self.app = app
self.maildomain = maildomain
self.display_servers = display_servers or []
self.admin_users = admin_users or []
self.remote_user_header = remote_user_header or 'HTTP_REMOTE_USER'
+ self.config_secret_header = remote_user_secret_header
def __call__( self, environ, start_response ):
# Allow display servers
@@ -59,6 +61,34 @@
# Rewrite* method for passing REMOTE_USER and a user is
# un-authenticated. Any other possible values need to go here as well.
path_info = environ.get('PATH_INFO', '')
+
+ # If the secret header is enabled, we expect upstream to send along some key
+ # in HTTP_GX_SECRET, so we'll need to compare that here to the correct value
+ #
+ # This is not an ideal location for this function. The reason being
+ # that because this check is done BEFORE the REMOTE_USER check, it is
+ # possible to attack the GX_SECRET key without having correct
+ # credentials. However, that's why it's not "ideal", but it is "good
+ # enough". The only users able to exploit this are ones with access to
+ # the local system (unless Galaxy is listening on 0.0.0.0....). It
+ # seems improbable that an attacker with access to the server hosting
+ # Galaxy would not have access to Galaxy itself, and be attempting to
+ # attack the system
+ if self.config_secret_header is not None:
+ if not safe_str_cmp(environ.get('HTTP_GX_SECRET'), self.config_secret_header):
+ title = "Access to Galaxy is denied"
+ message = """
+ Galaxy is configured to authenticate users via an external
+ method (such as HTTP authentication in Apache), but an
+ incorrect shared secret key was provided by the
+ upstream (proxy) server.</p>
+ <p>Please contact your local Galaxy administrator. The
+ variable <code>remote_user_secret</code> and
+ <code>GX_SECRET</code> header must be set before you may
+ access Galaxy.
+ """
+ return self.error( start_response, title, message )
+
if not environ.get(self.remote_user_header, '(null)').startswith('(null)'):
if not environ[ self.remote_user_header ].count( '@' ):
if self.maildomain is not None:
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -503,8 +503,8 @@
app = RemoteUser( app, maildomain = conf.get( 'remote_user_maildomain', None ),
display_servers = util.listify( conf.get( 'display_servers', '' ) ),
admin_users = conf.get( 'admin_users', '' ).split( ',' ),
- remote_user_header = conf.get( 'remote_user_header', 'HTTP_REMOTE_USER' ) )
- log.debug( "Enabling 'remote user' middleware" )
+ remote_user_header = conf.get( 'remote_user_header', 'HTTP_REMOTE_USER' ),
+ remote_user_secret_header = conf.get('remote_user_secret', None) )
# The recursive middleware allows for including requests in other
# requests or forwarding of requests, all on the server side.
if asbool(conf.get('use_recursive', True)):
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/webapps/tool_shed/buildapp.py
--- a/lib/galaxy/webapps/tool_shed/buildapp.py
+++ b/lib/galaxy/webapps/tool_shed/buildapp.py
@@ -157,7 +157,8 @@
from galaxy.webapps.tool_shed.framework.middleware.remoteuser import RemoteUser
app = RemoteUser( app, maildomain = conf.get( 'remote_user_maildomain', None ),
display_servers = util.listify( conf.get( 'display_servers', '' ) ),
- admin_users = conf.get( 'admin_users', '' ).split( ',' ) )
+ admin_users = conf.get( 'admin_users', '' ).split( ',' ),
+ remote_user_secret_header = conf.get('remote_user_secret', None) )
log.debug( "Enabling 'remote user' middleware" )
# The recursive middleware allows for including requests in other
# requests or forwarding of requests, all on the server side.
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/webapps/tool_shed/config.py
--- a/lib/galaxy/webapps/tool_shed/config.py
+++ b/lib/galaxy/webapps/tool_shed/config.py
@@ -73,6 +73,7 @@
self.remote_user_maildomain = kwargs.get( "remote_user_maildomain", None )
self.remote_user_header = kwargs.get( "remote_user_header", 'HTTP_REMOTE_USER' )
self.remote_user_logout_href = kwargs.get( "remote_user_logout_href", None )
+ self.remote_user_secret = kwargs.get( "remote_user_secret", None )
self.require_login = string_as_bool( kwargs.get( "require_login", "False" ) )
self.allow_user_creation = string_as_bool( kwargs.get( "allow_user_creation", "True" ) )
self.allow_user_deletion = string_as_bool( kwargs.get( "allow_user_deletion", "False" ) )
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
--- a/lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
+++ b/lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
@@ -3,6 +3,7 @@
"""
import socket
+from galaxy.util import safe_str_cmp
errorpage = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
@@ -36,11 +37,13 @@
"""
class RemoteUser( object ):
- def __init__( self, app, maildomain=None, display_servers=None, admin_users=None ):
+ def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_secret_header=None ):
self.app = app
self.maildomain = maildomain
self.display_servers = display_servers or []
self.admin_users = admin_users or []
+ self.config_secret_header = remote_user_secret_header
+
def __call__( self, environ, start_response ):
environ[ 'webapp' ] = 'tool_shed'
# Allow display servers
@@ -53,6 +56,34 @@
if host in self.display_servers:
environ[ 'HTTP_REMOTE_USER' ] = 'remote_display_server@%s' % ( self.maildomain or 'example.org' )
return self.app( environ, start_response )
+
+ # If the secret header is enabled, we expect upstream to send along some key
+ # in HTTP_GX_SECRET, so we'll need to compare that here to the correct value
+ #
+ # This is not an ideal location for this function. The reason being
+ # that because this check is done BEFORE the REMOTE_USER check, it is
+ # possible to attack the GX_SECRET key without having correct
+ # credentials. However, that's why it's not "ideal", but it is "good
+ # enough". The only users able to exploit this are ones with access to
+ # the local system (unless Galaxy is listening on 0.0.0.0....). It
+ # seems improbable that an attacker with access to the server hosting
+ # Galaxy would not have access to Galaxy itself, and be attempting to
+ # attack the system
+ if self.config_secret_header is not None:
+ if not safe_str_cmp(environ.get('HTTP_GX_SECRET'), self.config_secret_header):
+ title = "Access to Galaxy is denied"
+ message = """
+ Galaxy is configured to authenticate users via an external
+ method (such as HTTP authentication in Apache), but an
+ incorrect shared secret key was provided by the
+ upstream (proxy) server.</p>
+ <p>Please contact your local Galaxy administrator. The
+ variable <code>remote_user_secret</code> and
+ <code>GX_SECRET</code> header must be set before you may
+ access Galaxy.
+ """
+ return self.error( start_response, title, message )
+
# Apache sets REMOTE_USER to the string '(null)' when using the Rewrite* method for passing REMOTE_USER and a user is
# un-authenticated. Any other possible values need to go here as well.
path_info = environ.get('PATH_INFO', '')
@@ -88,6 +119,7 @@
<p>Contact your local Galaxy tool shed administrator.
"""
return self.error( start_response, title, message )
+
def error( self, start_response, title="Access denied", message="Contact your local Galaxy tool shed administrator." ):
start_response( '403 Forbidden', [('Content-type', 'text/html')] )
return [errorpage % (title, message)]
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7a889340aba7/
Changeset: 7a889340aba7
User: erasche2
Date: 2014-12-17 21:25:07+00:00
Summary: Allow for shared secret between Galaxy and upstream proxies
This prevents an impersonation attack available on Galaxies with command line
users and REMOTE_USER authentication. It is not uncommon to run Galaxy on a
"lab server" (or similar), where there are command line users in addition to
the Galaxy service. With REMOTE_USER authentication, Galaxy blindly (and
correctly) trusts the upstream value of REMOTE_USER, enabling such attacks as:
curl -H "REMOTE_USER: admin.user(a)domain.edu" http://localhost:8000/galaxy/
This changest adds a shared secret between Galaxy and the upstream proxy,
thereby preventing that attack. Only requests from the upstream proxy with the
correct secret key are recognised, everything else is tossed out with a 403
Forbidden.
This was implemented as part of the REMOTE_USER stack as the situation only
applies if that middleware is in use.
Affected #: 9 files
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 config/galaxy.ini.sample
--- a/config/galaxy.ini.sample
+++ b/config/galaxy.ini.sample
@@ -713,6 +713,13 @@
# *not* include 'HTTP_' at the beginning of the header name.
#remote_user_header = HTTP_REMOTE_USER
+# If use_remote_user is enabled, anyone who can log in to the Galaxy host may
+# impersonate any other user by simply sending the appropriate header. Thus a
+# secret shared between the upstream proxy server, and Galaxy is required.
+# If anyone other than the Galaxy user is using the server, then apache/nginx should
+# pass a value in the header 'GX_SECRET' that is identical the one below
+#remote_user_secret = USING THE DEFAULT IS NOT SECURE!
+
# If use_remote_user is enabled, you can set this to a URL that will log your
# users out.
#remote_user_logout_href = None
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 config/tool_shed.ini.sample
--- a/config/tool_shed.ini.sample
+++ b/config/tool_shed.ini.sample
@@ -67,6 +67,13 @@
# https://wiki.galaxyproject.org/Admin/Config/ApacheProxy
#use_remote_user = False
+# If use_remote_user is enabled, anyone who can log in to the Galaxy host may
+# impersonate any other user by simply sending the appropriate header. Thus a
+# secret shared between the upstream proxy server, and Galaxy is required.
+# If anyone other than the Galaxy user is using the server, then apache/nginx should
+# pass a value in the header 'GX_SECRET' that is identical the one below
+#remote_user_secret = changethisinproductiontoo
+
# Configuration for debugging middleware
debug = true
use_lint = false
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -132,6 +132,7 @@
self.remote_user_maildomain = kwargs.get( "remote_user_maildomain", None )
self.remote_user_header = kwargs.get( "remote_user_header", 'HTTP_REMOTE_USER' )
self.remote_user_logout_href = kwargs.get( "remote_user_logout_href", None )
+ self.remote_user_secret = kwargs.get( "remote_user_secret", None )
self.require_login = string_as_bool( kwargs.get( "require_login", "False" ) )
self.allow_user_creation = string_as_bool( kwargs.get( "allow_user_creation", "True" ) )
self.allow_user_deletion = string_as_bool( kwargs.get( "allow_user_deletion", "False" ) )
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 lib/galaxy/util/__init__.py
--- a/lib/galaxy/util/__init__.py
+++ b/lib/galaxy/util/__init__.py
@@ -1119,6 +1119,8 @@
def safe_str_cmp(a, b):
+ """safely compare two strings in a timing-attack-resistant manner
+ """
if len(a) != len(b):
return False
rv = 0
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 lib/galaxy/web/framework/middleware/remoteuser.py
--- a/lib/galaxy/web/framework/middleware/remoteuser.py
+++ b/lib/galaxy/web/framework/middleware/remoteuser.py
@@ -3,6 +3,7 @@
"""
import socket
+from galaxy.util import safe_str_cmp
errorpage = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
@@ -37,12 +38,13 @@
class RemoteUser( object ):
- def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_header=None ):
+ def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_header=None, remote_user_secret_header=None ):
self.app = app
self.maildomain = maildomain
self.display_servers = display_servers or []
self.admin_users = admin_users or []
self.remote_user_header = remote_user_header or 'HTTP_REMOTE_USER'
+ self.config_secret_header = remote_user_secret_header
def __call__( self, environ, start_response ):
# Allow display servers
@@ -59,6 +61,34 @@
# Rewrite* method for passing REMOTE_USER and a user is
# un-authenticated. Any other possible values need to go here as well.
path_info = environ.get('PATH_INFO', '')
+
+ # If the secret header is enabled, we expect upstream to send along some key
+ # in HTTP_GX_SECRET, so we'll need to compare that here to the correct value
+ #
+ # This is not an ideal location for this function. The reason being
+ # that because this check is done BEFORE the REMOTE_USER check, it is
+ # possible to attack the GX_SECRET key without having correct
+ # credentials. However, that's why it's not "ideal", but it is "good
+ # enough". The only users able to exploit this are ones with access to
+ # the local system (unless Galaxy is listening on 0.0.0.0....). It
+ # seems improbable that an attacker with access to the server hosting
+ # Galaxy would not have acess to Galaxy itself, and be attempting to
+ # attack the system
+ if self.config_secret_header is not None:
+ if not safe_str_cmp(environ.get('HTTP_GX_SECRET'), self.config_secret_header):
+ title = "Access to Galaxy is denied"
+ message = """
+ Galaxy is configured to authenticate users via an external
+ method (such as HTTP authentication in Apache), but an
+ incorrect shared secret key was provided by the
+ upstream (proxy) server.</p>
+ <p>Please contact your local Galaxy administrator. The
+ variable <code>remote_user_secret</code> and
+ <code>GX_SECRET</code> header must be set before you may
+ access Galaxy.
+ """
+ return self.error( start_response, title, message )
+
if not environ.get(self.remote_user_header, '(null)').startswith('(null)'):
if not environ[ self.remote_user_header ].count( '@' ):
if self.maildomain is not None:
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -503,8 +503,8 @@
app = RemoteUser( app, maildomain = conf.get( 'remote_user_maildomain', None ),
display_servers = util.listify( conf.get( 'display_servers', '' ) ),
admin_users = conf.get( 'admin_users', '' ).split( ',' ),
- remote_user_header = conf.get( 'remote_user_header', 'HTTP_REMOTE_USER' ) )
- log.debug( "Enabling 'remote user' middleware" )
+ remote_user_header = conf.get( 'remote_user_header', 'HTTP_REMOTE_USER' ),
+ remote_user_secret_header = conf.get('remote_user_secret', None) )
# The recursive middleware allows for including requests in other
# requests or forwarding of requests, all on the server side.
if asbool(conf.get('use_recursive', True)):
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 lib/galaxy/webapps/tool_shed/buildapp.py
--- a/lib/galaxy/webapps/tool_shed/buildapp.py
+++ b/lib/galaxy/webapps/tool_shed/buildapp.py
@@ -157,7 +157,8 @@
from galaxy.webapps.tool_shed.framework.middleware.remoteuser import RemoteUser
app = RemoteUser( app, maildomain = conf.get( 'remote_user_maildomain', None ),
display_servers = util.listify( conf.get( 'display_servers', '' ) ),
- admin_users = conf.get( 'admin_users', '' ).split( ',' ) )
+ admin_users = conf.get( 'admin_users', '' ).split( ',' ),
+ remote_user_secret_header = conf.get('remote_user_secret', None) )
log.debug( "Enabling 'remote user' middleware" )
# The recursive middleware allows for including requests in other
# requests or forwarding of requests, all on the server side.
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 lib/galaxy/webapps/tool_shed/config.py
--- a/lib/galaxy/webapps/tool_shed/config.py
+++ b/lib/galaxy/webapps/tool_shed/config.py
@@ -83,6 +83,7 @@
self.remote_user_maildomain = kwargs.get( "remote_user_maildomain", None )
self.remote_user_header = kwargs.get( "remote_user_header", 'HTTP_REMOTE_USER' )
self.remote_user_logout_href = kwargs.get( "remote_user_logout_href", None )
+ self.remote_user_secret = kwargs.get( "remote_user_secret", None )
self.require_login = string_as_bool( kwargs.get( "require_login", "False" ) )
self.allow_user_creation = string_as_bool( kwargs.get( "allow_user_creation", "True" ) )
self.allow_user_deletion = string_as_bool( kwargs.get( "allow_user_deletion", "False" ) )
diff -r 5e5c0cf930bb96bf8af0bd19daad1a999b40c374 -r 7a889340aba7e078d31963aa99139c7ddaea07c2 lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
--- a/lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
+++ b/lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
@@ -3,6 +3,7 @@
"""
import socket
+from galaxy.util import safe_str_cmp
errorpage = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
@@ -36,11 +37,13 @@
"""
class RemoteUser( object ):
- def __init__( self, app, maildomain=None, display_servers=None, admin_users=None ):
+ def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_secret_header=None ):
self.app = app
self.maildomain = maildomain
self.display_servers = display_servers or []
self.admin_users = admin_users or []
+ self.config_secret_header = remote_user_secret_header
+
def __call__( self, environ, start_response ):
environ[ 'webapp' ] = 'tool_shed'
# Allow display servers
@@ -53,6 +56,34 @@
if host in self.display_servers:
environ[ 'HTTP_REMOTE_USER' ] = 'remote_display_server@%s' % ( self.maildomain or 'example.org' )
return self.app( environ, start_response )
+
+ # If the secret header is enabled, we expect upstream to send along some key
+ # in HTTP_GX_SECRET, so we'll need to compare that here to the correct value
+ #
+ # This is not an ideal location for this function. The reason being
+ # that because this check is done BEFORE the REMOTE_USER check, it is
+ # possible to attack the GX_SECRET key without having correct
+ # credentials. However, that's why it's not "ideal", but it is "good
+ # enough". The only users able to exploit this are ones with access to
+ # the local system (unless Galaxy is listening on 0.0.0.0....). It
+ # seems improbable that an attacker with access to the server hosting
+ # Galaxy would not have acess to Galaxy itself, and be attempting to
+ # attack the system
+ if self.config_secret_header is not None:
+ if not safe_str_cmp(environ.get('HTTP_GX_SECRET'), self.config_secret_header):
+ title = "Access to Galaxy is denied"
+ message = """
+ Galaxy is configured to authenticate users via an external
+ method (such as HTTP authentication in Apache), but an
+ incorrect shared secret key was provided by the
+ upstream (proxy) server.</p>
+ <p>Please contact your local Galaxy administrator. The
+ variable <code>remote_user_secret</code> and
+ <code>GX_SECRET</code> header must be set before you may
+ access Galaxy.
+ """
+ return self.error( start_response, title, message )
+
# Apache sets REMOTE_USER to the string '(null)' when using the Rewrite* method for passing REMOTE_USER and a user is
# un-authenticated. Any other possible values need to go here as well.
path_info = environ.get('PATH_INFO', '')
@@ -88,6 +119,7 @@
<p>Contact your local Galaxy tool shed administrator.
"""
return self.error( start_response, title, message )
+
def error( self, start_response, title="Access denied", message="Contact your local Galaxy tool shed administrator." ):
start_response( '403 Forbidden', [('Content-type', 'text/html')] )
return [errorpage % (title, message)]
https://bitbucket.org/galaxy/galaxy-central/commits/b7deaa9fb8b7/
Changeset: b7deaa9fb8b7
User: erasche2
Date: 2014-12-18 19:43:00+00:00
Summary: Fixed typos in documentation
Affected #: 2 files
diff -r 7a889340aba7e078d31963aa99139c7ddaea07c2 -r b7deaa9fb8b7cadd141fd07b2c50654716c88720 lib/galaxy/web/framework/middleware/remoteuser.py
--- a/lib/galaxy/web/framework/middleware/remoteuser.py
+++ b/lib/galaxy/web/framework/middleware/remoteuser.py
@@ -72,7 +72,7 @@
# enough". The only users able to exploit this are ones with access to
# the local system (unless Galaxy is listening on 0.0.0.0....). It
# seems improbable that an attacker with access to the server hosting
- # Galaxy would not have acess to Galaxy itself, and be attempting to
+ # Galaxy would not have access to Galaxy itself, and be attempting to
# attack the system
if self.config_secret_header is not None:
if not safe_str_cmp(environ.get('HTTP_GX_SECRET'), self.config_secret_header):
diff -r 7a889340aba7e078d31963aa99139c7ddaea07c2 -r b7deaa9fb8b7cadd141fd07b2c50654716c88720 lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
--- a/lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
+++ b/lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
@@ -67,7 +67,7 @@
# enough". The only users able to exploit this are ones with access to
# the local system (unless Galaxy is listening on 0.0.0.0....). It
# seems improbable that an attacker with access to the server hosting
- # Galaxy would not have acess to Galaxy itself, and be attempting to
+ # Galaxy would not have access to Galaxy itself, and be attempting to
# attack the system
if self.config_secret_header is not None:
if not safe_str_cmp(environ.get('HTTP_GX_SECRET'), self.config_secret_header):
https://bitbucket.org/galaxy/galaxy-central/commits/ac1859e27eb0/
Changeset: ac1859e27eb0
User: jmchilton
Date: 2015-01-01 19:16:50+00:00
Summary: Merged in erasche2/galaxy-central2 (pull request #619)
Allow for shared secret between Galaxy and upstream proxies
Affected #: 9 files
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 config/galaxy.ini.sample
--- a/config/galaxy.ini.sample
+++ b/config/galaxy.ini.sample
@@ -713,6 +713,13 @@
# *not* include 'HTTP_' at the beginning of the header name.
#remote_user_header = HTTP_REMOTE_USER
+# If use_remote_user is enabled, anyone who can log in to the Galaxy host may
+# impersonate any other user by simply sending the appropriate header. Thus a
+# secret shared between the upstream proxy server, and Galaxy is required.
+# If anyone other than the Galaxy user is using the server, then apache/nginx should
+# pass a value in the header 'GX_SECRET' that is identical the one below
+#remote_user_secret = USING THE DEFAULT IS NOT SECURE!
+
# If use_remote_user is enabled, you can set this to a URL that will log your
# users out.
#remote_user_logout_href = None
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 config/tool_shed.ini.sample
--- a/config/tool_shed.ini.sample
+++ b/config/tool_shed.ini.sample
@@ -67,6 +67,13 @@
# https://wiki.galaxyproject.org/Admin/Config/ApacheProxy
#use_remote_user = False
+# If use_remote_user is enabled, anyone who can log in to the Galaxy host may
+# impersonate any other user by simply sending the appropriate header. Thus a
+# secret shared between the upstream proxy server, and Galaxy is required.
+# If anyone other than the Galaxy user is using the server, then apache/nginx should
+# pass a value in the header 'GX_SECRET' that is identical the one below
+#remote_user_secret = changethisinproductiontoo
+
# Configuration for debugging middleware
debug = true
use_lint = false
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -133,6 +133,7 @@
self.remote_user_maildomain = kwargs.get( "remote_user_maildomain", None )
self.remote_user_header = kwargs.get( "remote_user_header", 'HTTP_REMOTE_USER' )
self.remote_user_logout_href = kwargs.get( "remote_user_logout_href", None )
+ self.remote_user_secret = kwargs.get( "remote_user_secret", None )
self.require_login = string_as_bool( kwargs.get( "require_login", "False" ) )
self.allow_user_creation = string_as_bool( kwargs.get( "allow_user_creation", "True" ) )
self.allow_user_deletion = string_as_bool( kwargs.get( "allow_user_deletion", "False" ) )
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/util/__init__.py
--- a/lib/galaxy/util/__init__.py
+++ b/lib/galaxy/util/__init__.py
@@ -1119,6 +1119,8 @@
def safe_str_cmp(a, b):
+ """safely compare two strings in a timing-attack-resistant manner
+ """
if len(a) != len(b):
return False
rv = 0
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/web/framework/middleware/remoteuser.py
--- a/lib/galaxy/web/framework/middleware/remoteuser.py
+++ b/lib/galaxy/web/framework/middleware/remoteuser.py
@@ -3,6 +3,7 @@
"""
import socket
+from galaxy.util import safe_str_cmp
errorpage = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
@@ -37,12 +38,13 @@
class RemoteUser( object ):
- def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_header=None ):
+ def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_header=None, remote_user_secret_header=None ):
self.app = app
self.maildomain = maildomain
self.display_servers = display_servers or []
self.admin_users = admin_users or []
self.remote_user_header = remote_user_header or 'HTTP_REMOTE_USER'
+ self.config_secret_header = remote_user_secret_header
def __call__( self, environ, start_response ):
# Allow display servers
@@ -59,6 +61,34 @@
# Rewrite* method for passing REMOTE_USER and a user is
# un-authenticated. Any other possible values need to go here as well.
path_info = environ.get('PATH_INFO', '')
+
+ # If the secret header is enabled, we expect upstream to send along some key
+ # in HTTP_GX_SECRET, so we'll need to compare that here to the correct value
+ #
+ # This is not an ideal location for this function. The reason being
+ # that because this check is done BEFORE the REMOTE_USER check, it is
+ # possible to attack the GX_SECRET key without having correct
+ # credentials. However, that's why it's not "ideal", but it is "good
+ # enough". The only users able to exploit this are ones with access to
+ # the local system (unless Galaxy is listening on 0.0.0.0....). It
+ # seems improbable that an attacker with access to the server hosting
+ # Galaxy would not have access to Galaxy itself, and be attempting to
+ # attack the system
+ if self.config_secret_header is not None:
+ if not safe_str_cmp(environ.get('HTTP_GX_SECRET'), self.config_secret_header):
+ title = "Access to Galaxy is denied"
+ message = """
+ Galaxy is configured to authenticate users via an external
+ method (such as HTTP authentication in Apache), but an
+ incorrect shared secret key was provided by the
+ upstream (proxy) server.</p>
+ <p>Please contact your local Galaxy administrator. The
+ variable <code>remote_user_secret</code> and
+ <code>GX_SECRET</code> header must be set before you may
+ access Galaxy.
+ """
+ return self.error( start_response, title, message )
+
if not environ.get(self.remote_user_header, '(null)').startswith('(null)'):
if not environ[ self.remote_user_header ].count( '@' ):
if self.maildomain is not None:
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -503,8 +503,8 @@
app = RemoteUser( app, maildomain = conf.get( 'remote_user_maildomain', None ),
display_servers = util.listify( conf.get( 'display_servers', '' ) ),
admin_users = conf.get( 'admin_users', '' ).split( ',' ),
- remote_user_header = conf.get( 'remote_user_header', 'HTTP_REMOTE_USER' ) )
- log.debug( "Enabling 'remote user' middleware" )
+ remote_user_header = conf.get( 'remote_user_header', 'HTTP_REMOTE_USER' ),
+ remote_user_secret_header = conf.get('remote_user_secret', None) )
# The recursive middleware allows for including requests in other
# requests or forwarding of requests, all on the server side.
if asbool(conf.get('use_recursive', True)):
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/webapps/tool_shed/buildapp.py
--- a/lib/galaxy/webapps/tool_shed/buildapp.py
+++ b/lib/galaxy/webapps/tool_shed/buildapp.py
@@ -157,7 +157,8 @@
from galaxy.webapps.tool_shed.framework.middleware.remoteuser import RemoteUser
app = RemoteUser( app, maildomain = conf.get( 'remote_user_maildomain', None ),
display_servers = util.listify( conf.get( 'display_servers', '' ) ),
- admin_users = conf.get( 'admin_users', '' ).split( ',' ) )
+ admin_users = conf.get( 'admin_users', '' ).split( ',' ),
+ remote_user_secret_header = conf.get('remote_user_secret', None) )
log.debug( "Enabling 'remote user' middleware" )
# The recursive middleware allows for including requests in other
# requests or forwarding of requests, all on the server side.
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/webapps/tool_shed/config.py
--- a/lib/galaxy/webapps/tool_shed/config.py
+++ b/lib/galaxy/webapps/tool_shed/config.py
@@ -73,6 +73,7 @@
self.remote_user_maildomain = kwargs.get( "remote_user_maildomain", None )
self.remote_user_header = kwargs.get( "remote_user_header", 'HTTP_REMOTE_USER' )
self.remote_user_logout_href = kwargs.get( "remote_user_logout_href", None )
+ self.remote_user_secret = kwargs.get( "remote_user_secret", None )
self.require_login = string_as_bool( kwargs.get( "require_login", "False" ) )
self.allow_user_creation = string_as_bool( kwargs.get( "allow_user_creation", "True" ) )
self.allow_user_deletion = string_as_bool( kwargs.get( "allow_user_deletion", "False" ) )
diff -r 84d5a72790735ae4da03f27735c52182bb925d9b -r ac1859e27eb0217ae5dabd7495a3b9314f65a1f7 lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
--- a/lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
+++ b/lib/galaxy/webapps/tool_shed/framework/middleware/remoteuser.py
@@ -3,6 +3,7 @@
"""
import socket
+from galaxy.util import safe_str_cmp
errorpage = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
@@ -36,11 +37,13 @@
"""
class RemoteUser( object ):
- def __init__( self, app, maildomain=None, display_servers=None, admin_users=None ):
+ def __init__( self, app, maildomain=None, display_servers=None, admin_users=None, remote_user_secret_header=None ):
self.app = app
self.maildomain = maildomain
self.display_servers = display_servers or []
self.admin_users = admin_users or []
+ self.config_secret_header = remote_user_secret_header
+
def __call__( self, environ, start_response ):
environ[ 'webapp' ] = 'tool_shed'
# Allow display servers
@@ -53,6 +56,34 @@
if host in self.display_servers:
environ[ 'HTTP_REMOTE_USER' ] = 'remote_display_server@%s' % ( self.maildomain or 'example.org' )
return self.app( environ, start_response )
+
+ # If the secret header is enabled, we expect upstream to send along some key
+ # in HTTP_GX_SECRET, so we'll need to compare that here to the correct value
+ #
+ # This is not an ideal location for this function. The reason being
+ # that because this check is done BEFORE the REMOTE_USER check, it is
+ # possible to attack the GX_SECRET key without having correct
+ # credentials. However, that's why it's not "ideal", but it is "good
+ # enough". The only users able to exploit this are ones with access to
+ # the local system (unless Galaxy is listening on 0.0.0.0....). It
+ # seems improbable that an attacker with access to the server hosting
+ # Galaxy would not have access to Galaxy itself, and be attempting to
+ # attack the system
+ if self.config_secret_header is not None:
+ if not safe_str_cmp(environ.get('HTTP_GX_SECRET'), self.config_secret_header):
+ title = "Access to Galaxy is denied"
+ message = """
+ Galaxy is configured to authenticate users via an external
+ method (such as HTTP authentication in Apache), but an
+ incorrect shared secret key was provided by the
+ upstream (proxy) server.</p>
+ <p>Please contact your local Galaxy administrator. The
+ variable <code>remote_user_secret</code> and
+ <code>GX_SECRET</code> header must be set before you may
+ access Galaxy.
+ """
+ return self.error( start_response, title, message )
+
# Apache sets REMOTE_USER to the string '(null)' when using the Rewrite* method for passing REMOTE_USER and a user is
# un-authenticated. Any other possible values need to go here as well.
path_info = environ.get('PATH_INFO', '')
@@ -88,6 +119,7 @@
<p>Contact your local Galaxy tool shed administrator.
"""
return self.error( start_response, title, message )
+
def error( self, start_response, title="Access denied", message="Contact your local Galaxy tool shed administrator." ):
start_response( '403 Forbidden', [('Content-type', 'text/html')] )
return [errorpage % (title, message)]
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a8cf78bd3629/
Changeset: a8cf78bd3629
User: jmchilton
Date: 2015-01-01 15:02:23+00:00
Summary: PEP-8 fix for lib/tool_shed/tools/tool_version_manager.py.
Affected #: 1 file
diff -r bb548455022c7ad21c74ba61b4fe37b606737db7 -r a8cf78bd3629e4d9fa28e2641b670efb78ba2a56 lib/tool_shed/tools/tool_version_manager.py
--- a/lib/tool_shed/tools/tool_version_manager.py
+++ b/lib/tool_shed/tools/tool_version_manager.py
@@ -1,5 +1,4 @@
import logging
-import os
from galaxy.model.orm import and_
https://bitbucket.org/galaxy/galaxy-central/commits/81a99e6f570e/
Changeset: 81a99e6f570e
User: jmchilton
Date: 2015-01-01 15:02:23+00:00
Summary: Unit test to verify tool panel handles multiple successive TS install...
In particular that the integrated panel reflects all the installed tools but that they are groupped correctly in ToolBox._tool_panel.
Affected #: 3 files
diff -r a8cf78bd3629e4d9fa28e2641b670efb78ba2a56 -r 81a99e6f570ef0b0cb6511bfd9ee4dd767490fef test/unit/tool_shed_unit_tests/test_tool_panel_manager.py
--- a/test/unit/tool_shed_unit_tests/test_tool_panel_manager.py
+++ b/test/unit/tool_shed_unit_tests/test_tool_panel_manager.py
@@ -5,6 +5,10 @@
from tools.test_toolbox import BaseToolBoxTestCase
from tool_shed.galaxy_install.tools import tool_panel_manager
+from tool_shed.tools import tool_version_manager
+
+DEFAULT_GUID = "123456"
+
class ToolPanelManagerTestCase( BaseToolBoxTestCase ):
@@ -34,15 +38,14 @@
assert len( toolbox._tool_panel ) == 2
def test_add_tool_to_panel( self ):
- self._init_tool()
- self._add_config( """<toolbox tool_path="%s"></toolbox>""" % self.test_directory )
- tool_path = os.path.join(self.test_directory, "tool.xml")
- self.tool.guid = "123456"
- new_tools = [{"guid": "123456", "tool_config": tool_path}]
+ self._init_ts_tool( guid=DEFAULT_GUID )
+ self._init_dynamic_tool_conf()
+ tool_path = self._tool_path()
+ new_tools = [{"guid": DEFAULT_GUID, "tool_config": tool_path}]
repository_tools_tups = [
(
tool_path,
- "123456",
+ DEFAULT_GUID,
self.tool,
)
]
@@ -63,6 +66,51 @@
)
self._verify_tool_confs()
+ def test_add_twice( self ):
+ self._init_dynamic_tool_conf()
+ tool_versions = {}
+ previous_guid = None
+ for v in "1", "2", "3":
+ changeset = "0123456789abcde%s" % v
+ guid = DEFAULT_GUID + ("v%s" % v)
+ tool = self._init_ts_tool( guid=guid, filename="tool_v%s.xml" % v )
+ tool_path = self._tool_path( name="tool_v%s.xml" % v )
+ new_tools = [{"guid": guid, "tool_config": tool_path}]
+ tool_shed_repository = self._repo_install( changeset )
+ repository_tools_tups = [
+ (
+ tool_path,
+ guid,
+ tool,
+ )
+ ]
+ _, section = self.toolbox.get_section("tid1", create_if_needed=True)
+ tpm = self.tpm
+ tool_panel_dict = tpm.generate_tool_panel_dict_for_new_install(
+ tool_dicts=new_tools,
+ tool_section=section,
+ )
+ if previous_guid:
+ tool_versions[ guid ] = previous_guid
+ self.tvm.handle_tool_versions( [tool_versions], tool_shed_repository )
+ tpm.add_to_tool_panel(
+ repository_name="example",
+ repository_clone_url="github.com",
+ changeset_revision=changeset,
+ repository_tools_tups=repository_tools_tups,
+ owner="galaxyproject",
+ shed_tool_conf="tool_conf.xml",
+ tool_panel_dict=tool_panel_dict,
+ )
+ self._verify_tool_confs()
+ section = self.toolbox._tool_panel["tid1"]
+ # New GUID replaced old one in tool panel but both
+ # appear in integrated tool panel.
+ if previous_guid:
+ assert ("tool_%s" % previous_guid) not in section.panel_items()
+ assert ("tool_%s" % guid) in self.toolbox._integrated_tool_panel["tid1"].panel_items()
+ previous_guid = guid
+
def test_deactivate_in_section( self ):
self._setup_two_versions_remove_one( section=True, uninstall=False )
self._verify_version_2_removed_from_panel( )
@@ -154,6 +202,19 @@
message = message_template % ( filename, open( filename, "r" ).read() )
raise AssertionError( message )
+ def _init_dynamic_tool_conf( self ):
+ # Add a dynamic tool conf (such as a ToolShed managed one) to list of configs.
+ self._add_config( """<toolbox tool_path="%s"></toolbox>""" % self.test_directory )
+
+ def _init_ts_tool( self, guid=DEFAULT_GUID, **kwds ):
+ tool = self._init_tool( **kwds )
+ tool.guid = guid
+ return tool
+
@property
def tpm( self ):
return tool_panel_manager.ToolPanelManager( self.app )
+
+ @property
+ def tvm( self ):
+ return tool_version_manager.ToolVersionManager( self.app )
diff -r a8cf78bd3629e4d9fa28e2641b670efb78ba2a56 -r 81a99e6f570ef0b0cb6511bfd9ee4dd767490fef test/unit/tools/test_toolbox.py
--- a/test/unit/tools/test_toolbox.py
+++ b/test/unit/tools/test_toolbox.py
@@ -123,6 +123,10 @@
path = os.path.join( self.test_directory, name )
return path
+ def _tool_path( self, name="tool.xml" ):
+ path = os.path.join( self.test_directory, name )
+ return path
+
def __reindex( self ):
self.reindexed = True
diff -r a8cf78bd3629e4d9fa28e2641b670efb78ba2a56 -r 81a99e6f570ef0b0cb6511bfd9ee4dd767490fef test/unit/tools_support.py
--- a/test/unit/tools_support.py
+++ b/test/unit/tools_support.py
@@ -72,7 +72,7 @@
contents_template = string.Template( tool_contents )
tool_contents = contents_template.safe_substitute( dict( version=version ) )
self.__write_tool( tool_contents )
- self.__setup_tool( )
+ return self.__setup_tool( )
def _init_app_for_tools( self ):
self.app.config.drmaa_external_runjob_script = ""
@@ -85,6 +85,7 @@
self.tool = Tool( self.tool_file, tool_source, self.app )
if getattr( self, "tool_action", None ):
self.tool.tool_action = self.tool_action
+ return self.tool
def __write_tool( self, contents ):
open( self.tool_file, "w" ).write( contents )
https://bitbucket.org/galaxy/galaxy-central/commits/d3484078d199/
Changeset: d3484078d199
User: jmchilton
Date: 2015-01-01 15:02:23+00:00
Summary: Tweak InstallManger handle_repository_contents to clarify...
... that this method is only used within this class.
Affected #: 1 file
diff -r 81a99e6f570ef0b0cb6511bfd9ee4dd767490fef -r d3484078d199cedc593d64e651a7c8c2d51d5f75 lib/tool_shed/galaxy_install/install_manager.py
--- a/lib/tool_shed/galaxy_install/install_manager.py
+++ b/lib/tool_shed/galaxy_install/install_manager.py
@@ -501,8 +501,8 @@
repo_info_dicts = [ repo_info_dict ]
return repository_revision_dict, repo_info_dicts
- def handle_repository_contents( self, tool_shed_repository, tool_path, repository_clone_url, relative_install_dir,
- tool_shed=None, tool_section=None, shed_tool_conf=None, reinstalling=False ):
+ def __handle_repository_contents( self, tool_shed_repository, tool_path, repository_clone_url, relative_install_dir,
+ tool_shed=None, tool_section=None, shed_tool_conf=None, reinstalling=False ):
"""
Generate the metadata for the installed tool shed repository, among other things.
This method is called when an administrator is installing a new repository or
@@ -839,14 +839,14 @@
create=False )
hg_util.pull_repository( repo, repository_clone_url, current_changeset_revision )
hg_util.update_repository( repo, ctx_rev=current_ctx_rev )
- self.handle_repository_contents( tool_shed_repository=tool_shed_repository,
- tool_path=tool_path,
- repository_clone_url=repository_clone_url,
- relative_install_dir=relative_install_dir,
- tool_shed=tool_shed_repository.tool_shed,
- tool_section=tool_section,
- shed_tool_conf=shed_tool_conf,
- reinstalling=reinstalling )
+ self.__handle_repository_contents( tool_shed_repository=tool_shed_repository,
+ tool_path=tool_path,
+ repository_clone_url=repository_clone_url,
+ relative_install_dir=relative_install_dir,
+ tool_shed=tool_shed_repository.tool_shed,
+ tool_section=tool_section,
+ shed_tool_conf=shed_tool_conf,
+ reinstalling=reinstalling )
self.install_model.context.refresh( tool_shed_repository )
metadata = tool_shed_repository.metadata
if 'tools' in metadata:
https://bitbucket.org/galaxy/galaxy-central/commits/84d5a7279073/
Changeset: 84d5a7279073
User: jmchilton
Date: 2015-01-01 15:02:23+00:00
Summary: Bugfix: Populte tool lineage stuff prior to install.
During tool shed tool installs populate lineage information in tool shed install database prior to adding tool to the tool panel so that the lineage information may be used to group tools. Previously I believe these tools would only be correctly groupped after restarting Galaxy.
Affected #: 1 file
diff -r d3484078d199cedc593d64e651a7c8c2d51d5f75 -r 84d5a72790735ae4da03f27735c52182bb925d9b lib/tool_shed/galaxy_install/install_manager.py
--- a/lib/tool_shed/galaxy_install/install_manager.py
+++ b/lib/tool_shed/galaxy_install/install_manager.py
@@ -40,6 +40,8 @@
log = logging.getLogger( __name__ )
+FAILED_TO_FETCH_VERSIONS = object()
+
class InstallToolDependencyManager( object ):
@@ -502,7 +504,8 @@
return repository_revision_dict, repo_info_dicts
def __handle_repository_contents( self, tool_shed_repository, tool_path, repository_clone_url, relative_install_dir,
- tool_shed=None, tool_section=None, shed_tool_conf=None, reinstalling=False ):
+ tool_shed=None, tool_section=None, shed_tool_conf=None, reinstalling=False,
+ tool_versions_response=None ):
"""
Generate the metadata for the installed tool shed repository, among other things.
This method is called when an administrator is installing a new repository or
@@ -530,6 +533,10 @@
tool_shed_repository.tool_shed_status = tool_shed_status_dict
self.install_model.context.add( tool_shed_repository )
self.install_model.context.flush()
+ if tool_versions_response and tool_versions_response is not FAILED_TO_FETCH_VERSIONS:
+ tool_version_dicts = tool_versions_response
+ tvm = tool_version_manager.ToolVersionManager( self.app )
+ tvm.handle_tool_versions( tool_version_dicts, tool_shed_repository )
if 'tool_dependencies' in irmm_metadata_dict and not reinstalling:
tool_dependency_util.create_tool_dependency_objects( self.app,
tool_shed_repository,
@@ -839,6 +846,7 @@
create=False )
hg_util.pull_repository( repo, repository_clone_url, current_changeset_revision )
hg_util.update_repository( repo, ctx_rev=current_ctx_rev )
+ tool_versions_response = fetch_tool_versions( self.app, tool_shed_repository )
self.__handle_repository_contents( tool_shed_repository=tool_shed_repository,
tool_path=tool_path,
repository_clone_url=repository_clone_url,
@@ -846,6 +854,7 @@
tool_shed=tool_shed_repository.tool_shed,
tool_section=tool_section,
shed_tool_conf=shed_tool_conf,
+ tool_versions_response=tool_versions_response,
reinstalling=reinstalling )
self.install_model.context.refresh( tool_shed_repository )
metadata = tool_shed_repository.metadata
@@ -853,18 +862,7 @@
# Get the tool_versions from the tool shed for each tool in the installed change set.
self.update_tool_shed_repository_status( tool_shed_repository,
self.install_model.ToolShedRepository.installation_status.SETTING_TOOL_VERSIONS )
- tool_shed_url = common_util.get_tool_shed_url_from_tool_shed_registry( self.app, str( tool_shed_repository.tool_shed ) )
- params = '?name=%s&owner=%s&changeset_revision=%s' % ( str( tool_shed_repository.name ),
- str( tool_shed_repository.owner ),
- str( tool_shed_repository.changeset_revision ) )
- url = common_util.url_join( tool_shed_url,
- '/repository/get_tool_versions%s' % params )
- text = common_util.tool_shed_get( self.app, tool_shed_url, url )
- if text:
- tool_version_dicts = json.loads( text )
- tvm = tool_version_manager.ToolVersionManager( self.app )
- tvm.handle_tool_versions( tool_version_dicts, tool_shed_repository )
- else:
+ if tool_versions_response is FAILED_TO_FETCH_VERSIONS:
if not error_message:
error_message = ""
error_message += "Version information for the tools included in the <b>%s</b> repository is missing. " % tool_shed_repository.name
@@ -958,3 +956,27 @@
tool_shed_repository.error_message = str( error_message )
self.install_model.context.add( tool_shed_repository )
self.install_model.context.flush()
+
+
+def fetch_tool_versions( app, tool_shed_repository ):
+ """ Fetch a data structure describing tool shed versions from the tool shed
+ corresponding to a tool_shed_repository object.
+ """
+ failed_to_fetch = False
+ try:
+ tool_shed_url = common_util.get_tool_shed_url_from_tool_shed_registry( app, str( tool_shed_repository.tool_shed ) )
+ params = '?name=%s&owner=%s&changeset_revision=%s' % ( str( tool_shed_repository.name ),
+ str( tool_shed_repository.owner ),
+ str( tool_shed_repository.changeset_revision ) )
+ url = common_util.url_join( tool_shed_url,
+ '/repository/get_tool_versions%s' % params )
+ text = common_util.tool_shed_get( app, tool_shed_url, url )
+ if text:
+ return json.loads( text )
+ else:
+ failed_to_fetch = True
+ except Exception:
+ failed_to_fetch = True
+ if failed_to_fetch:
+ log.exception("Failed to fetch tool shed repository verion information.")
+ return FAILED_TO_FETCH_VERSIONS
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0