Repository: ansible-collections/community.general

Issue:
Feature Request: ipa_config: ipadefaulthomedirpath:

##### SUMMARY

ipa_config module should allow setting the default home directory path


##### ISSUE TYPE
- Feature Idea

##### COMPONENT NAME
ipa_config

##### ADDITIONAL INFORMATION
In a production environment home directories may be somewhere besides /home

<!--- Paste example playbooks or commands between quotes below -->
```yaml

    - name: Set default shell and home dir path
      ipa_config:
        ipa_host: "{{ ipa_server }}.{{ ipa_domain }}"
        ipa_user: "{{ ipa_usr }}"
        ipa_pass: "{{ ipa_passwd }}"
        ipadefaultemaildomain: xxx.lan
        ipadefaultloginshell: /bin/bash
        ipadefaulthomedirpath: /storage/home

```

<!--- HINT: You can also paste gist.github.com links for larger files -->



Discussion:
Files identified in the description:
* [`plugins/modules/identity/ipa/ipa_config.py`](https://github.com/ansible-collections/community.general/blob/master/plugins/modules/identity/ipa/ipa_config.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @Akasurde @Nosmoht @fxfitz
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Just to add to this, it would be nice to also have all the password policy configurations available as well.

Resolving patch:
diff --git a/plugins/modules/identity/ipa/ipa_config.py b/plugins/modules/identity/ipa/ipa_config.py
--- a/plugins/modules/identity/ipa/ipa_config.py
+++ b/plugins/modules/identity/ipa/ipa_config.py
@@ -14,6 +14,13 @@
 description:
 - Modify global configuration settings of a FreeIPA Server.
 options:
+  ipaconfigstring:
+    description: Extra hashes to generate in password plug-in.
+    aliases: ["configstring"]
+    type: list
+    elements: str
+    choices: ["AllowNThash", "KDC:Disable Last Success", "KDC:Disable Lockout", "KDC:Disable Default Preauth for SPNs"]
+    version_added: '2.5.0'
   ipadefaultloginshell:
     description: Default shell for new users.
     aliases: ["loginshell"]
@@ -22,25 +29,158 @@
     description: Default e-mail domain for new users.
     aliases: ["emaildomain"]
     type: str
+  ipadefaultprimarygroup:
+    description: Default group for new users.
+    aliases: ["primarygroup"]
+    type: str
+    version_added: '2.5.0'
+  ipagroupsearchfields:
+    description: A list of fields to search in when searching for groups.
+    aliases: ["groupsearchfields"]
+    type: list
+    elements: str
+    version_added: '2.5.0'
+  ipahomesrootdir:
+    description: Default location of home directories.
+    aliases: ["homesrootdir"]
+    type: str
+    version_added: '2.5.0'
+  ipakrbauthzdata:
+    description: Default types of PAC supported for services.
+    aliases: ["krbauthzdata"]
+    type: list
+    elements: str
+    choices: ["MS-PAC", "PAD", "nfs:NONE"]
+    version_added: '2.5.0'
+  ipamaxusernamelength:
+    description: Maximum length of usernames.
+    aliases: ["maxusernamelength"]
+    type: int
+    version_added: '2.5.0'
+  ipapwdexpadvnotify:
+    description: Notice of impending password expiration, in days.
+    aliases: ["pwdexpadvnotify"]
+    type: int
+    version_added: '2.5.0'
+  ipasearchrecordslimit:
+    description: Maximum number of records to search (-1 or 0 is unlimited).
+    aliases: ["searchrecordslimit"]
+    type: int
+    version_added: '2.5.0'
+  ipasearchtimelimit:
+    description: Maximum amount of time (seconds) for a search (-1 or 0 is unlimited).
+    aliases: ["searchtimelimit"]
+    type: int
+    version_added: '2.5.0'
+  ipauserauthtype:
+    description: The authentication type to use by default.
+    aliases: ["userauthtype"]
+    choices: ["password", "radius", "otp", "pkinit", "hardened", "disabled"]
+    type: list
+    elements: str
+    version_added: '2.5.0'
+  ipausersearchfields:
+    description: A list of fields to search in when searching for users.
+    aliases: ["usersearchfields"]
+    type: list
+    elements: str
+    version_added: '2.5.0'
 extends_documentation_fragment:
 - community.general.ipa.documentation
 
 '''
 
 EXAMPLES = r'''
-- name: Ensure the default login shell is bash.
+- name: Ensure password plugin features DC:Disable Last Success and KDC:Disable Lockout are enabled
+  community.general.ipa_config:
+    ipaconfigstring: ["KDC:Disable Last Success", "KDC:Disable Lockout"]
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the default login shell is bash
   community.general.ipa_config:
     ipadefaultloginshell: /bin/bash
     ipa_host: localhost
     ipa_user: admin
     ipa_pass: supersecret
 
-- name: Ensure the default e-mail domain is ansible.com.
+- name: Ensure the default e-mail domain is ansible.com
   community.general.ipa_config:
     ipadefaultemaildomain: ansible.com
     ipa_host: localhost
     ipa_user: admin
     ipa_pass: supersecret
+
+- name: Ensure the default primary group is set to ipausers
+  community.general.ipa_config:
+    ipadefaultprimarygroup: ipausers
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the group search fields are set to 'cn,description'
+  community.general.ipa_config:
+    ipagroupsearchfields: ['cn', 'description']
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the home directory location is set to /home
+  community.general.ipa_config:
+    ipahomesrootdir: /home
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the default types of PAC supported for services is set to MS-PAC and PAD
+  community.general.ipa_config:
+    ipakrbauthzdata: ["MS-PAC", "PAD"]
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the maximum user name length is set to 32
+  community.general.ipa_config:
+    ipamaxusernamelength: 32
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the password expiration notice is set to 4 days
+  community.general.ipa_config:
+    ipapwdexpadvnotify: 4
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the search record limit is set to 100
+  community.general.ipa_config:
+    ipasearchrecordslimit: 100
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the search time limit is set to 2 seconds
+  community.general.ipa_config:
+    ipasearchtimelimit: 2
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the default user auth type is password
+  community.general.ipa_config:
+    ipauserauthtype: ['password']
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
+
+- name: Ensure the user search fields is set to 'uid,givenname,sn,ou,title'
+  community.general.ipa_config:
+    ipausersearchfields: ['uid', 'givenname', 'sn', 'ou', 'title']
+    ipa_host: localhost
+    ipa_user: admin
+    ipa_pass: supersecret
 '''
 
 RETURN = r'''
@@ -68,12 +208,40 @@ def config_mod(self, name, item):
         return self._post_json(method='config_mod', name=name, item=item)
 
 
-def get_config_dict(ipadefaultloginshell=None, ipadefaultemaildomain=None):
+def get_config_dict(ipaconfigstring=None, ipadefaultloginshell=None,
+                    ipadefaultemaildomain=None, ipadefaultprimarygroup=None,
+                    ipagroupsearchfields=None, ipahomesrootdir=None,
+                    ipakrbauthzdata=None, ipamaxusernamelength=None,
+                    ipapwdexpadvnotify=None, ipasearchrecordslimit=None,
+                    ipasearchtimelimit=None, ipauserauthtype=None,
+                    ipausersearchfields=None):
     config = {}
+    if ipaconfigstring is not None:
+        config['ipaconfigstring'] = ipaconfigstring
     if ipadefaultloginshell is not None:
         config['ipadefaultloginshell'] = ipadefaultloginshell
     if ipadefaultemaildomain is not None:
         config['ipadefaultemaildomain'] = ipadefaultemaildomain
+    if ipadefaultprimarygroup is not None:
+        config['ipadefaultprimarygroup'] = ipadefaultprimarygroup
+    if ipagroupsearchfields is not None:
+        config['ipagroupsearchfields'] = ','.join(ipagroupsearchfields)
+    if ipahomesrootdir is not None:
+        config['ipahomesrootdir'] = ipahomesrootdir
+    if ipakrbauthzdata is not None:
+        config['ipakrbauthzdata'] = ipakrbauthzdata
+    if ipamaxusernamelength is not None:
+        config['ipamaxusernamelength'] = str(ipamaxusernamelength)
+    if ipapwdexpadvnotify is not None:
+        config['ipapwdexpadvnotify'] = str(ipapwdexpadvnotify)
+    if ipasearchrecordslimit is not None:
+        config['ipasearchrecordslimit'] = str(ipasearchrecordslimit)
+    if ipasearchtimelimit is not None:
+        config['ipasearchtimelimit'] = str(ipasearchtimelimit)
+    if ipauserauthtype is not None:
+        config['ipauserauthtype'] = ipauserauthtype
+    if ipausersearchfields is not None:
+        config['ipausersearchfields'] = ','.join(ipausersearchfields)
 
     return config
 
@@ -84,8 +252,19 @@ def get_config_diff(client, ipa_config, module_config):
 
 def ensure(module, client):
     module_config = get_config_dict(
+        ipaconfigstring=module.params.get('ipaconfigstring'),
         ipadefaultloginshell=module.params.get('ipadefaultloginshell'),
         ipadefaultemaildomain=module.params.get('ipadefaultemaildomain'),
+        ipadefaultprimarygroup=module.params.get('ipadefaultprimarygroup'),
+        ipagroupsearchfields=module.params.get('ipagroupsearchfields'),
+        ipahomesrootdir=module.params.get('ipahomesrootdir'),
+        ipakrbauthzdata=module.params.get('ipakrbauthzdata'),
+        ipamaxusernamelength=module.params.get('ipamaxusernamelength'),
+        ipapwdexpadvnotify=module.params.get('ipapwdexpadvnotify'),
+        ipasearchrecordslimit=module.params.get('ipasearchrecordslimit'),
+        ipasearchtimelimit=module.params.get('ipasearchtimelimit'),
+        ipauserauthtype=module.params.get('ipauserauthtype'),
+        ipausersearchfields=module.params.get('ipausersearchfields'),
     )
     ipa_config = client.config_show()
     diff = get_config_diff(client, ipa_config, module_config)
@@ -106,8 +285,31 @@ def ensure(module, client):
 def main():
     argument_spec = ipa_argument_spec()
     argument_spec.update(
+        ipaconfigstring=dict(type='list', elements='str',
+                             choices=['AllowNThash',
+                                      'KDC:Disable Last Success',
+                                      'KDC:Disable Lockout',
+                                      'KDC:Disable Default Preauth for SPNs'],
+                             aliases=['configstring']),
         ipadefaultloginshell=dict(type='str', aliases=['loginshell']),
         ipadefaultemaildomain=dict(type='str', aliases=['emaildomain']),
+        ipadefaultprimarygroup=dict(type='str', aliases=['primarygroup']),
+        ipagroupsearchfields=dict(type='list', elements='str',
+                                  aliases=['groupsearchfields']),
+        ipahomesrootdir=dict(type='str', aliases=['homesrootdir']),
+        ipakrbauthzdata=dict(type='list', elements='str',
+                             choices=['MS-PAC', 'PAD', 'nfs:NONE'],
+                             aliases=['krbauthzdata']),
+        ipamaxusernamelength=dict(type='int', aliases=['maxusernamelength']),
+        ipapwdexpadvnotify=dict(type='int', aliases=['pwdexpadvnotify']),
+        ipasearchrecordslimit=dict(type='int', aliases=['searchrecordslimit']),
+        ipasearchtimelimit=dict(type='int', aliases=['searchtimelimit']),
+        ipauserauthtype=dict(type='list', elements='str',
+                             aliases=['userauthtype'],
+                             choices=["password", "radius", "otp", "pkinit",
+                                      "hardened", "disabled"]),
+        ipausersearchfields=dict(type='list', elements='str',
+                                 aliases=['usersearchfields']),
     )
 
     module = AnsibleModule(


Test patch: