Remove NSSConnection from Dogtag

Replaced NSSConnection with Python's httplib.HTTPSConnection.
This class is OpenSSL-based.

A client certificate with a private key is required to authenticate
against the certificate server. We facilitate the RA_AGENT_PEM which
already exists.

https://fedorahosted.org/freeipa/ticket/5695

Reviewed-By: Jan Cholasta <jcholast@redhat.com>
This commit is contained in:
Stanislav Laznicka 2016-12-20 10:23:47 +01:00 committed by Jan Cholasta
parent 6b074ad833
commit 0a54fac02c
5 changed files with 42 additions and 63 deletions

View File

@ -20,16 +20,16 @@
import collections
import xml.dom.minidom
import nss.nss as nss
import six
# pylint: disable=import-error
from six.moves.urllib.parse import urlencode
# pylint: enable=import-error
from ipalib import api, errors
from ipalib.util import create_https_connection
from ipalib.errors import NetworkError
from ipalib.text import _
from ipapython import nsslib, ipautil
from ipapython import ipautil
from ipapython.ipa_log_manager import root_logger
# Python 3 rename. The package is available in "six.moves.http_client", but
@ -131,8 +131,8 @@ def ca_status(ca_host=None):
return _parse_ca_status(body)
def https_request(host, port, url, secdir, password, nickname,
method='POST', headers=None, body=None, **kw):
def https_request(host, port, url, cafile, client_certfile,
method='POST', headers=None, body=None, **kw):
"""
:param method: HTTP request method (defalut: 'POST')
:param url: The path (not complete URL!) to post to.
@ -145,16 +145,12 @@ def https_request(host, port, url, secdir, password, nickname,
"""
def connection_factory(host, port):
no_init = secdir == nsslib.current_dbdir
conn = nsslib.NSSConnection(host, port, dbdir=secdir, no_init=no_init,
tls_version_min=api.env.tls_version_min,
tls_version_max=api.env.tls_version_max)
conn.set_debuglevel(0)
conn.connect()
conn.sock.set_client_auth_data_callback(
nsslib.client_auth_data_callback,
nickname, password, nss.get_default_certdb())
return conn
return create_https_connection(
host, port,
cafile=cafile,
client_certfile=client_certfile,
tls_version_min=api.env.tls_version_min,
tls_version_max=api.env.tls_version_max)
if body is None:
body = urlencode(kw)

View File

