#!/usr/bin/python
#
# Bootstraps the PLC database with a default administrator account and
-# a default site.
+# a default site. Also generates the MA/SA API certificate.
#
# Mark Huang <mlhuang@cs.princeton.edu>
# Copyright (C) 2006 The Trustees of Princeton University
#
-# $Id$
+# $Id: api-config,v 1.15 2006/07/11 20:57:25 mlhuang Exp $
#
-import plcapilib
-(plcapi, moreopts, argv) = plcapilib.plcapi(globals())
from plc_config import PLCConfiguration
+import os
+import re
+import xml
+import CertOps, Certificate
+import Certificate
+import commands
def main():
variables = cfg.variables()
# Load variables into dictionaries
- (category, variablelist) = variables['plc']
- plc = dict(zip(variablelist.keys(),
- [variable['value'] for variable in variablelist.values()]))
+ for category_id, (category, variablelist) in variables.iteritems():
+ globals()[category_id] = dict(zip(variablelist.keys(),
+ [variable['value'] for variable in variablelist.values()]))
- (category, variablelist) = variables['plc_www']
- plc_www = dict(zip(variablelist.keys(),
- [variable['value'] for variable in variablelist.values()]))
+ # Get the issuer e-mail address and public key from the root CA certificate
+ root_ca_email = commands.getoutput("openssl x509 -in %s -noout -email" % \
+ plc_ma_sa['ca_ssl_crt'])
+ root_ca_key_pub = commands.getoutput("openssl x509 -in %s -noout -pubkey" % \
+ plc_ma_sa['ca_ssl_crt'])
- (category, variablelist) = variables['plc_api']
- plc_api = dict(zip(variablelist.keys(),
- [variable['value'] for variable in variablelist.values()]))
+ # Verify API certificate
+ if os.path.exists(plc_ma_sa['api_crt']):
+ print "Verifying API certificate '%s'" % plc_ma_sa['api_crt']
+ try:
+ cert_xml = file(plc_ma_sa['api_crt']).read().strip()
+ # Verify root CA signature
+ CertOps.authenticate_cert(cert_xml, {root_ca_email: root_ca_key_pub})
+ # Check if MA/SA e-mail address has changed
+ dom = xml.dom.minidom.parseString(cert_xml)
+ for subject in dom.getElementsByTagName('subject'):
+ if subject.getAttribute('email') != plc_mail['support_address']:
+ raise Exception, "E-mail address '%s' in certificate '%s' does not match support address '%s'" % \
+ (subject.getAttribute('email'), plc_ma_sa['api_crt'], plc_mail['support_address'])
+ except Exception, e:
+ # Delete invalid API certificate
+ print "Warning: ", e
+ os.unlink(plc_ma_sa['api_crt'])
- # Create/update the default administrator account (should be
- # person_id 2).
- admin = { 'person_id': 2,
- 'first_name': "Default",
- 'last_name': "Administrator",
- 'email': plc['root_user'],
- 'password': plc['root_password'] }
- persons = AdmGetPersons([admin['person_id']])
- if not persons:
- person_id = AdmAddPerson(admin['first_name'], admin['last_name'], admin)
- if person_id != admin['person_id']:
- # Huh? Someone deleted the account manually from the database.
- AdmDeletePerson(person_id)
- raise Exception, "Someone deleted the \"%s %s\" account from the database!" % \
- (admin['first_name'], admin['last_name'])
- AdmSetPersonEnabled(person_id, True)
- else:
- person_id = persons[0]['person_id']
- AdmUpdatePerson(person_id, admin)
-
- # Create/update the default site (should be site_id 0)
- if plc_www['port'] == '80':
- url = "http://" + plc_www['host'] + "/"
- elif plc_www['port'] == '443':
- url = "https://" + plc_www['host'] + "/"
- else:
- url = "http://" + plc_www['host'] + ":" + plc_www['port'] + "/"
- site = { 'site_id': 1,
- 'name': plc['name'] + " Central",
- 'abbreviated_name': plc['name'],
- 'login_base': plc['slice_prefix'],
- 'is_public': False,
- 'url': url,
- 'max_slices': 100 }
-
- sites = AdmGetSites([site['site_id']])
- if not sites:
- site_id = AdmAddSite(site['name'], site['abbreviated_name'], site['login_base'], site)
- if site_id != site['site_id']:
- AdmDeleteSite(site_id)
- raise Exception, "Someone deleted the \"%s\" site from the database!" % \
- site['name']
- else:
- site_id = sites[0]['site_id']
- # XXX login_base cannot be updated
- del site['login_base']
- AdmUpdateSite(site_id, site)
-
- # The default administrator account must be associated with a site
- # in order to login.
- AdmAddPersonToSite(admin['person_id'], site['site_id'])
- AdmSetPersonPrimarySite(admin['person_id'], site['site_id'])
-
- # Grant admin and PI roles to the default administrator account
- AdmGrantRoleToPerson(admin['person_id'], 10)
- AdmGrantRoleToPerson(admin['person_id'], 20)
-
- # XXX Setup default slice attributes and initscripts (copy from PLC)
-
- # XXX Setup PlanetLabConf entries (copy from PLC)
+ # Generate self-signed API certificate
+ if not os.path.exists(plc_ma_sa['api_crt']):
+ print "Generating new API certificate"
+ try:
+ cert = Certificate.Certificate('ticket-cert-0')
+ ma_sa_ssl_key_pub = commands.getoutput("openssl x509 -in %s -noout -pubkey" % \
+ plc_ma_sa['ssl_crt'])
+ cert.add_subject_pubkey(pubkey = ma_sa_ssl_key_pub, email = plc_mail['support_address'])
+ root_ca_subject = commands.getoutput("openssl x509 -in %s -noout -subject" % \
+ plc_ma_sa['ssl_crt'])
+ m = re.search('/CN=([^/]*).*', root_ca_subject)
+ if m is None:
+ root_ca_cn = plc['name'] + " Management and Slice Authority"
+ else:
+ root_ca_cn = m.group(1)
+ cert.set_issuer(email = root_ca_email, cn = root_ca_cn)
+ cert_xml = cert.sign(plc_ma_sa['ssl_key'])
+ ma_sa_api_crt = file(plc_ma_sa['api_crt'], "w")
+ ma_sa_api_crt.write(cert_xml)
+ ma_sa_api_crt.close()
+ except Exception, e:
+ print "Warning: Could not generate API certificate: ", e
if __name__ == '__main__':
main()