Merge pull request #1372 from rjeffman/passkey_support

Add support for passkey
This commit is contained in:
Thomas Woerner
2026-01-07 20:22:46 +01:00
committed by GitHub
20 changed files with 567 additions and 18 deletions

View File

@@ -145,7 +145,7 @@ Variable | Description | Required
`selinuxusermaporder` \| `ipaselinuxusermaporder`| Set ordered list in increasing priority of SELinux users | no
`selinuxusermapdefault`\| `ipaselinuxusermapdefault` | Set default SELinux user when no match is found in SELinux map rule | no
`pac_type` \| `ipakrbauthzdata` | set default types of PAC supported for services (choices: `MS-PAC`, `PAD`, `nfs:NONE`). Use `""` to clear this variable. | no
`user_auth_type` \| `ipauserauthtype` | set default types of supported user authentication (choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp`, `disabled`, `""`). An additional check ensures that only types can be used that are supported by the IPA version. Use `""` to clear this variable. | no
`user_auth_type` \| `ipauserauthtype` | set default types of supported user authentication (choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp`, `passkey`, `disabled`, `""`). An additional check ensures that only types can be used that are supported by the IPA version. Use `""` to clear this variable. | no
`domain_resolution_order` \| `ipadomainresolutionorder` | Set list of domains used for short name qualification | no
`ca_renewal_master_server` \| `ipacarenewalmasterserver`| Renewal master for IPA certificate authority. | no
`enable_sid` | New users and groups automatically get a SID assigned. Cannot be deactivated once activated. Requires IPA 4.9.8+. (bool) | no

View File

@@ -354,7 +354,7 @@ Variable | Description | Required
`mac_address` \| `macaddress` | List of hardware MAC addresses. | no
`sshpubkey` \| `ipasshpubkey` | List of SSH public keys | no
`userclass` \| `class` | Host category (semantics placed on this attribute are for local interpretation) | no
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. Use 'otp' to allow OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA authentications. Use empty string to reset auth_ind to the initial value. Other values may be used for custom configurations. An additional check ensures that only types can be used that are supported by the IPA version. Choices: ["radius", "otp", "pkinit", "hardened", "idp", ""] | no
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. Use 'otp' to allow OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA authentications. Use empty string to reset auth_ind to the initial value. Other values may be used for custom configurations. An additional check ensures that only types can be used that are supported by the IPA version. Choices: ["radius", "otp", "pkinit", "hardened", "idp", "passkey", ""] | no
`requires_pre_auth` \| `ipakrbrequirespreauth` | Pre-authentication is required for the service (bool) | no
`ok_as_delegate` \| `ipakrbokasdelegate` | Client credentials may be delegated to the service (bool) | no
`ok_to_auth_as_delegate` \| `ipakrboktoauthasdelegate` | The service is allowed to authenticate on behalf of a client (bool) | no

88
README-passkeyconfig.md Normal file
View File

@@ -0,0 +1,88 @@
Passkeyconfig module
============
Description
-----------
The passkeyconfig module allows to manage FreeIPA passkey configuration settings.
Features
--------
* Passkeyconfig management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipapasskeyconfig module.
Requirements
------------
**Controller**
* Ansible version: 2.15+
**Node**
* Supported FreeIPA version (see above)
Usage
=====
Example inventory file
```ini
[ipaserver]
ipaserver.test.local
```
By default, user verification for passkey authentication is turned on (`true`). Example playbook to ensure that the requirement for user verification for passkey authentication is turned off:
```yaml
---
- name: Playbook to manage IPA passkeyconfig.
hosts: ipaserver
become: false
tasks:
- name: Ensure require_user_verification is false
ipapasskeyconfig:
ipaadmin_password: SomeADMINpassword
require_user_verification: false
```
Example playbook to get current passkeyconfig:
```yaml
---
- name: Playbook to get IPA passkeyconfig.
hosts: ipaserver
become: false
tasks:
- name: Retrieve current passkey configuration
ipapasskeyconfig:
ipaadmin_password: SomeADMINpassword
```
Variables
---------
Variable | Description | Required
-------- | ----------- | --------
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to true. (bool) | no
`require_user_verification` \| `iparequireuserverification` | Require user verification for passkey authentication. (bool) | no
Authors
=======
Rafael Guterres Jeffman

View File

