Imported Upstream version 4.0.5
This commit is contained in:
@@ -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)
|
||||
@@ -1,395 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Implements a base class to track changes to an LDAP object.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import functools
|
||||
|
||||
from ipalib import api, errors
|
||||
from ipapython.dn import DN
|
||||
from ipapython.version import API_VERSION
|
||||
from ipatests.util import Fuzzy
|
||||
|
||||
|
||||
class BaseTracker(object):
|
||||
_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 = {}
|
||||
|
||||
@property
|
||||
def dn(self):
|
||||
"""A property containing the distinguished name of the entry."""
|
||||
if not self._dn:
|
||||
raise ValueError('The DN must be set in the init method.')
|
||||
return self._dn
|
||||
|
||||
@dn.setter
|
||||
def dn(self, value):
|
||||
if not (isinstance(value, DN) or isinstance(value, Fuzzy)):
|
||||
raise ValueError('The value must be an instance of DN or Fuzzy.')
|
||||
self._dn = value
|
||||
|
||||
@property
|
||||
def rdn(self):
|
||||
return self.dn[0]
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Property holding the name of the entry in LDAP.
|
||||
|
||||
This property is computed in runtime.
|
||||
"""
|
||||
return self.rdn.value
|
||||
|
||||
def filter_attrs(self, keys):
|
||||
"""Return a dict of expected attrs, filtered by the given keys"""
|
||||
if not self.attrs:
|
||||
raise RuntimeError('The tracker instance has no attributes.')
|
||||
return {k: v for k, v in self.attrs.items() if k in keys}
|
||||
|
||||
def run_command(self, name, *args, **options):
|
||||
"""Run the given IPA command
|
||||
|
||||
Logs the command using print for easier debugging
|
||||
"""
|
||||
cmd = self.api.Command[name]
|
||||
|
||||
options.setdefault('version', self.default_version)
|
||||
|
||||
args_repr = ', '.join(
|
||||
[repr(a) for a in args] +
|
||||
['%s=%r' % item for item in list(options.items())])
|
||||
try:
|
||||
result = cmd(*args, **options)
|
||||
except Exception as e:
|
||||
print('Ran command: %s(%s): %s: %s' % (cmd, args_repr,
|
||||
type(e).__name__, e))
|
||||
raise
|
||||
else:
|
||||
print('Ran command: %s(%s): OK' % (cmd, args_repr))
|
||||
return result
|
||||
|
||||
def make_command(self, name, *args, **options):
|
||||
"""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
|
||||
|
||||
The fixture ensures the plugin entry does not exist before
|
||||
and after the tests that use it.
|
||||
"""
|
||||
del_command = self.make_delete_command()
|
||||
try:
|
||||
del_command()
|
||||
except errors.NotFound:
|
||||
pass
|
||||
|
||||
def cleanup():
|
||||
existed = self.exists
|
||||
try:
|
||||
del_command()
|
||||
except errors.NotFound:
|
||||
if existed:
|
||||
raise
|
||||
self.exists = False
|
||||
|
||||
request.addfinalizer(cleanup)
|
||||
|
||||
return super(CreationTracker, self).make_fixture(request)
|
||||
|
||||
|
||||
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 cleanup():
|
||||
if self.original_enabled != self.enabled:
|
||||
if self.original_enabled:
|
||||
command = self.make_enable_command()
|
||||
else:
|
||||
command = self.make_disable_command()
|
||||
command()
|
||||
|
||||
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.
|
||||
"""
|
||||
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
|
||||
|
||||
def revert():
|
||||
update = self.make_update_command(original_state)
|
||||
try:
|
||||
update()
|
||||
except errors.EmptyModlist:
|
||||
# ignore no change
|
||||
pass
|
||||
|
||||
request.addfinalizer(revert)
|
||||
|
||||
return super(ConfigurationTracker, self).make_fixture(request)
|
||||
|
||||
|
||||
class Tracker(RetrievalTracker, SearchTracker, ModificationTracker,
|
||||
CreationTracker):
|
||||
"""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.
|
||||
"""
|
||||
pass
|
||||
@@ -1,143 +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):
|
||||
"""Make function that retrieves the entry using ${CMD}_show"""
|
||||
return self.make_command('ca_show', self.name, all=all, raw=raw)
|
||||
|
||||
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)
|
||||
@@ -1,383 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
from ipalib import errors
|
||||
from ipatests.util import assert_deepequal
|
||||
from ipatests.test_xmlrpc.xmlrpc_test import (fuzzy_caacldn, fuzzy_uuid,
|
||||
fuzzy_ipauniqueid)
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.test_xmlrpc.tracker.base import Tracker
|
||||
|
||||
|
||||
class CAACLTracker(Tracker):
|
||||
"""Tracker class for CA ACL LDAP object.
|
||||
|
||||
The class implements methods required by the base class
|
||||
to help with basic CRUD operations.
|
||||
|
||||
Methods for adding and deleting actual member entries into an ACL
|
||||
do not have check methods as these would make the class
|
||||
unnecessarily complicated. The checks are implemented as
|
||||
a standalone test suite. However, this makes the test crucial
|
||||
in debugging more complicated test cases. Since the add/remove
|
||||
operation won't be checked right away by the tracker, a problem
|
||||
in this operation may propagate into more complicated test case.
|
||||
|
||||
It is possible to pass a list of member uids to these methods.
|
||||
|
||||
The test uses instances of Fuzzy class to compare results as they
|
||||
are in the UUID format. The dn and rdn properties were modified
|
||||
to reflect this as well.
|
||||
"""
|
||||
|
||||
member_keys = {
|
||||
u'memberuser_user', u'memberuser_group',
|
||||
u'memberhost_host', u'memberhost_hostgroup',
|
||||
u'memberservice_service',
|
||||
u'ipamembercertprofile_certprofile',
|
||||
u'ipamemberca_ca'}
|
||||
category_keys = {
|
||||
u'ipacacategory', u'ipacertprofilecategory', u'usercategory',
|
||||
u'hostcategory', u'servicecategory', u'ipacacategory'}
|
||||
retrieve_keys = {
|
||||
u'dn', u'cn', u'description', u'ipaenabledflag',
|
||||
u'ipamemberca', u'ipamembercertprofile', u'memberuser',
|
||||
u'memberhost', u'memberservice'} | member_keys | category_keys
|
||||
retrieve_all_keys = retrieve_keys | {u'objectclass', u'ipauniqueid'}
|
||||
create_keys = {u'dn', u'cn', u'description', u'ipacertprofilecategory',
|
||||
u'usercategory', u'hostcategory', u'ipacacategory',
|
||||
u'servicecategory', u'ipaenabledflag', u'objectclass',
|
||||
u'ipauniqueid'}
|
||||
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):
|
||||
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)
|
||||
|
||||
self.dn = fuzzy_caacldn
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def rdn(self):
|
||||
return fuzzy_ipauniqueid
|
||||
|
||||
@property
|
||||
def categories(self):
|
||||
"""To be used in track_create"""
|
||||
return {cat: v for cat, v in self._categories.items() if v}
|
||||
|
||||
@property
|
||||
def create_categories(self):
|
||||
""" Return the categories set on create.
|
||||
Unused categories are left out.
|
||||
"""
|
||||
return {cat: [v] for cat, v in self.categories.items() if v}
|
||||
|
||||
def make_create_command(self):
|
||||
return self.make_command(u'caacl_add', self.name,
|
||||
description=self.description,
|
||||
**self.categories)
|
||||
|
||||
def check_create(self, result):
|
||||
assert_deepequal(dict(
|
||||
value=self.name,
|
||||
summary=u'Added CA ACL "{}"'.format(self.name),
|
||||
result=dict(self.filter_attrs(self.create_keys))
|
||||
), result)
|
||||
|
||||
def track_create(self):
|
||||
self.attrs = dict(
|
||||
dn=self.dn,
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
cn=[self.name],
|
||||
objectclass=objectclasses.caacl,
|
||||
ipaenabledflag=[u'TRUE'])
|
||||
|
||||
self.attrs.update(self.create_categories)
|
||||
if self.description:
|
||||
self.attrs.update({u'description', [self.description]})
|
||||
|
||||
self.exists = True
|
||||
|
||||
def make_delete_command(self):
|
||||
return self.make_command('caacl_del', self.name)
|
||||
|
||||
def check_delete(self, result):
|
||||
assert_deepequal(dict(
|
||||
value=[self.name],
|
||||
summary=u'Deleted CA ACL "{}"'.format(self.name),
|
||||
result=dict(failed=[])
|
||||
), result)
|
||||
|
||||
def make_retrieve_command(self, all=False, raw=False):
|
||||
return self.make_command('caacl_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('caacl_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 CA ACL matched',
|
||||
result=[expected]
|
||||
), result)
|
||||
|
||||
def make_update_command(self, updates):
|
||||
return self.make_command('caacl_mod', self.name, **updates)
|
||||
|
||||
def update(self, updates, expected_updates=None, silent=False):
|
||||
"""If removing a category, delete it from tracker as well"""
|
||||
# filter out empty categories and track changes
|
||||
|
||||
filtered_updates = dict()
|
||||
for key, value in updates.items():
|
||||
if key in self.category_keys:
|
||||
if not value:
|
||||
try:
|
||||
del self.attrs[key]
|
||||
except IndexError:
|
||||
if silent:
|
||||
pass
|
||||
else:
|
||||
# if there is a value, prepare the pair for update
|
||||
filtered_updates.update({key: value})
|
||||
else:
|
||||
filtered_updates.update({key: value})
|
||||
|
||||
if expected_updates is None:
|
||||
expected_updates = {}
|
||||
|
||||
command = self.make_update_command(updates)
|
||||
|
||||
try:
|
||||
result = command()
|
||||
except errors.EmptyModlist:
|
||||
if silent:
|
||||
self.attrs.update(filtered_updates)
|
||||
self.attrs.update(expected_updates)
|
||||
self.check_update(result,
|
||||
extra_keys=set(self.update_keys) |
|
||||
set(expected_updates.keys()))
|
||||
|
||||
def check_update(self, result, extra_keys=()):
|
||||
assert_deepequal(dict(
|
||||
value=self.name,
|
||||
summary=u'Modified CA ACL "{}"'.format(self.name),
|
||||
result=self.filter_attrs(self.update_keys | set(extra_keys))
|
||||
), result)
|
||||
|
||||
# Helper methods for caacl subcommands. The check methods will be
|
||||
# implemented in standalone test
|
||||
#
|
||||
# The methods implemented here will be:
|
||||
# caacl_{add,remove}_{host, service, certprofile, user, ca}
|
||||
|
||||
def _add_acl_component(self, command_name, keys, track):
|
||||
""" Add a resource into ACL rule and track it.
|
||||
|
||||
command_name - the name in the API
|
||||
keys = {
|
||||
'tracker_attr': {
|
||||
'api_key': 'value'
|
||||
}
|
||||
}
|
||||
|
||||
e.g.
|
||||
|
||||
keys = {
|
||||
'memberhost_host': {
|
||||
'host': 'hostname'
|
||||
},
|
||||
'memberhost_hostgroup': {
|
||||
'hostgroup': 'hostgroup_name'
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
if not self.exists:
|
||||
raise errors.NotFound(reason="The tracked entry doesn't exist.")
|
||||
|
||||
command = self.make_command(command_name, self.name)
|
||||
command_options = dict()
|
||||
|
||||
# track
|
||||
for tracker_attr in keys:
|
||||
api_options = keys[tracker_attr]
|
||||
if track:
|
||||
for option in api_options:
|
||||
try:
|
||||
if type(option) in (list, tuple):
|
||||
self.attrs[tracker_attr].extend(api_options[option])
|
||||
else:
|
||||
self.attrs[tracker_attr].append(api_options[option])
|
||||
except KeyError:
|
||||
if type(option) in (list, tuple):
|
||||
self.attrs[tracker_attr] = api_options[option]
|
||||
else:
|
||||
self.attrs[tracker_attr] = [api_options[option]]
|
||||
# prepare options for the command call
|
||||
command_options.update(api_options)
|
||||
|
||||
return command(**command_options)
|
||||
|
||||
def _remove_acl_component(self, command_name, keys, track):
|
||||
""" Remove a resource from ACL rule and track it.
|
||||
|
||||
command_name - the name in the API
|
||||
keys = {
|
||||
'tracker_attr': {
|
||||
'api_key': 'value'
|
||||
}
|
||||
}
|
||||
|
||||
e.g.
|
||||
|
||||
keys = {
|
||||
'memberhost_host': {
|
||||
'host': 'hostname'
|
||||
},
|
||||
'memberhost_hostgroup': {
|
||||
'hostgroup': 'hostgroup_name'
|
||||
}
|
||||
}
|
||||
"""
|
||||
command = self.make_command(command_name, self.name)
|
||||
command_options = dict()
|
||||
|
||||
for tracker_attr in keys:
|
||||
api_options = keys[tracker_attr]
|
||||
if track:
|
||||
for option in api_options:
|
||||
if type(option) in (list, tuple):
|
||||
for item in option:
|
||||
self.attrs[tracker_attr].remove(item)
|
||||
else:
|
||||
self.attrs[tracker_attr].remove(api_options[option])
|
||||
if len(self.attrs[tracker_attr]) == 0:
|
||||
del self.attrs[tracker_attr]
|
||||
command_options.update(api_options)
|
||||
|
||||
return command(**command_options)
|
||||
|
||||
def add_host(self, host=None, hostgroup=None, track=True):
|
||||
"""Associates an host or hostgroup entry with the ACL.
|
||||
|
||||
The command takes an unicode string with the name
|
||||
of the entry (RDN).
|
||||
|
||||
It is the responsibility of a test writer to provide
|
||||
the correct value, object type as the method does not
|
||||
verify whether the entry exists.
|
||||
|
||||
The method can add only one entry of each type
|
||||
in one call.
|
||||
"""
|
||||
|
||||
options = {
|
||||
u'memberhost_host': {u'host': host},
|
||||
u'memberhost_hostgroup': {u'hostgroup': hostgroup}}
|
||||
|
||||
return self._add_acl_component(u'caacl_add_host', options, track)
|
||||
|
||||
def remove_host(self, host=None, hostgroup=None, track=True):
|
||||
options = {
|
||||
u'memberhost_host': {u'host': host},
|
||||
u'memberhost_hostgroup': {u'hostgroup': hostgroup}}
|
||||
|
||||
return self._remove_acl_component(u'caacl_remove_host', options, track)
|
||||
|
||||
def add_user(self, user=None, group=None, track=True):
|
||||
options = {
|
||||
u'memberuser_user': {u'user': user},
|
||||
u'memberuser_group': {u'group': group}}
|
||||
|
||||
return self._add_acl_component(u'caacl_add_user', options, track)
|
||||
|
||||
def remove_user(self, user=None, group=None, track=True):
|
||||
options = {
|
||||
u'memberuser_user': {u'user': user},
|
||||
u'memberuser_group': {u'group': group}}
|
||||
|
||||
return self._remove_acl_component(u'caacl_remove_user', options, track)
|
||||
|
||||
def add_service(self, service=None, track=True):
|
||||
options = {
|
||||
u'memberservice_service': {u'service': service}}
|
||||
|
||||
return self._add_acl_component(u'caacl_add_service', options, track)
|
||||
|
||||
def remove_service(self, service=None, track=True):
|
||||
options = {
|
||||
u'memberservice_service': {u'service': service}}
|
||||
|
||||
return self._remove_acl_component(u'caacl_remove_service', options, track)
|
||||
|
||||
def add_profile(self, certprofile=None, track=True):
|
||||
options = {
|
||||
u'ipamembercertprofile_certprofile':
|
||||
{u'certprofile': certprofile}}
|
||||
|
||||
return self._add_acl_component(u'caacl_add_profile', options, track)
|
||||
|
||||
def remove_profile(self, certprofile=None, track=True):
|
||||
options = {
|
||||
u'ipamembercertprofile_certprofile':
|
||||
{u'certprofile': certprofile}}
|
||||
|
||||
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']})
|
||||
command()
|
||||
|
||||
def disable(self):
|
||||
command = self.make_command(u'caacl_disable', self.name)
|
||||
self.attrs.update({u'ipaenabledflag': [u'FALSE']})
|
||||
command()
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
from nose.tools import assert_raises
|
||||
|
||||
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 assert_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 assert_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)
|
||||
@@ -1,137 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
import six
|
||||
|
||||
from ipapython.dn import DN
|
||||
from ipatests.test_xmlrpc.tracker.base import Tracker
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.util import assert_deepequal
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
class CertprofileTracker(Tracker):
|
||||
"""Tracker class for certprofile plugin.
|
||||
"""
|
||||
|
||||
retrieve_keys = {
|
||||
'dn', 'cn', 'description', 'ipacertprofilestoreissued'
|
||||
}
|
||||
retrieve_all_keys = retrieve_keys | {'objectclass'}
|
||||
create_keys = retrieve_keys | {'objectclass'}
|
||||
update_keys = retrieve_keys - {'dn'}
|
||||
managedby_keys = retrieve_keys
|
||||
allowedto_keys = retrieve_keys
|
||||
|
||||
def __init__(self, name, store=False, desc='dummy description',
|
||||
profile=None, default_version=None):
|
||||
super(CertprofileTracker, self).__init__(
|
||||
default_version=default_version
|
||||
)
|
||||
|
||||
self.store = store
|
||||
self.description = desc
|
||||
self._profile_path = profile
|
||||
|
||||
self.dn = DN(('cn', name), 'cn=certprofiles', 'cn=ca',
|
||||
self.api.env.basedn)
|
||||
|
||||
@property
|
||||
def profile(self):
|
||||
if not self._profile_path:
|
||||
return None
|
||||
|
||||
if os.path.isabs(self._profile_path):
|
||||
path = self._profile_path
|
||||
else:
|
||||
path = os.path.join(os.path.dirname(__file__),
|
||||
self._profile_path)
|
||||
|
||||
with open(path, 'r') as f:
|
||||
content = f.read()
|
||||
return unicode(content)
|
||||
|
||||
def make_create_command(self):
|
||||
if not self.profile:
|
||||
raise RuntimeError('Tracker object without path to profile '
|
||||
'cannot be used to create profile entry.')
|
||||
|
||||
return self.make_command('certprofile_import', self.name,
|
||||
description=self.description,
|
||||
ipacertprofilestoreissued=self.store,
|
||||
file=self.profile)
|
||||
|
||||
def check_create(self, result):
|
||||
assert_deepequal(dict(
|
||||
value=self.name,
|
||||
summary=u'Imported profile "{}"'.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],
|
||||
ipacertprofilestoreissued=[unicode(self.store).upper()],
|
||||
objectclass=objectclasses.certprofile
|
||||
)
|
||||
self.exists = True
|
||||
|
||||
def make_delete_command(self):
|
||||
return self.make_command('certprofile_del', self.name)
|
||||
|
||||
def check_delete(self, result):
|
||||
assert_deepequal(dict(
|
||||
value=[self.name], # correctly a list?
|
||||
summary=u'Deleted profile "{}"'.format(self.name),
|
||||
result=dict(failed=[]),
|
||||
), result)
|
||||
|
||||
def make_retrieve_command(self, all=False, raw=False, **options):
|
||||
return self.make_command('certprofile_show', self.name, all=all,
|
||||
raw=raw, **options)
|
||||
|
||||
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('certprofile_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 profile matched',
|
||||
result=[expected]
|
||||
), result)
|
||||
|
||||
def make_update_command(self, updates):
|
||||
return self.make_command('certprofile_mod', self.name, **updates)
|
||||
|
||||
def check_update(self, result, extra_keys=()):
|
||||
assert_deepequal(dict(
|
||||
value=self.name,
|
||||
summary=u'Modified Certificate Profile "{}"'.format(self.name),
|
||||
result=self.filter_attrs(self.update_keys | set(extra_keys))
|
||||
), result)
|
||||
@@ -1,264 +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_digits, fuzzy_uuid
|
||||
|
||||
from ipatests.test_xmlrpc.tracker.base import Tracker
|
||||
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'description',
|
||||
u'memberof_group', u'memberofindirect_group',
|
||||
u'memberindirect_group', u'memberindirect_user'}
|
||||
|
||||
retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass'}
|
||||
|
||||
create_keys = retrieve_all_keys
|
||||
update_keys = retrieve_keys - {u'dn'}
|
||||
|
||||
add_member_keys = retrieve_keys | {u'description'}
|
||||
|
||||
def __init__(self, name, description=u'Group desc'):
|
||||
super(GroupTracker, self).__init__(default_version=None)
|
||||
self.cn = name
|
||||
self.description = description
|
||||
self.dn = get_group_dn(self.cn)
|
||||
|
||||
def make_create_command(self, nonposix=False, external=False,
|
||||
*args, **kwargs):
|
||||
""" 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)
|
||||
|
||||
def make_delete_command(self):
|
||||
""" Make function that deletes a group using 'group-del' """
|
||||
return self.make_command('group_del', self.cn)
|
||||
|
||||
def make_retrieve_command(self, all=False, raw=False):
|
||||
""" Make function that retrieves a group using 'group-show' """
|
||||
return self.make_command('group_show', self.cn, all=all)
|
||||
|
||||
def make_find_command(self, *args, **kwargs):
|
||||
""" Make function that searches for a group using 'group-find' """
|
||||
return self.make_command('group_find', *args, **kwargs)
|
||||
|
||||
def make_update_command(self, updates):
|
||||
""" Make function that updates a group using 'group-mod' """
|
||||
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 """
|
||||
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 """
|
||||
return self.make_command('group_remove_member', self.cn, **options)
|
||||
|
||||
def make_detach_command(self):
|
||||
""" Make function that detaches a managed group using
|
||||
'group-detach' """
|
||||
self.exists = True
|
||||
return self.make_command('group_detach', self.cn)
|
||||
|
||||
def track_create(self):
|
||||
""" Updates expected state for group creation"""
|
||||
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) 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']]
|
||||
|
||||
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'])
|
||||
|
||||
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
|
||||
|
||||
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(
|
||||
value=self.cn,
|
||||
summary=u'Added group "%s"' % self.cn,
|
||||
result=self.filter_attrs(self.create_keys)
|
||||
), result)
|
||||
|
||||
def check_delete(self, result):
|
||||
""" Checks 'group_del' command result """
|
||||
assert_deepequal(dict(
|
||||
value=[self.cn],
|
||||
summary=u'Deleted group "%s"' % self.cn,
|
||||
result=dict(failed=[]),
|
||||
), result)
|
||||
|
||||
def check_retrieve(self, result, all=False, raw=False):
|
||||
""" Checks 'group_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 'group_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 group matched',
|
||||
result=[expected],
|
||||
), result)
|
||||
|
||||
def check_update(self, result, extra_keys={}):
|
||||
""" Checks 'group_mod' command result """
|
||||
assert_deepequal(dict(
|
||||
value=self.cn,
|
||||
summary=u'Modified group "%s"' % self.cn,
|
||||
result=self.filter_attrs(self.update_keys | set(extra_keys))
|
||||
), result)
|
||||
|
||||
def check_add_member(self, result):
|
||||
""" Checks 'group_add_member' command result """
|
||||
assert_deepequal(dict(
|
||||
completed=1,
|
||||
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"""
|
||||
expected = dict(
|
||||
completed=0,
|
||||
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:
|
||||
expected[u'failed'][u'member'][u'user'] = [(
|
||||
options[u'user'], u'no such entry')]
|
||||
elif u'group' in options:
|
||||
expected[u'failed'][u'member'][u'group'] = [(
|
||||
options[u'group'], 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': ()}},
|
||||
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')]
|
||||
|
||||
assert_deepequal(expected, result)
|
||||
|
||||
def check_remove_member(self, result):
|
||||
""" Checks 'group_remove_member' command result """
|
||||
self.check_add_member(result)
|
||||
|
||||
def check_detach(self, result):
|
||||
""" Checks 'group_detach' command result """
|
||||
assert_deepequal(dict(
|
||||
value=self.cn,
|
||||
summary=u'Detached group "%s" from user "%s"' % (
|
||||
self.cn, self.cn),
|
||||
result=True
|
||||
), result)
|
||||
@@ -1,201 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
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):
|
||||
"""Wraps and tracks modifications to a Host object
|
||||
|
||||
Implements the helper functions for host plugin.
|
||||
|
||||
The HostTracker object stores information about the host, e.g.
|
||||
``fqdn`` and ``dn``.
|
||||
"""
|
||||
retrieve_keys = {
|
||||
'dn', 'fqdn', 'description', 'l', 'krbcanonicalname',
|
||||
'krbprincipalname', 'managedby_host',
|
||||
'has_keytab', 'has_password', 'issuer',
|
||||
'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',
|
||||
'ipaallowedtoperform_write_keys_user',
|
||||
'ipaallowedtoperform_write_keys_group',
|
||||
'ipaallowedtoperform_write_keys_host',
|
||||
'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'}
|
||||
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)
|
||||
|
||||
self.shortname = name
|
||||
if fqdn:
|
||||
self.fqdn = fqdn
|
||||
else:
|
||||
self.fqdn = u'%s.%s' % (name, self.api.env.domain)
|
||||
self.dn = DN(('fqdn', self.fqdn), 'cn=computers', 'cn=accounts',
|
||||
self.api.env.basedn)
|
||||
|
||||
self.description = u'Test host <%s>' % name
|
||||
self.location = u'Undisclosed location <%s>' % name
|
||||
|
||||
def make_create_command(self, force=True):
|
||||
"""Make function that creates this host using host_add"""
|
||||
return self.make_command('host_add', self.fqdn,
|
||||
description=self.description,
|
||||
l=self.location,
|
||||
force=force)
|
||||
|
||||
def make_delete_command(self):
|
||||
"""Make function that deletes the host using host_del"""
|
||||
return self.make_command('host_del', self.fqdn)
|
||||
|
||||
def make_retrieve_command(self, all=False, raw=False):
|
||||
"""Make function that retrieves the host using host_show"""
|
||||
return self.make_command('host_show', self.fqdn, all=all, raw=raw)
|
||||
|
||||
def make_find_command(self, *args, **kwargs):
|
||||
"""Make function that finds hosts using host_find
|
||||
|
||||
Note that the fqdn (or other search terms) needs to be specified
|
||||
in arguments.
|
||||
"""
|
||||
return self.make_command('host_find', *args, **kwargs)
|
||||
|
||||
def make_update_command(self, updates):
|
||||
"""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(
|
||||
dn=self.dn,
|
||||
fqdn=[self.fqdn],
|
||||
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],
|
||||
has_keytab=False,
|
||||
has_password=False,
|
||||
cn=[self.fqdn],
|
||||
ipakrbokasdelegate=False,
|
||||
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
|
||||
|
||||
def check_create(self, result):
|
||||
"""Check `host_add` command result"""
|
||||
assert_deepequal(dict(
|
||||
value=self.fqdn,
|
||||
summary=u'Added host "%s"' % self.fqdn,
|
||||
result=self.filter_attrs(self.create_keys),
|
||||
), result)
|
||||
|
||||
def check_delete(self, result):
|
||||
"""Check `host_del` command result"""
|
||||
assert_deepequal(dict(
|
||||
value=[self.fqdn],
|
||||
summary=u'Deleted host "%s"' % self.fqdn,
|
||||
result=dict(failed=[]),
|
||||
), result)
|
||||
|
||||
def check_retrieve(self, result, all=False, raw=False):
|
||||
"""Check `host_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.fqdn,
|
||||
summary=None,
|
||||
result=expected,
|
||||
), result)
|
||||
|
||||
def check_find(self, result, all=False, raw=False):
|
||||
"""Check `host_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 host matched',
|
||||
result=[expected],
|
||||
), result)
|
||||
|
||||
def check_update(self, result, extra_keys=()):
|
||||
"""Check `host_update` command result"""
|
||||
assert_deepequal(dict(
|
||||
value=self.fqdn,
|
||||
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)
|
||||
@@ -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)
|
||||
@@ -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']
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"0"],
|
||||
)
|
||||
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
|
||||
@@ -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)
|
||||
@@ -1,301 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
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)
|
||||
|
||||
from ipatests.util import assert_deepequal
|
||||
from ipapython.dn import DN
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
sshpubkey = (u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGAX3xAeLeaJggwTqMjxNwa6X'
|
||||
'HBUAikXPGMzEpVrlLDCZtv00djsFTBi38PkgxBJVkgRWMrcBsr/35lq7P6w8KGI'
|
||||
'wA8GI48Z0qBS2NBMJ2u9WQ2hjLN6GdMlo77O0uJY3251p12pCVIS/bHRSq8kHO2'
|
||||
'No8g7KA9fGGcagPfQH+ee3t7HUkpbQkFTmbPPN++r3V8oVUk5LxbryB3UIIVzNm'
|
||||
'cSIn3JrXynlvui4MixvrtX6zx+O/bBo68o8/eZD26QrahVbA09fivrn/4h3TM01'
|
||||
'9Eu/c2jOdckfU3cHUV/3Tno5d6JicibyaoDDK7S/yjdn5jhaz8MSEayQvFkZkiF'
|
||||
'0L public key test')
|
||||
sshpubkeyfp = (u'SHA256:cStA9o5TRSARbeketEOooMUMSWRSsArIAXloBZ4vNsE '
|
||||
'public key test (ssh-rsa)')
|
||||
|
||||
|
||||
class StageUserTracker(KerberosAliasMixin, Tracker):
|
||||
""" Tracker class for staged user LDAP object
|
||||
|
||||
Implements helper functions for host plugin.
|
||||
StageUserTracker object stores information about the user.
|
||||
"""
|
||||
|
||||
retrieve_keys = {
|
||||
u'uid', u'givenname', u'sn', u'homedirectory', u'loginshell',
|
||||
u'uidnumber', u'gidnumber', u'mail', u'ou', u'telephonenumber',
|
||||
u'title', u'memberof', u'nsaccountlock', u'memberofindirect',
|
||||
u'ipauserauthtype', u'userclass', u'ipatokenradiusconfiglink',
|
||||
u'ipatokenradiususername', u'krbprincipalexpiration',
|
||||
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'}
|
||||
retrieve_all_keys = retrieve_keys | {
|
||||
u'cn', u'ipauniqueid', u'objectclass', u'description',
|
||||
u'displayname', u'gecos', u'initials', u'manager'}
|
||||
|
||||
create_keys = retrieve_all_keys | {
|
||||
u'objectclass', u'ipauniqueid', u'randompassword',
|
||||
u'userpassword', u'krbextradata', u'krblastpwdchange',
|
||||
u'krbpasswordexpiration', u'krbprincipalkey'}
|
||||
|
||||
update_keys = retrieve_keys - {u'dn', u'nsaccountlock'}
|
||||
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))
|
||||
|
||||
super(StageUserTracker, self).__init__(default_version=None)
|
||||
self.uid = unicode(name)
|
||||
self.givenname = unicode(givenname)
|
||||
self.sn = unicode(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 """
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
def make_delete_command(self):
|
||||
""" Make function that deletes a staged user using stageuser-del """
|
||||
return self.make_command('stageuser_del', self.uid)
|
||||
|
||||
def make_retrieve_command(self, all=False, raw=False):
|
||||
""" Make function that retrieves a staged user using stageuser-show """
|
||||
return self.make_command('stageuser_show', self.uid, all=all)
|
||||
|
||||
def make_find_command(self, *args, **kwargs):
|
||||
""" Make function that finds staged user using stageuser-find """
|
||||
return self.make_command('stageuser_find', *args, **kwargs)
|
||||
|
||||
def make_update_command(self, updates):
|
||||
""" Make function that updates staged user using stageuser-mod """
|
||||
return self.make_command('stageuser_mod', self.uid, **updates)
|
||||
|
||||
def make_activate_command(self):
|
||||
""" Make function that activates staged user
|
||||
using stageuser-activate """
|
||||
return self.make_command('stageuser_activate', self.uid)
|
||||
|
||||
def track_create(self):
|
||||
""" Update expected state for staged user creation """
|
||||
self.attrs = dict(
|
||||
dn=self.dn,
|
||||
uid=[self.uid],
|
||||
givenname=[self.givenname],
|
||||
sn=[self.sn],
|
||||
homedirectory=[u'/home/%s' % self.uid],
|
||||
displayname=[u'%s %s' % (self.givenname, self.sn)],
|
||||
cn=[u'%s %s' % (self.givenname, self.sn)],
|
||||
initials=[u'%s%s' % (self.givenname[0], self.sn[0])],
|
||||
objectclass=objectclasses.user_base,
|
||||
description=[u'__no_upg__'],
|
||||
ipauniqueid=[u'autogenerate'],
|
||||
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'],
|
||||
has_keytab=False,
|
||||
has_password=False,
|
||||
nsaccountlock=[u'true'],
|
||||
)
|
||||
|
||||
for key in self.kwargs:
|
||||
if key == u'krbprincipalname':
|
||||
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 == u'random' or key == u'userpassword':
|
||||
self.attrs[u'krbextradata'] = [Fuzzy(type=bytes)]
|
||||
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'has_keytab'] = True
|
||||
self.attrs[u'has_password'] = True
|
||||
if key == u'random':
|
||||
self.attrs[u'randompassword'] = fuzzy_string
|
||||
else:
|
||||
self.attrs[key] = [self.kwargs[key]]
|
||||
|
||||
self.exists = True
|
||||
|
||||
def check_create(self, result):
|
||||
""" Check 'stageuser-add' command result """
|
||||
assert_deepequal(dict(
|
||||
value=self.uid,
|
||||
summary=u'Added stage user "%s"' % self.uid,
|
||||
result=self.filter_attrs(self.create_keys),
|
||||
), result)
|
||||
|
||||
def check_delete(self, result):
|
||||
""" Check 'stageuser-del' command result """
|
||||
assert_deepequal(dict(
|
||||
value=[self.uid],
|
||||
summary=u'Deleted stage user "%s"' % self.uid,
|
||||
result=dict(failed=[]),
|
||||
), result)
|
||||
|
||||
def check_retrieve(self, result, all=False, raw=False):
|
||||
""" Check 'stageuser-show' command result """
|
||||
if all:
|
||||
expected = self.filter_attrs(self.retrieve_all_keys)
|
||||
else:
|
||||
expected = self.filter_attrs(self.retrieve_keys)
|
||||
|
||||
# small override because stageuser-find returns different
|
||||
# type of nsaccountlock value than DS, but overall the value
|
||||
# fits expected result
|
||||
if expected[u'nsaccountlock'] == [u'true']:
|
||||
expected[u'nsaccountlock'] = True
|
||||
elif expected[u'nsaccountlock'] == [u'false']:
|
||||
expected[u'nsaccountlock'] = False
|
||||
|
||||
assert_deepequal(dict(
|
||||
value=self.uid,
|
||||
summary=None,
|
||||
result=expected,
|
||||
), result)
|
||||
|
||||
def check_find(self, result, all=False, raw=False):
|
||||
""" Check 'stageuser-find' command result """
|
||||
if all:
|
||||
expected = self.filter_attrs(self.find_all_keys)
|
||||
else:
|
||||
expected = self.filter_attrs(self.find_keys)
|
||||
|
||||
# small override because stageuser-find returns different
|
||||
# type of nsaccountlock value than DS, but overall the value
|
||||
# fits expected result
|
||||
if expected[u'nsaccountlock'] == [u'true']:
|
||||
expected[u'nsaccountlock'] = True
|
||||
elif expected[u'nsaccountlock'] == [u'false']:
|
||||
expected[u'nsaccountlock'] = False
|
||||
|
||||
assert_deepequal(dict(
|
||||
count=1,
|
||||
truncated=False,
|
||||
summary=u'1 user matched',
|
||||
result=[expected],
|
||||
), result)
|
||||
|
||||
def check_find_nomatch(self, result):
|
||||
""" Check 'stageuser-find' command result when no match is expected """
|
||||
assert_deepequal(dict(
|
||||
count=0,
|
||||
truncated=False,
|
||||
summary=u'0 users matched',
|
||||
result=[],
|
||||
), result)
|
||||
|
||||
def check_update(self, result, extra_keys=()):
|
||||
""" Check 'stageuser-mod' command result """
|
||||
assert_deepequal(dict(
|
||||
value=self.uid,
|
||||
summary=u'Modified stage user "%s"' % self.uid,
|
||||
result=self.filter_attrs(self.update_keys | set(extra_keys))
|
||||
), result)
|
||||
|
||||
def check_restore_preserved(self, result):
|
||||
assert_deepequal(dict(
|
||||
value=[self.uid],
|
||||
summary=u'Staged user account "%s"' % self.uid,
|
||||
result=dict(failed=[]),
|
||||
), result)
|
||||
|
||||
def make_fixture_activate(self, request):
|
||||
"""Make a pytest fixture for a staged user that is to be activated
|
||||
|
||||
The fixture ensures the plugin entry does not exist before
|
||||
and after the tests that use it. It takes into account
|
||||
that the staged user no longer exists after activation,
|
||||
therefore the fixture verifies after the tests
|
||||
that the staged user doesn't exist instead of deleting it.
|
||||
"""
|
||||
del_command = self.make_delete_command()
|
||||
try:
|
||||
del_command()
|
||||
except errors.NotFound:
|
||||
pass
|
||||
|
||||
def finish():
|
||||
with raises_exact(errors.NotFound(
|
||||
reason=u'%s: stage user not found' % self.uid)):
|
||||
del_command()
|
||||
|
||||
request.addfinalizer(finish)
|
||||
|
||||
return self
|
||||
|
||||
def create_from_preserved(self, user):
|
||||
""" Copies values from preserved user - helper function for
|
||||
restoration tests """
|
||||
self.attrs = user.attrs
|
||||
self.uid = user.uid
|
||||
self.givenname = user.givenname
|
||||
self.sn = user.sn
|
||||
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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -1,540 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
from ipalib import api, errors
|
||||
from ipapython.dn import DN
|
||||
|
||||
import six
|
||||
|
||||
from ipatests.util import assert_deepequal, get_group_dn
|
||||
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 for host plugin like tests """
|
||||
|
||||
retrieve_keys = {
|
||||
u'dn', u'uid', u'givenname', u'sn', u'homedirectory', u'loginshell',
|
||||
u'uidnumber', u'gidnumber', u'mail', u'ou',
|
||||
u'telephonenumber', u'title', u'memberof', u'nsaccountlock',
|
||||
u'memberofindirect', u'ipauserauthtype', u'userclass',
|
||||
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 | {
|
||||
u'usercertificate', u'street', u'postalcode',
|
||||
u'facsimiletelephonenumber', u'carlicense', u'ipasshpubkey',
|
||||
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'}
|
||||
|
||||
retrieve_preserved_keys = (retrieve_keys - {u'memberof_group'}) | {
|
||||
u'preserved'}
|
||||
retrieve_preserved_all_keys = retrieve_all_keys - {u'memberof_group'}
|
||||
|
||||
create_keys = retrieve_all_keys | {
|
||||
u'krbextradata', u'krbpasswordexpiration', u'krblastpwdchange',
|
||||
u'krbprincipalkey', u'userpassword', u'randompassword'}
|
||||
create_keys = create_keys - {u'nsaccountlock'}
|
||||
|
||||
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'
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
super(UserTracker, self).__init__(default_version=None)
|
||||
self.uid = unicode(name)
|
||||
self.givenname = unicode(givenname)
|
||||
self.sn = unicode(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
|
||||
)
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
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
|
||||
self.attrs[u'dn'] = DN(
|
||||
('uid', self.uid),
|
||||
api.env.container_deleteuser,
|
||||
api.env.basedn
|
||||
)
|
||||
self.attrs[u'objectclass'] = objectclasses.user_base
|
||||
|
||||
return self.make_command(
|
||||
'user_del', self.uid,
|
||||
no_preserve=no_preserve,
|
||||
preserve=preserve
|
||||
)
|
||||
|
||||
def make_retrieve_command(self, all=False, raw=False):
|
||||
""" Make function that retrieves a user using user-show """
|
||||
return self.make_command('user_show', self.uid, all=all)
|
||||
|
||||
def make_find_command(self, *args, **kwargs):
|
||||
""" Make function that finds user using user-find """
|
||||
return self.make_command('user_find', *args, **kwargs)
|
||||
|
||||
def make_update_command(self, updates):
|
||||
""" Make function that updates user using user-mod """
|
||||
return self.make_command('user_mod', self.uid, **updates)
|
||||
|
||||
def make_undelete_command(self):
|
||||
""" Make function that activates preserved user using user-undel """
|
||||
return self.make_command('user_undel', self.uid)
|
||||
|
||||
def make_enable_command(self):
|
||||
""" Make function that enables user using user-enable """
|
||||
return self.make_command('user_enable', self.uid)
|
||||
|
||||
def make_disable_command(self):
|
||||
""" Make function that disables user using user-disable """
|
||||
return self.make_command('user_disable', self.uid)
|
||||
|
||||
def make_stage_command(self):
|
||||
""" Make function that restores preserved user by moving it to
|
||||
staged container """
|
||||
return self.make_command('user_stage', self.uid)
|
||||
|
||||
def make_group_add_member_command(self, *args, **kwargs):
|
||||
return self.make_command('group_add_member', *args, **kwargs)
|
||||
|
||||
def track_create(self):
|
||||
""" Update expected state for user creation """
|
||||
self.attrs = dict(
|
||||
dn=self.dn,
|
||||
uid=[self.uid],
|
||||
givenname=[self.givenname],
|
||||
sn=[self.sn],
|
||||
homedirectory=[u'/home/%s' % self.uid],
|
||||
displayname=[u'%s %s' % (self.givenname, self.sn)],
|
||||
cn=[u'%s %s' % (self.givenname, self.sn)],
|
||||
initials=[u'%s%s' % (self.givenname[0], self.sn[0])],
|
||||
objectclass=objectclasses.user,
|
||||
description=[u'__no_upg__'],
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
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'],
|
||||
has_keytab=False,
|
||||
has_password=False,
|
||||
mepmanagedentry=[get_group_dn(self.uid)],
|
||||
memberof_group=[u'ipausers'],
|
||||
nsaccountlock=[u'false'],
|
||||
)
|
||||
|
||||
for key in self.kwargs:
|
||||
if key == u'krbprincipalname':
|
||||
try:
|
||||
self.attrs[key] = [u'%s@%s' % (
|
||||
(self.kwargs[key].split('@'))[0].lower(),
|
||||
(self.kwargs[key].split('@'))[1]
|
||||
)]
|
||||
except IndexError:
|
||||
# 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:
|
||||
self.attrs[key] = [self.kwargs[key]]
|
||||
else:
|
||||
self.attrs[key] = self.kwargs[key]
|
||||
|
||||
self.exists = True
|
||||
|
||||
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 parameters 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 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
|
||||
else:
|
||||
self.attrs[key] = [value]
|
||||
for key, value in expected_updates.items():
|
||||
if value is None or value is '' or value is u'':
|
||||
del self.attrs[key]
|
||||
else:
|
||||
self.attrs[key] = value
|
||||
|
||||
self.check_update(
|
||||
result,
|
||||
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))
|
||||
assert_deepequal(dict(
|
||||
value=self.uid,
|
||||
summary=u'Added user "%s"' % self.uid,
|
||||
result=self.filter_attrs(expected),
|
||||
), result)
|
||||
|
||||
def check_delete(self, result):
|
||||
""" Check 'user-del' command result """
|
||||
assert_deepequal(dict(
|
||||
value=[self.uid],
|
||||
summary=u'Deleted user "%s"' % self.uid,
|
||||
result=dict(failed=[]),
|
||||
), result)
|
||||
|
||||
def check_retrieve(self, result, all=False, raw=False):
|
||||
""" Check 'user-show' command result """
|
||||
if u'preserved' in self.attrs and self.attrs[u'preserved']:
|
||||
self.retrieve_all_keys = self.retrieve_preserved_all_keys
|
||||
self.retrieve_keys = self.retrieve_preserved_keys
|
||||
elif u'preserved' not in self.attrs and all:
|
||||
self.attrs[u'preserved'] = False
|
||||
|
||||
if all:
|
||||
expected = self.filter_attrs(self.retrieve_all_keys)
|
||||
else:
|
||||
expected = self.filter_attrs(self.retrieve_keys)
|
||||
|
||||
# small override because stageuser-find returns different type
|
||||
# of nsaccountlock value than DS, but overall the value fits
|
||||
# expected result
|
||||
if u'nsaccountlock' in expected:
|
||||
if expected[u'nsaccountlock'] == [u'true']:
|
||||
expected[u'nsaccountlock'] = True
|
||||
elif expected[u'nsaccountlock'] == [u'false']:
|
||||
expected[u'nsaccountlock'] = False
|
||||
|
||||
assert_deepequal(dict(
|
||||
value=self.uid,
|
||||
summary=None,
|
||||
result=expected,
|
||||
), result)
|
||||
|
||||
def check_find(self, result, all=False, pkey_only=False, raw=False,
|
||||
expected_override=None):
|
||||
""" Check 'user-find' command result """
|
||||
if all:
|
||||
if u'preserved' not in self.attrs:
|
||||
self.attrs.update(preserved=False)
|
||||
expected = self.filter_attrs(self.find_all_keys)
|
||||
elif pkey_only:
|
||||
expected = self.filter_attrs(self.primary_keys)
|
||||
else:
|
||||
expected = self.filter_attrs(self.find_keys)
|
||||
|
||||
if all and self.attrs[u'preserved']:
|
||||
del expected[u'mepmanagedentry']
|
||||
|
||||
if u'nsaccountlock' in expected:
|
||||
if expected[u'nsaccountlock'] == [u'true']:
|
||||
expected[u'nsaccountlock'] = True
|
||||
elif expected[u'nsaccountlock'] == [u'false']:
|
||||
expected[u'nsaccountlock'] = False
|
||||
|
||||
if expected_override:
|
||||
assert isinstance(expected_override, dict)
|
||||
expected.update(expected_override)
|
||||
|
||||
assert_deepequal(dict(
|
||||
count=1,
|
||||
truncated=False,
|
||||
summary=u'1 user matched',
|
||||
result=[expected],
|
||||
), result)
|
||||
|
||||
def check_find_nomatch(self, result):
|
||||
""" Check 'user-find' command result when no user should be found """
|
||||
assert_deepequal(dict(
|
||||
count=0,
|
||||
truncated=False,
|
||||
summary=u'0 users matched',
|
||||
result=[],
|
||||
), result)
|
||||
|
||||
def check_update(self, result, extra_keys=()):
|
||||
""" Check 'user-mod' command result """
|
||||
expected = self.filter_attrs(self.update_keys | set(extra_keys))
|
||||
if expected[u'nsaccountlock'] == [u'true']:
|
||||
expected[u'nsaccountlock'] = True
|
||||
elif expected[u'nsaccountlock'] == [u'false']:
|
||||
expected[u'nsaccountlock'] = False
|
||||
|
||||
assert_deepequal(dict(
|
||||
value=self.uid,
|
||||
summary=u'Modified user "%s"' % self.uid,
|
||||
result=expected
|
||||
), result)
|
||||
|
||||
def check_enable(self, result):
|
||||
""" Check result of enable user operation """
|
||||
assert_deepequal(dict(
|
||||
value=self.name,
|
||||
summary=u'Enabled user account "%s"' % self.name,
|
||||
result=True
|
||||
), result)
|
||||
|
||||
def check_disable(self, result):
|
||||
""" Check result of disable user operation """
|
||||
assert_deepequal(dict(
|
||||
value=self.name,
|
||||
summary=u'Disabled user account "%s"' % self.name,
|
||||
result=True
|
||||
), result)
|
||||
|
||||
def create_from_staged(self, stageduser):
|
||||
""" Copies attributes from staged user - helper function for
|
||||
activation tests """
|
||||
self.attrs = stageduser.attrs
|
||||
self.uid = stageduser.uid
|
||||
self.givenname = stageduser.givenname
|
||||
self.sn = stageduser.sn
|
||||
|
||||
self.attrs[u'mepmanagedentry'] = None
|
||||
self.attrs[u'dn'] = self.dn
|
||||
self.attrs[u'ipauniqueid'] = [fuzzy_uuid]
|
||||
self.attrs[u'memberof_group'] = [u'ipausers']
|
||||
self.attrs[u'mepmanagedentry'] = [u'cn=%s,%s,%s' % (
|
||||
self.uid, api.env.container_group, api.env.basedn
|
||||
)]
|
||||
self.attrs[u'objectclass'] = objectclasses.user
|
||||
if self.attrs[u'gidnumber'] == [u'-1']:
|
||||
self.attrs[u'gidnumber'] = [fuzzy_digits]
|
||||
if self.attrs[u'uidnumber'] == [u'-1']:
|
||||
self.attrs[u'uidnumber'] = [fuzzy_digits]
|
||||
|
||||
if u'ipasshpubkey' in self.kwargs:
|
||||
self.attrs[u'ipasshpubkey'] = [str(
|
||||
self.kwargs[u'ipasshpubkey']
|
||||
)]
|
||||
self.attrs[u'nsaccountlock'] = [u'false']
|
||||
|
||||
def check_activate(self, result):
|
||||
""" Check 'stageuser-activate' command result """
|
||||
expected = dict(
|
||||
value=self.uid,
|
||||
summary=u'Stage user %s activated' % self.uid,
|
||||
result=self.filter_attrs(self.activate_keys))
|
||||
|
||||
# small override because stageuser-find returns different
|
||||
# type of nsaccountlock value than DS, but overall the value
|
||||
# fits expected result
|
||||
if expected['result'][u'nsaccountlock'] == [u'true']:
|
||||
expected['result'][u'nsaccountlock'] = True
|
||||
elif expected['result'][u'nsaccountlock'] == [u'false']:
|
||||
expected['result'][u'nsaccountlock'] = False
|
||||
|
||||
assert_deepequal(expected, result)
|
||||
|
||||
self.exists = True
|
||||
|
||||
def check_undel(self, result):
|
||||
""" Check 'user-undel' command result """
|
||||
assert_deepequal(dict(
|
||||
value=self.uid,
|
||||
summary=u'Undeleted user account "%s"' % self.uid,
|
||||
result=True
|
||||
), result)
|
||||
|
||||
def enable(self):
|
||||
""" Enable user account if it was disabled """
|
||||
if (self.attrs['nsaccountlock'] is True or
|
||||
self.attrs['nsaccountlock'] == [u'true']):
|
||||
self.attrs.update(nsaccountlock=False)
|
||||
result = self.make_enable_command()()
|
||||
self.check_enable(result)
|
||||
|
||||
def disable(self):
|
||||
""" Disable user account if it was enabled """
|
||||
if (self.attrs['nsaccountlock'] is False or
|
||||
self.attrs['nsaccountlock'] == [u'false']):
|
||||
self.attrs.update(nsaccountlock=True)
|
||||
result = self.make_disable_command()()
|
||||
self.check_disable(result)
|
||||
|
||||
def track_delete(self, preserve=False):
|
||||
"""Update expected state for host deletion"""
|
||||
if preserve:
|
||||
self.exists = True
|
||||
if u'memberof_group' in self.attrs:
|
||||
del self.attrs[u'memberof_group']
|
||||
self.attrs[u'nsaccountlock'] = True
|
||||
self.attrs[u'preserved'] = True
|
||||
else:
|
||||
self.exists = False
|
||||
self.attrs = {}
|
||||
|
||||
def make_preserved_user(self):
|
||||
""" 'Creates' a preserved user necessary for some tests """
|
||||
self.ensure_exists()
|
||||
self.track_delete(preserve=True)
|
||||
command = self.make_delete_command(no_preserve=False, preserve=True)
|
||||
result = command()
|
||||
self.check_delete(result)
|
||||
|
||||
def check_attr_preservation(self, expected):
|
||||
""" Verifies that ipaUniqueID, uidNumber and gidNumber are
|
||||
preserved upon reactivation. Also verifies that resulting
|
||||
active user is a member of ipausers group only."""
|
||||
command = self.make_retrieve_command(all=True)
|
||||
result = command()
|
||||
|
||||
assert_deepequal(dict(
|
||||
ipauniqueid=result[u'result'][u'ipauniqueid'],
|
||||
uidnumber=result[u'result'][u'uidnumber'],
|
||||
gidnumber=result[u'result'][u'gidnumber']
|
||||
), expected)
|
||||
|
||||
if (u'memberof_group' not in result[u'result'] or
|
||||
result[u'result'][u'memberof_group'] != (u'ipausers',)):
|
||||
assert False
|
||||
|
||||
def make_fixture_restore(self, request):
|
||||
"""Make a pytest fixture for a preserved user that is to be moved to
|
||||
staged area.
|
||||
|
||||
The fixture ensures the plugin entry does not exist before
|
||||
and after the tests that use it. It takes into account
|
||||
that the preserved user no longer exists after restoring it,
|
||||
therefore the fixture verifies after the tests
|
||||
that the preserved user doesn't exist instead of deleting it.
|
||||
"""
|
||||
del_command = self.make_delete_command()
|
||||
try:
|
||||
del_command()
|
||||
except errors.NotFound:
|
||||
pass
|
||||
|
||||
def finish():
|
||||
with raises_exact(errors.NotFound(
|
||||
reason=u'%s: user not found' % self.uid)):
|
||||
del_command()
|
||||
|
||||
request.addfinalizer(finish)
|
||||
|
||||
return self
|
||||
|
||||
def make_admin(self, admin_group=u'admins'):
|
||||
""" Add user to the administrator's group """
|
||||
result = self.run_command('group_show', admin_group)
|
||||
admin_group_content = result[u'result'][u'member_user']
|
||||
admin_group_expected = list(admin_group_content) + [self.name]
|
||||
|
||||
command = self.make_group_add_member_command(
|
||||
admin_group, **dict(user=self.name)
|
||||
)
|
||||
result = command()
|
||||
assert_deepequal(dict(
|
||||
completed=1,
|
||||
failed=dict(
|
||||
member=dict(group=tuple(), user=tuple())
|
||||
),
|
||||
result={
|
||||
'dn': get_group_dn(admin_group),
|
||||
'member_user': admin_group_expected,
|
||||
'gidnumber': [fuzzy_digits],
|
||||
'cn': [admin_group],
|
||||
'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)
|
||||
Reference in New Issue
Block a user