diff options
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.py | 138 |
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() |