summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2016-11-23 17:40:47 +0100
committerMartin Basti <mbasti@redhat.com>2016-11-29 14:50:51 +0100
commit7d5c680ace7ccea3b0f7f1471cf8dbc07b3da5a1 (patch)
tree9dbbb1c9cf63a236947ecee6d82ea16d4c256a3e /ipalib
parent75b70e3f0d52a9c98f443d3fc2f7cef92bdc7b1a (diff)
downloadfreeipa-7d5c680ace7ccea3b0f7f1471cf8dbc07b3da5a1.tar.gz
freeipa-7d5c680ace7ccea3b0f7f1471cf8dbc07b3da5a1.tar.xz
freeipa-7d5c680ace7ccea3b0f7f1471cf8dbc07b3da5a1.zip
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>
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/install/kinit.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py
new file mode 100644
index 000000000..2c59b5e13
--- /dev/null
+++ b/ipalib/install/kinit.py
@@ -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)