|
|
590d18 |
From 83bfd97806d3900f62cac007b66cc8daa0c45234 Mon Sep 17 00:00:00 2001
|
|
|
590d18 |
From: Petr Vobornik <pvoborni@redhat.com>
|
|
|
590d18 |
Date: Tue, 25 Aug 2015 19:56:00 +0200
|
|
|
590d18 |
Subject: [PATCH] vault: add vault container commands
|
|
|
590d18 |
|
|
|
590d18 |
adds commands:
|
|
|
590d18 |
* vaultcontainer-show [--service <service>|--user <user>|--shared ]
|
|
|
590d18 |
* vaultcontainer-del [--service <service>|--user <user>|--shared ]
|
|
|
590d18 |
* vaultcontainer-add-owner
|
|
|
590d18 |
[--service <service>|--user <user>|--shared ]
|
|
|
590d18 |
[--users <users>] [--groups <groups>] [--services <services>]
|
|
|
590d18 |
* vaultcontainer-remove-owner
|
|
|
590d18 |
[--service <service>|--user <user>|--shared ]
|
|
|
590d18 |
[--users <users>] [--groups <groups>] [--services <services>]
|
|
|
590d18 |
|
|
|
590d18 |
https://fedorahosted.org/freeipa/ticket/5250
|
|
|
590d18 |
|
|
|
590d18 |
Reviewed-By: Petr Vobornik <pvoborni@redhat.com>
|
|
|
590d18 |
---
|
|
|
590d18 |
API.txt | 53 +++++++++++
|
|
|
590d18 |
VERSION | 4 +-
|
|
|
590d18 |
ipalib/plugins/vault.py | 243 +++++++++++++++++++++++++++++++++++++++++++-----
|
|
|
590d18 |
3 files changed, 277 insertions(+), 23 deletions(-)
|
|
|
590d18 |
|
|
|
590d18 |
diff --git a/API.txt b/API.txt
|
|
|
590d18 |
index 5253e1585e000f39d6e185a94548037dfe54d4d8..4d36a9885157de13529573b3a386b4ef39eba176 100644
|
|
|
590d18 |
--- a/API.txt
|
|
|
590d18 |
+++ b/API.txt
|
|
|
590d18 |
@@ -5667,6 +5667,59 @@ option: Str('version?', exclude='webui')
|
|
|
590d18 |
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
|
|
590d18 |
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
|
|
590d18 |
output: PrimaryKey('value', None, None)
|
|
|
590d18 |
+command: vaultcontainer_add_owner
|
|
|
590d18 |
+args: 0,10,3
|
|
|
590d18 |
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
|
|
|
590d18 |
+option: Str('group*', alwaysask=True, cli_name='groups', csv=True)
|
|
|
590d18 |
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
|
|
|
590d18 |
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
|
|
|
590d18 |
+option: Str('service?')
|
|
|
590d18 |
+option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False)
|
|
|
590d18 |
+option: Flag('shared?', autofill=True, default=False)
|
|
|
590d18 |
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
|
|
|
590d18 |
+option: Str('username?', cli_name='user')
|
|
|
590d18 |
+option: Str('version?', exclude='webui')
|
|
|
590d18 |
+output: Output('completed', <type 'int'>, None)
|
|
|
590d18 |
+output: Output('failed', <type 'dict'>, None)
|
|
|
590d18 |
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
|
|
590d18 |
+command: vaultcontainer_del
|
|
|
590d18 |
+args: 0,5,3
|
|
|
590d18 |
+option: Flag('continue', autofill=True, cli_name='continue', default=False)
|
|
|
590d18 |
+option: Str('service?')
|
|
|
590d18 |
+option: Flag('shared?', autofill=True, default=False)
|
|
|
590d18 |
+option: Str('username?', cli_name='user')
|
|
|
590d18 |
+option: Str('version?', exclude='webui')
|
|
|
590d18 |
+output: Output('result', <type 'dict'>, None)
|
|
|
590d18 |
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
|
|
590d18 |
+output: ListOfPrimaryKeys('value', None, None)
|
|
|
590d18 |
+command: vaultcontainer_remove_owner
|
|
|
590d18 |
+args: 0,10,3
|
|
|
590d18 |
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
|
|
|
590d18 |
+option: Str('group*', alwaysask=True, cli_name='groups', csv=True)
|
|
|
590d18 |
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
|
|
|
590d18 |
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
|
|
|
590d18 |
+option: Str('service?')
|
|
|
590d18 |
+option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False)
|
|
|
590d18 |
+option: Flag('shared?', autofill=True, default=False)
|
|
|
590d18 |
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
|
|
|
590d18 |
+option: Str('username?', cli_name='user')
|
|
|
590d18 |
+option: Str('version?', exclude='webui')
|
|
|
590d18 |
+output: Output('completed', <type 'int'>, None)
|
|
|
590d18 |
+output: Output('failed', <type 'dict'>, None)
|
|
|
590d18 |
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
|
|
590d18 |
+command: vaultcontainer_show
|
|
|
590d18 |
+args: 0,8,3
|
|
|
590d18 |
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
|
|
|
590d18 |
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
|
|
|
590d18 |
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
|
|
|
590d18 |
+option: Flag('rights', autofill=True, default=False)
|
|
|
590d18 |
+option: Str('service?')
|
|
|
590d18 |
+option: Flag('shared?', autofill=True, default=False)
|
|
|
590d18 |
+option: Str('username?', cli_name='user')
|
|
|
590d18 |
+option: Str('version?', exclude='webui')
|
|
|
590d18 |
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
|
|
590d18 |
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
|
|
590d18 |
+output: PrimaryKey('value', None, None)
|
|
|
590d18 |
capability: messages 2.52
|
|
|
590d18 |
capability: optional_uid_params 2.54
|
|
|
590d18 |
capability: permissions2 2.69
|
|
|
590d18 |
diff --git a/VERSION b/VERSION
|
|
|
590d18 |
index da721fdd548023dc3dcd9b4f6a8ba72922a3c6f2..c2b5c87a2615d77e75259edfb8e3a6b7740fac52 100644
|
|
|
590d18 |
--- a/VERSION
|
|
|
590d18 |
+++ b/VERSION
|
|
|
590d18 |
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
|
|
|
590d18 |
# #
|
|
|
590d18 |
########################################################
|
|
|
590d18 |
IPA_API_VERSION_MAJOR=2
|
|
|
590d18 |
-IPA_API_VERSION_MINOR=155
|
|
|
590d18 |
-# Last change: ftweedal - remove certprofile 'rename' option
|
|
|
590d18 |
+IPA_API_VERSION_MINOR=156
|
|
|
590d18 |
+# Last change: pvoborni - add vault container commands
|
|
|
590d18 |
diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py
|
|
|
590d18 |
index e369eeee20f5652942681f7c3e268e6173005452..733741dfc2c87995055599cc3816f321ec344496 100644
|
|
|
590d18 |
--- a/ipalib/plugins/vault.py
|
|
|
590d18 |
+++ b/ipalib/plugins/vault.py
|
|
|
590d18 |
@@ -257,6 +257,228 @@ vault_options = (
|
|
|
590d18 |
)
|
|
|
590d18 |
|
|
|
590d18 |
|
|
|
590d18 |
+class VaultModMember(LDAPModMember):
|
|
|
590d18 |
+ def get_options(self):
|
|
|
590d18 |
+ for param in super(VaultModMember, self).get_options():
|
|
|
590d18 |
+ if param.name == 'service' and param not in vault_options:
|
|
|
590d18 |
+ param = param.clone_rename('services')
|
|
|
590d18 |
+ yield param
|
|
|
590d18 |
+
|
|
|
590d18 |
+ def get_member_dns(self, **options):
|
|
|
590d18 |
+ if 'services' in options:
|
|
|
590d18 |
+ options['service'] = options.pop('services')
|
|
|
590d18 |
+ else:
|
|
|
590d18 |
+ options.pop('service', None)
|
|
|
590d18 |
+ return super(VaultModMember, self).get_member_dns(**options)
|
|
|
590d18 |
+
|
|
|
590d18 |
+ def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
|
|
|
590d18 |
+ for fail in failed.itervalues():
|
|
|
590d18 |
+ fail['services'] = fail.pop('service', [])
|
|
|
590d18 |
+ self.obj.get_container_attribute(entry_attrs, options)
|
|
|
590d18 |
+ return completed, dn
|
|
|
590d18 |
+
|
|
|
590d18 |
+
|
|
|
590d18 |
+@register()
|
|
|
590d18 |
+class vaultcontainer(LDAPObject):
|
|
|
590d18 |
+ __doc__ = _("""
|
|
|
590d18 |
+ Vault Container object.
|
|
|
590d18 |
+ """)
|
|
|
590d18 |
+
|
|
|
590d18 |
+ container_dn = api.env.container_vault
|
|
|
590d18 |
+
|
|
|
590d18 |
+ object_name = _('vaultcontainer')
|
|
|
590d18 |
+ object_name_plural = _('vaultcontainers')
|
|
|
590d18 |
+ object_class = ['ipaVaultContainer']
|
|
|
590d18 |
+
|
|
|
590d18 |
+ attribute_members = {
|
|
|
590d18 |
+ 'owner': ['user', 'group', 'service'],
|
|
|
590d18 |
+ }
|
|
|
590d18 |
+
|
|
|
590d18 |
+ label = _('Vault Containers')
|
|
|
590d18 |
+ label_singular = _('Vault Container')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ takes_params = (
|
|
|
590d18 |
+ Str(
|
|
|
590d18 |
+ 'owner_user?',
|
|
|
590d18 |
+ label=_('Owner users'),
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ Str(
|
|
|
590d18 |
+ 'owner_group?',
|
|
|
590d18 |
+ label=_('Owner groups'),
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ Str(
|
|
|
590d18 |
+ 'owner_service?',
|
|
|
590d18 |
+ label=_('Owner services'),
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ Str(
|
|
|
590d18 |
+ 'owner?',
|
|
|
590d18 |
+ label=_('Failed owners'),
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ Str(
|
|
|
590d18 |
+ 'service?',
|
|
|
590d18 |
+ label=_('Vault service'),
|
|
|
590d18 |
+ flags={'virtual_attribute'},
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ Flag(
|
|
|
590d18 |
+ 'shared?',
|
|
|
590d18 |
+ label=_('Shared vault'),
|
|
|
590d18 |
+ flags={'virtual_attribute'},
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ Str(
|
|
|
590d18 |
+ 'username?',
|
|
|
590d18 |
+ label=_('Vault user'),
|
|
|
590d18 |
+ flags={'virtual_attribute'},
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ )
|
|
|
590d18 |
+
|
|
|
590d18 |
+ def get_dn(self, *keys, **options):
|
|
|
590d18 |
+ """
|
|
|
590d18 |
+ Generates vault DN from parameters.
|
|
|
590d18 |
+ """
|
|
|
590d18 |
+ service = options.get('service')
|
|
|
590d18 |
+ shared = options.get('shared')
|
|
|
590d18 |
+ user = options.get('username')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ count = (bool(service) + bool(shared) + bool(user))
|
|
|
590d18 |
+ if count > 1:
|
|
|
590d18 |
+ raise errors.MutuallyExclusiveError(
|
|
|
590d18 |
+ reason=_('Service, shared and user options ' +
|
|
|
590d18 |
+ 'cannot be specified simultaneously'))
|
|
|
590d18 |
+
|
|
|
590d18 |
+ parent_dn = super(vaultcontainer, self).get_dn(*keys, **options)
|
|
|
590d18 |
+
|
|
|
590d18 |
+ if not count:
|
|
|
590d18 |
+ principal = getattr(context, 'principal')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ if principal.startswith('host/'):
|
|
|
590d18 |
+ raise errors.NotImplementedError(
|
|
|
590d18 |
+ reason=_('Host is not supported'))
|
|
|
590d18 |
+
|
|
|
590d18 |
+ (name, realm) = split_principal(principal)
|
|
|
590d18 |
+ if '/' in name:
|
|
|
590d18 |
+ service = name
|
|
|
590d18 |
+ else:
|
|
|
590d18 |
+ user = name
|
|
|
590d18 |
+
|
|
|
590d18 |
+ if service:
|
|
|
590d18 |
+ dn = DN(('cn', service), ('cn', 'services'), parent_dn)
|
|
|
590d18 |
+ elif shared:
|
|
|
590d18 |
+ dn = DN(('cn', 'shared'), parent_dn)
|
|
|
590d18 |
+ elif user:
|
|
|
590d18 |
+ dn = DN(('cn', user), ('cn', 'users'), parent_dn)
|
|
|
590d18 |
+ else:
|
|
|
590d18 |
+ raise RuntimeError
|
|
|
590d18 |
+
|
|
|
590d18 |
+ return dn
|
|
|
590d18 |
+
|
|
|
590d18 |
+ def get_container_attribute(self, entry, options):
|
|
|
590d18 |
+ if options.get('raw', False):
|
|
|
590d18 |
+ return
|
|
|
590d18 |
+ container_dn = DN(self.container_dn, self.api.env.basedn)
|
|
|
590d18 |
+ if entry.dn.endswith(DN(('cn', 'services'), container_dn)):
|
|
|
590d18 |
+ entry['service'] = entry.dn[0]['cn']
|
|
|
590d18 |
+ elif entry.dn.endswith(DN(('cn', 'shared'), container_dn)):
|
|
|
590d18 |
+ entry['shared'] = True
|
|
|
590d18 |
+ elif entry.dn.endswith(DN(('cn', 'users'), container_dn)):
|
|
|
590d18 |
+ entry['username'] = entry.dn[0]['cn']
|
|
|
590d18 |
+
|
|
|
590d18 |
+
|
|
|
590d18 |
+@register()
|
|
|
590d18 |
+class vaultcontainer_show(LDAPRetrieve):
|
|
|
590d18 |
+ __doc__ = _('Display information about a vault container.')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ takes_options = LDAPRetrieve.takes_options + vault_options
|
|
|
590d18 |
+
|
|
|
590d18 |
+ has_output_params = LDAPRetrieve.has_output_params
|
|
|
590d18 |
+
|
|
|
590d18 |
+ def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
|
|
|
590d18 |
+ assert isinstance(dn, DN)
|
|
|
590d18 |
+
|
|
|
590d18 |
+ if not self.api.Command.kra_is_enabled()['result']:
|
|
|
590d18 |
+ raise errors.InvocationError(
|
|
|
590d18 |
+ format=_('KRA service is not enabled'))
|
|
|
590d18 |
+
|
|
|
590d18 |
+ return dn
|
|
|
590d18 |
+
|
|
|
590d18 |
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
|
|
|
590d18 |
+ self.obj.get_container_attribute(entry_attrs, options)
|
|
|
590d18 |
+ return dn
|
|
|
590d18 |
+
|
|
|
590d18 |
+
|
|
|
590d18 |
+@register()
|
|
|
590d18 |
+class vaultcontainer_del(LDAPDelete):
|
|
|
590d18 |
+ __doc__ = _('Delete a vault container.')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ takes_options = LDAPDelete.takes_options + vault_options
|
|
|
590d18 |
+
|
|
|
590d18 |
+ msg_summary = _('Deleted vault container')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ subtree_delete = False
|
|
|
590d18 |
+
|
|
|
590d18 |
+ def pre_callback(self, ldap, dn, *keys, **options):
|
|
|
590d18 |
+ assert isinstance(dn, DN)
|
|
|
590d18 |
+
|
|
|
590d18 |
+ if not self.api.Command.kra_is_enabled()['result']:
|
|
|
590d18 |
+ raise errors.InvocationError(
|
|
|
590d18 |
+ format=_('KRA service is not enabled'))
|
|
|
590d18 |
+
|
|
|
590d18 |
+ return dn
|
|
|
590d18 |
+
|
|
|
590d18 |
+ def execute(self, *keys, **options):
|
|
|
590d18 |
+ keys = keys + (u'',)
|
|
|
590d18 |
+ return super(vaultcontainer_del, self).execute(*keys, **options)
|
|
|
590d18 |
+
|
|
|
590d18 |
+
|
|
|
590d18 |
+@register()
|
|
|
590d18 |
+class vaultcontainer_add_owner(VaultModMember, LDAPAddMember):
|
|
|
590d18 |
+ __doc__ = _('Add owners to a vault container.')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ takes_options = LDAPAddMember.takes_options + vault_options
|
|
|
590d18 |
+
|
|
|
590d18 |
+ member_attributes = ['owner']
|
|
|
590d18 |
+ member_param_label = _('owner %s')
|
|
|
590d18 |
+ member_count_out = ('%i owner added.', '%i owners added.')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ has_output = (
|
|
|
590d18 |
+ output.Entry('result'),
|
|
|
590d18 |
+ output.Output(
|
|
|
590d18 |
+ 'failed',
|
|
|
590d18 |
+ type=dict,
|
|
|
590d18 |
+ doc=_('Owners that could not be added'),
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ output.Output(
|
|
|
590d18 |
+ 'completed',
|
|
|
590d18 |
+ type=int,
|
|
|
590d18 |
+ doc=_('Number of owners added'),
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ )
|
|
|
590d18 |
+
|
|
|
590d18 |
+
|
|
|
590d18 |
+@register()
|
|
|
590d18 |
+class vaultcontainer_remove_owner(VaultModMember, LDAPRemoveMember):
|
|
|
590d18 |
+ __doc__ = _('Remove owners from a vault container.')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ takes_options = LDAPRemoveMember.takes_options + vault_options
|
|
|
590d18 |
+
|
|
|
590d18 |
+ member_attributes = ['owner']
|
|
|
590d18 |
+ member_param_label = _('owner %s')
|
|
|
590d18 |
+ member_count_out = ('%i owner removed.', '%i owners removed.')
|
|
|
590d18 |
+
|
|
|
590d18 |
+ has_output = (
|
|
|
590d18 |
+ output.Entry('result'),
|
|
|
590d18 |
+ output.Output(
|
|
|
590d18 |
+ 'failed',
|
|
|
590d18 |
+ type=dict,
|
|
|
590d18 |
+ doc=_('Owners that could not be removed'),
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ output.Output(
|
|
|
590d18 |
+ 'completed',
|
|
|
590d18 |
+ type=int,
|
|
|
590d18 |
+ doc=_('Number of owners removed'),
|
|
|
590d18 |
+ ),
|
|
|
590d18 |
+ )
|
|
|
590d18 |
+
|
|
|
590d18 |
+
|
|
|
590d18 |
@register()
|
|
|
590d18 |
class vault(LDAPObject):
|
|
|
590d18 |
__doc__ = _("""
|
|
|
590d18 |
@@ -1729,27 +1951,6 @@ class vault_retrieve_internal(PKQuery):
|
|
|
590d18 |
return response
|
|
|
590d18 |
|
|
|
590d18 |
|
|
|
590d18 |
-class VaultModMember(LDAPModMember):
|
|
|
590d18 |
- def get_options(self):
|
|
|
590d18 |
- for param in super(VaultModMember, self).get_options():
|
|
|
590d18 |
- if param.name == 'service' and param not in vault_options:
|
|
|
590d18 |
- param = param.clone_rename('services')
|
|
|
590d18 |
- yield param
|
|
|
590d18 |
-
|
|
|
590d18 |
- def get_member_dns(self, **options):
|
|
|
590d18 |
- if 'services' in options:
|
|
|
590d18 |
- options['service'] = options.pop('services')
|
|
|
590d18 |
- else:
|
|
|
590d18 |
- options.pop('service', None)
|
|
|
590d18 |
- return super(VaultModMember, self).get_member_dns(**options)
|
|
|
590d18 |
-
|
|
|
590d18 |
- def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
|
|
|
590d18 |
- for fail in failed.itervalues():
|
|
|
590d18 |
- fail['services'] = fail.pop('service', [])
|
|
|
590d18 |
- self.obj.get_container_attribute(entry_attrs, options)
|
|
|
590d18 |
- return completed, dn
|
|
|
590d18 |
-
|
|
|
590d18 |
-
|
|
|
590d18 |
@register()
|
|
|
590d18 |
class vault_add_owner(VaultModMember, LDAPAddMember):
|
|
|
590d18 |
__doc__ = _('Add owners to a vault.')
|
|
|
590d18 |
--
|
|
|
590d18 |
2.4.3
|
|
|
590d18 |
|