import string import cPickle import os import zipfile import subprocess from urlparse import urlparse from cStringIO import StringIO import xml.etree.ElementTree as ET from django.conf import settings from . import app_settings def get_provider_key(provider_id): return provider_id.replace('://', '-').replace('/', '-').replace('?', '-').replace(':', '-') class DeployInstance(object): skeleton = 'default' skel_dir = None collectivity_install_dir = None def __init__(self, domain, title): self.domain = domain self.title = title def make(self): self.skel_dir = os.path.join(settings.MEDIA_ROOT, 'skeletons', self.skeleton) url_template = app_settings.URL_TEMPLATE self.url = url_template % {'domain': self.domain} host, path = urlparse(self.url)[1:3] if path.endswith('/'): path = path[:-1] coldir = host if path: coldir += path.replace('/', '+') self.collectivity_install_dir = os.path.join(app_settings.WCS_APP_DIR, coldir) if os.path.exists(self.collectivity_install_dir): # site exists, let's update it pass anew = False else: anew = True os.mkdir(self.collectivity_install_dir) z = zipfile.ZipFile(os.path.join(self.skel_dir, 'export.wcs'), 'r') for f in z.namelist(): path = os.path.join(self.collectivity_install_dir, f) data = z.read(f) if not os.path.exists(os.path.dirname(path)): os.mkdir(os.path.dirname(path)) open(path, 'w').write(data) z.close() config_file = os.path.join(self.collectivity_install_dir, 'config.pck') if os.path.exists(config_file): wcs_cfg = cPickle.load(file(os.path.join(self.collectivity_install_dir, 'config.pck'))) else: wcs_cfg = {} has_sql = self.make_sql_config(wcs_cfg) self.make_sso_config(wcs_cfg) self.make_site_options() cPickle.dump(wcs_cfg, file(config_file, 'w')) if has_sql: self.make_sql_tables(wcs_cfg) self.make_apache_vhost() self.reload_apache() def make_sql_config(self, wcs_cfg): if not wcs_cfg.get('postgresql'): # this is not a site configured to use SQL return False database_name = wcs_cfg['postgresql'].get('database', 'wcs') domain_table_name = self.domain.replace('-', '_').replace('.', '_') if '_' in database_name: database_name = '%s_%s' % (database_name.split('_')[0], domain_table_name) else: database_name = '%s_%s' % (database_name, domain_table_name) try: pgconn = psycopg2.connect(**wcs_cfg['postgresql']) except psycopg2.Error: # XXX: log raise cur = pgconn.cursor() cur.execute('''CREATE DATABASE %s''' % database_name) pgconn.commit() cur.close() wcs_cfg['postgresql']['database'] = database_name return True def make_sql_tables(self, wcs_cfg): params = [] for param in ('dbname', 'user', 'password', 'host', 'port'): if wcs_cfg.get('postgresql').get(param): params.append(param) params.append(wcs_cfg.get('postgresql').get(param)) os.system('wcsctl convertsql %s %s' % (' '.join(params), self.domain)) def make_sso_config(self, wcs_cfg): has_idff = False has_saml2 = False service_provider_configuration = {} if self.url.endswith('/'): url_stripped = self.url[:-1] else: url_stripped = self.url if os.path.exists(os.path.join(self.skel_dir, 'idff-metadata-template')): # there's a ID-FF metadata template, so we do the ID-FF stuff has_idff = True service_provider_configuration.update({ 'base_url': '%s/liberty' % url_stripped, 'metadata': 'metadata.xml', 'providerid': '%s/liberty/metadata' % url_stripped, }) idff_metadata_template = file( os.path.join(self.skel_dir, 'idff-metadata-template')).read() file(os.path.join(self.collectivity_install_dir, 'metadata.xml'), 'w').write( string.Template(idff_metadata_template).substitute({'url': url_stripped})) if os.path.exists(os.path.join(self.skel_dir, 'saml2-metadata-template')): # there's a SAMLv2 metadata template, so we do the SAMLv2 stuff has_saml2 = True service_provider_configuration.update({ 'saml2_base_url': '%s/saml' % url_stripped, 'saml2_metadata': 'saml2-metadata.xml', 'saml2_providerid': '%s/saml/metadata' % url_stripped }) saml2_metadata_template = file( os.path.join(self.skel_dir, 'saml2-metadata-template')).read() file(os.path.join(self.collectivity_install_dir, 'saml2-metadata.xml'), 'w').write( string.Template(saml2_metadata_template).substitute({'url': url_stripped})) if has_idff or has_saml2: idp_metadata = ET.parse(file(os.path.join(self.skel_dir, 'idp-metadata.xml'))) entity_id = idp_metadata.getroot().attrib['entityID'] idp_key = get_provider_key(entity_id) wcs_cfg['identification'] = {'methods': ['idp']} wcs_cfg['idp'] = { idp_key: { 'metadata': 'provider-%s-metadata.xml' % idp_key, 'metadata_url': entity_id, 'publickey_url': None, 'role': 2}} wcs_cfg['sp'] = { 'common_domain': None, 'common_domain_getter_url': None, 'organization_name': '%s' % self.title, 'privatekey': 'private-key.pem', 'publickey': 'public-key.pem'} wcs_cfg['sp'].update(service_provider_configuration) file(os.path.join(self.collectivity_install_dir, 'provider-%s-metadata.xml' % idp_key), 'w').write( file(os.path.join(self.skel_dir, 'idp-metadata.xml')).read()) file(os.path.join(self.collectivity_install_dir, 'public-key.pem'), 'w').write( file(os.path.join(self.skel_dir, 'public-key.pem')).read()) file(os.path.join(self.collectivity_install_dir, 'private-key.pem'), 'w').write( file(os.path.join(self.skel_dir, 'private-key.pem')).read()) else: wcs_cfg['identification'] = {'methods': ['password']} def make_site_options(self): options_template_path = os.path.join(self.skel_dir, 'site-options.cfg') if not os.path.exists(options_template_path): return options_template = file(options_template_path).read() file(os.path.join(self.collectivity_install_dir, 'site-options.cfg'), 'w').write( string.Template(options_template).substitute({'domain': self.domain})) def make_apache_vhost(self): apache_vhost_template_path = os.path.join(self.skel_dir, 'apache-vhost.conf') if not os.path.exists(apache_vhost_template_path): return apache_vhost_template = file(apache_vhost_template_path).read() apache_dir = os.path.join(settings.MEDIA_ROOT, 'vhosts.d') if not os.path.exists(apache_dir): os.mkdir(apache_dir) file(os.path.join(apache_dir, '%s.conf' % self.domain), 'w').write( string.Template(apache_vhost_template).substitute({'domain': self.domain})) def reload_apache(self): os.system('sudo -n /etc/init.d/apache2 reload')