On 10.8.2015 21:12, Endi Sukma Dewata wrote:
On 8/4/2015 10:32 AM, Endi Sukma Dewata wrote:
Martin, I do not think going on with business as usual is the right
thing to do here. We know this is going to bite.
I suggest Endy adds a *new* API if making it backwards compatible is
not
possible. The era of bumping whole API version must stop, the sooner
the
better.


My point is that we do not know yet how to do this kind of changes
long term.
So what I did not want to end up are 2 copy&pasted Vault plugins
maintained
forever, differing in just that.

If you know how to do this without copypasting, I will be fine with
that.

We probably can do it like this:
* the old plugin continues to provide Vault 1.0 functionality
* the new plugin will be a proxy to the old plugin except for the parts
that have changed in Vault 1.1.

Or the other way around:
* the new plugin will provide Vault 1.1 functionality
* the old plugin will be a proxy to the new plugin except for the parts
that needs to be maintained for Vault 1.0.

The first option is probably safer.

In any case, IPA 4.2.1 will only provide a single client for Vault 1.1,
but two services for Vault 1.0 and 1.1.

A new patch #369-1 is attached. It has been rebased on top of #372 and
#373 that fix the conflicting parameter while maintaining backward
compatibility.

I have modified the first version of the patch to maintain backward compatibility and not require your patches #372 and #373. Should be much easier to review. See attachment.

--
Jan Cholasta
From 81ff19e8b3a5a8bdbb412155f4e3155e192befd3 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edew...@redhat.com>
Date: Tue, 11 Aug 2015 08:19:59 +0200
Subject: [PATCH] Added CLI param and ACL for vault service operations.

The CLIs to manage vault owners and members have been modified
to accept services with a new parameter. Due to name conflict,
the existing 'service' parameter has been renamed to
'servicename'.

A new ACL has been added to allow a service to create its own
service container.

https://fedorahosted.org/freeipa/ticket/5172
---
 API.txt                    | 12 +++++---
 VERSION                    |  4 +--
 install/share/vault.update |  1 +
 ipalib/plugins/vault.py    | 76 +++++++++++++++++++++++++++++++++++-----------
 4 files changed, 70 insertions(+), 23 deletions(-)

diff --git a/API.txt b/API.txt
index 04f2f89..9dbf86a 100644
--- a/API.txt
+++ b/API.txt
@@ -5434,13 +5434,14 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: PrimaryKey('value', None, None)
 command: vault_add_member
-args: 1,9,3
+args: 1,10,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: 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: Flag('shared?', autofill=True, default=False)
 option: Str('user*', alwaysask=True, cli_name='users', csv=True)
 option: Str('username?', cli_name='user')
@@ -5449,13 +5450,14 @@ 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: vault_add_owner
-args: 1,9,3
+args: 1,10,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: 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: Flag('shared?', autofill=True, default=False)
 option: Str('user*', alwaysask=True, cli_name='users', csv=True)
 option: Str('username?', cli_name='user')
@@ -5547,13 +5549,14 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: PrimaryKey('value', None, None)
 command: vault_remove_member
-args: 1,9,3
+args: 1,10,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: 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: Flag('shared?', autofill=True, default=False)
 option: Str('user*', alwaysask=True, cli_name='users', csv=True)
 option: Str('username?', cli_name='user')
@@ -5562,13 +5565,14 @@ 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: vault_remove_owner
-args: 1,9,3
+args: 1,10,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: 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: Flag('shared?', autofill=True, default=False)
 option: Str('user*', alwaysask=True, cli_name='users', csv=True)
 option: Str('username?', cli_name='user')
diff --git a/VERSION b/VERSION
index a3d586d..c42bea0 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=148
-# Last change: ftweedal - add --out option to user-show
+IPA_API_VERSION_MINOR=149
+# Last change: edewata - Added CLI param and ACL for vault service operations
diff --git a/install/share/vault.update b/install/share/vault.update
index 61a8940..14421b5 100644
--- a/install/share/vault.update
+++ b/install/share/vault.update
@@ -8,6 +8,7 @@ default: objectClass: top
 default: objectClass: ipaVaultContainer
 default: cn: vaults
 default: aci: (target="ldap:///cn=*,cn=users,cn=vaults,cn=kra,$SUFFIX";)(version 3.0; acl "Allow users to create private container"; allow (add) userdn = "ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX";)
+default: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX";)(version 3.0; acl "Allow services to create private container"; allow (add) userdn = "ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX";)
 default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Container owners can manage vaults in the container"; allow(read, search, compare, add, delete) userattr="parent[1].owner#USERDN";)
 default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect container owners can manage vaults in the container"; allow(read, search, compare, add, delete) userattr="parent[1].owner#GROUPDN";)
 default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Vault members can access the vault"; allow(read, search, compare) userattr="member#USERDN";)
diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py
index 423df6b..98f0654 100644
--- a/ipalib/plugins/vault.py
+++ b/ipalib/plugins/vault.py
@@ -44,7 +44,7 @@ from ipalib.crud import PKQuery, Retrieve, Update
 from ipalib.plugable import Registry
 from ipalib.plugins.baseldap import LDAPObject, LDAPCreate, LDAPDelete,\
     LDAPSearch, LDAPUpdate, LDAPRetrieve, LDAPAddMember, LDAPRemoveMember,\
