Check LDAP instead of local configuration to see if IPA CA is enabled

The check is done using a new hidden command ca_is_enabled.

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

Reviewed-By: David Kupka <dkupka@redhat.com>
This commit is contained in:
Jan Cholasta 2014-10-13 14:30:15 +02:00 committed by Martin Kosek
parent 277850e02c
commit 5303e6324e
16 changed files with 144 additions and 65 deletions

View File

@ -450,6 +450,12 @@ arg: Any('methods*')
option: Str('version?', exclude='webui')
output: Output('count', <type 'int'>, None)
output: Output('results', (<type 'list'>, <type 'tuple'>), None)
command: ca_is_enabled
args: 0,1,3
option: Str('version?', exclude='webui')
output: Output('result', <type 'bool'>, None)
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: cert_find
args: 0,17,4
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')

View File

@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
IPA_API_VERSION_MINOR=106
# Last change: npmccallum - Remove token vendor, model, serial defaults
IPA_API_VERSION_MINOR=107
# Last change: jcholast - add ca_is_enabled

View File

@ -255,9 +255,6 @@ def install_master(safe_options, options):
api.bootstrap(in_server=True)
api.finalize()
if api.env.enable_ra:
sys.exit("CA is already installed.\n")
dm_password = options.password
if not dm_password:
if options.unattended:
@ -272,6 +269,9 @@ def install_master(safe_options, options):
api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
bind_pw=dm_password)
if api.Command.ca_is_enabled()['result']:
sys.exit("CA is already installed.\n")
config = api.Command['config_show']()['result']
subject_base = config['ipacertificatesubjectbase'][0]

View File

@ -235,7 +235,8 @@ def install_http(config, auto_redirect):
http.create_instance(
config.realm_name, config.host_name, config.domain_name,
config.dirman_password, False, pkcs12_info,
auto_redirect=auto_redirect, ca_file = config.dir + "/ca.crt")
auto_redirect=auto_redirect, ca_file = config.dir + "/ca.crt",
ca_is_configured=ipautil.file_exists(config.dir + "/cacert.p12"))
# Now copy the autoconfiguration files
try:

View File

@ -1214,11 +1214,13 @@ def main():
http.create_instance(
realm_name, host_name, domain_name, dm_password,
pkcs12_info=http_pkcs12_info, subject_base=options.subject,
auto_redirect=options.ui_redirect)
auto_redirect=options.ui_redirect,
ca_is_configured=setup_ca)
else:
http.create_instance(
realm_name, host_name, domain_name, dm_password,
subject_base=options.subject, auto_redirect=options.ui_redirect)
subject_base=options.subject, auto_redirect=options.ui_redirect,
ca_is_configured=setup_ca)
tasks.restore_context(paths.CACHE_IPA_SESSIONS)
# Export full CA chain

View File

@ -976,11 +976,13 @@ def add_ca_dns_records():
root_logger.info('IPA CA DNS records already processed')
return
try:
api.Backend.ldap2.connect(autobind=True)
except ipalib.errors.PublicError, e:
root_logger.error("Cannot connect to LDAP to add DNS records: %s", e)
return
if not api.Backend.ldap2.isconnected():
try:
api.Backend.ldap2.connect(autobind=True)
except ipalib.errors.PublicError, e:
root_logger.error(
"Cannot connect to LDAP to add DNS records: %s", e)
return
ret = api.Command['dns_is_enabled']()
if not ret['result']:
@ -1191,12 +1193,19 @@ def remove_ds_ra_cert(subject_base):
def fix_trust_flags():
root_logger.info('[Fixing trust flags in %s]' % paths.HTTPD_ALIAS_DIR)
if not api.env.enable_ra:
root_logger.info("CA is not enabled")
if sysupgrade.get_upgrade_state('http', 'fix_trust_flags'):
root_logger.info("Trust flags already processed")
return
if sysupgrade.get_upgrade_state(service, 'fix_trust_flags'):
root_logger.info("Trust flags already fixed")
if not api.Backend.ldap2.isconnected():
try:
api.Backend.ldap2.connect(autobind=True)
except ipalib.errors.PublicError, e:
root_logger.error("Cannot connect to LDAP: %s", e)
return
if not api.Command.ca_is_enabled()['result']:
root_logger.info("CA is not enabled")
return
db = certs.CertDB(api.env.realm)

