[Freeipa-devel] [PATCH] Password vault

Endi Sukma Dewata edewata at redhat.com
Tue Jun 9 21:13:18 UTC 2015


Please take a look at the attached patch to add symmetric & asymmetric 
vaults. Some comments about the patch:

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.

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?

-- 
Endi S. Dewata
-------------- next part --------------
>From 9cc5b1a22c4545124a13e73343db598d6fb58b2c Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata at 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                   | 507 +++++++++++++++++++++++++++---
 ipatests/test_xmlrpc/test_vault_plugin.py | 218 +++++++++++--
 6 files changed, 717 insertions(+), 70 deletions(-)

diff --git a/API.txt b/API.txt
index 9e3f223b7ac338840d7090299f9108e951ea920a..2ce57fb09293bf3cf1f82f4d0bf4e93b30e0fd60 100644
--- a/API.txt
+++ b/API.txt
@@ -5132,14 +5132,33 @@ 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,12,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('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')
@@ -5147,11 +5166,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)
@@ -5160,11 +5181,14 @@ 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,13,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('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: Bytes('nonce')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Str('service?')
@@ -5188,11 +5212,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?')
@@ -5206,12 +5231,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?')
@@ -5223,10 +5251,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)
@@ -5235,7 +5267,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 535b3e228a3500f2013ea793b19a97d9fbd05021..efc3cf0d105db540680002cf814991f81816a089 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=126
-# Last change: edewata - added vault-archive and vault-retrieve
+IPA_API_VERSION_MINOR=127
+# Last change: edewata - added symmetric and asymmetric vaults
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 23c3d1a8005d36ce253f9979235454ba80c3dbcf..fdf89f98a95e9d2d2818bd2bf5c506df63abcd79 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 e1e64aa40331067e610661142fc7e4c1340a56dd..687e5da6e711ea376cea28d2631eea7626ccf51f 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
+""") + _("""
+ Add an asymmetric vault:
+   ipa vault-add <name> --type asymmetric
+""") + _("""
  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,168 @@ class vault(LDAPObject):
 
         return 'ipa:' + id
 
+    def get_password(self):
+        """
+        Gets 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'),
+        ),
+        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')
+        public_key = options.get('ipapublickey')
+        public_key_file = options.get('public_key_file')
+
+        # don't send these parameters to server
+        if 'ipapublickey' in options:
+            del options['ipapublickey']
+        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':
+
+            # 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()
+
+            else:
+                raise errors.ValidationError(
+                    name='ipapublickey',
+                    error=_('Missing vault public key'))
+
+            # store vault public key
+            options['ipapublickey'] = public_key
+
+        return self.api.Command.vault_add_internal(*args, **options)
+
+
+ at register()
+class vault_add_internal(LDAPCreate):
+
+    NO_CLI = True
+
+    takes_options = vault_options
 
     msg_summary = _('Added vault "%(value)s"')
 
@@ -513,29 +756,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 +809,69 @@ 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':
+
+            salt = vault['ipavaultsalt'][0]
+
+            # 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_password()
+
+            # 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 +895,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 +915,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(Update):
+
     NO_CLI = True
 
     takes_options = vault_options + (
@@ -622,6 +938,8 @@ class vault_archive_encrypted(Update):
         ),
     )
 
+    msg_summary = _('Archived data into vault "%(value)s"')
+
     def execute(self, *args, **options):
 
         if not self.api.env.enable_kra:
@@ -633,8 +951,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 +983,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 +1002,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 +1032,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 +1062,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 +1091,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 +1113,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_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(Retrieve):
+
     NO_CLI = True
 
     takes_options = vault_options + (
@@ -772,6 +1201,8 @@ class vault_retrieve_encrypted(Retrieve):
         ),
     )
 
+    msg_summary = _('Retrieved data from vault "%(value)s"')
+
     def execute(self, *args, **options):
 
         if not self.api.env.enable_kra:
@@ -781,8 +1212,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,9 +1237,16 @@ 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
diff --git a/ipatests/test_xmlrpc/test_vault_plugin.py b/ipatests/test_xmlrpc/test_vault_plugin.py
index 4b18672c102e9d1cc5513b159c4f903a711da3f4..d68d06f4b5d7634b48ff5672ece41ed50d69e089 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,%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,%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,%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,%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,%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,%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,%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,%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),
+                          % (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,121 @@ 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',
+                },
+            ),
+            'expected': {
+                'value': symmetric_vault_name,
+                'summary': 'Added vault "%s"' % symmetric_vault_name,
+                'result': {
+                    'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,%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': [vault_name],
-                'summary': u'Deleted vault "%s"' % vault_name,
+                'value': asymmetric_vault_name,
+                'summary': 'Added vault "%s"' % asymmetric_vault_name,
                 'result': {
-                    'failed': (),
+                    'dn': u'cn=%s,cn=admin,cn=users,cn=vaults,%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': 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': {
+                    'data': secret,
                 },
             },
         },
-- 
1.9.3



More information about the Freeipa-devel mailing list