-    pkey_to_value
+    LDAPModMember, pkey_to_value
 from ipalib.request import context
 from ipalib.plugins.user import split_principal
 from ipalib import _, ngettext
@@ -199,16 +199,20 @@ EXAMPLES:
    ipa vault-retrieve <name> --out data.bin --private-key-file private.pem
 """) + _("""
  Add a vault owner:
-   ipa vault-add-owner <name> --users <usernames>
+   ipa vault-add-owner <name> [--users <usernames>] \
+       [--groups <goupnames>] [--services <service names>]
 """) + _("""
  Delete a vault owner:
-   ipa vault-remove-owner <name> --users <usernames>
+   ipa vault-remove-owner <name> [--users <usernames>] \
+       [--groups <goupnames>] [--services <service names>]
 """) + _("""
  Add a vault member:
-   ipa vault-add-member <name> --users <usernames>
+   ipa vault-add-member <name> [--users <usernames>] \
+       [--groups <goupnames>] [--services <service names>]
 """) + _("""
  Delete a vault member:
-   ipa vault-remove-member <name> --users <usernames>
+   ipa vault-remove-member <name> [--users <usernames>] \
+       [--groups <goupnames>] [--services <service names>]
 """)
 
 
@@ -285,8 +289,8 @@ class vault(LDAPObject):
         'ipavaulttype',
     ]
     attribute_members = {
-        'owner': ['user', 'group'],
-        'member': ['user', 'group'],
+        'owner': ['user', 'group', 'service'],
+        'member': ['user', 'group', 'service'],
     }
 
     label = _('Vaults')
@@ -340,6 +344,11 @@ class vault(LDAPObject):
             label=_('Owner groups'),
             flags=['no_create', 'no_update', 'no_search'],
         ),
+        Str(
+            'owner_service?',
+            label=_('Owner services'),
+            flags=['no_create', 'no_update', 'no_search'],
+        ),
     )
 
     def get_dn(self, *keys, **options):
@@ -693,6 +702,29 @@ class vault_add_internal(LDAPCreate):
             raise errors.InvocationError(
                 format=_('KRA service is not enabled'))
 
+        parent_dn = DN(*dn[1:])
+
+        container_dn = DN(self.api.Object.vault.container_dn,
+                          self.api.env.basedn)
+
+        services_dn = DN(('cn', 'services'), container_dn)
+        users_dn = DN(('cn', 'users'), container_dn)
+
+        if dn.endswith(services_dn):
+            # service container should be owned by the service
+            service = parent_dn[0]['cn']
+            parent_owner_dn = self.api.Object.service.get_dn(service)
+
+        elif dn.endswith(users_dn):
+            # user container should be owned by the user
+            user = parent_dn[0]['cn']
+            parent_owner_dn = self.api.Object.user.get_dn(user)
+
+        try:
+            self.obj.create_container(parent_dn, parent_owner_dn)
+        except errors.DuplicateEntry, e:
+            pass
+
         principal = getattr(context, 'principal')
         (name, realm) = split_principal(principal)
         if '/' in name:
@@ -700,12 +732,7 @@ class vault_add_internal(LDAPCreate):
         else:
             owner_dn = self.api.Object.user.get_dn(name)
 
-        try:
-            parent_dn = DN(*dn[1:])
-            self.obj.create_container(parent_dn, owner_dn)
-        except errors.DuplicateEntry, e:
-            pass
-
+        # vault should be owned by the creator
         entry_attrs['owner'] = owner_dn
 
         return dn
@@ -1407,8 +1434,23 @@ class vault_retrieve_internal(PKQuery):
         return response
 
 
+class VaultModMember(LDAPModMember):
+    def get_options(self):
+        for param in super(VaultModMember, self).get_options():
+            if param.name == 'service' and param not in vault_options:
+                param = param.clone_rename('services')
+            yield param
+
+    def get_member_dns(self, **options):
+        if 'services' in options:
+            options['service'] = options.pop('services')
+        else:
+            options.pop('service', None)
+        return super(VaultModMember, self).get_member_dns(**options)
+
+
 @register()
-class vault_add_owner(LDAPAddMember):
+class vault_add_owner(VaultModMember, LDAPAddMember):
     __doc__ = _('Add owners to a vault.')
 
     takes_options = LDAPAddMember.takes_options + vault_options
@@ -1432,7 +1474,7 @@ class vault_add_owner(LDAPAddMember):
 
 
 @register()
-class vault_remove_owner(LDAPRemoveMember):
+class vault_remove_owner(VaultModMember, LDAPRemoveMember):
     __doc__ = _('Remove owners from a vault.')
 
     takes_options = LDAPRemoveMember.takes_options + vault_options
@@ -1456,14 +1498,14 @@ class vault_remove_owner(LDAPRemoveMember):
 
 
 @register()
-class vault_add_member(LDAPAddMember):
+class vault_add_member(VaultModMember, LDAPAddMember):
     __doc__ = _('Add members to a vault.')
 
     takes_options = LDAPAddMember.takes_options + vault_options
 
 
 @register()
-class vault_remove_member(LDAPRemoveMember):
+class vault_remove_member(VaultModMember, LDAPRemoveMember):
     __doc__ = _('Remove members from a vault.')
 
     takes_options = LDAPRemoveMember.takes_options + vault_options
-- 
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