View File

@ -1093,11 +1093,11 @@ def configure_krb5_conf(cli_realm, cli_domain, cli_server, cli_kdc, dnsok,
return 0
def configure_certmonger(fstore, subject_base, cli_realm, hostname, options,
remote_env):
ca_enabled):
if not options.request_cert:
return
if not remote_env['enable_ra']:
if not ca_enabled:
root_logger.warning(
"An RA is not configured on the server. "
"Not requesting host certificate.")
@ -1696,11 +1696,11 @@ def print_port_conf_info():
" TCP: 464\n"
" UDP: 464, 123 (if NTP enabled)")
def get_certs_from_ldap(server, base_dn, realm, enable_ra):
def get_certs_from_ldap(server, base_dn, realm, ca_enabled):
conn = ipaldap.IPAdmin(server, sasl_nocanon=True)
try:
conn.do_sasl_gssapi_bind()
certs = certstore.get_ca_certs(conn, base_dn, realm, enable_ra)
certs = certstore.get_ca_certs(conn, base_dn, realm, ca_enabled)
except errors.NotFound:
raise errors.NoCertificateError(entry=server)
except errors.NetworkError, e:
@ -2640,13 +2640,20 @@ def install(options, env, fstore, statestore):
return CLIENT_INSTALL_ERROR
# Use the RPC directly so older servers are supported
result = api.Backend.rpcclient.forward(
'env',
server=True,
version=u'2.0',
)
remote_env = result['result']
if not remote_env['enable_ra']:
try:
result = api.Backend.rpcclient.forward(
'ca_is_enabled',
version=u'2.0',
)
ca_enabled = result['result']
except errors.CommandError:
result = api.Backend.rpcclient.forward(
'env',
server=True,
version=u'2.0',
)
ca_enabled = result['result']['enable_ra']
if not ca_enabled:
disable_ra()
# Create IPA NSS database
@ -2658,7 +2665,7 @@ def install(options, env, fstore, statestore):
# Get CA certificates from the certificate store
ca_certs = get_certs_from_ldap(cli_server[0], cli_basedn, cli_realm,
remote_env['enable_ra'])
ca_enabled)
ca_certs_trust = [(c, n, certstore.key_policy_to_trust_flags(t, True, u))
for (c, n, t, u) in ca_certs]
@ -2692,7 +2699,7 @@ def install(options, env, fstore, statestore):
if not options.on_master:
client_dns(cli_server[0], hostname, options.dns_updates)
configure_certmonger(fstore, subject_base, cli_realm, hostname,
options, remote_env)
options, ca_enabled)
update_ssh_keys(cli_server[0], hostname, services.knownservices.sshd.get_config_dir(), options.create_sshfp)

View File

@ -27,7 +27,7 @@ from ipapython import (admintool, ipautil, ipaldap, sysrestore, dogtag,
from ipaplatform import services
from ipaplatform.paths import paths
from ipaplatform.tasks import tasks
from ipalib import api, x509, certstore
from ipalib import api, errors, x509, certstore
class CertUpdate(admintool.AdminTool):
@ -59,10 +59,26 @@ class CertUpdate(admintool.AdminTool):
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir, principal)
api.Backend.rpcclient.connect()
try:
result = api.Backend.rpcclient.forward(
'ca_is_enabled',
version=u'2.0',
)
ca_enabled = result['result']
except errors.CommandError:
result = api.Backend.rpcclient.forward(
'env',
server=True,
version=u'2.0',
)
ca_enabled = result['result']['enable_ra']
api.Backend.rpcclient.disconnect()
ldap.do_sasl_gssapi_bind()
certs = certstore.get_ca_certs(ldap, api.env.basedn,
api.env.realm, api.env.enable_ra)
api.env.realm, ca_enabled)
finally:
shutil.rmtree(tmpdir)

View File

