Blame SOURCES/ansible-freeipa-1.8.3-ipaconfig-Add-support-for-SID-related-attributes_3c8d6c7_RHBZ#2132994.patch

9b9c8d
From 3c8d6c7c7aec408b3b68440982929e30e7d69130 Mon Sep 17 00:00:00 2001
9b9c8d
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
9b9c8d
Date: Mon, 5 Sep 2022 17:18:00 -0300
9b9c8d
Subject: [PATCH] ipaconfig: Add support for SID related attributes.
9b9c8d
9b9c8d
Since FreeIPA 4.9.8 the 'config_mod' command has parameters to enable
9b9c8d
and configure SIDs, and set the Netbios name.
9b9c8d
9b9c8d
This patch adds the following parameters to ipaconfig plugin:
9b9c8d
    enable_sids: New users and groups automatically get a SID assigned
9b9c8d
    add_sids: Add SIDs for existing users and groups
9b9c8d
    netbios_name: NetBIOS name of the IPA domain
9b9c8d
9b9c8d
Both add_sids and netbios_name requires 'enable_sid: yes'.
9b9c8d
9b9c8d
'enable_sid' and 'netbios_name' are returned when querying IPA
9b9c8d
configuration.
9b9c8d
9b9c8d
'add_sids' always generate SIDs for users and groups, so, muiltiple
9b9c8d
executions of the playbook with 'add_sids: yes' will return 'changed',
9b9c8d
even if users and groups SIDs are not modified.
9b9c8d
9b9c8d
A new test playbook is available:
9b9c8d
9b9c8d
    tests/config/test_config_sid.yml
9b9c8d
9b9c8d
New examples playbooks are available:
9b9c8d
9b9c8d
    playbooks/config/change-ipa-domain-netbios-name.yml
9b9c8d
    playbooks/config/generate-users-groups-sids.yml
9b9c8d
9b9c8d
Fixes: #781
9b9c8d
Related: https://bugzilla.redhat.com/show_bug.cgi?id=2069174
9b9c8d
Related: https://bugzilla.redhat.com/show_bug.cgi?id=2069184
9b9c8d
---
9b9c8d
 README-config.md                              |  42 ++++++
9b9c8d
 .../config/change-ipa-domain-netbios-name.yml |  12 ++
9b9c8d
 .../config/generate-users-groups-sids.yml     |  12 ++
9b9c8d
 plugins/modules/ipaconfig.py                  | 120 +++++++++++++++++-
9b9c8d
 tests/azure/templates/variables_centos-7.yaml |   9 +-
9b9c8d
 tests/config/test_config_sid.yml              |  70 ++++++++++
9b9c8d
 6 files changed, 256 insertions(+), 9 deletions(-)
9b9c8d
 create mode 100644 playbooks/config/change-ipa-domain-netbios-name.yml
9b9c8d
 create mode 100644 playbooks/config/generate-users-groups-sids.yml
9b9c8d
 create mode 100644 tests/config/test_config_sid.yml
9b9c8d
9b9c8d
diff --git a/README-config.md b/README-config.md
9b9c8d
index 17c85f1..13023ea 100644
9b9c8d
--- a/README-config.md
9b9c8d
+++ b/README-config.md
9b9c8d
@@ -65,6 +65,9 @@ Example playbook to read config options:
9b9c8d
         maxusername: 64
9b9c8d
 ```
9b9c8d
 
9b9c8d
+
9b9c8d
+Example playbook to set global configuration options:
9b9c8d
+
9b9c8d
 ```yaml
9b9c8d
 ---
9b9c8d
 - name: Playbook to ensure some config options are set
