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.

--
Endi S. Dewata
From ccbfa01f40e2ac4c978e5ef0f1fbe167f96793a2 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edew...@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.

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
+
+
+@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
+
+
+@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
+
+
+@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
+
+
+@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
+
+
+@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
+
+
+@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
+
+
+@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
+
+
+@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

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to