- RHEL-147191 ipa uninstallation is failing with message "'NoneType' object has no attribute 'lower'" - RHEL-146185 Names of domains from a trusted forest should be compared case-insentive - RHEL-146184 ipa-advise client script requires keytab (should just require root access on client system) - RHEL-145854 Include latest fixes in python3-ipatests package - RHEL-143684 When using xmlrpc, ipa server failed with assert type(value) in (unicode, float, int, bool, type(None)) - RHEL-141500 ipa use systemd-sysusers Note that there is a slight modification of the patch for systemd-sysusers. Instead of definining kdcproxy and ipaapi with u! the patch uses u (because u! requires systemd version 257). Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
761 lines
30 KiB
Diff
761 lines
30 KiB
Diff
From 7cb2c5d38a84eb31aa9ddd20cf9dc0b6d90fa242 Mon Sep 17 00:00:00 2001
|
|
From: PRANAV THUBE <pthube@redhat.com>
|
|
Date: Tue, 27 Jan 2026 18:45:53 +0530
|
|
Subject: [PATCH] ipatests: Add integration tests for ipa-join command
|
|
|
|
Add tests for ipa-join command covering hostname, server, keytab,
|
|
and bindpw options with positive and negative scenarios.
|
|
|
|
Related: https://pagure.io/freeipa/issue/9930
|
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
---
|
|
ipatests/prci_definitions/gating.yaml | 12 +
|
|
.../nightly_ipa-4-13_latest.yaml | 12 +
|
|
.../nightly_ipa-4-13_latest_selinux.yaml | 13 +
|
|
ipatests/pytest_ipa/integration/tasks.py | 49 ++
|
|
ipatests/test_integration/test_ipa_join.py | 614 ++++++++++++++++++
|
|
5 files changed, 700 insertions(+)
|
|
create mode 100644 ipatests/test_integration/test_ipa_join.py
|
|
|
|
diff --git a/ipatests/prci_definitions/gating.yaml b/ipatests/prci_definitions/gating.yaml
|
|
index 0c2a0dafa9de12add8959d9974f080ba8bec0706..182f2c5a097856d22336fa66a0876bdfcf3f3f8d 100644
|
|
--- a/ipatests/prci_definitions/gating.yaml
|
|
+++ b/ipatests/prci_definitions/gating.yaml
|
|
@@ -394,3 +394,15 @@ jobs:
|
|
template: *ci-ipa-4-13-latest
|
|
timeout: 7200
|
|
topology: *master_3client
|
|
+
|
|
+ fedora-latest-ipa-4-13/test_ipa_join:
|
|
+ requires: [fedora-latest-ipa-4-13/build]
|
|
+ priority: 100
|
|
+ job:
|
|
+ class: RunPytest
|
|
+ args:
|
|
+ build_url: '{fedora-latest-ipa-4-13/build_url}'
|
|
+ test_suite: test_integration/test_ipa_join.py
|
|
+ template: *ci-ipa-4-13-latest
|
|
+ timeout: 3600
|
|
+ topology: *master_1repl_1client
|
|
diff --git a/ipatests/prci_definitions/nightly_ipa-4-13_latest.yaml b/ipatests/prci_definitions/nightly_ipa-4-13_latest.yaml
|
|
index c61701ef5f88760f1d6fc36d4acce453a22b6f8f..aba33a5a05185460305c7516c93ae25c60f9dda7 100644
|
|
--- a/ipatests/prci_definitions/nightly_ipa-4-13_latest.yaml
|
|
+++ b/ipatests/prci_definitions/nightly_ipa-4-13_latest.yaml
|
|
@@ -2292,3 +2292,15 @@ jobs:
|
|
template: *ci-ipa-4-13-latest
|
|
timeout: 2400
|
|
topology: *ipaserver
|
|
+
|
|
+ fedora-latest-ipa-4-13/test_ipa_join:
|
|
+ requires: [fedora-latest-ipa-4-13/build]
|
|
+ priority: 50
|
|
+ job:
|
|
+ class: RunPytest
|
|
+ args:
|
|
+ build_url: '{fedora-latest-ipa-4-13/build_url}'
|
|
+ test_suite: test_integration/test_ipa_join.py
|
|
+ template: *ci-ipa-4-13-latest
|
|
+ timeout: 3600
|
|
+ topology: *master_1repl_1client
|
|
diff --git a/ipatests/prci_definitions/nightly_ipa-4-13_latest_selinux.yaml b/ipatests/prci_definitions/nightly_ipa-4-13_latest_selinux.yaml
|
|
index 9b96f3e857e2125478b45632d8d58e42b6e92668..7184b722076ba2cab7d782d990a9bc218158a09f 100644
|
|
--- a/ipatests/prci_definitions/nightly_ipa-4-13_latest_selinux.yaml
|
|
+++ b/ipatests/prci_definitions/nightly_ipa-4-13_latest_selinux.yaml
|
|
@@ -2476,3 +2476,16 @@ jobs:
|
|
template: *ci-ipa-4-13-latest
|
|
timeout: 2400
|
|
topology: *ipaserver
|
|
+
|
|
+ fedora-latest-ipa-4-13/test_ipa_join:
|
|
+ requires: [fedora-latest-ipa-4-13/build]
|
|
+ priority: 50
|
|
+ job:
|
|
+ class: RunPytest
|
|
+ args:
|
|
+ build_url: '{fedora-latest-ipa-4-13/build_url}'
|
|
+ selinux_enforcing: True
|
|
+ test_suite: test_integration/test_ipa_join.py
|
|
+ template: *ci-ipa-4-13-latest
|
|
+ timeout: 3600
|
|
+ topology: *master_1repl_1client
|
|
diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py
|
|
index ff2ea9792d04ebd2e6bd7bb3b51d97f35cb3fbfb..47330d6d93401485e4eb7b2501cf5ea37498d719 100755
|
|
--- a/ipatests/pytest_ipa/integration/tasks.py
|
|
+++ b/ipatests/pytest_ipa/integration/tasks.py
|
|
@@ -3355,3 +3355,52 @@ def host_add_with_random_password(host, new_host):
|
|
re.MULTILINE)
|
|
randpasswd1 = result.group('password')
|
|
return randpasswd1
|
|
+
|
|
+
|
|
+def ipa_join(host, *extra_args, raiseonerr=True):
|
|
+ """Run ipa-join command.
|
|
+
|
|
+ :param host: The host to run command on
|
|
+ :param extra_args: Additional arguments (variable positional args)
|
|
+ e.g., '--hostname=client.example.com',
|
|
+ '--server=master.example.com',
|
|
+ '--keytab=/tmp/test.keytab',
|
|
+ '--bindpw=password',
|
|
+ '-u' (for unenroll)
|
|
+ :param raiseonerr: If True, raise exception on command failure
|
|
+ :return: Command result object
|
|
+ """
|
|
+ command = ['ipa-join']
|
|
+ command.extend(extra_args)
|
|
+ return host.run_command(command, raiseonerr=raiseonerr)
|
|
+
|
|
+
|
|
+def host_del(host, hostname, *extra_args, raiseonerr=True):
|
|
+ """Delete a host from IPA.
|
|
+
|
|
+ :param host: The IPA host to run command on
|
|
+ :param hostname: Hostname to delete
|
|
+ :param extra_args: Additional arguments (variable positional args)
|
|
+ :param raiseonerr: If True, raise exception on command failure
|
|
+ :return: Command result object
|
|
+ """
|
|
+ command = ['ipa', 'host-del', hostname]
|
|
+ command.extend(extra_args)
|
|
+ return host.run_command(command, raiseonerr=raiseonerr)
|
|
+
|
|
+
|
|
+def host_add(host, hostname, *extra_args, password=None, raiseonerr=True):
|
|
+ """Add a host to IPA.
|
|
+
|
|
+ :param host: The IPA host to run command on
|
|
+ :param hostname: Hostname to add
|
|
+ :param extra_args: Additional arguments (variable positional args)
|
|
+ :param password: OTP/enrollment password for the host (optional)
|
|
+ :param raiseonerr: If True, raise exception on command failure
|
|
+ :return: Command result object
|
|
+ """
|
|
+ command = ['ipa', 'host-add', hostname]
|
|
+ if password:
|
|
+ command.append(f'--password={password}')
|
|
+ command.extend(extra_args)
|
|
+ return host.run_command(command, raiseonerr=raiseonerr)
|
|
diff --git a/ipatests/test_integration/test_ipa_join.py b/ipatests/test_integration/test_ipa_join.py
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1f7592aec8db1bfd048ec574d06d25bc24373499
|
|
--- /dev/null
|
|
+++ b/ipatests/test_integration/test_ipa_join.py
|
|
@@ -0,0 +1,614 @@
|
|
+#
|
|
+# Copyright (C) 2026 FreeIPA Contributors see COPYING for license
|
|
+#
|
|
+
|
|
+"""
|
|
+Tests for ipa-join command functionality.
|
|
+
|
|
+This module tests various combinations of ipa-join options including:
|
|
+- hostname
|
|
+- server
|
|
+- keytab
|
|
+- bindpw (OTP/enrollment password)
|
|
+- unenroll
|
|
+
|
|
+Ported from the shell-based test suite (t.ipajoin.sh and t.ipaotp.sh).
|
|
+"""
|
|
+
|
|
+from __future__ import absolute_import
|
|
+
|
|
+from ipapython.ipautil import ipa_generate_password
|
|
+from ipatests.pytest_ipa.integration import tasks
|
|
+from ipatests.test_integration.base import IntegrationTest
|
|
+
|
|
+
|
|
+# Constants
|
|
+OTP = ipa_generate_password(special=None)
|
|
+INVALID_PASSWORD = "WrongPassword"
|
|
+INVALID_SERVER = "No.Such.IPA.Server.Domain.com"
|
|
+TEST_KEYTAB = "/tmp/ipajoin.test.keytab"
|
|
+
|
|
+# Error messages
|
|
+ERR_SASL_BIND_FAILED = "SASL Bind failed"
|
|
+ERR_UNAUTHENTICATED_BIND = "Unauthenticated binds are not allowed"
|
|
+ERR_COULD_NOT_RESOLVE = "JSON-RPC call failed: Could not resolve hostname"
|
|
+ERR_UNABLE_ROOT_DN = "Unable to determine root DN"
|
|
+ERR_NO_CONFIG = "Unable to determine IPA server from /etc/ipa/default.conf"
|
|
+ERR_PREAUTH_FAILED = "Generic preauthentication failure"
|
|
+
|
|
+# Exit codes
|
|
+EXIT_SUCCESS = 0
|
|
+EXIT_GENERAL_ERROR = 1
|
|
+EXIT_PREAUTH_ERROR = 19
|
|
+EXIT_ROOT_DN_ERROR = 14
|
|
+EXIT_SASL_BIND_FAILED = 15
|
|
+EXIT_RESOLVE_ERROR = 17
|
|
+
|
|
+
|
|
+class TestIPAJoin(IntegrationTest):
|
|
+ """Tests for ipa-join command functionality.
|
|
+
|
|
+ This test class covers various ipa-join scenarios including:
|
|
+ - Basic enrollment and unenrollment
|
|
+ - Using hostname, server, keytab, and bindpw options
|
|
+ - Positive and negative test cases
|
|
+ - OTP (one-time password) enrollment tests
|
|
+
|
|
+ Tests require one master and one client.
|
|
+ """
|
|
+
|
|
+ topology = 'line'
|
|
+ num_clients = 1
|
|
+
|
|
+ @classmethod
|
|
+ def install(cls, mh):
|
|
+ tasks.install_master(cls.master, setup_dns=True)
|
|
+ tasks.install_client(cls.master, cls.clients[0])
|
|
+
|
|
+ @classmethod
|
|
+ def uninstall(cls, mh):
|
|
+ # Cleanup test keytab if exists
|
|
+ cls.clients[0].run_command(
|
|
+ ['rm', '-f', TEST_KEYTAB],
|
|
+ raiseonerr=False
|
|
+ )
|
|
+ tasks.uninstall_client(cls.clients[0])
|
|
+ tasks.uninstall_master(cls.master)
|
|
+
|
|
+ # =========================================================================
|
|
+ # ipa-join basic tests
|
|
+ # =========================================================================
|
|
+
|
|
+ def test_unenroll(self):
|
|
+ """Test ipa-join --unenroll option."""
|
|
+ result = tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+
|
|
+ def test_unenroll_already_unenrolled(self):
|
|
+ """Test ipa-join -u on an already unenrolled client.
|
|
+
|
|
+ When trying to unenroll a client that is not enrolled,
|
|
+ ipa-join should fail with a preauthentication error.
|
|
+ """
|
|
+ # Client is already unenrolled from previous test
|
|
+ result = tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ assert result.returncode == EXIT_PREAUTH_ERROR
|
|
+ assert ERR_PREAUTH_FAILED in result.stderr_text
|
|
+
|
|
+ def test_hostname_with_kerberos(self):
|
|
+ """Test ipa-join with --hostname using Kerberos auth."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_hostname_bindpw_invalid(self):
|
|
+ """Test ipa-join with hostname and invalid bindpw."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--bindpw={INVALID_PASSWORD}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ assert ERR_SASL_BIND_FAILED in result.stderr_text
|
|
+
|
|
+ def test_hostname_bindpw_valid(self):
|
|
+ """Test ipa-join with hostname and valid OTP."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--bindpw={OTP}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_hostname_keytab_with_kerberos(self):
|
|
+ """Test ipa-join with hostname and keytab using Kerberos."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--keytab={TEST_KEYTAB}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_hostname_keytab_bindpw_invalid(self):
|
|
+ """Test ipa-join with hostname, keytab, and invalid bindpw."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ f'--bindpw={INVALID_PASSWORD}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ assert ERR_SASL_BIND_FAILED in result.stderr_text
|
|
+
|
|
+ def test_hostname_keytab_bindpw_valid(self):
|
|
+ """Test ipa-join with hostname, keytab, and valid OTP."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ f'--bindpw={OTP}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_hostname_server_invalid_with_kerberos(self):
|
|
+ """Test ipa-join with hostname and invalid server."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={INVALID_SERVER}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_RESOLVE_ERROR
|
|
+ assert ERR_COULD_NOT_RESOLVE in result.stderr_text
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+
|
|
+ def test_hostname_server_invalid_bindpw_valid(self):
|
|
+ """Test ipa-join with hostname, invalid server, and valid OTP."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={INVALID_SERVER}',
|
|
+ f'--bindpw={OTP}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_ROOT_DN_ERROR
|
|
+ assert ERR_UNABLE_ROOT_DN in result.stderr_text
|
|
+
|
|
+ def test_hostname_server_invalid_keytab_with_kerberos(self):
|
|
+ """Test ipa-join with hostname, invalid server, keytab."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={INVALID_SERVER}',
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_RESOLVE_ERROR
|
|
+ assert ERR_COULD_NOT_RESOLVE in result.stderr_text
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+
|
|
+ def test_hostname_server_invalid_keytab_bindpw_valid(self):
|
|
+ """Test ipa-join with hostname, invalid server, keytab, valid OTP."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={INVALID_SERVER}',
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ f'--bindpw={OTP}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_ROOT_DN_ERROR
|
|
+ assert ERR_UNABLE_ROOT_DN in result.stderr_text
|
|
+
|
|
+ def test_hostname_server_valid_with_kerberos(self):
|
|
+ """Test ipa-join with hostname and valid server."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={self.master.hostname}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_hostname_server_valid_bindpw_invalid(self):
|
|
+ """Test ipa-join with hostname, valid server, invalid bindpw."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={self.master.hostname}',
|
|
+ f'--bindpw={INVALID_PASSWORD}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ assert ERR_SASL_BIND_FAILED in result.stderr_text
|
|
+
|
|
+ def test_hostname_server_valid_bindpw_valid(self):
|
|
+ """Test ipa-join with hostname, valid server, valid OTP."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={self.master.hostname}',
|
|
+ f'--bindpw={OTP}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_hostname_server_valid_keytab_with_kerberos(self):
|
|
+ """Test ipa-join with hostname, valid server, keytab."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname)
|
|
+
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={self.master.hostname}',
|
|
+ f'--keytab={TEST_KEYTAB}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_hostname_server_valid_keytab_bindpw_invalid(self):
|
|
+ """Test ipa-join with hostname, valid server, keytab, bad bindpw."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={self.master.hostname}',
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ f'--bindpw={INVALID_PASSWORD}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ # Note: Original test had "SASL Bind Failed" (capital F), checking both
|
|
+ assert "SASL Bind" in result.stderr_text
|
|
+ assert "ailed" in result.stderr_text
|
|
+
|
|
+ def test_hostname_server_valid_keytab_bindpw_valid(self):
|
|
+ """Test ipa-join with hostname, valid server, keytab, valid OTP."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--server={self.master.hostname}',
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ f'--bindpw={OTP}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_keytab_only_with_kerberos(self):
|
|
+ """Test ipa-join with keytab only using Kerberos."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname)
|
|
+
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--keytab={TEST_KEYTAB}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_keytab_bindpw_invalid(self):
|
|
+ """Test ipa-join with keytab and invalid bindpw."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ f'--bindpw={INVALID_PASSWORD}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ assert ERR_SASL_BIND_FAILED in result.stderr_text
|
|
+
|
|
+ def test_keytab_bindpw_valid(self):
|
|
+ """Test ipa-join with keytab and valid OTP."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ f'--bindpw={OTP}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_server_invalid_only_with_kerberos(self):
|
|
+ """Test ipa-join with invalid server only."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--server={INVALID_SERVER}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_RESOLVE_ERROR
|
|
+ assert ERR_COULD_NOT_RESOLVE in result.stderr_text
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+
|
|
+ def test_server_invalid_bindpw_valid(self):
|
|
+ """Test ipa-join with invalid server and valid OTP."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--server={INVALID_SERVER}',
|
|
+ f'--bindpw={OTP}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_ROOT_DN_ERROR
|
|
+ assert ERR_UNABLE_ROOT_DN in result.stderr_text
|
|
+
|
|
+ def test_server_invalid_keytab_with_kerberos(self):
|
|
+ """Test ipa-join with invalid server and keytab."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--server={INVALID_SERVER}',
|
|
+ f'--keytab={TEST_KEYTAB}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_RESOLVE_ERROR
|
|
+ assert ERR_COULD_NOT_RESOLVE in result.stderr_text
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+
|
|
+ def test_server_valid_only_with_kerberos(self):
|
|
+ """Test ipa-join with valid server only."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname)
|
|
+
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--server={self.master.hostname}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_server_valid_bindpw_invalid(self):
|
|
+ """Test ipa-join with valid server and invalid bindpw."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--server={self.master.hostname}',
|
|
+ f'--bindpw={INVALID_PASSWORD}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ assert ERR_SASL_BIND_FAILED in result.stderr_text
|
|
+
|
|
+ def test_server_valid_bindpw_valid(self):
|
|
+ """Test ipa-join with valid server and valid OTP."""
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--server={self.master.hostname}',
|
|
+ f'--bindpw={OTP}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_server_valid_keytab_with_kerberos(self):
|
|
+ """Test ipa-join with valid server and keytab."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname)
|
|
+
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--server={self.master.hostname}',
|
|
+ f'--keytab={TEST_KEYTAB}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_bindpw_invalid_only(self):
|
|
+ """Test ipa-join with invalid bindpw only."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--bindpw={INVALID_PASSWORD}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ assert ERR_SASL_BIND_FAILED in result.stderr_text
|
|
+
|
|
+ # =========================================================================
|
|
+ # OTP (One-Time Password) tests
|
|
+ # =========================================================================
|
|
+
|
|
+ def test_otp_empty_password(self):
|
|
+ """Test ipa-join with empty OTP password (ipa_otp_1001)."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ '--bindpw=',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_ROOT_DN_ERROR
|
|
+ assert ERR_UNAUTHENTICATED_BIND in result.stderr_text
|
|
+
|
|
+ def test_otp_wrong_password(self):
|
|
+ """Test ipa-join with wrong OTP password (ipa_otp_1002)."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--bindpw={INVALID_PASSWORD}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ assert ERR_SASL_BIND_FAILED in result.stderr_text
|
|
+
|
|
+ def test_otp_valid_password(self):
|
|
+ """Test ipa-join with valid OTP password (ipa_otp_1003)."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+ try:
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--bindpw={OTP}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ def test_otp_reuse_fails(self):
|
|
+ """Test that reusing the same OTP fails (ipa_otp_1004)."""
|
|
+ tasks.kinit_admin(self.clients[0])
|
|
+ tasks.kinit_admin(self.master)
|
|
+ tasks.host_del(self.master, self.clients[0].hostname, raiseonerr=False)
|
|
+ tasks.host_add(self.master, self.clients[0].hostname, password=OTP)
|
|
+ try:
|
|
+ # First use should succeed
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--bindpw={OTP}'
|
|
+ )
|
|
+ assert result.returncode == EXIT_SUCCESS
|
|
+ finally:
|
|
+ self.clients[0].run_command(['kdestroy', '-A'], raiseonerr=False)
|
|
+ tasks.ipa_join(self.clients[0], '-u', raiseonerr=False)
|
|
+
|
|
+ # Second use of same OTP should fail
|
|
+ result = tasks.ipa_join(
|
|
+ self.clients[0],
|
|
+ f'--hostname={self.clients[0].hostname}',
|
|
+ f'--bindpw={OTP}',
|
|
+ raiseonerr=False
|
|
+ )
|
|
+
|
|
+ assert result.returncode == EXIT_SASL_BIND_FAILED
|
|
+ assert ERR_SASL_BIND_FAILED in result.stderr_text
|
|
--
|
|
2.52.0
|
|
|