Please take a look at the new patch.

On 6/17/2015 1:32 AM, Jan Cholasta wrote:
I think it would be better to use a new attribute type which inherits
from ipaPublicKey (ipaVaultPublicKey?) rather than ipaPublicKey directly
for assymetric vault public keys, so that assymetric public key and
escrow public key are on the same level and you can still use
ipaPublicKey to refer to either one:

     ipaPublicKey
         ipaVaultPublicKey
         ipaEscrowPublicKey

OK. To be consistent the parameters need to be renamed too:
--vault-public-key and --vault-public-key-file.

It doesn't need to, there is no requirement for CLI names to always
match attribute names. (Also I don't insist on the name
"ipaVaultPublicKey", feel free to change it if you want.)

It's unchanged for now. In a previous discussion it was advised to reuse the existing attribute type whenever possible.

1. The vault_add was split into a client-side vault_add and
server-side
vault_add_internal since the parameters are different (i.e. public
key file and
future escrow-related params). Since vault_add inherits from Local all
non-primary-key attributes have to be added explicitly.

The split is not really necessary, since the only difference is the
public_key_file option, which exists only because of the lack of proper
file support in the framework. This is a different situation from
vault_{archive,retrieve}, which has two different sets of options on
client and server side. Escrow adds only ipaescrowpublickey and
escrow_public_key_file, right? If yes, we can safely keep the command in
a single piece.

We know the vault-add will have at least two client-only parameters:
vault_public_key_file and escrow_public_key_file. Keeping these
parameters on the server API would be wrong and confusing. If the API is
called on the server side with vault_public_key_file the operation will
fail. In the previous discussion you considered this as broken API:

Server API is used not only by the server itself, but also by installers
for example. Anyway the point is that there *can't* be a broken API like
this, you should at least raise an error if the command is called from
server API, although actually separating it into client and server parts
would be preferable.

You are comparing apples and oranges:

Non-identical items are different by definition. Even between 2 apples there are differences, but it doesn't mean the distinction is important. The latest patch shows that the vault_add needs to be split, not just because of the options, but because of what they do differently on the client and server.

  a) When the non-split vault_{archive,retrieve} was called from a
server API with client-only options, it crashed. This is the broken API
I was talking about.

This is because in the current framework any API called on the server side will be a server API, so you are not supposed to call it with client options in the first place. Because of that limitation, the only way to use client options is to use a separate API on the client side to call the original API on the server side. The point is, client options belong to client API, and server options belong to server API. In vault_add the public key file name belongs to client API because it's used to load a file on the client side. You should not add public key file name option to the server API just because it can safely be ignored.

  b) The non-split vault_{archive,retrieve} had server-only options,
which were also accepted on client, but setting them had no effect.

Similarly, in a combined vault_add the public key file name option will be accepted by the server, but it will be ignored. If something calls vault_add on the server side and provides a file name, the operation will crash too because the command expects the public key data to be provided via another option. Splitting the vault_add into client and server components avoids the potential problems.

  c) The CLI options to read param values from files should be generated
by the framework without having to specify dummy params. Once this is
implemented, the dummy params will go away. However, this will still
leave some client-only options in vault_{archive,retrieve}.

I'm not sure how the options will look like when that's implemented, but regardless, the vault_add will still have client-only password option.

None of the above applies to vault_add - it does not have any
server-only options and the only client-only options it has are the
dummy options for file input, which are ignored on the server.

Let's not get fixated with just the options. The vault_add will now archive a blank initial data as it was originally designed. The data can be used later to verify the vault password in subsequent archival operations. The vault_archive must be called by vault_add's client component since it takes a password and the password cannot be sent to the server.

Also, originally the vault was designed like this: when you create a
symmetric vault you're supposed to specify the password as well, similar
to adding a public key when creating an asymmetric vault. When you
archive, you're supposed to enter the same password for verification,
not a new password. So it would look like this:

$ ipa vault-add test --type symmetric
New password: ********
Verify password: ********

$ ipa vault-archive test --in secret1.txt
Password: ******** (same password)

$ ipa vault-archive test --in secret2.txt
Password: ******** (same password)

In the original design the vault-add would also archive a blank data,
which later could be used to verify the password during vault-archive by
decrypting the existing data first. There's also a plan to add a
mechanism to change the password after the ACL patch.

In the current design the vault-add doesn't archive anything, so during
vault-archive it cannot verify the password because there is nothing to
decrypt. In other words you can specify different passwords on each
archival, regardless of previous archivals:

$ ipa vault-add test --type symmetric

$ ipa vault-archive test --in secret1.txt
New password: ********
Verify password: ********

$ ipa vault-archive test --in secret2.txt
New password: ********
Verify password: ********

So basically here are the options:

1. Specify the crypto parameters once during vault creation, then
reuse/verify the parameters on each archival & retrieval. You can change
the parameters only with a special command.

2. Don't specify the crypto parameters during vault creation, but
specify new parameters on each archival. For retrieval you'd have to
use/verify the parameters specified in the last archival.

I think the first one makes more sense and is easier to use. That also
means the vault-add will have additional client-only parameters such as
--password and --password-file.

How come --password is client-side? When setting password for a user,
the password is sent to the server. If it's OK for users, why is it not
OK for vaults?

Please see the sequence diagram in the vault design page. Vault password is used by the user to encrypt the secret before it's sent to the server. The server is not supposed to know the vault password. I'm not sure exactly how the user password is used, but I suppose the crypto operation is done on the server side.

Does the password need to be set in vault_add? Why not have a separate
command for setting the password, like what we have for users?

No. Vault password is not stored on the server. It's only used to generate encryption key on the client side, and the password & key will be discarded immediately after each use. That's why you have to specify the password on each archival & retrieval.

2. Since the vault_archive_internal inherits from Update, it accepts
all non
primary-key attributes automatically. This is incorrect since we
don't want to
update these parameters during archival. Can this behavior be
overridden?

