Imported Upstream version 4.3.1

This commit is contained in:
Mario Fetka
2021-08-10 02:37:58 +02:00
parent a791de49a2
commit 2f177da8f2
2056 changed files with 421730 additions and 1668138 deletions

View File

@@ -1,337 +0,0 @@
#
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
from ipatests.test_xmlrpc import objectclasses
from ipatests.test_xmlrpc.xmlrpc_test import (
fuzzy_uuid, fuzzy_automember_message, fuzzy_automember_dn)
from ipatests.test_xmlrpc.tracker.base import Tracker
from ipatests.util import assert_deepequal
from ipalib import api
from ipapython.dn import DN
class AutomemberTracker(Tracker):
""" Class for tracking automembers """
retrieve_keys = {u'dn', u'cn', u'member_host', u'description',
u'member_automember', u'memberindirect_host',
u'automemberinclusiveregex', u'automemberexclusiveregex',
u'automembertargetgroup'}
retrieve_all_keys = retrieve_keys | {u'objectclass',
u'automembertargetgroup'}
create_keys = retrieve_all_keys
update_keys = retrieve_keys - {u'dn'}
add_member_keys = retrieve_keys | {u'member_host'}
add_condition_keys = retrieve_keys - {u'dn'} |\
{u'automemberinclusiveregex', u'automembertargetgroup'}
add_condition_negative_keys = {u'automemberinclusiveregex'}
def __init__(self, groupname, membertype, description=u'Automember desc'):
super(AutomemberTracker, self).__init__(default_version=None)
self.cn = groupname
self.description = description
self.membertype = membertype
self.dn = DN(('cn', self.cn), ('cn', self.membertype.title()),
('cn', 'automember'), ('cn', 'etc'), api.env.basedn)
def make_create_command(self, *args, **kwargs):
""" Make function that creates an automember using 'automember-add' """
return self.make_command('automember_add', self.cn,
description=self.description,
type=self.membertype,
*args, **kwargs)
def make_delete_command(self):
""" Make function that deletes an automember using 'automember-del' """
return self.make_command('automember_del', self.cn,
**dict(type=self.membertype))
def make_retrieve_command(self, all=False, raw=False, membertype=None):
""" Make function that retrieves an automember
using 'automember-show' """
if membertype is None:
membertype = self.membertype
return self.make_command('automember_show', self.cn, type=membertype)
def make_find_command(self, *args, **kwargs):
""" Make function that searches for an automember
using 'automember-find' """
return self.make_command('automember_find', self.cn,
type=self.membertype)
def make_update_command(self, updates):
""" Make function that updates an automember using 'automember-mod' """
return self.make_command('automember_mod', self.cn,
type=self.membertype, **updates)
def make_add_member_command(self, options={}):
""" Make function that adds a member to an automember """
return self.make_command('automember_add_member', self.cn, **options)
def make_remove_member_command(self, options={}):
""" Make function that removes a member from an automember """
return self.make_command('automember_remove_member',
self.cn, **options)
def make_rebuild_command(self, *args, **kwargs):
""" Make function that issues automember_rebuild.
This function can be executed with arbitrary automember tracker """
return self.make_command('automember_rebuild', *args, **kwargs)
def make_add_condition_command(self, *args, **kwargs):
""" Make function that issues automember_add_condition """
return self.make_command('automember_add_condition', self.cn,
*args, **kwargs)
def track_create(self):
""" Updates expected state for automember creation"""
self.attrs = dict(
dn=self.dn,
mepmanagedentry=[DN(('cn', self.cn), ('cn', 'ng'),
('cn', 'alt'), api.env.basedn)],
cn=[self.cn],
description=[self.description],
ipauniqueid=[fuzzy_uuid],
objectclass=objectclasses.automember,
automembertargetgroup=[DN(('cn', self.cn),
('cn', self.membertype + 's'),
('cn', 'accounts'), api.env.basedn)]
)
self.exists = True
def add_member(self, options):
""" Add a member host to automember and perform check """
if u'group' in options:
try:
self.attrs[u'group'] =\
self.attrs[u'group'] + [options[u'group']]
except KeyError:
self.attrs[u'group'] = [options[u'group']]
# search for hosts in the target automember and
# add them as memberindirect hosts
elif u'hostgroup' in options:
try:
self.attrs[u'hostgroup'] =\
self.attrs[u'hostgroup'] + [options[u'hostgroup']]
except KeyError:
self.attrs[u'hostgroup'] = [options[u'hostgroup']]
command = self.make_add_member_command(options)
result = command()
self.check_add_member(result)
def remove_member(self, options):
""" Remove a member host from automember and perform check """
if u'host' in options:
self.attrs[u'member_host'].remove(options[u'host'])
elif u'automember' in options:
self.attrs[u'member_automember'].remove(options[u'automember'])
try:
if not self.attrs[u'member_host']:
del self.attrs[u'member_host']
except KeyError:
pass
try:
if not self.attrs[u'member_automember']:
del self.attrs[u'member_automember']
except KeyError:
pass
command = self.make_remove_member_command(options)
result = command()
self.check_remove_member(result)
def update(self, updates, expected_updates=None):
"""Helper function to update this user and check the result
Overriding Tracker method for setting self.attrs correctly;
* most attributes stores its value in list
* the rest can be overridden by expected_updates
* allow deleting parametrs if update value is None
"""
if expected_updates is None:
expected_updates = {}
self.ensure_exists()
command = self.make_update_command(updates)
result = command()
for key, value in updates.items():
if value is None:
del self.attrs[key]
else:
self.attrs[key] = [value]
for key, value in expected_updates.items():
if value is None:
del self.attrs[key]
else:
self.attrs[key] = value
self.check_update(
result,
extra_keys=set(updates.keys()) | set(expected_updates.keys())
)
def add_condition(self, key, type, inclusiveregex):
""" Add a condition with given inclusive regex and check for result.
Only one condition can be added. For more specific uses please
use make_add_condition_command instead. """
command = self.make_add_condition_command(
key=key, type=type, automemberinclusiveregex=inclusiveregex)
self.attrs['automemberinclusiveregex'] = [u'%s=%s' %
(key, inclusiveregex[0])]
result = command()
self.check_add_condition(result)
def rebuild(self, no_wait=False):
""" Rebuild automember conditions and check for result """
command = self.make_rebuild_command(type=self.membertype,
no_wait=no_wait)
result = command()
self.check_rebuild(result, no_wait=no_wait)
def check_rebuild(self, result, no_wait=False):
""" Check result of automember_rebuild command """
if no_wait is False:
assert_deepequal(dict(
value=None, result=dict(),
summary=fuzzy_automember_message
), result)
else:
assert_deepequal(dict(
value=None,
result=dict(dn=fuzzy_automember_dn),
summary=u'Automember rebuild membership task started'
), result)
def check_add_condition(self, result):
""" Check result of automember_add_condition command """
assert_deepequal(dict(
value=self.cn,
summary=u'Added condition(s) to "%s"' % self.cn,
completed=1,
failed=dict(
failed=dict(automemberinclusiveregex=tuple(),
automemberexclusiveregex=tuple(),
)
),
result=self.filter_attrs(self.add_condition_keys)
), result)
def check_add_condition_negative(self, result):
""" Check result of automember_add_condition command
when the operation didn't add anything. """
assert_deepequal(dict(
value=self.cn,
summary=u'Added condition(s) to "%s"' % self.cn,
completed=0,
failed=dict(
failed=dict(automemberinclusiveregex=tuple(),
automemberexclusiveregex=tuple(),
)
),
result=self.filter_attrs(self.add_condition_negative_keys)
), result)
def check_create(self, result):
""" Checks 'automember_add' command result """
assert_deepequal(dict(
value=self.cn,
summary=u'Added automember rule "%s"' % self.cn,
result=self.filter_attrs(self.create_keys)
), result)
def check_delete(self, result):
""" Checks 'automember_del' command result """
assert_deepequal(dict(
value=[self.cn],
summary=u'Deleted automember rule "%s"' % self.cn,
result=dict(failed=[]),
), result)
def check_retrieve(self, result, all=False, raw=False):
""" Checks 'automember_show' command result """
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
value=self.cn,
summary=None,
result=expected
), result)
def check_find(self, result, all=False, raw=False):
""" Checks 'automember_find' command result """
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
count=1,
truncated=False,
summary=u'1 rules matched',
result=[expected],
), result)
def check_update(self, result, extra_keys={}):
""" Checks 'automember_mod' command result """
assert_deepequal(dict(
value=self.cn,
summary=u'Modified automember rule "%s"' % self.cn,
result=self.filter_attrs(self.update_keys | set(extra_keys))
), result)
def check_add_member(self, result):
""" Checks 'automember_add_member' command result """
assert_deepequal(dict(
completed=1,
failed={u'member': {u'host': (), u'automember': ()}},
result=self.filter_attrs(self.add_member_keys)
), result)
def check_add_member_negative(self, result, options):
""" Checks 'automember_add_member' command result
when expected result is failure of the operation"""
expected = dict(
completed=0,
failed={u'member': {u'automember': (), u'user': ()}},
result=self.filter_attrs(self.add_member_keys)
)
if u'host' in options:
expected[u'failed'][u'member'][u'host'] = [(
options[u'host'], u'no such entry')]
elif u'automember' in options:
expected[u'failed'][u'member'][u'automember'] = [(
options[u'automember'], u'no such entry')]
assert_deepequal(expected, result)
def check_remove_member_negative(self, result, options):
""" Checks 'automember_remove_member' command result
when expected result is failure of the operation"""
expected = dict(
completed=0,
failed={u'member': {u'automember': (), u'host': ()}},
result=self.filter_attrs(self.add_member_keys)
)
if u'user' in options:
expected[u'failed'][u'member'][u'host'] = [(
options[u'user'], u'This entry is not a member')]
elif u'automember' in options:
expected[u'failed'][u'member'][u'automember'] = [(
options[u'automember'], u'This entry is not a member')]
assert_deepequal(expected, result)
def check_remove_member(self, result):
""" Checks 'automember_remove_member' command result """
self.check_add_member(result)

View File

