On 08/25/2015 08:04 PM, Petr Vobornik wrote:
adds commands:
* vaultcontainer-show [--service <service>|--user <user> ]
* vaultcontainer-add-owner
      [--service <service>|--user <user> ]
      [--users <users>]  [--groups <groups>] [--services <services>]
* vaultcontainer-remove-owner
      [--service <service>|--user <user> ]
      [--users <users>]  [--groups <groups>] [--services <services>]

https://fedorahosted.org/freeipa/ticket/5250

Use cases:
1. When user/service is deleted, associated vault container looses
owner. There was no API command to set the owner.
2. Change owner of container by admin to manage access.

Show command was added to show current owners.

Find command was not added, should it be?



There is also a design for vault container ownership handling created by Endi - it's for future Vault 2.0.

http://www.freeipa.org/page/V4/Password_Vault_2.0#Adding_container_owner

This patch has a different API than the proposed - different way of specifying the container. The design page uses path e.g. /users/foobar. This patch uses the same way as vaults e.g. --user=foobar. This means that the implementation in this patch cannot manage ownership of parent vault containers e.g. cn=users,cn=vaults,cn=kra,$SUFFIX.

Do we want to go with this approach in 4.2?

Attaching also new path which removes setting of owner which doesn't exist so that integrity is OK and that it is consistent with removing of user.

Updated patch attached - output fix.
--
Petr Vobornik
From 7ef2a5580f06103d803e2ec2e85315a40d5e8666 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Wed, 26 Aug 2015 13:00:05 +0200
Subject: [PATCH] vault: set vaultcontainer owner only if exists

To be consistent with situation when owner(e.g. user) is deleted.

https://fedorahosted.org/freeipa/ticket/5250
---
 ipalib/plugins/vault.py | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py
index 0026ac11ed79c5aaf8de7d8ad13778284d00496b..da1a58cfb77932e8a907725eb88f9f5c6df023c9 100644
--- a/ipalib/plugins/vault.py
+++ b/ipalib/plugins/vault.py
@@ -422,6 +422,12 @@ class vault(LDAPObject):
 
         entries = []
 
+        # check that owner exists
+        try:
+            self.backend.get_entry(owner_dn, [])
+        except errors.NotFound:
+            owner_dn = None
+
         while dn:
             assert dn.endswith(container_dn)
 
@@ -431,9 +437,11 @@ class vault(LDAPObject):
                 {
                     'objectclass': ['ipaVaultContainer'],
                     'cn': rdn['cn'],
-                    'owner': [owner_dn],
                 })
 
+            if owner_dn:
+                entry['owner'] = [owner_dn]
+
             # if entry can be added, return
             try:
                 self.backend.add_entry(entry)
-- 
2.4.3

From 846851d30caaf3da56b5f97f7023f147c34515da Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Tue, 25 Aug 2015 19:56:00 +0200
Subject: [PATCH] vault: add vault container commands

adds commands:
* vaultcontainer-show [--service <service>|--user <user> ]
* vaultcontainer-add-owner
     [--service <service>|--user <user> ]
     [--users <users>]  [--groups <groups>] [--services <services>]
* vaultcontainer-remove-owner
     [--service <service>|--user <user> ]
     [--users <users>]  [--groups <groups>] [--services <services>]

https://fedorahosted.org/freeipa/ticket/5250
---
 API.txt                 |  40 +++++++++++
 VERSION                 |   4 +-
 ipalib/plugins/vault.py | 180 ++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 216 insertions(+), 8 deletions(-)

