mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Enable a host to retrieve a keytab for all its services.
Using the host service principal one should be able to retrieve a keytab for other services for the host using ipa-getkeytab. This required a number of changes: - allow hosts in the service's managedby to write krbPrincipalKey - automatically add the host to managedby when a service is created - fix ipa-getkeytab to return the entire prinicpal and not just the first data element. It was returning "host" from the service tgt and not host/ipa.example.com - fix the display of the managedby attribute in the service plugin This led to a number of changes in the service unit tests. I took the opportunity to switch to the Declarative scheme and tripled the number of tests we were doing. This shed some light on a few bugs in the plugin: - if a service had a bad usercertificate it was impossible to delete the service. I made it a bit more flexible. - I added a summary for the mod and find commands - has_keytab wasn't being set in the find output ticket 68
This commit is contained in:
@@ -38,10 +38,12 @@ add: aci
|
|||||||
aci: (targetattr="krbPrincipalName || krbCanonicalName || krbUPEnabled || krbPrincipalKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account"; allow (read, search, compare, write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
|
aci: (targetattr="krbPrincipalName || krbCanonicalName || krbUPEnabled || krbPrincipalKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account"; allow (read, search, compare, write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
|
||||||
|
|
||||||
# Define which hosts can edit services
|
# Define which hosts can edit services
|
||||||
|
# The managedby attribute stores the DN of hosts that are allowed to manage
|
||||||
|
# a service. Use service-add-host to add hosts to a service.
|
||||||
dn: cn=services,cn=accounts,$SUFFIX
|
dn: cn=services,cn=accounts,$SUFFIX
|
||||||
changetype: modify
|
changetype: modify
|
||||||
add: aci
|
add: aci
|
||||||
aci: (targetattr=userCertificate)(version 3.0; aci "Hosts can modify service userCertificate"; allow(write) userattr = "parent[0,1].managedby#USERDN";)
|
aci: (targetattr="userCertificate || krbPrincipalKey")(version 3.0; aci "Hosts can manage service Certificates and kerberos keys"; allow(write) userattr = "parent[0,1].managedby#USERDN";)
|
||||||
|
|
||||||
# Allow hosts to update their own certificate in host/
|
# Allow hosts to update their own certificate in host/
|
||||||
dn: cn=computers,cn=accounts,$SUFFIX
|
dn: cn=computers,cn=accounts,$SUFFIX
|
||||||
|
|||||||
@@ -69,14 +69,19 @@ static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *s
|
|||||||
sasl_interact_t *in = NULL;
|
sasl_interact_t *in = NULL;
|
||||||
int ret = LDAP_OTHER;
|
int ret = LDAP_OTHER;
|
||||||
krb5_principal princ = (krb5_principal)priv_data;
|
krb5_principal princ = (krb5_principal)priv_data;
|
||||||
|
krb5_context krbctx;
|
||||||
|
char *outname = NULL;
|
||||||
|
|
||||||
if (!ld) return LDAP_PARAM_ERROR;
|
if (!ld) return LDAP_PARAM_ERROR;
|
||||||
|
|
||||||
|
krb5_init_context(&krbctx);
|
||||||
|
|
||||||
for (in = sit; in && in->id != SASL_CB_LIST_END; in++) {
|
for (in = sit; in && in->id != SASL_CB_LIST_END; in++) {
|
||||||
switch(in->id) {
|
switch(in->id) {
|
||||||
case SASL_CB_USER:
|
case SASL_CB_USER:
|
||||||
in->result = princ->data[0].data;
|
krb5_unparse_name(krbctx, princ, &outname);
|
||||||
in->len = princ->data[0].length;
|
in->result = outname;
|
||||||
|
in->len = strlen(outname);
|
||||||
ret = LDAP_SUCCESS;
|
ret = LDAP_SUCCESS;
|
||||||
break;
|
break;
|
||||||
case SASL_CB_GETREALM:
|
case SASL_CB_GETREALM:
|
||||||
@@ -90,7 +95,8 @@ static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *s
|
|||||||
ret = LDAP_OTHER;
|
ret = LDAP_OTHER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
krb5_free_context(krbctx);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_keys_contents(krb5_context krbctx, struct keys_container *keys)
|
static void free_keys_contents(krb5_context krbctx, struct keys_container *keys)
|
||||||
@@ -809,19 +815,19 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (NULL == bindpw) {
|
if (NULL == bindpw) {
|
||||||
krberr = krb5_cc_default(krbctx, &ccache);
|
krberr = krb5_cc_default(krbctx, &ccache);
|
||||||
if (krberr) {
|
if (krberr) {
|
||||||
fprintf(stderr, "Kerberos Credential Cache not found\n"
|
fprintf(stderr, "Kerberos Credential Cache not found\n"
|
||||||
"Do you have a Kerberos Ticket?\n");
|
"Do you have a Kerberos Ticket?\n");
|
||||||
exit(5);
|
exit(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
krberr = krb5_cc_get_principal(krbctx, ccache, &uprinc);
|
krberr = krb5_cc_get_principal(krbctx, ccache, &uprinc);
|
||||||
if (krberr) {
|
if (krberr) {
|
||||||
fprintf(stderr, "Kerberos User Principal not found\n"
|
fprintf(stderr, "Kerberos User Principal not found\n"
|
||||||
"Do you have a valid Credential Cache?\n");
|
"Do you have a valid Credential Cache?\n");
|
||||||
exit(6);
|
exit(6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
krberr = krb5_kt_resolve(krbctx, ktname, &kt);
|
krberr = krb5_kt_resolve(krbctx, ktname, &kt);
|
||||||
|
|||||||
@@ -65,8 +65,18 @@ from ipalib import Str, Flag, Bytes
|
|||||||
from ipalib.plugins.baseldap import *
|
from ipalib.plugins.baseldap import *
|
||||||
from ipalib import x509
|
from ipalib import x509
|
||||||
from ipalib import _, ngettext
|
from ipalib import _, ngettext
|
||||||
|
from nss.error import NSPRError
|
||||||
|
|
||||||
|
|
||||||
|
output_params = (
|
||||||
|
Flag('has_keytab',
|
||||||
|
label=_('Keytab'),
|
||||||
|
),
|
||||||
|
Str('managedby_host',
|
||||||
|
label='Managed by',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def split_principal(principal):
|
def split_principal(principal):
|
||||||
service = hostname = realm = None
|
service = hostname = realm = None
|
||||||
|
|
||||||
@@ -155,6 +165,7 @@ class service_add(LDAPCreate):
|
|||||||
"""
|
"""
|
||||||
msg_summary = _('Added service "%(value)s"')
|
msg_summary = _('Added service "%(value)s"')
|
||||||
member_attributes = ['managedby']
|
member_attributes = ['managedby']
|
||||||
|
has_output_params = LDAPCreate.has_output_params + output_params
|
||||||
takes_options = (
|
takes_options = (
|
||||||
Flag('force',
|
Flag('force',
|
||||||
doc=_('force principal name even if not in DNS'),
|
doc=_('force principal name even if not in DNS'),
|
||||||
@@ -171,7 +182,7 @@ class service_add(LDAPCreate):
|
|||||||
raise errors.HostService()
|
raise errors.HostService()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
api.Command['host_show'](hostname)
|
hostresult = api.Command['host_show'](hostname)['result']
|
||||||
except errors.NotFound:
|
except errors.NotFound:
|
||||||
raise errors.NotFound(reason="The host '%s' does not exist to add a service to." % hostname)
|
raise errors.NotFound(reason="The host '%s' does not exist to add a service to." % hostname)
|
||||||
|
|
||||||
@@ -188,6 +199,8 @@ class service_add(LDAPCreate):
|
|||||||
# really want to discourage creating services for hosts that
|
# really want to discourage creating services for hosts that
|
||||||
# don't exist in DNS.
|
# don't exist in DNS.
|
||||||
util.validate_host_dns(self.log, hostname)
|
util.validate_host_dns(self.log, hostname)
|
||||||
|
if not 'managedby' in entry_attrs:
|
||||||
|
entry_attrs['managedby'] = hostresult['dn']
|
||||||
|
|
||||||
return dn
|
return dn
|
||||||
|
|
||||||
@@ -206,18 +219,26 @@ class service_del(LDAPDelete):
|
|||||||
cert = entry_attrs.get('usercertificate')
|
cert = entry_attrs.get('usercertificate')
|
||||||
if cert:
|
if cert:
|
||||||
cert = cert[0]
|
cert = cert[0]
|
||||||
serial = unicode(x509.get_serial_number(cert, x509.DER))
|
|
||||||
try:
|
try:
|
||||||
result = api.Command['cert_show'](unicode(serial))['result']
|
serial = unicode(x509.get_serial_number(cert, x509.DER))
|
||||||
if 'revocation_reason' not in result:
|
try:
|
||||||
try:
|
result = api.Command['cert_show'](unicode(serial))['result']
|
||||||
api.Command['cert_revoke'](unicode(serial), revocation_reason=4)
|
if 'revocation_reason' not in result:
|
||||||
except errors.NotImplementedError:
|
try:
|
||||||
# some CA's might not implement revoke
|
api.Command['cert_revoke'](unicode(serial), revocation_reason=4)
|
||||||
pass
|
except errors.NotImplementedError:
|
||||||
except errors.NotImplementedError:
|
# some CA's might not implement revoke
|
||||||
# some CA's might not implement revoke
|
pass
|
||||||
pass
|
except errors.NotImplementedError:
|
||||||
|
# some CA's might not implement revoke
|
||||||
|
pass
|
||||||
|
except NSPRError, nsprerr:
|
||||||
|
if nsprerr.errno == -8183:
|
||||||
|
# If we can't decode the cert them proceed with
|
||||||
|
# removing the service.
|
||||||
|
self.log.info("Problem decoding certificate %s" % nsprerr.args[1])
|
||||||
|
else:
|
||||||
|
raise nsprerr
|
||||||
return dn
|
return dn
|
||||||
|
|
||||||
api.register(service_del)
|
api.register(service_del)
|
||||||
@@ -227,6 +248,7 @@ class service_mod(LDAPUpdate):
|
|||||||
"""
|
"""
|
||||||
Modify service.
|
Modify service.
|
||||||
"""
|
"""
|
||||||
|
msg_summary = _('Modified service "%(value)s"')
|
||||||
takes_options = LDAPUpdate.takes_options + (
|
takes_options = LDAPUpdate.takes_options + (
|
||||||
Bytes('usercertificate?', validate_certificate,
|
Bytes('usercertificate?', validate_certificate,
|
||||||
cli_name='certificate',
|
cli_name='certificate',
|
||||||
@@ -234,6 +256,7 @@ class service_mod(LDAPUpdate):
|
|||||||
doc=_('Base-64 encoded server certificate'),
|
doc=_('Base-64 encoded server certificate'),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
has_output_params = LDAPUpdate.has_output_params + output_params
|
||||||
|
|
||||||
member_attributes = ['managedby']
|
member_attributes = ['managedby']
|
||||||
|
|
||||||
@@ -261,6 +284,9 @@ class service_find(LDAPSearch):
|
|||||||
"""
|
"""
|
||||||
Search for services.
|
Search for services.
|
||||||
"""
|
"""
|
||||||
|
msg_summary = ngettext(
|
||||||
|
'%(count)d service matched', '%(count)d services matched'
|
||||||
|
)
|
||||||
member_attributes = ['managedby']
|
member_attributes = ['managedby']
|
||||||
takes_options = LDAPSearch.takes_options + (
|
takes_options = LDAPSearch.takes_options + (
|
||||||
Bytes('usercertificate?', validate_certificate,
|
Bytes('usercertificate?', validate_certificate,
|
||||||
@@ -269,6 +295,7 @@ class service_find(LDAPSearch):
|
|||||||
doc=_('Base-64 encoded server certificate'),
|
doc=_('Base-64 encoded server certificate'),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
has_output_params = LDAPSearch.has_output_params + output_params
|
||||||
def pre_callback(self, ldap, filter, attrs_list, base_dn, *args, **options):
|
def pre_callback(self, ldap, filter, attrs_list, base_dn, *args, **options):
|
||||||
# lisp style!
|
# lisp style!
|
||||||
custom_filter = '(&(objectclass=ipaService)' \
|
custom_filter = '(&(objectclass=ipaService)' \
|
||||||
@@ -282,6 +309,16 @@ class service_find(LDAPSearch):
|
|||||||
(custom_filter, filter), rules=ldap.MATCH_ALL
|
(custom_filter, filter), rules=ldap.MATCH_ALL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
api.register(service_find)
|
api.register(service_find)
|
||||||
|
|
||||||
|
|
||||||
@@ -297,11 +334,7 @@ class service_show(LDAPRetrieve):
|
|||||||
doc=_('Base-64 encoded server certificate'),
|
doc=_('Base-64 encoded server certificate'),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
has_output_params = (
|
has_output_params = LDAPRetrieve.has_output_params + output_params
|
||||||
Flag('has_keytab',
|
|
||||||
label=_('Keytab'),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
|
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
|
||||||
if 'krblastpwdchange' in entry_attrs:
|
if 'krblastpwdchange' in entry_attrs:
|
||||||
@@ -320,6 +353,7 @@ class service_add_host(LDAPAddMember):
|
|||||||
Add hosts that can manage this service.
|
Add hosts that can manage this service.
|
||||||
"""
|
"""
|
||||||
member_attributes = ['managedby']
|
member_attributes = ['managedby']
|
||||||
|
has_output_params = LDAPAddMember.has_output_params + output_params
|
||||||
|
|
||||||
api.register(service_add_host)
|
api.register(service_add_host)
|
||||||
|
|
||||||
@@ -329,6 +363,7 @@ class service_remove_host(LDAPRemoveMember):
|
|||||||
Remove hosts that can manage this service.
|
Remove hosts that can manage this service.
|
||||||
"""
|
"""
|
||||||
member_attributes = ['managedby']
|
member_attributes = ['managedby']
|
||||||
|
has_output_params = LDAPRemoveMember.has_output_params + output_params
|
||||||
|
|
||||||
api.register(service_remove_host)
|
api.register(service_remove_host)
|
||||||
|
|
||||||
@@ -339,6 +374,7 @@ class service_disable(LDAPQuery):
|
|||||||
"""
|
"""
|
||||||
has_output = output.standard_value
|
has_output = output.standard_value
|
||||||
msg_summary = _('Removed kerberos key from "%(value)s"')
|
msg_summary = _('Removed kerberos key from "%(value)s"')
|
||||||
|
has_output_params = LDAPQuery.has_output_params + output_params
|
||||||
|
|
||||||
def execute(self, *keys, **options):
|
def execute(self, *keys, **options):
|
||||||
ldap = self.obj.backend
|
ldap = self.obj.backend
|
||||||
|
|||||||
@@ -300,6 +300,7 @@ class test_host(Declarative):
|
|||||||
dn=service1dn,
|
dn=service1dn,
|
||||||
krbprincipalname=[service1],
|
krbprincipalname=[service1],
|
||||||
objectclass=objectclasses.service,
|
objectclass=objectclasses.service,
|
||||||
|
managedby_host=[fqdn1],
|
||||||
ipauniqueid=[fuzzy_uuid],
|
ipauniqueid=[fuzzy_uuid],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -321,7 +322,7 @@ class test_host(Declarative):
|
|||||||
expected=dict(
|
expected=dict(
|
||||||
count=0,
|
count=0,
|
||||||
truncated=False,
|
truncated=False,
|
||||||
summary=None,
|
summary=u'0 services matched',
|
||||||
result=[
|
result=[
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -21,94 +21,288 @@
|
|||||||
Test the `ipalib/plugins/service.py` module.
|
Test the `ipalib/plugins/service.py` module.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
from ipalib import api, errors
|
||||||
from xmlrpc_test import XMLRPC_test, assert_attr_equal
|
from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
|
||||||
from ipalib import api
|
from tests.test_xmlrpc import objectclasses
|
||||||
from ipalib import errors
|
|
||||||
|
|
||||||
|
|
||||||
class test_service(XMLRPC_test):
|
fqdn1 = u'testhost1.%s' % api.env.domain
|
||||||
"""
|
fqdn2 = u'testhost2.%s' % api.env.domain
|
||||||
Test the `service` plugin.
|
service1 = u'HTTP/%s@%s' % (fqdn1, api.env.realm)
|
||||||
"""
|
hostprincipal1 = u'host/%s@%s' % (fqdn1, api.env.realm)
|
||||||
host = u'ipatest.%s' % api.env.domain
|
service1dn = u'krbprincipalname=%s,cn=services,cn=accounts,%s' % (service1.lower(), api.env.basedn)
|
||||||
principal = u'HTTP/ipatest.%s@%s' % (api.env.domain, api.env.realm)
|
host1dn = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn1, api.env.basedn)
|
||||||
hostprincipal = u'host/ipatest.%s@%s' % (api.env.domain, api.env.realm)
|
host2dn = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn2, api.env.basedn)
|
||||||
kw = {'krbprincipalname': principal}
|
|
||||||
|
|
||||||
def test_1_service_add(self):
|
|
||||||
"""
|
|
||||||
Test adding a HTTP principal using the `xmlrpc.service_add` method.
|
|
||||||
"""
|
|
||||||
self.failsafe_add(api.Object.host, self.host, force=True)
|
|
||||||
entry = self.failsafe_add(api.Object.service, self.principal, force=True)['result']
|
|
||||||
assert_attr_equal(entry, 'krbprincipalname', self.principal)
|
|
||||||
assert_attr_equal(entry, 'objectclass', 'ipaobject')
|
|
||||||
|
|
||||||
def test_2_service_add(self):
|
class test_host(Declarative):
|
||||||
"""
|
|
||||||
Test adding a host principal using `xmlrpc.service_add`. Host
|
|
||||||
services are not allowed.
|
|
||||||
"""
|
|
||||||
kw = {'krbprincipalname': self.hostprincipal}
|
|
||||||
try:
|
|
||||||
api.Command['service_add'](**kw)
|
|
||||||
except errors.HostService:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
assert False
|
|
||||||
|
|
||||||
def test_3_service_add(self):
|
cleanup_commands = [
|
||||||
"""
|
('host_del', [fqdn1], {}),
|
||||||
Test adding a malformed principal ('foo').
|
('host_del', [fqdn2], {}),
|
||||||
"""
|
('service_del', [service1], {}),
|
||||||
kw = {'krbprincipalname': u'foo', 'force': True}
|
]
|
||||||
try:
|
|
||||||
api.Command['service_add'](**kw)
|
|
||||||
except errors.MalformedServicePrincipal:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
assert False
|
|
||||||
|
|
||||||
def test_4_service_add(self):
|
tests = [
|
||||||
"""
|
dict(
|
||||||
Test adding a malformed principal ('HTTP/foo@FOO.NET').
|
desc='Try to retrieve non-existent %r' % service1,
|
||||||
"""
|
command=('service_show', [service1], {}),
|
||||||
kw = {'krbprincipalname': u'HTTP/foo@FOO.NET', 'force': True}
|
expected=errors.NotFound(reason='no such entry'),
|
||||||
try:
|
),
|
||||||
api.Command['service_add'](**kw)
|
|
||||||
except errors.RealmMismatch:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
assert False
|
|
||||||
|
|
||||||
def test_5_service_show(self):
|
|
||||||
"""
|
|
||||||
Test the `xmlrpc.service_show` method.
|
|
||||||
"""
|
|
||||||
entry = api.Command['service_show'](self.principal)['result']
|
|
||||||
assert_attr_equal(entry, 'krbprincipalname', self.principal)
|
|
||||||
assert(entry['has_keytab'] == False)
|
|
||||||
|
|
||||||
def test_6_service_find(self):
|
dict(
|
||||||
"""
|
desc='Try to update non-existent %r' % service1,
|
||||||
Test the `xmlrpc.service_find` method.
|
command=('service_mod', [service1], dict(usercertificate='Nope')),
|
||||||
"""
|
expected=errors.NotFound(reason='no such entry'),
|
||||||
entries = api.Command['service_find'](self.principal)['result']
|
),
|
||||||
assert_attr_equal(entries[0], 'krbprincipalname', self.principal)
|
|
||||||
|
|
||||||
def test_7_service_del(self):
|
|
||||||
"""
|
|
||||||
Test the `xmlrpc.service_del` method.
|
|
||||||
"""
|
|
||||||
assert api.Command['service_del'](self.principal)['result'] is True
|
|
||||||
|
|
||||||
# Verify that it is gone
|
dict(
|
||||||
try:
|
desc='Try to delete non-existent %r' % service1,
|
||||||
api.Command['service_show'](self.principal)
|
command=('service_del', [service1], {}),
|
||||||
except errors.NotFound:
|
expected=errors.NotFound(reason='no such entry'),
|
||||||
pass
|
),
|
||||||
else:
|
|
||||||
assert False
|
|
||||||
|
|
||||||
api.Command['host_del'](self.host)
|
|
||||||
|
dict(
|
||||||
|
desc='Create %r' % fqdn1,
|
||||||
|
command=('host_add', [fqdn1],
|
||||||
|
dict(
|
||||||
|
description=u'Test host 1',
|
||||||
|
l=u'Undisclosed location 1',
|
||||||
|
force=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expected=dict(
|
||||||
|
value=fqdn1,
|
||||||
|
summary=u'Added host "%s"' % fqdn1,
|
||||||
|
result=dict(
|
||||||
|
dn=host1dn,
|
||||||
|
fqdn=[fqdn1],
|
||||||
|
description=[u'Test host 1'],
|
||||||
|
l=[u'Undisclosed location 1'],
|
||||||
|
krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
|
||||||
|
objectclass=objectclasses.host,
|
||||||
|
ipauniqueid=[fuzzy_uuid],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Create %r' % fqdn2,
|
||||||
|
command=('host_add', [fqdn2],
|
||||||
|
dict(
|
||||||
|
description=u'Test host 2',
|
||||||
|
l=u'Undisclosed location 2',
|
||||||
|
force=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expected=dict(
|
||||||
|
value=fqdn2,
|
||||||
|
summary=u'Added host "%s"' % fqdn2,
|
||||||
|
result=dict(
|
||||||
|
dn=host2dn,
|
||||||
|
fqdn=[fqdn2],
|
||||||
|
description=[u'Test host 2'],
|
||||||
|
l=[u'Undisclosed location 2'],
|
||||||
|
krbprincipalname=[u'host/%s@%s' % (fqdn2, api.env.realm)],
|
||||||
|
objectclass=objectclasses.host,
|
||||||
|
ipauniqueid=[fuzzy_uuid],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Create %r' % service1,
|
||||||
|
command=('service_add', [service1],
|
||||||
|
dict(
|
||||||
|
force=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expected=dict(
|
||||||
|
value=service1,
|
||||||
|
summary=u'Added service "%s"' % service1,
|
||||||
|
result=dict(
|
||||||
|
dn=service1dn,
|
||||||
|
krbprincipalname=[service1],
|
||||||
|
objectclass=objectclasses.service,
|
||||||
|
ipauniqueid=[fuzzy_uuid],
|
||||||
|
managedby_host=[fqdn1],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Try to create duplicate %r' % service1,
|
||||||
|
command=('service_add', [service1],
|
||||||
|
dict(
|
||||||
|
force=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expected=errors.DuplicateEntry(),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Retrieve %r' % service1,
|
||||||
|
command=('service_show', [service1], {}),
|
||||||
|
expected=dict(
|
||||||
|
value=service1,
|
||||||
|
summary=None,
|
||||||
|
result=dict(
|
||||||
|
dn=service1dn,
|
||||||
|
krbprincipalname=[service1],
|
||||||
|
has_keytab=False,
|
||||||
|
managedby_host=[fqdn1],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Retrieve %r with all=True' % service1,
|
||||||
|
command=('service_show', [service1], dict(all=True)),
|
||||||
|
expected=dict(
|
||||||
|
value=service1,
|
||||||
|
summary=None,
|
||||||
|
result=dict(
|
||||||
|
dn=service1dn,
|
||||||
|
krbprincipalname=[service1],
|
||||||
|
objectclass=objectclasses.service,
|
||||||
|
ipauniqueid=[fuzzy_uuid],
|
||||||
|
managedby_host=[fqdn1],
|
||||||
|
has_keytab=False
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Search for %r' % service1,
|
||||||
|
command=('service_find', [service1], {}),
|
||||||
|
expected=dict(
|
||||||
|
count=1,
|
||||||
|
truncated=False,
|
||||||
|
summary=u'1 service matched',
|
||||||
|
result=[
|
||||||
|
dict(
|
||||||
|
dn=service1dn,
|
||||||
|
krbprincipalname=[service1],
|
||||||
|
managedby_host=[fqdn1],
|
||||||
|
has_keytab=False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Search for %r with all=True' % service1,
|
||||||
|
command=('service_find', [service1], dict(all=True)),
|
||||||
|
expected=dict(
|
||||||
|
count=1,
|
||||||
|
truncated=False,
|
||||||
|
summary=u'1 service matched',
|
||||||
|
result=[
|
||||||
|
dict(
|
||||||
|
dn=service1dn,
|
||||||
|
krbprincipalname=[service1],
|
||||||
|
objectclass=objectclasses.service,
|
||||||
|
ipauniqueid=[fuzzy_uuid],
|
||||||
|
has_keytab=False,
|
||||||
|
managedby_host=[fqdn1],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Update %r' % service1,
|
||||||
|
command=('service_mod', [service1], dict(usercertificate='aGVsbG8=')),
|
||||||
|
expected=dict(
|
||||||
|
value=service1,
|
||||||
|
summary=u'Modified service "%s"' % service1,
|
||||||
|
result=dict(
|
||||||
|
usercertificate=['hello'],
|
||||||
|
krbprincipalname=[service1],
|
||||||
|
managedby_host=[fqdn1],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Retrieve %r to verify update' % service1,
|
||||||
|
command=('service_show', [service1], {}),
|
||||||
|
expected=dict(
|
||||||
|
value=service1,
|
||||||
|
summary=None,
|
||||||
|
result=dict(
|
||||||
|
dn=service1dn,
|
||||||
|
usercertificate=['hello'],
|
||||||
|
krbprincipalname=[service1],
|
||||||
|
has_keytab=False,
|
||||||
|
managedby_host=[fqdn1],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Delete %r' % service1,
|
||||||
|
command=('service_del', [service1], {}),
|
||||||
|
expected=dict(
|
||||||
|
value=service1,
|
||||||
|
summary=u'Deleted service "%s"' % service1,
|
||||||
|
result=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Try to retrieve non-existent %r' % service1,
|
||||||
|
command=('service_show', [service1], {}),
|
||||||
|
expected=errors.NotFound(reason='no such entry'),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Try to update non-existent %r' % service1,
|
||||||
|
command=('service_mod', [service1], dict(usercertificate='Nope')),
|
||||||
|
expected=errors.NotFound(reason='no such entry'),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Try to delete non-existent %r' % service1,
|
||||||
|
command=('service_del', [service1], {}),
|
||||||
|
expected=errors.NotFound(reason='no such entry'),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Create service with malformed principal "foo"',
|
||||||
|
command=('service_add', [u'foo'], {}),
|
||||||
|
expected=errors.MalformedServicePrincipal(reason='missing service')
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Create service with bad realm "HTTP/foo@FOO.NET"',
|
||||||
|
command=('service_add', [u'HTTP/foo@FOO.NET'], {}),
|
||||||
|
expected=errors.RealmMismatch(),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
dict(
|
||||||
|
desc='Create a host service %r' % hostprincipal1,
|
||||||
|
command=('service_add', [hostprincipal1], {}),
|
||||||
|
expected=errors.HostService()
|
||||||
|
),
|
||||||
|
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user