@@ -15,14 +15,71 @@ from ipapython.version import API_VERSION
from ipatests.util import Fuzzy
class BaseTracker(object):
class Tracker(object):
"""Wraps and tracks modifications to a plugin LDAP entry object
Stores a copy of state of a plugin entry object and allows checking that
the state in the database is the same as expected.
This allows creating independent tests: the individual tests check
that the relevant changes have been made. At the same time
the entry doesn't need to be recreated and cleaned up for each test.
Two attributes are used for tracking: ``exists`` (true if the entry is
supposed to exist) and ``attrs`` (a dict of LDAP attributes that are
expected to be returned from IPA commands).
For commonly used operations, there is a helper method, e.g.
``create``, ``update``, or ``find``, that does these steps:
* ensure the entry exists (or does not exist, for "create")
* store the expected modifications
* get the IPA command to run, and run it
* check that the result matches the expected state
Tests that require customization of these steps are expected to do them
manually, using lower-level methods.
Especially the first step (ensure the entry exists) is important for
achieving independent tests.
The Tracker object also stores information about the entry, e.g.
``dn``, ``rdn`` and ``name`` which is derived from DN property.
To use this class, the programer must subclass it and provide the
implementation of following methods:
* make_*_command -- implementing the API call for particular plugin
and operation (add, delete, ...)
These methods should use the make_command method
* check_* commands -- an assertion for a plugin command (CRUD)
* track_create -- to make an internal representation of the
entry
Apart from overriding these methods, the subclass must provide the
distinguished name of the entry in `self.dn` property.
It is also required to override the class variables defining the sets
of ldap attributes/keys for these operations specific to the plugin
being implemented. Take the host plugin test for an example.
The implementation of these methods is not strictly enforced.
A missing method will cause a NotImplementedError during runtime
as a result.
"""
retrieve_keys = None
retrieve_all_keys = None
create_keys = None
update_keys = None
managedby_keys = None
allowedto_keys = None
_override_me_msg = "This method needs to be overridden in a subclass"
def __init__(self, default_version=None):
self.api = api
self.default_version = default_version or API_VERSION
self._dn = None
self.attrs = {}
self.exists = False
@property
def dn(self):
@@ -81,160 +138,6 @@ class BaseTracker(object):
"""Make a functools.partial function to run the given command"""
return functools.partial(self.run_command, name, *args, **options)
def make_fixture(self, request):
"""Make fixture for the tracker
Don't do anything here.
"""
return self
class RetrievalTracker(BaseTracker):
retrieve_keys = None
retrieve_all_keys = None
def make_retrieve_command(self, all=False, raw=False):
"""Make function that retrieves the entry using ${CMD}_show"""
raise NotImplementedError(self._override_me_msg)
def check_retrieve(self, result, all=False, raw=False):
"""Check the plugin's `show` command result"""
raise NotImplementedError(self._override_me_msg)
def retrieve(self, all=False, raw=False):
"""Helper function to retrieve an entry and check the result"""
command = self.make_retrieve_command(all=all, raw=raw)
result = command()
self.check_retrieve(result, all=all, raw=raw)
class SearchTracker(BaseTracker):
def make_find_command(self, *args, **kwargs):
"""Make function that finds the entry using ${CMD}_find
Note that the name (or other search terms) needs to be specified
in arguments.
"""
raise NotImplementedError(self._override_me_msg)
def check_find(self, result, all=False, raw=False):
"""Check the plugin's `find` command result"""
raise NotImplementedError(self._override_me_msg)
def find(self, all=False, raw=False):
"""Helper function to search for this hosts and check the result"""
command = self.make_find_command(self.name, all=all, raw=raw)
result = command()
self.check_find(result, all=all, raw=raw)
class ModificationTracker(BaseTracker):
update_keys = None
singlevalue_keys = None
def make_update_command(self, updates):
"""Make function that modifies the entry using ${CMD}_mod"""
raise NotImplementedError(self._override_me_msg)
def check_update(self, result, extra_keys=()):
"""Check the plugin's `mod` command result"""
raise NotImplementedError(self._override_me_msg)
def update(self, updates, expected_updates=None):
"""Helper function to update this hosts and check the result
The ``updates`` are used as options to the *_mod command,
and the self.attrs is updated with this dict.
Additionally, self.attrs is updated with ``expected_updates``.
"""
if expected_updates is None:
expected_updates = {}
command = self.make_update_command(updates)
result = command()
self.attrs.update(updates)
self.attrs.update(expected_updates)
for key, value in self.attrs.items():
if value is None:
del self.attrs[key]
self.check_update(
result,
extra_keys=set(updates.keys()) | set(expected_updates.keys())
)
class CreationTracker(BaseTracker):
create_keys = None
def __init__(self, default_version=None):
super(CreationTracker, self).__init__(default_version=default_version)
self.exists = False
def make_create_command(self):
"""Make function that creates the plugin entry object."""
raise NotImplementedError(self._override_me_msg)
def track_create(self):
"""Update expected state for host creation
The method should look similar to the following
example of host plugin.
self.attrs = dict(
dn=self.dn,
fqdn=[self.fqdn],
description=[self.description],
... # all required attributes
)
self.exists = True
"""
raise NotImplementedError(self._override_me_msg)
def check_create(self, result):
"""Check plugin's add command result"""
raise NotImplementedError(self._override_me_msg)
def create(self):
"""Helper function to create an entry and check the result"""
self.track_create()
command = self.make_create_command()
result = command()
self.check_create(result)
def ensure_exists(self):
"""If the entry does not exist (according to tracker state), create it
"""
if not self.exists:
self.create()
def make_delete_command(self):
"""Make function that deletes the plugin entry object."""
raise NotImplementedError(self._override_me_msg)
def track_delete(self):
"""Update expected state for host deletion"""
self.exists = False
self.attrs = {}
def check_delete(self, result):
"""Check plugin's `del` command result"""
raise NotImplementedError(self._override_me_msg)
def delete(self):
"""Helper function to delete a host and check the result"""
self.track_delete()
command = self.make_delete_command()
result = command()
self.check_delete(result)
def ensure_missing(self):
"""If the entry exists (according to tracker state), delete it
"""
if self.exists:
self.delete()
def make_fixture(self, request):
"""Make a pytest fixture for this tracker
@@ -258,137 +161,129 @@ class CreationTracker(BaseTracker):
request.addfinalizer(cleanup)
return super(CreationTracker, self).make_fixture(request)
return self
class EnableTracker(BaseTracker):
def __init__(self, default_version=None, enabled=True):
super(EnableTracker, self).__init__(default_version=default_version)
self.original_enabled = enabled
self.enabled = enabled
def make_enable_command(self):
"""Make function that enables the entry using ${CMD}_enable"""
raise NotImplementedError(self._override_me_msg)
def enable(self):
self.enabled = True
command = self.make_enable_command()
result = command()
self.check_enable(result)
def check_enable(self, result):
"""Check the plugin's `enable` command result"""
raise NotImplementedError(self._override_me_msg)
def make_disable_command(self):
"""Make function that disables the entry using ${CMD}_disable"""
raise NotImplementedError(self._override_me_msg)
def disable(self):
self.enabled = False
command = self.make_disable_command()
result = command()
self.check_disable(result)
def check_disable(self, result):
"""Check the plugin's `disable` command result"""
raise NotImplementedError(self._override_me_msg)
def make_fixture(self, request):
"""Make a pytest fixture for this tracker
The fixture ensures the plugin entry is in the same state
(enabled/disabled) after the test as it was before it.
def ensure_exists(self):
"""If the entry does not exist (according to tracker state), create it
"""
def cleanup():
if self.original_enabled != self.enabled:
if self.original_enabled:
command = self.make_enable_command()
else:
command = self.make_disable_command()
command()
if not self.exists:
self.create(force=True)
request.addfinalizer(cleanup)
return super(EnableTracker, self).make_fixture(request)
class ConfigurationTracker(RetrievalTracker, ModificationTracker):
def make_fixture(self, request):
"""Make a pytest fixture for this tracker
Make sure that the state of entry in the end is the same
it was in the begining.
def ensure_missing(self):
"""If the entry exists (according to tracker state), delete it
"""
retrieve = self.make_retrieve_command(all=True)
res = retrieve()['result']
original_state = {}
for k, v in res.items():
if k in self.update_keys:
original_state[k] = v[0] if k in self.singlevalue_keys else v
if self.exists:
self.delete()
def revert():
update = self.make_update_command(original_state)
try:
update()
except errors.EmptyModlist:
# ignore no change
pass
def make_create_command(self, force=True):
"""Make function that creates the plugin entry object."""
raise NotImplementedError(self._override_me_msg)
request.addfinalizer(revert)
def make_delete_command(self):
"""Make function that deletes the plugin entry object."""
raise NotImplementedError(self._override_me_msg)
return super(ConfigurationTracker, self).make_fixture(request)
def make_retrieve_command(self, all=False, raw=False):
"""Make function that retrieves the entry using ${CMD}_show"""
raise NotImplementedError(self._override_me_msg)
def make_find_command(self, *args, **kwargs):
"""Make function that finds the entry using ${CMD}_find
class Tracker(RetrievalTracker, SearchTracker, ModificationTracker,
CreationTracker):
"""Wraps and tracks modifications to a plugin LDAP entry object
Note that the name (or other search terms) needs to be specified
in arguments.
"""
raise NotImplementedError(self._override_me_msg)
Stores a copy of state of a plugin entry object and allows checking that
the state in the database is the same as expected.
This allows creating independent tests: the individual tests check
that the relevant changes have been made. At the same time
the entry doesn't need to be recreated and cleaned up for each test.
def make_update_command(self, updates):
"""Make function that modifies the entry using ${CMD}_mod"""
raise NotImplementedError(self._override_me_msg)
Two attributes are used for tracking: ``exists`` (true if the entry is
supposed to exist) and ``attrs`` (a dict of LDAP attributes that are
expected to be returned from IPA commands).
def create(self, force=True):
"""Helper function to create an entry and check the result"""
self.ensure_missing()
self.track_create()
command = self.make_create_command(force=force)
result = command()
self.check_create(result)
For commonly used operations, there is a helper method, e.g.
``create``, ``update``, or ``find``, that does these steps:
def track_create(self):
"""Update expected state for host creation
* ensure the entry exists (or does not exist, for "create")
* store the expected modifications
* get the IPA command to run, and run it
* check that the result matches the expected state
The method should look similar to the following
example of host plugin.
Tests that require customization of these steps are expected to do them
manually, using lower-level methods.
Especially the first step (ensure the entry exists) is important for
achieving independent tests.
self.attrs = dict(
dn=self.dn,
fqdn=[self.fqdn],
description=[self.description],
... # all required attributes
)
self.exists = True
"""
raise NotImplementedError(self._override_me_msg)
The Tracker object also stores information about the entry, e.g.
``dn``, ``rdn`` and ``name`` which is derived from DN property.
def check_create(self, result):
"""Check plugin's add command result"""
raise NotImplementedError(self._override_me_msg)
To use this class, the programer must subclass it and provide the
implementation of following methods:
def delete(self):
"""Helper function to delete a host and check the result"""
self.ensure_exists()
self.track_delete()
command = self.make_delete_command()
result = command()
self.check_delete(result)
* make_*_command -- implementing the API call for particular plugin
and operation (add, delete, ...)
These methods should use the make_command method
* check_* commands -- an assertion for a plugin command (CRUD)
* track_create -- to make an internal representation of the
entry
def track_delete(self):
"""Update expected state for host deletion"""
self.exists = False
self.attrs = {}
Apart from overriding these methods, the subclass must provide the
distinguished name of the entry in `self.dn` property.
def check_delete(self, result):
"""Check plugin's `del` command result"""
raise NotImplementedError(self._override_me_msg)
It is also required to override the class variables defining the sets
of ldap attributes/keys for these operations specific to the plugin
being implemented. Take the host plugin test for an example.
def retrieve(self, all=False, raw=False):
"""Helper function to retrieve an entry and check the result"""
self.ensure_exists()
command = self.make_retrieve_command(all=all, raw=raw)
result = command()
self.check_retrieve(result, all=all, raw=raw)
The implementation of these methods is not strictly enforced.
A missing method will cause a NotImplementedError during runtime
as a result.
"""
def check_retrieve(self, result, all=False, raw=False):
"""Check the plugin's `show` command result"""
raise NotImplementedError(self._override_me_msg)
def find(self, all=False, raw=False):
"""Helper function to search for this hosts and check the result"""
self.ensure_exists()
command = self.make_find_command(self.name, all=all, raw=raw)
result = command()
self.check_find(result, all=all, raw=raw)
def check_find(self, result, all=False, raw=False):
"""Check the plugin's `find` command result"""
raise NotImplementedError(self._override_me_msg)
def update(self, updates, expected_updates=None):
"""Helper function to update this hosts and check the result
The ``updates`` are used as options to the *_mod command,
and the self.attrs is updated with this dict.
Additionally, self.attrs is updated with ``expected_updates``.
"""
if expected_updates is None:
expected_updates = {}
self.ensure_exists()
command = self.make_update_command(updates)
result = command()
self.attrs.update(updates)
self.attrs.update(expected_updates)
self.check_update(result, extra_keys=set(updates.keys()) |
set(expected_updates.keys()))
def check_update(self, result, extra_keys=()):
"""Check the plugin's `find` command result"""
raise NotImplementedError(self._override_me_msg)

View File

