The vault-mod command has been modified to support changing vault encryption attributes (i.e. type, password, public/private keys) in addition to normal attributes (i.e. description). Changing the encryption requires retrieving the stored secret with the old attributes and rearchieving it with the new attributes.
https://fedorahosted.org/freeipa/ticket/5176 -- Endi S. Dewata
From e80928fa8e8a099576fcdbff08fd90a634600825 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" <[email protected]> Date: Fri, 31 Jul 2015 07:53:15 +0200 Subject: [PATCH] Added support for changing vault encryption. The vault-mod command has been modified to support changing vault encryption attributes (i.e. type, password, public/private keys) in addition to normal attributes (i.e. description). Changing the encryption requires retrieving the stored secret with the old attributes and rearchieving it with the new attributes. https://fedorahosted.org/freeipa/ticket/5176 --- API.txt | 27 +++++- VERSION | 4 +- ipalib/plugins/vault.py | 239 ++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 248 insertions(+), 22 deletions(-) diff --git a/API.txt b/API.txt index 00b47b8709c81217d7f2a69e719093f4a04f1734..bd5c48998056ab94729cb1b475bf444707a883cb 100644 --- a/API.txt +++ b/API.txt @@ -5466,11 +5466,12 @@ output: Output('completed', <type 'int'>, None) output: Output('failed', <type 'dict'>, None) output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) command: vault_archive -args: 1,10,3 +args: 1,11,3 arg: Str('cn', attribute=True, cli_name='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: Flag('override_password?', autofill=True, default=False) 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') @@ -5528,6 +5529,30 @@ 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,18,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: Flag('change_password?', autofill=True, default=False) +option: Str('description?', cli_name='desc') +option: Bytes('ipavaultsalt?', cli_name='salt') +option: Str('ipavaulttype?', cli_name='type') +option: Str('new_password?', cli_name='new_password') +option: Str('new_password_file?', cli_name='new_password_file') +option: Str('old_password?', cli_name='old_password') +option: Str('old_password_file?', cli_name='old_password_file') +option: Bytes('private_key?', cli_name='private_key') +option: Str('private_key_file?', cli_name='private_key_file') +option: Bytes('public_key?', cli_name='public_key') +option: Str('public_key_file?', cli_name='public_key_file') +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +option: Str('servicename?', cli_name='service') +option: Flag('shared?', autofill=True, default=False) +option: Str('username?', cli_name='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_mod_internal args: 1,15,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') diff --git a/VERSION b/VERSION index c42bea06522dae55e1a89ff94ae394594086b467..feb9f4db92c7c7b95e9e5d5907b1f97e96b26886 100644 --- a/VERSION +++ b/VERSION @@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=149 -# Last change: edewata - Added CLI param and ACL for vault service operations +IPA_API_VERSION_MINOR=150 +# Last change: edewata - Added support for changing vault encryption. diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py index 3b62822366a62c90f843a6293589c28383e782ef..5bee6aaae8ddd306d4ee0c273143c9d0ffc913d5 100644 --- a/ipalib/plugins/vault.py +++ b/ipalib/plugins/vault.py @@ -133,19 +133,36 @@ EXAMPLES: ipa vault-show <name> --shared """) + _(""" Show a user vault: - ipa vault-show <name> --user <username> + ipa vault-show <name> """) + _(""" - Modify a private vault: - ipa vault-mod <name> --desc <description> + Modify vault description: + ipa vault-mod <name> + [--user <username>|--service <service name>|--shared] + --desc <description> """) + _(""" - Modify a service vault: - ipa vault-mod <name> --service <service name> --desc <description> + Modify vault type: + ipa vault-mod <name> + [--user <username>|--service <service name>|--shared] + --type <type> """) + _(""" - Modify a shared vault: - ipa vault-mod <name> --shared --desc <description> + Modify vault password: + ipa vault-mod <name> + [--user <username>|--service <service name>|--shared] + --change-password + ipa vault-mod <name> + [--user <username>|--service <service name>|--shared] + --old-password <old password> + --new-password <new password> + ipa vault-mod <name> + [--user <username>|--service <service name>|--shared] + --old-password-file <old password file> + --new-password-file <new password file> """) + _(""" - Modify a user vault: - ipa vault-mod <name> --user <username> --desc <description> + Modify vault keys: + ipa vault-mod <name> + [--user <username>|--service <service name>|--shared] + --private-key-file <old private key file> + --public-key-file <new public key file> """) + _(""" Delete a private vault: ipa vault-del <name> @@ -478,7 +495,7 @@ class vault(LDAPObject): print ' ** Passwords do not match! **' - def get_existing_password(self, new=False): + def get_existing_password(self): """ Gets existing password from user. """ @@ -818,9 +835,183 @@ class vault_find(LDAPSearch): @register() -class vault_mod(LDAPUpdate): +class vault_mod(PKQuery, Local): __doc__ = _('Modify a vault.') + takes_options = vault_options + ( + Str( + 'description?', + cli_name='desc', + doc=_('Vault description'), + ), + Str( + 'ipavaulttype?', + cli_name='type', + doc=_('Vault type'), + ), + Bytes( + 'ipavaultsalt?', + cli_name='salt', + doc=_('Vault salt'), + ), + Flag( + 'change_password?', + doc=_('Change password'), + ), + Str( + 'old_password?', + cli_name='old_password', + doc=_('Old vault password'), + ), + Str( # TODO: use File parameter + 'old_password_file?', + cli_name='old_password_file', + doc=_('File containing the old vault password'), + ), + Str( + 'new_password?', + cli_name='new_password', + doc=_('New vault password'), + ), + Str( # TODO: use File parameter + 'new_password_file?', + cli_name='new_password_file', + doc=_('File containing the new vault password'), + ), + Bytes( + 'private_key?', + cli_name='private_key', + doc=_('Old vault private key'), + ), + Str( # TODO: use File parameter + 'private_key_file?', + cli_name='private_key_file', + doc=_('File containing the old vault private key'), + ), + Bytes( + 'public_key?', + cli_name='public_key', + doc=_('New vault public key'), + ), + Str( # TODO: use File parameter + 'public_key_file?', + cli_name='public_key_file', + doc=_('File containing the new vault public key'), + ), + ) + + has_output = output.standard_entry + + def forward(self, *args, **options): + + vault_type = options.pop('ipavaulttype', False) + salt = options.pop('ipavaultsalt', False) + change_password = options.pop('change_password', False) + + old_password = options.pop('old_password', None) + old_password_file = options.pop('old_password_file', None) + new_password = options.pop('new_password', None) + new_password_file = options.pop('new_password_file', None) + + old_private_key = options.pop('private_key', None) + old_private_key_file = options.pop('private_key_file', None) + new_public_key = options.pop('public_key', None) + new_public_key_file = options.pop('public_key_file', None) + + 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()) + + # determine the vault type based on parameters specified + if vault_type: + pass + + elif change_password or \ + new_password or new_password_file or salt: + vault_type = u'symmetric' + + elif new_public_key or new_public_key_file: + vault_type = u'asymmetric' + + # if vault type is specified, retrieve existing secret + if vault_type: + opts = options.copy() + opts.pop('description', None) + + opts['password'] = old_password + opts['password_file'] = old_password_file + opts['private_key'] = old_private_key + opts['private_key_file'] = old_private_key_file + + response = self.api.Command.vault_retrieve(*args, **opts) + data = response['result']['data'] + + opts = options.copy() + + # if vault type is specified, update crypto attributes + if vault_type: + opts['ipavaulttype'] = vault_type + + if vault_type == u'standard': + opts['ipavaultsalt'] = None + opts['ipavaultpublickey'] = None + + elif vault_type == u'symmetric': + if salt: + opts['ipavaultsalt'] = salt + else: + opts['ipavaultsalt'] = os.urandom(16) + + opts['ipavaultpublickey'] = None + + elif vault_type == u'asymmetric': + + # get new vault public key + if new_public_key and new_public_key_file: + raise errors.MutuallyExclusiveError( + reason=_('New public key specified multiple times')) + + elif new_public_key: + pass + + elif new_public_key_file: + new_public_key = validated_read('public_key_file', + new_public_key_file, + mode='rb') + + else: + raise errors.ValidationError( + name='ipavaultpublickey', + error=_('Missing new vault public key')) + + opts['ipavaultsalt'] = None + opts['ipavaultpublickey'] = new_public_key + + response = self.api.Command.vault_mod_internal(*args, **opts) + + # if vault type is specified, rearchive existing secret + if vault_type: + opts = options.copy() + opts.pop('description', None) + + opts['data'] = data + opts['password'] = new_password + opts['password_file'] = new_password_file + opts['override_password'] = True + + self.api.Command.vault_archive(*args, **opts) + + return response + + +@register() +class vault_mod_internal(LDAPUpdate): + + NO_CLI = True + takes_options = LDAPUpdate.takes_options + vault_options msg_summary = _('Modified vault "%(value)s"') @@ -933,6 +1124,10 @@ class vault_archive(PKQuery, Local): cli_name='password_file', doc=_('File containing the vault password'), ), + Flag( + 'override_password?', + doc=_('Override existing password'), + ), ) has_output = output.standard_entry @@ -947,6 +1142,8 @@ class vault_archive(PKQuery, Local): password = options.get('password') password_file = options.get('password_file') + override_password = options.pop('override_password', False) + # don't send these parameters to server if 'data' in options: del options['data'] @@ -1001,15 +1198,19 @@ class vault_archive(PKQuery, Local): password = password.rstrip('\n') else: - password = self.obj.get_existing_password() + if override_password: + password = self.obj.get_new_password() + 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 + if not override_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] -- 2.4.3
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code
