diff --git a/README-service.md b/README-service.md
index 666c18936742aac57dc9333ba0a3999724199f7c..c0cd32728cfeabdd459f7ce03b13742d949e4b40 100644
--- a/README-service.md
+++ b/README-service.md
@@ -293,8 +293,8 @@ Variable | Description | Required
 `ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
 `name` \| `service` | The list of service name strings. | yes
 `certificate` \| `usercertificate` | Base-64 encoded service certificate. | no
-`pac_type` \| `ipakrbauthzdata` | Supported PAC type. It can be one of `MS-PAC`, `PAD`, or `NONE`. | no
-`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit`, or `hardened`. | no
+`pac_type` \| `ipakrbauthzdata` | Supported PAC type. It can be one of `MS-PAC`, `PAD`, or `NONE`. Use empty string to reset pac_type to the initial value. | no
+`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit` or `hardened`.  Use empty string to reset auth_ind to the initial value. | no
 `requires_pre_auth` \| `ipakrbrequirespreauth` | Pre-authentication is required for the service. Default to true. (bool) | no
 `ok_as_delegate` \|  `ipakrbokasdelegate` | Client credentials may be delegated to the service. Default to false. (bool) | no
 `ok_to_auth_as_delegate` \|  `ipakrboktoauthasdelegate` | The service is allowed to authenticate on behalf of a client. Default to false. (bool) | no
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
index 3c25c7953c9bb72fbb54a9262c82297128326cf3..17d02d0e2490125064fd6d371c857f850c998e73 100644
--- a/plugins/module_utils/ansible_freeipa_module.py
+++ b/plugins/module_utils/ansible_freeipa_module.py
@@ -398,11 +398,32 @@ else:
 
         return value
 
-    def module_params_get(module, name):
-        return _afm_convert(module.params.get(name))
-
-    def module_params_get_lowercase(module, name):
+    def module_params_get(module, name, allow_empty_string=False):
         value = _afm_convert(module.params.get(name))
+
+        # Fail on empty strings in the list or if allow_empty_string is True
+        # if there is another entry in the list together with the empty
+        # string.
+        # Due to an issue in Ansible it is possible to use the empty string
+        # "" for lists with choices, even if the empty list is not part of
+        # the choices.
+        # Ansible issue https://github.com/ansible/ansible/issues/77108
+        if isinstance(value, list):
+            for val in value:
+                if isinstance(val, (str, unicode)) and not val:
+                    if not allow_empty_string:
+                        module.fail_json(
+                            msg="Parameter '%s' contains an empty string" %
+                            name)
+                    elif len(value) > 1:
+                        module.fail_json(
+                            msg="Parameter '%s' may not contain another "
+                            "entry together with an empty string" % name)
+
+        return value
+
+    def module_params_get_lowercase(module, name, allow_empty_string=False):
+        value = module_params_get(module, name, allow_empty_string)
         if isinstance(value, list):
             value = [v.lower() for v in value]
         if isinstance(value, (str, unicode)):
@@ -897,7 +918,7 @@ else:
                 finally:
                     temp_kdestroy(ccache_dir, ccache_name)
 
-        def params_get(self, name):
+        def params_get(self, name, allow_empty_string=False):
             """
             Retrieve value set for module parameter.
 
@@ -905,11 +926,13 @@ else:
             ----------
             name: string
                 The name of the parameter to retrieve.
+            allow_empty_string: bool
+                The parameter allowes to have empty strings in a list
 
             """
-            return module_params_get(self, name)
+            return module_params_get(self, name, allow_empty_string)
 
-        def params_get_lowercase(self, name):
+        def params_get_lowercase(self, name, allow_empty_string=False):
             """
             Retrieve value set for module parameter as lowercase, if not None.
 
@@ -917,9 +940,11 @@ else:
             ----------
             name: string
                 The name of the parameter to retrieve.
+            allow_empty_string: bool
+                The parameter allowes to have empty strings in a list
 
             """
-            return module_params_get_lowercase(self, name)
+            return module_params_get_lowercase(self, name, allow_empty_string)
 
         def params_fail_used_invalid(self, invalid_params, state, action=None):
             """
diff --git a/plugins/modules/ipaconfig.py b/plugins/modules/ipaconfig.py
index 2a155bdfed49b39be87f03bb69aacb830cb00452..f7901f2c23817c5016f832f86158db205875226b 100644
--- a/plugins/modules/ipaconfig.py
+++ b/plugins/modules/ipaconfig.py
@@ -346,11 +346,13 @@ def main():
         "ca_renewal_master_server": "ca_renewal_master_server",
         "domain_resolution_order": "ipadomainresolutionorder"
     }
+    allow_empty_string = ["pac_type", "user_auth_type", "configstring"]
     reverse_field_map = {v: k for k, v in field_map.items()}
 
     params = {}
     for x in field_map:
-        val = ansible_module.params_get(x)
+        val = ansible_module.params_get(
+            x, allow_empty_string=(x in allow_empty_string))
 
         if val is not None:
             params[field_map.get(x, x)] = val
@@ -401,6 +403,10 @@ def main():
                 k: v for k, v in params.items()
                 if k not in result or result[k] != v
             }
+            # Remove empty string args from params if result arg is not set
+            for k in ["ipakrbauthzdata", "ipauserauthtype", "ipaconfigstring"]:
+                if k not in result and k in params and params[k] == [""]:
+                    del params[k]
             if params \
                and not compare_args_ipa(ansible_module, params, result):
                 changed = True
@@ -441,6 +447,13 @@ def main():
                             raise ValueError(
                                 "Unexpected attribute type: %s" % arg_type)
                         exit_args[k] = type_map[arg_type](value)
+            # Add empty pac_type and user_auth_type if they are not set
+            for key in ["pac_type", "user_auth_type"]:
+                if key not in exit_args:
+                    exit_args[key] = ""
+            # Add empty domain_resolution_order if it is not set
+            if "domain_resolution_order" not in exit_args:
+                exit_args["domain_resolution_order"] = []
 
     # Done
     ansible_module.exit_json(changed=changed, config=exit_args)
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
index 453200e6e762e47e7b22a3478b4491d63c9f7ca4..39857bca633dfdec6213c28b01482f79bf1adf83 100644
--- a/plugins/modules/ipahost.py
+++ b/plugins/modules/ipahost.py
@@ -764,7 +764,7 @@ def main():
     mac_address = ansible_module.params_get("mac_address")
     sshpubkey = ansible_module.params_get("sshpubkey")
     userclass = ansible_module.params_get("userclass")
-    auth_ind = ansible_module.params_get("auth_ind")
+    auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
     requires_pre_auth = ansible_module.params_get("requires_pre_auth")
     ok_as_delegate = ansible_module.params_get("ok_as_delegate")
     ok_to_auth_as_delegate = ansible_module.params_get(
diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py
index bc737712660e3ea9c40412b6fb59fc49a4f34792..989ab9a03c0a73b4856396b236b4d8b3247179bd 100644
--- a/plugins/modules/ipaservice.py
+++ b/plugins/modules/ipaservice.py
@@ -50,13 +50,13 @@ options:
   pac_type:
     description: Supported PAC type.
     required: false
-    choices: ["MS-PAC", "PAD", "NONE"]
+    choices: ["MS-PAC", "PAD", "NONE", ""]
     type: list
     aliases: ["pac_type", "ipakrbauthzdata"]
   auth_ind:
     description: Defines a whitelist for Authentication Indicators.
     required: false
-    choices: ["otp", "radius", "pkinit", "hardened"]
+    choices: ["otp", "radius", "pkinit", "hardened", ""]
     aliases: ["krbprincipalauthind"]
   skip_host_check:
     description: Skip checking if host object exists.
@@ -356,7 +356,7 @@ def init_ansible_module():
             smb=dict(type="bool", required=False),
             netbiosname=dict(type="str", required=False),
             pac_type=dict(type="list", aliases=["ipakrbauthzdata"],
-                          choices=["MS-PAC", "PAD", "NONE"]),
+                          choices=["MS-PAC", "PAD", "NONE", ""]),
             auth_ind=dict(type="list",
                           aliases=["krbprincipalauthind"],
                           choices=["otp", "radius", "pkinit", "hardened", ""]),
@@ -420,8 +420,8 @@ def main():
     # service attributes
     principal = ansible_module.params_get("principal")
     certificate = ansible_module.params_get("certificate")
-    pac_type = ansible_module.params_get("pac_type")
-    auth_ind = ansible_module.params_get("auth_ind")
+    pac_type = ansible_module.params_get("pac_type", allow_empty_string=True)
+    auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
     skip_host_check = ansible_module.params_get("skip_host_check")
     force = ansible_module.params_get("force")
     requires_pre_auth = ansible_module.params_get("requires_pre_auth")
@@ -537,6 +537,15 @@ def main():
                             if remove in args:
                                 del args[remove]
 
+                        if (
+                            "ipakrbauthzdata" in args
+                            and (
+                                args.get("ipakrbauthzdata", [""]) ==
+                                res_find.get("ipakrbauthzdata", [""])
+                            )
+                        ):
+                            del args["ipakrbauthzdata"]
+
                         if (
                             "krbprincipalauthind" in args
                             and (
diff --git a/plugins/modules/ipauser.py b/plugins/modules/ipauser.py
index aee71cd22aaaa68fc4d4a337cb339c52c9cf87e4..fb0fbc47727176048867515ac6ae6d03a9c30f6e 100644
--- a/plugins/modules/ipauser.py
+++ b/plugins/modules/ipauser.py
@@ -892,8 +892,10 @@ def main():
     title = ansible_module.params_get("title")
     manager = ansible_module.params_get("manager")
     carlicense = ansible_module.params_get("carlicense")
-    sshpubkey = ansible_module.params_get("sshpubkey")
-    userauthtype = ansible_module.params_get("userauthtype")
+    sshpubkey = ansible_module.params_get("sshpubkey",
+                                          allow_empty_string=True)
+    userauthtype = ansible_module.params_get("userauthtype",
+                                             allow_empty_string=True)
     userclass = ansible_module.params_get("userclass")
     radius = ansible_module.params_get("radius")
     radiususer = ansible_module.params_get("radiususer")
@@ -1101,6 +1103,13 @@ def main():
                         if "noprivate" in args:
                             del args["noprivate"]
 
+                        # Ignore sshpubkey if it is empty (for resetting)
+                        # and not set in for the user
+                        if "ipasshpubkey" not in res_find and \
+                           "ipasshpubkey" in args and \
+                           args["ipasshpubkey"] == ['']:
+                            del args["ipasshpubkey"]
+
                         # Ignore userauthtype if it is empty (for resetting)
                         # and not set in for the user
                         if "ipauserauthtype" not in res_find and \
diff --git a/tests/config/test_config_empty_string_params.yml b/tests/config/test_config_empty_string_params.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5329c20361de513a556634be57d59600cb2166d2
--- /dev/null
+++ b/tests/config/test_config_empty_string_params.yml
@@ -0,0 +1,143 @@
+---
+- name: Test config
+  hosts: "{{ ipa_test_host | default('ipaserver') }}"
+  become: yes
+  gather_facts: no
+
+  tasks:
+
+  # GET CURRENT CONFIG
+
+  - name: Return current values of the global configuration options
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+    register: previousconfig
+
+  - name: Ensure config with empty pac_type, user_auth_type and configstring
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      pac_type: ""
+      user_auth_type: ""
+      configstring: ""
+
+  # TESTS
+
+  - name: Ensure config with pac_type "nfs:NONE" and PAD
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      pac_type:
+      - "nfs:NONE"
+      - PAD
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure config with pac_type "nfs:NONE" and PAD, again
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      pac_type:
+      - "nfs:NONE"
+      - PAD
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure config with empty pac_type
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      pac_type: ""
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure config with empty pac_type, again
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      pac_type: ""
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure config with user_auth_type otp and radius
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      user_auth_type:
+      - otp
+      - radius
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure config with user_auth_type otp and radius, again
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      user_auth_type:
+      - otp
+      - radius
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure config with empty user_auth_type
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      user_auth_type: ""
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure config with empty user_auth_type, again
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      user_auth_type: ""
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure config with configstring AllowNThash and "KDC:Disable Lockout"
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      configstring:
+      - AllowNThash
+      - "KDC:Disable Lockout"
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure config with configstring AllowNThash and "KDC:Disable Lockout", again
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      configstring:
+      - AllowNThash
+      - "KDC:Disable Lockout"
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure config with empty configstring
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      configstring: ""
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure config with empty configstring, again
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      configstring: ""
+    register: result
+    failed_when: result.changed or result.failed
+
+  # REVERT TO PREVIOUS CONFIG
+
+  - name: Reset to previous pac_type and user_auth_type
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      pac_type: '{{ previousconfig.config.pac_type }}'
+      user_auth_type: '{{ previousconfig.config.user_auth_type }}'
+      configstring: '{{ previousconfig.config.configstring }}'
diff --git a/tests/host/test_host_empty_string_params.yml b/tests/host/test_host_empty_string_params.yml
new file mode 100644
index 0000000000000000000000000000000000000000..59481d1198d048d87a45c7c03ccc90cb455a3daa
--- /dev/null
+++ b/tests/host/test_host_empty_string_params.yml
@@ -0,0 +1,86 @@
+---
+- name: Test host
+  hosts: "{{ ipa_test_host | default('ipaserver') }}"
+  become: yes
+  gather_facts: yes
+
+  tasks:
+  - name: Get Domain from server name
+    set_fact:
+      ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join ('.') }}"
+    when: ipaserver_domain is not defined
+
+  - name: Set host1_fqdn .. host6_fqdn
+    set_fact:
+      host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+
+  # CLEANUP TEST ITEMS
+
+  - name: Ensure host "{{ host1_fqdn }}" absent
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "{{ host1_fqdn }}"
+      state: absent
+
+  # CREATE TEST ITEMS
+
+  - name: Ensure host "{{ host1_fqdn }}" present
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "{{ host1_fqdn }}"
+      force: yes
+    register: result
+    failed_when: not result.changed or result.failed
+
+  # TESTS
+
+  - name: Ensure host "{{ host1_fqdn }}" present with auth_ind otp and radius
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "{{ host1_fqdn }}"
+      auth_ind:
+      - otp
+      - radius
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure host "{{ host1_fqdn }}" present with auth_ind otp and radius, again
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "{{ host1_fqdn }}"
+      auth_ind:
+      - otp
+      - radius
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure host "{{ host1_fqdn }}" present with empty auth_ind
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "{{ host1_fqdn }}"
+      auth_ind: ""
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure host "{{ host1_fqdn }}" present with empty auth_ind, again
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "{{ host1_fqdn }}"
+      auth_ind: ""
+    register: result
+    failed_when: result.changed or result.failed
+
+  # CLEANUP TEST ITEMS
+
+  - name: Ensure host "{{ host1_fqdn }}" absent
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "{{ host1_fqdn }}"
+      state: absent
diff --git a/tests/service/test_service_empty_string_params.yml b/tests/service/test_service_empty_string_params.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1831e49633cf254f9e2e6f28fc6647940af4d81e
--- /dev/null
+++ b/tests/service/test_service_empty_string_params.yml
@@ -0,0 +1,110 @@
+---
+- name: Test service
+  hosts: "{{ ipa_test_host | default('ipaserver') }}"
+  become: yes
+  gather_facts: yes
+
+  tasks:
+
+  # CLEANUP TEST ITEMS
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is absent.
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      continue: yes
+      state: absent
+
+  # CREATE TEST ITEMS
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+    register: result
+    failed_when: not result.changed or result.failed
+
+  # TESTS
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with pac_type MS-PAC and PAD
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      pac_type:
+        - MS-PAC
+        - PAD
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with pac_type MS-PAC and PAD, again
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      pac_type:
+        - MS-PAC
+        - PAD
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty pac_type
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      pac_type: ""
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty pac_type, again
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      pac_type: ""
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with auth_ind otp and radius
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      auth_ind:
+        - otp
+        - radius
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with auth_ind otp and radius, again
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      auth_ind:
+        - otp
+        - radius
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty auth_ind
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      auth_ind: ""
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty auth_ind, again
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      auth_ind: ""
+    register: result
+    failed_when: result.changed or result.failed
+
+  # CLEANUP TEST ITEMS
+
+  - name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is absent.
+    ipaservice:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: "test-service/{{ ansible_facts['fqdn'] }}"
+      continue: yes
+      state: absent
diff --git a/tests/user/test_user_empty_string_params.yml b/tests/user/test_user_empty_string_params.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ebece0c026d5f501438bdc50eb5e6ba9a441f328
--- /dev/null
+++ b/tests/user/test_user_empty_string_params.yml
@@ -0,0 +1,115 @@
+---
+- name: Test user
+  hosts: "{{ ipa_test_host | default('ipaserver') }}"
+  become: true
+  gather_facts: false
+
+  tasks:
+
+  # CLEANUP TEST ITEMS
+
+  - name: Ensure user testuser absent
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      state: absent
+
+  # CREATE TEST ITEMS
+
+  - name: Ensure user testuser present
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      first: test
+      last: user
+    register: result
+    failed_when: not result.changed or result.failed
+
+  # TESTS
+
+  - name: Ensure user testuser present with userauthtype password,radius,otp
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      userauthtype: password,radius,otp
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure user testuser present with userauthtype password,radius,otp, again
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      userauthtype: password,radius,otp
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure user testuser present with empty userauthtype
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      userauthtype: ""
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure user testuser present with empty userauthtype, again
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      userauthtype: ""
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure user testuser present with sshpubkey
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      sshpubkey:
+      # yamllint disable-line rule:line-length
+      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqmVDpEX5gnSjKuv97AyzOhaUMMKz8ahOA3GY77tVC4o68KNgMCmDSEG1/kOIaElngNLaCha3p/2iAcU9Bi1tLKUlm2bbO5NHNwHfRxY/3cJtq+/7D1vxJzqThYwI4F9vr1WxyY2+mMTv3pXbfAJoR8Mu06XaEY5PDetlDKjHLuNWF+/O7ZU8PsULTa1dJZFrtXeFpmUoLoGxQBvlrlcPI1zDciCSU24t27Zan5Py2l5QchyI7yhCyMM77KDtj5+AFVpmkb9+zq50rYJAyFVeyUvwjzErvQrKJzYpA0NyBp7vskWbt36M16/M/LxEK7HA6mkcakO3ESWx5MT1LAjvdlnxbWG3787MxweHXuB8CZU+9bZPFBaJ+VQtOfJ7I8eH0S16moPC4ak8FlcFvOH8ERDPWLFDqfy09yaZ7bVIF0//5ZI7Nf3YDe3S7GrBX5ieYuECyP6UNkTx9BRsAQeVvXEc6otzB7iCSnYBMGUGzCqeigoAWaVQUONsSR3Uatks= pinky@ipaserver.el81.local  # noqa 204
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure user testuser present with sshpubkey, again
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      sshpubkey:
+      # yamllint disable-line rule:line-length
+      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqmVDpEX5gnSjKuv97AyzOhaUMMKz8ahOA3GY77tVC4o68KNgMCmDSEG1/kOIaElngNLaCha3p/2iAcU9Bi1tLKUlm2bbO5NHNwHfRxY/3cJtq+/7D1vxJzqThYwI4F9vr1WxyY2+mMTv3pXbfAJoR8Mu06XaEY5PDetlDKjHLuNWF+/O7ZU8PsULTa1dJZFrtXeFpmUoLoGxQBvlrlcPI1zDciCSU24t27Zan5Py2l5QchyI7yhCyMM77KDtj5+AFVpmkb9+zq50rYJAyFVeyUvwjzErvQrKJzYpA0NyBp7vskWbt36M16/M/LxEK7HA6mkcakO3ESWx5MT1LAjvdlnxbWG3787MxweHXuB8CZU+9bZPFBaJ+VQtOfJ7I8eH0S16moPC4ak8FlcFvOH8ERDPWLFDqfy09yaZ7bVIF0//5ZI7Nf3YDe3S7GrBX5ieYuECyP6UNkTx9BRsAQeVvXEc6otzB7iCSnYBMGUGzCqeigoAWaVQUONsSR3Uatks= pinky@ipaserver.el81.local  # noqa 204
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure user testuser present with empty sshpubkey
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      sshpubkey: ""
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Ensure user testuser present with empty sshpubkey, again
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      sshpubkey: ""
+    register: result
+    failed_when: result.changed or result.failed
+
+  # CLEANUP TEST ITEMS
+
+  - name: Ensure user testuser absent
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+      ipaapi_context: "{{ ipa_context | default(omit) }}"
+      name: testuser
+      state: absent