@@ -1,144 +0,0 @@
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
from __future__ import absolute_import
import six
from ipapython.dn import DN
from ipatests.test_xmlrpc.tracker.base import Tracker
from ipatests.util import assert_deepequal
from ipatests.test_xmlrpc.xmlrpc_test import (
fuzzy_issuer,
fuzzy_caid,
fuzzy_base64,
fuzzy_sequence_of,
fuzzy_bytes,
)
from ipatests.test_xmlrpc import objectclasses
if six.PY3:
unicode = str
class CATracker(Tracker):
"""Implementation of a Tracker class for CA plugin."""
ldap_keys = {
'dn', 'cn', 'ipacaid', 'ipacasubjectdn', 'ipacaissuerdn', 'description'
}
cert_keys = {
'certificate',
}
cert_all_keys = {
'certificate_chain',
}
find_keys = ldap_keys
find_all_keys = {'objectclass'} | ldap_keys
retrieve_keys = ldap_keys | cert_keys
retrieve_all_keys = {'objectclass'} | retrieve_keys | cert_all_keys
create_keys = {'objectclass'} | retrieve_keys
update_keys = ldap_keys - {'dn'}
def __init__(self, name, subject, desc=u"Test generated CA",
default_version=None):
super(CATracker, self).__init__(default_version=default_version)
self.attrs = {}
self.ipasubjectdn = subject
self.description = desc
self.dn = DN(('cn', name),
self.api.env.container_ca,
self.api.env.basedn)
def make_create_command(self):
"""Make function that creates the plugin entry object."""
return self.make_command(
'ca_add', self.name, ipacasubjectdn=self.ipasubjectdn,
description=self.description
)
def check_create(self, result):
assert_deepequal(dict(
value=self.name,
summary=u'Created CA "{}"'.format(self.name),
result=dict(self.filter_attrs(self.create_keys))
), result)
def track_create(self):
self.attrs = dict(
dn=unicode(self.dn),
cn=[self.name],
description=[self.description],
ipacasubjectdn=[self.ipasubjectdn],
ipacaissuerdn=[fuzzy_issuer],
ipacaid=[fuzzy_caid],
certificate=fuzzy_base64,
certificate_chain=fuzzy_sequence_of(fuzzy_bytes),
objectclass=objectclasses.ca
)
self.exists = True
def make_delete_command(self):
"""Make function that deletes the plugin entry object."""
return self.make_command('ca_del', self.name)
def check_delete(self, result):
assert_deepequal(dict(
value=[self.name],
summary=u'Deleted CA "{}"'.format(self.name),
result=dict(failed=[])
), result)
def make_retrieve_command(self, all=False, raw=False, **options):
"""Make function that retrieves the entry using ${CMD}_show"""
return self.make_command('ca_show', self.name, all=all, raw=raw,
**options)
def check_retrieve(self, result, all=False, raw=False):
"""Check the plugin's `show` command result"""
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
value=self.name,
summary=None,
result=expected
), result)
def make_find_command(self, *args, **kwargs):
"""Make function that finds the entry using ${CMD}_find
Note that the name (or other search terms) needs to be specified
in arguments.
"""
return self.make_command('ca_find', *args, **kwargs)
def check_find(self, result, all=False, raw=False):
"""Check the plugin's `find` command result"""
if all:
expected = self.filter_attrs(self.find_all_keys)
else:
expected = self.filter_attrs(self.find_keys)
assert_deepequal(dict(
count=1,
truncated=False,
summary=u'1 CA matched',
result=[expected]
), result)
def make_update_command(self, updates):
"""Make function that modifies the entry using ${CMD}_mod"""
return self.make_command('ca_mod', self.name, **updates)
def check_update(self, result, extra_keys=()):
"""Check the plugin's `find` command result"""
assert_deepequal(dict(
value=self.name,
summary=u'Modified CA "{}"'.format(self.name),
result=self.filter_attrs(self.update_keys | set(extra_keys))
), result)

View File

@@ -35,11 +35,10 @@ class CAACLTracker(Tracker):
u'memberuser_user', u'memberuser_group',
u'memberhost_host', u'memberhost_hostgroup',
u'memberservice_service',
u'ipamembercertprofile_certprofile',
u'ipamemberca_ca'}
u'ipamembercertprofile_certprofile'}
category_keys = {
u'ipacacategory', u'ipacertprofilecategory', u'usercategory',
u'hostcategory', u'servicecategory', u'ipacacategory'}
u'hostcategory', u'servicecategory'}
retrieve_keys = {
u'dn', u'cn', u'description', u'ipaenabledflag',
u'ipamemberca', u'ipamembercertprofile', u'memberuser',
@@ -52,15 +51,14 @@ class CAACLTracker(Tracker):
update_keys = create_keys - {u'dn'}
def __init__(self, name, ipacertprofile_category=None, user_category=None,
service_category=None, host_category=None,
ipaca_category=None, description=None, default_version=None):
service_category=None, host_category=None, description=None,
default_version=None):
super(CAACLTracker, self).__init__(default_version=default_version)
self._name = name
self.description = description
self._categories = dict(
ipacertprofilecategory=ipacertprofile_category,
ipacacategory=ipaca_category,
usercategory=user_category,
servicecategory=service_category,
hostcategory=host_category)
@@ -87,7 +85,7 @@ class CAACLTracker(Tracker):
"""
return {cat: [v] for cat, v in self.categories.items() if v}
def make_create_command(self):
def make_create_command(self, force=True):
return self.make_command(u'caacl_add', self.name,
description=self.description,
**self.categories)
@@ -202,7 +200,7 @@ class CAACLTracker(Tracker):
# implemented in standalone test
#
# The methods implemented here will be:
# caacl_{add,remove}_{host, service, certprofile, user, ca}
# caacl_{add,remove}_{host, service, certprofile, user [, subca]}
def _add_acl_component(self, command_name, keys, track):
""" Add a resource into ACL rule and track it.
@@ -358,20 +356,6 @@ class CAACLTracker(Tracker):
return self._remove_acl_component(u'caacl_remove_profile', options, track)
def add_ca(self, ca=None, track=True):
options = {
u'ipamemberca_ca':
{u'ca': ca}}
return self._add_acl_component(u'caacl_add_ca', options, track)
def remove_ca(self, ca=None, track=True):
options = {
u'ipamemberca_ca':
{u'ca': ca}}
return self._remove_acl_component(u'caacl_remove_ca', options, track)
def enable(self):
command = self.make_command(u'caacl_enable', self.name)
self.attrs.update({u'ipaenabledflag': [u'TRUE']})

View File

@@ -1,225 +0,0 @@
#
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
#
from ipapython.dn import DN
from ipatests.test_xmlrpc.tracker.base import Tracker
from ipatests.test_xmlrpc.tracker.base import ConfigurationTracker, EnableTracker
from ipatests.test_xmlrpc import objectclasses
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_string
from ipatests.util import assert_deepequal
class CertmapruleTracker(Tracker, EnableTracker):
""" Tracker for testin certmaprule plugin """
retrieve_keys = {
u'dn',
u'cn',
u'description',
u'ipacertmapmaprule',
u'ipacertmapmatchrule',
u'associateddomain',
u'ipacertmappriority',
u'ipaenabledflag'
}
retrieve_all_keys = retrieve_keys | {u'objectclass'}
create_keys = retrieve_keys | {u'objectclass'}
update_keys = retrieve_keys - {u'dn'}
def __init__(self, cn, description, ipacertmapmaprule,
ipacertmapmatchrule, associateddomain, ipacertmappriority,
default_version=None):
super(CertmapruleTracker, self).__init__(
default_version=default_version)
self.dn = DN((u'cn', cn,),
self.api.env.container_certmaprules,
self.api.env.basedn)
self.options = {
u'description': description,
u'ipacertmapmaprule': ipacertmapmaprule,
u'ipacertmapmatchrule': ipacertmapmatchrule,
u'associateddomain': associateddomain,
u'ipacertmappriority': ipacertmappriority,
}
def make_create_command(self, dont_fill=()):
kwargs = {k: v for k, v in self.options.items() if k not in dont_fill}
return self.make_command('certmaprule_add', self.name, **kwargs)
def track_create(self, dont_fill=()):
self.attrs = {
'dn': self.dn,
'cn': [self.name],
'ipaenabledflag': [u'TRUE'],
'objectclass': objectclasses.certmaprule,
}
self.attrs.update({
k: [v] for k, v in self.options.items() if k not in dont_fill
})
self.exists = True
def check_create(self, result):
assert_deepequal(dict(
value=self.name,
summary=u'Added Certificate Identity Mapping Rule "{}"'
u''.format(self.name),
result=self.filter_attrs(self.create_keys),
), result)
def create(self, dont_fill=()):
self.track_create(dont_fill)
command = self.make_create_command(dont_fill)
result = command()
self.check_create(result)
def make_delete_command(self):
return self.make_command('certmaprule_del', self.name)
def check_delete(self, result):
assert_deepequal(
dict(
value=[self.name],
summary=u'Deleted Certificate Identity Mapping Rule "{}"'
''.format(self.name),
result=dict(failed=[]),
),
result
)
def make_retrieve_command(self, all=False, raw=False):
return self.make_command('certmaprule_show', self.name, all=all,
raw=raw)
def check_retrieve(self, result, all=False, raw=False):
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(
dict(
value=self.name,
summary=None,
result=expected,
),
result
)
def make_find_command(self, *args, **kwargs):
return self.make_command('certmaprule_find', *args, **kwargs)
def check_find(self, result, all=False, raw=False):
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(
dict(
count=1,
truncated=False,
summary=u'1 Certificate Identity Mapping Rule matched',
result=[expected],
),
result
)
def make_update_command(self, updates):
return self.make_command('certmaprule_mod', self.name, **updates)
def check_update(self, result, extra_keys=()):
assert_deepequal(
dict(
value=self.name,
summary=u'Modified Certificate Identity Mapping Rule "{}"'
u''.format(self.name),
result=self.filter_attrs(self.update_keys | set(extra_keys)),
),
result
)
def make_enable_command(self):
return self.make_command('certmaprule_enable', self.name)
def check_enable(self, result):
assert_deepequal(
dict(
value=self.name,
summary=u'Enabled Certificate Identity Mapping Rule "{}"'
u''.format(self.name),
result=True,
),
result
)
def make_disable_command(self):
return self.make_command('certmaprule_disable', self.name)
def check_disable(self, result):
assert_deepequal(
dict(
value=self.name,
summary=u'Disabled Certificate Identity Mapping Rule "{}"'
u''.format(self.name),
result=True,
),
result
)
class CertmapconfigTracker(ConfigurationTracker):
retrieve_keys = {
u'dn',
u'ipacertmappromptusername',
}
retrieve_all_keys = retrieve_keys | {
u'cn',
u'objectclass',
u'aci',
}
update_keys = retrieve_keys - {u'dn'}
singlevalue_keys = {u'ipacertmappromptusername'}
def __init__(self, default_version=None):
super(CertmapconfigTracker, self).__init__(
default_version=default_version)
self.attrs = {
u'dn': DN(self.api.env.container_certmap, self.api.env.basedn),
u'cn': [self.api.env.container_certmap[0].value],
u'objectclass': objectclasses.certmapconfig,
u'aci': [fuzzy_string],
u'ipacertmappromptusername': self.api.Command.certmapconfig_show(
)[u'result'][u'ipacertmappromptusername']
}
def make_update_command(self, updates):
return self.make_command('certmapconfig_mod', **updates)
def check_update(self, result, extra_keys=()):
assert_deepequal(
dict(
value=None,
summary=None,
result=self.filter_attrs(self.update_keys | set(extra_keys)),
),
result
)
def make_retrieve_command(self, all=False, raw=False):
return self.make_command('certmapconfig_show', all=all, raw=raw)
def check_retrieve(self, result, all=False, raw=False):
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(
dict(
value=None,
summary=None,
result=expected,
),
result
)

View File

