ipautil: move kinit functions to ipalib.install

kinit_password() depends on ipaplatform.

Move kinit_password() as well as kinit_keytab() to a new
ipalib.install.kinit module, as they are used only from installers.

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

Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
This commit is contained in:
Jan Cholasta 2016-11-23 17:40:47 +01:00 committed by Martin Basti
parent 75b70e3f0d
commit 7d5c680ace
16 changed files with 146 additions and 127 deletions

View File

@ -42,6 +42,7 @@ from six.moves.urllib.parse import urlsplit
from optparse import OptionParser # pylint: disable=deprecated-module
from ipalib import api, errors
from ipalib.install import sysrestore
from ipalib.install.kinit import kinit_keytab
from ipapython import ipautil
from ipaclient import ipadiscovery
from ipaclient import ipachangeconf
@ -443,7 +444,7 @@ def main():
try:
try:
host_princ = str('host/%s@%s' % (api.env.host, api.env.realm))
ipautil.kinit_keytab(host_princ, paths.KRB5_KEYTAB, ccache_name)
kinit_keytab(host_princ, paths.KRB5_KEYTAB, ccache_name)
os.environ['KRB5CCNAME'] = ccache_name
except gssapi.exceptions.GSSError as e:
sys.exit("Failed to obtain host TGT: %s" % e)

View File

@ -15,10 +15,10 @@ import os
import sys
import ipalib
from ipalib.install.kinit import kinit_keytab
from ipapython.dn import DN
from ipapython.ipa_log_manager import root_logger, standard_logging_setup
from ipapython import ipaldap
from ipapython import ipautil
from ipaplatform.paths import paths
from ipaserver.dnssec.abshsm import (sync_pkcs11_metadata,
ldap2p11helper_api_params,
@ -134,8 +134,8 @@ log.debug('Kerberos principal: %s', PRINCIPAL)
ccache_filename = os.path.join(WORKDIR, 'ipa-dnskeysync-replica.ccache')
try:
ipautil.kinit_keytab(PRINCIPAL, paths.IPA_DNSKEYSYNCD_KEYTAB,
ccache_filename, attempts=5)
kinit_keytab(PRINCIPAL, paths.IPA_DNSKEYSYNCD_KEYTAB, ccache_filename,
attempts=5)
except GSSError as e:
log.critical('Kerberos authentication failed: %s', e)
sys.exit(1)

View File

@ -11,10 +11,10 @@ import signal
import time
from ipalib import api
from ipalib.install.kinit import kinit_keytab
from ipapython.dn import DN
from ipapython.ipa_log_manager import root_logger, standard_logging_setup
from ipapython import ipaldap
from ipapython import ipautil
from ipaplatform.paths import paths
from ipaserver.dnssec.keysyncer import KeySyncer
@ -65,7 +65,7 @@ PRINCIPAL = str('%s/%s' % (DAEMONNAME, api.env.host))
log.debug('Kerberos principal: %s', PRINCIPAL)
ccache_filename = os.path.join(WORKDIR, 'ipa-dnskeysyncd.ccache')
try:
ipautil.kinit_keytab(PRINCIPAL, KEYTAB_FB, ccache_filename, attempts=5)
kinit_keytab(PRINCIPAL, KEYTAB_FB, ccache_filename, attempts=5)
except Exception as ex:
log.critical("Kerberos authentication failed: %s", ex)
# signal failure and let init system to restart the daemon

View File

@ -32,9 +32,9 @@ import sqlite3
import traceback
import ipalib
from ipalib.install.kinit import kinit_keytab
from ipapython.dn import DN
from ipapython import ipaldap
from ipapython import ipautil
from ipaplatform.paths import paths
from ipaserver.dnssec.abshsm import sync_pkcs11_metadata, wrappingmech_name2id
from ipaserver.dnssec.ldapkeydb import LdapKeyDB
@ -623,8 +623,8 @@ log.debug('Kerberos principal: %s', PRINCIPAL)
ccache_name = paths.IPA_ODS_EXPORTER_CCACHE
try:
ipautil.kinit_keytab(PRINCIPAL, paths.IPA_ODS_EXPORTER_KEYTAB, ccache_name,
attempts=5)
kinit_keytab(PRINCIPAL, paths.IPA_ODS_EXPORTER_KEYTAB, ccache_name,
attempts=5)
except GSSError as e:
log.critical('Kerberos authentication failed: %s', e)
sys.exit(1)

View File

@ -7,7 +7,6 @@ from ipalib import api
from ipapython.dn import DN
from ipalib.config import Env
from ipalib.constants import DEFAULT_CONFIG
from ipapython.ipautil import kinit_keytab
from ipaplatform.constants import constants
import sys
import os
@ -16,6 +15,8 @@ import pwd
import six
import gssapi
from ipalib.install.kinit import kinit_keytab
if six.PY3:
unicode = str

View File

@ -29,6 +29,7 @@ import traceback
from ipapython import ipautil
from ipalib import api, errors, x509, certstore
from ipalib.install.kinit import kinit_keytab
from ipaserver.install import certs, cainstance, installutils
from ipaserver.plugins.ldap2 import ldap2
from ipaplatform import services
@ -72,7 +73,7 @@ def _main():
try:
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
ccache_filename = os.path.join(tmpdir, 'ccache')
ipautil.kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename)
kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename)
os.environ['KRB5CCNAME'] = ccache_filename
ca = cainstance.CAInstance(host_name=api.env.host)

