From df5ae8d6778833c83d7383586df28aefd2e18f92 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mon, 22 Aug 2011 16:24:07 -0400
Subject: [PATCH] Change the way has_keytab is determined, also check for password.

We need an indicator to see if a keytab has been set on host and
service entries. We also need a way to know if a one-time password is
set on a host.

This adds an ACI that grants search on userPassword and
krbPrincipalKey so we can do an existence search on them. This way
we can tell if the attribute is set and create a fake attribute
accordingly.

When a userPassword is set on a host a keytab is generated against
that password so we always set has_keytab to False if a password
exists. This is fine because when keytab gets generated for the
host the password is removed (hence one-time).

This adds has_keytab/has_password to the user, host and service plugins.

ticket https://fedorahosted.org/freeipa/ticket/1538
---
 install/share/default-aci.ldif             |    8 ++++++
 install/updates/20-aci.update              |    4 +++
 ipalib/plugins/baseldap.py                 |   26 ++++++++++++++++++++++
 ipalib/plugins/host.py                     |   33 +++++++++++++++++----------
 ipalib/plugins/service.py                  |   27 ++++++----------------
 ipalib/plugins/user.py                     |    6 +++++
 tests/test_xmlrpc/test_attr.py             |   16 +++++++++++++
 tests/test_xmlrpc/test_group_plugin.py     |    4 +++
 tests/test_xmlrpc/test_host_plugin.py      |   22 +++++++++++++++++-
 tests/test_xmlrpc/test_hostgroup_plugin.py |    2 +
 tests/test_xmlrpc/test_krbtpolicy.py       |    2 +
 tests/test_xmlrpc/test_nesting.py          |   11 +++++++++
 tests/test_xmlrpc/test_netgroup_plugin.py  |    6 +++++
 tests/test_xmlrpc/test_replace.py          |   14 +++++++++++
 tests/test_xmlrpc/test_service_plugin.py   |    8 ++++++-
 tests/test_xmlrpc/test_user_plugin.py      |   30 +++++++++++++++++++++++++
 16 files changed, 185 insertions(+), 34 deletions(-)

diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif
index 88269d282ea56c6ae48d3a0c8d3ffd28114cb91a..586ec61fcf067d47ed51bcbc1b94f6fe041d1473 100644
--- a/install/share/default-aci.ldif
+++ b/install/share/default-aci.ldif
@@ -79,3 +79,11 @@ dn: cn=sudo,$SUFFIX
 changetype: modify
 add: aci
 aci: (targetattr = "*")(version 3.0; acl "No anonymous access to sudo"; deny (read,search,compare) userdn != "ldap:///all";)
+
+# This is used for the host/service one-time passwordn and keytab indirectors.
+# We can do a query on a DN to see if an attribute exists.
+dn: cn=accounts,$SUFFIX
+changetype: modify
+add: aci
+aci: (targetattr="userPassword || krbPrincipalKey")(version 3.0; acl "Search existence of password and kerberos keys"; allow(search) userdn = "ldap:///all";)
+
diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update
index 42f1e9fe617d3812b5dcf29c49ad426a3c304e89..41d35da35c6a9eb5c1cf610c49393c304294ecb6 100644
--- a/install/updates/20-aci.update
+++ b/install/updates/20-aci.update
@@ -2,3 +2,7 @@
 dn: cn=ng,cn=alt,$SUFFIX
 add:aci: '(targetfilter = "(objectClass=mepManagedEntry)")(targetattr = "*")(version 3.0; acl "Managed netgroups cannot be modified"; deny (write) userdn = "ldap:///all";)'
 