@@ -1,135 +0,0 @@
#
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
import base64
from cryptography import x509
from cryptography.hazmat.backends import default_backend
import pytest
from ipalib.errors import MutuallyExclusiveError, RequirementError
from ipapython.dn import DN
from ipatests.util import assert_deepequal
class CertmapdataMixin(object):
certmapdata_options = {u'issuer', u'subject', u'certificate',
u'ipacertmapdata'}
def _data_from_options(self, **options):
issuer = None
subject = None
if not self.certmapdata_options & set(options):
raise RequirementError(name=u'certmapdata')
if ({u'issuer', u'subject'} & set(options) and
{u'ipacertmapdata', u'certificate'} & set(options)):
raise MutuallyExclusiveError(reason=u'Mutually exclusive options '
u'provided at the same time.')
if u'issuer' in options and u'subject' not in options:
raise RequirementError(name=u'subject')
if u'subject' in options and u'issuer' not in options:
raise RequirementError(name=u'issuer')
if {u'ipacertmapdata', u'certificate'} & set(options):
try:
data = options[u'ipacertmapdata']
except KeyError:
data = []
else:
if not isinstance(data, list):
data = [data]
try:
certs = options[u'certificate']
except KeyError:
certs = []
else:
if not isinstance(certs, list):
certs = [certs]
for cert in certs:
cert = x509.load_der_x509_certificate(
base64.b64decode(cert),
backend=default_backend()
)
issuer = DN(cert.issuer).x500_text()
subject = DN(cert.subject).x500_text()
data.append(
u'X509:<I>{i}<S>{s}'.format(i=issuer, s=subject)
)
else:
issuer = DN(options[u'issuer']).x500_text()
subject = DN(options[u'subject']).x500_text()
data = [u'X509:<I>{i}<S>{s}'.format(i=issuer, s=subject)]
return set(data)
def _make_add_certmap(self):
raise NotImplementedError("_make_add_certmap method must be "
"implemented in instance.")
def _make_remove_certmap(self):
raise NotImplementedError("_make_remove_certmap method must be "
"implemented in instance.")
def add_certmap(self, **kwargs):
cmd = self._make_add_certmap()
try:
expected_certmapdata = self._data_from_options(**kwargs)
except Exception as e:
with pytest.raises(type(e)):
cmd(**kwargs)
else:
result = cmd(**kwargs)
self.attrs.setdefault(u'ipacertmapdata', []).extend(
expected_certmapdata)
expected = dict(
summary=(u'Added certificate mappings to user '
u'"{}"'.format(self.name)),
value=self.name,
result=dict(
uid=(self.name,),
),
)
if self.attrs[u'ipacertmapdata']:
expected[u'result'][u'ipacertmapdata'] = (
self.attrs[u'ipacertmapdata'])
assert_deepequal(expected, result)
def remove_certmap(self, **kwargs):
cmd = self._make_remove_certmap()
try:
expected_certmapdata = self._data_from_options(**kwargs)
except Exception as e:
with pytest.raises(type(e)):
cmd(**kwargs)
else:
result = cmd(**kwargs)
for data in expected_certmapdata:
self.attrs[u'ipacertmapdata'].remove(data)
expected = dict(
summary=(u'Removed certificate mappings from user '
u'"{}"'.format(self.name)),
value=self.name,
result=dict(
uid=(self.name,),
),
)
if self.attrs[u'ipacertmapdata']:
expected[u'result'][u'ipacertmapdata'] = (
self.attrs[u'ipacertmapdata'])
assert_deepequal(expected, result)

View File

@@ -57,14 +57,7 @@ class CertprofileTracker(Tracker):
content = f.read()
return unicode(content)
def make_create_command(self, extra_lines=None):
"""
:param extra_lines: list of extra lines to append to profile config.
"""
if extra_lines is None:
extra_lines = []
def make_create_command(self, force=True):
if not self.profile:
raise RuntimeError('Tracker object without path to profile '
'cannot be used to create profile entry.')
@@ -72,7 +65,7 @@ class CertprofileTracker(Tracker):
return self.make_command('certprofile_import', self.name,
description=self.description,
ipacertprofilestoreissued=self.store,
file=u'\n'.join([self.profile] + extra_lines))
file=self.profile)
def check_create(self, result):
assert_deepequal(dict(

View File

@@ -12,11 +12,7 @@ from ipatests.util import assert_deepequal, get_group_dn
class GroupTracker(Tracker):
""" Class for host plugin like tests """
retrieve_keys = {u'dn', u'cn', u'gidnumber', u'member_user',
u'member_group', u'member_service', u'description',
u'memberof_group', u'memberofindirect_group',
u'memberindirect_group', u'memberindirect_user',
u'memberindirect_service'}
u'member_group'}
retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass'}
create_keys = retrieve_all_keys
@@ -24,19 +20,16 @@ class GroupTracker(Tracker):
add_member_keys = retrieve_keys | {u'description'}
def __init__(self, name, description=u'Group desc'):
def __init__(self, name):
super(GroupTracker, self).__init__(default_version=None)
self.cn = name
self.description = description
self.dn = get_group_dn(self.cn)
self.dn = get_group_dn(name)
def make_create_command(self, nonposix=False, external=False,
*args, **kwargs):
force=True):
""" Make function that creates a group using 'group-add' """
return self.make_command('group_add', self.cn,
description=self.description,
nonposix=nonposix, external=external,
*args, **kwargs)
nonposix=nonposix, external=external)
def make_delete_command(self):
""" Make function that deletes a group using 'group-del' """
@@ -55,12 +48,23 @@ class GroupTracker(Tracker):
return self.make_command('group_mod', self.cn, **updates)
def make_add_member_command(self, options={}):
""" Make function that adds a member to a group """
""" Make function that adds a member to a group
Attention: only works for one user OR group! """
if u'user' in options:
self.attrs[u'member_user'] = [options[u'user']]
elif u'group' in options:
self.attrs[u'member_group'] = [options[u'group']]
self.adds = options
return self.make_command('group_add_member', self.cn, **options)
def make_remove_member_command(self, options={}):
""" Make function that removes a member from a group """
""" Make function that removes a member from a group
Attention: only works for one user OR group! """
if u'user' in options:
del self.attrs[u'member_user']
elif u'group' in options:
del self.attrs[u'member_group']
return self.make_command('group_remove_member', self.cn, **options)
def make_detach_command(self):
@@ -74,98 +78,12 @@ class GroupTracker(Tracker):
self.attrs = dict(
dn=get_group_dn(self.cn),
cn=[self.cn],
description=[self.description],
gidnumber=[fuzzy_digits],
ipauniqueid=[fuzzy_uuid],
objectclass=objectclasses.posixgroup,
)
self.exists = True
def update(self, updates, expected_updates=None):
"""Helper function to update the group and check the result
Overriding Tracker method for setting self.attrs correctly;
* most attributes stores its value in list
* the rest can be overridden by expected_updates
* allow deleting parametrs if update value is None
"""
if expected_updates is None:
expected_updates = {}
self.ensure_exists()
command = self.make_update_command(updates)
result = command()
for key, value in updates.items():
if value is None:
del self.attrs[key]
else:
self.attrs[key] = [value]
for key, value in expected_updates.items():
if value is None:
del self.attrs[key]
else:
self.attrs[key] = value
self.check_update(
result,
extra_keys=set(updates.keys()) | set(expected_updates.keys())
)
def add_member(self, options):
""" Add a member (group OR user OR service) and performs check """
if u'user' in options:
try:
self.attrs[u'member_user'] =\
self.attrs[u'member_user'] + [options[u'user']]
except KeyError:
self.attrs[u'member_user'] = [options[u'user']]
elif u'group' in options:
try:
self.attrs[u'member_group'] =\
self.attrs[u'member_group'] + [options[u'group']]
except KeyError:
self.attrs[u'member_group'] = [options[u'group']]
elif u'service' in options:
try:
self.attrs[u'member_service'] =\
self.attrs[u'member_service'] + [options[u'service']]
except KeyError:
self.attrs[u'member_service'] = [options[u'service']]
command = self.make_add_member_command(options)
result = command()
self.check_add_member(result)
def remove_member(self, options):
""" Remove a member (group OR user) and performs check """
if u'user' in options:
self.attrs[u'member_user'].remove(options[u'user'])
elif u'group' in options:
self.attrs[u'member_group'].remove(options[u'group'])
elif u'service' in options:
self.attrs[u'member_service'].remove(options[u'service'])
try:
if not self.attrs[u'member_user']:
del self.attrs[u'member_user']
except KeyError:
pass
try:
if not self.attrs[u'member_group']:
del self.attrs[u'member_group']
except KeyError:
pass
try:
if not self.attrs[u'member_service']:
del self.attrs[u'member_service']
except KeyError:
pass
command = self.make_remove_member_command(options)
result = command()
self.check_remove_member(result)
def check_create(self, result):
""" Checks 'group_add' command result """
assert_deepequal(dict(
@@ -221,58 +139,39 @@ class GroupTracker(Tracker):
""" Checks 'group_add_member' command result """
assert_deepequal(dict(
completed=1,
failed={u'member': {u'group': (), u'user': (), u'service': ()}},
failed={u'member': {u'group': (), u'user': ()}},
result=self.filter_attrs(self.add_member_keys)
), result)
def check_add_member_negative(self, result, options={}):
""" Checks 'group_add_member' command result
when expected result is failure of the operation"""
def check_add_member_negative(self, result):
""" Checks 'group_add_member' command result when expected result
is failure of the operation"""
if u'member_user' in self.attrs:
del self.attrs[u'member_user']
elif u'member_group' in self.attrs:
del self.attrs[u'member_group']
expected = dict(
completed=0,
failed={u'member': {u'group': (), u'user': (), u'service': ()}},
failed={u'member': {u'group': (), u'user': ()}},
result=self.filter_attrs(self.add_member_keys)
)
if not options:
try:
options = self.adds
except NameError:
pass
if u'user' in options:
if u'user' in self.adds:
expected[u'failed'][u'member'][u'user'] = [(
options[u'user'], u'no such entry')]
elif u'group' in options:
self.adds[u'user'], u'no such entry')]
elif u'group' in self.adds:
expected[u'failed'][u'member'][u'group'] = [(
options[u'group'], u'no such entry')]
elif u'service' in options:
expected[u'failed'][u'member'][u'service'] = [(
options[u'service'], u'no such entry')]
assert_deepequal(expected, result)
def check_remove_member_negative(self, result, options):
""" Checks 'group_remove_member' command result
when expected result is failure of the operation"""
expected = dict(
completed=0,
failed={u'member': {u'group': (), u'user': (), u'service': ()}},
result=self.filter_attrs(self.add_member_keys)
)
if u'user' in options:
expected[u'failed'][u'member'][u'user'] = [(
options[u'user'], u'This entry is not a member')]
elif u'group' in options:
expected[u'failed'][u'member'][u'group'] = [(
options[u'group'], u'This entry is not a member')]
elif u'service' in options:
expected[u'failed'][u'member'][u'service'] = [(
options[u'service'], u'This entry is not a member')]
self.adds[u'group'], u'no such entry')]
assert_deepequal(expected, result)
def check_remove_member(self, result):
""" Checks 'group_remove_member' command result """
self.check_add_member(result)
assert_deepequal(dict(
completed=1,
failed={u'member': {u'group': (), u'user': ()}},
result=self.filter_attrs(self.add_member_keys)
), result)
def check_detach(self, result):
""" Checks 'group_detach' command result """
@@ -282,3 +181,16 @@ class GroupTracker(Tracker):
self.cn, self.cn),
result=True
), result)
def make_fixture_detach(self, request):
"""Make a pytest fixture for this tracker
The fixture ensures the plugin entry does not exist before
and after the tests that use itself.
"""
def cleanup():
pass
request.addfinalizer(cleanup)
return self

View File