View File

@ -27,7 +27,7 @@ import tempfile
import shutil
import traceback
from ipapython import ipautil
from ipalib.install.kinit import kinit_keytab
from ipalib import api
from ipaserver.install import certs, cainstance, krainstance
from ipaplatform.paths import paths
@ -44,8 +44,7 @@ def _main():
try:
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
ccache_filename = os.path.join(tmpdir, 'ccache')
ipautil.kinit_keytab(principal, paths.KRB5_KEYTAB,
ccache_filename)
kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename)
os.environ['KRB5CCNAME'] = ccache_filename
ca = cainstance.CAInstance(host_name=api.env.host)

View File

@ -22,6 +22,8 @@ import sys
import os
import shutil
import tempfile
from ipalib.install.kinit import kinit_keytab
from ipapython import ipautil
from ipaserver.install import installutils
@ -227,7 +229,7 @@ def promote(safe_options, options, filename):
with ipautil.private_ccache():
ccache = os.environ['KRB5CCNAME']
ipautil.kinit_keytab(
kinit_keytab(
'host/{env.host}@{env.realm}'.format(env=api.env),
paths.KRB5_KEYTAB,
ccache)

View File

@ -45,6 +45,7 @@ from ipalib import (
from ipalib.constants import CACERT
from ipalib.install import certmonger, service, sysrestore
from ipalib.install import hostname as hostname_
from ipalib.install.kinit import kinit_keytab, kinit_password
from ipalib.install.service import enroll_only, prepare_only
from ipalib.rpc import delete_persistent_client_session_data
from ipalib.util import (
@ -2497,8 +2498,8 @@ def _install(options):
stdin = sys.stdin.readline()
try:
ipautil.kinit_password(principal, stdin, ccache_name,
config=krb_name)
kinit_password(principal, stdin, ccache_name,
config=krb_name)
except RuntimeError as e:
print_port_conf_info()
raise ScriptError(
@ -2508,10 +2509,11 @@ def _install(options):
join_args.append("-f")
if os.path.exists(options.keytab):
try:
ipautil.kinit_keytab(host_principal, options.keytab,
ccache_name,
config=krb_name,
attempts=options.kinit_attempts)
kinit_keytab(host_principal,
options.keytab,
ccache_name,
config=krb_name,
attempts=options.kinit_attempts)
except gssapi.exceptions.GSSError as e:
print_port_conf_info()
raise ScriptError(
@ -2592,10 +2594,9 @@ def _install(options):
# Other KDCs might not have replicated the principal yet.
# Once we have the TGT, it's usable on any server.
try:
ipautil.kinit_keytab(host_principal, paths.KRB5_KEYTAB,
CCACHE_FILE,
config=krb_name,
attempts=options.kinit_attempts)
kinit_keytab(host_principal, paths.KRB5_KEYTAB, CCACHE_FILE,
config=krb_name,
attempts=options.kinit_attempts)
env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = CCACHE_FILE
except gssapi.exceptions.GSSError as e:
print_port_conf_info()
@ -2646,9 +2647,8 @@ def _install(options):
# If on master assume kerberos is already configured properly.
# Get the host TGT.
try:
ipautil.kinit_keytab(host_principal, paths.KRB5_KEYTAB,
CCACHE_FILE,
attempts=options.kinit_attempts)
kinit_keytab(host_principal, paths.KRB5_KEYTAB, CCACHE_FILE,
attempts=options.kinit_attempts)
os.environ['KRB5CCNAME'] = CCACHE_FILE
except gssapi.exceptions.GSSError as e:
root_logger.error("Failed to obtain host TGT: %s" % e)

View File

@ -26,6 +26,7 @@ from six.moves.urllib.parse import urlsplit
# pylint: enable=import-error
from ipalib.install import certmonger, sysrestore
from ipalib.install.kinit import kinit_keytab
from ipapython import admintool, certdb, ipaldap, ipautil
from ipaplatform import services
from ipaplatform.paths import paths
@ -63,7 +64,7 @@ class CertUpdate(admintool.AdminTool):
ccache_name = os.path.join(tmpdir, 'ccache')
try:
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
ipautil.kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_name)
kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_name)
os.environ['KRB5CCNAME'] = ccache_name
api.Backend.rpcclient.connect()

97
ipalib/install/kinit.py Normal file
View File

@ -0,0 +1,97 @@
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
import os
import time
import gssapi
from ipaplatform.paths import paths
from ipapython.ipa_log_manager import root_logger
from ipapython.ipautil import run
# Cannot contact any KDC for requested realm
KRB5_KDC_UNREACH = 2529639068
# A service is not available that s required to process the request
KRB5KDC_ERR_SVC_UNAVAILABLE = 2529638941
def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
"""
Given a ccache_path, keytab file and a principal kinit as that user.
The optional parameter 'attempts' specifies how many times the credential
initialization should be attempted in case of non-responsive KDC.
"""
errors_to_retry = {KRB5KDC_ERR_SVC_UNAVAILABLE,
KRB5_KDC_UNREACH}
root_logger.debug("Initializing principal %s using keytab %s"
% (principal, keytab))
root_logger.debug("using ccache %s" % ccache_name)
for attempt in range(1, attempts + 1):
old_config = os.environ.get('KRB5_CONFIG')
if config is not None:
os.environ['KRB5_CONFIG'] = config
else:
os.environ.pop('KRB5_CONFIG', None)
try:
name = gssapi.Name(principal, gssapi.NameType.kerberos_principal)
store = {'ccache': ccache_name,
'client_keytab': keytab}
cred = gssapi.Credentials(name=name, store=store, usage='initiate')
root_logger.debug("Attempt %d/%d: success"
% (attempt, attempts))
return cred
except gssapi.exceptions.GSSError as e:
if e.min_code not in errors_to_retry: # pylint: disable=no-member
raise
root_logger.debug("Attempt %d/%d: failed: %s"
% (attempt, attempts, e))
if attempt == attempts:
root_logger.debug("Maximum number of attempts (%d) reached"
% attempts)
raise
root_logger.debug("Waiting 5 seconds before next retry")
time.sleep(5)
finally:
if old_config is not None:
os.environ['KRB5_CONFIG'] = old_config
else:
os.environ.pop('KRB5_CONFIG', None)
def kinit_password(principal, password, ccache_name, config=None,
armor_ccache_name=None, canonicalize=False,
enterprise=False):
"""
perform interactive kinit as principal using password. If using FAST for
web-based authentication, use armor_ccache_path to specify http service
ccache.
"""
root_logger.debug("Initializing principal %s using password" % principal)
args = [paths.KINIT, principal, '-c', ccache_name]
if armor_ccache_name is not None:
root_logger.debug("Using armor ccache %s for FAST webauth"
% armor_ccache_name)
args.extend(['-T', armor_ccache_name])
if canonicalize:
root_logger.debug("Requesting principal canonicalization")
args.append('-C')
if enterprise:
root_logger.debug("Using enterprise principal")
args.append('-E')
env = {'LC_ALL': 'C'}
if config is not None:
env['KRB5_CONFIG'] = config
# this workaround enables us to capture stderr and put it
# into the raised exception in case of unsuccessful authentication
result = run(args, stdin=password, env=env, raiseonerr=False,
capture_error=True)
if result.returncode:
raise RuntimeError(result.error_output)

View File

@ -34,7 +34,6 @@ import datetime
import netaddr
import netifaces
import time
import gssapi
import pwd
import grp
from contextlib import contextmanager
@ -56,11 +55,6 @@ from ipapython.dn import DN
GEN_PWD_LEN = 22
GEN_TMP_PWD_LEN = 12 # only for OTP password that is manually retyped by user
# Having this in krb_utils would cause circular import
KRB5_KDC_UNREACH = 2529639068 # Cannot contact any KDC for requested realm
KRB5KDC_ERR_SVC_UNAVAILABLE = 2529638941 # A service is not available that is
# required to process the request
class UnsafeIPAddress(netaddr.IPAddress):
"""Any valid IP address with or without netmask."""
@ -1285,85 +1279,6 @@ def wait_for_open_socket(socket_name, timeout=0):
raise e
def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
"""
Given a ccache_path, keytab file and a principal kinit as that user.
The optional parameter 'attempts' specifies how many times the credential
initialization should be attempted in case of non-responsive KDC.
"""
errors_to_retry = {KRB5KDC_ERR_SVC_UNAVAILABLE,
KRB5_KDC_UNREACH}
root_logger.debug("Initializing principal %s using keytab %s"
% (principal, keytab))
root_logger.debug("using ccache %s" % ccache_name)
for attempt in range(1, attempts + 1):
old_config = os.environ.get('KRB5_CONFIG')
if config is not None:
os.environ['KRB5_CONFIG'] = config
else:
os.environ.pop('KRB5_CONFIG', None)
try:
name = gssapi.Name(principal, gssapi.NameType.kerberos_principal)
store = {'ccache': ccache_name,
'client_keytab': keytab}
cred = gssapi.Credentials(name=name, store=store, usage='initiate')
root_logger.debug("Attempt %d/%d: success"
% (attempt, attempts))
return cred
except gssapi.exceptions.GSSError as e:
if e.min_code not in errors_to_retry: # pylint: disable=no-member
raise
root_logger.debug("Attempt %d/%d: failed: %s"
% (attempt, attempts, e))
if attempt == attempts:
root_logger.debug("Maximum number of attempts (%d) reached"
% attempts)
raise
root_logger.debug("Waiting 5 seconds before next retry")
time.sleep(5)
finally:
if old_config is not None:
os.environ['KRB5_CONFIG'] = old_config
else:
os.environ.pop('KRB5_CONFIG', None)
def kinit_password(principal, password, ccache_name, config=None,
armor_ccache_name=None, canonicalize=False,
enterprise=False):
"""
perform interactive kinit as principal using password. If using FAST for
web-based authentication, use armor_ccache_path to specify http service
ccache.
"""
root_logger.debug("Initializing principal %s using password" % principal)
args = [paths.KINIT, principal, '-c', ccache_name]
if armor_ccache_name is not None:
root_logger.debug("Using armor ccache %s for FAST webauth"
% armor_ccache_name)
args.extend(['-T', armor_ccache_name])
if canonicalize:
root_logger.debug("Requesting principal canonicalization")
args.append('-C')
if enterprise:
root_logger.debug("Using enterprise principal")
args.append('-E')
env = {'LC_ALL': 'C'}
if config is not None:
env['KRB5_CONFIG'] = config
# this workaround enables us to capture stderr and put it
# into the raised exception in case of unsuccessful authentication
result = run(args, stdin=password, env=env, raiseonerr=False,
capture_error=True)
if result.returncode:
raise RuntimeError(result.error_output)
def dn_attribute_property(private_name):
'''
Create a property for a dn attribute which assures the attribute

View File

@ -45,6 +45,7 @@ from six.moves.configparser import SafeConfigParser, NoOptionError
# pylint: enable=import-error
from ipalib.install import sysrestore
from ipalib.install.kinit import kinit_password
import ipaplatform
from ipapython import ipautil, admintool, version
from ipapython.admintool import ScriptError
@ -1204,7 +1205,7 @@ def check_creds(options, realm_name):
options.admin_password = stdin
try:
ipautil.kinit_password(principal, stdin, ccache_name)
kinit_password(principal, stdin, ccache_name)
except RuntimeError as e:
root_logger.error("Kerberos authentication failed: %s" % e)
raise ScriptError("Invalid credentials: %s" % e)

View File

@ -18,6 +18,7 @@ from pkg_resources import parse_version
import six
from ipalib.install import sysrestore
from ipalib.install.kinit import kinit_keytab
from ipapython import ipaldap, ipautil
from ipapython.dn import DN
from ipapython.ipa_log_manager import root_logger
@ -816,9 +817,9 @@ def install_check(installer):
enroll_dl0_replica(installer, fstore, remote_api)
ccache = os.environ['KRB5CCNAME']
ipautil.kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env),
paths.KRB5_KEYTAB,
ccache)
kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env),
paths.KRB5_KEYTAB,
ccache)
except errors.ACIError:
raise ScriptError("\nThe password provided is incorrect for LDAP server "
@ -1042,9 +1043,9 @@ def promote_check(installer):
installutils.verify_fqdn(config.master_host_name, options.no_host_dns)
ccache = os.environ['KRB5CCNAME']
ipautil.kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env),
paths.KRB5_KEYTAB,
ccache)
kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env),
paths.KRB5_KEYTAB,
ccache)
cafile = paths.IPA_CA_CRT
if not ipautil.file_exists(cafile):

View File

@ -43,6 +43,7 @@ from six.moves.xmlrpc_client import Fault
from ipalib import plugable, errors
from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES
from ipalib.frontend import Local
from ipalib.install.kinit import kinit_keytab, kinit_password
from ipalib.backend import Executioner
from ipalib.errors import (PublicError, InternalError, JSONError,
CCacheError, RefererError, InvalidSessionPassword, NotFound, ACIError,
@ -1006,7 +1007,7 @@ class login_password(Backend, KerberosSession, HTTP_Status):
armor_principal, keytab, armor_path)
try:
ipautil.kinit_keytab(armor_principal, paths.IPA_KEYTAB, armor_path)
kinit_keytab(armor_principal, paths.IPA_KEYTAB, armor_path)
except gssapi.exceptions.GSSError as e:
raise CCacheError(message=unicode(e))
@ -1014,8 +1015,8 @@ class login_password(Backend, KerberosSession, HTTP_Status):
principal = krb5_format_principal_name(user, realm)
try:
ipautil.kinit_password(principal, password, ccache_name,
armor_ccache_name=armor_path)
kinit_password(principal, password, ccache_name,
armor_ccache_name=armor_path)
self.debug('Cleanup the armor ccache')
ipautil.run(

View File

@ -39,12 +39,11 @@ import ldap.modlist
import ipalib
from ipalib import api
from ipalib.install.kinit import kinit_keytab, kinit_password
from ipalib.plugable import Plugin
from ipalib.request import context
from ipapython.dn import DN
from ipapython.ipautil import (
private_ccache, kinit_password, kinit_keytab, run
)
from ipapython.ipautil import private_ccache, run
from ipaplatform.paths import paths
if six.PY3: