Warning

This document is for an old release of Galaxy. You can alternatively view this page in the latest release if it exists or view the top of the latest release's documentation.

Source code for tool_shed.webapp.framework.middleware.remoteuser

"""
Middleware for handling $REMOTE_USER if use_remote_user is enabled.
"""
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">
<html lang="en">
    <head>
        <title>Galaxy</title>
        <style type="text/css">
        body {
            min-width: 500px;
            text-align: center;
        }
        .errormessage {
            font: 75%% verdana, "Bitstream Vera Sans", geneva, arial, helvetica, helve, sans-serif;
            padding: 10px;
            margin: 100px auto;
            min-height: 32px;
            max-width: 500px;
            border: 1px solid #AA6666;
            background-color: #FFCCCC;
            text-align: left;
        }
        </style>
    </head>
    <body>
        <div class="errormessage">
            <h4>%s</h4>
            <p>%s</p>
        </div>
    </body>
</html>
"""


[docs]class RemoteUser:
[docs] 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 if self.display_servers and 'REMOTE_ADDR' in environ: try: host = socket.gethostbyaddr(environ['REMOTE_ADDR'])[0] except(OSError, socket.herror, socket.gaierror, socket.timeout): # in the event of a lookup failure, deny access host = None 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', '') if 'HTTP_REMOTE_USER' in environ and environ['HTTP_REMOTE_USER'] != '(null)': if not environ['HTTP_REMOTE_USER'].count('@'): if self.maildomain is not None: environ['HTTP_REMOTE_USER'] += f"@{self.maildomain}" else: title = "Access to this Galaxy tool shed is denied" message = """ This Galaxy tool shed is configured to authenticate users via an external method (such as HTTP authentication in Apache), but only a username (not an email address) was provided by the upstream (proxy) server. Since tool shed usernames are email addresses, a default mail domain must be set.</[> <p>The variable <code>remote_user_maildomain</code> must be set before you can access this tool shed. Contact your local tool shed administrator. """ return self.error(start_response, title, message) return self.app(environ, start_response) elif path_info.startswith('/api/'): # The API handles its own authentication via keys return self.app(environ, start_response) elif path_info.startswith('/user/api_keys'): # api_keys can be managed when remote_user is in use. pass else: title = "Access to this Galaxy tool shed is denied" message = """ This Galaxy tool shed is configured to authenticate users via an external method (such as HTTP authentication in Apache), but a username was not provided by the upstream (proxy) server. This is generally due to a misconfiguration in the upstream server.</p> <p>Contact your local Galaxy tool shed administrator. """ return self.error(start_response, title, message)
[docs] 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)]