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/6142

Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
This commit is contained in:
Milan Kubík
2016-07-22 17:07:56 +02:00
committed by Martin Basti
parent 6eb9eb7303
commit 5582d1df32
4 changed files with 130 additions and 6 deletions

View File

@@ -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(KerberosAliasMixin, Tracker):
"""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)

View File

@@ -0,0 +1,99 @@
#
# 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.
"""
class KerberosAliasError(Exception):
pass
class KerberosAliasMixin(object):
"""KerberosAliasMixin"""
def _make_add_alias_cmd(self):
raise NotImplementedError("The _make_add_alias_cmd method "
"is not implemented.")
def _make_remove_alias_cmd(self):
raise NotImplementedError("The _make_remove_alias_cmd method "
"is not implemented.")
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):
"""Add kerberos principal alias to the entity.
Add principal alias to the underlying entry and
update the attributes in the Tracker instance.
"""
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):
"""Remove kerberos principal alias from an entry.
Remove principal alias from the tracked entry.
"""
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

View File

@@ -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(KerberosAliasMixin, Tracker):
"""
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)

View File

@@ -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(KerberosAliasMixin, Tracker):
""" 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)