summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2011-07-05 13:36:48 -0400
committerRob Crittenden <rcritten@redhat.com>2011-07-11 18:45:49 -0400
commitd9627ab1651f4ab00c3734cc5bd69b051f79f92b (patch)
tree8c6ec64e0f0bd48791d4b326d5e4ef5912f82194
parent3a5e26a01c9cbb7b0a1c38d1b0467b780c3df124 (diff)
downloadfreeipa-d9627ab1651f4ab00c3734cc5bd69b051f79f92b.tar.gz
freeipa-d9627ab1651f4ab00c3734cc5bd69b051f79f92b.tar.xz
freeipa-d9627ab1651f4ab00c3734cc5bd69b051f79f92b.zip
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
-rw-r--r--ipalib/errors.py17
-rw-r--r--ipaserver/plugins/ldap2.py7
-rw-r--r--tests/test_xmlrpc/test_host_plugin.py35
3 files changed, 58 insertions, 1 deletions
diff --git a/ipalib/errors.py b/ipalib/errors.py
index cad6e37b4..04211e6ed 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -1210,6 +1210,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 5d6d21d43..6f34984ca 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 f4e020ed7..793729629 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,