1
|
import os
|
2
|
import re
|
3
|
import urllib
|
4
|
import base64
|
5
|
|
6
|
from quixote import get_publisher, get_request
|
7
|
|
8
|
from qommon import get_cfg
|
9
|
|
10
|
from larpe.hosts import Host
|
11
|
from larpe.Defaults import APP_DIR, APACHE_MAIN_VHOST, APACHE_VHOST_COMMON, APACHE_RELOAD
|
12
|
|
13
|
def write_apache2_vhosts():
|
14
|
hosts = Host.select(lambda x: x.name != 'larpe')
|
15
|
hosts.sort()
|
16
|
vhosts_dir = os.path.join(APP_DIR, 'vhosts.d')
|
17
|
vhost_locations_dir = os.path.join(APP_DIR, 'vhost-locations.d')
|
18
|
vhosts_dir_disabled = os.path.join(APP_DIR, 'vhosts.d.disabled')
|
19
|
vhost_locations_dir_disabled = os.path.join(APP_DIR, 'vhost-locations.d.disabled')
|
20
|
vhost_file_name = get_request().get_server().split(':')[0]
|
21
|
vhost_file = None
|
22
|
reversed_hostname = ''
|
23
|
vhost = None
|
24
|
|
25
|
if get_publisher().cfg.get(str('allow_config_generation'), True):
|
26
|
vhost_file = open(os.path.join(vhosts_dir, vhost_file_name), 'w')
|
27
|
locations_file = open(os.path.join(vhost_locations_dir, vhost_file_name), 'w')
|
28
|
else:
|
29
|
vhost_file = open(os.path.join(vhosts_dir_disabled, vhost_file_name), 'w')
|
30
|
locations_file = open(os.path.join(vhost_locations_dir_disabled, vhost_file_name), 'w')
|
31
|
try:
|
32
|
main_vhost = open(APACHE_MAIN_VHOST, 'r')
|
33
|
file_content = main_vhost.read()
|
34
|
regexp = re.compile('<VirtualHost (.*?)>')
|
35
|
vhost_ip = regexp.findall(file_content)[0]
|
36
|
except (IOError, IndexError):
|
37
|
vhost_ip = '*'
|
38
|
|
39
|
for host in hosts:
|
40
|
if host.orig_site is None:
|
41
|
# This site hasn't been fully configured
|
42
|
continue
|
43
|
if host.reversed_hostname != reversed_hostname \
|
44
|
and host.reversed_hostname != get_cfg('proxy_hostname'):
|
45
|
if vhost is not None:
|
46
|
vhost.close()
|
47
|
vhost = Vhost(host, vhost_ip)
|
48
|
vhost.write(vhost_file)
|
49
|
reversed_hostname = host.reversed_hostname
|
50
|
|
51
|
if host.reversed_hostname == get_cfg('proxy_hostname'):
|
52
|
conf_file = locations_file
|
53
|
else:
|
54
|
conf_file = vhost_file
|
55
|
|
56
|
Location(host).write(conf_file)
|
57
|
|
58
|
if vhost_file is not None:
|
59
|
if vhost is not None:
|
60
|
vhost.close()
|
61
|
vhost_file.close()
|
62
|
if locations_file is not None:
|
63
|
locations_file.close()
|
64
|
|
65
|
if get_publisher().cfg.get(str('allow_config_generation'), True):
|
66
|
os.system(APACHE_RELOAD)
|
67
|
|
68
|
|
69
|
class Vhost(object):
|
70
|
def __init__(self, host, main_ip_port):
|
71
|
self.host = host
|
72
|
self.main_ip_port = main_ip_port
|
73
|
self.conf_file = None
|
74
|
|
75
|
def get_ip_port(self):
|
76
|
if self.host.scheme == 'https':
|
77
|
return self.main_ip_port.replace(':80', ':443')
|
78
|
else:
|
79
|
return self.main_ip_port.replace(':443', ':80')
|
80
|
ip_port = property(get_ip_port)
|
81
|
|
82
|
def get_proxy_url(self):
|
83
|
if get_cfg('proxy', {}).get('enabled') and self.host.use_proxy == True:
|
84
|
return 'http://%(ip)s:%(port)s' % get_cfg('proxy', {})
|
85
|
return None
|
86
|
proxy_url = property(get_proxy_url)
|
87
|
|
88
|
def get_proxy_auth(self):
|
89
|
if self.get_proxy_url() and get_cfg('proxy', {}).get('user'):
|
90
|
credentials = base64.encodestring(
|
91
|
'%(user)s:%(password)s' % get_cfg('proxy', {}))[:-1]
|
92
|
return '"Basic %s"' % credentials
|
93
|
return None
|
94
|
proxy_auth = property(get_proxy_auth)
|
95
|
|
96
|
def get_cfg(self):
|
97
|
return { 'ip_port': self.ip_port,
|
98
|
'reversed_hostname': self.host.reversed_hostname,
|
99
|
'proxy_url': self.proxy_url,
|
100
|
'proxy_auth': self.proxy_auth }
|
101
|
cfg = property(get_cfg)
|
102
|
|
103
|
def write(self, conf_file):
|
104
|
self.conf_file = conf_file
|
105
|
conf_lines = []
|
106
|
# Start Virtual Host
|
107
|
conf_lines.append('<VirtualHost %(ip_port)s>' % self.cfg)
|
108
|
# Server name and administrator
|
109
|
conf_lines.append('ServerName %(reversed_hostname)s' % self.cfg)
|
110
|
conf_lines.append('# ServerAdmin root@localhost\n')
|
111
|
# Include common vhost configuration
|
112
|
conf_lines.append('include %s\n' % APACHE_VHOST_COMMON)
|
113
|
# SSL
|
114
|
if self.host.scheme == 'https':
|
115
|
conf_lines.append('SSLEngine On\n')
|
116
|
if self.host.orig_site.startswith('https'):
|
117
|
conf_lines.append('SSLProxyEngine On\n')
|
118
|
# Remote proxy configuration
|
119
|
if self.proxy_url is not None:
|
120
|
conf_lines.append('ProxyRemote * %(proxy_url)s' % self.cfg)
|
121
|
if self.proxy_auth is not None:
|
122
|
conf_lines.append(
|
123
|
'RequestHeader set Proxy-Authorization %(proxy_auth)s\n' % self.cfg)
|
124
|
# Write it all
|
125
|
conf_file.write('\n\t'.join(conf_lines))
|
126
|
|
127
|
def close(self):
|
128
|
if self.conf_file:
|
129
|
self.conf_file.write('</VirtualHost>\n\n')
|
130
|
|
131
|
|
132
|
def apache_escape_chars(url):
|
133
|
special_characters = ('\\', '.', '?', '*', '+', '^', '$', '|', '(', ')', '[', ']')
|
134
|
for char in special_characters:
|
135
|
url = url.replace(char, '\%s' % char)
|
136
|
return url
|
137
|
|
138
|
class Location(object):
|
139
|
def __init__(self, host):
|
140
|
self.host = host
|
141
|
|
142
|
def get_reversed_directory(self):
|
143
|
if not self.host.reversed_directory:
|
144
|
return '%s/' % get_request().environ['SCRIPT_NAME']
|
145
|
else:
|
146
|
return '%s/%s/' % (get_request().environ['SCRIPT_NAME'], self.host.reversed_directory)
|
147
|
reversed_directory = property(get_reversed_directory)
|
148
|
|
149
|
def get_python_path(self):
|
150
|
if self.host.apache_output_python_filters and \
|
151
|
self.host.apache_python_paths:
|
152
|
python_path = 'PythonPath "sys.path'
|
153
|
for path in self.host.apache_python_paths:
|
154
|
python_path += "+['%s']" % path
|
155
|
python_path += '"'
|
156
|
return python_path
|
157
|
else:
|
158
|
return None
|
159
|
python_path = property(get_python_path)
|
160
|
|
161
|
def get_output_filters(self):
|
162
|
python_filters = ''
|
163
|
output_filters = []
|
164
|
if self.host.apache_output_python_filters:
|
165
|
i = 0
|
166
|
for filter_file in self.host.apache_output_python_filters:
|
167
|
filter_name = 'filter%d' % i
|
168
|
python_filters += 'PythonOutputFilter %s %s\n\t\t' % (filter_file, filter_name)
|
169
|
output_filters.append(filter_name)
|
170
|
i += 1
|
171
|
if self.host.apache_output_filters:
|
172
|
for output_filter in self.host.apache_output_filters:
|
173
|
output_filters.append(output_filter)
|
174
|
if output_filters:
|
175
|
return python_filters + 'SetOutputFilter ' + ';'.join(output_filters)
|
176
|
else:
|
177
|
return None
|
178
|
output_filters = property(get_output_filters)
|
179
|
|
180
|
def get_old_auth_url(self):
|
181
|
old_auth_url = None
|
182
|
if self.host.initiate_sso_url:
|
183
|
old_auth_url = self.host.initiate_sso_url
|
184
|
elif self.host.auth_url is not None:
|
185
|
if self.host.auth_url.startswith('http://'):
|
186
|
chars_to_skip = 5
|
187
|
else:
|
188
|
chars_to_skip = 6
|
189
|
regexp = re.compile(self.host.orig_site[chars_to_skip:])
|
190
|
old_auth_url_short = regexp.sub('', self.host.auth_url[chars_to_skip:])
|
191
|
if old_auth_url_short.startswith('/'):
|
192
|
old_auth_url = old_auth_url_short
|
193
|
else:
|
194
|
old_auth_url = '/' + old_auth_url_short
|
195
|
if old_auth_url:
|
196
|
old_auth_url = apache_escape_chars(old_auth_url)
|
197
|
return old_auth_url
|
198
|
old_auth_url = property(get_old_auth_url)
|
199
|
|
200
|
def get_new_auth_url(self):
|
201
|
if not hasattr(self.host, 'base_url'):
|
202
|
return None
|
203
|
base_url_tokens = self.host.base_url.split('/')
|
204
|
base_url_tokens[-1] = 'login'
|
205
|
return '/'.join(base_url_tokens)
|
206
|
new_auth_url = property(get_new_auth_url)
|
207
|
|
208
|
def get_old_logout_url(self):
|
209
|
old_logout_url = None
|
210
|
if self.host.logout_url is not None:
|
211
|
if self.host.logout_url.startswith('http://'):
|
212
|
chars_to_skip = 5
|
213
|
else:
|
214
|
chars_to_skip = 6
|
215
|
regexp = re.compile(self.host.orig_site[chars_to_skip:])
|
216
|
old_logout_url_short = regexp.sub('', self.host.logout_url[chars_to_skip:])
|
217
|
if old_logout_url_short.startswith('/'):
|
218
|
old_logout_url = old_logout_url_short
|
219
|
else:
|
220
|
old_logout_url = '/' + old_logout_url_short
|
221
|
old_logout_url = apache_escape_chars(old_logout_url)
|
222
|
return old_logout_url
|
223
|
old_logout_url = property(get_old_logout_url)
|
224
|
|
225
|
def get_new_logout_url(self):
|
226
|
if not hasattr(self.host, 'base_url'):
|
227
|
return None
|
228
|
base_url_tokens = self.host.base_url.split('/')
|
229
|
base_url_tokens[-1] = 'logout'
|
230
|
return '/'.join(base_url_tokens)
|
231
|
new_logout_url = property(get_new_logout_url)
|
232
|
|
233
|
def get_orig_site_url_and_dir(self):
|
234
|
# Split url
|
235
|
if self.host.orig_site.startswith('http://'):
|
236
|
orig_host, orig_query = urllib.splithost(self.host.orig_site[5:])
|
237
|
else:
|
238
|
orig_host, orig_query = urllib.splithost(self.host.orig_site[6:])
|
239
|
# Add a trailing slash if necessary
|
240
|
if self.host.orig_site.endswith('/'):
|
241
|
orig_url = self.host.orig_site
|
242
|
orig_dir = orig_query
|
243
|
else:
|
244
|
orig_url = self.host.orig_site + '/'
|
245
|
orig_dir = orig_query + '/'
|
246
|
return orig_url, orig_dir
|
247
|
|
248
|
def get_orig_url(self):
|
249
|
orig_url, orig_dir = self.get_orig_site_url_and_dir()
|
250
|
return orig_url
|
251
|
orig_url = property(get_orig_url)
|
252
|
|
253
|
def get_orig_dir(self):
|
254
|
orig_url, orig_dir = self.get_orig_site_url_and_dir()
|
255
|
return orig_dir
|
256
|
orig_dir = property(get_orig_dir)
|
257
|
|
258
|
def get_cfg(self):
|
259
|
return { 'reversed_directory': self.reversed_directory,
|
260
|
'old_auth_url': self.old_auth_url,
|
261
|
'new_auth_url': self.new_auth_url,
|
262
|
'old_logout_url': self.old_logout_url,
|
263
|
'new_logout_url': self.new_logout_url,
|
264
|
'orig_url': self.orig_url,
|
265
|
'orig_dir': self.orig_dir }
|
266
|
cfg = property(get_cfg)
|
267
|
|
268
|
def write(self, conf_file):
|
269
|
conf_lines = []
|
270
|
# Start Location
|
271
|
conf_lines.append('\n\t<Location %(reversed_directory)s>' % self.cfg)
|
272
|
# No user restriction
|
273
|
conf_lines.append('Allow from all')
|
274
|
# Apache output filters
|
275
|
if self.python_path:
|
276
|
conf_lines.append(self.python_path)
|
277
|
if self.output_filters:
|
278
|
conf_lines.append(self.output_filters)
|
279
|
# Redirect rules
|
280
|
# Redirect old authentication url to the new one
|
281
|
if self.old_auth_url is not None and self.host.auth_form_places == 'form_once':
|
282
|
conf_lines.append(
|
283
|
'RedirectMatch %(old_auth_url)s %(new_auth_url)s' % self.cfg)
|
284
|
# Redirect old logout url to the new one
|
285
|
if self.old_logout_url is not None:
|
286
|
conf_lines.append(
|
287
|
'RedirectMatch %(old_logout_url)s %(new_logout_url)s' % self.cfg)
|
288
|
# Redirect the home page to the login page
|
289
|
if self.host.redirect_root_to_login is True:
|
290
|
conf_lines.append('RedirectMatch ^/$ %(new_auth_url)s' % self.cfg)
|
291
|
# Convert urls in http headers to/from the new domain
|
292
|
conf_lines.append('ProxyPass %(orig_url)s' % self.cfg)
|
293
|
conf_lines.append('ProxyPassReverse %(orig_url)s' % self.cfg)
|
294
|
# Convert urls in html pages to/from the new domain
|
295
|
conf_lines.append('ProxyHTMLURLMap %(orig_dir)s %(reversed_directory)s' % self.cfg)
|
296
|
conf_lines.append('ProxyHTMLURLMap %(orig_url)s %(reversed_directory)s' % self.cfg)
|
297
|
# Write it all and close the Location
|
298
|
conf_file.write('\n\t\t'.join(conf_lines))
|
299
|
conf_file.write('\n\t</Location>\n')
|
300
|
|