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)] |
---|