Hi,

I'm sending the tests for kerberos principal aliases rfe. The tests are implemented according to test plan [1] sent earlier. Some of the patches implement modifications and extensions to previous code to allow implement the tests themselves.

The patches can be cloned also from github [2].

[1]: http://www.freeipa.org/page/V4/Kerberos_principal_aliases/Test_Plan
[2]: https://github.com/apophys/freeipa/tree/krb5-principal-aliases-test

Cheers,

--
Milan Kubik

From e4fdd561af48beb02748e9cb14ffcb4e5f257128 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Fri, 22 Jul 2016 17:07:56 +0200
Subject: [PATCH 1/6] ipatests: Add tracker class for kerberos principal
 aliases

The commit implements a mixin class providing capability
to track and modify kerberos principal aliases on supported
types of entries.

The class using the mixin must inherit from the Tracker class
and must provide the implementation of two methods:

* _make_add_alias_cmd
* _make_remove_alias_cmd

These are used to get the type specific command for the particular
entry class. The methods provided will not work on entries that
do not have 'krbprincipalname' attribute.

The service, host and user trackers are being extended to use this
new mixin class.

https://fedorahosted.org/freeipa/ticket/3864
---
 ipatests/test_xmlrpc/tracker/host_plugin.py      |  10 ++-
 ipatests/test_xmlrpc/tracker/kerberos_aliases.py | 110 +++++++++++++++++++++++
 ipatests/test_xmlrpc/tracker/service_plugin.py   |  17 +++-
 ipatests/test_xmlrpc/tracker/user_plugin.py      |  10 ++-
 4 files changed, 141 insertions(+), 6 deletions(-)
 create mode 100644 ipatests/test_xmlrpc/tracker/kerberos_aliases.py

diff --git a/ipatests/test_xmlrpc/tracker/host_plugin.py b/ipatests/test_xmlrpc/tracker/host_plugin.py
index 03113b8fe7de7bfa2d2383b1903ff05d2543a9ed..8630a7d0c96edd725f448f5a460df91dd8f37ccc 100644
--- a/ipatests/test_xmlrpc/tracker/host_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/host_plugin.py
@@ -7,13 +7,14 @@ from __future__ import print_function
 
 from ipapython.dn import DN
 from ipatests.test_xmlrpc.tracker.base import Tracker
+from ipatests.test_xmlrpc.tracker.kerberos_aliases import KerberosAliasMixin
 from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_uuid
 from ipatests.test_xmlrpc import objectclasses
 from ipatests.util import assert_deepequal
 from ipalib import errors
 
 