@@ -7,14 +7,12 @@ 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(KerberosAliasMixin, Tracker):
class HostTracker(Tracker):
"""Wraps and tracks modifications to a Host object
Implements the helper functions for host plugin.
@@ -23,14 +21,11 @@ class HostTracker(KerberosAliasMixin, Tracker):
``fqdn`` and ``dn``.
"""
retrieve_keys = {
'dn', 'fqdn', 'description', 'l', 'krbcanonicalname',
'krbprincipalname', 'managedby_host',
'has_keytab', 'has_password', 'issuer',
'dn', 'fqdn', 'description', 'l', 'krbprincipalname', 'managedby_host',
'has_keytab', 'has_password', 'issuer', 'md5_fingerprint',
'serial_number', 'serial_number_hex', 'sha1_fingerprint',
'sha256_fingerprint',
'subject', 'usercertificate', 'valid_not_after', 'valid_not_before',
'macaddress', 'sshpubkeyfp', 'ipaallowedtoperform_read_keys_user',
'memberof_hostgroup', 'memberofindirect_hostgroup',
'ipaallowedtoperform_read_keys_group',
'ipaallowedtoperform_read_keys_host',
'ipaallowedtoperform_read_keys_hostgroup',
@@ -40,19 +35,12 @@ class HostTracker(KerberosAliasMixin, Tracker):
'ipaallowedtoperform_write_keys_hostgroup'}
retrieve_all_keys = retrieve_keys | {
u'cn', u'ipakrbokasdelegate', u'ipakrbrequirespreauth', u'ipauniqueid',
u'krbcanonicalname', u'managing_host', u'objectclass',
u'serverhostname', u'ipakrboktoauthasdelegate',
u'krbpwdpolicyreference'}
u'managing_host', u'objectclass', u'serverhostname'}
create_keys = retrieve_keys | {'objectclass', 'ipauniqueid',
'randompassword'}
update_keys = retrieve_keys - {'dn'}
managedby_keys = retrieve_keys - {'has_keytab', 'has_password'}
allowedto_keys = retrieve_keys - {'has_keytab', 'has_password'}
find_keys = retrieve_keys - {
'has_keytab', 'has_password', 'memberof_hostgroup',
'memberofindirect_hostgroup', 'managedby_host',
}
find_all_keys = retrieve_all_keys - {'has_keytab', 'has_password'}
def __init__(self, name, fqdn=None, default_version=None):
super(HostTracker, self).__init__(default_version=default_version)
@@ -95,14 +83,6 @@ class HostTracker(KerberosAliasMixin, Tracker):
"""Make function that modifies the host using host_mod"""
return self.make_command('host_mod', self.fqdn, **updates)
def create(self, force=True):
"""Helper function to create an entry and check the result"""
self.ensure_missing()
self.track_create()
command = self.make_create_command(force=force)
result = command()
self.check_create(result)
def track_create(self):
"""Update expected state for host creation"""
self.attrs = dict(
@@ -111,7 +91,6 @@ class HostTracker(KerberosAliasMixin, Tracker):
description=[self.description],
l=[self.location],
krbprincipalname=[u'host/%s@%s' % (self.fqdn, self.api.env.realm)],
krbcanonicalname=[u'host/%s@%s' % (self.fqdn, self.api.env.realm)],
objectclass=objectclasses.host,
ipauniqueid=[fuzzy_uuid],
managedby_host=[self.fqdn],
@@ -122,12 +101,6 @@ class HostTracker(KerberosAliasMixin, Tracker):
ipakrbrequirespreauth=True,
managing_host=[self.fqdn],
serverhostname=[self.shortname],
ipakrboktoauthasdelegate=False,
krbpwdpolicyreference=[DN(
u'cn=Default Host Password Policy',
self.api.env.container_host,
self.api.env.basedn,
)],
)
self.exists = True
@@ -162,9 +135,9 @@ class HostTracker(KerberosAliasMixin, Tracker):
def check_find(self, result, all=False, raw=False):
"""Check `host_find` command result"""
if all:
expected = self.filter_attrs(self.find_all_keys)
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.find_keys)
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
count=1,
truncated=False,
@@ -179,23 +152,3 @@ class HostTracker(KerberosAliasMixin, Tracker):
summary=u'Modified host "%s"' % self.fqdn,
result=self.filter_attrs(self.update_keys | set(extra_keys))
), result)
def add_finalizer_certcleanup(self, request):
""" Fixture to cleanup certificate from local host """
cleanup_command = self.make_update_command(
updates={'usercertificate':''})
def cleanup():
try:
cleanup_command()
except errors.EmptyModlist:
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

@@ -1,257 +0,0 @@
#
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
from ipatests.test_xmlrpc import objectclasses
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_uuid
from ipatests.test_xmlrpc.tracker.base import Tracker
from ipatests.util import assert_deepequal
from ipalib import api
from ipapython.dn import DN
class HostGroupTracker(Tracker):
""" Class for tracking hostgroups """
retrieve_keys = {u'dn', u'cn', u'member_host', u'description',
u'member_hostgroup', u'memberindirect_host'}
retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass',
u'mepmanagedentry'}
create_keys = retrieve_all_keys
update_keys = retrieve_keys - {u'dn'}
add_member_keys = retrieve_keys | {u'member_host'}
find_keys = {
u'dn', u'cn', u'description',
}
find_all_keys = {
u'dn', u'cn', u'member_host', u'description', u'member_hostgroup',
u'memberindirect_host', u'ipauniqueid', u'objectclass',
u'mepmanagedentry',
}
def __init__(self, name, description=u'HostGroup desc'):
super(HostGroupTracker, self).__init__(default_version=None)
self.cn = name
self.description = description
self.dn = DN(('cn', self.cn), ('cn', 'hostgroups'),
('cn', 'accounts'), api.env.basedn)
def make_create_command(self,
force=True, *args, **kwargs):
""" Make function that creates a hostgroup using 'hostgroup-add' """
return self.make_command('hostgroup_add', self.cn,
description=self.description,
*args, **kwargs)
def make_delete_command(self):
""" Make function that deletes a hostgroup using 'hostgroup-del' """
return self.make_command('hostgroup_del', self.cn)
def make_retrieve_command(self, all=False, raw=False):
""" Make function that retrieves a hostgroup using 'hostgroup-show' """
return self.make_command('hostgroup_show', self.cn, all=all)
def make_find_command(self, *args, **kwargs):
""" Make function that searches for a hostgroup
using 'hostgroup-find' """
return self.make_command('hostgroup_find', *args, **kwargs)
def make_update_command(self, updates):
""" Make function that updates a hostgroup using 'hostgroup-mod' """
return self.make_command('hostgroup_mod', self.cn, **updates)
def make_add_member_command(self, options={}):
""" Make function that adds a member to a hostgroup """
return self.make_command('hostgroup_add_member', self.cn, **options)
def make_remove_member_command(self, options={}):
""" Make function that removes a member from a hostgroup """
return self.make_command('hostgroup_remove_member', self.cn, **options)
def track_create(self):
""" Updates expected state for hostgroup creation"""
self.attrs = dict(
dn=self.dn,
mepmanagedentry=[DN(('cn', self.cn), ('cn', 'ng'),
('cn', 'alt'), api.env.basedn)],
cn=[self.cn],
description=[self.description],
ipauniqueid=[fuzzy_uuid],
objectclass=objectclasses.hostgroup,
)
self.exists = True
def add_member(self, options):
""" Add a member host to hostgroup and perform check """
if u'host' in options:
try:
self.attrs[u'member_host'] =\
self.attrs[u'member_host'] + [options[u'host']]
except KeyError:
self.attrs[u'member_host'] = [options[u'host']]
# search for hosts in the target hostgroup and
# add them as memberindirect hosts
elif u'hostgroup' in options:
try:
self.attrs[u'member_hostgroup'] =\
self.attrs[u'member_hostgroup'] + [options[u'hostgroup']]
except KeyError:
self.attrs[u'member_hostgroup'] = [options[u'hostgroup']]
command = self.make_add_member_command(options)
result = command()
self.check_add_member(result)
def remove_member(self, options):
""" Remove a member host from hostgroup and perform check """
if u'host' in options:
self.attrs[u'member_host'].remove(options[u'host'])
elif u'hostgroup' in options:
self.attrs[u'member_hostgroup'].remove(options[u'hostgroup'])
try:
if not self.attrs[u'member_host']:
del self.attrs[u'member_host']
except KeyError:
pass
try:
if not self.attrs[u'member_hostgroup']:
del self.attrs[u'member_hostgroup']
except KeyError:
pass
command = self.make_remove_member_command(options)
result = command()
self.check_remove_member(result)
def update(self, updates, expected_updates=None):
"""Helper function to update this user and check the result
Overriding Tracker method for setting self.attrs correctly;
* most attributes stores its value in list
* the rest can be overridden by expected_updates
* allow deleting parametrs if update value is None
"""
if expected_updates is None:
expected_updates = {}
self.ensure_exists()
command = self.make_update_command(updates)
result = command()
for key, value in updates.items():
if value is None:
del self.attrs[key]
else:
self.attrs[key] = [value]
for key, value in expected_updates.items():
if value is None:
del self.attrs[key]
else:
self.attrs[key] = value
self.check_update(
result,
extra_keys=set(updates.keys()) | set(expected_updates.keys())
)
def check_create(self, result):
""" Checks 'hostgroup_add' command result """
assert_deepequal(dict(
value=self.cn,
summary=u'Added hostgroup "%s"' % self.cn,
result=self.filter_attrs(self.create_keys)
), result)
def check_delete(self, result):
""" Checks 'hostgroup_del' command result """
assert_deepequal(dict(
value=[self.cn],
summary=u'Deleted hostgroup "%s"' % self.cn,
result=dict(failed=[]),
), result)
def check_retrieve(self, result, all=False, raw=False):
""" Checks 'hostgroup_show' command result """
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
value=self.cn,
summary=None,
result=expected
), result)
def check_find(self, result, all=False, raw=False):
""" Checks 'hostgroup_find' command result """
if all:
expected = self.filter_attrs(self.find_all_keys)
else:
expected = self.filter_attrs(self.find_keys)
assert_deepequal(dict(
count=1,
truncated=False,
summary=u'1 hostgroup matched',
result=[expected],
), result)
def check_update(self, result, extra_keys={}):
""" Checks 'hostgroup_mod' command result """
assert_deepequal(dict(
value=self.cn,
summary=u'Modified hostgroup "%s"' % self.cn,
result=self.filter_attrs(self.update_keys | set(extra_keys))
), result)
def check_add_member(self, result):
""" Checks 'hostgroup_add_member' command result """
assert_deepequal(dict(
completed=1,
failed={u'member': {u'host': (), u'hostgroup': ()}},
result=self.filter_attrs(self.add_member_keys)
), result)
def check_add_member_negative(self, result, options):
""" Checks 'hostgroup_add_member' command result
when expected result is failure of the operation"""
expected = dict(
completed=0,
failed={u'member': {u'hostgroup': (), u'user': ()}},
result=self.filter_attrs(self.add_member_keys)
)
if u'host' in options:
expected[u'failed'][u'member'][u'host'] = [(
options[u'host'], u'no such entry')]
elif u'hostgroup' in options:
expected[u'failed'][u'member'][u'hostgroup'] = [(
options[u'hostgroup'], u'no such entry')]
assert_deepequal(expected, result)
def check_remove_member_negative(self, result, options):
""" Checks 'hostgroup_remove_member' command result
when expected result is failure of the operation"""
expected = dict(
completed=0,
failed={u'member': {u'hostgroup': (), u'host': ()}},
result=self.filter_attrs(self.add_member_keys)
)
if u'user' in options:
expected[u'failed'][u'member'][u'host'] = [(
options[u'user'], u'This entry is not a member')]
elif u'hostgroup' in options:
expected[u'failed'][u'member'][u'hostgroup'] = [(
options[u'hostgroup'], u'This entry is not a member')]
assert_deepequal(expected, result)
def check_remove_member(self, result):
""" Checks 'hostgroup_remove_member' command result """
self.check_add_member(result)

View File

@@ -1,116 +0,0 @@
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
from ipalib import api
from ipapython.dn import DN
from ipatests.test_xmlrpc.tracker.base import Tracker
from ipatests.util import assert_deepequal
from ipatests.test_xmlrpc import objectclasses
import six
if six.PY3:
unicode = str
class IdviewTracker(Tracker):
"""Class for idview tests"""
retrieve_keys = {
u'cn'
}
retrieve_all_keys = retrieve_keys | {
u'description', u'objectclass', u'dn'
}
create_keys = retrieve_all_keys
find_all_keys = retrieve_all_keys
def del_cert_from_idoverrideuser(self, username, cert):
result = api.Command.idoverrideuser_remove_cert(
self.cn, username, usercertificate=cert
)
return dict(
usercertificate=result['result'].get('usercertificate', []),
value=result.get('value'),
summary=result.get('summary')
)
def add_cert_to_idoverrideuser(self, username, cert):
result = api.Command.idoverrideuser_add_cert(
self.cn, username, usercertificate=cert
)
return dict(
usercertificate=result['result'].get('usercertificate', []),
value=result.get('value'),
summary=result.get('summary')
)
def __init__(self, cn, **kwargs):
super(IdviewTracker, self).__init__(default_version=None)
self.cn = cn
self.dn = DN(('cn', cn), api.env.container_views, api.env.basedn)
self.kwargs = kwargs
def make_create_command(self):
return self.make_command(
'idview_add', self.cn, **self.kwargs
)
def make_delete_command(self):
return self.make_command(
'idview_del', self.cn, **self.kwargs
)
def make_retrieve_command(self, all=False, raw=False):
""" Make function that retrieves a idview using idview-show """
return self.make_command('idview_show', self.cn, all=all)
def make_find_command(self, *args, **kwargs):
""" Make function that finds idview using idview-find """
return self.make_command('idview_find', *args, **kwargs)
def make_update_command(self, updates):
""" Make function that updates idview using idview-mod """
return self.make_command('idview_mod', self.cn, **updates)
def track_create(self):
self.attrs = dict(
cn=(self.cn,),
dn=unicode(self.dn),
idoverrideusers=[],
objectclass=objectclasses.idview
)
if 'description' in self.kwargs:
self.attrs['description'] = self.kwargs['description']
self.exists = True
def make_add_idoverrideuser_command(self, username, options=None):
options = options or {}
""" Make function that adds a member to a group """
return self.make_command('idoverrideuser_add', self.cn, username,
**options)
def idoverrideuser_add(self, user):
command = self.make_add_idoverrideuser_command(user.name)
result = command()
self.attrs['idoverrideusers'].append(result['value'])
self.check_idoverrideuser_add(result, user)
def check_create(self, result, extra_keys=()):
""" Check 'user-add' command result """
expected = self.filter_attrs(self.create_keys | set(extra_keys))
assert_deepequal(dict(
summary=u'Added ID View "%s"' % self.cn,
result=self.filter_attrs(expected),
value=self.cn
), result)
def check_idoverrideuser_add(self, result, user):
""" Checks 'group_add_member' command result """
assert_deepequal(
u'Added User ID override "%s"' % user.name,
result['summary']
)

