301 lines
12 KiB
Python
301 lines
12 KiB
Python
import os
|
|
import re
|
|
import urllib
|
|
import base64
|
|
|
|
from quixote import get_publisher, get_request
|
|
|
|
from qommon import get_cfg
|
|
|
|
from larpe.hosts import Host
|
|
from larpe.Defaults import APP_DIR, APACHE_MAIN_VHOST, APACHE_VHOST_COMMON, APACHE_RELOAD
|
|
|
|
def write_apache2_vhosts():
|
|
hosts = Host.select(lambda x: x.name != 'larpe')
|
|
hosts.sort()
|
|
vhosts_dir = os.path.join(APP_DIR, 'vhosts.d')
|
|
vhost_locations_dir = os.path.join(APP_DIR, 'vhost-locations.d')
|
|
vhosts_dir_disabled = os.path.join(APP_DIR, 'vhosts.d.disabled')
|
|
vhost_locations_dir_disabled = os.path.join(APP_DIR, 'vhost-locations.d.disabled')
|
|
vhost_file_name = get_request().get_server().split(':')[0]
|
|
vhost_file = None
|
|
reversed_hostname = ''
|
|
vhost = None
|
|
|
|
if get_publisher().cfg.get(str('allow_config_generation'), True):
|
|
vhost_file = open(os.path.join(vhosts_dir, vhost_file_name), 'w')
|
|
locations_file = open(os.path.join(vhost_locations_dir, vhost_file_name), 'w')
|
|
else:
|
|
vhost_file = open(os.path.join(vhosts_dir_disabled, vhost_file_name), 'w')
|
|
locations_file = open(os.path.join(vhost_locations_dir_disabled, vhost_file_name), 'w')
|
|
try:
|
|
main_vhost = open(APACHE_MAIN_VHOST, 'r')
|
|
file_content = main_vhost.read()
|
|
regexp = re.compile('<VirtualHost (.*?)>')
|
|
vhost_ip = regexp.findall(file_content)[0]
|
|
except (IOError, IndexError):
|
|
vhost_ip = '*'
|
|
|
|
for host in hosts:
|
|
if host.orig_site is None:
|
|
# This site hasn't been fully configured
|
|
continue
|
|
if host.reversed_hostname != reversed_hostname \
|
|
and host.reversed_hostname != get_cfg('proxy_hostname'):
|
|
if vhost is not None:
|
|
vhost.close()
|
|
vhost = Vhost(host, vhost_ip)
|
|
vhost.write(vhost_file)
|
|
reversed_hostname = host.reversed_hostname
|
|
|
|
if host.reversed_hostname == get_cfg('proxy_hostname'):
|
|
conf_file = locations_file
|
|
else:
|
|
conf_file = vhost_file
|
|
|
|
Location(host).write(conf_file)
|
|
|
|
if vhost_file is not None:
|
|
if vhost is not None:
|
|
vhost.close()
|
|
vhost_file.close()
|
|
if locations_file is not None:
|
|
locations_file.close()
|
|
|
|
if get_publisher().cfg.get(str('allow_config_generation'), True):
|
|
os.system(APACHE_RELOAD)
|
|
|
|
|
|
class Vhost(object):
|
|
def __init__(self, host, main_ip_port):
|
|
self.host = host
|
|
self.main_ip_port = main_ip_port
|
|
self.conf_file = None
|
|
|
|
def get_ip_port(self):
|
|
if self.host.scheme == 'https':
|
|
return self.main_ip_port.replace(':80', ':443')
|
|
else:
|
|
return self.main_ip_port.replace(':443', ':80')
|
|
ip_port = property(get_ip_port)
|
|
|
|
def get_proxy_url(self):
|
|
if get_cfg('proxy', {}).get('enabled') and self.host.use_proxy == True:
|
|
return 'http://%(ip)s:%(port)s' % get_cfg('proxy', {})
|
|
return None
|
|
proxy_url = property(get_proxy_url)
|
|
|
|
def get_proxy_auth(self):
|
|
if self.get_proxy_url() and get_cfg('proxy', {}).get('user'):
|
|
credentials = base64.encodestring(
|
|
'%(user)s:%(password)s' % get_cfg('proxy', {}))[:-1]
|
|
return '"Basic %s"' % credentials
|
|
return None
|
|
proxy_auth = property(get_proxy_auth)
|
|
|
|
def get_cfg(self):
|
|
return { 'ip_port': self.ip_port,
|
|
'reversed_hostname': self.host.reversed_hostname,
|
|
'proxy_url': self.proxy_url,
|
|
'proxy_auth': self.proxy_auth }
|
|
cfg = property(get_cfg)
|
|
|
|
def write(self, conf_file):
|
|
self.conf_file = conf_file
|
|
conf_lines = []
|
|
# Start Virtual Host
|
|
conf_lines.append('<VirtualHost %(ip_port)s>' % self.cfg)
|
|
# Server name and administrator
|
|
conf_lines.append('ServerName %(reversed_hostname)s' % self.cfg)
|
|
conf_lines.append('# ServerAdmin root@localhost\n')
|
|
# Include common vhost configuration
|
|
conf_lines.append('include %s\n' % APACHE_VHOST_COMMON)
|
|
# SSL
|
|
if self.host.scheme == 'https':
|
|
conf_lines.append('SSLEngine On\n')
|
|
if self.host.orig_site.startswith('https'):
|
|
conf_lines.append('SSLProxyEngine On\n')
|
|
# Remote proxy configuration
|
|
if self.proxy_url is not None:
|
|
conf_lines.append('ProxyRemote * %(proxy_url)s' % self.cfg)
|
|
if self.proxy_auth is not None:
|
|
conf_lines.append(
|
|
'RequestHeader set Proxy-Authorization %(proxy_auth)s\n' % self.cfg)
|
|
# Write it all
|
|
conf_file.write('\n\t'.join(conf_lines))
|
|
|
|
def close(self):
|
|
if self.conf_file:
|
|
self.conf_file.write('</VirtualHost>\n\n')
|
|
|
|
|
|
def apache_escape_chars(url):
|
|
special_characters = ('\\', '.', '?', '*', '+', '^', '$', '|', '(', ')', '[', ']')
|
|
for char in special_characters:
|
|
url = url.replace(char, '\%s' % char)
|
|
return url
|
|
|
|
class Location(object):
|
|
def __init__(self, host):
|
|
self.host = host
|
|
|
|
def get_reversed_directory(self):
|
|
if not self.host.reversed_directory:
|
|
return '%s/' % get_request().environ['SCRIPT_NAME']
|
|
else:
|
|
return '%s/%s/' % (get_request().environ['SCRIPT_NAME'], self.host.reversed_directory)
|
|
reversed_directory = property(get_reversed_directory)
|
|
|
|
def get_python_path(self):
|
|
if self.host.apache_output_python_filters and \
|
|
self.host.apache_python_paths:
|
|
python_path = 'PythonPath "sys.path'
|
|
for path in self.host.apache_python_paths:
|
|
python_path += "+['%s']" % path
|
|
python_path += '"'
|
|
return python_path
|
|
else:
|
|
return None
|
|
python_path = property(get_python_path)
|
|
|
|
def get_output_filters(self):
|
|
python_filters = ''
|
|
output_filters = []
|
|
if self.host.apache_output_python_filters:
|
|
i = 0
|
|
for filter_file in self.host.apache_output_python_filters:
|
|
filter_name = 'filter%d' % i
|
|
python_filters += 'PythonOutputFilter %s %s\n\t\t' % (filter_file, filter_name)
|
|
output_filters.append(filter_name)
|
|
i += 1
|
|
if self.host.apache_output_filters:
|
|
for output_filter in self.host.apache_output_filters:
|
|
output_filters.append(output_filter)
|
|
if output_filters:
|
|
return python_filters + 'SetOutputFilter ' + ';'.join(output_filters)
|
|
else:
|
|
return None
|
|
output_filters = property(get_output_filters)
|
|
|
|
def get_old_auth_url(self):
|
|
old_auth_url = None
|
|
if self.host.initiate_sso_url:
|
|
old_auth_url = self.host.initiate_sso_url
|
|
elif self.host.auth_url is not None:
|
|
if self.host.auth_url.startswith('http://'):
|
|
chars_to_skip = 5
|
|
else:
|
|
chars_to_skip = 6
|
|
regexp = re.compile(self.host.orig_site[chars_to_skip:])
|
|
old_auth_url_short = regexp.sub('', self.host.auth_url[chars_to_skip:])
|
|
if old_auth_url_short.startswith('/'):
|
|
old_auth_url = old_auth_url_short
|
|
else:
|
|
old_auth_url = '/' + old_auth_url_short
|
|
if old_auth_url:
|
|
old_auth_url = apache_escape_chars(old_auth_url)
|
|
return old_auth_url
|
|
old_auth_url = property(get_old_auth_url)
|
|
|
|
def get_new_auth_url(self):
|
|
if not hasattr(self.host, 'base_url'):
|
|
return None
|
|
base_url_tokens = self.host.base_url.split('/')
|
|
base_url_tokens[-1] = 'login'
|
|
return '/'.join(base_url_tokens)
|
|
new_auth_url = property(get_new_auth_url)
|
|
|
|
def get_old_logout_url(self):
|
|
old_logout_url = None
|
|
if self.host.logout_url is not None:
|
|
if self.host.logout_url.startswith('http://'):
|
|
chars_to_skip = 5
|
|
else:
|
|
chars_to_skip = 6
|
|
regexp = re.compile(self.host.orig_site[chars_to_skip:])
|
|
old_logout_url_short = regexp.sub('', self.host.logout_url[chars_to_skip:])
|
|
if old_logout_url_short.startswith('/'):
|
|
old_logout_url = old_logout_url_short
|
|
else:
|
|
old_logout_url = '/' + old_logout_url_short
|
|
old_logout_url = apache_escape_chars(old_logout_url)
|
|
return old_logout_url
|
|
old_logout_url = property(get_old_logout_url)
|
|
|
|
def get_new_logout_url(self):
|
|
if not hasattr(self.host, 'base_url'):
|
|
return None
|
|
base_url_tokens = self.host.base_url.split('/')
|
|
base_url_tokens[-1] = 'logout'
|
|
return '/'.join(base_url_tokens)
|
|
new_logout_url = property(get_new_logout_url)
|
|
|
|
def get_orig_site_url_and_dir(self):
|
|
# Split url
|
|
if self.host.orig_site.startswith('http://'):
|
|
orig_host, orig_query = urllib.splithost(self.host.orig_site[5:])
|
|
else:
|
|
orig_host, orig_query = urllib.splithost(self.host.orig_site[6:])
|
|
# Add a trailing slash if necessary
|
|
if self.host.orig_site.endswith('/'):
|
|
orig_url = self.host.orig_site
|
|
orig_dir = orig_query
|
|
else:
|
|
orig_url = self.host.orig_site + '/'
|
|
orig_dir = orig_query + '/'
|
|
return orig_url, orig_dir
|
|
|
|
def get_orig_url(self):
|
|
orig_url, orig_dir = self.get_orig_site_url_and_dir()
|
|
return orig_url
|
|
orig_url = property(get_orig_url)
|
|
|
|
def get_orig_dir(self):
|
|
orig_url, orig_dir = self.get_orig_site_url_and_dir()
|
|
return orig_dir
|
|
orig_dir = property(get_orig_dir)
|
|
|
|
def get_cfg(self):
|
|
return { 'reversed_directory': self.reversed_directory,
|
|
'old_auth_url': self.old_auth_url,
|
|
'new_auth_url': self.new_auth_url,
|
|
'old_logout_url': self.old_logout_url,
|
|
'new_logout_url': self.new_logout_url,
|
|
'orig_url': self.orig_url,
|
|
'orig_dir': self.orig_dir }
|
|
cfg = property(get_cfg)
|
|
|
|
def write(self, conf_file):
|
|
conf_lines = []
|
|
# Start Location
|
|
conf_lines.append('\n\t<Location %(reversed_directory)s>' % self.cfg)
|
|
# No user restriction
|
|
conf_lines.append('Allow from all')
|
|
# Apache output filters
|
|
if self.python_path:
|
|
conf_lines.append(self.python_path)
|
|
if self.output_filters:
|
|
conf_lines.append(self.output_filters)
|
|
# Redirect rules
|
|
# Redirect old authentication url to the new one
|
|
if self.old_auth_url is not None and self.host.auth_form_places == 'form_once':
|
|
conf_lines.append(
|
|
'RedirectMatch %(old_auth_url)s %(new_auth_url)s' % self.cfg)
|
|
# Redirect old logout url to the new one
|
|
if self.old_logout_url is not None:
|
|
conf_lines.append(
|
|
'RedirectMatch %(old_logout_url)s %(new_logout_url)s' % self.cfg)
|
|
# Redirect the home page to the login page
|
|
if self.host.redirect_root_to_login is True:
|
|
conf_lines.append('RedirectMatch ^/$ %(new_auth_url)s' % self.cfg)
|
|
# Convert urls in http headers to/from the new domain
|
|
conf_lines.append('ProxyPass %(orig_url)s' % self.cfg)
|
|
conf_lines.append('ProxyPassReverse %(orig_url)s' % self.cfg)
|
|
# Convert urls in html pages to/from the new domain
|
|
conf_lines.append('ProxyHTMLURLMap %(orig_dir)s %(reversed_directory)s' % self.cfg)
|
|
conf_lines.append('ProxyHTMLURLMap %(orig_url)s %(reversed_directory)s' % self.cfg)
|
|
# Write it all and close the Location
|
|
conf_file.write('\n\t\t'.join(conf_lines))
|
|
conf_file.write('\n\t</Location>\n')
|
|
|