-class HostTracker(Tracker):
+class HostTracker(Tracker, KerberosAliasMixin):
     """Wraps and tracks modifications to a Host object
 
     Implements the helper functions for host plugin.
@@ -175,3 +176,10 @@ class HostTracker(Tracker):
                 pass
 
         request.addfinalizer(cleanup)
+
+    #  Kerberos aliases methods
+    def _make_add_alias_cmd(self):
+        return self.make_command('host_add_principal', self.name)
+
+    def _make_remove_alias_cmd(self):
+        return self.make_command('host_remove_principal', self.name)
diff --git a/ipatests/test_xmlrpc/tracker/kerberos_aliases.py b/ipatests/test_xmlrpc/tracker/kerberos_aliases.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf82a7a8ce27506fd0cdbff6d297ffa5c5b6e4b9
--- /dev/null
+++ b/ipatests/test_xmlrpc/tracker/kerberos_aliases.py
@@ -0,0 +1,110 @@
+#
+# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
+#
+"""kerberos_aliases
+
+The module implements a mixin class that provides an interface
+to the Kerberos Aliases feature of freeIPA.
+
+In order to use the class the child class must implement the
+`_make_add_alias_cmd` and `_make_remove_alias_cmd` methods that
+are different for each entity type.
+
+The KerberosAliasMixin class then provides the implementation
+of the manipulation of the kerberos alias in general.
+
+It is up to the child class or the user to validate the
+alias being added for a particular type of an entry.
+"""
+
+from ipatests.test_xmlrpc.tracker.base import Tracker
+
+
+class KerberosAliasError(Exception):
+    pass
+
+
+class KerberosAliasMixin:
+    """KerberosAliasMixin"""
+
+    def _make_add_alias_cmd(self):
+        raise RuntimeError("The _make_add_alias_cmd method "
+                           "is not implemented.")
+
+    def _make_remove_alias_cmd(self):
+        raise RuntimeError("The _make_remove_alias_cmd method "
+                           "is not implemented.")
+
+    def _check_for_tracker(self):
+        if not isinstance(self, Tracker):
+            raise KerberosAliasError("Class using {} must inherit from {}."
+                                     .format(KerberosAliasMixin, Tracker))
+
+    def _check_for_krbprincipalname_attr(self):
+        # Check if the tracker has a principal name
+        # Each compatible entry has at least one kerberos
+        # principal matching the canonical principal name
+        principals = self.attrs.get('krbprincipalname')
+        if self.exists:
+            if not principals:
+                raise KerberosAliasError(
+                    "{} doesn't have krbprincipalname attribute"
+                    .format(self.__class__.__name__))
+        else:
+            raise ValueError("The entry {} doesn't seem to exist"
+                             .format(self.name))
+
+    def _normalize_principal_list(self, principal_list):
+        """Normalize the list for further manipulation."""
+        if not isinstance(principal_list, (list, tuple)):
+            return [principal_list]
+        else:
+            return principal_list
+
+    def _normalize_principal_value(self, principal):
+        """Normalize principal value by appending the realm string."""
+        return u'@'.join((principal, self.api.env.realm))
+
+    def add_principal(self, principal_list, options=None):
+        """Add kerberos principal alias to the entity.
+
+        Add principal alias to the underlying entry and
+        update the attributes in the Tracker instance.
+        """
+        options = options or {}
+        self._check_for_tracker()
+        self._check_for_krbprincipalname_attr()
+
+        principal_list = self._normalize_principal_list(principal_list)
+
+        cmd = self._make_add_alias_cmd()
+        cmd(principal_list, **options)
+
+        tracker_principals = self.attrs.get('krbprincipalname')
+        tracker_principals.extend((
+            self._normalize_principal_value(item) for item in principal_list))
+
+    def remove_principal(self, principal_list, options=None):
+        """Remove kerberos principal alias from an entry.
+
+        Remove principal alias from the tracked entry.
+        """
+        options = options or {}
+        self._check_for_tracker()
+        self._check_for_krbprincipalname_attr()
+
+        principal_list = self._normalize_principal_list(principal_list)
+
+        cmd = self._make_remove_alias_cmd()
+        cmd(principal_list, **options)
+
+        # Make a copy of the list so the tracker instance is not modified
+        # if there is an error deleting the aliases
+        # This can happen when deleting multiple aliases and at least
+        # one of them doesn't exist, raising ValueError
+        tracker_principals = self.attrs.get('krbprincipalname')[:]
+
+        for item in principal_list:
+            tracker_principals.remove(self._normalize_principal_value(item))
+
+        self.attrs['krbprincipalname'] = tracker_principals
diff --git a/ipatests/test_xmlrpc/tracker/service_plugin.py b/ipatests/test_xmlrpc/tracker/service_plugin.py
index 89c27e82161b70a77ac4e45ffd8b60d3da657163..9e9b88b196f54cd56dd54feec50c4e722de845bb 100644
--- a/ipatests/test_xmlrpc/tracker/service_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/service_plugin.py
@@ -7,6 +7,7 @@ import six
 
 from ipalib import api
 from ipatests.test_xmlrpc.tracker.base import Tracker
+from ipatests.test_xmlrpc.tracker.kerberos_aliases import KerberosAliasMixin
 from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_uuid
 from ipatests.test_xmlrpc import objectclasses
 from ipatests.util import assert_deepequal
@@ -16,7 +17,7 @@ if six.PY3:
     unicode = str
 
 
-class ServiceTracker(Tracker):
+class ServiceTracker(Tracker, KerberosAliasMixin):
     """
     Tracker class for service plugin
 