Inherit from PKQuery instead (don't forget to add "has_output =
output.standard_entry").

Previously you didn't want to use LDAPQuery because of semantics
reasons. Is PKQuery fine semantically?

It's not. Currently there is a set of commands which operate on the LDAP
part of vault and another set of commands which operate on the KRA part
of vault and we don't want the commands in one set to see attributes
related to the other part of vault. If you insist on keeping both parts
in a single object, you have to resort to hackery like using PKQuery,
hence my suggestion to split the data part off to a separate object to
avoid this.

This because the framework was based on simplistic assumptions which create unnecessary restrictions, for example: * client API is just a proxy to server API (i.e. client and server cannot do different things) * CLI options will be identical to client and server API options (i.e. no CLI-only, client-only, or server-only options) * a plugin will only access one type of data (i.e. LDAP plugin can only access LDAP data) * a command name will match the object name (i.e. must use vaultdata_mod instead of a more intuitive vault_archive)

We know that some use cases do not fit these assumptions. Rather than compromising the use case, or looking at workarounds as hacks, I'd suggest finding ideas to improve the framework itself to be more accommodating.

Why not use LDAPQuery since vault
is an LDAPObject?

Because you are retrieving data from KRA, not from LDAP.

The vault archive and retrieve do actually retrieve the vault LDAP entry first, then perform the KRA archival/retrieval after that. Right now they use vault_show to do the LDAP retrieval, but in the old patch it was implemented as LDAPRetrieve. Regardless, they are retrieving both LDAP and KRA data.

And to be consistent should vault_retrieve_internal
inherit from the same class?

It could, but it's not necessary.

Changed for consistency.

--
Endi S. Dewata
>From 0f0ba6bf9a78b154a0a52e1805ba651a9d93beb7 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edew...@redhat.com>
Date: Fri, 24 Oct 2014 19:53:16 -0400
Subject: [PATCH] Added symmetric and asymmetric vaults.

The vault plugin has been modified to support symmetric and asymmetric
vaults to provide additional security over the standard vault by
encrypting the data before it's sent to the server. The encryption
functionality is implemented using the python-cryptography library.

https://fedorahosted.org/freeipa/ticket/3872
---
 API.txt                                   |  52 ++-
 VERSION                                   |   4 +-
 freeipa.spec.in                           |   2 +
 install/share/60basev3.ldif               |   4 +-
 ipalib/plugins/vault.py                   | 583 ++++++++++++++++++++++++++++--
 ipatests/test_xmlrpc/test_vault_plugin.py | 221 +++++++++--
 6 files changed, 794 insertions(+), 72 deletions(-)

diff --git a/API.txt b/API.txt
index 
3bcb3bdd24ada4e513f6263fc32a2953c18fc142..a90e60ad97fa56a304c54fd61a4b02ad7559882f
 100644
--- a/API.txt
+++ b/API.txt
@@ -5327,14 +5327,35 @@ output: Output('result', <type 'bool'>, None)
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: PrimaryKey('value', None, None)
 command: vault_add
-args: 1,9,3
+args: 1,14,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: Str('addattr*', cli_name='addattr', exclude='webui')
+option: Flag('all', autofill=True, cli_name='all', default=False, 
exclude='webui')
+option: Str('description?', cli_name='desc')
+option: Bytes('ipapublickey?', cli_name='public_key')
+option: Str('ipavaulttype?', cli_name='type')
+option: Str('password?', cli_name='password')
+option: Str('password_file?', cli_name='password_file')
+option: Str('public_key_file?', cli_name='public_key_file')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, 
exclude='webui')
+option: Str('service?')
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Flag('shared?', autofill=True, default=False)
+option: Str('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)
+command: vault_add_internal
+args: 1,10,3
 arg: Str('cn', attribute=True, cli_name='name', maxlength=255, 
multivalue=False, pattern='^[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: Bytes('ipapublickey', attribute=True, cli_name='public_key', 
multivalue=False, required=False)
+option: Bytes('ipavaultsalt', attribute=True, cli_name='salt', 
multivalue=False, required=False)
+option: Str('ipavaulttype', attribute=True, autofill=True, cli_name='type', 
default=u'standard', multivalue=False, required=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, 
exclude='webui')
 option: Str('service?')
-option: Str('setattr*', cli_name='setattr', exclude='webui')
 option: Flag('shared?', autofill=True, default=False)
 option: Str('user?')
 option: Str('version?', exclude='webui')
@@ -5342,11 +5363,13 @@ 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_archive
-args: 1,8,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: Bytes('data?')
 option: Str('in?')
+option: Str('password?', cli_name='password')
+option: Str('password_file?', cli_name='password_file')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, 
exclude='webui')
 option: Str('service?')
 option: Flag('shared?', autofill=True, default=False)
@@ -5355,11 +5378,10 @@ 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_archive_encrypted
-args: 1,10,3
+command: vault_archive_internal
+args: 1,9,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('description', attribute=True, autofill=False, cli_name='desc', 
multivalue=False, required=False)
 option: Bytes('nonce')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, 
exclude='webui')
 option: Str('service?')
@@ -5383,11 +5405,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,11,4
+args: 1,12,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='name', 
maxlength=255, multivalue=False, pattern='^[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: Str('ipavaulttype', attribute=True, autofill=False, cli_name='type', 
default=u'standard', 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')
 option: Str('service?')
@@ -5401,12 +5424,15 @@ 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,11,3
+args: 1,14,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: 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: Bytes('ipapublickey', attribute=True, autofill=False, 
cli_name='public_key', multivalue=False, required=False)
+option: Bytes('ipavaultsalt', attribute=True, autofill=False, cli_name='salt', 
multivalue=False, required=False)
+option: Str('ipavaulttype', attribute=True, autofill=False, cli_name='type', 
default=u'standard', multivalue=False, required=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, 
exclude='webui')
 option: Flag('rights', autofill=True, default=False)
 option: Str('service?')
@@ -5418,10 +5444,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_retrieve
-args: 1,7,3
+args: 1,11,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('out?')
+option: Str('password?', cli_name='password')
+option: Str('password_file?', cli_name='password_file')
+option: Bytes('private_key?', cli_name='private_key')
+option: Str('private_key_file?', cli_name='private_key_file')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, 
exclude='webui')
 option: Str('service?')
 option: Flag('shared?', autofill=True, default=False)
@@ -5430,7 +5460,7 @@ 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_retrieve_encrypted
+command: vault_retrieve_internal
 args: 1,7,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')
diff --git a/VERSION b/VERSION
index 
224d34925685c8ecb6f2db3672d34c40621dc9dc..f96638721fb10c5925e9289da4ba41c86e39adeb
 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=135
-# Last change: jcholast - User life cycle: Make user-del flags CLI-specific
+IPA_API_VERSION_MINOR=136
+# Last change: edewata - added symmetric and asymmetric vaults
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 
809ac1e5bb877c85e29c082ecfb9ad91aa97b4f5..e90b489c831f8eec01e9a13bbf159edcce9a9407
 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -64,6 +64,7 @@ BuildRequires:  python-ldap
 BuildRequires:  python-setuptools
 BuildRequires:  python-krbV
 BuildRequires:  python-nss
+BuildRequires:  python-cryptography
 BuildRequires:  python-netaddr
 BuildRequires:  python-kerberos >= 1.1-14
 BuildRequires:  python-rhsm
@@ -286,6 +287,7 @@ Requires: iproute
 Requires: keyutils
 Requires: pyOpenSSL
 Requires: python-nss >= 0.16
+Requires: python-cryptography
 Requires: python-lxml
 Requires: python-netaddr
 Requires: libipa_hbac-python
diff --git a/install/share/60basev3.ldif b/install/share/60basev3.ldif
index 
33f4804e30ff1b3814ecf295bb41f07e2a8cd12f..cb159db05a5371c71e421160f60140d85ba5496f
 100644