+# This is used for the host/service one-time passwordn and keytab indirectors.
+# We can do a query on a DN to see if an attribute exists.
+dn: cn=accounts,$SUFFIX
+add:aci: (targetattr="userPassword || krbPrincipalKey")(version 3.0; acl "Search existence of password and kerberos keys"; allow(search) userdn = "ldap:///all";)
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 6c6481799010c771a7680920d3ce02d9522bab52..d2559f6a5665c72f29f201874c43bffb6cce5a38 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -36,6 +36,12 @@ from ipalib.util import json_serialize
 from ipalib.dn import *
 
 global_output_params = (
+    Flag('has_keytab',
+        label=_('Keytab'),
+    ),
+    Flag('has_password',
+        label=_('Password'),
+    ),
     Str('member',
         label=_('Failed members'),
     ),
@@ -322,6 +328,7 @@ class LDAPObject(Object):
     uuid_attribute = ''
     attribute_members = {}
     rdnattr = None
+    password_attributes = []
     # Can bind as this entry (has userPassword or krbPrincipalKey)
     bindable = False
     relationships = {
@@ -410,6 +417,25 @@ class LDAPObject(Object):
                         )
             del entry_attrs[attr]
 
+    def get_password_attributes(self, ldap, dn, entry_attrs):
+        """
+        Search on the entry to determine if it has a password or
+        keytab set.
+
+        A tuple is used to determine which attribute is set
+        in entry_attrs. The value is set to True/False whether a
+        given password type is set.
+        """
+        for (pwattr, attr) in self.password_attributes:
+            search_filter = '(%s=*)' % pwattr
+            try:
+                (entries, truncated) = ldap.find_entries(
+                    search_filter, [pwattr], dn, ldap.SCOPE_BASE
+                )
+                entry_attrs[attr] = True
+            except errors.NotFound:
+                entry_attrs[attr] = False
+
     def handle_not_found(self, *keys):
         pkey = ''
         if self.primary_key:
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index 5cd1056ec483f11e5277f7fa5f61947548ba962a..6e9efec1a085736b4fb3637ff9802381105bc2e4 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -162,9 +162,6 @@ def remove_fwd_ptr(ipaddr, host, domain, recordtype):
         pass
 
 host_output_params = (
-    Flag('has_keytab',
-        label=_('Keytab'),
-    ),
     Str('managedby_host',
         label='Managed by',
     ),
@@ -224,7 +221,7 @@ class host(LDAPObject):
     default_attributes = [
         'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname',
         'nshardwareplatform', 'nsosversion', 'usercertificate', 'memberof',
-        'krblastpwdchange', 'managedby', 'memberindirect', 'memberofindirect',
+        'managedby', 'memberindirect', 'memberofindirect',
     ]
     uuid_attribute = 'ipauniqueid'
     attribute_members = {
@@ -242,6 +239,8 @@ class host(LDAPObject):
         'managedby': ('Managed by', 'man_by_', 'not_man_by_'),
         'managing': ('Managing', 'man_', 'not_man_'),
     }
+    password_attributes = [('userpassword', 'has_password'),
+                           ('krbprincipalkey', 'has_keytab')]
 
     label = _('Hosts')
     label_singular = _('Host')
@@ -466,6 +465,11 @@ class host_add(LDAPCreate):
 
         if options.get('all', False):
                 entry_attrs['managing'] = self.obj.get_managed_hosts(dn)
+        self.obj.get_password_attributes(ldap, dn, entry_attrs)
+        if entry_attrs['has_password']:
+            # If an OTP is set there is no keytab, at least not one
+            # fetched anywhere.
+            entry_attrs['has_keytab'] = False
 
         return dn
 
@@ -691,8 +695,13 @@ class host_find(LDAPSearch):
 
     def post_callback(self, ldap, entries, truncated, *args, **options):
         for entry in entries:
-            entry_attrs = entry[1]
+            (dn, entry_attrs) = entry
             set_certificate_attrs(entry_attrs)
+            self.obj.get_password_attributes(ldap, dn, entry_attrs)
+            if entry_attrs['has_password']:
+                # If an OTP is set there is no keytab, at least not one
+                # fetched anywhere.
+                entry_attrs['has_keytab'] = False
 
             if options.get('all', False):
                 entry_attrs['managing'] = self.obj.get_managed_hosts(entry[0])
@@ -714,11 +723,10 @@ class host_show(LDAPRetrieve):
     member_attributes = ['managedby']
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
-        if 'krblastpwdchange' in entry_attrs:
-            entry_attrs['has_keytab'] = True
-            if not options.get('all', False):
-                del entry_attrs['krblastpwdchange']
-        else:
+        self.obj.get_password_attributes(ldap, dn, entry_attrs)
+        if entry_attrs['has_password']:
+            # If an OTP is set there is no keytab, at least not one
+            # fetched anywhere.
             entry_attrs['has_keytab'] = False
 
         set_certificate_attrs(entry_attrs)
@@ -766,7 +774,7 @@ class host_disable(LDAPQuery):
 
         dn = self.obj.get_dn(*keys, **options)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, ['krblastpwdchange', 'usercertificate'])
+            (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate'])
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -816,7 +824,8 @@ class host_disable(LDAPQuery):
             ldap.update_entry(dn, {'usercertificate': None})
             done_work = True
 
-        if 'krblastpwdchange' in entry_attrs:
+        self.obj.get_password_attributes(ldap, dn, entry_attrs)
+        if entry_attrs['has_keytab']:
             ldap.remove_principal_key(dn)
             done_work = True
 
diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py
index 11970f4013a0ae217ccf66f51075d6b7d115989d..bcaa76afb941f8b5092d12bbd311a73fb5c41b90 100644
--- a/ipalib/plugins/service.py
+++ b/ipalib/plugins/service.py
@@ -83,9 +83,6 @@ from ipapython.ipautil import file_exists
 
 
 output_params = (
-    Flag('has_keytab',
-        label=_('Keytab'),
-    ),
     Str('managedby_host',
         label='Managed by',
     ),
@@ -207,7 +204,7 @@ class service(LDAPObject):
         'ipaservice', 'pkiuser'
     ]
     search_attributes = ['krbprincipalname', 'managedby']
-    default_attributes = ['krbprincipalname', 'usercertificate', 'managedby', 'krblastpwdchange']
+    default_attributes = ['krbprincipalname', 'usercertificate', 'managedby']
     uuid_attribute = 'ipauniqueid'
     attribute_members = {
         'managedby': ['host'],
@@ -216,6 +213,7 @@ class service(LDAPObject):
     relationships = {
         'managedby': ('Managed by', 'man_by_', 'not_man_by_'),
     }
+    password_attributes = [('krbprincipalkey', 'has_keytab')]
 
     label = _('Services')
     label_singular = _('Service')
@@ -379,13 +377,8 @@ class service_find(LDAPSearch):
 
     def post_callback(self, ldap, entries, truncated, *args, **options):
         for entry in entries:
-            entry_attrs = entry[1]
-            if 'krblastpwdchange' in entry_attrs:
-                entry_attrs['has_keytab'] = True
-                if not options.get('all', False):
-                    del entry_attrs['krblastpwdchange']
-            else:
-                entry_attrs['has_keytab'] = False
+            (dn, entry_attrs) = entry
+            self.obj.get_password_attributes(ldap, dn, entry_attrs)
             set_certificate_attrs(entry_attrs)
 
 api.register(service_find)
@@ -403,12 +396,7 @@ class service_show(LDAPRetrieve):
     )
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
-        if 'krblastpwdchange' in entry_attrs:
-            entry_attrs['has_keytab'] = True
-            if not options.get('all', False):
-                del entry_attrs['krblastpwdchange']
-        else:
-            entry_attrs['has_keytab'] = False
+        self.obj.get_password_attributes(ldap, dn, entry_attrs)
 
         set_certificate_attrs(entry_attrs)
 
@@ -461,7 +449,7 @@ class service_disable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(*keys, **options)
-        (dn, entry_attrs) = ldap.get_entry(dn, ['krblastpwdchange', 'usercertificate'])
+        (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate'])
 
         # See if we do any work at all here and if not raise an exception
         done_work = False
@@ -493,7 +481,8 @@ class service_disable(LDAPQuery):
             ldap.update_entry(dn, {'usercertificate': None})
             done_work = True
 
-        if 'krblastpwdchange' in entry_attrs:
+        self.obj.get_password_attributes(ldap, dn, entry_attrs)
+        if entry_attrs['has_keytab']:
             ldap.remove_principal_key(dn)
             done_work = True
 
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 3068c6291f2ab8977713777d5cdba77240b26846..2112c03d0977dc51e4e61821bb7ddfb299a17bd2 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -113,6 +113,8 @@ class user(LDAPObject):
     }
     rdnattr = 'uid'
     bindable = True
+    password_attributes = [('userpassword', 'has_password'),
+                           ('krbprincipalkey', 'has_keytab')]
 
     label = _('Users')
     label_singular = _('User')
@@ -407,6 +409,7 @@ class user_add(LDAPCreate):
                 newentry = wait_for_value(ldap, dn, 'objectclass', 'mepOriginEntry')
                 entry_from_entry(entry_attrs, newentry)
 
+        self.obj.get_password_attributes(ldap, dn, entry_attrs)
         return dn
 
 api.register(user_add)
@@ -443,6 +446,7 @@ class user_mod(LDAPUpdate):
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         convert_nsaccountlock(entry_attrs)
         self.obj._convert_manager(entry_attrs, **options)
+        self.obj.get_password_attributes(ldap, dn, entry_attrs)
         return dn
 
 api.register(user_mod)
@@ -472,6 +476,7 @@ class user_find(LDAPSearch):
         for entry in entries:
             (dn, attrs) = entry
             self.obj._convert_manager(attrs, **options)
+            self.obj.get_password_attributes(ldap, dn, attrs)
             convert_nsaccountlock(attrs)
 
     msg_summary = ngettext(
@@ -488,6 +493,7 @@ class user_show(LDAPRetrieve):
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         convert_nsaccountlock(entry_attrs)
         self.obj._convert_manager(entry_attrs, **options)
+        self.obj.get_password_attributes(ldap, dn, entry_attrs)
         return dn
 
 api.register(user_show)
diff --git a/tests/test_xmlrpc/test_attr.py b/tests/test_xmlrpc/test_attr.py
index 3f78a678d50b96627cabd58c88cfb63a48f0b453..11aaa01e37d20e17994c438e6a34a8c103754b3d 100644
--- a/tests/test_xmlrpc/test_attr.py
+++ b/tests/test_xmlrpc/test_attr.py
@@ -69,6 +69,8 @@ class test_attr(Declarative):
                     dn=lambda x: DN(x) == \
                         DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
                            api.env.basedn),
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -91,6 +93,8 @@ class test_attr(Declarative):
                     mail=[u'test@example.com'],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -115,6 +119,8 @@ class test_attr(Declarative):
                     mail=[u'test@example.com', u'test2@example.com'],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -140,6 +146,8 @@ class test_attr(Declarative):
                     memberof_group=[u'ipausers'],
                     telephonenumber=[u'410-555-1212', u'301-555-1212'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -165,6 +173,8 @@ class test_attr(Declarative):
                     memberof_group=[u'ipausers'],
                     telephonenumber=[u'301-555-1212'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -190,6 +200,8 @@ class test_attr(Declarative):
                     memberof_group=[u'ipausers'],
                     telephonenumber=[u'301-555-1212', u'202-888-9833', u'703-555-1212'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -233,6 +245,8 @@ class test_attr(Declarative):
                     memberof_group=[u'ipausers'],
                     telephonenumber=[u'301-555-1212', u'202-888-9833', u'703-555-1212'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -258,6 +272,8 @@ class test_attr(Declarative):
                     memberof_group=[u'ipausers'],
                     telephonenumber=[u'301-555-1212', u'202-888-9833', u'703-555-1212'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
diff --git a/tests/test_xmlrpc/test_group_plugin.py b/tests/test_xmlrpc/test_group_plugin.py
index 096bab2de0349c605c4970b3a70ba1486948149d..6403251e6532843e08d436e1d8ab93321b8c9bed 100644
--- a/tests/test_xmlrpc/test_group_plugin.py
+++ b/tests/test_xmlrpc/test_group_plugin.py
@@ -637,6 +637,8 @@ class test_group(Declarative):
                     dn=lambda x: DN(x) == \
                         DN(('uid',user1),('cn','users'),('cn','accounts'),
                            api.env.basedn),
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -753,6 +755,8 @@ class test_group(Declarative):
                     dn=lambda x: DN(x) == \
                         DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
                            api.env.basedn),
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py
index 87eb93768b554baf712b78f5c502ed3132903849..f7746407b24b101808b3f18383abf6fc94944165 100644
--- a/tests/test_xmlrpc/test_host_plugin.py
+++ b/tests/test_xmlrpc/test_host_plugin.py
@@ -109,6 +109,8 @@ class test_host(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[fqdn1],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -140,6 +142,7 @@ class test_host(Declarative):
                     l=[u'Undisclosed location 1'],
                     krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
                     has_keytab=False,
+                    has_password=False,
                     managedby_host=[fqdn1],
                 ),
             ),
@@ -168,7 +171,8 @@ class test_host(Declarative):
                     managedby_host=[fqdn1],
                     managing_host=[fqdn1],
                     ipauniqueid=[fuzzy_uuid],
-                    has_keytab=False
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -189,6 +193,8 @@ class test_host(Declarative):
                         l=[u'Undisclosed location 1'],
                         krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
                         managedby_host=[u'%s' % fqdn1],
+                        has_keytab=False,
+                        has_password=False,
                     ),
                 ],
             ),
@@ -219,6 +225,8 @@ class test_host(Declarative):
                         ipauniqueid=[fuzzy_uuid],
                         managedby_host=[u'%s' % fqdn1],
                         managing_host=[u'%s' % fqdn1],
+                        has_keytab=False,
+                        has_password=False,
                     ),
                 ],
             ),