@@ -49,14 +50,14 @@ class ServiceTracker(Tracker):
         u'usercertificate', u'has_keytab'}
     update_keys = retrieve_keys - {u'dn'}
 
-    def __init__(self, name, host_fqdn, options):
+    def __init__(self, name, host_fqdn, options=None):
         super(ServiceTracker, self).__init__(default_version=None)
         self._name = "{0}/{1}@{2}".format(name, host_fqdn, api.env.realm)
         self.dn = DN(
             ('krbprincipalname', self.name), api.env.container_service,
             api.env.basedn)
         self.host_fqdn = host_fqdn
-        self.options = options
+        self.options = options or {}
 
     @property
     def name(self):
@@ -92,7 +93,8 @@ class ServiceTracker(Tracker):
             u'objectclass': objectclasses.service,
             u'ipauniqueid': [fuzzy_uuid],
             u'managedby_host': [self.host_fqdn],
-            u'krbcanonicalname': [u'{0}'.format(self.name)]
+            u'krbcanonicalname': [u'{0}'.format(self.name)],
+            u'has_keytab': False
         }
 
         for key in self.options:
@@ -150,3 +152,10 @@ class ServiceTracker(Tracker):
             u'summary': u'Modified service "{0}"'.format(self.name),
             u'result': self.filter_attrs(self.update_keys | set(extra_keys))
             }, result)
+
+    #  Kerberos aliases methods
+    def _make_add_alias_cmd(self):
+        return self.make_command('service_add_principal', self.name)
+
+    def _make_remove_alias_cmd(self):
+        return self.make_command('service_remove_principal', self.name)
diff --git a/ipatests/test_xmlrpc/tracker/user_plugin.py b/ipatests/test_xmlrpc/tracker/user_plugin.py
index d95c3e223106451b4114ace4ddf564085e6a0511..da78615c98a7ad117d64fa3452b792f4da71d083 100644
--- a/ipatests/test_xmlrpc/tracker/user_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/user_plugin.py
@@ -12,12 +12,13 @@ from ipatests.test_xmlrpc import objectclasses
 from ipatests.test_xmlrpc.xmlrpc_test import (
     fuzzy_digits, fuzzy_uuid, raises_exact)
 from ipatests.test_xmlrpc.tracker.base import Tracker
+from ipatests.test_xmlrpc.tracker.kerberos_aliases import KerberosAliasMixin
 
 if six.PY3:
     unicode = str
 
 
-class UserTracker(Tracker):
+class UserTracker(Tracker, KerberosAliasMixin):
     """ Class for host plugin like tests """
 
     retrieve_keys = {
@@ -492,3 +493,10 @@ class UserTracker(Tracker):
                 'description': [u'Account administrators group'],
             },
         ), result)
+
+    #  Kerberos aliases methods
+    def _make_add_alias_cmd(self):
+        return self.make_command('user_add_principal', self.name)
+
+    def _make_remove_alias_cmd(self):
+        return self.make_command('user_remove_principal', self.name)
-- 
2.9.0

From 3da974baf19a4d01b16f5d4137cd856a5dbaa061 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Fri, 22 Jul 2016 17:16:25 +0200
Subject: [PATCH 2/6] ipatests: Extend the MockLDAP utility class

Added mod_entry method to allow modifying existing entries via the
ldap connection.

The commit also implements the context manager protocol for the class.

https://fedorahosted.org/freeipa/ticket/3864
---
 ipatests/util.py | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/ipatests/util.py b/ipatests/util.py
index 118c47a12e0d97907cb559d716989a9ca6c5f304..7e12a9d86b2f44e6ade96d602a2dcac8aa018c7f 100644
--- a/ipatests/util.py
+++ b/ipatests/util.py
@@ -652,6 +652,9 @@ class MockLDAP(object):
         except ldap.ALREADY_EXISTS:
             pass
 
+    def mod_entry(self, dn, mods):
+        self.connection.modify_s(dn, mods)
+
     def del_entry(self, dn):
         try:
             self.connection.delete_s(dn)
@@ -662,6 +665,13 @@ class MockLDAP(object):
         if self.connection is not None:
             self.connection.unbind_s()
 
