[Freeipa-devel] [PATCH] 355 Added vault access control.

Endi Sukma Dewata edewata at redhat.com
Tue Oct 28 22:35:30 UTC 2014


On 10/22/2014 3:04 PM, Endi Sukma Dewata wrote:
> New LDAP ACIs have been added to allow users to create their own
> private vault container, to allow owners to manage vaults and
> containers, and to allow members to use the vaults. New CLIs have
> been added to manage the owner and member list. For archive and
> retrieve operations the access control has to be enforced by the
> plugins because the operations only affects KRA. The LDAP schema
> has been updated as well.
>
> Ticket #3872
>
> This patch depends on #353-2.

New patch attached to fix the ticket URL. It depends on #353-3.

-- 
Endi S. Dewata
-------------- next part --------------
>From 6f464581e4e30e6105522ff25047764ec97e5a53 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata at redhat.com>
Date: Fri, 17 Oct 2014 12:05:34 -0400
Subject: [PATCH] Added vault access control.

New LDAP ACIs have been added to allow users to create their own
private vault container, to allow owners to manage vaults and
containers, and to allow members to use the vaults. New CLIs have
been added to manage the owner and member list. For archive and
retrieve operations the access control has to be enforced by the
plugins because the operations only affects KRA. The LDAP schema
has been updated as well.

https://fedorahosted.org/freeipa/ticket/3872
---
 API.txt                         | 134 +++++++++++++++++++++--
 VERSION                         |   4 +-
 install/share/60basev4.ldif     |   4 +-
 install/updates/40-vault.update |   7 ++
 ipalib/plugins/vault.py         | 233 +++++++++++++++++++++++++++++++++++++++-
 5 files changed, 366 insertions(+), 16 deletions(-)

diff --git a/API.txt b/API.txt
index cfa6558fcf678e5915a90407da517f9a591a41bf..a46592ec9e82e618154bf09393c83d4b854315c5 100644
--- a/API.txt
+++ b/API.txt
@@ -4476,11 +4476,12 @@ output: Output('result', <type 'bool'>, None)
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: PrimaryKey('value', None, None)
 command: vault_add
-args: 1,8,3
+args: 1,9,3
 arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, required=True)
 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: Str('in?', cli_name='in')
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
 option: Str('parent', attribute=False, cli_name='parent', multivalue=False, required=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Flag('rights', autofill=True, default=False)
@@ -4489,12 +4490,39 @@ 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_add_member
+args: 1,7,3
+arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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: Str('parent?', cli_name='parent')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+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: vault_add_owner
+args: 1,7,3
+arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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: Str('parent?', cli_name='parent')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+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: vault_archive
-args: 1,10,3
+args: 1,11,3
 arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True)
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Bytes('encrypted_data?', cli_name='encrypted_data')
 option: Str('in?', cli_name='in')
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
 option: Bytes('nonce?', cli_name='nonce')
 option: Str('parent?', cli_name='parent')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
@@ -4515,11 +4543,12 @@ output: Output('result', <type 'dict'>, None)
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: ListOfPrimaryKeys('value', None, None)
 command: vault_find