@@ -265,6 +273,7 @@ class test_host(Declarative):
                     l=[u'Undisclosed location 1'],
                     krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
                     has_keytab=False,
+                    has_password=False,
                     managedby_host=[u'%s' % fqdn1],
                     usercertificate=[base64.b64decode(servercert)],
                     valid_not_before=fuzzy_date,
@@ -300,6 +309,8 @@ class test_host(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[u'%s' % fqdn3],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -326,6 +337,8 @@ class test_host(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[u'%s' % fqdn4],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -369,6 +382,7 @@ class test_host(Declarative):
                     l=[u'Undisclosed location 2'],
                     krbprincipalname=[u'host/%s@%s' % (fqdn3, api.env.realm)],
                     has_keytab=False,
+                    has_password=False,
                     managedby_host=[u'%s' % fqdn3, u'%s' % fqdn1],
                 ),
             ),
@@ -468,6 +482,8 @@ class test_host(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[u'%s' % fqdn1],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -479,7 +495,7 @@ class test_host(Declarative):
                 value=service1,
                 summary=u'Added service "%s"' % service1,
                 result=dict(
-                    dn=service1dn,
+                    dn=lambda x: DN(x) == service1dn,
                     krbprincipalname=[service1],
                     objectclass=objectclasses.service,
                     managedby_host=[fqdn1],
@@ -539,6 +555,8 @@ class test_host(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[u'%s' % fqdn2],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
diff --git a/tests/test_xmlrpc/test_hostgroup_plugin.py b/tests/test_xmlrpc/test_hostgroup_plugin.py
index 6f6008f0be9fc1a8a58032c8b3644ce398e13997..0c0605aefc80cb1337832ea3fb7fedef3e70dcae 100644
--- a/tests/test_xmlrpc/test_hostgroup_plugin.py
+++ b/tests/test_xmlrpc/test_hostgroup_plugin.py
@@ -122,6 +122,8 @@ class test_hostgroup(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[fqdn1],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
diff --git a/tests/test_xmlrpc/test_krbtpolicy.py b/tests/test_xmlrpc/test_krbtpolicy.py
index 3db743d51323dc839bcc3f5022e414a0e1cd3c4c..3ef603b3a4027a1506eec6ed64bd720f94e5a867 100644
--- a/tests/test_xmlrpc/test_krbtpolicy.py
+++ b/tests/test_xmlrpc/test_krbtpolicy.py
@@ -116,6 +116,8 @@ class test_krbtpolicy(Declarative):
                         [DN(('cn',user1),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid',user1),('cn','users'),('cn','accounts'),
                            api.env.basedn)
diff --git a/tests/test_xmlrpc/test_nesting.py b/tests/test_xmlrpc/test_nesting.py
index 162fdc95ac8d8d1b7af871677188c4c8256308f2..1f97589ff8e40feda1e8819690dedfd26666a9e9 100644
--- a/tests/test_xmlrpc/test_nesting.py
+++ b/tests/test_xmlrpc/test_nesting.py
@@ -186,6 +186,8 @@ class test_nesting(Declarative):
                         [DN(('cn',user1),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid',user1),('cn','users'),('cn','accounts'),
                            api.env.basedn)
@@ -224,6 +226,8 @@ class test_nesting(Declarative):
                         [DN(('cn',user2),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid',user2),('cn','users'),('cn','accounts'),
                            api.env.basedn)
@@ -262,6 +266,8 @@ class test_nesting(Declarative):
                         [DN(('cn',user3),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid',user3),('cn','users'),('cn','accounts'),
                            api.env.basedn)
@@ -300,6 +306,8 @@ class test_nesting(Declarative):
                         [DN(('cn',user4),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid',user4),('cn','users'),('cn','accounts'),
                            api.env.basedn)
@@ -676,6 +684,8 @@ class test_nesting(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[fqdn1],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -806,6 +816,7 @@ class test_nesting(Declarative):
                     l=[u'Undisclosed location 1'],
                     krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
                     has_keytab=False,
+                    has_password=False,
                     managedby_host=[fqdn1],
                     memberof_hostgroup = [u'testhostgroup2'],
                     memberofindirect_hostgroup = [u'testhostgroup1'],
diff --git a/tests/test_xmlrpc/test_netgroup_plugin.py b/tests/test_xmlrpc/test_netgroup_plugin.py
index 3513e6fe218d947be99ee4e93fff2ae41fee0016..d39aacefd5a4f4404c77eba9881b324c064e8cee 100644
--- a/tests/test_xmlrpc/test_netgroup_plugin.py
+++ b/tests/test_xmlrpc/test_netgroup_plugin.py
@@ -168,6 +168,8 @@ class test_netgroup(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[host1],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -226,6 +228,8 @@ class test_netgroup(Declarative):
                         [DN(('cn',user1),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid',user1),('cn','users'),('cn','accounts'),
                            api.env.basedn),
@@ -263,6 +267,8 @@ class test_netgroup(Declarative):
                         [DN(('cn',user2),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid',user2),('cn','users'),('cn','accounts'),
                            api.env.basedn),
diff --git a/tests/test_xmlrpc/test_replace.py b/tests/test_xmlrpc/test_replace.py
index a1fd5d280675e150544f2506173bbe19092d6e40..f5203607c014c855b04519680fea1b61e973eb2c 100644
--- a/tests/test_xmlrpc/test_replace.py
+++ b/tests/test_xmlrpc/test_replace.py
@@ -73,6 +73,8 @@ class test_replace(Declarative):
                         [DN(('cn',user1),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
                            api.env.basedn),
@@ -98,6 +100,8 @@ class test_replace(Declarative):
                     mail=[u'test1@example.com', u'test3@example.com'],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -122,6 +126,8 @@ class test_replace(Declarative):
                     mail=[u'test4@example.com'],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -146,6 +152,8 @@ class test_replace(Declarative):
                     mail=[u'test6@example.com', u'test7@example.com', u'test5@example.com'],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -169,6 +177,8 @@ class test_replace(Declarative):
                     gidnumber=[fuzzy_digits],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -193,6 +203,8 @@ class test_replace(Declarative):
                     initials=[u'ABC'],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -216,6 +228,8 @@ class test_replace(Declarative):
                     gidnumber=[fuzzy_digits],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
diff --git a/tests/test_xmlrpc/test_service_plugin.py b/tests/test_xmlrpc/test_service_plugin.py
index d424eeedd1c57605e6136bfc68f2121f78aaadf4..d36dac984e4c1e3e4352c8653a787a2f0fd3d030 100644
--- a/tests/test_xmlrpc/test_service_plugin.py
+++ b/tests/test_xmlrpc/test_service_plugin.py
@@ -47,7 +47,7 @@ fd.close()
 badservercert = 'MIICbzCCAdigAwIBAgICA/4wDQYJKoZIhvcNAQEFBQAwKTEnMCUGA1UEAxMeSVBBIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgwOTE1MDIyN1oXDTIwMDgwOTE1MDIyN1owKTEMMAoGA1UEChMDSVBBMRkwFwYDVQQDExBwdW1hLmdyZXlvYWsuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwYbfEOQPgGenPn9vt1JFKvWm/Je3y2tawGWA3LXDuqfFJyYtZ8ib3TcBUOnLk9WK5g2qCwHaNlei7bj8ggIfr5hegAVe10cun+wYErjnYo7hsHYd+57VZezeipWrXu+7NoNd4+c4A5lk4A/xJay9j3bYx2oOM8BEox4xWYoWge1ljPrc5JK46f0X7AGW4F2VhnKPnf8rwSuzI1U8VGjutyM9TWNy3m9KMWeScjyG/ggIpOjUDMV7HkJL0Di61lznR9jXubpiEC7gWGbTp84eGl/Nn9bgK1AwHfJ2lHwfoY4uiL7ge1gyP6EvuUlHoBzdb7pekiX28iePjW3iEG9IawIDAQABoyIwIDARBglghkgBhvhCAQEEBAMCBkAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4GBACRESLemRV9BPxfEgbALuxH5oE8jQm8WZ3pm2pALbpDlAd9wQc3yVf6RtkfVthyDnM18bg7IhxKpd77/p3H8eCnS8w5MLVRda6ktUC6tGhFTS4QKAf0WyDGTcIgkXbeDw0OPAoNHivoXbIXIIRxlw/XgaSaMzJQDBG8iROsN4kCv'
 
 
-class test_host(Declarative):
+class test_service(Declarative):
 
     cleanup_commands = [
         ('host_del', [fqdn1], {}),
@@ -99,6 +99,8 @@ class test_host(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[u'%s' % fqdn1],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -125,6 +127,8 @@ class test_host(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[u'%s' % fqdn2],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
@@ -151,6 +155,8 @@ class test_host(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[u'%s' % fqdn3.lower()],
+                    has_keytab=False,
+                    has_password=False,
                 ),
             ),
         ),
diff --git a/tests/test_xmlrpc/test_user_plugin.py b/tests/test_xmlrpc/test_user_plugin.py
index 12aec153c997e43eedc25e03e7454a20e3035f27..9392742e9a820d0968ed92900cec289d5225a6b7 100644
--- a/tests/test_xmlrpc/test_user_plugin.py
+++ b/tests/test_xmlrpc/test_user_plugin.py
@@ -104,6 +104,8 @@ class test_user(Declarative):
                         [DN(('cn',user1),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
                            api.env.basedn),
@@ -140,6 +142,8 @@ class test_user(Declarative):
                     gidnumber=[fuzzy_digits],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 value=user1,
                 summary=None,
@@ -178,6 +182,8 @@ class test_user(Declarative):
                             [DN(('cn','global_policy'),('cn',api.env.realm),
                                 ('cn','kerberos'),api.env.basedn)],
                         'nsaccountlock': False,
+                        'has_keytab': False,
+                        'has_password': False,
                         'displayname': [u'Test User1'],
                         'cn': [u'Test User1'],
                         'initials': [u'TU'],
@@ -206,6 +212,8 @@ class test_user(Declarative):
                         sn=[u'User1'],
                         uid=[user1],
                         nsaccountlock=False,
+                        has_keytab=False,
+                        has_password=False,
                         uidnumber=[fuzzy_digits],
                         gidnumber=[fuzzy_digits],
                     ),
@@ -233,6 +241,8 @@ class test_user(Declarative):
                         sn=[u'Administrator'],
                         uid=[u'admin'],
                         nsaccountlock=False,
+                        has_keytab=True,
+                        has_password=True,
                         uidnumber=[fuzzy_digits],
                         gidnumber=[fuzzy_digits],
                     ),
@@ -246,6 +256,8 @@ class test_user(Declarative):
                         sn=[u'User1'],
                         uid=[user1],
                         nsaccountlock=False,
+                        has_keytab=False,
+                        has_password=False,
                         uidnumber=[fuzzy_digits],
                         gidnumber=[fuzzy_digits],
                     ),
@@ -273,6 +285,8 @@ class test_user(Declarative):
                         sn=[u'Administrator'],
                         uid=[u'admin'],
                         nsaccountlock=False,
+                        has_keytab=True,
+                        has_password=True,
                         uidnumber=[fuzzy_digits],
                         gidnumber=[fuzzy_digits],
                     ),
@@ -326,6 +340,8 @@ class test_user(Declarative):
                     gidnumber=[fuzzy_digits],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "tuser1"',
                 value=user1,
@@ -359,6 +375,8 @@ class test_user(Declarative):
                     gidnumber=[fuzzy_digits],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=None,
                 value=user1,
@@ -381,6 +399,8 @@ class test_user(Declarative):
                     gidnumber=[fuzzy_digits],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "%s"' % user1,
                 value=user1,
@@ -409,6 +429,8 @@ class test_user(Declarative):
                     gidnumber=[fuzzy_digits],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                 ),
                 summary=u'Modified user "%s"' % renameduser1,
                 value=renameduser1,
@@ -475,6 +497,8 @@ class test_user(Declarative):
                         [DN(('cn',user1),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
                            api.env.basedn),
@@ -513,6 +537,8 @@ class test_user(Declarative):
                         [DN(('cn',user2),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
                            api.env.basedn),
@@ -542,6 +568,8 @@ class test_user(Declarative):
                     gidnumber=[fuzzy_digits],
                     memberof_group=[u'ipausers'],
                     nsaccountlock=False,
+                    has_keytab=False,
+                    has_password=False,
                     manager=[user1],
                 ),
                 summary=u'Modified user "%s"' % user2,
@@ -655,6 +683,8 @@ class test_user(Declarative):
                         [DN(('cn',user1),('cn','groups'),('cn','accounts'),
                             api.env.basedn)],
                     memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
                     dn=lambda x: DN(x) == \
                         DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
                            api.env.basedn),
-- 
1.7.4

