From b9985978159fdf6691857e81a82e05de13080f92 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Tue, 17 May 2022 22:44:50 -0300 Subject: [PATCH 1/3] ansible_module_utils: add method to retrive SID from dom_name. When managing idranges, it might be needed to obtain the domain SID from the domain name. As this method needs to use the IPA API object and requires imorting some ipaserver modules, teh best place for this method to be implemented is on ansible_module_utils. --- .../module_utils/ansible_freeipa_module.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py index 88d12116..dc5c5868 100644 --- a/plugins/module_utils/ansible_freeipa_module.py +++ b/plugins/module_utils/ansible_freeipa_module.py @@ -139,6 +139,13 @@ else: return fstore.has_files() + # Try to import dcerpc + try: + import ipaserver.dcerpc # pylint: disable=no-member + _dcerpc_bindings_installed = True # pylint: disable=invalid-name + except ImportError: + _dcerpc_bindings_installed = False # pylint: disable=invalid-name + if six.PY3: unicode = str @@ -221,6 +228,8 @@ else: ldap_cache: Control use of LDAP cache layer. (bool) """ + global _dcerpc_bindings_installed # pylint: disable=C0103,W0603 + env = Env() env._bootstrap() env._finalize_core(**dict(DEFAULT_CONFIG)) @@ -252,6 +261,7 @@ else: backend = api.Backend.ldap2 else: backend = api.Backend.rpcclient + _dcerpc_bindings_installed = False if not backend.isconnected(): backend.connect(ccache=os.environ.get('KRB5CCNAME', None)) @@ -701,6 +711,40 @@ else: print(jsonify(kwargs)) sys.exit(0) + def __get_domain_validator(): + if not _dcerpc_bindings_installed: + raise ipalib_errors.NotFound( + reason=( + 'Cannot perform SID validation without Samba 4 support ' + 'installed. Make sure you have installed server-trust-ad ' + 'sub-package of IPA on the server' + ) + ) + + domain_validator = ipaserver.dcerpc.DomainValidator(api) + + if not domain_validator.is_configured(): + raise ipalib_errors.NotFound( + reason=( + 'Cross-realm trusts are not configured. Make sure you ' + 'have run ipa-adtrust-install on the IPA server first' + ) + ) + + return domain_validator + + def get_trusted_domain_sid_from_name(dom_name): + """ + Given a trust domain name, returns the domain SID. + + Returns unicode string representation for a given trusted domain name + or None if SID for the given trusted domain name could not be found. + """ + domain_validator = __get_domain_validator() + sid = domain_validator.get_sid_from_domain_name(dom_name) + + return unicode(sid) if sid is not None else None + class IPAParamMapping(Mapping): """ Provides IPA API mapping to playbook parameters or computed values. From d990832681c5a31154e8ce911401abf2ec3f5c1e Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Tue, 17 May 2022 22:30:02 -0300 Subject: [PATCH 2/3] idrange: Fix addition of idrange with dom_name. When ensuring presence of an idrange using dom_name instead of dom_sid, the SID must be obtained so that the idrange can be created. Related to RHBZ#2086993 and RHBZ#2086994. --- README-idrange.md | 2 +- plugins/modules/ipaidrange.py | 13 +++-- tests/idrange/test_idrange.yml | 89 ++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/README-idrange.md b/README-idrange.md index 8855f0ef..0f584ab7 100644 --- a/README-idrange.md +++ b/README-idrange.md @@ -175,8 +175,8 @@ Variable | Description | Required `rid_base` \| `ipabaserid` | First RID of the corresponding RID range. (int) | no `secondary_rid_base` \| `ipasecondarybaserid` | First RID of the secondary RID range. (int) | no `dom_sid` \| `ipanttrusteddomainsid` | Domain SID of the trusted domain. | no -`dom_name` \| `ipanttrusteddomainname` | Name of the trusted domain. | no `idrange_type` \| `iparangetype` | ID range type, one of `ipa-ad-trust`, `ipa-ad-trust-posix`, `ipa-local`. Only valid if idrange does not exist. | no +`dom_name` \| `ipanttrusteddomainname` | Name of the trusted domain. Can only be used when `ipaapi_context: server`. | no `auto_private_groups` \| `ipaautoprivategroups` | Auto creation of private groups, one of `true`, `false`, `hybrid`. | no `delete_continue` \| `continue` | Continuous mode: don't stop on errors. Valid only if `state` is `absent`. Default: `no` (bool) | no `state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no diff --git a/plugins/modules/ipaidrange.py b/plugins/modules/ipaidrange.py index 78553f94..b9e5dd98 100644 --- a/plugins/modules/ipaidrange.py +++ b/plugins/modules/ipaidrange.py @@ -74,7 +74,9 @@ options: required: false aliases: ["ipanttrusteddomainsid"] dom_name: - description: Domain name of the trusted domain. + description: | + Domain name of the trusted domain. Can only be used when + `ipaapi_context: server`. type: string required: false aliases: ["ipanttrusteddomainname"] @@ -134,7 +136,7 @@ RETURN = """ from ansible.module_utils.ansible_freeipa_module import \ - IPAAnsibleModule, compare_args_ipa + IPAAnsibleModule, compare_args_ipa, get_trusted_domain_sid_from_name from ansible.module_utils import six if six.PY3: @@ -154,7 +156,7 @@ def find_idrange(module, name): def gen_args( base_id, range_size, rid_base, secondary_rid_base, idrange_type, dom_sid, - auto_private_groups + dom_name, auto_private_groups ): _args = {} # Integer parameters are stored as strings. @@ -169,6 +171,8 @@ def gen_args( _args["ipasecondarybaserid"] = secondary_rid_base if idrange_type is not None: _args["iparangetype"] = idrange_type + if dom_name is not None: + dom_sid = get_trusted_domain_sid_from_name(dom_name) if dom_sid is not None: _args["ipanttrusteddomainsid"] = dom_sid if auto_private_groups is not None: @@ -230,6 +234,7 @@ def main(): secondary_rid_base = ansible_module.params_get("secondary_rid_base") idrange_type = ansible_module.params_get("idrange_type") dom_sid = ansible_module.params_get("dom_sid") + dom_name = ansible_module.params_get("dom_name") auto_private_groups = \ ansible_module.params_get_lowercase("auto_private_groups") @@ -278,7 +283,7 @@ def main(): # Generate args args = gen_args( base_id, range_size, rid_base, secondary_rid_base, - idrange_type, dom_sid, auto_private_groups + idrange_type, dom_sid, dom_name, auto_private_groups ) # Found the idrange diff --git a/tests/idrange/test_idrange.yml b/tests/idrange/test_idrange.yml index 0d12af90..9acc3beb 100644 --- a/tests/idrange/test_idrange.yml +++ b/tests/idrange/test_idrange.yml @@ -227,6 +227,50 @@ name: ad_id_range state: absent + # Create trust with range_type: ipa-ad-trust-posix + - name: Create trust with range_type 'ipa-ad-trust' + include_tasks: tasks_set_trust.yml + vars: + trust_base_id: 10000000 + trust_range_size: 200000 + trust_range_type: ipa-ad-trust + + - name: Ensure AD-trust idrange is present, with dom_name + ipaidrange: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: ad_id_range + base_id: 150000000 + range_size: 200000 + rid_base: 1000000 + idrange_type: ipa-ad-trust + dom_name: "{{ adserver.domain }}" + auto_private_groups: "false" + register: result + failed_when: not result.changed or result.failed + + # Remove trust and idrange + - name: Remove test trust. + include_tasks: tasks_remove_trust.yml + + - name: Ensure AD-trust idrange is absent + ipaidrange: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: ad_id_range + state: absent + + # Remove trust and idrange + - name: Remove test trust. + include_tasks: tasks_remove_trust.yml + + - name: Ensure AD-trust idrange is absent + ipaidrange: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: ad_id_range + state: absent + # Create trust with range_type: ipa-ad-trust-posix - name: Create trust with range_type 'ipa-ad-trust-posix' include_tasks: tasks_set_trust.yml @@ -260,6 +304,51 @@ register: result failed_when: result.changed or result.failed + - name: Check if AD-trust-posix idrange is present, using dom_name + ipaidrange: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: ad_posix_id_range + base_id: 150000000 + range_size: 200000 + idrange_type: ipa-ad-trust-posix + dom_name: "{{ adserver.domain }}" + check_mode: yes + register: result + failed_when: result.changed or result.failed + + # Remove trust and idrange + - name: Remove test trust. + include_tasks: tasks_remove_trust.yml + + - name: Ensure AD-trust idrange is absent + ipaidrange: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: ad_posix_id_range + state: absent + + # Create trust with range_type: ipa-ad-trust-posix + - name: Create trust with range_type 'ipa-ad-trust-posix' + include_tasks: tasks_set_trust.yml + vars: + trust_base_id: 10000000 + trust_range_size: 2000000 + trust_range_type: ipa-ad-trust-posix + + # Can't use secondary_rid_base or rid_base with "ad-trust-posix" + - name: Ensure AD-trust-posix idrange is present, with dom_name + ipaidrange: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: ad_posix_id_range + base_id: 150000000 + range_size: 200000 + idrange_type: ipa-ad-trust-posix + dom_name: "{{ adserver.domain }}" + register: result + failed_when: not result.changed or result.failed + always: # CLEANUP TEST ITEMS - name: Remove test trust. From d45e6ac39934541c02ab54d85c4bd86128c85c36 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Tue, 17 May 2022 22:58:20 -0300 Subject: [PATCH 3/3] pylint: Ignore module ipaserver.dcerpc errors. When evaluating imports, pylint does not have access to IPA imports, so they need to be ignored during import or usage. --- plugins/module_utils/ansible_freeipa_module.py | 2 ++ setup.cfg | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py index dc5c5868..82f48e85 100644 --- a/plugins/module_utils/ansible_freeipa_module.py +++ b/plugins/module_utils/ansible_freeipa_module.py @@ -721,7 +721,9 @@ else: ) ) + # pylint: disable=no-member domain_validator = ipaserver.dcerpc.DomainValidator(api) + # pylint: enable=no-member if not domain_validator.is_configured(): raise ipalib_errors.NotFound( diff --git a/setup.cfg b/setup.cfg index 6c4f672c..10edc502 100644 --- a/setup.cfg +++ b/setup.cfg @@ -71,7 +71,8 @@ ignored-modules = ipaplatform, ipaplatform.paths, ipaplatform.tasks, ipapython.admintool, ipaserver.install.installutils, ipaserver.install.server.install, ipaserver.install, - ipaclient.install.ipachangeconf, ipaclient.install.client + ipaclient.install.ipachangeconf, ipaclient.install.client, + ipaserver.dcerpc [pylint.REFACTORING] max-nested-blocks = 9