@@ -361,7 +361,7 @@ Variable | Description | Required
-------- | ----------- | --------
`certificate` \| `usercertificate` | Base-64 encoded service certificate. | 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`, `hardened`, `idp` or `""`. An additional check ensures that only types can be used that are supported by the IPA version. Use empty string to reset auth_ind to the initial value. | no
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit`, `hardened`, `idp`, `passkey` or `""`. An additional check ensures that only types can be used that are supported by the IPA version. 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

View File

@@ -452,7 +452,7 @@ Variable | Description | Required
`manager` | List of manager user names. | no
`carlicense` | List of car licenses. | no
`sshpubkey` \| `ipasshpubkey` | List of SSH public keys. | no
`userauthtype` \| `ipauserauthtype` | List of supported user authentication types. Choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp` and `""`. An additional check ensures that only types can be used that are supported by the IPA version. Use empty string to reset userauthtype to the initial value. | no
`userauthtype` \| `ipauserauthtype` | List of supported user authentication types. Choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp`, `passkey` and `""`. An additional check ensures that only types can be used that are supported by the IPA version. Use empty string to reset userauthtype to the initial value. | no
`userclass` | User category. (semantics placed on this attribute are for local interpretation). | no
`radius` | RADIUS proxy configuration | no
`radiususer` | RADIUS proxy username | no

View File

@@ -38,6 +38,7 @@ Features
* Modules for idview management
* Modules for location management
* Modules for netgroup management
* Modules for passkeyconfig management
* Modules for permission management
* Modules for privilege management
* Modules for pwpolicy management
@@ -454,6 +455,7 @@ Modules in plugin/modules
* [idview](README-idview.md)
* [ipalocation](README-location.md)
* [ipanetgroup](README-netgroup.md)
* [ipapasskeyconfig](README-passkeyconfig.md)
* [ipapermission](README-permission.md)
* [ipaprivilege](README-privilege.md)
* [ipapwpolicy](README-pwpolicy.md)

View File

@@ -0,0 +1,10 @@
---
- name: Passkeyconfig example
hosts: ipaserver
become: no
tasks:
- name: Set passkeyconfig require_user_verification to false
ipapasskeyconfig:
ipaadmin_password: SomeADMINpassword
require_user_verification: false

View File

@@ -0,0 +1,14 @@
---
- name: Passkeyconfig get current configuration example
hosts: ipaserver
become: true
tasks:
- name: Get current passkey configuration
ipapasskeyconfig:
ipaadmin_password: SomeADMINpassword
register: result
- name: Display current passkey configuration
ansible.builtin.debug:
var: result.passkeyconfig

View File