--- a/install/share/60basev3.ldif
+++ b/install/share/60basev3.ldif
@@ -56,6 +56,8 @@ attributeTypes: (2.16.840.1.113730.3.8.11.64 NAME 
'ipaSecretKeyRef' DESC 'DN of
 attributeTypes: (2.16.840.1.113730.3.8.11.65 NAME 'ipaWrappingMech' DESC 
'PKCS#11 wrapping mechanism equivalent to CK_MECHANISM_TYPE' EQUALITY 
caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA 
v4.1')
 attributeTypes: (2.16.840.1.113730.3.8.11.70 NAME 'ipaPermTargetTo' DESC 
'Destination location to move an entry IPA permission ACI' EQUALITY 
distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE 
X-ORIGIN 'IPA v4.0' )
 attributeTypes: (2.16.840.1.113730.3.8.11.71 NAME 'ipaPermTargetFrom' DESC 
'Source location from where moving an entry IPA permission ACI' EQUALITY 
distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE 
X-ORIGIN 'IPA v4.0' )
+attributeTypes: (2.16.840.1.113730.3.8.18.2.1 NAME 'ipaVaultType' DESC 'IPA 
vault type' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 
X-ORIGIN 'IPA v4.2')
+attributeTypes: (2.16.840.1.113730.3.8.18.2.2 NAME 'ipaVaultSalt' DESC 'IPA 
vault salt' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 
X-ORIGIN 'IPA v4.2' )
 objectClasses: (2.16.840.1.113730.3.8.12.1 NAME 'ipaExternalGroup' SUP top 
STRUCTURAL MUST ( cn ) MAY ( ipaExternalMember $ memberOf $ description $ 
owner) X-ORIGIN 'IPA v3' )
 objectClasses: (2.16.840.1.113730.3.8.12.2 NAME 'ipaNTUserAttrs' SUP top 
AUXILIARY MUST ( ipaNTSecurityIdentifier ) MAY ( ipaNTHash $ ipaNTLogonScript $ 
ipaNTProfilePath $ ipaNTHomeDirectory $ ipaNTHomeDirectoryDrive ) X-ORIGIN 'IPA 
v3' )
 objectClasses: (2.16.840.1.113730.3.8.12.3 NAME 'ipaNTGroupAttrs' SUP top 
AUXILIARY MUST ( ipaNTSecurityIdentifier ) X-ORIGIN 'IPA v3' )
@@ -79,4 +81,4 @@ objectClasses: (2.16.840.1.113730.3.8.12.24 NAME 
'ipaPublicKeyObject' DESC 'Wrap
 objectClasses: (2.16.840.1.113730.3.8.12.25 NAME 'ipaPrivateKeyObject' DESC 
'Wrapped private keys' SUP top AUXILIARY MUST ( ipaPrivateKey $ ipaWrappingKey 
$ ipaWrappingMech ) X-ORIGIN 'IPA v4.1' )
 objectClasses: (2.16.840.1.113730.3.8.12.26 NAME 'ipaSecretKeyObject' DESC 
'Wrapped secret keys' SUP top AUXILIARY MUST ( ipaSecretKey $ ipaWrappingKey $ 
ipaWrappingMech ) X-ORIGIN 'IPA v4.1' )
 objectClasses: (2.16.840.1.113730.3.8.12.34 NAME 'ipaSecretKeyRefObject' DESC 
'Indirect storage for encoded key material' SUP top AUXILIARY MUST ( 
ipaSecretKeyRef ) X-ORIGIN 'IPA v4.1' )
-objectClasses: (2.16.840.1.113730.3.8.18.1.1 NAME 'ipaVault' DESC 'IPA vault' 
SUP top STRUCTURAL MUST ( cn ) MAY ( description ) X-ORIGIN 'IPA v4.2' )
+objectClasses: (2.16.840.1.113730.3.8.18.1.1 NAME 'ipaVault' DESC 'IPA vault' 
SUP top STRUCTURAL MUST ( cn ) MAY ( description $ ipaVaultType $ ipaVaultSalt 
$ ipaPublicKey ) X-ORIGIN 'IPA v4.2' )
diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py
index 
f80ecfdfa72671a68822f9f87599d8d5f2898728..193fa5cbb6eb06d22a30d8cfba62e10e9557c1d6
 100644
--- a/ipalib/plugins/vault.py
+++ b/ipalib/plugins/vault.py
@@ -18,11 +18,20 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import base64
+import getpass
 import json
 import os
 import sys
 import tempfile
 
+from cryptography.fernet import Fernet, InvalidToken
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
+from cryptography.hazmat.primitives.asymmetric import padding
+from cryptography.hazmat.primitives.serialization import load_pem_public_key,\
+    load_pem_private_key
+
 import nss.nss as nss
 import krbV
 
@@ -50,6 +59,36 @@ Vaults
 """) + _("""
 Manage vaults.
 """) + _("""
+Vault is a secure place to store a secret.
+""") + _("""
+Based on the ownership there are three vault categories:
+* user/private vault
+* service vault
+* shared vault
+""") + _("""
+User vaults are vaults owned used by a particular user. Private
+vaults are vaults owned the current user. Service vaults are
+vaults owned by a service. Shared vaults are owned by the admin
+but they can be used by other users or services.
+""") + _("""
+Based on the security mechanism there are three types of
+vaults:
+* standard vault
+* symmetric vault
+* asymmetric vault
+""") + _("""
+Standard vault uses a secure mechanism to transport and
+store the secret. The secret can only be retrieved by users
+that have access to the vault.
+""") + _("""
+Symmetric vault is similar to the standard vault, but it
+pre-encrypts the secret using a password before transport.
+The secret can only be retrieved using the same password.
+""") + _("""
+Asymmetric vault is similar to the standard vault, but it
+pre-encrypts the secret using a public key before transport.
+The secret can only be retrieved using the private key.
+""") + _("""
 EXAMPLES:
 """) + _("""
  List private vaults:
@@ -76,6 +115,12 @@ EXAMPLES:
  Add a user vault:
    ipa vault-add <name> --user <username>
 """) + _("""
+ Add a symmetric vault:
+   ipa vault-add <name> --type symmetric --password-file password.txt
+""") + _("""
+ Add an asymmetric vault:
+   ipa vault-add <name> --type asymmetric --public-key-file public.pem
+""") + _("""
  Show a private vault:
    ipa vault-show <name>
 """) + _("""
@@ -113,7 +158,7 @@ EXAMPLES:
    ipa vault-del <name> --user <username>
 """) + _("""
  Display vault configuration:
-   ipa vault-config
+   ipa vaultconfig-show
 """) + _("""
  Archive data into private vault:
    ipa vault-archive <name> --in <input file>
@@ -127,6 +172,12 @@ EXAMPLES:
  Archive data into user vault:
    ipa vault-archive <name> --user <username> --in <input file>
 """) + _("""
+ Archive data into symmetric vault:
+   ipa vault-archive <name> --in <input file>
+""") + _("""
+ Archive data into asymmetric vault:
+   ipa vault-archive <name> --in <input file>
+""") + _("""
  Retrieve data from private vault:
    ipa vault-retrieve <name> --out <output file>
 """) + _("""
@@ -137,7 +188,13 @@ EXAMPLES:
    ipa vault-retrieve <name> --shared --out <output file>
 """) + _("""
  Retrieve data from user vault:
-   ipa vault-retrieve <name> --user <user name> --out <output file>
+   ipa vault-retrieve <name> --user <username> --out <output file>
+""") + _("""
+ Retrieve data from symmetric vault:
+   ipa vault-retrieve <name> --out data.bin
+""") + _("""
+ Retrieve data from asymmetric vault:
+   ipa vault-retrieve <name> --out data.bin --private-key-file private.pem
 """)
 
 register = Registry()
@@ -146,7 +203,7 @@ register = Registry()
 vault_options = (
     Str(
         'service?',
-        doc=_('Service name'),
+        doc=_('Service name of the service vault'),
     ),
     Flag(
         'shared?',
@@ -154,7 +211,7 @@ vault_options = (
     ),
     Str(
         'user?',
-        doc=_('Username'),
+        doc=_('Username of the user vault'),
     ),
 )
 
@@ -174,6 +231,14 @@ class vault(LDAPObject):
     default_attributes = [
         'cn',
         'description',
+        'ipavaulttype',
+        'ipavaultsalt',
+        'ipapublickey',
+    ]
+    search_display_attributes = [
+        'cn',
+        'description',
+        'ipavaulttype',
     ]
 
     label = _('Vaults')
@@ -195,6 +260,28 @@ class vault(LDAPObject):
             label=_('Description'),
             doc=_('Vault description'),
         ),
+        Str(
+            'ipavaulttype?',
+            cli_name='type',
+            label=_('Type'),
+            doc=_('Vault type'),
+            default=u'standard',
+            autofill=True,
+        ),
+        Bytes(
+            'ipavaultsalt?',
+            cli_name='salt',
+            label=_('Salt'),
+            doc=_('Vault salt'),
+            flags=['no_search'],
+        ),
+        Bytes(
+            'ipapublickey?',
+            cli_name='public_key',
+            label=_('Public key'),
+            doc=_('Vault public key'),
+            flags=['no_search'],
+        ),
     )
 
     def get_dn(self, *keys, **options):
@@ -307,12 +394,232 @@ class vault(LDAPObject):
 
         return 'ipa:' + id
 
+    def get_new_password(self):
+        """
+        Gets new password from user and verify it.
+        """
+        while True:
+            password = getpass.getpass('New password: ').decode(
+                sys.stdin.encoding)
+            password2 = getpass.getpass('Verify password: ').decode(
+                sys.stdin.encoding)
+
+            if password == password2:
+                return password
+
+            print '  ** Passwords do not match! **'
+
+    def get_existing_password(self, new=False):
+        """
+        Gets existing password from user.
+        """
+        return getpass.getpass('Password: ').decode(sys.stdin.encoding)
+
+    def generate_symmetric_key(self, password, salt):
+        """
+        Generates symmetric key from password and salt.
+        """
+        kdf = PBKDF2HMAC(
+            algorithm=hashes.SHA256(),
+            length=32,
+            salt=salt,
+            iterations=100000,
+            backend=default_backend()
+        )
+
+        return base64.b64encode(kdf.derive(password.encode('utf-8')))
+
+    def encrypt(self, data, symmetric_key=None, public_key=None):
+        """
+        Encrypts data with symmetric key or public key.
+        """
+        if symmetric_key:
+            fernet = Fernet(symmetric_key)
+            return fernet.encrypt(data)
+
+        elif public_key:
+            rsa_public_key = load_pem_public_key(
+                data=public_key,
+                backend=default_backend()
+            )
+            return rsa_public_key.encrypt(
+                data,
+                padding.OAEP(
+                    mgf=padding.MGF1(algorithm=hashes.SHA1()),
+                    algorithm=hashes.SHA1(),
+                    label=None
+                )
+            )
+
+    def decrypt(self, data, symmetric_key=None, private_key=None):
+        """
+        Decrypts data with symmetric key or public key.
+        """
+        if symmetric_key:
+            try:
+                fernet = Fernet(symmetric_key)
+                return fernet.decrypt(data)
+            except InvalidToken:
+                raise errors.AuthenticationError(
+                    message=_('Invalid credentials'))
+
+        elif private_key:
+            try:
+                rsa_private_key = load_pem_private_key(
+                    data=private_key,
+                    password=None,
+                    backend=default_backend()
+                )
+                return rsa_private_key.decrypt(
+                    data,
+                    padding.OAEP(
+                        mgf=padding.MGF1(algorithm=hashes.SHA1()),
+                        algorithm=hashes.SHA1(),
+                        label=None
+                    )
+                )
+            except AssertionError:
+                raise errors.AuthenticationError(
+                    message=_('Invalid credentials'))
+
 
 @register()
-class vault_add(LDAPCreate):
+class vault_add(PKQuery, Local):
     __doc__ = _('Create a new vault.')
 
-    takes_options = LDAPCreate.takes_options + vault_options
+    takes_options = LDAPCreate.takes_options + vault_options + (
+        Str(
+            'description?',
+            cli_name='desc',
+            doc=_('Vault description'),
+        ),
+        Str(
+            'ipavaulttype?',
+            cli_name='type',
+            doc=_('Vault type'),
+        ),
+        Str(
+            'password?',
+            cli_name='password',
+            doc=_('Vault password'),
+        ),
+        Str(  # TODO: use File parameter
+            'password_file?',
+            cli_name='password_file',
+            doc=_('File containing the vault password'),
+        ),
+        Bytes(
+            'ipapublickey?',
+            cli_name='public_key',
+            doc=_('Vault public key'),
+        ),
+        Str(  # TODO: use File parameter
+            'public_key_file?',
+            cli_name='public_key_file',
+            doc=_('File containing the vault public key'),
+        ),
+    )
+
+    has_output = output.standard_entry
+
+    def forward(self, *args, **options):
+
+        vault_type = options.get('ipavaulttype', u'standard')
+        password = options.get('password')
+        password_file = options.get('password_file')
+        public_key = options.get('ipapublickey')
+        public_key_file = options.get('public_key_file')
+
+        # don't send these parameters to server
+        if 'password' in options:
+            del options['password']
+        if 'password_file' in options:
+            del options['password_file']
+        if 'public_key_file' in options:
+            del options['public_key_file']
+
+        if self.api.env.in_server:
+            backend = self.api.Backend.ldap2
+        else:
+            backend = self.api.Backend.rpcclient
+        if not backend.isconnected():
+            backend.connect(ccache=krbV.default_context().default_ccache())
+
+        if vault_type == u'standard':
+
+            pass
+
+        elif vault_type == u'symmetric':
+
+            # get password
+            if password and password_file:
+                raise errors.MutuallyExclusiveError(
+                    reason=_('Password specified multiple times'))
+
+            elif password:
+                pass
+
+            elif password_file:
+                with open(password_file, 'rb') as f:
+                    password = f.read().rstrip('\n').decode('utf-8')
+
+            else:
+                password = self.obj.get_new_password()
+
+            # generate vault salt
+            options['ipavaultsalt'] = os.urandom(16)
+
+        elif vault_type == u'asymmetric':
+
+            # get new vault public key
+            if public_key and public_key_file:
+                raise errors.MutuallyExclusiveError(
+                    reason=_('Public key specified multiple times'))
+
+            elif public_key:
+                pass
+
+            elif public_key_file:
+                with open(public_key_file, 'rb') as f:
+                    public_key = f.read()
+
+                # store vault public key
+                options['ipapublickey'] = public_key
+
+            else:
+                raise errors.ValidationError(
+                    name='ipapublickey',
+                    error=_('Missing vault public key'))
+
+        # create vault
+        response = self.api.Command.vault_add_internal(*args, **options)
+
+        # prepare parameters for archival
+        opts = options.copy()
+        if 'description' in opts:
+            del opts['description']
+        if 'ipavaulttype' in opts:
+            del opts['ipavaulttype']
+
+        if vault_type == u'symmetric':
+            opts['password'] = password
+            del opts['ipavaultsalt']
+
+        elif vault_type == u'asymmetric':
+            del opts['ipapublickey']
+
+        # archive blank data
+        self.api.Command.vault_archive(*args, **opts)
+
+        return response
+
+
+@register()
+class vault_add_internal(LDAPCreate):
+
+    NO_CLI = True
+
+    takes_options = vault_options
 
     msg_summary = _('Added vault "%(value)s"')
 
@@ -513,29 +820,46 @@ class vault_archive(PKQuery, Local):
             'in?',
             doc=_('File containing data to archive'),
         ),
+        Str(
+            'password?',
+            cli_name='password',
+            doc=_('Vault password'),
+        ),
+        Str(  # TODO: use File parameter
+            'password_file?',
+            cli_name='password_file',
+            doc=_('File containing the vault password'),
+        ),
     )
 
     has_output = output.standard_entry
 
-    msg_summary = _('Archived data into vault "%(value)s"')
-
     def forward(self, *args, **options):
 
+        name = args[-1]
+
         data = options.get('data')
         input_file = options.get('in')
 
+        password = options.get('password')
+        password_file = options.get('password_file')
+
         # don't send these parameters to server
         if 'data' in options:
             del options['data']
         if 'in' in options:
             del options['in']
+        if 'password' in options:
+            del options['password']
+        if 'password_file' in options:
+            del options['password_file']
 
         # get data
         if data and input_file:
             raise errors.MutuallyExclusiveError(
                 reason=_('Input data specified multiple times'))
 
-        if input_file:
+        elif input_file:
             with open(input_file, 'rb') as f:
                 data = f.read()
 
@@ -549,13 +873,77 @@ class vault_archive(PKQuery, Local):
         if not backend.isconnected():
             backend.connect(ccache=krbV.default_context().default_ccache())
 
+        # retrieve vault info
+        vault = self.api.Command.vault_show(*args, **options)['result']
+
+        vault_type = vault['ipavaulttype'][0]
+
+        if vault_type == u'standard':
+
+            encrypted_key = None
+
+        elif vault_type == u'symmetric':
+
+            # get password
+            if password and password_file:
+                raise errors.MutuallyExclusiveError(
+                    reason=_('Password specified multiple times'))
+
+            elif password:
+                pass
+
+            elif password_file:
+                with open(password_file) as f:
+                    password = f.read().rstrip('\n').decode('utf-8')
+
+            else:
+                password = self.obj.get_existing_password()
+
+            # verify password by retrieving existing data
+            opts = options.copy()
+            opts['password'] = password
+            try:
+                self.api.Command.vault_retrieve(*args, **opts)
+            except errors.NotFound:
+                pass
+
+            salt = vault['ipavaultsalt'][0]
+
+            # generate encryption key from vault password
+            encryption_key = self.obj.generate_symmetric_key(
+                password, salt)
+
+            # encrypt data with encryption key
+            data = self.obj.encrypt(data, symmetric_key=encryption_key)
+
+            encrypted_key = None
+
+        elif vault_type == u'asymmetric':
+
+            public_key = vault['ipapublickey'][0].encode('utf-8')
+
+            # generate encryption key
+            encryption_key = base64.b64encode(os.urandom(32))
+
+            # encrypt data with encryption key
+            data = self.obj.encrypt(data, symmetric_key=encryption_key)
+
+            # encrypt encryption key with public key
+            encrypted_key = self.obj.encrypt(
+                encryption_key, public_key=public_key)
+
+        else:
+            raise errors.ValidationError(
+                name='vault_type',
+                error=_('Invalid vault type'))
+
         # initialize NSS database
         current_dbdir = paths.IPA_NSSDB_DIR
         nss.nss_init(current_dbdir)
 
         # retrieve transport certificate
-        config = self.api.Command.vaultconfig_show()
-        transport_cert_der = config['result']['transport_cert']
+        config = self.api.Command.vaultconfig_show()['result']
+        transport_cert_der = config['transport_cert']
         nss_transport_cert = nss.Certificate(transport_cert_der)
 
         # generate session key
@@ -579,6 +967,10 @@ class vault_archive(PKQuery, Local):
         vault_data = {}
         vault_data[u'data'] = base64.b64encode(data).decode('utf-8')
 
+        if encrypted_key:
+            vault_data[u'encrypted_key'] = base64.b64encode(encrypted_key)\
+                .decode('utf-8')
+
         json_vault_data = json.dumps(vault_data)
 
         # wrap vault_data with session key
@@ -595,16 +987,12 @@ class vault_archive(PKQuery, Local):
 
         options['vault_data'] = wrapped_vault_data
 
-        response = self.api.Command.vault_archive_encrypted(*args, **options)
-
-        response['result'] = {}
-        del response['summary']
-
-        return response
+        return self.api.Command.vault_archive_internal(*args, **options)
 
 
 @register()
-class vault_archive_encrypted(Update):
+class vault_archive_internal(PKQuery):
+
     NO_CLI = True
 
     takes_options = vault_options + (
@@ -622,6 +1010,10 @@ class vault_archive_encrypted(Update):
         ),
     )
 
+    has_output = output.standard_entry
+
+    msg_summary = _('Archived data into vault "%(value)s"')
+
     def execute(self, *args, **options):
 
         if not self.api.Command.kra_is_enabled()['result']:
@@ -633,8 +1025,7 @@ class vault_archive_encrypted(Update):
         wrapped_session_key = options.pop('session_key')
 
         # retrieve vault info
-        result = self.api.Command.vault_show(*args, **options)
-        vault = result['result']
+        vault = self.api.Command.vault_show(*args, **options)['result']
 
         # connect to KRA
         kra_client = self.api.Backend.kra.get_client()
@@ -666,7 +1057,14 @@ class vault_archive_encrypted(Update):
 
         kra_account.logout()
 
-        return result
+        response = {
+            'value': args[-1],
+            'result': {},
+        }
+
+        response['summary'] = self.msg_summary % response
+
+        return response
 
 
 @register()
@@ -678,6 +1076,26 @@ class vault_retrieve(PKQuery, Local):
             'out?',
             doc=_('File to store retrieved data'),
         ),
+        Str(
+            'password?',
+            cli_name='password',
+            doc=_('Vault password'),
+        ),
+        Str(  # TODO: use File parameter
+            'password_file?',
+            cli_name='password_file',
+            doc=_('File containing the vault password'),
+        ),
+        Bytes(
+            'private_key?',
+            cli_name='private_key',
+            doc=_('Vault private key'),
+        ),
+        Str(  # TODO: use File parameter
+            'private_key_file?',
+            cli_name='private_key_file',
+            doc=_('File containing the vault private key'),
+        ),
     )
 
     has_output = output.standard_entry
@@ -688,15 +1106,28 @@ class vault_retrieve(PKQuery, Local):
         ),
     )
 
-    msg_summary = _('Retrieved data from vault "%(value)s"')
-
     def forward(self, *args, **options):
 
+        name = args[-1]
+
         output_file = options.get('out')
 
+        password = options.get('password')
+        password_file = options.get('password_file')
+        private_key = options.get('private_key')
+        private_key_file = options.get('private_key_file')
+
         # don't send these parameters to server
         if 'out' in options:
             del options['out']
+        if 'password' in options:
+            del options['password']
+        if 'password_file' in options:
+            del options['password_file']
+        if 'private_key' in options:
+            del options['private_key']
+        if 'private_key_file' in options:
+            del options['private_key_file']
 
         if self.api.env.in_server:
             backend = self.api.Backend.ldap2
@@ -705,13 +1136,18 @@ class vault_retrieve(PKQuery, Local):
         if not backend.isconnected():
             backend.connect(ccache=krbV.default_context().default_ccache())
 
+        # retrieve vault info
+        vault = self.api.Command.vault_show(*args, **options)['result']
+
+        vault_type = vault['ipavaulttype'][0]
+
         # initialize NSS database
         current_dbdir = paths.IPA_NSSDB_DIR
         nss.nss_init(current_dbdir)
 
         # retrieve transport certificate
-        config = self.api.Command.vaultconfig_show()
-        transport_cert_der = config['result']['transport_cert']
+        config = self.api.Command.vaultconfig_show()['result']
+        transport_cert_der = config['transport_cert']
         nss_transport_cert = nss.Certificate(transport_cert_der)
 
         # generate session key
@@ -729,7 +1165,7 @@ class vault_retrieve(PKQuery, Local):
         # send retrieval request to server
         options['session_key'] = wrapped_session_key.data
 
-        response = self.api.Command.vault_retrieve_encrypted(*args, **options)
+        response = self.api.Command.vault_retrieve_internal(*args, **options)
 
         result = response['result']
         nonce = result['nonce']
@@ -751,18 +1187,85 @@ class vault_retrieve(PKQuery, Local):
         vault_data = json.loads(json_vault_data)
         data = base64.b64decode(vault_data[u'data'].encode('utf-8'))
 
+        encrypted_key = None
+
+        if 'encrypted_key' in vault_data:
+            encrypted_key = base64.b64decode(vault_data[u'encrypted_key']
+                                             .encode('utf-8'))
+
+        if vault_type == u'standard':
+
+            pass
+
+        elif vault_type == u'symmetric':
+
+            salt = vault['ipavaultsalt'][0]
+
+            # get encryption key from vault password
+            if password and password_file:
+                raise errors.MutuallyExclusiveError(
+                    reason=_('Password specified multiple times'))
+
+            elif password:
+                pass
+
+            elif password_file:
+                with open(password_file) as f:
+                    password = f.read().rstrip('\n').decode('utf-8')
+
+            else:
+                password = self.obj.get_existing_password()
+
+            # generate encryption key from password
+            encryption_key = self.obj.generate_symmetric_key(password, salt)
+
+            # decrypt data with encryption key
+            data = self.obj.decrypt(data, symmetric_key=encryption_key)
+
+        elif vault_type == u'asymmetric':
+
+            # get encryption key with vault private key
+            if private_key and private_key_file:
+                raise errors.MutuallyExclusiveError(
+                    reason=_('Private key specified multiple times'))
+
+            elif private_key:
+                pass
+
+            elif private_key_file:
+                with open(private_key_file, 'rb') as f:
+                    private_key = f.read()
+
+            else:
+                raise errors.ValidationError(
+                    name='private_key',
+                    error=_('Missing vault private key'))
+
+            # decrypt encryption key with private key
+            encryption_key = self.obj.decrypt(
+                encrypted_key, private_key=private_key)
+
+            # decrypt data with encryption key
+            data = self.obj.decrypt(data, symmetric_key=encryption_key)
+
+        else:
+            raise errors.ValidationError(
+                name='vault_type',
+                error=_('Invalid vault type'))
+
         if output_file:
             with open(output_file, 'w') as f:
                 f.write(data)
 
-        response['result'] = {'data': data}
-        del response['summary']
+        else:
+            response['result'] = {'data': data}
 
         return response
 
 
 @register()
-class vault_retrieve_encrypted(Retrieve):
+class vault_retrieve_internal(PKQuery):
+
     NO_CLI = True
 
     takes_options = vault_options + (
@@ -772,6 +1275,10 @@ class vault_retrieve_encrypted(Retrieve):
         ),
     )
 
+    has_output = output.standard_entry
+
+    msg_summary = _('Retrieved data from vault "%(value)s"')
+
     def execute(self, *args, **options):
 
         if not self.api.Command.kra_is_enabled()['result']:
@@ -781,8 +1288,7 @@ class vault_retrieve_encrypted(Retrieve):
         wrapped_session_key = options.pop('session_key')
 
         # retrieve vault info
-        result = self.api.Command.vault_show(*args, **options)
-        vault = result['result']
+        vault = self.api.Command.vault_show(*args, **options)['result']
 
         # connect to KRA
         kra_client = self.api.Backend.kra.get_client()
@@ -807,12 +1313,19 @@ class vault_retrieve_encrypted(Retrieve):
             key_info.get_key_id(),
             wrapped_session_key)
 
-        vault['vault_data'] = key.encrypted_data
-        vault['nonce'] = key.nonce_data
-
         kra_account.logout()
 
-        return result
+        response = {
+            'value': args[-1],
+            'result': {
+                'vault_data': key.encrypted_data,
+                'nonce': key.nonce_data,
+            },
+        }
+
+        response['summary'] = self.msg_summary % response
+
+        return response
 
 
 @register()
diff --git a/ipatests/test_xmlrpc/test_vault_plugin.py 
b/ipatests/test_xmlrpc/test_vault_plugin.py
index 
9a40547b17f4e35f0bc0032e4e1d73e226243355..f8b57855a152c4c86d3a7681e6cc187a85b2c468
 100644
--- a/ipatests/test_xmlrpc/test_vault_plugin.py
+++ b/ipatests/test_xmlrpc/test_vault_plugin.py
@@ -22,15 +22,63 @@ Test the `ipalib/plugins/vault.py` module.
 """
 
 from ipalib import api, errors
-from xmlrpc_test import Declarative
+from xmlrpc_test import Declarative, fuzzy_string
 
 vault_name = u'test_vault'
 service_name = u'HTTP/server.example.com'
 user_name = u'testuser'
 
+standard_vault_name = u'standard_test_vault'
+symmetric_vault_name = u'symmetric_test_vault'
+asymmetric_vault_name = u'asymmetric_test_vault'
+
 # binary data from \x00 to \xff
 secret = ''.join(map(chr, xrange(0, 256)))
 
+password = u'password'
+
+public_key = """
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnT61EFxUOQgCJdM0tmw/
+pRRPDPGchTClnU1eBtiQD3ItKYf1+weMGwGOSJXPtkto7NlE7Qs8WHAr0UjyeBDe
+k/zeB6nSVdk47OdaW1AHrJL+44r238Jbm/+7VO5lTu6Z4N5p0VqoWNLi0Uh/CkqB
+tsxXaaAgjMp0AGq2U/aO/akeEYWQOYIdqUKVgAEKX5MmIA8tmbmoYIQ+B4Q3vX7N
+otG4eR6c2o9Fyjd+M4Gai5Ce0fSrigRvxAYi8xpRkQ5yQn5gf4WVrn+UKTfOIjLO
+pVThop+Xivcre3SpI0kt6oZPhBw9i8gbMnqifVmGFpVdhq+QVBqp+MVJvTbhRPG6
+3wIDAQAB
+-----END PUBLIC KEY-----
+"""
+
+private_key = """
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAnT61EFxUOQgCJdM0tmw/pRRPDPGchTClnU1eBtiQD3ItKYf1
++weMGwGOSJXPtkto7NlE7Qs8WHAr0UjyeBDek/zeB6nSVdk47OdaW1AHrJL+44r2
+38Jbm/+7VO5lTu6Z4N5p0VqoWNLi0Uh/CkqBtsxXaaAgjMp0AGq2U/aO/akeEYWQ
+OYIdqUKVgAEKX5MmIA8tmbmoYIQ+B4Q3vX7NotG4eR6c2o9Fyjd+M4Gai5Ce0fSr
+igRvxAYi8xpRkQ5yQn5gf4WVrn+UKTfOIjLOpVThop+Xivcre3SpI0kt6oZPhBw9
+i8gbMnqifVmGFpVdhq+QVBqp+MVJvTbhRPG63wIDAQABAoIBAQCD2bXnfxPcMnvi
+jaPwpvoDCPF0EBBHmk/0g5ApO2Qon3uBDJFUqbJwXrCY6o2d9MOJfnGONlKmcYA8
+X+d4h+SqwGjIkjxdYeSauS+Jy6Rzr1ptH/P8EjPQrfG9uJxYQDflV3nxYwwwVrx7
+8kccMPdteRB+8Bb7FzOHufMimmayCNFETnVT5CKH2PrYoPB+fr0itCipWOenDp33
+e73OV+K9U3rclmtHaoRxGohqByKfQRUkipjw4m+T3qfZZc5eN77RGW8J+oL1GVom
+fwtiH7N1HVte0Dmd13nhiASg355kjqRPcIMPsRHvXkOpgg5HRUTKG5elqAyvvm27
+Fzj1YdeRAoGBAMnE61+FYh8qCyEGe8r6RGjO8iuoyk1t+0gBWbmILLBiRnj4K8Tc
+k7HBG/pg3XCNbCuRwiLg8tk3VAAXzn6o+IJr3QnKbNCGa1lKfYU4mt11sBEyuL5V
+NpZcZ8IiPhMlGyDA9cFbTMKOE08RqbOIdxOmTizFt0R5sYZAwOjEvBIZAoGBAMeC
+N/P0bdrScFZGeS51wEdiWme/CO0IyGoqU6saI8L0dbmMJquiaAeIEjIKLqxH1RON
+axhsyk97e0PCcc5QK62Utf50UUAbL/v7CpIG+qdSRYDO4bVHSCkwF32N3pYh/iVU
+EsEBEkZiJi0dWa/0asDbsACutxcHda3RI5pi7oO3AoGAcbGNs/CUHt1xEfX2UaT+
+YVSjb2iYPlNH8gYYygvqqqVl8opdF3v3mYUoP8jPXrnCBzcF/uNk1HNx2O+RQxvx
+lIQ1NGwlLsdfvBvWaPhBg6LqSHadVVrs/IMrUGA9PEp/Y9B3arIIqeSnCrn4Nxsh
+higDCwWKRIKSPwVD7qXVGBkCgYEAu5/CASIRIeYgEXMLSd8hKcDcJo8o1MoauIT/
+1Hyrvw9pm0qrn2QHk3WrLvYWeJzBTTcEzZ6aEG+fN9UodA8/VGnzUc6QDsrCsKWh
+hj0cArlDdeSZrYLQ4TNCFCiUePqU6QQM8weP6TMqlejxTKF+t8qi1bF5rCWuzP1P
+D0UU7DcCgYAUvmEGckugS+FTatop8S/rmkcQ4Bf5M/YCZfsySavucDiHcBt0QtXt
+Swh0XdDsYS3W1yj2XqqsQ7R58KNaffCHjjulWFzb5IiuSvvdxzWtiXHisOpO36MJ
+kUlCMj24a8XsShzYTWBIyW2ngvGe3pQ9PfjkUdm0LGZjYITCBvgOKw==
+-----END RSA PRIVATE KEY-----
+"""
+
 
 class test_vault_plugin(Declarative):
 
@@ -42,6 +90,9 @@ class test_vault_plugin(Declarative):
         }),
         ('vault_del', [vault_name], {'shared': True, 'continue': True}),
         ('vault_del', [vault_name], {'user': user_name, 'continue': True}),
+        ('vault_del', [standard_vault_name], {'continue': True}),
+        ('vault_del', [symmetric_vault_name], {'continue': True}),
+        ('vault_del', [asymmetric_vault_name], {'continue': True}),
     ]
 
     tests = [
@@ -61,6 +112,7 @@ class test_vault_plugin(Declarative):
                           % (vault_name, api.env.basedn),
                     'objectclass': [u'top', u'ipaVault'],
                     'cn': [vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -81,6 +133,7 @@ class test_vault_plugin(Declarative):
                         'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,cn=kra,%s'
                               % (vault_name, api.env.basedn),
                         'cn': [vault_name],
+                        'ipavaulttype': [u'standard'],
                     },
                 ],
             },