@ -19,13 +19,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from ipalib import api, SkipPluginModule
if api.env.enable_ra is not True:
# In this case, abort loading this plugin module...
raise SkipPluginModule(reason='env.enable_ra is not True')
import os
import time
from ipalib import Command, Str, Int, Bytes, Flag, File
from ipalib import api
from ipalib import errors
from ipalib import pkcs10
from ipalib import x509
@ -33,6 +30,7 @@ from ipalib import util
from ipalib import ngettext
from ipalib.plugable import Registry
from ipalib.plugins.virtual import *
from ipalib.plugins.baseldap import pkey_to_value
from ipalib.plugins.service import split_principal
import base64
import traceback
@ -214,6 +212,10 @@ def get_host_from_principal(principal):
return hostname
def ca_enabled_check():
if not api.Command.ca_is_enabled()['result']:
raise errors.NotFound(reason=_('CA is not configured'))
@register()
class cert_request(VirtualCommand):
__doc__ = _('Submit a certificate signing request.')
@ -289,6 +291,8 @@ class cert_request(VirtualCommand):
}
def execute(self, csr, **kw):
ca_enabled_check()
ldap = self.api.Backend.ldap2
principal = kw.get('principal')
add = kw.get('add')
@ -475,6 +479,7 @@ class cert_status(VirtualCommand):
def execute(self, request_id, **kw):
ca_enabled_check()
self.check_access()
return dict(
result=self.Backend.ra.check_request_status(request_id)
@ -536,6 +541,7 @@ class cert_show(VirtualCommand):
operation="retrieve certificate"
def execute(self, serial_number, **options):
ca_enabled_check()
hostname = None
try:
self.check_access()
@ -603,6 +609,7 @@ class cert_revoke(VirtualCommand):
)
def execute(self, serial_number, **kw):
ca_enabled_check()
hostname = None
try:
self.check_access()
@ -641,6 +648,7 @@ class cert_remove_hold(VirtualCommand):
operation = "certificate remove hold"
def execute(self, serial_number, **kw):
ca_enabled_check()
self.check_access()
return dict(
result=self.Backend.ra.take_certificate_off_hold(serial_number)
@ -740,6 +748,7 @@ class cert_find(Command):
)
def execute(self, **options):
ca_enabled_check()
ret = dict(
result=self.Backend.ra.find(options)
)
@ -747,3 +756,24 @@ class cert_find(Command):
ret['truncated'] = False
return ret
@register()
class ca_is_enabled(Command):
"""
Checks if any of the servers has the CA service enabled.
"""
NO_CLI = True
has_output = output.standard_value
def execute(self, *args, **options):
base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
self.api.env.basedn)
filter = '(&(objectClass=ipaConfigObject)(cn=CA))'
try:
self.api.Backend.ldap2.find_entries(
base_dn=base_dn, filter=filter, attrs_list=[])
except errors.NotFound:
result = False
else:
result = True
return dict(result=result, value=pkey_to_value(None, options))

View File

@ -721,7 +721,7 @@ class host_del(LDAPDelete):
**delkw)
break
if self.api.env.enable_ra:
if self.api.Command.ca_is_enabled()['result']:
try:
entry_attrs = ldap.get_entry(dn, ['usercertificate'])
except errors.NotFound:
@ -806,7 +806,7 @@ class host_mod(LDAPUpdate):
entry_attrs['objectclass'] = obj_classes
cert = x509.normalize_certificate(entry_attrs.get('usercertificate'))
if cert:
if self.api.env.enable_ra:
if self.api.Command.ca_is_enabled()['result']:
x509.verify_cert_subject(ldap, keys[-1], cert)
entry_attrs_old = ldap.get_entry(dn, ['usercertificate'])
oldcert = entry_attrs_old.single_value.get('usercertificate')
@ -1084,7 +1084,7 @@ class host_disable(LDAPQuery):
self.obj.handle_not_found(*keys)
cert = entry_attrs.single_value.get('usercertificate')
if cert:
if self.api.env.enable_ra:
if self.api.Command.ca_is_enabled()['result']:
cert = x509.normalize_certificate(cert)
try:
serial = unicode(x509.get_serial_number(cert, x509.DER))

View File

