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
This commit is contained in:
Rob Crittenden
2009-04-13 13:39:15 -04:00
parent fdf03cb07b
commit 9182c10b03
5 changed files with 362 additions and 102 deletions

View File

@@ -42,6 +42,7 @@ from ipaserver.install import krbinstance
from ipaserver.install import bindinstance
from ipaserver.install import httpinstance
from ipaserver.install import ntpinstance
from ipaserver.install import certs
from ipaserver.install import service
from ipapython import version
@@ -512,6 +513,12 @@ def main():
print >> sys.stderr, "Import failed: %s" % sys.exc_value
sys.exit(1)
# Clean up any previous self-signed CA that may exist
try:
os.remove(certs.CA_SERIALNO)
except:
pass
cs = cainstance.CADSInstance()
cs.create_instance("dirsrv", realm_name, host_name, domain_name, dm_password)
ca = cainstance.CAInstance()
@@ -526,7 +533,7 @@ def main():
finally:
os.remove(pw_name)
else:
ds.create_instance(ds_user, realm_name, host_name, domain_name, dm_password)
ds.create_instance(ds_user, realm_name, host_name, domain_name, dm_password, self_signed_ca=not options.ca)
# Create a kerberos instance
krb = krbinstance.KrbInstance(fstore)
@@ -545,7 +552,7 @@ def main():
http.create_instance(realm_name, host_name, domain_name, autoconfig=False, pkcs12_info=pkcs12_info)
os.remove(pw_name)
else:
http.create_instance(realm_name, host_name, domain_name, autoconfig=True)
http.create_instance(realm_name, host_name, domain_name, autoconfig=True, self_signed_ca=not options.ca)
# Create the config file
fstore.backup_file("/etc/ipa/ipa.conf")

View File

@@ -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")
# 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 = data.split('\r\n')
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")
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 = data.split('\r\n')
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)

View File

@@ -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()
# 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.")
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).

View File

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

View File

@@ -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, '</VirtualHost>', 'Include conf.d/ipa-rewrite.conf\n</VirtualHost>') != 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")