@@ -100,6 +153,7 @@ class test_vault_plugin(Declarative):
                     'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,cn=kra,%s'
                           % (vault_name, api.env.basedn),
                     'cn': [vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -119,6 +173,7 @@ class test_vault_plugin(Declarative):
                 'result': {
                     'cn': [vault_name],
                     'description': [u'Test vault'],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -156,6 +211,7 @@ class test_vault_plugin(Declarative):
                           % (vault_name, service_name, api.env.basedn),
                     'objectclass': [u'top', u'ipaVault'],
                     'cn': [vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -178,6 +234,7 @@ class test_vault_plugin(Declarative):
                         'dn': u'cn=%s,cn=%s,cn=services,cn=vaults,cn=kra,%s'
                               % (vault_name, service_name, api.env.basedn),
                         'cn': [vault_name],
+                        'ipavaulttype': [u'standard'],
                     },
                 ],
             },
@@ -199,6 +256,7 @@ class test_vault_plugin(Declarative):
                     'dn': u'cn=%s,cn=%s,cn=services,cn=vaults,cn=kra,%s'
                           % (vault_name, service_name, api.env.basedn),
                     'cn': [vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -219,6 +277,7 @@ class test_vault_plugin(Declarative):
                 'result': {
                     'cn': [vault_name],
                     'description': [u'Test vault'],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -258,6 +317,7 @@ class test_vault_plugin(Declarative):
                           % (vault_name, api.env.basedn),
                     'objectclass': [u'top', u'ipaVault'],
                     'cn': [vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -280,6 +340,7 @@ class test_vault_plugin(Declarative):
                         'dn': u'cn=%s,cn=shared,cn=vaults,cn=kra,%s'
                               % (vault_name, api.env.basedn),
                         'cn': [vault_name],
+                        'ipavaulttype': [u'standard'],
                     },
                 ],
             },
