It will only ever return one entry so if more than one are found then we raise an exception. This is most easily seen in the host plugin where we search on the server shortname which can be the same across sub-domains (e.g. foo.example.com & foo.lab.example.com).

https://fedorahosted.org/freeipa/ticket/1388

rob
>From f52e98e12f133ca45b57653c3d69c356e361fce3 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Tue, 5 Jul 2011 13:36:48 -0400
Subject: [PATCH] find_entry_by_attr() should fail if multiple entries are found

It will only ever return one entry so if more than one are found
then we raise an exception. This is most easily seen in the host
plugin where we search on the server shortname which can be the
same across sub-domains (e.g. foo.example.com &
foo.lab.example.com).

https://fedorahosted.org/freeipa/ticket/1388
---
 ipalib/errors.py                      |   17 ++++++++++++++++
 ipaserver/plugins/ldap2.py            |    7 +++++-
 tests/test_xmlrpc/test_host_plugin.py |   35 +++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletions(-)

diff --git a/ipalib/errors.py b/ipalib/errors.py
index 74bc5f679502f91f860e2f376620a37d98dc9746..c6389da81f60d06ebae610ef45a4246cb4fe165d 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -1209,6 +1209,23 @@ class AttrValueNotFound(ExecutionError):
     format = _('%(attr)s does not contain \'%(value)s\'')
 
 
+class SingleMatchExpected(ExecutionError):
+    """
+    **4027** Raised when a search should return a single match
+
+    For example:
+
+    >>> raise SingleMatchExpected(found=9)
+    Traceback (most recent call last):
+      ...
+    SingleMatchExpected: The search criteria was not specific enough. Expected 1 and found 9.
+    """
+
+    errno = 4027
+    rval = 1
+    format = _('The search criteria was not specific enough. Expected 1 and found %(found)d.')
+
+
 class BuiltinError(ExecutionError):
     """
     **4100** Base class for builtin execution errors (*4100 - 4199*).
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index 5d6d21d43cab7e1337af6667c027c4e1d956ea9f..6f34984caf85fce7a8174bad10255299a45fc5d4 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -620,7 +620,12 @@ class ldap2(CrudBackend, Encoder):
         """
         search_kw = {attr: value, 'objectClass': object_class}
         filter = self.make_filter(search_kw, rules=self.MATCH_ALL)
-        return self.find_entries(filter, attrs_list, base_dn)[0][0]
+        (entries, truncated) = self.find_entries(filter, attrs_list, base_dn)
+
+        if len(entries) > 1:
+            raise errors.SingleMatchExpected(found=len(entries))
+        else:
+            return entries[0]
 
     def get_entry(self, dn, attrs_list=None, time_limit=None,
                   size_limit=None, normalize=True):
diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py
index f4e020ed7abcd1ccf9de0df32b5d00c898b5b088..793729629eda71a3800b87b9068378207492f426 100644
--- a/tests/test_xmlrpc/test_host_plugin.py
+++ b/tests/test_xmlrpc/test_host_plugin.py
@@ -39,6 +39,8 @@ dn2 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn2, api.env.basedn)
 fqdn3 = u'testhost2.%s' % api.env.domain
 short3 = u'testhost2'
 dn3 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn3, api.env.basedn)
+fqdn4 = u'testhost2.lab.%s' % api.env.domain
+dn4 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn4, api.env.basedn)
 
 # We can use the same cert we generated for the service tests
 fd = open('tests/test_xmlrpc/service.crt', 'r')
@@ -53,6 +55,7 @@ class test_host(Declarative):
         ('host_del', [fqdn1], {}),
         ('host_del', [fqdn2], {}),
         ('host_del', [fqdn3], {}),
+        ('host_del', [fqdn4], {}),
         ('service_del', [service1], {}),
     ]
 
@@ -295,6 +298,32 @@ class test_host(Declarative):
 
 
         dict(
+            desc='Create %r' % fqdn4,
+            command=('host_add', [fqdn4],
+                dict(
+                    description=u'Test host 4',
+                    l=u'Undisclosed location 4',
+                    force=True,
+                ),
+            ),
+            expected=dict(
+                value=fqdn4,
+                summary=u'Added host "%s"' % fqdn4,
+                result=dict(
+                    dn=dn4,
+                    fqdn=[fqdn4],
+                    description=[u'Test host 4'],
+                    l=[u'Undisclosed location 4'],
+                    krbprincipalname=[u'host/%s@%s' % (fqdn4, api.env.realm)],
+                    objectclass=objectclasses.host,
+                    ipauniqueid=[fuzzy_uuid],
+                    managedby_host=[u'%s' % fqdn4],
+                ),
+            ),
+        ),
+
+
+        dict(
             desc='Add managedby_host %r to %r' % (fqdn1, fqdn3),
             command=('host_add_managedby', [fqdn3],
                 dict(
@@ -363,6 +392,12 @@ class test_host(Declarative):
         ),
 
 
+        dict(
+            desc='Show a host with multiple matches %s' % short3,
+            command=('host_show', [short3], {}),
+            expected=errors.SingleMatchExpected(found=2),
+        ),
+
 
         dict(
             desc='Try to rename %r' % fqdn1,
-- 
1.7.4

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to