9b9c8d
@@ -79,6 +82,40 @@ Example playbook to read config options:
9b9c8d
 ```
9b9c8d
 
9b9c8d
 
9b9c8d
+Example playbook to enable SID and generate users and groups SIDs:
9b9c8d
+
9b9c8d
+```yaml
9b9c8d
+---
9b9c8d
+- name: Playbook to ensure SIDs are enabled and users and groups have SIDs
9b9c8d
+  hosts: ipaserver
9b9c8d
+  become: no
9b9c8d
+  gather_facts: no
9b9c8d
+
9b9c8d
+  tasks:
9b9c8d
+    - name: Enable SID and generate users and groups SIDS
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        enable_sid: yes
9b9c8d
+        add_sids: yes
9b9c8d
+```
9b9c8d
+
9b9c8d
+Example playbook to change IPA domain NetBIOS name:
9b9c8d
+
9b9c8d
+```yaml
9b9c8d
+---
9b9c8d
+- name: Playbook to change IPA domain netbios name
9b9c8d
+  hosts: ipaserver
9b9c8d
+  become: no
9b9c8d
+  gather_facts: no
9b9c8d
+
9b9c8d
+  tasks:
9b9c8d
+    - name: Set IPA domain netbios name
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        enable_sid: yes
9b9c8d
+        netbios_name: IPADOM
9b9c8d
+```
9b9c8d
+
9b9c8d
 Variables
9b9c8d
 =========
9b9c8d
 
9b9c8d
@@ -111,6 +148,9 @@ Variable | Description | Required
9b9c8d
 `user_auth_type` \| `ipauserauthtype` |  set default types of supported user authentication (choices: `password`, `radius`, `otp`, `disabled`). Use `""` to clear this variable. | no
9b9c8d
 `domain_resolution_order` \| `ipadomainresolutionorder` | Set list of domains used for short name qualification | no
9b9c8d
 `ca_renewal_master_server` \| `ipacarenewalmasterserver`| Renewal master for IPA certificate authority. | no
9b9c8d
+`enable_sid` | New users and groups automatically get a SID assigned. Requires IPA 4.9.8+. (bool) | no
9b9c8d
+`netbios_name` | NetBIOS name of the IPA domain. Requires IPA 4.9.8+ and 'enable_sid: yes'. | no
9b9c8d
+`add_sids` | Add SIDs for existing users and groups. Requires IPA 4.9.8+ and 'enable_sid: yes'. (bool) | no
9b9c8d
 
9b9c8d
 
9b9c8d
 Return Values
9b9c8d
@@ -140,6 +180,8 @@ Variable | Description | Returned When
9b9c8d
   | `user_auth_type` |  
9b9c8d
   | `domain_resolution_order` |  
9b9c8d
   | `ca_renewal_master_server` |  
9b9c8d
+  | `enable_sid` |  
9b9c8d
+  | `netbios_name` |  
9b9c8d
 
9b9c8d
 All returned fields take the same form as their namesake input parameters
9b9c8d
 
9b9c8d
diff --git a/playbooks/config/change-ipa-domain-netbios-name.yml b/playbooks/config/change-ipa-domain-netbios-name.yml
9b9c8d
new file mode 100644
9b9c8d
index 0000000..04e56b3
9b9c8d
--- /dev/null
9b9c8d
+++ b/playbooks/config/change-ipa-domain-netbios-name.yml
9b9c8d
@@ -0,0 +1,12 @@
9b9c8d
+---
9b9c8d
+- name: Playbook to change IPA domain netbios name
9b9c8d
+  hosts: ipaserver
9b9c8d
+  become: no
9b9c8d
+  gather_facts: no
9b9c8d
+
9b9c8d
+  tasks:
9b9c8d
+    - name: Set IPA domain netbios name
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        enable_sid: yes
9b9c8d
+        netbios_name: IPADOM
9b9c8d
diff --git a/playbooks/config/generate-users-groups-sids.yml b/playbooks/config/generate-users-groups-sids.yml
9b9c8d
new file mode 100644
9b9c8d
index 0000000..9df85ba
9b9c8d
--- /dev/null
9b9c8d
+++ b/playbooks/config/generate-users-groups-sids.yml
9b9c8d
@@ -0,0 +1,12 @@
9b9c8d
+---
9b9c8d
+- name: Playbook to ensure SIDs are enabled and users and groups have SIDs
9b9c8d
+  hosts: ipaserver
9b9c8d
+  become: no
9b9c8d
+  gather_facts: no
9b9c8d
+
9b9c8d
+  tasks:
9b9c8d
+    - name: Enable SID and generate users and groups SIDS
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        enable_sid: yes
9b9c8d
+        add_sids: yes
9b9c8d
diff --git a/plugins/modules/ipaconfig.py b/plugins/modules/ipaconfig.py
9b9c8d
index 6731e37..d1f1398 100644
9b9c8d
--- a/plugins/modules/ipaconfig.py
9b9c8d
+++ b/plugins/modules/ipaconfig.py
9b9c8d
@@ -148,6 +148,24 @@ options:
9b9c8d
         required: false
9b9c8d
         type: list
9b9c8d
         aliases: ["ipadomainresolutionorder"]
9b9c8d
+    enable_sid:
9b9c8d
+        description: >
9b9c8d
+          New users and groups automatically get a SID assigned.
9b9c8d
+          Requires IPA 4.9.8+.
9b9c8d
+        required: false
9b9c8d
+        type: bool
9b9c8d
+    netbios_name:
9b9c8d
+        description: >
9b9c8d
+          NetBIOS name of the IPA domain.
9b9c8d
+          Requires IPA 4.9.8+ and 'enable_sid: yes'.
9b9c8d
+        required: false
9b9c8d
+        type: string
9b9c8d
+    add_sids:
9b9c8d
+        description: >
9b9c8d
+          Add SIDs for existing users and groups.
9b9c8d
+          Requires IPA 4.9.8+ and 'enable_sid: yes'.
9b9c8d
+        required: false
9b9c8d
+        type: bool
9b9c8d
 '''
9b9c8d
 
9b9c8d
 EXAMPLES = '''
9b9c8d
@@ -169,6 +187,24 @@ EXAMPLES = '''
9b9c8d
         ipaadmin_password: SomeADMINpassword
9b9c8d
         defaultshell: /bin/bash
9b9c8d
         maxusername: 64
9b9c8d
+
9b9c8d
+- name: Playbook to enable SID and generate users and groups SIDs
9b9c8d
+  hosts: ipaserver
9b9c8d
+  tasks:
9b9c8d
+    - name: Enable SID and generate users and groups SIDS
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        enable_sid: yes
9b9c8d
+        add_sids: yes
9b9c8d
+
9b9c8d
+- name: Playbook to change IPA domain netbios name
9b9c8d
+  hosts: ipaserver
9b9c8d
+  tasks:
9b9c8d
+    - name: Enable SID and generate users and groups SIDS
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        enable_sid: yes
9b9c8d
+        netbios_name: IPADOM
9b9c8d
 '''
9b9c8d
 
9b9c8d
 RETURN = '''
9b9c8d
@@ -247,6 +283,14 @@ config:
9b9c8d
     domain_resolution_order:
9b9c8d
         description: list of domains used for short name qualification
9b9c8d
         returned: always
9b9c8d
+    enable_sid:
9b9c8d
+        description: >
9b9c8d
+          new users and groups automatically get a SID assigned.
9b9c8d
+          Requires IPA 4.9.8+.
9b9c8d
+        returned: always
9b9c8d
+    netbios_name:
9b9c8d
+        description: NetBIOS name of the IPA domain. Requires IPA 4.9.8+.
9b9c8d
+        returned: if enable_sid is True
9b9c8d
 '''
9b9c8d
 
9b9c8d
 
9b9c8d
@@ -260,6 +304,28 @@ def config_show(module):
9b9c8d
     return _result["result"]
9b9c8d
 
9b9c8d
 
9b9c8d
+def get_netbios_name(module):
9b9c8d
+    try:
9b9c8d
+        _result = module.ipa_command_no_name("trustconfig_show", {"all": True})
9b9c8d
+    except Exception:  # pylint: disable=broad-except
9b9c8d
+        return None
9b9c8d
+    else:
9b9c8d
+        return _result["result"]["ipantflatname"][0]
9b9c8d
+
9b9c8d
+
9b9c8d
+def is_enable_sid(module):
9b9c8d
+    """When 'enable-sid' is true admin user and admins group have SID set."""
9b9c8d
+    _result = module.ipa_command("user_show", "admin", {"all": True})
9b9c8d
+    sid = _result["result"].get("ipantsecurityidentifier", [""])
9b9c8d
+    if not sid[0].endswith("-500"):
9b9c8d
+        return False
9b9c8d
+    _result = module.ipa_command("group_show", "admins", {"all": True})
9b9c8d
+    sid = _result["result"].get("ipantsecurityidentifier", [""])
9b9c8d
+    if not sid[0].endswith("-512"):
9b9c8d
+        return False
9b9c8d
+    return True
9b9c8d
+
9b9c8d
+
9b9c8d
 def main():
9b9c8d
     ansible_module = IPAAnsibleModule(
9b9c8d
         argument_spec=dict(
9b9c8d
@@ -313,7 +379,10 @@ def main():
9b9c8d
                                 aliases=["ipauserauthtype"]),
9b9c8d
             ca_renewal_master_server=dict(type="str", required=False),
9b9c8d
             domain_resolution_order=dict(type="list", required=False,
9b9c8d
-                                         aliases=["ipadomainresolutionorder"])
9b9c8d
+                                         aliases=["ipadomainresolutionorder"]),
9b9c8d
+            enable_sid=dict(type="bool", required=False),
9b9c8d
+            add_sids=dict(type="bool", required=False),
9b9c8d
+            netbios_name=dict(type="str", required=False),
9b9c8d
         ),
9b9c8d
         supports_check_mode=True,
9b9c8d
     )
9b9c8d
@@ -344,7 +413,10 @@ def main():
9b9c8d
         "pac_type": "ipakrbauthzdata",
9b9c8d
         "user_auth_type": "ipauserauthtype",
9b9c8d
         "ca_renewal_master_server": "ca_renewal_master_server",
9b9c8d
-        "domain_resolution_order": "ipadomainresolutionorder"
9b9c8d
+        "domain_resolution_order": "ipadomainresolutionorder",
9b9c8d
+        "enable_sid": "enable_sid",
9b9c8d
+        "netbios_name": "netbios_name",
9b9c8d
+        "add_sids": "add_sids",
9b9c8d
     }
9b9c8d
     allow_empty_string = ["pac_type", "user_auth_type", "configstring"]
9b9c8d
     reverse_field_map = {v: k for k, v in field_map.items()}
9b9c8d
@@ -394,11 +466,47 @@ def main():
9b9c8d
     changed = False
9b9c8d
     exit_args = {}
9b9c8d
 
9b9c8d
-    # Connect to IPA API
9b9c8d
-    with ansible_module.ipa_connect():
9b9c8d
+    # Connect to IPA API (enable-sid requires context == 'client')
9b9c8d
+    with ansible_module.ipa_connect(context="client"):
9b9c8d
+        has_enable_sid = ansible_module.ipa_command_param_exists(
9b9c8d
+            "config_mod", "enable_sid")
9b9c8d
 
9b9c8d
         result = config_show(ansible_module)
9b9c8d
+
9b9c8d
         if params:
9b9c8d
+            netbios_name = params.get("netbios_name")
9b9c8d
+            if netbios_name:
9b9c8d
+                netbios_name = netbios_name.upper()
9b9c8d
+            add_sids = params.get("add_sids")
9b9c8d
+            enable_sid = params.get("enable_sid")
9b9c8d
+            required_sid = any([netbios_name, add_sids])
9b9c8d
+            if required_sid and not enable_sid:
9b9c8d
+                ansible_module.fail_json(
9b9c8d
+                    "'enable-sid: yes' required for 'netbios_name' "
9b9c8d
+                    "and 'add-sids'."
9b9c8d
+                )
9b9c8d
+            if enable_sid:
9b9c8d
+                if not has_enable_sid:
9b9c8d
+                    ansible_module.fail_json(
9b9c8d
+                        "This version of IPA does not support 'enable-sid'.")
9b9c8d
+                if (
9b9c8d
+                    netbios_name
9b9c8d
+                    and netbios_name == get_netbios_name(ansible_module)
9b9c8d
+                ):
9b9c8d
+                    del params["netbios_name"]
9b9c8d
+                    netbios_name = None
9b9c8d
+                if not add_sids and "add_sids" in params:
9b9c8d
+                    del params["add_sids"]
9b9c8d
+                if (
9b9c8d
+                    not any([netbios_name, add_sids])
9b9c8d
+                    and is_enable_sid(ansible_module)
9b9c8d
+                ):
9b9c8d
+                    del params["enable_sid"]
9b9c8d
+            else:
9b9c8d
+                for param in ["enable_sid", "netbios_name", "add_sids"]:
9b9c8d
+                    if param in params:
9b9c8d
+                        del params[params]
9b9c8d
+
9b9c8d
             params = {
9b9c8d
                 k: v for k, v in params.items()
9b9c8d
                 if k not in result or result[k] != v
9b9c8d
@@ -458,6 +566,10 @@ def main():
9b9c8d
             # Add empty domain_resolution_order if it is not set
9b9c8d
             if "domain_resolution_order" not in exit_args:
9b9c8d
                 exit_args["domain_resolution_order"] = []
9b9c8d
+            # Set enable_sid
9b9c8d
+            if has_enable_sid:
9b9c8d
+                exit_args["enable_sid"] = is_enable_sid(ansible_module)
9b9c8d
+                exit_args["netbios_name"] = get_netbios_name(ansible_module)
9b9c8d
 
9b9c8d
     # Done
9b9c8d
     ansible_module.exit_json(changed=changed, config=exit_args)
9b9c8d
#diff --git a/tests/azure/templates/variables_centos-7.yaml b/tests/azure/templates/variables_centos-7.yaml
9b9c8d
#index 586d5ec..8628af2 100644
9b9c8d
#--- a/tests/azure/templates/variables_centos-7.yaml
9b9c8d
#+++ b/tests/azure/templates/variables_centos-7.yaml
9b9c8d
#@@ -12,8 +12,7 @@
9b9c8d
# #
9b9c8d
# ---
9b9c8d
# variables:
9b9c8d
#-  empty: true
9b9c8d
#-#   ipa_enabled_modules: >-
9b9c8d
#-#   ipa_enabled_tests: >-
9b9c8d
#-#   ipa_disabled_modules: >-
9b9c8d
#-#   ipa_disabled_tests: >-
9b9c8d
#+  # ipa_enabled_modules: >-
9b9c8d
#+  # ipa_enabled_tests: >-
9b9c8d
#+  # ipa_disabled_modules: >-
9b9c8d
#+  ipa_disabled_tests: test_config_sid
9b9c8d
diff --git a/tests/config/test_config_sid.yml b/tests/config/test_config_sid.yml
9b9c8d
new file mode 100644
9b9c8d
index 0000000..1761795
9b9c8d
--- /dev/null
9b9c8d
+++ b/tests/config/test_config_sid.yml
9b9c8d
@@ -0,0 +1,70 @@
9b9c8d
+---
9b9c8d
+- name: Test config
9b9c8d
+  hosts: "{{ ipa_test_host | default('ipaserver') }}"
9b9c8d
+  become: no
9b9c8d
+  gather_facts: no
9b9c8d
+
9b9c8d
+  tasks:
9b9c8d
+
9b9c8d
+  # GET CURRENT CONFIG
9b9c8d
+
9b9c8d
+  - name: Return current values of the global configuration options
9b9c8d
+    ipaconfig:
9b9c8d
+      ipaadmin_password: SomeADMINpassword
9b9c8d
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
9b9c8d
+    register: previous
9b9c8d
+
9b9c8d
+  # TESTS
9b9c8d
+  - block:
9b9c8d
+    - name: Ensure SID is enabled.
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        ipaapi_context: "{{ ipa_context | default(omit) }}"
9b9c8d
+        enable_sid: yes
9b9c8d
+      register: result
9b9c8d
+      failed_when: result.failed or previous.config.enable_sid == result.changed
9b9c8d
+
9b9c8d
+    - name: Ensure SID is enabled, again.
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        ipaapi_context: "{{ ipa_context | default(omit) }}"
9b9c8d
+        enable_sid: yes
9b9c8d
+      register: result
9b9c8d
+      failed_when: result.failed or result.changed
9b9c8d
+
9b9c8d
+    - name: Ensure netbios_name is "IPATESTPLAY"
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        ipaapi_context: "{{ ipa_context | default(omit) }}"
9b9c8d
+        enable_sid: yes
9b9c8d
+        netbios_name: IPATESTPLAY
9b9c8d
+      register: result
9b9c8d
+      failed_when: result.failed or not result.changed
9b9c8d
+
9b9c8d
+    - name: Ensure netbios_name is "IPATESTPLAY", again
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        ipaapi_context: "{{ ipa_context | default(omit) }}"
9b9c8d
+        enable_sid: yes
9b9c8d
+        netbios_name: IPATESTPLAY
9b9c8d
+      register: result
9b9c8d
+      failed_when: result.failed or result.changed
9b9c8d
+
9b9c8d
+    # add_sids is not idempotent as it always tries to generate the missing
9b9c8d
+    # SIDs for users and groups.
9b9c8d
+    - name: Add SIDs to users and groups.
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        ipaapi_context: "{{ ipa_context | default(omit) }}"
9b9c8d
+        enable_sid: yes
9b9c8d
+        add_sids: yes
9b9c8d
+
9b9c8d
+    # REVERT TO PREVIOUS CONFIG
9b9c8d
+    always:
9b9c8d
+    # Once SID is enabled, it cannot be reverted.
9b9c8d
+    - name: Revert netbios_name to original configuration
9b9c8d
+      ipaconfig:
9b9c8d
+        ipaadmin_password: SomeADMINpassword
9b9c8d
+        ipaapi_context: "{{ ipa_context | default(omit) }}"
9b9c8d
+        netbios_name: "{{ previous.config.netbios_name | default(omit) }}"
9b9c8d
+        enable_sid: yes
9b9c8d
-- 
9b9c8d
2.37.3
9b9c8d