-args: 1,10,4
+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='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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('no_members', autofill=True, default=False, exclude='webui')
 option: Str('parent', attribute=False, autofill=False, cli_name='parent', 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')
@@ -4532,12 +4561,13 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('truncated', <type 'bool'>, None)
 command: vault_mod
-args: 1,10,3
+args: 1,11,3
 arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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('no_members', autofill=True, default=False, exclude='webui')
 option: Str('parent', attribute=False, autofill=False, cli_name='parent', multivalue=False, required=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Flag('rights', autofill=True, default=False)
@@ -4547,10 +4577,37 @@ 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_remove_member
+args: 1,7,3
+arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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: Str('parent?', cli_name='parent')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+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: vault_remove_owner
+args: 1,7,3
+arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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: Str('parent?', cli_name='parent')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+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: vault_retrieve
-args: 1,7,3
+args: 1,8,3
 arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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('no_members', autofill=True, default=False, exclude='webui')
 option: Str('out?', cli_name='out')
 option: Str('parent?', cli_name='parent')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
@@ -4561,9 +4618,10 @@ 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_show
-args: 1,5,3
+args: 1,6,3
 arg: Str('cn', attribute=True, cli_name='vault_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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('no_members', autofill=True, default=False, exclude='webui')
 option: Str('parent?', cli_name='parent')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Flag('rights', autofill=True, default=False)
@@ -4572,11 +4630,12 @@ 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: vaultcontainer_add
-args: 1,7,3
+args: 1,8,3
 arg: Str('cn', attribute=True, cli_name='container_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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('no_members', autofill=True, default=False, exclude='webui')
 option: Str('parent', attribute=False, cli_name='parent', multivalue=False, required=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Str('setattr*', cli_name='setattr', exclude='webui')
@@ -4584,6 +4643,32 @@ 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_member
+args: 1,7,3
+arg: Str('cn', attribute=True, cli_name='container_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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: Str('parent?', cli_name='parent')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+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_add_owner
+args: 1,7,3
+arg: Str('cn', attribute=True, cli_name='container_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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: Str('parent?', cli_name='parent')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+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_del
 args: 1,3,3
 arg: Str('cn', attribute=True, cli_name='container_name', maxlength=255, multivalue=True, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True)
@@ -4594,11 +4679,12 @@ output: Output('result', <type 'dict'>, None)
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: ListOfPrimaryKeys('value', None, None)
 command: vaultcontainer_find
-args: 1,9,4
+args: 1,10,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='container_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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('no_members', autofill=True, default=False, exclude='webui')
 option: Str('parent', attribute=False, autofill=False, cli_name='parent', 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')
@@ -4610,12 +4696,13 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('truncated', <type 'bool'>, None)
 command: vaultcontainer_mod
-args: 1,9,3
+args: 1,10,3
 arg: Str('cn', attribute=True, cli_name='container_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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('no_members', autofill=True, default=False, exclude='webui')
 option: Str('parent', attribute=False, autofill=False, cli_name='parent', multivalue=False, required=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Flag('rights', autofill=True, default=False)
@@ -4624,11 +4711,38 @@ 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_remove_member
+args: 1,7,3
+arg: Str('cn', attribute=True, cli_name='container_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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: Str('parent?', cli_name='parent')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+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: 1,7,3
+arg: Str('cn', attribute=True, cli_name='container_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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: Str('parent?', cli_name='parent')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+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: 1,5,3
+args: 1,6,3
 arg: Str('cn', attribute=True, cli_name='container_name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[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('continue', autofill=True, cli_name='continue', default=False)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
 option: Str('parent?', cli_name='parent')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Str('version?', exclude='webui')
diff --git a/VERSION b/VERSION
index fe23eae5f349f4a2d40c3d3e55f6168a82b961b2..c471ed80af6a2c26be7fc89281ae60fac6c68577 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=109
-# Last change: edewata - initial vault implementation
+IPA_API_VERSION_MINOR=110
+# Last change: edewata - added vault access control
diff --git a/install/share/60basev4.ldif b/install/share/60basev4.ldif
index 97553d53938093c1b0ecba0826fc469d0d758c62..61590562ffa174134e10567be93c18ab437d8008 100644
--- a/install/share/60basev4.ldif
+++ b/install/share/60basev4.ldif
@@ -1,3 +1,3 @@
 dn: cn=schema
-objectClasses: (2.16.840.1.113730.3.8.18.1.1 NAME 'ipaVault' SUP nsContainer STRUCTURAL MAY ( description ) X-ORIGIN 'IPA v4.1' )
-objectClasses: (2.16.840.1.113730.3.8.18.1.2 NAME 'ipaVaultContainer' SUP nsContainer STRUCTURAL MAY ( description ) X-ORIGIN 'IPA v4.1' )
+objectClasses: (2.16.840.1.113730.3.8.18.1.1 NAME 'ipaVault' SUP nsContainer STRUCTURAL MAY ( description $ owner $ member ) X-ORIGIN 'IPA v4.1' )
+objectClasses: (2.16.840.1.113730.3.8.18.1.2 NAME 'ipaVaultContainer' SUP nsContainer STRUCTURAL MAY ( description $ owner $ member ) X-ORIGIN 'IPA v4.1' )
diff --git a/install/updates/40-vault.update b/install/updates/40-vault.update
index 59e5b629ce4e6c5acac06df78f02106afa6c859e..455d4719f612198890f8a914d3a13794a3b9ad75 100644
--- a/install/updates/40-vault.update
+++ b/install/updates/40-vault.update
@@ -4,6 +4,13 @@ default: objectClass: nsContainer
 default: objectClass: ipaVaultContainer
 default: cn: vaults
 default: description: Root vault container
+default: aci: (target="ldap:///cn=*,cn=users,cn=vaults,$SUFFIX")(targetattr="*")(version 3.0; acl "Allow add macro dn"; allow (add) userdn = "ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX";)
+default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="*")(version 3.0; acl "Container members can access the container"; allow(read, search, compare) userattr="member#USERDN";)
+default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="*")(version 3.0; acl "Container owners can modify the container"; allow(read, search, compare, write) userattr="owner#USERDN";)
+default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="*")(version 3.0; acl "Container owners can manage sub-containers"; allow(read, search, compare, add, delete) userattr="parent[1].owner#USERDN";)
+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 "Vault members can access the vault"; allow(read, search, compare) userattr="member#USERDN";)
+default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Vault owners can modify the vault"; allow(read, search, compare, write) userattr="owner#USERDN";)
 
 dn: cn=services,cn=vaults,$SUFFIX
 default: objectClass: top
diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py
index c0e66621d1cf326b0bfb88565951d66cda3b9500..95f96859235af1c477c8f5738a27571d64aabe3a 100644
--- a/ipalib/plugins/vault.py
+++ b/ipalib/plugins/vault.py
@@ -68,6 +68,18 @@ EXAMPLES:
  Delete a vault:
    ipa vault-del MyVault
 
+ Add a vault owner:
+   ipa vault-add-owner MyVault --users testuser
+
+ Delete a vault owner:
+   ipa vault-remove-owner MyVault --users testuser
+
+ Add a vault member:
+   ipa vault-add-member MyVault --users testuser
+
+ Delete a vault member:
+   ipa vault-remove-member MyVault --users testuser
+
  List private vault containers:
    ipa vaultcontainer-find
 
@@ -82,6 +94,18 @@ EXAMPLES:
 
  Delete a vault container:
    ipa vaultcontainer-del MyContainer
+
+ Add a vault container owner:
+   ipa vaultcontainer-add-owner MyContainer --users testuser
+
+ Delete a vault container owner:
+   ipa vaultcontainer-remove-owner MyContainer --users testuser
+
+ Add a vault container member:
+   ipa vaultcontainer-add-member MyContainer --users testuser
+
+ Delete a vault container member:
+   ipa vaultcontainer-remove-member MyContainer --users testuser
 """)
 
 register = Registry()
@@ -98,11 +122,15 @@ class vaultcontainer(LDAPObject):
 
     object_class = ['ipaVaultContainer']
     default_attributes = [
-        'cn', 'description',
+        'cn', 'description', 'owner', 'member',
     ]
     search_display_attributes = [
         'cn', 'description',
     ]
+    attribute_members = {
+        'owner': ['user', 'group'],
+        'member': ['user', 'group'],
+    }
 
     label = _('Vault Containers')
     label_singular = _('Vault Container')
@@ -206,6 +234,11 @@ class vaultcontainer_add(LDAPCreate):
         name = entry_attrs.get('cn')
         parent_id = self.obj.normalize_id(options.get('parent'))
 
+        principal = getattr(context, 'principal')
+        (username, realm) = split_principal(principal)
+        owner_dn = self.api.Object['user'].get_dn(username)
+        entry_attrs['owner'] = owner_dn
+
         # add parent container if it doesn't exist
         try:
             (grandparent_id, parent_name) = self.obj.split_id(parent_id)
@@ -293,6 +326,93 @@ class vaultcontainer_show(LDAPRetrieve):
 
 
 @register()
+class vaultcontainer_add_owner(LDAPAddMember):
+    __doc__ = _('Add owners to a vault container.')
+
+    takes_options = LDAPAddMember.takes_options + (
+        Str('parent?',
+            cli_name='parent',
+            doc=_('Parent container'),
+        ),
+    )
+
+    member_attributes = ['owner']
+    member_count_out = ('%i owner added.', '%i owners added.')
+
+    def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+
+        name = keys[0]
+        parent_id = self.obj.normalize_id(options.get('parent'))
+        id = parent_id + name
+        dn = self.obj.get_dn(id)
+        return dn
+
+
+ at register()
+class vaultcontainer_remove_owner(LDAPRemoveMember):
+    __doc__ = _('Remove owners from a vault container.')
+
+    takes_options = LDAPRemoveMember.takes_options + (
+        Str('parent?',
+            cli_name='parent',
+            doc=_('Parent container'),
+        ),
+    )
+
+    member_attributes = ['owner']
+    member_count_out = ('%i owner removed.', '%i owners removed.')
+
+    def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+
+        name = keys[0]
+        parent_id = self.obj.normalize_id(options.get('parent'))
+        id = parent_id + name
+        dn = self.obj.get_dn(id)
+        return dn
+
+
+ at register()
+class vaultcontainer_add_member(LDAPAddMember):
+    __doc__ = _('Add members to a vault container.')
+
+    takes_options = LDAPAddMember.takes_options + (
+        Str('parent?',
+            cli_name='parent',
+            doc=_('Parent container'),
+        ),
+    )
+
+    def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+
+        name = keys[0]
+        parent_id = self.obj.normalize_id(options.get('parent'))
+        id = parent_id + name
+        dn = self.obj.get_dn(id)
+        return dn
+
+
+ at register()
+class vaultcontainer_remove_member(LDAPRemoveMember):
+    __doc__ = _('Remove members from a vault container.')
+
+
+    takes_options = LDAPRemoveMember.takes_options + (
+        Str('parent?',
+            cli_name='parent',
+            doc=_('Parent container'),
+        ),
+    )
+
+    def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+
+        name = keys[0]
+        parent_id = self.obj.normalize_id(options.get('parent'))
+        id = parent_id + name
+        dn = self.obj.get_dn(id)
+        return dn
+
+
+ at register()
 class vault(LDAPObject):
     """
     Vault object.
@@ -303,11 +423,15 @@ class vault(LDAPObject):
 
     object_class = ['ipaVault']
     default_attributes = [
-        'cn', 'description',
+        'cn', 'description', 'owner', 'member',
     ]
     search_display_attributes = [
         'cn', 'description',
     ]
+    attribute_members = {
+        'owner': ['user', 'group'],
+        'member': ['user', 'group'],
+    }
 
     label = _('Vaults')
     label_singular = _('Vault')
@@ -371,6 +495,11 @@ class vault_add(LDAPCreate):
         parent_id = api.Object.vaultcontainer.normalize_id(options.get('parent'))
         dn = self.obj.get_dn(name, parent=parent_id)
 
+        principal = getattr(context, 'principal')
+        (username, realm) = split_principal(principal)
+        owner_dn = self.api.Object['user'].get_dn(username)
+        entry_attrs['owner'] = owner_dn
+
         # add parent container if it doesn't exist
         try:
             (grandparent_id, parent_name) = api.Object.vaultcontainer.split_id(parent_id)
@@ -541,6 +670,15 @@ class vault_archive(LDAPRetrieve):
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
 
         vault_id = entry_attrs.get('cn')[0]
+        owners = entry_attrs.get('owner', [])
+        members = entry_attrs.get('member', [])
+
+        principal = getattr(context, 'principal')
+        (username, realm) = split_principal(principal)
+        user_dn = self.api.Object['user'].get_dn(username)
+
+        if user_dn not in owners and user_dn not in members:
+            raise errors.ACIError(info=_("Insufficient access to vault '%s'.") % vault_id)
 
         kra_client = api.Backend.kra.get_client()
 
@@ -656,6 +794,15 @@ class vault_retrieve(LDAPRetrieve):
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
 
         vault_id = entry_attrs.get('cn')[0]
+        owners = entry_attrs.get('owner', [])
+        members = entry_attrs.get('member', [])
+
+        principal = getattr(context, 'principal')
+        (username, realm) = split_principal(principal)
+        user_dn = self.api.Object['user'].get_dn(username)
+
+        if user_dn not in owners and user_dn not in members:
+            raise errors.ACIError(info=_("Insufficient access to vault '%s'.") % vault_id)
 
         wrapped_session_key = base64.b64decode(options['wrapped_session_key'])
 
@@ -722,3 +869,85 @@ class vault_retrieve(LDAPRetrieve):
             response['result']['secret'] = unicode(secret)
 
         return response
+
+
+ at register()
+class vault_add_owner(LDAPAddMember):
+    __doc__ = _('Add owners to a vault.')
+
+    takes_options = LDAPAddMember.takes_options + (
+        Str('parent?',
+            cli_name='parent',
+            doc=_('Parent container'),
+        ),
+    )
+
+    member_attributes = ['owner']
+    member_count_out = ('%i owner added.', '%i owners added.')
+
+    def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+
+        name = keys[0]
+        parent_id = api.Object.vaultcontainer.normalize_id(options.get('parent'))
+        dn = self.obj.get_dn(name, parent=parent_id)
+        return dn
+
+
+ at register()
+class vault_remove_owner(LDAPRemoveMember):
+    __doc__ = _('Remove owners from a vault.')
+
+    takes_options = LDAPRemoveMember.takes_options + (
+        Str('parent?',
+            cli_name='parent',
+            doc=_('Parent container'),
+        ),
+    )
+
+    member_attributes = ['owner']
+    member_count_out = ('%i owner removed.', '%i owners removed.')
+
+    def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+
+        name = keys[0]
+        parent_id = api.Object.vaultcontainer.normalize_id(options.get('parent'))
+        dn = self.obj.get_dn(name, parent=parent_id)
+        return dn
+
+
+ at register()
+class vault_add_member(LDAPAddMember):
+    __doc__ = _('Add members to a vault.')
+
+    takes_options = LDAPAddMember.takes_options + (
+        Str('parent?',
+            cli_name='parent',
+            doc=_('Parent container'),
+        ),
+    )
+
+    def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+
+        name = keys[0]
+        parent_id = api.Object.vaultcontainer.normalize_id(options.get('parent'))
+        dn = self.obj.get_dn(name, parent=parent_id)
+        return dn
+
+
+ at register()
+class vault_remove_member(LDAPRemoveMember):
+    __doc__ = _('Remove members from a vault.')
+
+    takes_options = LDAPRemoveMember.takes_options + (
+        Str('parent?',
+            cli_name='parent',
+            doc=_('Parent container'),
+        ),
+    )
+
+    def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+
+        name = keys[0]
+        parent_id = api.Object.vaultcontainer.normalize_id(options.get('parent'))
+        dn = self.obj.get_dn(name, parent=parent_id)
+        return dn
-- 
1.9.0



More information about the Freeipa-devel mailing list