This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
larpe/larpe/trunk/larpe/admin/apache.py

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