View File

@@ -1,99 +0,0 @@
#
# 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

@@ -1,157 +0,0 @@
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
from __future__ import absolute_import
import six
from ipapython.dn import DN
from ipapython.dnsutil import DNSName
from ipatests.util import assert_deepequal
from ipatests.test_xmlrpc.tracker.base import Tracker
if six.PY3:
unicode = str
class LocationTracker(Tracker):
"""Tracker for IPA Location tests"""
retrieve_keys = {
'idnsname', 'description', 'dn', 'servers_server', 'dns_server'}
retrieve_all_keys = retrieve_keys | {'objectclass'}
create_keys = {'idnsname', 'description', 'dn', 'objectclass'}
find_keys = {'idnsname', 'description', 'dn',}
find_all_keys = find_keys | {'objectclass'}
update_keys = {'idnsname', 'description'}
def __init__(self, name, description=u"Location description"):
super(LocationTracker, self).__init__(default_version=None)
# ugly hack to allow testing invalid inputs
try:
self.idnsname_obj = DNSName(name)
except Exception:
self.idnsname_obj = DNSName(u"placeholder-for-invalid-value")
self.idnsname = name
self.description = description
self.dn = DN(
('idnsname', self.idnsname_obj.ToASCII()),
'cn=locations',
'cn=etc', self.api.env.basedn
)
self.servers = {}
def make_create_command(self):
"""Make function that creates this location using location-add"""
return self.make_command(
'location_add', self.idnsname, description=self.description,
)
def make_delete_command(self):
"""Make function that removes this location using location-del"""
return self.make_command('location_del', self.idnsname)
def make_retrieve_command(self, all=False, raw=False):
"""Make function that retrieves this location using location-show"""
return self.make_command(
'location_show', self.idnsname, all=all, raw=raw
)
def make_find_command(self, *args, **kwargs):
"""Make function that finds locations using location-find"""
return self.make_command('location_find', *args, **kwargs)
def make_update_command(self, updates):
"""Make function that modifies the location using location-mod"""
return self.make_command('location_mod', self.idnsname, **updates)
def track_create(self):
"""Update expected state for location creation"""
self.attrs = dict(
dn=self.dn,
idnsname=[self.idnsname_obj],
description=[self.description],
objectclass=[u'top', u'ipaLocationObject'],
)
self.exists = True
def check_create(self, result):
"""Check `location-add` command result"""
assert_deepequal(dict(
value=self.idnsname_obj,
summary=u'Added IPA location "{loc}"'.format(loc=self.idnsname),
result=self.filter_attrs(self.create_keys)
), result)
def check_delete(self, result):
"""Check `location-del` command result"""
assert_deepequal(dict(
value=[self.idnsname_obj],
summary=u'Deleted IPA location "{loc}"'.format(loc=self.idnsname),
result=dict(failed=[]),
), result)
def check_retrieve(self, result, all=False, raw=False):
"""Check `location-show` command result"""
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
value=self.idnsname_obj,
summary=None,
result=expected,
servers=self.servers,
), result)
def check_find(self, result, all=False, raw=False):
"""Check `location-find` command result"""
if all:
expected = self.filter_attrs(self.find_all_keys)
else:
expected = self.filter_attrs(self.find_keys)
assert_deepequal(dict(
count=1,
truncated=False,
summary=u'1 IPA location matched',
result=[expected],
), result)
def check_update(self, result, extra_keys=()):
"""Check `location-update` command result"""
assert_deepequal(dict(
value=self.idnsname_obj,
summary=u'Modified IPA location "{loc}"'.format(loc=self.idnsname),
result=self.filter_attrs(self.update_keys | set(extra_keys))
), result)
def add_server_to_location(
self, server_name, weight=100, relative_weight=u"100.0%"):
self.attrs.setdefault('servers_server', []).append(server_name)
self.attrs.setdefault('dns_server', []).append(server_name)
self.servers[server_name] = {
'cn': [server_name],
'ipaserviceweight': [unicode(weight)],
'service_relative_weight': [relative_weight],
'enabled_role_servrole': lambda other: True
}
def remove_server_from_location(self, server_name):
if 'servers_server' in self.attrs:
try:
self.attrs['servers_server'].remove(server_name)
self.attrs['dns_server'].remove(server_name)
except ValueError:
pass
else:
if not self.attrs['servers_server']:
del self.attrs['servers_server']
if not self.attrs['dns_server']:
del self.attrs['dns_server']
try:
del self.servers[server_name]
except KeyError:
pass

View File

@@ -1,149 +0,0 @@
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
from __future__ import absolute_import
from ipalib import errors
from ipapython.dn import DN
from ipatests.util import assert_deepequal
from ipatests.test_xmlrpc.tracker.base import Tracker
class ServerTracker(Tracker):
"""Tracker for IPA Location tests"""
retrieve_keys = {
'cn', 'dn', 'ipamaxdomainlevel', 'ipamindomainlevel',
'iparepltopomanagedsuffix_topologysuffix', 'ipalocation_location',
'ipaserviceweight', 'enabled_role_servrole'
}
retrieve_all_keys = retrieve_keys | {'objectclass'}
create_keys = retrieve_keys | {'objectclass'}
find_keys = {
'cn', 'dn', 'ipamaxdomainlevel', 'ipamindomainlevel',
'ipaserviceweight',
}
find_all_keys = retrieve_all_keys
update_keys = {
'cn', 'ipamaxdomainlevel', 'ipamindomainlevel',
'ipalocation_location', 'ipaserviceweight',
}
def __init__(self, name):
super(ServerTracker, self).__init__(default_version=None)
self.server_name = name
self.dn = DN(
('cn', self.server_name),
'cn=masters,cn=ipa,cn=etc',
self.api.env.basedn
)
self.exists = True # we cannot add server manually using server-add
self.attrs = dict(
dn=self.dn,
cn=[self.server_name],
iparepltopomanagedsuffix_topologysuffix=[u'domain', u'ca'],
objectclass=[
u"ipalocationmember",
u"ipaReplTopoManagedServer",
u"top",
u"ipaConfigObject",
u"nsContainer",
u"ipaSupportedDomainLevelConfig"
],
ipamaxdomainlevel=[u"1"],
ipamindomainlevel=[u"1"],
)
self.exists = True
def make_retrieve_command(self, all=False, raw=False):
"""Make function that retrieves this server using server-show"""
return self.make_command(
'server_show', self.name, all=all, raw=raw
)
def make_find_command(self, *args, **kwargs):
"""Make function that finds servers using server-find"""
return self.make_command('server_find', *args, **kwargs)
def make_update_command(self, updates):
"""Make function that modifies the server using server-mod"""
return self.make_command('server_mod', self.name, **updates)
def check_retrieve(self, result, all=False, raw=False):
"""Check `server-show` command result"""
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
value=self.server_name,
summary=None,
result=expected,
), result)
def check_find(self, result, all=False, raw=False):
"""Check `server-find` command result"""
if all:
expected = self.filter_attrs(self.find_all_keys)
else:
expected = self.filter_attrs(self.find_keys)
assert_deepequal(dict(
count=1,
truncated=False,
summary=u'1 IPA server matched',
result=[expected],
), result)
def check_find_nomatch(self, result):
""" Check 'server-find' command result when no match is expected """
assert_deepequal(dict(
count=0,
truncated=False,
summary=u'0 IPA servers matched',
result=[],
), result)
def check_update(self, result, extra_keys=(), messages=None):
"""Check `server-update` command result"""
expected = dict(
value=self.server_name,
summary=u'Modified IPA server "{server}"'.format(
server=self.name),
result=self.filter_attrs(self.update_keys | set(extra_keys))
)
if messages:
expected['messages'] = messages
assert_deepequal(expected, result)
def update(self, updates, expected_updates=None, messages=None):
if expected_updates is None:
expected_updates = {}
self.ensure_exists()
command = self.make_update_command(updates)
result = command()
self.attrs.update(updates)
self.attrs.update(expected_updates)
for key, value in list(self.attrs.items()):
if value is None:
del self.attrs[key]
self.check_update(
result,
extra_keys=set(updates.keys()) | set(expected_updates.keys()),
messages=messages)
def make_fixture_clean_location(self, request):
command = self.make_update_command({u'ipalocation_location': None})
try:
command()
except errors.EmptyModlist:
pass
def cleanup():
try:
command()
except errors.EmptyModlist:
pass
request.addfinalizer(cleanup)
return self

View File

