diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
commit | 975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch) | |
tree | 89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/microsoft/ad/plugins/action | |
parent | Initial commit. (diff) | |
download | ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip |
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/microsoft/ad/plugins/action')
5 files changed, 252 insertions, 0 deletions
diff --git a/ansible_collections/microsoft/ad/plugins/action/__init__.py b/ansible_collections/microsoft/ad/plugins/action/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/microsoft/ad/plugins/action/__init__.py diff --git a/ansible_collections/microsoft/ad/plugins/action/debug_ldap_client.py b/ansible_collections/microsoft/ad/plugins/action/debug_ldap_client.py new file mode 100644 index 000000000..a33f21dda --- /dev/null +++ b/ansible_collections/microsoft/ad/plugins/action/debug_ldap_client.py @@ -0,0 +1,176 @@ +# Copyright (c) 2023 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +import importlib +import importlib.metadata +import typing as t +import traceback + + +from ansible.plugins.action import ActionBase +from ansible.utils.display import Display + +display = Display() + +try: + import dns.resolver + + HAS_DNSRESOLVER = True +except Exception: + HAS_DNSRESOLVER = False + + +try: + import krb5 + + HAS_KRB5 = True +except Exception: + HAS_KRB5 = False + + +class ActionModule(ActionBase): + def run( + self, + tmp: t.Optional[str] = None, + task_vars: t.Optional[t.Dict[str, t.Any]] = None, + ) -> t.Dict[str, t.Any]: + self._supports_check_mode = True + self._supports_async = True + + result = super().run(tmp=tmp, task_vars=task_vars) + del tmp + + kerb_info = self._get_kerberos_info() + + dns_info: t.Dict[str, t.Any] = {} + default_realm = kerb_info.get("default_realm", None) + if default_realm: + dns_info = self._get_server_lookup_info(default_realm) + + result.update( + { + "dns": dns_info, + "kerberos": kerb_info, + "packages": { + "dnspython": self._import_lib("dns.resolver", package_name="dnspython"), + "dpapi_ng": self._import_lib("dpapi_ng", package_name="dpapi-ng"), + "krb5": self._import_lib("krb5"), + "pyspnego": self._import_lib("spnego", package_name="pyspnego"), + "sansldap": self._import_lib("sansldap"), + }, + } + ) + + return result + + def _get_kerberos_info(self) -> t.Dict[str, t.Any]: + if not HAS_KRB5: + return {} + + res: t.Dict[str, t.Any] = { + "exception": None, + "default_realm": None, + "default_cc": {}, + } + + try: + ctx = krb5.init_context() + except Exception: + res["exception"] = traceback.format_exc() + + if not ctx: + return res + + try: + res["default_realm"] = krb5.get_default_realm(ctx).decode("utf-8") + except Exception: + res["exception"] = traceback.format_exc() + + res["default_cc"] = self._get_kerberos_cc_info(ctx) + + return res + + def _get_kerberos_cc_info( + self, + ctx: "krb5.Context", + ) -> t.Dict[str, t.Any]: + creds: t.List[t.Dict[str, t.Any]] = [] + res: t.Dict[str, t.Any] = { + "exception": None, + "name": None, + "principal": None, + "creds": creds, + } + + try: + default_cc = krb5.cc_default(ctx) + except Exception: + res["exception"] = traceback.format_exc() + + if not default_cc: + return res + + try: + res["name"] = str(default_cc) + res["principal"] = str(default_cc.principal) + for cred in default_cc: + # cred attrs added in krb5 0.5.0 + creds.append( + { + "client": str(getattr(cred, "client", "krb5 too old")), + "server": str(getattr(cred, "server", "krb5 too old")), + } + ) + except Exception: + res["exception"] = traceback.format_exc() + + return res + + def _get_server_lookup_info( + self, + default_realm: str, + ) -> t.Dict[str, t.Any]: + if not HAS_DNSRESOLVER: + return {} + + records: t.List[t.Dict[str, t.Any]] = [] + res: t.Dict[str, t.Any] = { + "exception": None, + "default_server": None, + "default_port": None, + "records": records, + } + + try: + srv_record = f"_ldap._tcp.dc._msdcs.{default_realm}" + + for rec in dns.resolver.resolve(srv_record, "SRV"): + records.append( + { + "target": str(rec.target), + "port": rec.port, + "weight": rec.weight, + "priority": rec.priority, + } + ) + + highest_record = next(iter(sorted(records, key=lambda k: (k["priority"], -k["weight"]))), None) + if highest_record: + res["default_server"] = highest_record["target"].rstrip(".") + res["default_port"] = highest_record["port"] + + except Exception: + res["exception"] = traceback.format_exc() + + return res + + def _import_lib( + self, + name: str, + package_name: t.Optional[str] = None, + ) -> str: + try: + importlib.import_module(name) + return importlib.metadata.version(package_name or name) + except Exception: + return traceback.format_exc() diff --git a/ansible_collections/microsoft/ad/plugins/action/domain.py b/ansible_collections/microsoft/ad/plugins/action/domain.py new file mode 100644 index 000000000..36cdb26e5 --- /dev/null +++ b/ansible_collections/microsoft/ad/plugins/action/domain.py @@ -0,0 +1,34 @@ +# Copyright (c) 2022 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +import typing as t + +from ..plugin_utils._module_with_reboot import ActionModuleWithReboot + + +class ActionModule(ActionModuleWithReboot): + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + super().__init__(*args, **kwargs) + self._ran_once = False + + def _ad_should_rerun(self, result: t.Dict[str, t.Any]) -> bool: + ran_once = self._ran_once + self._ran_once = True + + if ran_once or not result.get("_do_action_reboot", False): + return False + + if self._task.check_mode: + # Assume that on a rerun it will not have failed and that it + # ran successfull. + result["failed"] = False + result.pop("msg", None) + return False + + else: + return True + + def _ad_process_result(self, result: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]: + result.pop("_do_action_reboot", None) + + return result diff --git a/ansible_collections/microsoft/ad/plugins/action/domain_controller.py b/ansible_collections/microsoft/ad/plugins/action/domain_controller.py new file mode 100644 index 000000000..36cdb26e5 --- /dev/null +++ b/ansible_collections/microsoft/ad/plugins/action/domain_controller.py @@ -0,0 +1,34 @@ +# Copyright (c) 2022 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +import typing as t + +from ..plugin_utils._module_with_reboot import ActionModuleWithReboot + + +class ActionModule(ActionModuleWithReboot): + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + super().__init__(*args, **kwargs) + self._ran_once = False + + def _ad_should_rerun(self, result: t.Dict[str, t.Any]) -> bool: + ran_once = self._ran_once + self._ran_once = True + + if ran_once or not result.get("_do_action_reboot", False): + return False + + if self._task.check_mode: + # Assume that on a rerun it will not have failed and that it + # ran successfull. + result["failed"] = False + result.pop("msg", None) + return False + + else: + return True + + def _ad_process_result(self, result: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]: + result.pop("_do_action_reboot", None) + + return result diff --git a/ansible_collections/microsoft/ad/plugins/action/membership.py b/ansible_collections/microsoft/ad/plugins/action/membership.py new file mode 100644 index 000000000..5eea8d120 --- /dev/null +++ b/ansible_collections/microsoft/ad/plugins/action/membership.py @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from ..plugin_utils._module_with_reboot import ActionModuleWithReboot + + +class ActionModule(ActionModuleWithReboot): + ... |