+    # contextmanager protocol
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self.unbind()
+
 
 def prepare_config(template, values):
     with open(template) as f:
-- 
2.9.0

From f343752026f297fb783243f412a26ad99c562f58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Fri, 22 Jul 2016 17:19:31 +0200
Subject: [PATCH 3/6] ipatests: Provide a context manager for mocking a trust
 in RPC tests

The new module contains utility functions and a context manager to
make the mocking of an existing AD trust relation in the XMLRPC tests.

The module provides with two functions that create and delete the
containers for trusts and cifs domains. A context manager using these
is provided as well.

The user of the context manager is responsible for deleting all the
LDAP entries created during the test within the context. If there are
some entries left at the time of exiting the context manager, making
the container entries non-leaf entries, the tests will fail.

The context manager will not work when used on a server that already
has trust established.

https://fedorahosted.org/freeipa/ticket/3864
---
 ipatests/test_xmlrpc/utils.py | 52 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 ipatests/test_xmlrpc/utils.py

diff --git a/ipatests/test_xmlrpc/utils.py b/ipatests/test_xmlrpc/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..8313db62e59eb1a62e2647169488bf4559148e9f
--- /dev/null
+++ b/ipatests/test_xmlrpc/utils.py
@@ -0,0 +1,52 @@
+# coding: utf-8
+#
+# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
+#
+from contextlib import contextmanager
+
+from ipalib import api
+from ipatests.util import MockLDAP
+
+trust_container_dn = "cn=ad,cn=trusts,{basedn}".format(
+    basedn=api.env.basedn)
+trust_container_add = dict(
+    objectClass=[b"nsContainer", b"top"]
+    )
+
+smb_cont_dn = "{cifsdomains},{basedn}".format(
+    cifsdomains=api.env.container_cifsdomains,
+    basedn=api.env.basedn)
+smb_cont_add = dict(
+    objectClass=[b"nsContainer", b"top"]
+    )
+
+
+def create_mock_trust_containers():
+    with MockLDAP() as ldap:
+        ldap.add_entry(trust_container_dn, trust_container_add)
+        ldap.add_entry(smb_cont_dn, smb_cont_add)
+
+
+def remove_mock_trust_containers():
+    with MockLDAP() as ldap:
+        ldap.del_entry(trust_container_dn)
+        ldap.del_entry(smb_cont_dn)
+
+
+@contextmanager
+def mocked_trust_containers():
+    """Mocked trust containers
+
+    Provides containers for the RPC tests:
+    cn=ad,cn=trusts,BASEDN
+    cn=ad,cn=etc,BASEDN
+
+    Upon exiting, it tries to remove the container entries.
+    If the user of the context manager failed to remove
+    all child entries, exiting the context manager will fail.
+    """
+    create_mock_trust_containers()
+    try:
+        yield
+    finally:
+        remove_mock_trust_containers()
-- 
2.9.0

From e9ab321b08cb79be1f0c1bbf904e83702275df07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Mon, 25 Jul 2016 13:20:54 +0200
Subject: [PATCH 4/6] ipapython: Extend kinit_password to support principal
 canonicalization

In order to authenticate with a principal alias it is necessary
to request canonicalization of the principal. This patch extends
the kinit_password with this option.