@ -1584,7 +1584,6 @@ def import_included_profiles():
cn=['certprofiles'],
)
api.Backend.ra_certprofile._read_password()
api.Backend.ra_certprofile.override_port = 8443
for (profile_id, desc, store_issued) in dogtag.INCLUDED_PROFILES:
@ -1621,7 +1620,6 @@ def repair_profile_caIPAserviceCert():
This function detects and repairs occurrences of this problem.
"""
api.Backend.ra_certprofile._read_password()
api.Backend.ra_certprofile.override_port = 8443
profile_id = 'caIPAserviceCert'
@ -1664,8 +1662,6 @@ def migrate_profiles_to_ldap():
"""
ensure_ldap_profiles_container()
api.Backend.ra_certprofile._read_password()
api.Backend.ra_certprofile.override_port = 8443
with open(paths.CA_CS_CFG_PATH) as f:
@ -1750,8 +1746,6 @@ def ensure_ipa_authority_entry():
"""
# find out authority id, issuer DN and subject DN of IPA CA
#
api.Backend.ra_lightweight_ca._read_password()
api.Backend.ra_lightweight_ca.override_port = 8443
with api.Backend.ra_lightweight_ca as lwca:
data = lwca.read_ca('host-authority')

View File

@ -330,7 +330,7 @@ class CertDB(object):
except RuntimeError as e:
root_logger.error("certmonger failed to stop tracking certificate: %s" % str(e))
def create_server_cert(self, nickname, hostname, other_certdb=None, subject=None):
def create_server_cert(self, nickname, hostname, subject=None):
"""
If we are using a dogtag CA then other_certdb contains the RA agent key
that will issue our cert.
@ -339,13 +339,10 @@ class CertDB(object):
Returns a certificate in DER format.
"""
cdb = other_certdb
if not cdb:
cdb = self
if subject is None:
subject=DN(('CN', hostname), self.subject_base)
self.request_cert(subject, san_dnsnames=[hostname])
cdb.issue_server_cert(self.certreq_fname, self.certder_fname)
self.issue_server_cert(self.certreq_fname, self.certder_fname)
self.import_cert(self.certder_fname, nickname)
fd = open(self.certder_fname, "r")
dercert = fd.read()
@ -397,12 +394,12 @@ class CertDB(object):
'xmlOutput': 'true'}
# Send the request to the CA
f = open(self.passwd_fname, "r")
password = f.readline()
f.close()
result = dogtag.https_request(
self.host_name, 8443, "/ca/ee/ca/profileSubmitSSLClient",
self.secdir, password, "ipaCert", **params)
self.host_name, 8443,
url="/ca/ee/ca/profileSubmitSSLClient",
cafile=api.env.tls_ca_cert,
client_certfile=paths.RA_AGENT_PEM,
**params)
http_status, _http_headers, http_body = result
root_logger.debug("CA answer: %s", http_body)
@ -451,12 +448,12 @@ class CertDB(object):
'xmlOutput': 'true'}
# Send the request to the CA
f = open(self.passwd_fname, "r")
password = f.readline()
f.close()
result = dogtag.https_request(
self.host_name, 8443, "/ca/ee/ca/profileSubmitSSLClient",
self.secdir, password, "ipaCert", **params)
self.host_name, 8443,
url="/ca/ee/ca/profileSubmitSSLClient",
cafile=api.env.tls_ca_cert,
client_certfile=paths.RA_AGENT_PEM,
**params)
http_status, _http_headers, http_body = result
if http_status != 200:
raise RuntimeError("Unable to submit cert request")

View File

@ -600,17 +600,14 @@ class ReplicaPrepare(admintool.AdminTool):
db = certs.CertDB(
api.env.realm, nssdir=self.dir, subject_base=subject_base)
db.create_passwd_file()
ca_db = certs.CertDB(
api.env.realm, host_name=api.env.host,
subject_base=subject_base)
db.create_from_cacert()
db.create_server_cert(nickname, hostname, ca_db)
db.create_server_cert(nickname, hostname)
pkcs12_fname = os.path.join(self.dir, fname + ".p12")
try:
if is_kdc:
ca_db.export_pem_p12(pkcs12_fname, passwd_fname,
db.export_pem_p12(pkcs12_fname, passwd_fname,
nickname, os.path.join(self.dir, "kdc.pem"))
else:
db.export_pkcs12(pkcs12_fname, passwd_fname, nickname)

View File

@ -1238,30 +1238,18 @@ class RestClient(Backend):
return None
def __init__(self, api):
self.ca_cert = api.env.tls_ca_cert
if api.env.in_tree:
self.sec_dir = api.env.dot_ipa + os.sep + 'alias'
self.pwd_file = self.sec_dir + os.sep + '.pwd'
self.client_certfile = os.path.join(
api.env.dot_ipa, 'ra-agent.pem')
else:
self.sec_dir = paths.IPA_RADB_DIR
self.pwd_file = os.path.join(paths.IPA_RADB_DIR, 'pwdfile.txt')
self.noise_file = self.sec_dir + os.sep + '.noise'
self.ipa_key_size = "2048"
self.ipa_certificate_nickname = "ipaCert"
self.ca_certificate_nickname = "caCert"
self._read_password()
self.client_certfile = paths.RA_AGENT_PEM
super(RestClient, self).__init__(api)
# session cookie
self.override_port = None
self.cookie = None
def _read_password(self):
try:
with open(self.pwd_file) as f:
self.password = f.readline().strip()
except IOError:
self.password = ''
@cachedproperty
def ca_host(self):
"""
@ -1288,8 +1276,9 @@ class RestClient(Backend):
return
status, resp_headers, _resp_body = dogtag.https_request(
self.ca_host, self.override_port or self.env.ca_agent_port,
'/ca/rest/account/login',
self.sec_dir, self.password, self.ipa_certificate_nickname,
url='/ca/rest/account/login',
cafile=self.ca_cert,
client_certfile=self.client_certfile,
method='GET'
)
cookies = ipapython.cookie.Cookie.parse(resp_headers.get('set-cookie', ''))
@ -1302,8 +1291,9 @@ class RestClient(Backend):
"""Log out of the REST API"""
dogtag.https_request(
self.ca_host, self.override_port or self.env.ca_agent_port,
'/ca/rest/account/logout',
self.sec_dir, self.password, self.ipa_certificate_nickname,
url='/ca/rest/account/logout',
cafile=self.ca_cert,
client_certfile=self.client_certfile,
method='GET'
)
self.cookie = None
@ -1344,8 +1334,9 @@ class RestClient(Backend):
# perform main request
status, resp_headers, resp_body = dogtag.https_request(
self.ca_host, self.override_port or self.env.ca_agent_port,
resource,
self.sec_dir, self.password, self.ipa_certificate_nickname,
url=resource,
cafile=self.ca_cert,
client_certfile=self.client_certfile,
method=method, headers=headers, body=body
)
if status < 200 or status >= 300:
@ -1426,7 +1417,11 @@ class ra(rabase.rabase, RestClient):
Perform an HTTPS request
"""
return dogtag.https_request(self.ca_host, port, url, self.sec_dir, self.password, self.ipa_certificate_nickname, **kw)
return dogtag.https_request(
self.ca_host, port, url,
cafile=self.ca_cert,
client_certfile=self.client_certfile,
**kw)
def get_parse_result_xml(self, xml_text, parse_func):
'''