summaryrefslogtreecommitdiffstats
path: root/test/integration/targets/prepare_http_tests/library/httptester_kinit.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/integration/targets/prepare_http_tests/library/httptester_kinit.py')
-rw-r--r--test/integration/targets/prepare_http_tests/library/httptester_kinit.py138
1 files changed, 138 insertions, 0 deletions
diff --git a/test/integration/targets/prepare_http_tests/library/httptester_kinit.py b/test/integration/targets/prepare_http_tests/library/httptester_kinit.py
new file mode 100644
index 0000000..4f7b7ad
--- /dev/null
+++ b/test/integration/targets/prepare_http_tests/library/httptester_kinit.py
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+
+# Copyright: (c) 2020, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+---
+module: httptester_kinit
+short_description: Get Kerberos ticket
+description: Get Kerberos ticket using kinit non-interactively.
+options:
+ username:
+ description: The username to get the ticket for.
+ required: true
+ type: str
+ password:
+ description: The password for I(username).
+ required; true
+ type: str
+author:
+- Ansible Project
+'''
+
+EXAMPLES = r'''
+#
+'''
+
+RETURN = r'''
+#
+'''
+
+import contextlib
+import errno
+import os
+import subprocess
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.common.text.converters import to_bytes, to_text
+
+try:
+ import configparser
+except ImportError:
+ import ConfigParser as configparser
+
+
+@contextlib.contextmanager
+def env_path(name, value, default_value):
+ """ Adds a value to a PATH-like env var and preserve the existing value if present. """
+ orig_value = os.environ.get(name, None)
+ os.environ[name] = '%s:%s' % (value, orig_value or default_value)
+ try:
+ yield
+
+ finally:
+ if orig_value:
+ os.environ[name] = orig_value
+
+ else:
+ del os.environ[name]
+
+
+@contextlib.contextmanager
+def krb5_conf(module, config):
+ """ Runs with a custom krb5.conf file that extends the existing config if present. """
+ if config:
+ ini_config = configparser.ConfigParser()
+ for section, entries in config.items():
+ ini_config.add_section(section)
+ for key, value in entries.items():
+ ini_config.set(section, key, value)
+
+ config_path = os.path.join(module.tmpdir, 'krb5.conf')
+ with open(config_path, mode='wt') as config_fd:
+ ini_config.write(config_fd)
+
+ with env_path('KRB5_CONFIG', config_path, '/etc/krb5.conf'):
+ yield
+
+ else:
+ yield
+
+
+def main():
+ module_args = dict(
+ username=dict(type='str', required=True),
+ password=dict(type='str', required=True, no_log=True),
+ )
+ module = AnsibleModule(
+ argument_spec=module_args,
+ required_together=[('username', 'password')],
+ )
+
+ # Heimdal has a few quirks that we want to paper over in this module
+ # 1. KRB5_TRACE does not work in any released version (<=7.7), we need to use a custom krb5.config to enable it
+ # 2. When reading the password it reads from the pty not stdin by default causing an issue with subprocess. We
+ # can control that behaviour with '--password-file=STDIN'
+ # Also need to set the custom path to krb5-config and kinit as FreeBSD relies on the newer Heimdal version in the
+ # port package.
+ sysname = os.uname()[0]
+ prefix = '/usr/local/bin/' if sysname == 'FreeBSD' else ''
+ is_heimdal = sysname in ['Darwin', 'FreeBSD']
+
+ # Debugging purposes, get the Kerberos version. On platforms like OpenSUSE this may not be on the PATH.
+ try:
+ process = subprocess.Popen(['%skrb5-config' % prefix, '--version'], stdout=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ version = to_text(stdout)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ version = 'Unknown (no krb5-config)'
+
+ kinit_args = ['%skinit' % prefix]
+ config = {}
+ if is_heimdal:
+ kinit_args.append('--password-file=STDIN')
+ config['logging'] = {'krb5': 'FILE:/dev/stdout'}
+ kinit_args.append(to_text(module.params['username'], errors='surrogate_or_strict'))
+
+ with krb5_conf(module, config):
+ # Weirdly setting KRB5_CONFIG in the modules environment block does not work unless we pass it in explicitly.
+ # Take a copy of the existing environment to make sure the process has the same env vars as ours. Also set
+ # KRB5_TRACE to output and debug logs helping to identify problems when calling kinit with MIT.
+ kinit_env = os.environ.copy()
+ kinit_env['KRB5_TRACE'] = '/dev/stdout'
+
+ process = subprocess.Popen(kinit_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ env=kinit_env)
+ stdout, stderr = process.communicate(to_bytes(module.params['password'], errors='surrogate_or_strict') + b'\n')
+ rc = process.returncode
+
+ module.exit_json(changed=True, stdout=to_text(stdout), stderr=to_text(stderr), rc=rc, version=version)
+
+
+if __name__ == '__main__':
+ main()