Projet

Général

Profil

Télécharger (11,5 ko) Statistiques
| Branche: | Révision:

root / larpe / tags / release-1.1.1 / larpe / admin / apache.py @ d03cb81c

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

    
(2-2/9)