@@ -301,6 +362,7 @@ class test_vault_plugin(Declarative):
                     'dn': u'cn=%s,cn=shared,cn=vaults,cn=kra,%s'
                           % (vault_name, api.env.basedn),
                     'cn': [vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -321,6 +383,7 @@ class test_vault_plugin(Declarative):
                 'result': {
                     'cn': [vault_name],
                     'description': [u'Test vault'],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -360,6 +423,7 @@ class test_vault_plugin(Declarative):
                           % (vault_name, user_name, api.env.basedn),
                     'objectclass': [u'top', u'ipaVault'],
                     'cn': [vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -382,6 +446,7 @@ class test_vault_plugin(Declarative):
                         'dn': u'cn=%s,cn=%s,cn=users,cn=vaults,cn=kra,%s'
                               % (vault_name, user_name, api.env.basedn),
                         'cn': [vault_name],
+                        'ipavaulttype': [u'standard'],
                     },
                 ],
             },
@@ -403,6 +468,7 @@ class test_vault_plugin(Declarative):
                     'dn': u'cn=%s,cn=%s,cn=users,cn=vaults,cn=kra,%s'
                           % (vault_name, user_name, api.env.basedn),
                     'cn': [vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -423,6 +489,7 @@ class test_vault_plugin(Declarative):
                 'result': {
                     'cn': [vault_name],
                     'description': [u'Test vault'],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
@@ -446,50 +513,53 @@ class test_vault_plugin(Declarative):
         },
 
         {
-            'desc': 'Create vault for archival',
+            'desc': 'Create standard vault',
             'command': (
                 'vault_add',
-                [vault_name],
+                [standard_vault_name],
                 {},
             ),
             'expected': {
-                'value': vault_name,
-                'summary': 'Added vault "%s"' % vault_name,
+                'value': standard_vault_name,
+                'summary': 'Added vault "%s"' % standard_vault_name,
                 'result': {
-                    'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,%s'
-                          % (vault_name, api.env.basedn),
+                    'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,cn=kra,%s'
+                          % (standard_vault_name, api.env.basedn),
                     'objectclass': [u'top', u'ipaVault'],
-                    'cn': [vault_name],
+                    'cn': [standard_vault_name],
+                    'ipavaulttype': [u'standard'],
                 },
             },
         },
 
         {
-            'desc': 'Archive secret',
+            'desc': 'Archive secret into standard vault',
             'command': (
                 'vault_archive',
-                [vault_name],
+                [standard_vault_name],
                 {
                     'data': secret,
                 },
             ),
             'expected': {
-                'value': vault_name,
-                'summary': 'Archived data into vault "%s"' % vault_name,
+                'value': standard_vault_name,
+                'summary': 'Archived data into vault "%s"'
+                           % standard_vault_name,
                 'result': {},
             },
         },
 
         {
-            'desc': 'Retrieve secret',
+            'desc': 'Retrieve secret from standard vault',
             'command': (
                 'vault_retrieve',
-                [vault_name],
+                [standard_vault_name],
                 {},
             ),
             'expected': {
-                'value': vault_name,
-                'summary': 'Retrieved data from vault "%s"' % vault_name,
+                'value': standard_vault_name,
+                'summary': 'Retrieved data from vault "%s"'
+                           % standard_vault_name,
                 'result': {
                     'data': secret,
                 },
@@ -497,17 +567,122 @@ class test_vault_plugin(Declarative):
         },
 
         {
-            'desc': 'Delete vault for archival',
+            'desc': 'Create symmetric vault',
             'command': (
-                'vault_del',
-                [vault_name],
-                {},
+                'vault_add',
+                [symmetric_vault_name],
+                {
+                    'ipavaulttype': u'symmetric',
+                    'password': password,
+                },
+            ),
+            'expected': {
+                'value': symmetric_vault_name,
+                'summary': 'Added vault "%s"' % symmetric_vault_name,
+                'result': {
+                    'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,cn=kra,%s'
+                          % (symmetric_vault_name, api.env.basedn),
+                    'objectclass': [u'top', u'ipaVault'],
+                    'cn': [symmetric_vault_name],
+                    'ipavaulttype': [u'symmetric'],
+                    'ipavaultsalt': [fuzzy_string],
+                },
+            },
+        },
+
+        {
+            'desc': 'Archive secret into symmetric vault',
+            'command': (
+                'vault_archive',
+                [symmetric_vault_name],
+                {
+                    'password': password,
+                    'data': secret,
+                },
+            ),
+            'expected': {
+                'value': symmetric_vault_name,
+                'summary': 'Archived data into vault "%s"'
+                           % symmetric_vault_name,
+                'result': {},
+            },
+        },
+
+        {
+            'desc': 'Retrieve secret from symmetric vault',
+            'command': (
+                'vault_retrieve',
+                [symmetric_vault_name],
+                {
+                    'password': password,
+                },
+            ),
+            'expected': {
+                'value': symmetric_vault_name,
+                'summary': 'Retrieved data from vault "%s"'
+                           % symmetric_vault_name,
+                'result': {
+                    'data': secret,
+                },
+            },
+        },
+
+        {
+            'desc': 'Create asymmetric vault',
+            'command': (
+                'vault_add',
+                [asymmetric_vault_name],
+                {
+                    'ipavaulttype': u'asymmetric',
+                    'ipapublickey': public_key,
+                },
+            ),
+            'expected': {
+                'value': asymmetric_vault_name,
+                'summary': 'Added vault "%s"' % asymmetric_vault_name,
+                'result': {
+                    'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,cn=kra,%s'
+                          % (asymmetric_vault_name, api.env.basedn),
+                    'objectclass': [u'top', u'ipaVault'],
+                    'cn': [asymmetric_vault_name],
+                    'ipavaulttype': [u'asymmetric'],
+                    'ipapublickey': [public_key],
+                },
+            },
+        },
+
+        {
+            'desc': 'Archive secret into asymmetric vault',
+            'command': (
+                'vault_archive',
+                [asymmetric_vault_name],
+                {
+                    'data': secret,
+                },
             ),
             'expected': {
-                'value': [vault_name],
-                'summary': u'Deleted vault "%s"' % vault_name,
+                'value': asymmetric_vault_name,
+                'summary': 'Archived data into vault "%s"'
+                           % asymmetric_vault_name,
+                'result': {},
+            },
+        },
+
+        {
+            'desc': 'Retrieve secret from asymmetric vault',
+            'command': (
+                'vault_retrieve',
+                [asymmetric_vault_name],
+                {
+                    'private_key': private_key,
+                },
+            ),
+            'expected': {
+                'value': asymmetric_vault_name,
+                'summary': 'Retrieved data from vault "%s"'
+                           % asymmetric_vault_name,
                 'result': {
-                    'failed': (),
+                    'data': secret,
                 },
             },
         },
-- 
1.9.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