@ -486,7 +486,7 @@ class service_del(LDAPDelete):
# custom services allow them to manage them.
(service, hostname, realm) = split_principal(keys[-1])
check_required_principal(ldap, hostname, service)
if self.api.env.enable_ra:
if self.api.Command.ca_is_enabled()['result']:
try:
entry_attrs = ldap.get_entry(dn, ['usercertificate'])
except errors.NotFound:
@ -676,7 +676,7 @@ class service_disable(LDAPQuery):
done_work = False
if 'usercertificate' in entry_attrs:
if self.api.env.enable_ra:
if self.api.Command.ca_is_enabled()['result']:
cert = x509.normalize_certificate(entry_attrs.get('usercertificate')[0])
try:
serial = unicode(x509.get_serial_number(cert, x509.DER))

View File

@ -71,7 +71,7 @@ def subject_base():
return _subject_base
def valid_issuer(issuer):
if not api.env.enable_ra:
if not api.Command.ca_is_enabled()['result']:
return True
# Handle all supported forms of issuer -- currently dogtag only.
if api.env.ra_plugin == 'dogtag':

View File

@ -82,12 +82,14 @@ class HTTPInstance(service.Service):
self.fstore = sysrestore.FileStore(paths.SYSRESTORE)
self.cert_nickname = cert_nickname
self.ca_is_configured = True
subject_base = ipautil.dn_attribute_property('_subject_base')
def create_instance(self, realm, fqdn, domain_name, dm_password=None,
autoconfig=True, pkcs12_info=None,
subject_base=None, auto_redirect=True, ca_file=None):
subject_base=None, auto_redirect=True, ca_file=None,
ca_is_configured=None):
self.fqdn = fqdn
self.realm = realm
self.domain = domain_name
@ -105,6 +107,8 @@ class HTTPInstance(service.Service):
CRL_PUBLISH_PATH=dogtag.install_constants.CRL_PUBLISH_PATH,
)
self.ca_file = ca_file
if ca_is_configured is not None:
self.ca_is_configured = ca_is_configured
# get a connection to the DS
self.ldap_connect()
@ -219,7 +223,7 @@ class HTTPInstance(service.Service):
db = certs.CertDB(self.realm, subject_base=self.subject_base)
if self.pkcs12_info:
if api.env.enable_ra:
if self.ca_is_configured:
trust_flags = 'CT,C,C'
else:
trust_flags = None
@ -236,7 +240,7 @@ class HTTPInstance(service.Service):
nickname = server_certs[0][0]
self.dercert = db.get_cert_from_db(nickname, pem=False)
if api.env.enable_ra:
if self.ca_is_configured:
db.track_server_cert(nickname, self.principal, db.passwd_fname, 'restart_httpd')
self.__set_mod_nss_nickname(nickname)
@ -267,7 +271,7 @@ class HTTPInstance(service.Service):
def __import_ca_certs(self):
db = certs.CertDB(self.realm, subject_base=self.subject_base)
self.import_ca_certs(db, api.env.enable_ra)
self.import_ca_certs(db, self.ca_is_configured)
def __setup_autoconfig(self):
target_fname = paths.PREFERENCES_HTML

View File