diff --git a/API.txt b/API.txt
index afd5017bee2bc1eed54497ccd504b92619ff7a58..c45d332528b0cf5aa6b125b9c58cd3b3b8c970dc 100644
--- a/API.txt
+++ b/API.txt
@@ -5668,6 +5668,46 @@ 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: vaultcontainer_add_owner
+args: 0,9,3
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('group*', alwaysask=True, cli_name='groups', csv=True)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('service?')
+option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False)
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+option: Str('username?', cli_name='user')
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: vaultcontainer_remove_owner
+args: 0,9,3
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('group*', alwaysask=True, cli_name='groups', csv=True)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('service?')
+option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False)
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+option: Str('username?', cli_name='user')
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: vaultcontainer_show
+args: 0,7,3
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('no_members', autofill=True, 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: Str('username?', cli_name='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
diff --git a/VERSION b/VERSION
index d3073e52ee022cc08b74953222a5040929ded60f..58ab1a8e582e1c4213dd45217b052ef896f03166 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=154
-# Last change: pvoborni - change default vault type to 'symmetric'
+IPA_API_VERSION_MINOR=155
+# Last change: pvoborni - add vault container commands
diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py
index d06b63d68a27ee0522f636504188852570033a42..0026ac11ed79c5aaf8de7d8ad13778284d00496b 100644
--- a/ipalib/plugins/vault.py
+++ b/ipalib/plugins/vault.py
@@ -236,17 +236,12 @@ def validated_read(argname, filename, mode='r', encoding=None):
 
 register = Registry()
 
-
-vault_options = (
+vaultcontainer_options = (
     Str(
         'service?',
         doc=_('Service name of the service vault'),
         normalizer=normalize_principal,
     ),
-    Flag(
-        'shared?',
-        doc=_('Shared vault'),
-    ),
     Str(
         'username?',
         cli_name='user',
@@ -254,6 +249,13 @@ vault_options = (
     ),
 )
 
+vault_options = vaultcontainer_options + (
+    Flag(
+        'shared?',
+        doc=_('Shared vault'),
+    ),
+)
+
 
 @register()
 class vault(LDAPObject):
@@ -1795,6 +1797,172 @@ class vault_remove_member(VaultModMember, LDAPRemoveMember):
 
 
 @register()
+class vaultcontainer(LDAPObject):
+    __doc__ = _("""
+    Vault Container object.
+    """)
+
+    container_dn = api.env.container_vault
+
+    object_name = _('vaultcontainer')
+    object_name_plural = _('vaultcontainers')
+    object_class = ['ipaVaultContainer']
+
+    attribute_members = {
+        'owner': ['user', 'group', 'service'],
+    }
+
+    label = _('Vault Containers')
+    label_singular = _('Vault Container')
+
+    takes_params = (
+        Str(
+            'owner_user?',
+            label=_('Owner users'),
+        ),
+        Str(
+            'owner_group?',
+            label=_('Owner groups'),
+        ),
+        Str(
+            'owner_service?',
+            label=_('Owner services'),
+        ),
+        Str(
+            'owner?',
+            label=_('Failed owners'),
+        ),
+        Str(
+            'service?',
+            label=_('Vault service'),
+            flags={'virtual_attribute'},
+        ),
+        Str(
+            'username?',
+            label=_('Vault user'),
+            flags={'virtual_attribute'},
+        ),
+    )
+
+    def get_dn(self, *keys, **options):
+        """
+        Generates vault DN from parameters.
+        """
+        service = options.get('service')
+        user = options.get('username')
+
+        if service and user:
+            raise errors.MutuallyExclusiveError(
+                reason=_('Service, and user options ' +
+                         'cannot be specified simultaneously'))
+
+        parent_dn = super(vaultcontainer, self).get_dn(*keys, **options)
+
+        if not service and not user:
+            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:
+            dn = DN(('cn', service), ('cn', 'services'), parent_dn)
+        elif user:
+            dn = DN(('cn', user), ('cn', 'users'), parent_dn)
+        else:
+            raise RuntimeError
+
+        return dn
+
+    def get_container_attribute(self, entry, options):
+        if options.get('raw', False):
+            return
+        container_dn = DN(self.container_dn, self.api.env.basedn)
+        if entry.dn.endswith(DN(('cn', 'services'), container_dn)):
+            entry['service'] = entry.dn[0]['cn']
+        elif entry.dn.endswith(DN(('cn', 'users'), container_dn)):
+            entry['username'] = entry.dn[0]['cn']
+
+
+@register()
+class vaultcontainer_show(LDAPRetrieve):
+    __doc__ = _('Display information about a vault.')
+
+    takes_options = LDAPRetrieve.takes_options + vaultcontainer_options
+
+    has_output_params = LDAPRetrieve.has_output_params
+
+    def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
+        assert isinstance(dn, DN)
+
+        if not self.api.Command.kra_is_enabled()['result']:
+            raise errors.InvocationError(
+                format=_('KRA service is not enabled'))
+
+        return dn
+
+    def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+        self.obj.get_container_attribute(entry_attrs, options)
+        return dn
+
+
+@register()
+class vaultcontainer_add_owner(VaultModMember, LDAPAddMember):
+    __doc__ = _('Add owners to a vault container.')
+
+    takes_options = LDAPAddMember.takes_options + vaultcontainer_options
+
+    member_attributes = ['owner']
+    member_param_label = _('owner %s')
+    member_count_out = ('%i owner added.', '%i owners added.')
+
+    has_output = (
+        output.Entry('result'),
+        output.Output(
+            'failed',
+            type=dict,
+            doc=_('Owners that could not be added'),
+        ),
+        output.Output(
+            'completed',
+            type=int,
+            doc=_('Number of owners added'),
+        ),
+    )
+
+
+@register()
+class vaultcontainer_remove_owner(VaultModMember, LDAPRemoveMember):
+    __doc__ = _('Remove owners from a vault container.')
+
+    takes_options = LDAPRemoveMember.takes_options + vaultcontainer_options
+
+    member_attributes = ['owner']
+    member_param_label = _('owner %s')
+    member_count_out = ('%i owner removed.', '%i owners removed.')
+
+    has_output = (
+        output.Entry('result'),
+        output.Output(
+            'failed',
+            type=dict,
+            doc=_('Owners that could not be removed'),
+        ),
+        output.Output(
+            'completed',
+            type=int,
+            doc=_('Number of owners removed'),
+        ),
+    )
+
+
+@register()
 class kra_is_enabled(Command):
     NO_CLI = True
 
-- 
2.4.3

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to