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 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(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, 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, 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. """ # 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, 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 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 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)