@ -161,12 +161,6 @@ class ReplicaPrepare(admintool.AdminTool):
if api.env.host == self.replica_fqdn:
raise admintool.ScriptError("You can't create a replica on itself")
if not api.env.enable_ra and not options.http_cert_files:
raise admintool.ScriptError(
"Cannot issue certificates: a CA is not installed. Use the "
"--http-cert-file, --dirsrv-cert-file options to provide "
"custom certificates.")
config_dir = dsinstance.config_dirname(
dsinstance.realm_to_serverid(api.env.realm))
if not ipautil.dir_exists(config_dir):
@ -198,10 +192,11 @@ class ReplicaPrepare(admintool.AdminTool):
# Try out the password & get the subject base
suffix = ipautil.realm_to_suffix(api.env.realm)
try:
conn = ldap2(shared_instance=False, base_dn=suffix)
conn = api.Backend.ldap2
conn.connect(bind_dn=DN(('cn', 'directory manager')),
bind_pw=self.dirman_password)
entry_attrs = conn.get_ipa_config()
ca_enabled = api.Command.ca_is_enabled()['result']
conn.disconnect()
except errors.ACIError:
raise admintool.ScriptError("The password provided is incorrect "
@ -212,6 +207,12 @@ class ReplicaPrepare(admintool.AdminTool):
except errors.DatabaseError, e:
raise admintool.ScriptError(e.desc)
if not ca_enabled and not options.http_cert_files:
raise admintool.ScriptError(
"Cannot issue certificates: a CA is not installed. Use the "
"--http-cert-file, --dirsrv-cert-file options to provide "
"custom certificates.")
self.subject_base = entry_attrs.get(
'ipacertificatesubjectbase', [None])[0]
if self.subject_base is not None:

View File

@ -83,7 +83,7 @@ class ServerCertInstall(admintool.AdminTool):
def ask_for_options(self):
super(ServerCertInstall, self).ask_for_options()
if self.options.dirsrv and not self.options.dirman_password:
if not self.options.dirman_password:
self.options.dirman_password = installutils.read_password(
"Directory Manager", confirm=False, validate=False, retry=False)
if self.options.dirman_password is None:
@ -101,20 +101,23 @@ class ServerCertInstall(admintool.AdminTool):
api.bootstrap(in_server=True)
api.finalize()
conn = api.Backend.ldap2
conn.connect(bind_dn=DN(('cn', 'directory manager')),
bind_pw=self.options.dirman_password)
if self.options.dirsrv:
self.install_dirsrv_cert()
if self.options.http:
self.install_http_cert()
conn.disconnect()
def install_dirsrv_cert(self):
serverid = dsinstance.realm_to_serverid(api.env.realm)
dirname = dsinstance.config_dirname(serverid)
conn = ldap2(shared_instance=False, base_dn='')
conn.connect(bind_dn=DN(('cn', 'directory manager')),
bind_pw=self.options.dirman_password)
conn = api.Backend.ldap2
entry = conn.get_entry(DN(('cn', 'RSA'), ('cn', 'encryption'),
('cn', 'config')),
['nssslpersonalityssl'])
@ -130,8 +133,6 @@ class ServerCertInstall(admintool.AdminTool):
except errors.EmptyModlist:
pass
conn.disconnect()
def install_http_cert(self):
dirname = certs.NSS_DIR
@ -165,14 +166,15 @@ class ServerCertInstall(admintool.AdminTool):
cdb = certs.CertDB(api.env.realm, nssdir=dirname)
try:
if api.env.enable_ra:
ca_enabled = api.Command.ca_is_enabled()['result']
if ca_enabled:
cdb.untrack_server_cert(old_cert)
cdb.delete_cert(old_cert)
cdb.import_pkcs12(pkcs12_file.name, pin)
server_cert = cdb.find_server_certs()[0][0]
if api.env.enable_ra:
if ca_enabled:
cdb.track_server_cert(server_cert, principal, cdb.passwd_fname,
command)
except RuntimeError, e:

View File

@ -34,7 +34,8 @@ class update_upload_cacrt(PostUpdate):
db = certs.CertDB(self.api.env.realm)
ca_cert = None
if self.api.env.enable_ra:
ca_enabled = self.api.Command.ca_is_enabled()['result']
if ca_enabled:
ca_nickname = certdb.get_ca_nickname(self.api.env.realm)
else:
ca_nickname = None
@ -49,7 +50,7 @@ class update_upload_cacrt(PostUpdate):
for nickname, trust_flags in db.list_certs():
if 'u' in trust_flags:
continue
if nickname == ca_nickname and self.api.env.enable_ra:
if nickname == ca_nickname and ca_enabled:
trust_flags = 'CT,C,C'
cert = db.get_cert_from_db(nickname, pem=False)
try:
@ -60,7 +61,7 @@ class update_upload_cacrt(PostUpdate):
continue
if nickname == ca_nickname:
ca_cert = cert
if self.api.env.enable_ra:
if ca_enabled:
entry.append('ipaConfigString:ipaCA')
entry.append('ipaConfigString:compatCA')
updates[dn] = {'dn': dn, 'default': entry}