From 9182c10b03a7841c9318ad64ae6c5deda77d93d1 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 13 Apr 2009 13:39:15 -0400 Subject: Issue DS and Apache server certs during CA installation. Notes: - will create a CA instance (pki-ca) if it doesn't exist - maintains support for a self-signed CA - A signing cert is still not created so Firefox autoconfig still won't work --- ipaserver/install/cainstance.py | 128 +++++++++++++------ ipaserver/install/certs.py | 254 +++++++++++++++++++++++++++++++------- ipaserver/install/dsinstance.py | 20 ++- ipaserver/install/httpinstance.py | 55 ++++++--- 4 files changed, 355 insertions(+), 102 deletions(-) (limited to 'ipaserver/install') diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index c402fb04..088744a4 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -34,11 +34,6 @@ import shutil import httplib import urllib import xml.dom.minidom -import getopt -import urlparse -import getpass -import socket -import errno from nss.error import NSPRError import nss.nss as nss @@ -309,7 +304,7 @@ class CADSInstance(service.Service): if not dsinstance.is_ds_running(): logging.critical("Failed to restart the directory server. See the installation log for details.") sys.exit(1) - except Exception, e: + except Exception: # TODO: roll back here? logging.critical("Failed to restart the directory server. See the installation log for details.") @@ -341,6 +336,18 @@ class CADSInstance(service.Service): class CAInstance(service.Service): + """ + In the self-signed case (all done in certs.py) the CA exists in the DS + database. When using a dogtag CA the DS database contains just the + server cert for DS. The mod_nss database will contain the RA agent + cert that will be used to do authenticated requests against dogtag. + + This is done because we use python-nss and will inherit the opened + NSS database in mod_python. In nsslib.py we do an nssinit but this will + return success if the database is already initialized. It doesn't care + if the database is different or not. + """ + def __init__(self): service.Service.__init__(self, "pki-ca") self.pki_user = None @@ -348,10 +355,14 @@ class CAInstance(service.Service): self.admin_password = None self.host_name = None + # The same database is used for mod_nss because the NSS context + # will already have been initialized by Apache by the time + # mod_python wants to do things. + self.canickname = "CA certificate" self.basedn = "o=ipaca" self.ca_agent_db = tempfile.mkdtemp(prefix = "tmp-") - self.ra_agent_db = "/etc/ipa/ra/alias" - self.ra_agent_pwd = self.ra_agent_db + "/.pwd" + self.ra_agent_db = "/etc/httpd/alias" + self.ra_agent_pwd = self.ra_agent_db + "/pwdfile.txt" self.ds_port = DEFAULT_DSPORT self.domain_name = "IPA" self.server_root = "/var/lib" @@ -368,6 +379,8 @@ class CAInstance(service.Service): self.admin_password = admin_password self.ds_port = ds_port + if not ipautil.dir_exists("/var/lib/pki-ca"): + self.step("creating pki-ca instance", self.create_instance) self.step("creating certificate server user", self.__create_ca_user) self.step("configuring certificate server instance", self.__configure_instance) self.step("creating CA agent PKCS#12 file in /root", self.__create_ca_agent_pkcs12) @@ -382,6 +395,33 @@ class CAInstance(service.Service): self.start_creation("Configuring certificate server:") + def create_instance(self): + """ + If for some reason the instance doesn't exist, create a new one." + + These values come from /usr/share/pki/ca/setup/postinstall + """ + PKI_INSTANCE_NAME="pki-ca" + AGENT_SECURE_PORT="9443" + EE_SECURE_PORT="9444" + ADMIN_SECURE_PORT="9445" + UNSECURE_PORT="9180" + TOMCAT_SERVER_PORT="9701" + + args = ['/usr/bin/pkicreate', + '-pki_instance_root', '/var/lib', + '-pki_instance_name', PKI_INSTANCE_NAME, + '-subsystem_type', 'ca', + '-agent_secure_port', AGENT_SECURE_PORT, + '-ee_secure_port', EE_SECURE_PORT, + '-admin_secure_port', ADMIN_SECURE_PORT, + '-unsecure_port', UNSECURE_PORT, + '-tomcat_server_port', TOMCAT_SERVER_PORT, + '-redirect', 'conf=/etc/pki-ca', + '-redirect', 'logs=/var/log/pki-ca', + ] + ipautil.run(args) + def __enable(self): self.backup_state("enabled", self.is_enabled()) self.chkconfig_on() @@ -500,7 +540,7 @@ class CAInstance(service.Service): def __restart_instance(self): try: self.restart() - except Exception, e: + except Exception: # TODO: roll back here? logging.critical("Failed to restart the certificate server. See the installation log for details.") @@ -526,35 +566,43 @@ class CAInstance(service.Service): os.remove(admin_name) # Retrieve the certificate request so we can get the values needed - # to issue a certificate. - conn = nsslib.NSSConnection(self.host_name,9443,dbdir=self.ca_agent_db) - conn.sslsock.set_client_auth_data_callback(client_auth_data_callback, "ipa-ca-agent", self.admin_password, nss.get_default_certdb()) - conn.set_debuglevel(0) - conn.request("GET", "/ca/agent/ca/profileReview?requestId=7") - res = conn.getresponse() - data = res.read() - if res.status != 200: - raise RuntimeError("Unable to retrieve certificate request from CA") - - data = data.split('\r\n') + # to issue a certificate. Use sslget here because this is a + # temporary database and nsslib doesn't currently support gracefully + # opening and closing an NSS database. This would leave the installer + # process stuck using this database during the entire cycle. We need + # to use the final RA agent database when issuing certs for DS and + # mod_nss. + args = [ + '/usr/bin/sslget', + '-n', 'ipa-ca-agent', + '-p', self.admin_password, + '-d', self.ca_agent_db, + '-r', '/ca/agent/ca/profileReview?requestId=7', + '%s:%d' % (self.host_name, 9443), + ] + (stdout, stderr) = ipautil.run(args) + + data = stdout.split('\r\n') params = get_defList(data) params['requestId'] = find_substring(data, "requestId") params['op'] = 'approve' params['submit'] = 'submit' params['requestNotes'] = '' params = urllib.urlencode(params) - headers = {"Content-type": "application/x-www-form-urlencoded", - "Accept": "text/plain"} # Now issue the RA certificate. - conn.request("POST", "/ca/agent/ca/profileProcess", params, headers) - res = conn.getresponse() - data = res.read() - conn.close() - if res.status != 200: - raise RuntimeError("Unable to issue RA certificate") - - data = data.split('\r\n') + args = [ + '/usr/bin/sslget', + '-n', 'ipa-ca-agent', + '-p', self.admin_password, + '-d', self.ca_agent_db, + '-e', params, + '-r', '/ca/agent/ca/profileProcess', + '%s:%d' % (self.host_name, 9443), + ] + (stdout, stderr) = ipautil.run(args) + + data = stdout.split('\r\n') outputList = get_outputList(data) self.ra_cert = outputList['b64_cert'] @@ -562,7 +610,7 @@ class CAInstance(service.Service): self.ra_cert = self.ra_cert.replace('-----BEGIN CERTIFICATE-----','') self.ra_cert = self.ra_cert.replace('-----END CERTIFICATE-----','') - # Add the new RA cert to the database in /etc/ipa/ra + # Add the new RA cert to the database in /etc/httpd/alias (agent_fd, agent_name) = tempfile.mkstemp() os.write(agent_fd, self.ra_cert) os.close(agent_fd) @@ -618,8 +666,10 @@ class CAInstance(service.Service): def __create_ra_agent_db(self): if ipautil.file_exists(self.ra_agent_db + "/cert8.db"): - # FIXME, use proper exception - raise ValueError("The RA Agent database already exists: %s" % self.ra_agent_db) + ipautil.backup_file(self.ra_agent_db + "/cert8.db") + ipautil.backup_file(self.ra_agent_db + "/key3.db") + ipautil.backup_file(self.ra_agent_db + "/secmod.db") + ipautil.backup_file(self.ra_agent_db + "/pwdfile.txt") if not ipautil.dir_exists(self.ra_agent_db): os.mkdir(self.ra_agent_db) @@ -647,9 +697,8 @@ class CAInstance(service.Service): return chain else: - # FIXME: raise proper exception conn.close() - raise ValueError("Unable to retrieve CA chain") + raise RuntimeError("Unable to retrieve CA chain") def __create_ca_agent_pkcs12(self): (pwd_fd, pwd_name) = tempfile.mkstemp() @@ -672,7 +721,7 @@ class CAInstance(service.Service): os.close(chain_fd) try: self.__run_certutil( - ['-A', '-t', 'CT,C,C', '-n', 'caCert', '-a', + ['-A', '-t', 'CT,C,C', '-n', self.canickname, '-a', '-i', chain_name] ) finally: @@ -709,13 +758,14 @@ class CAInstance(service.Service): res = conn.getresponse() if res.status == 200: data = res.read() + # FIXME: pull the requestId out so of the response so it isn't + # later hard-coded at 7 # print data conn.close() else: conn.close() - # FIXME: raise proper exception - raise ValueError("Unable to submit RA cert request") + raise RuntimeError("Unable to submit RA cert request") def __fix_ra_perms(self): os.chmod(self.ra_agent_db + "/cert8.db", 0640) @@ -731,7 +781,7 @@ class CAInstance(service.Service): def uninstall(self): try: ipautil.run(["/usr/bin/pkiremove", "-pki_instance_root=/var/lib", - "-pki_instance_name=pki-ca", "-force"]) + "-pki_instance_name=pki-ca", "--force"]) except ipautil.CalledProcessError, e: logging.critical("failed to uninstall CA instance %s" % e) diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py index e9061fe1..45958f2a 100644 --- a/ipaserver/install/certs.py +++ b/ipaserver/install/certs.py @@ -22,15 +22,46 @@ import sha import errno import tempfile import shutil +import logging +import urllib +import xml.dom.minidom +from ipapython import nsslib from ipapython import sysrestore from ipapython import ipautil +from nss.error import NSPRError +import nss.nss as nss + CA_SERIALNO="/var/lib/ipa/ca_serialno" +def client_auth_data_callback(ca_names, chosen_nickname, password, certdb): + cert = None + if chosen_nickname: + try: + cert = nss.find_cert_from_nickname(chosen_nickname, password) + priv_key = nss.find_key_by_any_cert(cert, password) + return cert, priv_key + except NSPRError, e: + logging.debug("client auth callback failed %s" % str(e)) + return False + else: + nicknames = nss.get_cert_nicknames(certdb, nss.SEC_CERT_NICKNAMES_USER) + for nickname in nicknames: + try: + cert = nss.find_cert_from_nickname(nickname, password) + if cert.check_valid_times(): + if cert.has_signer_in_ca_names(ca_names): + priv_key = nss.find_key_by_any_cert(cert, password) + return cert, priv_key + except NSPRError, e: + logging.debug("client auth callback failed %s" % str(e)) + return False + return False + class CertDB(object): - def __init__(self, dir, fstore=None): - self.secdir = dir + def __init__(self, nssdir, fstore=None, host_name=None): + self.secdir = nssdir self.noise_fname = self.secdir + "/noise.txt" self.passwd_fname = self.secdir + "/pwdfile.txt" @@ -40,9 +71,16 @@ class CertDB(object): self.cacert_fname = self.secdir + "/cacert.asc" self.pk12_fname = self.secdir + "/cacert.p12" self.pin_fname = self.secdir + "/pin.txt" + self.pwd_conf = "/etc/httpd/conf/password.conf" self.reqdir = tempfile.mkdtemp('', 'ipa-', '/var/lib/ipa') self.certreq_fname = self.reqdir + "/tmpcertreq" self.certder_fname = self.reqdir + "/tmpcert.der" + self.host_name = host_name + + if ipautil.file_exists(CA_SERIALNO): + self.self_signed_ca = True + else: + self.self_signed_ca = False # Making this a starting value that will generate # unique values for the current DB is the @@ -72,6 +110,22 @@ class CertDB(object): def __del__(self): shutil.rmtree(self.reqdir, ignore_errors=True) + def find_cert_from_txt(self, cert): + """ + Given a cert blob (str) which may or may not contian leading and + trailing text, pull out just the certificate part. This will return + the FIRST cert in a stream of data. + """ + s = cert.find('-----BEGIN CERTIFICATE-----') + e = cert.find('-----END CERTIFICATE-----') + if e > 0: e = e + 25 + + if s < 0 or e < 0: + raise RuntimeError("Unable to find certificate") + + cert = cert[s:e] + return cert + def set_serial_from_pkcs12(self): """A CA cert was loaded from a PKCS#12 file. Set up our serial file""" @@ -94,6 +148,7 @@ class CertDB(object): f.close() except IOError, e: if e.errno == errno.ENOENT: + self.self_signed_ca = True self.cur_serial = 1000 f=open(CA_SERIALNO,"w") f.write(str(self.cur_serial)) @@ -131,7 +186,8 @@ class CertDB(object): ipautil.run(new_args, stdin) def create_noise_file(self): - ipautil.backup_file(self.noise_fname) + if ipautil.file_exists(self.noise_fname): + os.remove(self.noise_fname) f = open(self.noise_fname, "w") f.write(self.gen_password()) self.set_perms(self.noise_fname) @@ -193,6 +249,14 @@ class CertDB(object): "-a", "-i", cacert_fname]) + def get_cert_from_db(self, nickname): + try: + args = ["-L", "-n", nickname, "-a"] + (cert, err) = self.run_certutil(args) + return cert + except ipautil.CalledProcessError: + return '' + def find_cacert_serial(self): (out,err) = self.run_certutil(["-L", "-n", self.cacert_name]) data = out.split('\n') @@ -203,11 +267,20 @@ class CertDB(object): raise RuntimeError("Unable to find serial number") - def create_server_cert(self, nickname, name, other_certdb=None): + def create_server_cert(self, nickname, subject, other_certdb=None): + """ + other_certdb can mean one of two things, depending on the context. + + If we are using a self-signed CA then other_certdb contains the + CA that will be signing our CSR. + + If we are using a dogtag CA then it contains the RA agent key + that will issue our cert. + """ cdb = other_certdb if not cdb: cdb = self - self.request_cert(name) + (out, err) = self.request_cert(subject) cdb.issue_server_cert(self.certreq_fname, self.certder_fname) self.add_cert(self.certder_fname, nickname) os.unlink(self.certreq_fname) @@ -223,41 +296,103 @@ class CertDB(object): os.unlink(self.certreq_fname) os.unlink(self.certder_fname) - def request_cert(self, name): - self.run_certutil(["-R", "-s", name, - "-o", self.certreq_fname, - "-g", self.keysize, - "-z", self.noise_fname, - "-f", self.passwd_fname]) + def request_cert(self, subject, certtype="rsa", keysize="2048"): + self.create_noise_file() + args = ["-R", "-s", subject, + "-o", self.certreq_fname, + "-k", certtype, + "-g", keysize, + "-z", self.noise_fname, + "-f", self.passwd_fname] + if not self.self_signed_ca: + args.append("-a") + (stdout, stderr) = self.run_certutil(args) + os.remove(self.noise_fname) + + return (stdout, stderr) def issue_server_cert(self, certreq_fname, cert_fname): - p = subprocess.Popen(["/usr/bin/certutil", - "-d", self.secdir, - "-C", "-c", self.cacert_name, - "-i", certreq_fname, - "-o", cert_fname, - "-m", self.next_serial(), - "-v", self.valid_months, - "-f", self.passwd_fname, - "-1", "-5"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) + if self.self_signed_ca: + p = subprocess.Popen(["/usr/bin/certutil", + "-d", self.secdir, + "-C", "-c", self.cacert_name, + "-i", certreq_fname, + "-o", cert_fname, + "-m", self.next_serial(), + "-v", self.valid_months, + "-f", self.passwd_fname, + "-1", "-5"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + + # Bah - this sucks, but I guess it isn't possible to fully + # control this with command line arguments. + # + # What this is requesting is: + # -1 (Create key usage extension) + # 2 - Key encipherment + # 9 - done + # n - not critical + # + # -5 (Create netscape cert type extension) + # 1 - SSL Server + # 9 - done + # n - not critical + p.stdin.write("2\n9\nn\n1\n9\nn\n") + p.wait() + else: + if self.host_name is None: + raise RuntimeError("CA Host is not set.") - # Bah - this sucks, but I guess it isn't possible to fully - # control this with command line arguments. - # - # What this is requesting is: - # -1 (Create key usage extension) - # 2 - Key encipherment - # 9 - done - # n - not critical - # - # -5 (Create netscape cert type extension) - # 1 - SSL Server - # 9 - done - # n - not critical - p.stdin.write("2\n9\nn\n1\n9\nn\n") - p.wait() + f = open(certreq_fname, "r") + csr = f.readlines() + f.close() + csr = "".join(csr) + + # We just want the CSR bits, make sure there is nothing else + s = csr.find("-----BEGIN NEW CERTIFICATE REQUEST-----") + e = csr.find("-----END NEW CERTIFICATE REQUEST-----") + if e > 0: + e = e + 37 + if s >= 0: + csr = csr[s:] + + params = urllib.urlencode({'profileId': 'caRAserverCert', + 'cert_request_type': 'pkcs10', + 'requestor_name': 'IPA Installer', + 'cert_request': csr, + 'xmlOutput': 'true'}) + headers = {"Content-type": "application/x-www-form-urlencoded", + "Accept": "text/plain"} + + # Send the CSR request to the CA + f = open(self.passwd_fname) + password = f.readline() + f.close() + conn = nsslib.NSSConnection(self.host_name, 9444, dbdir=self.secdir) + conn.sslsock.set_client_auth_data_callback(client_auth_data_callback, "ipaCert", password, nss.get_default_certdb()) + conn.set_debuglevel(0) + + conn.request("POST", "/ca/ee/ca/profileSubmit", params, headers) + res = conn.getresponse() + data = res.read() + conn.close() + if res.status != 200: + raise RuntimeError("Unable to submit cert request") + + # The result is an XML blob. Pull the certificate out of that + doc = xml.dom.minidom.parseString(data) + item_node = doc.getElementsByTagName("b64") + cert = item_node[0].childNodes[0].data + doc.unlink() + + # Write the certificate to a file. It will be imported in a later + # step. + f = open(cert_fname, "w") + f.write(cert) + f.close() + + return def issue_signing_cert(self, certreq_fname, cert_fname): p = subprocess.Popen(["/usr/bin/certutil", @@ -290,12 +425,18 @@ class CertDB(object): p.wait() def add_cert(self, cert_fname, nickname): - self.run_certutil(["-A", "-n", nickname, - "-t", "u,u,u", - "-i", cert_fname, - "-f", cert_fname]) + args = ["-A", "-n", nickname, + "-t", "u,u,u", + "-i", cert_fname, + "-f", cert_fname] + if not self.self_signed_ca: + args.append("-a") + self.run_certutil(args) def create_pin_file(self): + """ + This is the format of Directory Server pin files. + """ ipautil.backup_file(self.pin_fname) f = open(self.pin_fname, "w") f.write("Internal (Software) Token:") @@ -304,6 +445,17 @@ class CertDB(object): f.close() self.set_perms(self.pin_fname) + def create_password_conf(self): + """ + This is the format of mod_nss pin files. + """ + ipautil.backup_file(self.pwd_conf) + f = open(self.pwd_conf, "w") + f.write("internal:") + pwd = open(self.passwd_fname) + f.write(pwd.read()) + f.close() + def find_root_cert(self, nickname): p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, "-O", "-n", nickname], stdout=subprocess.PIPE) @@ -375,7 +527,24 @@ class CertDB(object): self.create_pin_file() def create_from_cacert(self, cacert_fname, passwd=""): - self.create_noise_file() + if ipautil.file_exists(self.certdb_fname): + # We already have a cert db, see if it is for the same CA. + # If it is we leave things as they are. + f = open(cacert_fname, "r") + newca = f.readlines() + f.close() + newca = "".join(newca) + newca = self.find_cert_from_txt(newca) + + cacert = self.get_cert_from_db(self.cacert_name) + if cacert != '': + cacert = self.find_cert_from_txt(cacert) + + if newca == cacert: + return + + # The CA certificates are different or something went wrong. Start with + # a new certificate database. self.create_passwd_file(passwd) self.create_certdbs() self.load_cacert(cacert_fname) @@ -403,6 +572,7 @@ class CertDB(object): self.trust_root_cert(nickname) self.create_pin_file() self.export_ca_cert(self.cacert_name, False) + self.self_signed_ca=False # This file implies that we have our own self-signed CA. Ensure # that it no longer exists (from previous installs, for example). diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index d6a386e4..53fca5af 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -154,7 +154,7 @@ class DsInstance(service.Service): else: self.suffix = None - def create_instance(self, ds_user, realm_name, host_name, domain_name, dm_password, pkcs12_info=None): + def create_instance(self, ds_user, realm_name, host_name, domain_name, dm_password, pkcs12_info=None, self_signed_ca=False): self.ds_user = ds_user self.realm_name = realm_name.upper() self.serverid = realm_to_serverid(self.realm_name) @@ -163,6 +163,7 @@ class DsInstance(service.Service): self.dm_password = dm_password self.domain = domain_name self.pkcs12_info = pkcs12_info + self.self_signed_ca = self_signed_ca self.__setup_sub_dict() self.step("creating directory server user", self.__create_ds_user) @@ -341,19 +342,26 @@ class DsInstance(service.Service): def __enable_ssl(self): dirname = config_dirname(self.serverid) - ca = certs.CertDB(dirname) + dsdb = certs.CertDB(dirname) if self.pkcs12_info: - ca.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1]) - server_certs = ca.find_server_certs() + dsdb.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1]) + server_certs = dsdb.find_server_certs() if len(server_certs) == 0: raise RuntimeError("Could not find a suitable server cert in import in %s" % pkcs12_info[0]) # We only handle one server cert nickname = server_certs[0][0] else: - ca.create_self_signed() - ca.create_server_cert("Server-Cert", "cn=%s,ou=Fedora Directory Server" % self.host_name) nickname = "Server-Cert" + if self.self_signed_ca: + dsdb.create_self_signed() + dsdb.create_server_cert("Server-Cert", "cn=%s,ou=Fedora Directory Server" % self.host_name) + else: + cadb = certs.CertDB("/etc/httpd/alias", host_name=self.host_name) + cadb.export_ca_cert(cadb.cacert_name, False) + dsdb.create_from_cacert(cadb.cacert_fname, passwd=None) + dsdb.create_server_cert("Server-Cert", "CN=%s,OU=pki-ipa,O=IPA" % self.host_name, cadb) + dsdb.create_pin_file() conn = ipaldap.IPAdmin("127.0.0.1") conn.simple_bind_s("cn=directory manager", self.dm_password) diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py index d4cebfac..0637e3f4 100644 --- a/ipaserver/install/httpinstance.py +++ b/ipaserver/install/httpinstance.py @@ -59,21 +59,25 @@ class HTTPInstance(service.Service): else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') - def create_instance(self, realm, fqdn, domain_name, autoconfig=True, pkcs12_info=None): + def create_instance(self, realm, fqdn, domain_name, autoconfig=True, pkcs12_info=None, self_signed_ca=False): self.fqdn = fqdn self.realm = realm self.domain = domain_name self.pkcs12_info = pkcs12_info + self.self_signed_ca = self_signed_ca self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain } self.step("disabling mod_ssl in httpd", self.__disable_mod_ssl) self.step("Setting mod_nss port to 443", self.__set_mod_nss_port) + if not self_signed_ca: + self.step("Setting mod_nss password file", self.__set_mod_nss_passwordfile) self.step("Adding URL rewriting rules", self.__add_include) self.step("configuring httpd", self.__configure_http) self.step("creating a keytab for httpd", self.__create_http_keytab) self.step("Setting up ssl", self.__setup_ssl) if autoconfig: self.step("Setting up browser autoconfig", self.__setup_autoconfig) + self.step("publish CA cert", self.__publish_ca_cert) self.step("configuring SELinux for httpd", self.__selinux_config) self.step("restarting httpd", self.__start) self.step("configuring httpd to start on boot", self.__enable) @@ -148,17 +152,23 @@ class HTTPInstance(service.Service): def __set_mod_nss_nickname(self, nickname): installutils.set_directive(NSS_CONF, 'NSSNickname', nickname) + def __set_mod_nss_passwordfile(self): + installutils.set_directive(NSS_CONF, 'NSSPassPhraseDialog', 'file:/etc/httpd/conf/password.conf') + def __add_include(self): """This should run after __set_mod_nss_port so is already backed up""" if installutils.update_file(NSS_CONF, '', 'Include conf.d/ipa-rewrite.conf\n') != 0: print "Adding Include conf.d/ipa-rewrite to %s failed." % NSS_CONF def __setup_ssl(self): - ds_ca = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm))) - ca = certs.CertDB(NSS_DIR) + if self.self_signed_ca: + ca_db = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm))) + else: + ca_db = certs.CertDB(NSS_DIR, host_name=self.fqdn) + db = certs.CertDB(NSS_DIR) if self.pkcs12_info: - ca.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], passwd="") - server_certs = ca.find_server_certs() + db.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], passwd="") + server_certs = db.find_server_certs() if len(server_certs) == 0: raise RuntimeError("Could not find a suitable server cert in import in %s" % pkcs12_info[0]) @@ -167,9 +177,13 @@ class HTTPInstance(service.Service): self.__set_mod_nss_nickname(nickname) else: - ca.create_from_cacert(ds_ca.cacert_fname) - ca.create_server_cert("Server-Cert", "cn=%s,ou=Apache Web Server" % self.fqdn, ds_ca) - ca.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ds_ca) + if self.self_signed_ca: + db.create_from_cacert(ca_db.cacert_fname) + db.create_server_cert("Server-Cert", "cn=%s,ou=Apache Web Server" % self.fqdn, ca_db) + db.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ca_db) + else: + db.create_server_cert("Server-Cert", "CN=%s,OU=ipa-pki,O=IPA" % self.fqdn, ca_db) + db.create_password_conf() # Fix the database permissions os.chmod(NSS_DIR + "/cert8.db", 0640) @@ -182,27 +196,38 @@ class HTTPInstance(service.Service): os.chown(NSS_DIR + "/secmod.db", 0, pent.pw_gid ) def __setup_autoconfig(self): + # FIXME. Need to issue the self-signed cert from the CA as well. + # A special profile is needed from the CS team to do this. + if not self.self_signed_ca: + return prefs_txt = ipautil.template_file(ipautil.SHARE_DIR + "preferences.html.template", self.sub_dict) prefs_fd = open("/usr/share/ipa/html/preferences.html", "w") prefs_fd.write(prefs_txt) prefs_fd.close() # The signing cert is generated in __setup_ssl - ds_ca = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm))) - ca = certs.CertDB(NSS_DIR) - - # Publish the CA certificate - shutil.copy(ds_ca.cacert_fname, "/usr/share/ipa/html/ca.crt") - os.chmod("/usr/share/ipa/html/ca.crt", 0444) + if self.self_signed_ca: + ca_db = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm))) + else: + ca_db = certs.CertDB(NSS_DIR) + db = certs.CertDB(NSS_DIR) tmpdir = tempfile.mkdtemp(prefix = "tmp-") shutil.copy("/usr/share/ipa/html/preferences.html", tmpdir) - ca.run_signtool(["-k", "Signing-Cert", + db.run_signtool(["-k", "Signing-Cert", "-Z", "/usr/share/ipa/html/configure.jar", "-e", ".html", tmpdir]) shutil.rmtree(tmpdir) + def __publish_ca_cert(self): + if self.self_signed_ca: + ca_db = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm))) + else: + ca_db = certs.CertDB(NSS_DIR) + shutil.copy(ca_db.cacert_fname, "/usr/share/ipa/html/ca.crt") + os.chmod("/usr/share/ipa/html/ca.crt", 0444) + def uninstall(self): running = self.restore_state("running") enabled = self.restore_state("enabled") -- cgit