diff options
author | Martin Babinsky <mbabinsk@redhat.com> | 2015-03-16 16:28:54 +0100 |
---|---|---|
committer | Jan Cholasta <jcholast@redhat.com> | 2015-04-20 08:27:35 +0000 |
commit | 415a5ff372fccee38a799cae37fb170145222107 (patch) | |
tree | 661ee7494d1c766ef641b2bb60fd1ef86484eae7 /ipapython | |
parent | e4930b3235e5d61d227a7e43d30a8feb7f35664d (diff) | |
download | freeipa-415a5ff372fccee38a799cae37fb170145222107.tar.gz freeipa-415a5ff372fccee38a799cae37fb170145222107.tar.xz freeipa-415a5ff372fccee38a799cae37fb170145222107.zip |
ipautil: new functions kinit_keytab and kinit_password
kinit_keytab replaces kinit_hostprincipal and performs Kerberos auth using
keytab file. Function is also able to repeat authentication multiple times
before giving up and raising Krb5Error.
kinit_password wraps kinit auth using password and also supports FAST
authentication using httpd armor ccache.
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Reviewed-By: Simo Sorce <ssorce@redhat.com>
Reviewed-By: Petr Spacek <pspacek@redhat.com>
Diffstat (limited to 'ipapython')
-rw-r--r-- | ipapython/ipautil.py | 71 |
1 files changed, 54 insertions, 17 deletions
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py index 6a06a8e95..bdbf8da49 100644 --- a/ipapython/ipautil.py +++ b/ipapython/ipautil.py @@ -1185,27 +1185,64 @@ def wait_for_open_socket(socket_name, timeout=0): else: raise e -def kinit_hostprincipal(keytab, ccachedir, principal): + +def kinit_keytab(principal, keytab, ccache_name, 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. """ - Given a ccache directory and a principal kinit as that user. + errors_to_retry = {krbV.KRB5KDC_ERR_SVC_UNAVAILABLE, + krbV.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): + try: + krbcontext = krbV.default_context() + ktab = krbV.Keytab(name=keytab, context=krbcontext) + princ = krbV.Principal(name=principal, context=krbcontext) + ccache = krbV.CCache(name=ccache_name, context=krbcontext, + primary_principal=princ) + ccache.init(princ) + ccache.init_creds_keytab(keytab=ktab, principal=princ) + root_logger.debug("Attempt %d/%d: success" + % (attempt, attempts)) + return + except krbV.Krb5Error as e: + if e.args[0] not in errors_to_retry: + 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) - This blindly overwrites the current CCNAME so if you need to save - it do so before calling this function. - Thus far this is used to kinit as the local host. +def kinit_password(principal, password, ccache_name, armor_ccache_name=None): """ - try: - ccache_file = 'FILE:%s/ccache' % ccachedir - krbcontext = krbV.default_context() - ktab = krbV.Keytab(name=keytab, context=krbcontext) - princ = krbV.Principal(name=principal, context=krbcontext) - os.environ['KRB5CCNAME'] = ccache_file - ccache = krbV.CCache(name=ccache_file, context=krbcontext, primary_principal=princ) - ccache.init(princ) - ccache.init_creds_keytab(keytab=ktab, principal=princ) - return ccache_file - except krbV.Krb5Error, e: - raise StandardError('Error initializing principal %s in %s: %s' % (principal, keytab, str(e))) + 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]) + + # this workaround enables us to capture stderr and put it + # into the raised exception in case of unsuccessful authentication + (stdout, stderr, retcode) = run(args, stdin=password, env={'LC_ALL': 'C'}, + raiseonerr=False) + if retcode: + raise RuntimeError(stderr) + def dn_attribute_property(private_name): ''' |