https://fedorahosted.org/freeipa/ticket/3864
---
 ipapython/ipautil.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 9964fba4f694b57242b3bd3065a418917d977533..22d58eb0a6a57f304ce7660609be7e824420c0cb 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -1328,7 +1328,7 @@ def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
 
 
 def kinit_password(principal, password, ccache_name, config=None,
-                   armor_ccache_name=None):
+                   armor_ccache_name=None, canonicalize=False):
     """
     perform interactive kinit as principal using password. If using FAST for
     web-based authentication, use armor_ccache_path to specify http service
@@ -1341,6 +1341,10 @@ def kinit_password(principal, password, ccache_name, config=None,
                           % armor_ccache_name)
         args.extend(['-T', armor_ccache_name])
 
+    if canonicalize:
+        root_logger.debug("Requesting principal canonicalization")
+        args.append('-C')
+
     env = {'LC_ALL': 'C'}
     if config is not None:
         env['KRB5_CONFIG'] = config
-- 
2.9.0

From 0bfc24d325e4d658dbf2183620c00b9ab9a1cc21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Mon, 25 Jul 2016 13:24:51 +0200
Subject: [PATCH 5/6] ipatests: Allow change_principal context manager to use
 canonicalization

The context manager has been extended to optionally request principal
canonicalization. This allows to change the user during the test
to an user using the alias.

https://fedorahosted.org/freeipa/ticket/3864
---
 ipatests/util.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/ipatests/util.py b/ipatests/util.py
index 7e12a9d86b2f44e6ade96d602a2dcac8aa018c7f..82e78b7065ef9ef03e89da6cb88932210c591f40 100644
--- a/ipatests/util.py
+++ b/ipatests/util.py
@@ -693,7 +693,8 @@ def unlock_principal_password(user, oldpw, newpw):
 
 
 @contextmanager
-def change_principal(user, password, client=None, path=None):
+def change_principal(user, password, client=None, path=None,
+                     canonicalize=False):
 
     if path:
         ccache_name = path
@@ -708,7 +709,8 @@ def change_principal(user, password, client=None, path=None):
 
     try:
         with private_ccache(ccache_name):
-            kinit_password(user, password, ccache_name)
+            kinit_password(user, password, ccache_name,
+                           canonicalize=canonicalize)
             client.Backend.rpcclient.connect()
 
             try:
-- 
2.9.0

From 11d39e5b2aae3fc08981d03272a4b610bf54a302 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Fri, 22 Jul 2016 17:25:06 +0200
Subject: [PATCH 6/6] ipatests: Add kerberos principal alias tests

Add tests for alias manipulation, tests authentication and several
error scenarios.

https://fedorahosted.org/freeipa/ticket/3864
https://fedorahosted.org/freeipa/ticket/5413
https://fedorahosted.org/freeipa/ticket/6099
---
 .../test_xmlrpc/test_kerberos_principal_aliases.py | 266 +++++++++++++++++++++
 1 file changed, 266 insertions(+)
 create mode 100644 ipatests/test_xmlrpc/test_kerberos_principal_aliases.py

diff --git a/ipatests/test_xmlrpc/test_kerberos_principal_aliases.py b/ipatests/test_xmlrpc/test_kerberos_principal_aliases.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f5da8c2a6f2ea6222c27708faf9611dc0886ce3
--- /dev/null
+++ b/ipatests/test_xmlrpc/test_kerberos_principal_aliases.py
@@ -0,0 +1,266 @@
+# coding: utf-8
+#
+# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
+#
+import ldap
+import pytest
+
+from ipalib import errors, api
+from ipapython import ipautil
+from ipaplatform.paths import paths
+
+from ipatests.util import MockLDAP
+from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test
+from ipatests.test_xmlrpc.tracker.user_plugin import UserTracker
+from ipatests.test_xmlrpc.tracker.host_plugin import HostTracker
+from ipatests.test_xmlrpc.tracker.service_plugin import ServiceTracker
+from ipatests.test_xmlrpc.test_range_plugin import (
+    get_trust_dn, get_trusted_dom_dict, encode_mockldap_value)
+from ipatests.test_xmlrpc.utils import mocked_trust_containers
+from ipatests.util import unlock_principal_password, change_principal
+
+
+@pytest.yield_fixture
+def ldapconn():
+    conn = MockLDAP()
+    yield conn
+    conn.unbind()
+
+
+@pytest.yield_fixture
+def trusted_domain():
+    """Fixture providing mocked AD trust entries
+
+    The fixture yields after creating a mock of AD trust
+    entries in the directory server. After the test, the entries
+    are deleted from the directory.
+    """
+    trusted_dom = u'trusted.domain.net'
+    trusted_dom_dn = get_trust_dn(trusted_dom)
+    trusted_dom_sid = u'S-1-5-21-2997650941-1802118864-3094776726'
+
+    trusted_dom_add = get_trusted_dom_dict(trusted_dom, trusted_dom_sid)
+
+    # Write the changes
+    with mocked_trust_containers(), MockLDAP() as ldap:
+        ldap.add_entry(trusted_dom_dn, trusted_dom_add)
+        yield trusted_dom
+        ldap.del_entry(trusted_dom_dn)
+
+
+@pytest.yield_fixture
+def trusted_domain_with_suffix():
+    """Fixture providing mocked AD trust entries
+
+    The fixture yields after creating a mock of AD trust
+    entries in the directory server. After the test, the entries
+    are deleted from the directory.
+    """
+    trusted_dom = u'trusted.domain.net'
+    trusted_dom_dn = get_trust_dn(trusted_dom)
+    trusted_dom_sid = u'S-1-5-21-2997650941-1802118864-3094776726'
+
+    trusted_dom_add = get_trusted_dom_dict(trusted_dom, trusted_dom_sid)
+    trusted_dom_add['ipaNTAdditionalSuffixes'] = (
+        encode_mockldap_value(trusted_dom))
+
+    # Write the changes
+    with mocked_trust_containers(),  MockLDAP() as ldap:
+        ldap.add_entry(trusted_dom_dn, trusted_dom_add)
+        yield trusted_dom
+        ldap.del_entry(trusted_dom_dn)
+
+
+@pytest.fixture(scope='function')
+def krbalias_user(request):
+    tracker = UserTracker(u'krbalias_user', u'krbalias', u'test')
+
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='function')
+def krbalias_user_c(request):
+    tracker = UserTracker(u'krbalias_user_conflict', u'krbalias', u'test')
+
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='function')
+def krbalias_host(request):
+    tracker = HostTracker(u'testhost-krb')
+
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture
+def krb_service_host(request):
+    tracker = HostTracker(u'krb-srv-host')
+
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='function')
+def krbalias_service(request, krb_service_host):
+    krb_service_host.ensure_exists()
+
+    tracker = ServiceTracker(name=u'SRV1', host_fqdn=krb_service_host.name)
+
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture
+def ldapservice(request):
+    tracker = ServiceTracker(
+        name=u'ldap', host_fqdn=api.env.host, options={'has_keytab': True})
+
+    tracker.track_create()
+    return tracker
+
+
+class TestKerberosAliasManipulation(XMLRPC_test):
+
+    def test_add_user_principal_alias(self, krbalias_user):
+        krbalias_user.ensure_exists()
+        krbalias_user.add_principal([u'test-user-alias'])
+        krbalias_user.retrieve()
+
+    def test_remove_user_principal_alias(self, krbalias_user):
+        krbalias_user.ensure_exists()
+        krbalias_user.add_principal([u'test-user-alias'])
+        krbalias_user.remove_principal(u'test-user-alias')
+        krbalias_user.retrieve()
+
+    def test_add_host_principal_alias(self, krbalias_host):
+        krbalias_host.ensure_exists()
+        krbalias_host.add_principal([u'testhost-krb-alias'])
+        krbalias_host.retrieve()
+
+    def test_remove_host_principal_alias(self, krbalias_host):
+        krbalias_host.ensure_exists()
+        krbalias_host.add_principal([u'testhost-krb-alias'])
+        krbalias_host.retrieve()
+        krbalias_host.remove_principal([u'testhost-krb-alias'])
+        krbalias_host.retrieve()
+
+    def test_add_service_principal_alias(self, krbalias_service):
+        krbalias_service.ensure_exists()
+        krbalias_service.add_principal(
+            [u'SRV2/{}'.format(krbalias_service.host_fqdn)])
+        krbalias_service.retrieve()
+
+    def test_remove_service_principal_alias(self, krbalias_service):
+        krbalias_service.ensure_exists()
+        krbalias_service.add_principal(
+            [u'SRV2/{}'.format(krbalias_service.host_fqdn)])
+        krbalias_service.retrieve()
+        krbalias_service.remove_principal(
+            [u'SRV2/{}'.format(krbalias_service.host_fqdn)])
+        krbalias_service.retrieve()
+
+    def test_adding_alias_adds_canonical_name(self, krbalias_user, ldapconn):
+        """Test adding alias on an entry without canonical name"""
+        krbalias_user.ensure_exists()
+
+        user_krb_principal = krbalias_user.attrs['krbprincipalname'][0]
+
+        # Delete all values of krbcanonicalname from an LDAP entry
+        dn = str(krbalias_user.dn)
+        modlist = [(ldap.MOD_DELETE, 'krbcanonicalname', None)]
+        ldapconn.mod_entry(dn, modlist)
+
+        # add new user principal alias
+        krbalias_user.add_principal(u'krbalias_principal_canonical')
+
+        # verify that the previous principal name is now krbcanonicalname
+        cmd = krbalias_user.make_retrieve_command()
+
+        new_canonical_name = cmd()['result']['krbcanonicalname'][0]
+        assert new_canonical_name == user_krb_principal
+
+    def test_authenticate_against_aliased_service(self, ldapservice):
+        alias = u'ldap/{newname}.{host}'.format(
+            newname='krbalias', host=api.env.host)
+        ldapservice.add_principal(alias)
+
+        rv = ipautil.run([paths.BIN_KVNO, alias],
+                         capture_error=True, raiseonerr=False)
+        ldapservice.remove_principal(alias)
+
+        assert rv.returncode == 0, rv.error_output
+
+    def test_authenticate_with_user_alias(self, krbalias_user):
+        krbalias_user.ensure_exists()
+
+        alias = u"{name}-alias".format(name=krbalias_user.name)
+
+        krbalias_user.add_principal(alias)
+
+        oldpw, newpw = u"Secret1234", u"Secret123"
+
+        pwdmod = krbalias_user.make_update_command({'userpassword': oldpw})
+        pwdmod()
+
+        unlock_principal_password(krbalias_user.name, oldpw, newpw)
+
+        with change_principal(alias, newpw, canonicalize=True):
+            api.Command.ping()
+
+
+class TestKerberosAliasExceptions(XMLRPC_test):
+
+    def test_add_user_coliding_with_alias(self, krbalias_user):
+        krbalias_user.ensure_exists()
+
+        user_alias = u'conflicting_name'
+        krbalias_user.add_principal([user_alias])
+
+        conflict_user = UserTracker(user_alias, u'test', u'conflict')
+
+        with pytest.raises(errors.DuplicateEntry):
+            conflict_user.create()
+
+    def test_add_alias_to_two_entries(self, krbalias_user, krbalias_user_c):
+        krbalias_user.ensure_exists()
+        krbalias_user_c.ensure_exists()
+
+        user_alias = u'krbalias-test'
+
+        krbalias_user.add_principal([user_alias])
+
+        with pytest.raises(errors.DuplicateEntry):
+            krbalias_user_c.add_principal([user_alias])
+
+    def test_remove_alias_matching_canonical_name(self, krbalias_user):
+        krbalias_user.ensure_exists()
+
+        with pytest.raises(errors.ValidationError):
+            krbalias_user.remove_principal(
+                krbalias_user.attrs.get('krbcanonicalname'))
+
+    def test_enterprise_principal_UPN_overlap_without_additional_suffix(
+            self, krbalias_user, trusted_domain):
+        krbalias_user.ensure_exists()
+
+        # Add an alias overlapping the UPN of a trusted domain
+        with pytest.raises(errors.ValidationError):
+            krbalias_user.add_principal(
+                u'{username}\@{trusted_domain}@{realm}'.format(
+                    username=krbalias_user.name,
+                    trusted_domain=trusted_domain,
+                    realm=api.env.realm
+                )
+            )
+
+    def test_enterprise_principal_UPN_overlap(
+            self, krbalias_user, trusted_domain_with_suffix):
+        krbalias_user.ensure_exists()
+
+        # Add an alias overlapping the UPN of a trusted domain
+        with pytest.raises(errors.ValidationError):
+            krbalias_user.add_principal(
+                u'{username}\@{trusted_domain}@{realm}'.format(
+                    username=krbalias_user.name,
+                    trusted_domain=trusted_domain_with_suffix,
+                    realm=api.env.realm
+                )
+            )
-- 
2.9.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to