@@ -1,179 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
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
from ipapython.dn import DN
if six.PY3:
unicode = str
class ServiceTracker(KerberosAliasMixin, Tracker):
"""
Tracker class for service plugin
So far does not include methods for these commands:
service-add-host
service-remove-host
service-allow-retrieve-keytab
service-disallow-retrieve-keytab
service-allow-create-keytab
service-disallow-create-keytab
service-disable
service-add-cert
service-remove-cert
"""
retrieve_keys = {
u'dn', u'krbprincipalname', u'usercertificate', u'has_keytab',
u'ipakrbauthzdata', u'ipaallowedtoperform', u'subject',
u'managedby', u'serial_number', u'serial_number_hex', u'issuer',
u'valid_not_before', u'valid_not_after', u'sha1_fingerprint',
u'sha256_fingerprint', u'krbprincipalauthind', u'managedby_host',
u'krbcanonicalname'}
retrieve_all_keys = retrieve_keys | {
u'ipaKrbPrincipalAlias', u'ipaUniqueID', u'krbExtraData',
u'krbLastPwdChange', u'krbLoginFailedCount', u'memberof',
u'objectClass', u'ipakrbrequirespreauth', u'krbpwdpolicyreference',
u'ipakrbokasdelegate', u'ipakrboktoauthasdelegate'}
create_keys = (retrieve_keys | {u'objectclass', u'ipauniqueid'}) - {
u'usercertificate', u'has_keytab'}
update_keys = retrieve_keys - {u'dn', u'has_keytab'}
def __init__(self, name, host_fqdn, options=None):
super(ServiceTracker, self).__init__(default_version=None)
self._name = u"{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 or {}
@property
def name(self):
return self._name
def make_create_command(self, force=True):
""" Make function that creates a service """
return self.make_command('service_add', self.name,
force=force, **self.options)
def make_delete_command(self):
""" Make function that deletes a service """
return self.make_command('service_del', self.name)
def make_retrieve_command(self, all=False, raw=False):
""" Make function that retrieves a service """
return self.make_command('service_show', self.name, all=all)
def make_find_command(self, *args, **kwargs):
""" Make function that searches for a service"""
return self.make_command('service_find', *args, **kwargs)
def make_update_command(self, updates):
""" Make function that updates a service """
return self.make_command('service_mod', self.name, **updates)
def make_disable_command(self):
""" make command that disables the service principal """
return self.make_command('service_disable', self.name)
def create(self, force=True):
"""Helper function to create an entry and check the result"""
self.ensure_missing()
self.track_create()
command = self.make_create_command(force=force)
result = command()
self.check_create(result)
def track_create(self, **options):
""" Update expected state for service creation """
self.attrs = {
u'dn': self.dn,
u'krbprincipalname': [u'{0}'.format(self.name)],
u'objectclass': objectclasses.service,
u'ipauniqueid': [fuzzy_uuid],
u'managedby_host': [self.host_fqdn],
u'krbcanonicalname': [u'{0}'.format(self.name)],
u'has_keytab': False,
u'ipakrboktoauthasdelegate': False,
u'krbpwdpolicyreference': [DN(
u'cn=Default Service Password Policy',
self.api.env.container_service,
self.api.env.basedn,
)],
}
for key in self.options:
self.attrs[key] = [self.options[key]]
self.exists = True
def check_create(self, result):
""" Check service-add command result """
assert_deepequal({
u'value': u'{0}'.format(self.name),
u'summary': u'Added service "{0}"'.format(self.name),
u'result': self.filter_attrs(self.create_keys)
}, result)
def check_delete(self, result):
""" Check service-del command result """
assert_deepequal({
u'value': [u'{0}'.format(self.name)],
u'summary': u'Deleted service "{0}"'.format(self.name),
u'result': {u'failed': []}
}, result)
def check_retrieve(self, result, all=False, raw=False):
""" Check service-show command result """
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal({
u'value': u'{0}'.format(self.name),
u'summary': None,
u'result': expected,
}, result)
def check_find(self, result, all=False, raw=False):
""" Check service-find command result """
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal({
u'count': 1,
u'truncated': False,
u'summary': u'1 service matched',
u'result': [expected]
}, result)
def check_update(self, result, extra_keys=()):
""" Check service-mod command result """
assert_deepequal({
u'value': u'{0}'.format(self.name),
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

@@ -7,12 +7,11 @@ import six
from ipalib import api, errors
from ipatests.test_xmlrpc.tracker.base import Tracker
from ipatests.test_xmlrpc.tracker.kerberos_aliases import KerberosAliasMixin
from ipatests.test_xmlrpc import objectclasses
from ipatests.test_xmlrpc.xmlrpc_test import (
Fuzzy, fuzzy_string, fuzzy_dergeneralizedtime, raises_exact)
fuzzy_string, fuzzy_dergeneralizedtime, raises_exact)
from ipatests.util import assert_deepequal
from ipatests.util import assert_deepequal, get_user_dn
from ipapython.dn import DN
if six.PY3:
@@ -25,11 +24,11 @@ sshpubkey = (u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGAX3xAeLeaJggwTqMjxNwa6X'
'cSIn3JrXynlvui4MixvrtX6zx+O/bBo68o8/eZD26QrahVbA09fivrn/4h3TM01'
'9Eu/c2jOdckfU3cHUV/3Tno5d6JicibyaoDDK7S/yjdn5jhaz8MSEayQvFkZkiF'
'0L public key test')
sshpubkeyfp = (u'SHA256:cStA9o5TRSARbeketEOooMUMSWRSsArIAXloBZ4vNsE '
sshpubkeyfp = (u'13:67:6B:BF:4E:A2:05:8E:AE:25:8B:A1:31:DE:6F:1B '
'public key test (ssh-rsa)')
class StageUserTracker(KerberosAliasMixin, Tracker):
class StageUserTracker(Tracker):
""" Tracker class for staged user LDAP object
Implements helper functions for host plugin.
@@ -45,10 +44,10 @@ class StageUserTracker(KerberosAliasMixin, Tracker):
u'usercertificate', u'dn', u'has_keytab', u'has_password',
u'street', u'postalcode', u'facsimiletelephonenumber',
u'carlicense', u'ipasshpubkey', u'sshpubkeyfp', u'l',
u'st', u'mobile', u'pager', u'krbcanonicalname', u'krbprincipalname'}
u'st', u'mobile', u'pager', }
retrieve_all_keys = retrieve_keys | {
u'cn', u'ipauniqueid', u'objectclass', u'description',
u'displayname', u'gecos', u'initials', u'manager'}
u'displayname', u'gecos', u'initials', u'krbprincipalname', u'manager'}
create_keys = retrieve_all_keys | {
u'objectclass', u'ipauniqueid', u'randompassword',
@@ -59,48 +58,23 @@ class StageUserTracker(KerberosAliasMixin, Tracker):
activate_keys = retrieve_keys | {
u'has_keytab', u'has_password', u'nsaccountlock'}
find_keys = retrieve_keys - {u'has_keytab', u'has_password'}
find_all_keys = retrieve_all_keys - {u'has_keytab', u'has_password'}
def __init__(self, name=None, givenname=None, sn=None, **kwargs):
""" Check for non-empty unicode string for the required attributes
in the init method """
if not (isinstance(givenname, six.string_types) and givenname):
raise ValueError(
"Invalid first name provided: {!r}".format(givenname)
)
if not (isinstance(sn, six.string_types) and sn):
raise ValueError("Invalid second name provided: {!r}".format(sn))
def __init__(self, name, givenname, sn, **kwargs):
super(StageUserTracker, self).__init__(default_version=None)
self.uid = unicode(name)
self.givenname = unicode(givenname)
self.sn = unicode(sn)
self.uid = name
self.givenname = givenname
self.sn = sn
self.dn = DN(
('uid', self.uid), api.env.container_stageuser, api.env.basedn)
self.kwargs = kwargs
def make_create_command(self, options=None):
""" Make function that creates a staged user using stageuser-add
with all set of attributes and with minimal values,
where uid is not specified """
def make_create_command(self, options=None, force=None):
""" Make function that creates a staged user using stageuser-add """
if options is not None:
self.kwargs = options
if self.uid is not None:
return self.make_command(
'stageuser_add', self.uid,
givenname=self.givenname,
sn=self.sn, **self.kwargs
)
else:
return self.make_command(
'stageuser_add',
givenname=self.givenname,
sn=self.sn, **self.kwargs
)
return self.make_command('stageuser_add', self.uid,
givenname=self.givenname,
sn=self.sn, **self.kwargs)
def make_delete_command(self):
""" Make function that deletes a staged user using stageuser-del """
@@ -140,7 +114,6 @@ class StageUserTracker(KerberosAliasMixin, Tracker):
uidnumber=[u'-1'],
gidnumber=[u'-1'],
krbprincipalname=[u'%s@%s' % (self.uid, self.api.env.realm)],
krbcanonicalname=[u'%s@%s' % (self.uid, self.api.env.realm)],
mail=[u'%s@%s' % (self.uid, self.api.env.domain)],
gecos=[u'%s %s' % (self.givenname, self.sn)],
loginshell=[u'/bin/sh'],
@@ -154,19 +127,18 @@ class StageUserTracker(KerberosAliasMixin, Tracker):
self.attrs[key] = [u'%s@%s' % (
(self.kwargs[key].split('@'))[0].lower(),
(self.kwargs[key].split('@'))[1])]
self.attrs[u'krbcanonicalname'] = self.attrs[key]
elif key == u'manager':
self.attrs[key] = [self.kwargs[key]]
elif key == u'ipasshpubkey':
self.attrs[u'sshpubkeyfp'] = [sshpubkeyfp]
self.attrs[key] = [self.kwargs[key]]
elif key in {u'random', u'userpassword'}:
self.attrs[u'krbextradata'] = [Fuzzy(type=bytes)]
elif key == u'random' or key == u'userpassword':
self.attrs[u'krbextradata'] = [fuzzy_string]
self.attrs[u'krbpasswordexpiration'] = [
fuzzy_dergeneralizedtime]
self.attrs[u'krblastpwdchange'] = [fuzzy_dergeneralizedtime]
self.attrs[u'krbprincipalkey'] = [Fuzzy(type=bytes)]
self.attrs[u'userpassword'] = [Fuzzy(type=bytes)]
self.attrs[u'krbprincipalkey'] = [fuzzy_string]
self.attrs[u'userpassword'] = [fuzzy_string]
self.attrs[u'has_keytab'] = True
self.attrs[u'has_password'] = True
if key == u'random':
@@ -216,9 +188,9 @@ class StageUserTracker(KerberosAliasMixin, Tracker):
def check_find(self, result, all=False, raw=False):
""" Check 'stageuser-find' command result """
if all:
expected = self.filter_attrs(self.find_all_keys)
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.find_keys)
expected = self.filter_attrs(self.retrieve_keys)
# small override because stageuser-find returns different
# type of nsaccountlock value than DS, but overall the value
@@ -293,9 +265,3 @@ class StageUserTracker(KerberosAliasMixin, Tracker):
self.dn = DN(
('uid', self.uid), api.env.container_stageuser, api.env.basedn)
self.attrs[u'dn'] = self.dn
def _make_add_alias_cmd(self):
return self.make_command('stageuser_add_principal', self.name)
def _make_remove_alias_cmd(self):
return self.make_command('stageuser_remove_principal', self.name)

View File

@@ -1,116 +0,0 @@
#
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
from ipatests.test_xmlrpc import objectclasses
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_uuid, fuzzy_sudocmddn
from ipatests.test_xmlrpc.tracker.base import Tracker
from ipatests.util import assert_deepequal
class SudoCmdTracker(Tracker):
""" Class for tracking sudo commands """
retrieve_keys = {u'dn', u'sudocmd', u'description',
u'memberof_sudocmdgroup'}
retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass'}
create_keys = retrieve_all_keys
update_keys = retrieve_keys - {u'dn'}
find_keys = {u'dn', u'sudocmd', u'description'}
find_all_keys = retrieve_all_keys
def __init__(self, command, description="Test sudo command"):
super(SudoCmdTracker, self).__init__(default_version=None)
self.cmd = command
self.dn = fuzzy_sudocmddn
self.description = description
@property
def name(self):
""" Property holding the name of the entry in LDAP """
return self.cmd
def make_create_command(self):
""" Make function that creates a sudocmd using 'sudocmd-add' """
return self.make_command('sudocmd_add', self.cmd,
description=self.description)
def make_delete_command(self):
""" Make function that deletes a sudocmd using 'sudocmd-del' """
return self.make_command('sudocmd_del', self.cmd)
def make_retrieve_command(self, all=False, raw=False):
""" Make function that retrieves a sudocmd using 'sudocmd-show' """
return self.make_command('sudocmd_show', self.cmd, all=all)
def make_find_command(self, *args, **kwargs):
""" Make function that searches for a sudocmd using 'sudocmd-find' """
return self.make_command('sudocmd_find', *args, **kwargs)
def make_update_command(self, updates):
""" Make function that updates a sudocmd using 'sudocmd-mod' """
return self.make_command('sudocmd_mod', self.cmd, **updates)
def track_create(self):
""" Updates expected state for sudocmd creation"""
self.attrs = dict(
dn=self.dn,
sudocmd=[self.cmd],
description=[self.description],
ipauniqueid=[fuzzy_uuid],
objectclass=objectclasses.sudocmd,
)
self.exists = True
def check_create(self, result):
""" Checks 'sudocmd_add' command result """
assert_deepequal(dict(
value=self.cmd,
summary=u'Added Sudo Command "%s"' % self.cmd,
result=self.filter_attrs(self.create_keys)
), result)
def check_delete(self, result):
""" Checks 'sudocmd_del' command result """
assert_deepequal(dict(
value=[self.cmd],
summary=u'Deleted Sudo Command "%s"' % self.cmd,
result=dict(failed=[]),
), result)
def check_retrieve(self, result, all=False, raw=False):
""" Checks 'sudocmd_show' command result """
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
value=self.cmd,
summary=None,
result=expected
), result)
def check_find(self, result, all=False, raw=False):
""" Checks 'sudocmd_find' command result """
if all:
expected = self.filter_attrs(self.find_all_keys)
else:
expected = self.filter_attrs(self.find_keys)
assert_deepequal(dict(
count=1,
truncated=False,
summary=u'1 Sudo Command matched',
result=[expected],
), result)
def check_update(self, result, extra_keys={}):
""" Checks 'sudocmd_mod' command result """
assert_deepequal(dict(
value=self.cmd,
summary=u'Modified Sudo Command "%s"' % self.cmd,
result=self.filter_attrs(self.update_keys | set(extra_keys))
), result)

View File

@@ -1,230 +0,0 @@
#
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
from ipatests.test_xmlrpc import objectclasses
from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_uuid
from ipatests.test_xmlrpc.tracker.base import Tracker
from ipatests.util import assert_deepequal
from ipalib import api
from ipapython.dn import DN
class SudoCmdGroupTracker(Tracker):
""" Class for tracking sudocmdgroups """
retrieve_keys = {u'dn', u'cn', u'member_sudocmd', u'description',
u'member_sudocmdgroup'}
retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass',
u'mepmanagedentry'}
create_keys = retrieve_all_keys
update_keys = retrieve_keys - {u'dn'}
add_member_keys = retrieve_keys | {u'member_sudocmd'}
find_keys = {
u'dn', u'cn', u'description', u'member_sudocmdgroup'}
find_all_keys = find_keys | {
u'ipauniqueid', u'objectclass', u'mepmanagedentry'}
def __init__(self, name, description=u'SudoCmdGroup desc'):
super(SudoCmdGroupTracker, self).__init__(default_version=None)
self.cn = name
self.description = description
self.dn = DN(('cn', self.cn), ('cn', 'sudocmdgroups'),
('cn', 'sudo'), api.env.basedn)
def make_create_command(self, *args, **kwargs):
""" Make function that creates a sudocmdgroup
using 'sudocmdgroup-add' """
return self.make_command('sudocmdgroup_add', self.cn,
description=self.description,
*args, **kwargs)
def make_delete_command(self):
""" Make function that deletes a sudocmdgroup
using 'sudocmdgroup-del' """
return self.make_command('sudocmdgroup_del', self.cn)
def make_retrieve_command(self, all=False, raw=False):
""" Make function that retrieves a sudocmdgroup
using 'sudocmdgroup-show' """
return self.make_command('sudocmdgroup_show', self.cn, all=all)
def make_find_command(self, *args, **kwargs):
""" Make function that searches for a sudocmdgroup
using 'sudocmdgroup-find' """
return self.make_command('sudocmdgroup_find', *args, **kwargs)
def make_update_command(self, updates):
""" Make function that updates a sudocmdgroup using
'sudocmdgroup-mod' """
return self.make_command('sudocmdgroup_mod', self.cn, **updates)
def make_add_member_command(self, options={}):
""" Make function that adds a member to a sudocmdgroup """
return self.make_command('sudocmdgroup_add_member', self.cn, **options)
def make_remove_member_command(self, options={}):
""" Make function that removes a member from a sudocmdgroup """
return self.make_command('sudocmdgroup_remove_member',
self.cn, **options)
def track_create(self):
""" Updates expected state for sudocmdgroup creation"""
self.attrs = dict(
dn=self.dn,
cn=[self.cn],
description=[self.description],
ipauniqueid=[fuzzy_uuid],
objectclass=objectclasses.sudocmdgroup,
)
self.exists = True
def add_member(self, options):
""" Add a member sudocmd to sudocmdgroup and perform check """
try:
self.attrs[u'member_sudocmd'] =\
self.attrs[u'member_sudocmd'] + [options[u'sudocmd']]
except KeyError:
self.attrs[u'member_sudocmd'] = [options[u'sudocmd']]
command = self.make_add_member_command(options)
result = command()
self.check_add_member(result)
def remove_member(self, options):
""" Remove a member sudocmd from sudocmdgroup and perform check """
self.attrs[u'member_sudocmd'].remove(options[u'sudocmd'])
try:
if not self.attrs[u'member_sudocmd']:
del self.attrs[u'member_sudocmd']
except KeyError:
pass
command = self.make_remove_member_command(options)
result = command()
self.check_remove_member(result)
def update(self, updates, expected_updates=None):
"""Helper function to update and check the result
Overriding Tracker method for setting self.attrs correctly;
* most attributes stores its value in list
* the rest can be overridden by expected_updates
* allow deleting parametrs if update value is None
"""
if expected_updates is None:
expected_updates = {}
self.ensure_exists()
command = self.make_update_command(updates)
result = command()
for key, value in updates.items():
if value is None:
del self.attrs[key]
else:
self.attrs[key] = [value]
for key, value in expected_updates.items():
if value is None:
del self.attrs[key]
else:
self.attrs[key] = value
self.check_update(
result,
extra_keys=set(updates.keys()) | set(expected_updates.keys())
)
def check_create(self, result):
""" Checks 'sudocmdgroup_add' command result """
assert_deepequal(dict(
value=self.cn,
summary=u'Added Sudo Command Group "%s"' % self.cn,
result=self.filter_attrs(self.create_keys)
), result)
def check_delete(self, result):
""" Checks 'sudocmdgroup_del' command result """
assert_deepequal(dict(
value=[self.cn],
summary=u'Deleted Sudo Command Group "%s"' % self.cn,
result=dict(failed=[]),
), result)
def check_retrieve(self, result, all=False, raw=False):
""" Checks 'sudocmdgroup_show' command result """
if all:
expected = self.filter_attrs(self.retrieve_all_keys)
else:
expected = self.filter_attrs(self.retrieve_keys)
assert_deepequal(dict(
value=self.cn,
summary=None,
result=expected
), result)
def check_find(self, result, all=False, raw=False):
""" Checks 'sudocmdgroup_find' command result """
if all:
expected = self.filter_attrs(self.find_all_keys)
else:
expected = self.filter_attrs(self.find_keys)
assert_deepequal(dict(
count=1,
truncated=False,
summary=u'1 Sudo Command Group matched',
result=[expected],
), result)
def check_update(self, result, extra_keys={}):
""" Checks 'sudocmdgroup_mod' command result """
assert_deepequal(dict(
value=self.cn,
summary=u'Modified Sudo Command Group "%s"' % self.cn,
result=self.filter_attrs(self.update_keys | set(extra_keys))
), result)
def check_add_member(self, result):
""" Checks 'sudocmdgroup_add_member' command result """
assert_deepequal(dict(
completed=1,
failed={u'member': {u'sudocmd': ()}},
result=self.filter_attrs(self.add_member_keys)
), result)
def check_add_member_negative(self, result, options):
""" Checks 'sudocmdgroup_add_member' command result
when expected result is failure of the operation"""
expected = dict(
completed=0,
failed={u'member': {u'sudocmd': ()}},
result=self.filter_attrs(self.add_member_keys)
)
expected[u'failed'][u'member'][u'sudocmd'] = [(
options[u'sudocmd'], u'no such entry')]
assert_deepequal(expected, result)
def check_remove_member_negative(self, result, options):
""" Checks 'sudocmdgroup_remove_member' command result
when expected result is failure of the operation"""
expected = dict(
completed=0,
failed={u'member': {u'sudocmd': ()}},
result=self.filter_attrs(self.add_member_keys)
)
expected[u'failed'][u'member'][u'sudocmd'] = [(
options[u'sudocmd'], u'This entry is not a member')]
assert_deepequal(expected, result)
def check_remove_member(self, result):
""" Checks 'sudocmdgroup_remove_member' command result """
self.check_add_member(result)

View File

@@ -12,14 +12,12 @@ 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
from ipatests.test_xmlrpc.tracker.certmapdata import CertmapdataMixin
if six.PY3:
unicode = str
class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
class UserTracker(Tracker):
""" Class for host plugin like tests """
retrieve_keys = {
@@ -30,7 +28,6 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
u'ipatokenradiusconfiglink', u'ipatokenradiususername',
u'krbprincipalexpiration', u'usercertificate;binary',
u'has_keytab', u'has_password', u'memberof_group', u'sshpubkeyfp',
u'krbcanonicalname', 'krbprincipalname'
}
retrieve_all_keys = retrieve_keys | {
@@ -39,7 +36,8 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
u'l', u'mobile', u'krbextradata', u'krblastpwdchange',
u'krbpasswordexpiration', u'pager', u'st', u'manager', u'cn',
u'ipauniqueid', u'objectclass', u'mepmanagedentry',
u'displayname', u'gecos', u'initials', u'preserved'}
u'displayname', u'gecos', u'initials', u'krbprincipalname',
u'preserved'}
retrieve_preserved_keys = (retrieve_keys - {u'memberof_group'}) | {
u'preserved'}
@@ -53,69 +51,34 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
update_keys = retrieve_keys - {u'dn'}
activate_keys = retrieve_keys
find_keys = retrieve_keys - {
u'mepmanagedentry', u'memberof_group', u'has_keytab', u'has_password',
u'manager',
}
find_all_keys = retrieve_all_keys - {
u'has_keytab', u'has_password'
}
find_keys = retrieve_keys - {u'mepmanagedentry', u'memberof_group'}
find_all_keys = retrieve_all_keys
primary_keys = {u'uid', u'dn'}
def __init__(self, name=None, givenname=None, sn=None, **kwargs):
""" Check for non-empty unicode string for the required attributes
in the init method """
if not (isinstance(givenname, six.string_types) and givenname):
raise ValueError(
"Invalid first name provided: {!r}".format(givenname)
)
if not (isinstance(sn, six.string_types) and sn):
raise ValueError("Invalid second name provided: {!r}".format(sn))
def __init__(self, name, givenname, sn, **kwargs):
super(UserTracker, self).__init__(default_version=None)
self.uid = unicode(name)
self.givenname = unicode(givenname)
self.sn = unicode(sn)
self.uid = name
self.givenname = givenname
self.sn = sn
self.dn = DN(('uid', self.uid), api.env.container_user, api.env.basedn)
self.kwargs = kwargs
def make_create_command(self, force=None):
""" Make function that creates a user using user-add
with all set of attributes and with minimal values,
where uid is not specified """
if self.uid is not None:
return self.make_command(
'user_add', self.uid,
givenname=self.givenname,
sn=self.sn, **self.kwargs
)
else:
return self.make_command(
'user_add', givenname=self.givenname,
sn=self.sn, **self.kwargs
)
""" Make function that crates a user using user-add """
return self.make_command(
'user_add', self.uid,
givenname=self.givenname,
sn=self.sn, **self.kwargs
)
def make_delete_command(self, no_preserve=True, preserve=False):
""" Make function that deletes a user using user-del
Arguments 'preserve' and 'no_preserve' represent implemented
options --preserve and --no-preserve of user-del command,
which are mutually exclusive.
If --preserve=True and --no-preserve=False, the user is moved
to deleted container.
If --preserve=True and --no-preserve=True, an error is raised.
If --preserve=False and --no-preserver=True, user is deleted.
"""
""" Make function that deletes a user using user-del """
if preserve and not no_preserve:
# --preserve=True and --no-preserve=False - user is moved to
# another container, hence it is necessary to change some user
# attributes
# necessary to change some user attributes due to moving
# to different container
self.attrs[u'dn'] = DN(
('uid', self.uid),
api.env.container_deleteuser,
@@ -178,7 +141,6 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
uidnumber=[fuzzy_digits],
gidnumber=[fuzzy_digits],
krbprincipalname=[u'%s@%s' % (self.uid, self.api.env.realm)],
krbcanonicalname=[u'%s@%s' % (self.uid, self.api.env.realm)],
mail=[u'%s@%s' % (self.uid, self.api.env.domain)],
gecos=[u'%s %s' % (self.givenname, self.sn)],
loginshell=[u'/bin/sh'],
@@ -196,14 +158,14 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
(self.kwargs[key].split('@'))[0].lower(),
(self.kwargs[key].split('@'))[1]
)]
except IndexError:
except IndexError as ex:
# we can provide just principal part
self.attrs[key] = [u'%s@%s' % (
(self.kwargs[key].lower(),
self.api.env.realm)
)]
else:
if type(self.kwargs[key]) is not list:
if not type(self.kwargs[key]) is list:
self.attrs[key] = [self.kwargs[key]]
else:
self.attrs[key] = self.kwargs[key]
@@ -216,7 +178,7 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
Overriding Tracker method for setting self.attrs correctly;
* most attributes stores its value in list
* the rest can be overridden by expected_updates
* allow deleting parameters if update value is None
* allow deleting parametrs if update value is None
"""
if expected_updates is None:
expected_updates = {}
@@ -228,12 +190,6 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
for key, value in updates.items():
if value is None or value is '' or value is u'':
del self.attrs[key]
elif key == 'rename':
new_principal = u'{0}@{1}'.format(value, self.api.env.realm)
self.attrs['uid'] = [value]
self.attrs['krbcanonicalname'] = [new_principal]
if new_principal not in self.attrs['krbprincipalname']:
self.attrs['krbprincipalname'].append(new_principal)
else:
if type(value) is list:
self.attrs[key] = value
@@ -250,9 +206,6 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
extra_keys=set(updates.keys()) | set(expected_updates.keys())
)
if 'rename' in updates:
self.uid = self.attrs['uid'][0]
def check_create(self, result, extra_keys=()):
""" Check 'user-add' command result """
expected = self.filter_attrs(self.create_keys | set(extra_keys))
@@ -514,7 +467,7 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
assert_deepequal(dict(
completed=1,
failed=dict(
member=dict(group=tuple(), user=tuple(), service=tuple())
member=dict(group=tuple(), user=tuple())
),
result={
'dn': get_group_dn(admin_group),
@@ -524,17 +477,3 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, 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)
# Certificate identity mapping methods
def _make_add_certmap(self):
return self.make_command('user_add_certmapdata', self.name)
def _make_remove_certmap(self):
return self.make_command('user_remove_certmapdata', self.name)