def get_secret(self, secret_metadata, context): """Retrieve a secret. :param secret_metadata: secret metadata :param context: StoreCryptoContext for secret :returns: SecretDTO that contains secret """ if (not context.secret_model or not context.secret_model.encrypted_data): raise sstore.SecretNotFoundException() # TODO(john-wood-w) Need to revisit 1 to many datum relationship. datum_model = context.secret_model.encrypted_data[0] # Find HSM-style 'crypto' plugin. decrypting_plugin = manager.get_manager().get_plugin_retrieve( datum_model.kek_meta_project.plugin_name) # wrap the KEKDatum instance in our DTO kek_meta_dto = crypto.KEKMetaDTO(datum_model.kek_meta_project) # Convert from text-based storage format to binary. encrypted = base64.b64decode(datum_model.cypher_text) decrypt_dto = crypto.DecryptDTO(encrypted) # Decrypt the secret. secret = decrypting_plugin.decrypt(decrypt_dto, kek_meta_dto, datum_model.kek_meta_extended, context.project_model.external_id) key_spec = sstore.KeySpec(alg=context.secret_model.algorithm, bit_length=context.secret_model.bit_length, mode=context.secret_model.mode) return sstore.SecretDTO(sstore.SecretType.SYMMETRIC, secret, key_spec, datum_model.content_type)
def test_plugin_created_as_per_mulitple_backend_conf(self): """Check plugins are created as per multiple backend conf""" store_plugin_names = ['store_crypto', 'kmip_plugin', 'store_crypto'] crypto_plugin_names = ['p11_crypto', '', 'simple_crypto'] self.init_via_conf_file(store_plugin_names, crypto_plugin_names, enabled=True) with mock.patch('barbican.plugin.crypto.p11_crypto.P11CryptoPlugin.' '_create_pkcs11') as m_pkcs11, \ mock.patch('kmip.pie.client.ProxyKmipClient') as m_kmip: manager = str.SecretStorePluginManager() # check pkcs11 and kmip plugin instantiation call is invoked m_pkcs11.called_once_with(mock.ANY, mock.ANY) m_kmip.called_once_with(mock.ANY) # check store crypto adapter is matched as its defined first. keySpec = str.KeySpec(str.KeyAlgorithm.AES, 128) plugin_found = manager.get_plugin_store(keySpec) self.assertIsInstance(plugin_found, store_crypto.StoreCryptoAdapterPlugin) # check pkcs11 crypto is matched as its defined first. crypto_plugin = cm.get_manager().get_plugin_store_generate( base.PluginSupportTypes.ENCRYPT_DECRYPT) self.assertIsInstance(crypto_plugin, p11_crypto.P11CryptoPlugin)
def generate_symmetric_key(self, key_spec, context): """Generate a symmetric key. :param key_spec: KeySpec that contains details on the type of key to generate :param context: StoreCryptoContext for secret :returns: a dictionary that contains metadata about the key """ # Find HSM-style 'crypto' plugin. plugin_type = _determine_generation_type(key_spec.alg) if crypto.PluginSupportTypes.SYMMETRIC_KEY_GENERATION != plugin_type: raise sstore.SecretAlgorithmNotSupportedException(key_spec.alg) generating_plugin = manager.get_manager().get_plugin_store_generate( plugin_type, key_spec.alg, key_spec.bit_length, key_spec.mode) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( generating_plugin, context.project_model) # Create an encrypted datum instance and add the created cypher text. generate_dto = crypto.GenerateDTO(key_spec.alg, key_spec.bit_length, key_spec.mode, None) # Create the encrypted meta. response_dto = generating_plugin.generate_symmetric( generate_dto, kek_meta_dto, context.project_model.external_id) # Convert binary data into a text-based format. _store_secret_and_datum(context, context.secret_model, kek_datum_model, response_dto) return None
def update_policy(self, data, project_id): policy_type = data['policy'] attribute = data['attribute'] enc_keys = _get_enc_keys(project_id) if enc_keys: encrypting_plugin = manager.get_manager( ).get_plugin_store_generate( crypto.PluginSupportTypes.ENCRYPT_DECRYPT) response = _get_project_policy(project_id) if response: mk_mr_e = response['attribute'] mk_attribute = None try: mk_attribute = encrypting_plugin.mk_encrypt( enc_keys, attribute, project_id, mk_mr_e) except Exception as e: return { 'status': 'Unable to decrypt with valid Session Key of this project. Unauthorized to update policy.' } else: mk_attribute = encrypting_plugin.mk_encrypt( enc_keys, attribute, project_id, None) _store_project_policy(project_id, policy_type, mk_attribute) else: return { 'status': 'Session key not yet provisioned for this project. Please perform Remote/Mutual Attestation first.' } return {'status': 'OK'}
def store_secret(self, secret_dto, context): """Store a secret. :param secret_dto: SecretDTO for secret :param context: StoreCryptoContext for secret :returns: an optional dictionary containing metadata about the secret """ # Find HSM-style 'crypto' plugin. encrypting_plugin = manager.get_manager().get_plugin_store_generate( crypto.PluginSupportTypes.ENCRYPT_DECRYPT) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( encrypting_plugin, context.project_model) # Secrets are base64 encoded before being passed to the secret stores. secret_bytes = base64.b64decode(secret_dto.secret) encrypt_dto = crypto.EncryptDTO(secret_bytes) # Enhance the context with content_type, This is needed to build # datum_model to store if not context.content_type: context.content_type = secret_dto.content_type # Create an encrypted datum instance and add the encrypted cyphertext. response_dto = encrypting_plugin.encrypt( encrypt_dto, kek_meta_dto, context.project_model.external_id) # Convert binary data into a text-based format. _store_secret_and_datum(context, context.secret_model, kek_datum_model, response_dto) return None
def do_provision_kek(self, data, project_id): encrypting_plugin = manager.get_manager().get_plugin_store_generate( crypto.PluginSupportTypes.ENCRYPT_DECRYPT) enc_keys = _get_enc_keys(project_id) response, output = encrypting_plugin.do_provision_kek( data, project_id, enc_keys) if output: _store_enc_keys(project_id, output['sk'], output['mk']) return response
def test_no_preferred_default_plugin(self, dataset): """Check name, plugin and crypto class used for default secret store Secret store name is crypto class plugin name if defined otherwise user friendly name is derived from store class plugin name """ self.init_via_conf_file(dataset['store_plugins'], dataset['crypto_plugins'], enabled=True) with mock.patch('barbican.plugin.crypto.p11_crypto.P11CryptoPlugin.' '_create_pkcs11'), \ mock.patch('kmip.pie.client.ProxyKmipClient'): manager = secret_store.SecretStorePluginManager() keySpec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 128) plugin_found = manager.get_plugin_store(keySpec) self.assertIsInstance(plugin_found, dataset['default_store_class']) global_secret_store = multiple_backends.\ get_global_default_secret_store() if dataset['default_crypto_class']: crypto_plugin = cm.get_manager().get_plugin_store_generate( base.PluginSupportTypes.ENCRYPT_DECRYPT) self.assertIsInstance(crypto_plugin, dataset['default_crypto_class']) # make sure secret store name is same as crypto class friendly name # as store_plugin class is not direct impl of SecretStoreBase self.assertEqual(global_secret_store.name, crypto_plugin.get_plugin_name()) else: # crypto class is not used # make sure secret store name is same as store plugin class # friendly name self.assertEqual(global_secret_store.name, plugin_found.get_plugin_name()) # error raised for no crypto plugin self.assertRaises(base.CryptoPluginNotFound, cm.get_manager().get_plugin_store_generate, base.PluginSupportTypes.ENCRYPT_DECRYPT)
def setUp(self): super(WhenTestingManager, self).setUp() self.plugin_returned = mock.MagicMock() self.plugin_type = crypto.PluginSupportTypes.ENCRYPT_DECRYPT self.plugin_returned.supports.return_value = True self.plugin_name = common_utils.generate_fullname_for(self.plugin_returned) self.plugin_loaded = mock.MagicMock(obj=self.plugin_returned) self.manager = cm.get_manager() self.manager.extensions = [self.plugin_loaded]
def test_can_override_enabled_plugins(self): """Verify can override default configuration for plugin selection.""" manager.CONF.set_override("enabled_crypto_plugins", ['foo_plugin'], group='crypto') manager_to_test = manager.get_manager() self.assertIsInstance(manager_to_test, manager._CryptoPluginManager) self.assertListEqual(['foo_plugin'], manager_to_test._names)
def do_attestation(self, data, external_project_id, is_mutual, context): encrypting_plugin = manager.get_manager().get_plugin_store_generate( crypto.PluginSupportTypes.ENCRYPT_DECRYPT) enc_keys = _get_enc_keys(external_project_id) policy_dict = _get_project_policy(external_project_id) response, output = encrypting_plugin.do_attestation( data, external_project_id, enc_keys, is_mutual, policy_dict) if output: _store_enc_keys(external_project_id, output['sk'], output['mk']) return response
def setUp(self): super(WhenTestingManager, self).setUp() self.plugin_returned = mock.MagicMock() self.plugin_type = crypto.PluginSupportTypes.ENCRYPT_DECRYPT self.plugin_returned.supports.return_value = True self.plugin_name = common_utils.generate_fullname_for( self.plugin_returned) self.plugin_loaded = mock.MagicMock(obj=self.plugin_returned) self.manager = cm.get_manager() self.manager.extensions = [self.plugin_loaded]
def generate_asymmetric_key(self, key_spec, context): """Generates an asymmetric key. Returns a AsymmetricKeyMetadataDTO object containing metadata(s) for asymmetric key components. The metadata can be used to retrieve individual components of asymmetric key pair. """ plugin_type = _determine_generation_type(key_spec.alg) if crypto.PluginSupportTypes.ASYMMETRIC_KEY_GENERATION != plugin_type: raise sstore.SecretAlgorithmNotSupportedException(key_spec.alg) generating_plugin = manager.get_manager().get_plugin_store_generate( plugin_type, key_spec.alg, key_spec.bit_length, project_id=context.project_model.id) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( generating_plugin, context.project_model) generate_dto = crypto.GenerateDTO(key_spec.alg, key_spec.bit_length, None, key_spec.passphrase) # Create the encrypted meta. private_key_dto, public_key_dto, passwd_dto = ( generating_plugin.generate_asymmetric( generate_dto, kek_meta_dto, context.project_model.external_id ) ) _store_secret_and_datum( context, context.private_secret_model, kek_datum_model, private_key_dto) _store_secret_and_datum( context, context.public_secret_model, kek_datum_model, public_key_dto) if key_spec.passphrase and passwd_dto: _store_secret_and_datum( context, context.passphrase_secret_model, kek_datum_model, passwd_dto) return sstore.AsymmetricKeyMetadataDTO()
def generate_asymmetric_key(self, key_spec, context): """Generates an asymmetric key. Returns a AsymmetricKeyMetadataDTO object containing metadata(s) for asymmetric key components. The metadata can be used to retrieve individual components of asymmetric key pair. """ plugin_type = _determine_generation_type(key_spec.alg) if base.PluginSupportTypes.ASYMMETRIC_KEY_GENERATION != plugin_type: raise sstore.SecretAlgorithmNotSupportedException(key_spec.alg) generating_plugin = manager.get_manager().get_plugin_store_generate( plugin_type, key_spec.alg, key_spec.bit_length, project_id=context.project_model.id) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( generating_plugin, context.project_model) generate_dto = base.GenerateDTO(key_spec.alg, key_spec.bit_length, None, key_spec.passphrase) # Create the encrypted meta. private_key_dto, public_key_dto, passwd_dto = ( generating_plugin.generate_asymmetric( generate_dto, kek_meta_dto, context.project_model.external_id ) ) _store_secret_and_datum( context, context.private_secret_model, kek_datum_model, private_key_dto) _store_secret_and_datum( context, context.public_secret_model, kek_datum_model, public_key_dto) if key_spec.passphrase and passwd_dto: _store_secret_and_datum( context, context.passphrase_secret_model, kek_datum_model, passwd_dto) return sstore.AsymmetricKeyMetadataDTO()
def test_can_override_enabled_plugins(self): """Verify can override default configuration for plugin selection.""" # Reset manager singleton otherwise we have test execution # order problems cm._PLUGIN_MANAGER = None cm.CONF.set_override("enabled_crypto_plugins", ["foo_plugin"], group="crypto", enforce_type=True) manager_to_test = cm.get_manager() self.assertIsInstance(manager_to_test, cm._CryptoPluginManager) self.assertListEqual(["foo_plugin"], manager_to_test._names)
def test_can_override_enabled_plugins(self): """Verify can override default configuration for plugin selection.""" # Reset manager singleton otherwise we have test execution # order problems cm._PLUGIN_MANAGER = None cm.CONF.set_override("enabled_crypto_plugins", ['foo_plugin'], group='crypto') manager_to_test = cm.get_manager() self.assertIsInstance(manager_to_test, cm._CryptoPluginManager) self.assertListEqual(['foo_plugin'], manager_to_test._names)
def get_secret(self, secret_type, metadata, context): """Retrieve a secret. :param secret_type: secret type :param metadata: secret metadata :param context: StoreCryptoContext for secret :returns: SecretDTO that contains secret """ if (not context.secret_model or not context.secret_model.encrypted_data): raise sstore.SecretNotFoundException() # TODO(john-wood-w) Need to revisit 1 to many datum relationship. datum_model = context.secret_model.encrypted_data[0] # Find HSM-style 'crypto' plugin. decrypting_plugin = manager.get_manager().get_plugin_retrieve( datum_model.kek_meta_project.plugin_name) # wrap the KEKDatum instance in our DTO kek_meta_dto = crypto.KEKMetaDTO(datum_model.kek_meta_project) # Convert from text-based storage format to binary. encrypted = base64.b64decode(datum_model.cypher_text) decrypt_dto = crypto.DecryptDTO(encrypted) # Decrypt the secret. secret = decrypting_plugin.decrypt(decrypt_dto, kek_meta_dto, datum_model.kek_meta_extended, context.project_model.external_id) secret = base64.b64encode(secret) key_spec = sstore.KeySpec(alg=context.secret_model.algorithm, bit_length=context.secret_model.bit_length, mode=context.secret_model.mode) return sstore.SecretDTO(secret_type, secret, key_spec, datum_model.content_type)
def store_secret(self, secret_dto, context): """Store a secret. :param secret_dto: SecretDTO for secret :param context: StoreCryptoContext for secret :returns: an optional dictionary containing metadata about the secret """ # Find HSM-style 'crypto' plugin. encrypting_plugin = manager.get_manager().get_plugin_store_generate( base.PluginSupportTypes.ENCRYPT_DECRYPT, project_id=context.project_model.id ) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( encrypting_plugin, context.project_model) # Secrets are base64 encoded before being passed to the secret stores. secret_bytes = base64.b64decode(secret_dto.secret) encrypt_dto = base.EncryptDTO(secret_bytes) # Enhance the context with content_type, This is needed to build # datum_model to store if not context.content_type: context.content_type = secret_dto.content_type # Create an encrypted datum instance and add the encrypted cyphertext. response_dto = encrypting_plugin.encrypt( encrypt_dto, kek_meta_dto, context.project_model.external_id ) # Convert binary data into a text-based format. _store_secret_and_datum( context, context.secret_model, kek_datum_model, response_dto) return None
def get_policy(self, project_id): response = _get_project_policy(project_id) if response: attribute = response['attribute'] enc_keys = _get_enc_keys(project_id) if enc_keys: sk_attribute = None encrypting_plugin = manager.get_manager( ).get_plugin_store_generate( crypto.PluginSupportTypes.ENCRYPT_DECRYPT) sk_attribute = encrypting_plugin.mk_decrypt( enc_keys, attribute, project_id) response['attribute'] = sk_attribute else: return { 'status': 'Session Key not provisioned for this project. Please perform Remote/Mutual Attestation first' } else: return {'status': 'No Policy set for this project.'} return response
def generate_symmetric_key(self, key_spec, context): """Generate a symmetric key. :param key_spec: KeySpec that contains details on the type of key to generate :param context: StoreCryptoContext for secret :returns: a dictionary that contains metadata about the key """ # Find HSM-style 'crypto' plugin. plugin_type = _determine_generation_type(key_spec.alg) if base.PluginSupportTypes.SYMMETRIC_KEY_GENERATION != plugin_type: raise sstore.SecretAlgorithmNotSupportedException(key_spec.alg) generating_plugin = manager.get_manager().get_plugin_store_generate( plugin_type, key_spec.alg, key_spec.bit_length, key_spec.mode, project_id=context.project_model.id) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( generating_plugin, context.project_model) # Create an encrypted datum instance and add the created cypher text. generate_dto = base.GenerateDTO(key_spec.alg, key_spec.bit_length, key_spec.mode, None) # Create the encrypted meta. response_dto = generating_plugin.generate_symmetric( generate_dto, kek_meta_dto, context.project_model.external_id) # Convert binary data into a text-based format. _store_secret_and_datum( context, context.secret_model, kek_datum_model, response_dto) return None
def sync_secret_stores(secretstore_manager, crypto_manager=None): """Synchronize secret store plugin names between service conf and database This method reads secret and crypto store plugin name from service configuration and then synchronizes corresponding data maintained in database SecretStores table. Any new plugin name(s) added in service configuration is added as a new entry in SecretStores table. If global_default value is changed for existing plugins, then global_default flag is updated to reflect that change in database. If plugin name is removed from service configuration, then removal is possible as long as respective plugin names are NOT set as preferred secret store for a project. If it is used and plugin name is removed, then error is raised. This logic is intended to be invoked at server startup so any error raised here will result in critical failure. """ if not utils.is_multiple_backends_enabled(): return # doing local import to avoid circular dependency between manager and # current utils module from barbican.plugin.crypto import manager as cm secret_stores_repo = db_repos.get_secret_stores_repository() proj_store_repo = db_repos.get_project_secret_store_repository() if crypto_manager is None: crypto_manager = cm.get_manager() def get_friendly_name_dict(ext_manager): """Returns dict of plugin internal name and friendly name entries.""" names_dict = {} for ext in ext_manager.extensions: if ext.obj and hasattr(ext.obj, 'get_plugin_name'): names_dict[ext.name] = ext.obj.get_plugin_name() return names_dict ss_friendly_names = get_friendly_name_dict(secretstore_manager) crypto_friendly_names = get_friendly_name_dict(crypto_manager) # get existing secret stores data from database db_stores = secret_stores_repo.get_all() # read secret store data from service configuration conf_stores = [] for parsed_store in secretstore_manager.parsed_stores: crypto_plugin = parsed_store.crypto_plugin if not crypto_plugin: crypto_plugin = None if crypto_plugin: friendly_name = crypto_friendly_names.get(crypto_plugin) else: friendly_name = ss_friendly_names.get(parsed_store.store_plugin) conf_stores.append(db_models.SecretStores( name=friendly_name, store_plugin=parsed_store.store_plugin, crypto_plugin=crypto_plugin, global_default=parsed_store.global_default)) if db_stores: def fn_match(lh_store, rh_store): return (lh_store.store_plugin == rh_store.store_plugin and lh_store.crypto_plugin == rh_store.crypto_plugin) for conf_store in conf_stores: # find existing db entry for plugin using conf based plugin names db_store_match = next((db_store for db_store in db_stores if fn_match(conf_store, db_store)), None) if db_store_match: # update existing db entry if global default is changed now if db_store_match.global_default != conf_store.global_default: db_store_match.global_default = conf_store.global_default # persist flag change. db_store_match.save() # remove matches store from local list after processing db_stores.remove(db_store_match) else: # new conf entry as no match found in existing entries secret_stores_repo.create_from(conf_store) # entries still present in db list are no longer configured in service # configuration, so try to remove them provided there is no project # is using it as preferred secret store. for db_store in db_stores: if proj_store_repo.get_count_by_secret_store(db_store.id) == 0: secret_stores_repo.delete_entity_by_id(db_store.id, None) else: raise exception.MultipleStorePluginStillInUse(db_store.name) else: # initial setup case when there is no secret stores data in db for conf_store in conf_stores: secret_stores_repo.create_from(conf_store)
def run(self): self.results[self.index] = cm.get_manager()
def test_project_preferred_default_plugin(self, dataset): """Check project preferred behavior with different global default""" self.init_via_conf_file(dataset['store_plugins'], dataset['crypto_plugins'], enabled=True) with mock.patch('barbican.plugin.crypto.p11_crypto.P11CryptoPlugin.' '_create_pkcs11'), \ mock.patch('kmip.pie.client.ProxyKmipClient'): manager = secret_store.SecretStorePluginManager() pkcs11_secret_store = self._get_secret_store_entry('store_crypto', 'p11_crypto') kmip_secret_store = self._get_secret_store_entry('kmip_plugin', None) db_secret_store = self._get_secret_store_entry('store_crypto', 'simple_crypto') project1 = self._create_project() project2 = self._create_project() project3 = self._create_project() # For project1 , make pkcs11 as preferred secret store self._create_project_store(project1.id, pkcs11_secret_store.id) # For project2 , make kmip as preferred secret store self._create_project_store(project2.id, kmip_secret_store.id) # For project3 , make db backend as preferred secret store self._create_project_store(project3.id, db_secret_store.id) keySpec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 128) cm_manager = cm.get_manager() # For project1, verify store and crypto plugin instance used are pkcs11 # specific plugin_found = manager.get_plugin_store(keySpec, project_id=project1.id) self.assertIsInstance(plugin_found, store_crypto.StoreCryptoAdapterPlugin) crypto_plugin = cm.get_manager().get_plugin_store_generate( base.PluginSupportTypes.ENCRYPT_DECRYPT, project_id=project1.id) self.assertIsInstance(crypto_plugin, p11_crypto.P11CryptoPlugin) # For project2, verify store plugin instance is kmip specific # and there is no crypto plugin instance plugin_found = manager.get_plugin_store(keySpec, project_id=project2.id) self.assertIsInstance(plugin_found, kss.KMIPSecretStore) self.assertRaises( base.CryptoPluginNotFound, cm_manager.get_plugin_store_generate, base.PluginSupportTypes.ENCRYPT_DECRYPT, project_id=project2.id) # For project3, verify store and crypto plugin instance used are db # backend specific plugin_found = manager.get_plugin_store(keySpec, project_id=project3.id) self.assertIsInstance(plugin_found, store_crypto.StoreCryptoAdapterPlugin) crypto_plugin = cm.get_manager().get_plugin_store_generate( base.PluginSupportTypes.ENCRYPT_DECRYPT, project_id=project3.id) self.assertIsInstance(crypto_plugin, simple_crypto.SimpleCryptoPlugin) # Make sure for project with no preferred setting, uses global default project4 = self._create_project() plugin_found = manager.get_plugin_store(keySpec, project_id=project4.id) self.assertIsInstance(plugin_found, dataset['default_store_class'])
def do_provision_kek(self, external_project_id): encrypting_plugin = manager.get_manager().get_plugin_store_generate( crypto.PluginSupportTypes.ENCRYPT_DECRYPT) response = encrypting_plugin.do_provision_kek(external_project_id) return response
def sync_secret_stores(secretstore_manager, crypto_manager=None): """Synchronize secret store plugin names between service conf and database This method reads secret and crypto store plugin name from service configuration and then synchronizes corresponding data maintained in database SecretStores table. Any new plugin name(s) added in service configuration is added as a new entry in SecretStores table. If global_default value is changed for existing plugins, then global_default flag is updated to reflect that change in database. If plugin name is removed from service configuration, then removal is possible as long as respective plugin names are NOT set as preferred secret store for a project. If it is used and plugin name is removed, then error is raised. This logic is intended to be invoked at server startup so any error raised here will result in critical failure. """ if not utils.is_multiple_backends_enabled(): return # doing local import to avoid circular dependency between manager and # current utils module from barbican.plugin.crypto import manager as cm secret_stores_repo = db_repos.get_secret_stores_repository() proj_store_repo = db_repos.get_project_secret_store_repository() if crypto_manager is None: crypto_manager = cm.get_manager() def get_friendly_name_dict(ext_manager): """Returns dict of plugin internal name and friendly name entries.""" names_dict = {} for ext in ext_manager.extensions: if ext.obj and hasattr(ext.obj, 'get_plugin_name'): names_dict[ext.name] = ext.obj.get_plugin_name() return names_dict ss_friendly_names = get_friendly_name_dict(secretstore_manager) crypto_friendly_names = get_friendly_name_dict(crypto_manager) # get existing secret stores data from database db_stores = secret_stores_repo.get_all() # read secret store data from service configuration conf_stores = [] for parsed_store in secretstore_manager.parsed_stores: crypto_plugin = parsed_store.crypto_plugin if not crypto_plugin: crypto_plugin = None if crypto_plugin: friendly_name = crypto_friendly_names.get(crypto_plugin) else: friendly_name = ss_friendly_names.get(parsed_store.store_plugin) conf_stores.append( db_models.SecretStores(name=friendly_name, store_plugin=parsed_store.store_plugin, crypto_plugin=crypto_plugin, global_default=parsed_store.global_default)) if db_stores: def fn_match(lh_store, rh_store): return (lh_store.store_plugin == rh_store.store_plugin and lh_store.crypto_plugin == rh_store.crypto_plugin) for conf_store in conf_stores: # find existing db entry for plugin using conf based plugin names db_store_match = next( (db_store for db_store in db_stores if fn_match(conf_store, db_store)), None) if db_store_match: # update existing db entry if global default is changed now if db_store_match.global_default != conf_store.global_default: db_store_match.global_default = conf_store.global_default # persist flag change. db_store_match.save() # remove matches store from local list after processing db_stores.remove(db_store_match) else: # new conf entry as no match found in existing entries secret_stores_repo.create_from(conf_store) # entries still present in db list are no longer configured in service # configuration, so try to remove them provided there is no project # is using it as preferred secret store. for db_store in db_stores: if proj_store_repo.get_count_by_secret_store(db_store.id) == 0: secret_stores_repo.delete_entity_by_id(db_store.id, None) else: raise exception.MultipleStorePluginStillInUse(db_store.name) else: # initial setup case when there is no secret stores data in db for conf_store in conf_stores: secret_stores_repo.create_from(conf_store)