@@ -161,7 +161,7 @@ options:
type: list
elements: str
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp",
"disabled", ""]
"passkey", "disabled", ""]
aliases: ["ipauserauthtype"]
ca_renewal_master_server:
description: Renewal master for IPA certificate authority.
@@ -426,7 +426,7 @@ def main():
user_auth_type=dict(type="list", elements="str", required=False,
choices=["password", "radius", "otp",
"pkinit", "hardened", "idp",
"disabled", ""],
"passkey", "disabled", ""],
aliases=["ipauserauthtype"]),
ca_renewal_master_server=dict(type="str", required=False),
domain_resolution_order=dict(type="list", elements="str",

View File

@@ -184,7 +184,7 @@ options:
type: list
elements: str
aliases: ["krbprincipalauthind"]
choices: ["radius", "otp", "pkinit", "hardened", "idp", ""]
choices: ["radius", "otp", "pkinit", "hardened", "idp", "passkey", ""]
required: false
requires_pre_auth:
description: Pre-authentication is required for the service
@@ -356,7 +356,7 @@ options:
type: list
elements: str
aliases: ["krbprincipalauthind"]
choices: ["radius", "otp", "pkinit", "hardened", "idp", ""]
choices: ["radius", "otp", "pkinit", "hardened", "idp", "passkey", ""]
required: false
requires_pre_auth:
description: Pre-authentication is required for the service
@@ -758,7 +758,7 @@ def main():
auth_ind=dict(type='list', elements="str",
aliases=["krbprincipalauthind"], default=None,
choices=["radius", "otp", "pkinit", "hardened", "idp",
""]),
"passkey", ""]),
requires_pre_auth=dict(type="bool", aliases=["ipakrbrequirespreauth"],
default=None),
ok_as_delegate=dict(type="bool", aliases=["ipakrbokasdelegate"],

View File

@@ -0,0 +1,174 @@
# -*- coding: utf-8 -*-
# Authors:
# Rafael Guterres Jeffman <rjeffman@redhat.com>
#
# Copyright (C) 2025 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipapasskeyconfig
short_description: Manage FreeIPA passkeyconfig
description: Manage FreeIPA passkeyconfig
extends_documentation_fragment:
- ipamodule_base_docs
options:
require_user_verification:
description: Require user verification for passkey authentication
required: false
type: bool
default: true
aliases: ["iparequireuserverification"]
author:
- Rafael Guterres Jeffman (@rjeffman)
"""
EXAMPLES = """
# Set passkeyconfig
- ipapasskeyconfig:
ipaadmin_password: SomeADMINpassword
require_user_verification: false
# Get current passkeyconfig
- ipapasskeyconfig:
ipaadmin_password: SomeADMINpassword
"""
RETURN = """
passkeyconfig:
description: Dict of passkeyconfig settings
returned: always
type: dict
contains:
require_user_verification:
description: Require user verification for passkey authentication
type: bool
returned: always
"""
from ansible.module_utils.ansible_freeipa_module import \
IPAAnsibleModule, compare_args_ipa, ipalib_errors
from ansible.module_utils import six
if six.PY3:
unicode = str
def find_passkeyconfig(module):
"""Find the current passkeyconfig settings."""
try:
_result = module.ipa_command_no_name(
"passkeyconfig_show", {"all": True})
except ipalib_errors.NotFound:
# An exception is raised if passkeyconfig is not found.
return None
return _result["result"]
def gen_args(require_user_verification):
_args = {}
if require_user_verification is not None:
_args["iparequireuserverification"] = require_user_verification
return _args
def main():
ansible_module = IPAAnsibleModule(
argument_spec=dict(
# passkeyconfig
require_user_verification=dict(
required=False, type='bool',
aliases=["iparequireuserverification"],
default=None
),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
require_user_verification = (
ansible_module.params_get("require_user_verification")
)
# Init
changed = False
exit_args = {}
# Connect to IPA API
with ansible_module.ipa_connect():
if not ansible_module.ipa_command_exists("passkeyconfig_show"):
msg = "Managing passkeyconfig is not supported by your IPA version"
ansible_module.fail_json(msg=msg)
result = find_passkeyconfig(ansible_module)
if result is None:
ansible_module.fail_json(msg="Could not retrieve passkeyconfig")
if require_user_verification is not None:
# Generate args
args = gen_args(require_user_verification)
# Check if there are different settings in the find result.
# If yes: modify
if not compare_args_ipa(ansible_module, args, result):
changed = True
if not ansible_module.check_mode:
try:
ansible_module.ipa_command_no_name(
"passkeyconfig_mod", args)
except ipalib_errors.EmptyModlist:
changed = False
except Exception as e:
ansible_module.fail_json(
msg="passkeyconfig_mod failed: %s" % str(e))
else:
# No parameters provided, just return current config
pass
# Get updated config if changes were made
if changed:
result = find_passkeyconfig(ansible_module)
# Prepare exit args
exit_args["passkeyconfig"] = {}
if result:
# Map IPA API field to module parameter
if "iparequireuserverification" in result:
exit_args["passkeyconfig"]["require_user_verification"] = \
result["iparequireuserverification"][0]
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -74,7 +74,7 @@ options:
type: list
elements: str
required: false
choices: ["otp", "radius", "pkinit", "hardened", "idp", ""]
choices: ["otp", "radius", "pkinit", "hardened", "idp", "passkey", ""]
aliases: ["krbprincipalauthind"]
skip_host_check:
description: Skip checking if host object exists.
@@ -192,7 +192,7 @@ options:
type: list
elements: str
required: false
choices: ["otp", "radius", "pkinit", "hardened", "idp", ""]
choices: ["otp", "radius", "pkinit", "hardened", "idp", "passkey", ""]
aliases: ["krbprincipalauthind"]
skip_host_check:
description: Skip checking if host object exists.
@@ -560,7 +560,7 @@ def init_ansible_module():
auth_ind=dict(type="list", elements="str",
aliases=["krbprincipalauthind"],
choices=["otp", "radius", "pkinit", "hardened", "idp",
""]),
"passkey", ""]),
skip_host_check=dict(type="bool"),
force=dict(type="bool"),
requires_pre_auth=dict(

View File

@@ -208,7 +208,8 @@ options:
Use empty string to reset userauthtype to the initial value.
type: list
elements: str
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp", ""]
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp",
"passkey", ""]
required: false
aliases: ["ipauserauthtype"]
userclass:
@@ -480,7 +481,8 @@ options:
Use empty string to reset userauthtype to the initial value.
type: list
elements: str
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp", ""]
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp",
"passkey", ""]
required: false
aliases: ["ipauserauthtype"]
userclass:
@@ -1070,7 +1072,7 @@ def main():
userauthtype=dict(type='list', elements="str",
aliases=["ipauserauthtype"], default=None,
choices=["password", "radius", "otp", "pkinit",
"hardened", "idp", ""]),
"hardened", "idp", "passkey", ""]),
userclass=dict(type="list", elements="str", aliases=["class"],
default=None),
radius=dict(type="str", aliases=["ipatokenradiusconfiglink"],

View File

@@ -5,6 +5,8 @@
gather_facts: no
tasks:
- name: Include tasks ../env_freeipa_facts.yml
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
# GET CURRENT CONFIG
@@ -80,6 +82,36 @@
register: result
failed_when: result.changed or result.failed
- name: Ensure config with user_auth_type passkey
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
user_auth_type:
- passkey
register: result
failed_when: not result.changed or result.failed
when: passkey_is_supported
- name: Ensure config with user_auth_type passkey, again
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
user_auth_type:
- passkey
register: result
failed_when: result.changed or result.failed
when: passkey_is_supported
- name: Check if correct message is given if passkey is not supported.
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
user_auth_type:
- passkey
register: result
failed_when: not result.failed or "'passkey' is not supported" not in result.msg
when: not passkey_is_supported
- name: Ensure config with empty user_auth_type
ipaconfig:
ipaadmin_password: SomeADMINpassword
@@ -138,6 +170,6 @@
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 }}'
pac_type: '{{ previousconfig.config.pac_type | default("") }}'
user_auth_type: '{{ previousconfig.config.user_auth_type | default("") }}'
configstring: '{{ previousconfig.config.configstring | default("") }}'

View File

@@ -38,12 +38,24 @@
krb5ccname: "__check_ipa_host_is_client_or_server__"
register: check_ad_support
- name: Verify if passkey tests are possible
ansible.builtin.shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin > /dev/null
RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa command-find passkey | grep "Number of entries returned")
kdestroy -A -c {{ krb5ccname }} > /dev/null
echo $RESULT
vars:
krb5ccname: "__check_ipa_host_is_client_or_server__"
register: check_passkey_support
- name: Set FreeIPA facts.
ansible.builtin.set_fact:
ipa_version: "{{ ipa_cmd_version.stdout_lines[0] }}"
ipa_api_version: "{{ ipa_cmd_version.stdout_lines[1] }}"
ipa_host_is_client: "{{ (check_client.stdout_lines[-1] == 'CLIENT') | bool }}"
trust_test_is_supported: "{{ 'AD trust agent' in check_ad_support.stdout }}"
passkey_is_supported: "{{ 'Number of entries returned 0' not in check_passkey_support.stdout }}"
- name: Ensure ipaserver_domain is set
when: ipaserver_domain is not defined

View File

@@ -5,6 +5,9 @@
gather_facts: yes
tasks:
- name: Include FreeIPA facts.
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
- name: Get Domain from server name
ansible.builtin.set_fact:
ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join('.') }}"
@@ -58,6 +61,39 @@
register: result
failed_when: result.changed or result.failed
- name: Ensure host "{{ host1_fqdn }}" present with auth_ind passkey
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
auth_ind:
- passkey
register: result
when: passkey_is_supported
failed_when: not result.changed or result.failed
- name: Ensure host "{{ host1_fqdn }}" present with auth_ind passkey, again
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
auth_ind:
- passkey
register: result
when: passkey_is_supported
failed_when: result.changed or result.failed
- name: Check if correct message is given if passkey is not supported.
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
auth_ind:
- passkey
register: result
when: not passkey_is_supported
failed_when: not result.failed or "'passkey' is not supported" not in result.msg
- name: Ensure host "{{ host1_fqdn }}" present with empty auth_ind
ipahost:
ipaadmin_password: SomeADMINpassword

View File

@@ -0,0 +1,67 @@
---
- name: Test passkeyconfig
hosts: "{{ ipa_test_host | default('ipaserver') }}"
# It is normally not needed to set "become" to "true" for a module test.
# Only set it to true if it is needed to execute commands as root.
become: false
# Enable "gather_facts" only if "ansible_facts" variable needs to be used.
gather_facts: false
module_defaults:
ipapasskeyconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
tasks:
- name: Include FreeIPA facts.
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
- name: Run tests only if passkey is supported
when: passkey_is_supported
block:
# TESTS
- name: Get current passkeyconfig
ipapasskeyconfig:
register: result_initial
failed_when: result_initial.failed
- name: Ensure require_user_verification is set to false
ipapasskeyconfig:
require_user_verification: false
register: result
failed_when: result.failed
- name: Ensure require_user_verification is set to false again
ipapasskeyconfig:
require_user_verification: false
register: result
failed_when: result.changed or result.failed
- name: Verify require_user_verification is false
ansible.builtin.assert:
that:
- result.passkeyconfig.require_user_verification == false
- name: Ensure require_user_verification is set to true
ipapasskeyconfig:
require_user_verification: true
register: result
failed_when: not result.changed or result.failed
- name: Ensure require_user_verification is set to true again
ipapasskeyconfig:
require_user_verification: true
register: result
failed_when: result.changed or result.failed
- name: Verify require_user_verification is true
ansible.builtin.assert:
that:
- result.passkeyconfig.require_user_verification == true
# CLEANUP: Restore original configuration
- name: Restore original passkeyconfig
ipapasskeyconfig:
require_user_verification: "{{ result_initial.passkeyconfig.require_user_verification }}"
when: result_initial.passkeyconfig is defined and result_initial.passkeyconfig.require_user_verification is defined

View File

@@ -0,0 +1,40 @@
---
- name: Test passkeyconfig
hosts: ipaclients, ipaserver
# It is normally not needed to set "become" to "true" for a module test.
# Only set it to true if it is needed to execute commands as root.
become: false
# Enable "gather_facts" only if "ansible_facts" variable needs to be used.
gather_facts: false
tasks:
- name: Include FreeIPA facts.
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
# Test will only be executed if host is not a server.
- name: Execute with server context in the client.
ipapasskeyconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: server
require_user_verification: false
register: result
failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*"))
when: ipa_host_is_client and passkey_is_supported
# Import basic module tests, and execute with ipa_context set to 'client'.
# If ipaclients is set, it will be executed using the client, if not,
# ipaserver will be used.
#
# With this setup, tests can be executed against an IPA client, against
# an IPA server using "client" context, and ensure that tests are executed
# in upstream CI.
- name: Test passkeyconfig using client context, in client host.
import_playbook: test_passkeyconfig.yml
when: groups['ipaclients'] and passkey_is_supported
vars:
ipa_test_host: ipaclients
- name: Test passkeyconfig using client context, in server host.
import_playbook: test_passkeyconfig.yml
when: passkey_is_supported and (groups['ipaclients'] is not defined or not groups['ipaclients'])

View File

@@ -5,6 +5,8 @@
gather_facts: yes
tasks:
- name: Include tasks ../env_freeipa_facts.yml
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
# CLEANUP TEST ITEMS
@@ -83,6 +85,37 @@
register: result
failed_when: result.changed or result.failed
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with auth_ind passkey
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
auth_ind:
- passkey
register: result
failed_when: not result.changed or result.failed
when: passkey_is_supported
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with auth_ind passkey, again
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
auth_ind:
- passkey
register: result
failed_when: result.changed or result.failed
when: passkey_is_supported
- name: Check if correct message is given if passkey is not supported.
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "test-service/{{ ansible_facts['fqdn'] }}"
auth_ind:
- passkey
register: result
failed_when: not result.failed or "'passkey' is not supported" not in result.msg
when: not passkey_is_supported
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty auth_ind
ipaservice:
ipaadmin_password: SomeADMINpassword

View File

@@ -5,6 +5,9 @@
gather_facts: false
tasks:
- name: Include FreeIPA facts.
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
- name: Remove test users
ipauser:
ipaadmin_password: SomeADMINpassword
@@ -392,6 +395,42 @@
register: result
failed_when: not result.changed or result.failed
- name: Ensure user pinky with userauthtype passkey exists
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: pinky
first: pinky
last: user
userauthtype: passkey
register: result
failed_when: not result.changed or result.failed
when: passkey_is_supported
- name: Ensure user pinky with userauthtype passkey exists, again
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: pinky
first: pinky
last: user
userauthtype: passkey
register: result
failed_when: result.changed or result.failed
when: passkey_is_supported
- name: Check if correct message is given if passkey is not supported.
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: pinky
first: pinky
last: user
userauthtype: passkey
register: result
when: not passkey_is_supported
failed_when: not result.failed or "'passkey' is not supported" not in result.msg
- name: User pinky absent and preserved for future exclusion.
ipauser:
ipaadmin_password: SomeADMINpassword