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