diff options
-rw-r--r-- | API.txt | 74 | ||||
-rw-r--r-- | VERSION | 4 | ||||
-rw-r--r-- | install/share/60basev3.ldif | 1 | ||||
-rw-r--r-- | install/updates/40-vault.update | 19 | ||||
-rw-r--r-- | install/updates/Makefile.am | 1 | ||||
-rw-r--r-- | ipa-client/man/default.conf.5 | 1 | ||||
-rw-r--r-- | ipalib/constants.py | 1 | ||||
-rw-r--r-- | ipalib/plugins/vault.py | 321 | ||||
-rw-r--r-- | ipatests/test_xmlrpc/test_vault_plugin.py | 445 |
9 files changed, 865 insertions, 2 deletions
@@ -4717,6 +4717,80 @@ option: Str('version?', exclude='webui') output: Output('result', <type 'bool'>, None) output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) output: PrimaryKey('value', None, None) +command: vault_add +args: 1,9,3 +arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, required=True) +option: Str('addattr*', cli_name='addattr', exclude='webui') +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') +option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +option: Str('service?') +option: Str('setattr*', cli_name='setattr', exclude='webui') +option: Flag('shared?', autofill=True, default=False) +option: Str('user?') +option: Str('version?', exclude='webui') +output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) +output: PrimaryKey('value', None, None) +command: vault_del +args: 1,5,3 +arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=True, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) +option: Flag('continue', autofill=True, cli_name='continue', default=False) +option: Str('service?') +option: Flag('shared?', autofill=True, default=False) +option: Str('user?') +option: Str('version?', exclude='webui') +output: Output('result', <type 'dict'>, None) +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) +output: ListOfPrimaryKeys('value', None, None) +command: vault_find +args: 1,11,4 +arg: Str('criteria?', noextrawhitespace=False) +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') +option: Str('cn', attribute=True, autofill=False, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=False) +option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, query=True, required=False) +option: Flag('pkey_only?', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +option: Str('service?') +option: Flag('shared?', autofill=True, default=False) +option: Int('sizelimit?', autofill=False, minvalue=0) +option: Int('timelimit?', autofill=False, minvalue=0) +option: Str('user?') +option: Str('version?', exclude='webui') +output: Output('count', <type 'int'>, None) +output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None)) +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) +output: Output('truncated', <type 'bool'>, None) +command: vault_mod +args: 1,11,3 +arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) +option: Str('addattr*', cli_name='addattr', exclude='webui') +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') +option: Str('delattr*', cli_name='delattr', exclude='webui') +option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, required=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +option: Flag('rights', autofill=True, default=False) +option: Str('service?') +option: Str('setattr*', cli_name='setattr', exclude='webui') +option: Flag('shared?', autofill=True, default=False) +option: Str('user?') +option: Str('version?', exclude='webui') +output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) +output: PrimaryKey('value', None, None) +command: vault_show +args: 1,7,3 +arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +option: Flag('rights', autofill=True, default=False) +option: Str('service?') +option: Flag('shared?', autofill=True, default=False) +option: Str('user?') +option: Str('version?', exclude='webui') +output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) +output: PrimaryKey('value', None, None) capability: messages 2.52 capability: optional_uid_params 2.54 capability: permissions2 2.69 @@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=118 -# Last change: tbordaz - Add stageuser_find, stageuser_mod, stageuser_del, stageuser_show +IPA_API_VERSION_MINOR=119 +# Last change: edewata - Added vault plugin diff --git a/install/share/60basev3.ldif b/install/share/60basev3.ldif index eb1c1298b..33f4804e3 100644 --- a/install/share/60basev3.ldif +++ b/install/share/60basev3.ldif @@ -79,3 +79,4 @@ objectClasses: (2.16.840.1.113730.3.8.12.24 NAME 'ipaPublicKeyObject' DESC 'Wrap objectClasses: (2.16.840.1.113730.3.8.12.25 NAME 'ipaPrivateKeyObject' DESC 'Wrapped private keys' SUP top AUXILIARY MUST ( ipaPrivateKey $ ipaWrappingKey $ ipaWrappingMech ) X-ORIGIN 'IPA v4.1' ) objectClasses: (2.16.840.1.113730.3.8.12.26 NAME 'ipaSecretKeyObject' DESC 'Wrapped secret keys' SUP top AUXILIARY MUST ( ipaSecretKey $ ipaWrappingKey $ ipaWrappingMech ) X-ORIGIN 'IPA v4.1' ) objectClasses: (2.16.840.1.113730.3.8.12.34 NAME 'ipaSecretKeyRefObject' DESC 'Indirect storage for encoded key material' SUP top AUXILIARY MUST ( ipaSecretKeyRef ) X-ORIGIN 'IPA v4.1' ) +objectClasses: (2.16.840.1.113730.3.8.18.1.1 NAME 'ipaVault' DESC 'IPA vault' SUP top STRUCTURAL MUST ( cn ) MAY ( description ) X-ORIGIN 'IPA v4.2' ) diff --git a/install/updates/40-vault.update b/install/updates/40-vault.update new file mode 100644 index 000000000..5a6b8c6a0 --- /dev/null +++ b/install/updates/40-vault.update @@ -0,0 +1,19 @@ +dn: cn=vaults,$SUFFIX +default: objectClass: top +default: objectClass: nsContainer +default: cn: vaults + +dn: cn=services,cn=vaults,$SUFFIX +default: objectClass: top +default: objectClass: nsContainer +default: cn: services + +dn: cn=shared,cn=vaults,$SUFFIX +default: objectClass: top +default: objectClass: nsContainer +default: cn: shared + +dn: cn=users,cn=vaults,$SUFFIX +default: objectClass: top +default: objectClass: nsContainer +default: cn: users diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am index 0d63d9ea8..66f6b9d37 100644 --- a/install/updates/Makefile.am +++ b/install/updates/Makefile.am @@ -33,6 +33,7 @@ app_DATA = \ 40-dns.update \ 40-automember.update \ 40-otp.update \ + 40-vault.update \ 45-roles.update \ 50-7_bit_check.update \ 50-dogtag10-migration.update \ diff --git a/ipa-client/man/default.conf.5 b/ipa-client/man/default.conf.5 index dbc8a5b46..0973f1a07 100644 --- a/ipa-client/man/default.conf.5 +++ b/ipa-client/man/default.conf.5 @@ -221,6 +221,7 @@ The following define the containers for the IPA server. Containers define where container_sudocmdgroup: cn=sudocmdgroups,cn=sudo container_sudorule: cn=sudorules,cn=sudo container_user: cn=users,cn=accounts + container_vault: cn=vaults container_virtual: cn=virtual operations,cn=etc .SH "FILES" diff --git a/ipalib/constants.py b/ipalib/constants.py index f1e14702f..195938a35 100644 --- a/ipalib/constants.py +++ b/ipalib/constants.py @@ -99,6 +99,7 @@ DEFAULT_CONFIG = ( ('container_hbacservice', DN(('cn', 'hbacservices'), ('cn', 'hbac'))), ('container_hbacservicegroup', DN(('cn', 'hbacservicegroups'), ('cn', 'hbac'))), ('container_dns', DN(('cn', 'dns'))), + ('container_vault', DN(('cn', 'vaults'))), ('container_virtual', DN(('cn', 'virtual operations'), ('cn', 'etc'))), ('container_sudorule', DN(('cn', 'sudorules'), ('cn', 'sudo'))), ('container_sudocmd', DN(('cn', 'sudocmds'), ('cn', 'sudo'))), diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py new file mode 100644 index 000000000..ebb9f9fd3 --- /dev/null +++ b/ipalib/plugins/vault.py @@ -0,0 +1,321 @@ +# Authors: +# Endi S. Dewata <edewata@redhat.com> +# +# Copyright (C) 2015 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from ipalib import api, errors +from ipalib import Str, Flag +from ipalib import output +from ipalib.plugable import Registry +from ipalib.plugins.baseldap import LDAPObject, LDAPCreate, LDAPDelete,\ + LDAPSearch, LDAPUpdate, LDAPRetrieve +from ipalib.request import context +from ipalib.plugins.user import split_principal +from ipalib import _, ngettext +from ipapython.dn import DN + +__doc__ = _(""" +Vaults +""") + _(""" +Manage vaults. +""") + _(""" +EXAMPLES: +""") + _(""" + List private vaults: + ipa vault-find +""") + _(""" + List service vaults: + ipa vault-find --service <service name> +""") + _(""" + List shared vaults: + ipa vault-find --shared +""") + _(""" + List user vaults: + ipa vault-find --user <username> +""") + _(""" + Add a private vault: + ipa vault-add <name> +""") + _(""" + Add a service vault: + ipa vault-add <name> --service <service name> +""") + _(""" + Add a shared vault: + ipa vault-add <ame> --shared +""") + _(""" + Add a user vault: + ipa vault-add <name> --user <username> +""") + _(""" + Show a private vault: + ipa vault-show <name> +""") + _(""" + Show a service vault: + ipa vault-show <name> --service <service name> +""") + _(""" + Show a shared vault: + ipa vault-show <name> --shared +""") + _(""" + Show a user vault: + ipa vault-show <name> --user <username> +""") + _(""" + Modify a private vault: + ipa vault-mod <name> --desc <description> +""") + _(""" + Modify a service vault: + ipa vault-mod <name> --service <service name> --desc <description> +""") + _(""" + Modify a shared vault: + ipa vault-mod <name> --shared --desc <description> +""") + _(""" + Modify a user vault: + ipa vault-mod <name> --user <username> --desc <description> +""") + _(""" + Delete a private vault: + ipa vault-del <name> +""") + _(""" + Delete a service vault: + ipa vault-del <name> --service <service name> +""") + _(""" + Delete a shared vault: + ipa vault-del <name> --shared +""") + _(""" + Delete a user vault: + ipa vault-del <name> --user <username> +""") + +register = Registry() + + +vault_options = ( + Str( + 'service?', + doc=_('Service name'), + ), + Flag( + 'shared?', + doc=_('Shared vault'), + ), + Str( + 'user?', + doc=_('Username'), + ), +) + + +@register() +class vault(LDAPObject): + __doc__ = _(""" + Vault object. + """) + + container_dn = api.env.container_vault + + object_name = _('vault') + object_name_plural = _('vaults') + + object_class = ['ipaVault'] + default_attributes = [ + 'cn', + 'description', + ] + + label = _('Vaults') + label_singular = _('Vault') + + takes_params = ( + Str( + 'cn', + cli_name='name', + label=_('Vault name'), + primary_key=True, + pattern='^[a-zA-Z0-9_.-]+$', + pattern_errmsg='may only include letters, numbers, _, ., and -', + maxlength=255, + ), + Str( + 'description?', + cli_name='desc', + label=_('Description'), + doc=_('Vault description'), + ), + ) + + def get_dn(self, *keys, **options): + """ + Generates vault DN from parameters. + """ + + service = options.get('service') + shared = options.get('shared') + user = options.get('user') + + count = 0 + if service: + count += 1 + + if shared: + count += 1 + + if user: + count += 1 + + if count > 1: + raise errors.MutuallyExclusiveError( + reason=_('Service, shared, and user options ' + + 'cannot be specified simultaneously')) + + # TODO: create container_dn after object initialization then reuse it + container_dn = DN(self.container_dn, self.api.env.basedn) + + dn = super(vault, self).get_dn(*keys, **options) + assert dn.endswith(container_dn) + rdns = DN(*dn[:-len(container_dn)]) + + if not count: + principal = getattr(context, 'principal') + + if principal.startswith('host/'): + raise errors.NotImplementedError( + reason=_('Host is not supported')) + + (name, realm) = split_principal(principal) + if '/' in name: + service = name + else: + user = name + + if service: + parent_dn = DN(('cn', service), ('cn', 'services'), container_dn) + elif shared: + parent_dn = DN(('cn', 'shared'), container_dn) + else: + parent_dn = DN(('cn', user), ('cn', 'users'), container_dn) + + return DN(rdns, parent_dn) + + def create_container(self, dn): + """ + Creates vault container and its parents. + """ + + # TODO: create container_dn after object initialization then reuse it + container_dn = DN(self.container_dn, self.api.env.basedn) + + entries = [] + + while dn: + assert dn.endswith(container_dn) + + rdn = dn[0] + entry = self.backend.make_entry( + dn, + { + 'objectclass': ['nsContainer'], + 'cn': rdn['cn'], + }) + + # if entry can be added, return + try: + self.backend.add_entry(entry) + break + + except errors.NotFound: + pass + + # otherwise, create parent entry first + dn = DN(*dn[1:]) + entries.insert(0, entry) + + # then create the entries again + for entry in entries: + self.backend.add_entry(entry) + + +@register() +class vault_add(LDAPCreate): + __doc__ = _('Create a new vault.') + + takes_options = LDAPCreate.takes_options + vault_options + + msg_summary = _('Added vault "%(value)s"') + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, + **options): + assert isinstance(dn, DN) + + try: + parent_dn = DN(*dn[1:]) + self.obj.create_container(parent_dn) + except errors.DuplicateEntry, e: + pass + + return dn + + +@register() +class vault_del(LDAPDelete): + __doc__ = _('Delete a vault.') + + takes_options = LDAPDelete.takes_options + vault_options + + msg_summary = _('Deleted vault "%(value)s"') + + +@register() +class vault_find(LDAPSearch): + __doc__ = _('Search for vaults.') + + takes_options = LDAPSearch.takes_options + vault_options + + msg_summary = ngettext( + '%(count)d vault matched', + '%(count)d vaults matched', + 0, + ) + + def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, + **options): + assert isinstance(base_dn, DN) + + base_dn = self.obj.get_dn(*args, **options) + + return (filter, base_dn, scope) + + def exc_callback(self, args, options, exc, call_func, *call_args, + **call_kwargs): + if call_func.__name__ == 'find_entries': + if isinstance(exc, errors.NotFound): + # ignore missing containers since they will be created + # automatically on vault creation. + raise errors.EmptyResult(reason=str(exc)) + + raise exc + + +@register() +class vault_mod(LDAPUpdate): + __doc__ = _('Modify a vault.') + + takes_options = LDAPUpdate.takes_options + vault_options + + msg_summary = _('Modified vault "%(value)s"') + + +@register() +class vault_show(LDAPRetrieve): + __doc__ = _('Display information about a vault.') + + takes_options = LDAPRetrieve.takes_options + vault_options diff --git a/ipatests/test_xmlrpc/test_vault_plugin.py b/ipatests/test_xmlrpc/test_vault_plugin.py new file mode 100644 index 000000000..44d397c58 --- /dev/null +++ b/ipatests/test_xmlrpc/test_vault_plugin.py @@ -0,0 +1,445 @@ +# Authors: +# Endi S. Dewata <edewata@redhat.com> +# +# Copyright (C) 2015 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Test the `ipalib/plugins/vault.py` module. +""" + +from ipalib import api, errors +from xmlrpc_test import Declarative, fuzzy_string + +vault_name = u'test_vault' +service_name = u'HTTP/server.example.com' +user_name = u'testuser' + + +class test_vault_plugin(Declarative): + + cleanup_commands = [ + ('vault_del', [vault_name], {'continue': True}), + ('vault_del', [vault_name], { + 'service': service_name, + 'continue': True + }), + ('vault_del', [vault_name], {'shared': True, 'continue': True}), + ('vault_del', [vault_name], {'user': user_name, 'continue': True}), + ] + + tests = [ + + { + 'desc': 'Create private vault', + 'command': ( + 'vault_add', + [vault_name], + {}, + ), + 'expected': { + 'value': vault_name, + 'summary': 'Added vault "%s"' % vault_name, + 'result': { + 'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,%s' + % (vault_name, api.env.basedn), + 'objectclass': [u'top', u'ipaVault'], + 'cn': [vault_name], + }, + }, + }, + + { + 'desc': 'Find private vaults', + 'command': ( + 'vault_find', + [], + {}, + ), + 'expected': { + 'count': 1, + 'truncated': False, + 'summary': u'1 vault matched', + 'result': [ + { + 'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,%s' + % (vault_name, api.env.basedn), + 'cn': [vault_name], + }, + ], + }, + }, + + { + 'desc': 'Show private vault', + 'command': ( + 'vault_show', + [vault_name], + {}, + ), + 'expected': { + 'value': vault_name, + 'summary': None, + 'result': { + 'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,%s' + % (vault_name, api.env.basedn), + 'cn': [vault_name], + }, + }, + }, + + { + 'desc': 'Modify private vault', + 'command': ( + 'vault_mod', + [vault_name], + { + 'description': u'Test vault', + }, + ), + 'expected': { + 'value': vault_name, + 'summary': u'Modified vault "%s"' % vault_name, + 'result': { + 'cn': [vault_name], + 'description': [u'Test vault'], + }, + }, + }, + + { + 'desc': 'Delete private vault', + 'command': ( + 'vault_del', + [vault_name], + {}, + ), + 'expected': { + 'value': [vault_name], + 'summary': u'Deleted vault "%s"' % vault_name, + 'result': { + 'failed': (), + }, + }, + }, + + { + 'desc': 'Create service vault', + 'command': ( + 'vault_add', + [vault_name], + { + 'service': service_name, + }, + ), + 'expected': { + 'value': vault_name, + 'summary': u'Added vault "%s"' % vault_name, + 'result': { + 'dn': u'cn=%s,cn=%s,cn=services,cn=vaults,%s' + % (vault_name, service_name, api.env.basedn), + 'objectclass': [u'top', u'ipaVault'], + 'cn': [vault_name], + }, + }, + }, + + { + 'desc': 'Find service vaults', + 'command': ( + 'vault_find', + [], + { + 'service': service_name, + }, + ), + 'expected': { + 'count': 1, + 'truncated': False, + 'summary': u'1 vault matched', + 'result': [ + { + 'dn': u'cn=%s,cn=%s,cn=services,cn=vaults,%s' + % (vault_name, service_name, api.env.basedn), + 'cn': [vault_name], + }, + ], + }, + }, + + { + 'desc': 'Show service vault', + 'command': ( + 'vault_show', + [vault_name], + { + 'service': service_name, + }, + ), + 'expected': { + 'value': vault_name, + 'summary': None, + 'result': { + 'dn': u'cn=%s,cn=%s,cn=services,cn=vaults,%s' + % (vault_name, service_name, api.env.basedn), + 'cn': [vault_name], + }, + }, + }, + + { + 'desc': 'Modify service vault', + 'command': ( + 'vault_mod', + [vault_name], + { + 'service': service_name, + 'description': u'Test vault', + }, + ), + 'expected': { + 'value': vault_name, + 'summary': u'Modified vault "%s"' % vault_name, + 'result': { + 'cn': [vault_name], + 'description': [u'Test vault'], + }, + }, + }, + + { + 'desc': 'Delete service vault', + 'command': ( + 'vault_del', + [vault_name], + { + 'service': service_name, + }, + ), + 'expected': { + 'value': [vault_name], + 'summary': u'Deleted vault "%s"' % vault_name, + 'result': { + 'failed': (), + }, + }, + }, + + { + 'desc': 'Create shared vault', + 'command': ( + 'vault_add', + [vault_name], + { + 'shared': True + }, + ), + 'expected': { + 'value': vault_name, + 'summary': u'Added vault "%s"' % vault_name, + 'result': { + 'dn': u'cn=%s,cn=shared,cn=vaults,%s' + % (vault_name, api.env.basedn), + 'objectclass': [u'top', u'ipaVault'], + 'cn': [vault_name], + }, + }, + }, + + { + 'desc': 'Find shared vaults', + 'command': ( + 'vault_find', + [], + { + 'shared': True + }, + ), + 'expected': { + 'count': 1, + 'truncated': False, + 'summary': u'1 vault matched', + 'result': [ + { + 'dn': u'cn=%s,cn=shared,cn=vaults,%s' + % (vault_name, api.env.basedn), + 'cn': [vault_name], + }, + ], + }, + }, + + { + 'desc': 'Show shared vault', + 'command': ( + 'vault_show', + [vault_name], + { + 'shared': True + }, + ), + 'expected': { + 'value': vault_name, + 'summary': None, + 'result': { + 'dn': u'cn=%s,cn=shared,cn=vaults,%s' + % (vault_name, api.env.basedn), + 'cn': [vault_name], + }, + }, + }, + + { + 'desc': 'Modify shared vault', + 'command': ( + 'vault_mod', + [vault_name], + { + 'shared': True, + 'description': u'Test vault', + }, + ), + 'expected': { + 'value': vault_name, + 'summary': u'Modified vault "%s"' % vault_name, + 'result': { + 'cn': [vault_name], + 'description': [u'Test vault'], + }, + }, + }, + + { + 'desc': 'Delete shared vault', + 'command': ( + 'vault_del', + [vault_name], + { + 'shared': True + }, + ), + 'expected': { + 'value': [vault_name], + 'summary': u'Deleted vault "%s"' % vault_name, + 'result': { + 'failed': (), + }, + }, + }, + + { + 'desc': 'Create user vault', + 'command': ( + 'vault_add', + [vault_name], + { + 'user': user_name, + }, + ), + 'expected': { + 'value': vault_name, + 'summary': u'Added vault "%s"' % vault_name, + 'result': { + 'dn': u'cn=%s,cn=%s,cn=users,cn=vaults,%s' + % (vault_name, user_name, api.env.basedn), + 'objectclass': [u'top', u'ipaVault'], + 'cn': [vault_name], + }, + }, + }, + + { + 'desc': 'Find user vaults', + 'command': ( + 'vault_find', + [], + { + 'user': user_name, + }, + ), + 'expected': { + 'count': 1, + 'truncated': False, + 'summary': u'1 vault matched', + 'result': [ + { + 'dn': u'cn=%s,cn=%s,cn=users,cn=vaults,%s' + % (vault_name, user_name, api.env.basedn), + 'cn': [vault_name], + }, + ], + }, + }, + + { + 'desc': 'Show user vault', + 'command': ( + 'vault_show', + [vault_name], + { + 'user': user_name, + }, + ), + 'expected': { + 'value': vault_name, + 'summary': None, + 'result': { + 'dn': u'cn=%s,cn=%s,cn=users,cn=vaults,%s' + % (vault_name, user_name, api.env.basedn), + 'cn': [vault_name], + }, + }, + }, + + { + 'desc': 'Modify user vault', + 'command': ( + 'vault_mod', + [vault_name], + { + 'user': user_name, + 'description': u'Test vault', + }, + ), + 'expected': { + 'value': vault_name, + 'summary': u'Modified vault "%s"' % vault_name, + 'result': { + 'cn': [vault_name], + 'description': [u'Test vault'], + }, + }, + }, + + { + 'desc': 'Delete user vault', + 'command': ( + 'vault_del', + [vault_name], + { + 'user': user_name, + }, + ), + 'expected': { + 'value': [vault_name], + 'summary': u'Deleted vault "%s"' % vault_name, + 'result': { + 'failed': (), + }, + }, + }, + + ] |