[2] | 1 | """ |
---|
| 2 | Middleware for handling $REMOTE_USER if use_remote_user is enabled. |
---|
| 3 | """ |
---|
| 4 | |
---|
| 5 | import socket |
---|
| 6 | |
---|
| 7 | errorpage = """ |
---|
| 8 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
---|
| 9 | <html lang="en"> |
---|
| 10 | <head> |
---|
| 11 | <title>Galaxy</title> |
---|
| 12 | <style type="text/css"> |
---|
| 13 | body { |
---|
| 14 | min-width: 500px; |
---|
| 15 | text-align: center; |
---|
| 16 | } |
---|
| 17 | .errormessage { |
---|
| 18 | font: 75%% verdana, "Bitstream Vera Sans", geneva, arial, helvetica, helve, sans-serif; |
---|
| 19 | padding: 10px; |
---|
| 20 | margin: 100px auto; |
---|
| 21 | min-height: 32px; |
---|
| 22 | max-width: 500px; |
---|
| 23 | border: 1px solid #AA6666; |
---|
| 24 | background-color: #FFCCCC; |
---|
| 25 | text-align: left; |
---|
| 26 | } |
---|
| 27 | </style> |
---|
| 28 | </head> |
---|
| 29 | <body> |
---|
| 30 | <div class="errormessage"> |
---|
| 31 | <h4>%s</h4> |
---|
| 32 | <p>%s</p> |
---|
| 33 | </div> |
---|
| 34 | </body> |
---|
| 35 | </html> |
---|
| 36 | """ |
---|
| 37 | |
---|
| 38 | UCSC_MAIN_SERVERS = ( |
---|
| 39 | 'hgw1.cse.ucsc.edu', |
---|
| 40 | 'hgw2.cse.ucsc.edu', |
---|
| 41 | 'hgw3.cse.ucsc.edu', |
---|
| 42 | 'hgw4.cse.ucsc.edu', |
---|
| 43 | 'hgw5.cse.ucsc.edu', |
---|
| 44 | 'hgw6.cse.ucsc.edu', |
---|
| 45 | 'hgw7.cse.ucsc.edu', |
---|
| 46 | 'hgw8.cse.ucsc.edu', |
---|
| 47 | ) |
---|
| 48 | UCSC_ARCHAEA_SERVERS = ( |
---|
| 49 | 'lowepub.cse.ucsc.edu', |
---|
| 50 | ) |
---|
| 51 | |
---|
| 52 | class RemoteUser( object ): |
---|
| 53 | def __init__( self, app, maildomain=None, ucsc_display_sites=[], admin_users=[] ): |
---|
| 54 | self.app = app |
---|
| 55 | self.maildomain = maildomain |
---|
| 56 | self.allow_ucsc_main = False |
---|
| 57 | self.allow_ucsc_archaea = False |
---|
| 58 | self.admin_users = admin_users |
---|
| 59 | if 'main' in ucsc_display_sites or 'test' in ucsc_display_sites: |
---|
| 60 | self.allow_ucsc_main = True |
---|
| 61 | if 'archaea' in ucsc_display_sites: |
---|
| 62 | self.allow_ucsc_archaea = True |
---|
| 63 | def __call__( self, environ, start_response ): |
---|
| 64 | # Allow through UCSC if the UCSC display links are enabled |
---|
| 65 | if ( self.allow_ucsc_main or self.allow_ucsc_archaea ) and environ.has_key( 'REMOTE_ADDR' ): |
---|
| 66 | try: |
---|
| 67 | host = socket.gethostbyaddr( environ[ 'REMOTE_ADDR' ] )[0] |
---|
| 68 | except( socket.error, socket.herror, socket.gaierror, socket.timeout ): |
---|
| 69 | # in the event of a lookup failure, deny access |
---|
| 70 | host = None |
---|
| 71 | if ( self.allow_ucsc_main and host in UCSC_MAIN_SERVERS ) or \ |
---|
| 72 | ( self.allow_ucsc_archaea and host in UCSC_ARCHAEA_SERVERS ): |
---|
| 73 | environ[ 'HTTP_REMOTE_USER' ] = 'ucsc_browser_display@example.org' |
---|
| 74 | return self.app( environ, start_response ) |
---|
| 75 | # Apache sets REMOTE_USER to the string '(null)' when using the |
---|
| 76 | # Rewrite* method for passing REMOTE_USER and a user is |
---|
| 77 | # un-authenticated. Any other possible values need to go here as well. |
---|
| 78 | path_info = environ.get('PATH_INFO', '') |
---|
| 79 | if environ.has_key( 'HTTP_REMOTE_USER' ) and environ[ 'HTTP_REMOTE_USER' ] != '(null)': |
---|
| 80 | if not environ[ 'HTTP_REMOTE_USER' ].count( '@' ): |
---|
| 81 | if self.maildomain is not None: |
---|
| 82 | environ[ 'HTTP_REMOTE_USER' ] += '@' + self.maildomain |
---|
| 83 | else: |
---|
| 84 | title = "Access to Galaxy is denied" |
---|
| 85 | message = """ |
---|
| 86 | Galaxy is configured to authenticate users via an external |
---|
| 87 | method (such as HTTP authentication in Apache), but only a |
---|
| 88 | username (not an email address) was provided by the |
---|
| 89 | upstream (proxy) server. Since Galaxy usernames are email |
---|
| 90 | addresses, a default mail domain must be set.</p> |
---|
| 91 | <p>Please contact your local Galaxy administrator. The |
---|
| 92 | variable <code>remote_user_maildomain</code> must be set |
---|
| 93 | before you may access Galaxy. |
---|
| 94 | """ |
---|
| 95 | return self.error( start_response, title, message ) |
---|
| 96 | if path_info.startswith( '/user/create' ) and environ[ 'HTTP_REMOTE_USER' ] in self.admin_users: |
---|
| 97 | pass # admins can create users |
---|
| 98 | elif path_info.startswith( '/user/api_keys' ): |
---|
| 99 | pass # api keys can be managed when remote_user is in use |
---|
| 100 | elif path_info.startswith( '/user' ): |
---|
| 101 | title = "Access to Galaxy user controls is disabled" |
---|
| 102 | message = """ |
---|
| 103 | User controls are disabled when Galaxy is configured |
---|
| 104 | for external authentication. |
---|
| 105 | """ |
---|
| 106 | return self.error( start_response, title, message ) |
---|
| 107 | return self.app( environ, start_response ) |
---|
| 108 | elif path_info.startswith( '/api/' ): |
---|
| 109 | # The API handles its own authentication via keys |
---|
| 110 | return self.app( environ, start_response ) |
---|
| 111 | else: |
---|
| 112 | title = "Access to Galaxy is denied" |
---|
| 113 | message = """ |
---|
| 114 | Galaxy is configured to authenticate users via an external |
---|
| 115 | method (such as HTTP authentication in Apache), but a username |
---|
| 116 | was not provided by the upstream (proxy) server. This is |
---|
| 117 | generally due to a misconfiguration in the upstream server.</p> |
---|
| 118 | <p>Please contact your local Galaxy administrator. |
---|
| 119 | """ |
---|
| 120 | return self.error( start_response, title, message ) |
---|
| 121 | def error( self, start_response, title="Access denied", message="Please contact your local Galaxy administrator." ): |
---|
| 122 | start_response( '403 Forbidden', [('Content-type', 'text/html')] ) |
---|
| 123 | return [errorpage % (title, message)] |
---|