def put(self, name, kvp): """ Create a new entry or update an existing one. """ # TODO: There is a race, add custom add_or_update which updates by non # id field existing_kvp = self.__get_by_name(name=name) kvp.name = name try: kvp_db = KeyValuePairAPI.to_model(kvp) if existing_kvp: kvp_db.id = existing_kvp.id kvp_db = KeyValuePair.add_or_update(kvp_db) except (ValidationError, ValueError) as e: LOG.exception('Validation failed for key value data=%s', kvp) abort(http_client.BAD_REQUEST, str(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair updated. KeyValuePair.id=%s' % (kvp_db.id), extra=extra) kvp_api = KeyValuePairAPI.from_model(kvp_db) return kvp_api
def put(self, name, kvp): """ Create a new entry or update an existing one. """ lock_name = self._get_lock_name_for_key(name=name) # TODO: Custom permission check since the key doesn't need to exist here # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): existing_kvp = self._get_by_name(resource_name=name) kvp.name = name try: kvp_db = KeyValuePairAPI.to_model(kvp) if existing_kvp: kvp_db.id = existing_kvp.id kvp_db = KeyValuePair.add_or_update(kvp_db) except (ValidationError, ValueError) as e: LOG.exception('Validation failed for key value data=%s', kvp) abort(http_client.BAD_REQUEST, str(e)) return except CryptoKeyNotSetupException as e: LOG.exception(str(e)) abort(http_client.BAD_REQUEST, str(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair updated. KeyValuePair.id=%s' % (kvp_db.id), extra=extra) kvp_api = KeyValuePairAPI.from_model(kvp_db) return kvp_api
def put(self, kvp, name, scope=FULL_SYSTEM_SCOPE): """ Create a new entry or update an existing one. """ if not scope: scope = FULL_SYSTEM_SCOPE requester_user = get_requester() scope = getattr(kvp, 'scope', scope) scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) user = getattr(kvp, 'user', requester_user) or requester_user # Validate that the authenticated user is admin if user query param is provided assert_request_user_is_admin_if_user_query_param_is_provider(request=pecan.request, user=user) key_ref = get_key_reference(scope=scope, name=name, user=user) lock_name = self._get_lock_name_for_key(name=key_ref, scope=scope) LOG.debug('PUT scope: %s, name: %s', scope, name) # TODO: Custom permission check since the key doesn't need to exist here # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): try: existing_kvp_api = self._get_one_by_scope_and_name( scope=scope, name=key_ref ) except StackStormDBObjectNotFoundError: existing_kvp_api = None kvp.name = key_ref kvp.scope = scope try: kvp_db = KeyValuePairAPI.to_model(kvp) if existing_kvp_api: kvp_db.id = existing_kvp_api.id kvp_db = KeyValuePair.add_or_update(kvp_db) except (ValidationError, ValueError) as e: LOG.exception('Validation failed for key value data=%s', kvp) abort(http_client.BAD_REQUEST, str(e)) return except CryptoKeyNotSetupException as e: LOG.exception(str(e)) abort(http_client.BAD_REQUEST, str(e)) return except InvalidScopeException as e: LOG.exception(str(e)) abort(http_client.BAD_REQUEST, str(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair updated. KeyValuePair.id=%s' % (kvp_db.id), extra=extra) kvp_api = KeyValuePairAPI.from_model(kvp_db) return kvp_api
def put(self, name, kvp): """ Create a new entry or update an existing one. """ lock_name = self._get_lock_name_for_key(name=name) # TODO: Custom permission check since the key doesn't need to exist here # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): existing_kvp = self.__get_by_name(name=name) kvp.name = name try: kvp_db = KeyValuePairAPI.to_model(kvp) if existing_kvp: kvp_db.id = existing_kvp.id kvp_db = KeyValuePair.add_or_update(kvp_db) except (ValidationError, ValueError) as e: LOG.exception('Validation failed for key value data=%s', kvp) abort(http_client.BAD_REQUEST, str(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair updated. KeyValuePair.id=%s' % (kvp_db.id), extra=extra) kvp_api = KeyValuePairAPI.from_model(kvp_db) return kvp_api
def put(self, kvp, name, scope=FULL_SYSTEM_SCOPE): """ Create a new entry or update an existing one. """ if not scope: scope = FULL_SYSTEM_SCOPE requester_user = get_requester() scope = getattr(kvp, 'scope', scope) scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) user = getattr(kvp, 'user', requester_user) or requester_user # Validate that the authenticated user is admin if user query param is provided assert_request_user_is_admin_if_user_query_param_is_provided( request=pecan.request, user=user) key_ref = get_key_reference(scope=scope, name=name, user=user) lock_name = self._get_lock_name_for_key(name=key_ref, scope=scope) LOG.debug('PUT scope: %s, name: %s', scope, name) # TODO: Custom permission check since the key doesn't need to exist here # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): try: existing_kvp_api = self._get_one_by_scope_and_name( scope=scope, name=key_ref) except StackStormDBObjectNotFoundError: existing_kvp_api = None kvp.name = key_ref kvp.scope = scope try: kvp_db = KeyValuePairAPI.to_model(kvp) if existing_kvp_api: kvp_db.id = existing_kvp_api.id kvp_db = KeyValuePair.add_or_update(kvp_db) except (ValidationError, ValueError) as e: LOG.exception('Validation failed for key value data=%s', kvp) abort(http_client.BAD_REQUEST, str(e)) return except CryptoKeyNotSetupException as e: LOG.exception(str(e)) abort(http_client.BAD_REQUEST, str(e)) return except InvalidScopeException as e: LOG.exception(str(e)) abort(http_client.BAD_REQUEST, str(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair updated. KeyValuePair.id=%s' % (kvp_db.id), extra=extra) kvp_api = KeyValuePairAPI.from_model(kvp_db) return kvp_api
def setUp(self): super(KeyValuesControllerRBACTestCase, self).setUp() self.kvps = {} # Insert mock users user_1_db = UserDB(name='user1') user_1_db = User.add_or_update(user_1_db) self.users['user_1'] = user_1_db user_2_db = UserDB(name='user2') user_2_db = User.add_or_update(user_2_db) self.users['user_2'] = user_2_db # Insert mock kvp objects kvp_api = KeyValuePairSetAPI(name='test_system_scope', value='value1', scope=FULL_SYSTEM_SCOPE) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_1'] = kvp_db kvp_api = KeyValuePairSetAPI(name='test_system_scope_secret', value='value_secret', scope=FULL_SYSTEM_SCOPE, secret=True) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_2'] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name='test_user_scope_1', user='******') kvp_db = KeyValuePairDB(name=name, value='valueu12', scope=FULL_USER_SCOPE) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_3'] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name='test_user_scope_2', user='******') kvp_api = KeyValuePairSetAPI(name=name, value='user_secret', scope=FULL_USER_SCOPE, secret=True) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_4'] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name='test_user_scope_3', user='******') kvp_db = KeyValuePairDB(name=name, value='valueu21', scope=FULL_USER_SCOPE) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_5'] = kvp_db self.system_scoped_items_count = 2 self.user_scoped_items_count = 3 self.user_scoped_items_per_user_count = { 'user1': 2, 'user2': 1 }
def setUp(self): super(KeyValuesControllerRBACTestCase, self).setUp() self.kvps = {} # Insert mock users user_1_db = UserDB(name="user1") user_1_db = User.add_or_update(user_1_db) self.users["user_1"] = user_1_db user_2_db = UserDB(name="user2") user_2_db = User.add_or_update(user_2_db) self.users["user_2"] = user_2_db # Insert mock kvp objects kvp_api = KeyValuePairSetAPI(name="test_system_scope", value="value1", scope=FULL_SYSTEM_SCOPE) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps["kvp_1"] = kvp_db kvp_api = KeyValuePairSetAPI( name="test_system_scope_secret", value="value_secret", scope=FULL_SYSTEM_SCOPE, secret=True ) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps["kvp_2"] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name="test_user_scope_1", user="******") kvp_db = KeyValuePairDB(name=name, value="valueu12", scope=FULL_USER_SCOPE) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps["kvp_3"] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name="test_user_scope_2", user="******") kvp_api = KeyValuePairSetAPI(name=name, value="user_secret", scope=FULL_USER_SCOPE, secret=True) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps["kvp_4"] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name="test_user_scope_3", user="******") kvp_db = KeyValuePairDB(name=name, value="valueu21", scope=FULL_USER_SCOPE) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps["kvp_5"] = kvp_db self.system_scoped_items_count = 2 self.user_scoped_items_count = 3 self.user_scoped_items_per_user_count = {"user1": 2, "user2": 1}
def set_datastore_value_for_config_key(pack_name, key_name, value, secret=False, user=None): """ Set config value in the datastore. This function takes care of correctly encoding the key name, serializing the value, etc. :param pack_name: Pack name. :type pack_name: ``str`` :param key_name: Config key name. :type key_name: ``str`` :param secret: True if this value is a secret. :type secret: ``bool`` :param user: Optional username if working on a user-scoped config item. :type user: ``str`` :rtype: :class:`KeyValuePairDB` """ if user: scope = FULL_USER_SCOPE else: scope = FULL_SYSTEM_SCOPE name = get_key_reference(scope=scope, name=key_name, user=user) kvp_api = KeyValuePairAPI(name=name, value=value, scope=scope, secret=secret) kvp_db = KeyValuePairAPI.to_model(kvp_api) # TODO: Obtain a lock try: existing_kvp_db = KeyValuePair.get_by_scope_and_name(scope=scope, name=name) except StackStormDBObjectNotFoundError: existing_kvp_db = None if existing_kvp_db: kvp_db.id = existing_kvp_db.id kvp_db = KeyValuePair.add_or_update(kvp_db) return kvp_db
def setUpClass(cls): super(ActionExecutionControllerTestCaseAuthEnabled, cls).setUpClass() cls.action = copy.deepcopy(ACTION_1) headers = { "content-type": "application/json", "X-Auth-Token": str(SYS_TOKEN.token), } post_resp = cls.app.post_json("/v1/actions", cls.action, headers=headers) cls.action["id"] = post_resp.json["id"] cls.action_encrypt = copy.deepcopy(ACTION_DEFAULT_ENCRYPT) post_resp = cls.app.post_json("/v1/actions", cls.action_encrypt, headers=headers) cls.action_encrypt["id"] = post_resp.json["id"] FixturesLoader().save_fixtures_to_db(fixtures_pack=FIXTURES_PACK, fixtures_dict=FIXTURES) # register datastore values which are used in this tests KeyValuePairAPI._setup_crypto() register_items = [ { "name": "secret", "secret": True, "value": crypto_utils.symmetric_encrypt(KeyValuePairAPI.crypto_key, "foo"), }, { "name": "user1:secret", "secret": True, "scope": FULL_USER_SCOPE, "value": crypto_utils.symmetric_encrypt(KeyValuePairAPI.crypto_key, "bar"), }, ] cls.kvps = [ KeyValuePair.add_or_update(KeyValuePairDB(**x)) for x in register_items ]
def setUpClass(cls): super(ActionExecutionControllerTestCaseAuthEnabled, cls).setUpClass() cls.action = copy.deepcopy(ACTION_1) headers = { 'content-type': 'application/json', 'X-Auth-Token': str(SYS_TOKEN.token) } post_resp = cls.app.post_json('/v1/actions', cls.action, headers=headers) cls.action['id'] = post_resp.json['id'] cls.action_encrypt = copy.deepcopy(ACTION_DEFAULT_ENCRYPT) post_resp = cls.app.post_json('/v1/actions', cls.action_encrypt, headers=headers) cls.action_encrypt['id'] = post_resp.json['id'] FixturesLoader().save_fixtures_to_db(fixtures_pack=FIXTURES_PACK, fixtures_dict=FIXTURES) # register datastore values which are used in this tests KeyValuePairAPI._setup_crypto() register_items = [ { 'name': 'secret', 'secret': True, 'value': crypto_utils.symmetric_encrypt(KeyValuePairAPI.crypto_key, 'foo') }, { 'name': 'user1:secret', 'secret': True, 'scope': FULL_USER_SCOPE, 'value': crypto_utils.symmetric_encrypt(KeyValuePairAPI.crypto_key, 'bar') }, ] cls.kvps = [ KeyValuePair.add_or_update(KeyValuePairDB(**x)) for x in register_items ]
def delete(self, name, requester_user, scope=FULL_SYSTEM_SCOPE, user=None): """ Delete the key value pair. Handles requests: DELETE /keys/1 """ if not scope: scope = FULL_SYSTEM_SCOPE if not requester_user: requester_user = UserDB(cfg.CONF.system_user.user) scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) user = user or requester_user.name # Validate that the authenticated user is admin if user query param is provided rbac_utils = get_rbac_backend().get_utils_class() rbac_utils.assert_user_is_admin_if_user_query_param_is_provided( user_db=requester_user, user=user, require_rbac=True) key_ref = get_key_reference(scope=scope, name=name, user=user) lock_name = self._get_lock_name_for_key(name=key_ref, scope=scope) # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): from_model_kwargs = {"mask_secrets": True} kvp_api = self._get_one_by_scope_and_name( name=key_ref, scope=scope, from_model_kwargs=from_model_kwargs) kvp_db = KeyValuePairAPI.to_model(kvp_api) LOG.debug( "DELETE /keys/ lookup with scope=%s name=%s found object: %s", scope, name, kvp_db, ) try: KeyValuePair.delete(kvp_db) except Exception as e: LOG.exception( "Database delete encountered exception during " 'delete of name="%s". ', name, ) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e)) return extra = {"kvp_db": kvp_db} LOG.audit("KeyValuePair deleted. KeyValuePair.id=%s" % (kvp_db.id), extra=extra) return Response(status=http_client.NO_CONTENT)
def deserialize_key_value(value, secret=False): """ Deserialize the datastore item value. Note: Right now only strings as supported so only thing this function does is it decrypts secret values. :param value: Value to deserialize. :type value: ``str`` :param secret: True if a value is a secret and is encrypted. :type secret: ``bool`` """ if secret: KeyValuePairAPI._setup_crypto() value = symmetric_decrypt(KeyValuePairAPI.crypto_key, value) return value
def delete(self, name, requester_user, scope=FULL_SYSTEM_SCOPE, user=None): """ Delete the key value pair. Handles requests: DELETE /keys/1 """ if not scope: scope = FULL_SYSTEM_SCOPE if not requester_user: requester_user = UserDB(cfg.CONF.system_user.user) scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) user = user or requester_user.name # Validate that the authenticated user is admin if user query param is provided rbac_utils = get_rbac_backend().get_utils_class() rbac_utils.assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user, user=user, require_rbac=True) key_ref = get_key_reference(scope=scope, name=name, user=user) lock_name = self._get_lock_name_for_key(name=key_ref, scope=scope) # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): from_model_kwargs = {'mask_secrets': True} kvp_api = self._get_one_by_scope_and_name( name=key_ref, scope=scope, from_model_kwargs=from_model_kwargs ) kvp_db = KeyValuePairAPI.to_model(kvp_api) LOG.debug('DELETE /keys/ lookup with scope=%s name=%s found object: %s', scope, name, kvp_db) try: KeyValuePair.delete(kvp_db) except Exception as e: LOG.exception('Database delete encountered exception during ' 'delete of name="%s". ', name) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair deleted. KeyValuePair.id=%s' % (kvp_db.id), extra=extra) return Response(status=http_client.NO_CONTENT)
def setUpClass(cls): super(ActionExecutionControllerTestCaseAuthEnabled, cls).setUpClass() cls.action = copy.deepcopy(ACTION_1) headers = {'content-type': 'application/json', 'X-Auth-Token': str(SYS_TOKEN.token)} post_resp = cls.app.post_json('/v1/actions', cls.action, headers=headers) cls.action['id'] = post_resp.json['id'] cls.action_encrypt = copy.deepcopy(ACTION_DEFAULT_ENCRYPT) post_resp = cls.app.post_json('/v1/actions', cls.action_encrypt, headers=headers) cls.action_encrypt['id'] = post_resp.json['id'] FixturesLoader().save_fixtures_to_db(fixtures_pack=FIXTURES_PACK, fixtures_dict=FIXTURES) # register datastore values which are used in this tests KeyValuePairAPI._setup_crypto() register_items = [ {'name': 'secret', 'secret': True, 'value': crypto_utils.symmetric_encrypt(KeyValuePairAPI.crypto_key, 'foo')}, {'name': 'user1:secret', 'secret': True, 'scope': FULL_USER_SCOPE, 'value': crypto_utils.symmetric_encrypt(KeyValuePairAPI.crypto_key, 'bar')}, ] cls.kvps = [KeyValuePair.add_or_update(KeyValuePairDB(**x)) for x in register_items]
def delete(self, name, scope=FULL_SYSTEM_SCOPE, user=None): """ Delete the key value pair. Handles requests: DELETE /keys/1 """ if not scope: scope = FULL_SYSTEM_SCOPE scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) requester_user = get_requester() user = user or requester_user # Validate that the authenticated user is admin if user query param is provided assert_request_user_is_admin_if_user_query_param_is_provider(request=pecan.request, user=user) key_ref = get_key_reference(scope=scope, name=name, user=user) lock_name = self._get_lock_name_for_key(name=key_ref, scope=scope) # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): from_model_kwargs = {'mask_secrets': True} kvp_api = self._get_one_by_scope_and_name( name=key_ref, scope=scope, from_model_kwargs=from_model_kwargs ) kvp_db = KeyValuePairAPI.to_model(kvp_api) LOG.debug('DELETE /keys/ lookup with scope=%s name=%s found object: %s', scope, name, kvp_db) try: KeyValuePair.delete(kvp_db) except Exception as e: LOG.exception('Database delete encountered exception during ' 'delete of name="%s". ', name) abort(http_client.INTERNAL_SERVER_ERROR, str(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair deleted. KeyValuePair.id=%s' % (kvp_db.id), extra=extra)
def delete(self, name, scope=FULL_SYSTEM_SCOPE, user=None): """ Delete the key value pair. Handles requests: DELETE /keys/1 """ if not scope: scope = FULL_SYSTEM_SCOPE scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) requester_user = get_requester() user = user or requester_user # Validate that the authenticated user is admin if user query param is provided assert_request_user_is_admin_if_user_query_param_is_provided( request=pecan.request, user=user) key_ref = get_key_reference(scope=scope, name=name, user=user) lock_name = self._get_lock_name_for_key(name=key_ref, scope=scope) # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): from_model_kwargs = {'mask_secrets': True} kvp_api = self._get_one_by_scope_and_name( name=key_ref, scope=scope, from_model_kwargs=from_model_kwargs) kvp_db = KeyValuePairAPI.to_model(kvp_api) LOG.debug( 'DELETE /keys/ lookup with scope=%s name=%s found object: %s', scope, name, kvp_db) try: KeyValuePair.delete(kvp_db) except Exception as e: LOG.exception( 'Database delete encountered exception during ' 'delete of name="%s". ', name) abort(http_client.INTERNAL_SERVER_ERROR, str(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair deleted. KeyValuePair.id=%s' % (kvp_db.id), extra=extra)
def get_all(self, **kw): """ List all keys. Handles requests: GET /keys/ """ # Prefix filtering prefix_filter = kw.get('prefix', None) if prefix_filter: kw['name__startswith'] = prefix_filter del kw['prefix'] kvp_dbs = KeyValuePair.get_all(**kw) kvps = [KeyValuePairAPI.from_model(kvp_db) for kvp_db in kvp_dbs] return kvps
def get_one(self, name): """ List key by name. Handle: GET /keys/key1 """ kvp_db = self.__get_by_name(name=name) if not kvp_db: LOG.exception('Database lookup for name="%s" resulted in exception.', name) abort(http_client.NOT_FOUND) return try: kvp_api = KeyValuePairAPI.from_model(kvp_db) except (ValidationError, ValueError) as e: abort(http_client.INTERNAL_SERVER_ERROR, str(e)) return return kvp_api
def set_datastore_value_for_config_key(pack_name, key_name, value, secret=False, user=None): """ Set config value in the datastore. This function takes care of correctly encoding the key name, serializing the value, etc. :param pack_name: Pack name. :type pack_name: ``str`` :param key_name: Config key name. :type key_name: ``str`` :param secret: True if this value is a secret. :type secret: ``bool`` :param user: Optional username if working on a user-scoped config item. :type user: ``str`` :rtype: :class:`KeyValuePairDB` """ if user: scope = USER_SCOPE else: scope = SYSTEM_SCOPE name = get_key_reference(scope=scope, name=key_name, user=user) kvp_api = KeyValuePairAPI(name=name, value=value, scope=scope, secret=secret) kvp_db = KeyValuePairAPI.to_model(kvp_api) # TODO: Obtain a lock existing_kvp_db = KeyValuePair.get_by_scope_and_name(scope=scope, name=name) if existing_kvp_db: kvp_db.id = existing_kvp_db.id kvp_db = KeyValuePair.add_or_update(kvp_db) return kvp_db
def delete(self, name, requester_user, scope=None, user=None): """ Delete the key value pair. Handles requests: DELETE /keys/1 """ if not scope or scope == ALL_SCOPE: # Default to system scope scope = FULL_SYSTEM_SCOPE if not requester_user: requester_user = UserDB(name=cfg.CONF.system_user.user) scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) user = user or requester_user.name rbac_utils = get_rbac_backend().get_utils_class() # Validate that the authenticated user is admin if user query param is provided rbac_utils.assert_user_is_admin_if_user_query_param_is_provided( user_db=requester_user, user=user, require_rbac=True) # Set key reference for system or user scope key_ref = get_key_reference(scope=scope, name=name, user=user) extra = { "scope": scope, "name": name, "user": user, "key_ref": key_ref } LOG.debug("DELETE /v1/keys/%s", name, extra=extra) # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( uid="%s:%s:%s" % (ResourceType.KEY_VALUE_PAIR, scope, key_ref), scope=scope, name=key_ref, ) # Check that user has permission to the key value pair. # If RBAC is enabled, this check will verify if user has system role with all access. # If RBAC is enabled, this check guards against a user accessing another user's kvp. # If RBAC is enabled, user needs to be explicitly granted permission to delete a system kvp. # The check is sufficient to allow decryption of the system kvp. rbac_utils.assert_user_has_resource_db_permission( user_db=requester_user, resource_db=kvp_db, permission_type=PermissionType.KEY_VALUE_PAIR_DELETE, ) # Acquire a lock to avoid race condition between concurrent API calls with self._coordinator.get_lock( self._get_lock_name_for_key(name=key_ref, scope=scope)): from_model_kwargs = {"mask_secrets": True} kvp_api = self._get_one_by_scope_and_name( name=key_ref, scope=scope, from_model_kwargs=from_model_kwargs) kvp_db = KeyValuePairAPI.to_model(kvp_api) extra["kvp_db"] = kvp_db LOG.debug("DELETE /v1/keys/%s", name, extra=extra) try: KeyValuePair.delete(kvp_db) except Exception as e: LOG.exception( "Database delete encountered exception during " 'delete of name="%s". ', name, ) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e)) return LOG.audit("DELETE /v1/keys/%s succeeded id=%s", name, kvp_db.id, extra=extra) return Response(status=http_client.NO_CONTENT)
def setUp(self): super(KeyValuesControllerRBACTestCase, self).setUp() self.kvps = {} # Insert mock users user_1_db = UserDB(name='user1') user_1_db = User.add_or_update(user_1_db) self.users['user_1'] = user_1_db user_2_db = UserDB(name='user2') user_2_db = User.add_or_update(user_2_db) self.users['user_2'] = user_2_db # Insert mock kvp objects kvp_api = KeyValuePairSetAPI(name='test_system_scope', value='value1', scope=FULL_SYSTEM_SCOPE) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_1'] = kvp_db kvp_api = KeyValuePairSetAPI(name='test_system_scope_secret', value='value_secret', scope=FULL_SYSTEM_SCOPE, secret=True) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_2'] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name='test_user_scope_1', user='******') kvp_db = KeyValuePairDB(name=name, value='valueu12', scope=FULL_USER_SCOPE) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_3'] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name='test_user_scope_2', user='******') kvp_api = KeyValuePairSetAPI(name=name, value='user_secret', scope=FULL_USER_SCOPE, secret=True) kvp_db = KeyValuePairSetAPI.to_model(kvp_api) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_4'] = kvp_db name = get_key_reference(scope=FULL_USER_SCOPE, name='test_user_scope_3', user='******') kvp_db = KeyValuePairDB(name=name, value='valueu21', scope=FULL_USER_SCOPE) kvp_db = KeyValuePair.add_or_update(kvp_db) kvp_db = KeyValuePairAPI.from_model(kvp_db) self.kvps['kvp_5'] = kvp_db self.system_scoped_items_count = 2 self.user_scoped_items_count = 3 self.user_scoped_items_per_user_count = {'user1': 2, 'user2': 1}
def put(self, kvp, name, requester_user, scope=FULL_SYSTEM_SCOPE): """ Create a new entry or update an existing one. """ if not scope: scope = FULL_SYSTEM_SCOPE if not requester_user: requester_user = UserDB(cfg.CONF.system_user.user) scope = getattr(kvp, 'scope', scope) scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) user = getattr(kvp, 'user', requester_user.name) or requester_user.name # Validate that the authenticated user is admin if user query param is provided assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user, user=user, require_rbac=True) # Validate that encrypted option can only be used by admins encrypted = getattr(kvp, 'encrypted', False) self._validate_encrypted_query_parameter(encrypted=encrypted, scope=scope, requester_user=requester_user) key_ref = get_key_reference(scope=scope, name=name, user=user) lock_name = self._get_lock_name_for_key(name=key_ref, scope=scope) LOG.debug('PUT scope: %s, name: %s', scope, name) # TODO: Custom permission check since the key doesn't need to exist here # Note: We use lock to avoid a race with self._coordinator.get_lock(lock_name): try: existing_kvp_api = self._get_one_by_scope_and_name( scope=scope, name=key_ref ) except StackStormDBObjectNotFoundError: existing_kvp_api = None # st2client sends invalid id when initially setting a key so we ignore those id_ = kvp.__dict__.get('id', None) if not existing_kvp_api and id_ and not bson.ObjectId.is_valid(id_): del kvp.__dict__['id'] kvp.name = key_ref kvp.scope = scope try: kvp_db = KeyValuePairAPI.to_model(kvp) if existing_kvp_api: kvp_db.id = existing_kvp_api.id kvp_db = KeyValuePair.add_or_update(kvp_db) except (ValidationError, ValueError) as e: LOG.exception('Validation failed for key value data=%s', kvp) abort(http_client.BAD_REQUEST, six.text_type(e)) return except CryptoKeyNotSetupException as e: LOG.exception(six.text_type(e)) abort(http_client.BAD_REQUEST, six.text_type(e)) return except InvalidScopeException as e: LOG.exception(six.text_type(e)) abort(http_client.BAD_REQUEST, six.text_type(e)) return extra = {'kvp_db': kvp_db} LOG.audit('KeyValuePair updated. KeyValuePair.id=%s' % (kvp_db.id), extra=extra) kvp_api = KeyValuePairAPI.from_model(kvp_db) return kvp_api
def put(self, kvp, name, requester_user, scope=None): """ Create a new entry or update an existing one. """ if not scope or scope == ALL_SCOPE: # Default to system scope scope = FULL_SYSTEM_SCOPE if not requester_user: requester_user = UserDB(name=cfg.CONF.system_user.user) scope = getattr(kvp, "scope", scope) scope = get_datastore_full_scope(scope) self._validate_scope(scope=scope) user = getattr(kvp, "user", requester_user.name) or requester_user.name rbac_utils = get_rbac_backend().get_utils_class() # Validate that the authenticated user is admin if user query param is provided rbac_utils.assert_user_is_admin_if_user_query_param_is_provided( user_db=requester_user, user=user, require_rbac=True) # Set key reference for system or user scope key_ref = get_key_reference(scope=scope, name=name, user=user) extra = { "scope": scope, "name": name, "user": user, "key_ref": key_ref } LOG.debug("PUT /v1/keys/%s", name, extra=extra) # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( uid="%s:%s:%s" % (ResourceType.KEY_VALUE_PAIR, scope, key_ref), scope=scope, name=key_ref, ) # Check that user has permission to the key value pair. # If RBAC is enabled, this check will verify if user has system role with all access. # If RBAC is enabled, this check guards against a user accessing another user's kvp. # If RBAC is enabled, user needs to be explicitly granted permission to set a system kvp. # The check is sufficient to allow decryption of the system kvp. rbac_utils.assert_user_has_resource_db_permission( user_db=requester_user, resource_db=kvp_db, permission_type=PermissionType.KEY_VALUE_PAIR_SET, ) # Validate that the pre-encrypted option can only be used by admins encrypted = getattr(kvp, "encrypted", False) self._validate_encrypted_query_parameter(encrypted=encrypted, scope=scope, requester_user=requester_user) # Acquire a lock to avoid race condition between concurrent API calls with self._coordinator.get_lock( self._get_lock_name_for_key(name=key_ref, scope=scope)): try: existing_kvp_api = self._get_one_by_scope_and_name( scope=scope, name=key_ref) except StackStormDBObjectNotFoundError: existing_kvp_api = None # st2client sends invalid id when initially setting a key so we ignore those id_ = kvp.__dict__.get("id", None) if not existing_kvp_api and id_ and not bson.ObjectId.is_valid( id_): del kvp.__dict__["id"] kvp.name = key_ref kvp.scope = scope try: kvp_db = KeyValuePairAPI.to_model(kvp) if existing_kvp_api: kvp_db.id = existing_kvp_api.id kvp_db = KeyValuePair.add_or_update(kvp_db) except (ValidationError, ValueError) as e: LOG.exception("Validation failed for key value data=%s", kvp) abort(http_client.BAD_REQUEST, six.text_type(e)) return except CryptoKeyNotSetupException as e: LOG.exception(six.text_type(e)) abort(http_client.BAD_REQUEST, six.text_type(e)) return except InvalidScopeException as e: LOG.exception(six.text_type(e)) abort(http_client.BAD_REQUEST, six.text_type(e)) return extra["kvp_db"] = kvp_db LOG.audit("PUT /v1/keys/%s succeeded id=%s", name, kvp_db.id, extra=extra) return KeyValuePairAPI.from_model(kvp_db)